aboutsummaryrefslogtreecommitdiff
path: root/lib/plugins/core
diff options
context:
space:
mode:
authorJan-Hendrik Willms <tleilax+github@gmail.com>2021-07-22 16:07:19 +0200
committerJan-Hendrik Willms <tleilax+github@gmail.com>2021-07-22 16:19:12 +0200
commita3da1483a9e689846179159355badfec8073dbec (patch)
tree770dcca6bdf5f6f2a11b0e7fcbbeda6919a3fc52 /lib/plugins/core
current code from svn, revision 62608
Diffstat (limited to 'lib/plugins/core')
-rw-r--r--lib/plugins/core/AdminCourseAction.class.php22
-rw-r--r--lib/plugins/core/AdminCourseContents.class.php23
-rw-r--r--lib/plugins/core/AdministrationPlugin.class.php19
-rw-r--r--lib/plugins/core/CorePlugin.php151
-rw-r--r--lib/plugins/core/DetailspagePlugin.class.php27
-rw-r--r--lib/plugins/core/FileUploadHook.class.php12
-rw-r--r--lib/plugins/core/FilesystemPlugin.class.php82
-rw-r--r--lib/plugins/core/ForumModule.class.php140
-rw-r--r--lib/plugins/core/HomepagePlugin.class.php33
-rw-r--r--lib/plugins/core/LibraryPlugin.class.php55
-rw-r--r--lib/plugins/core/MetricsPlugin.class.php23
-rw-r--r--lib/plugins/core/PluginAssetsTrait.php215
-rw-r--r--lib/plugins/core/PortalPlugin.class.php33
-rw-r--r--lib/plugins/core/PrivacyPlugin.class.php24
-rw-r--r--lib/plugins/core/QuestionnaireAssignmentPlugin.class.php55
-rw-r--r--lib/plugins/core/RESTAPIPlugin.class.php23
-rw-r--r--lib/plugins/core/Role.class.php89
-rw-r--r--lib/plugins/core/ScorePlugin.class.php29
-rw-r--r--lib/plugins/core/StandardPlugin.class.php17
-rw-r--r--lib/plugins/core/StudIPPlugin.class.php218
-rw-r--r--lib/plugins/core/SystemPlugin.class.php17
-rw-r--r--lib/plugins/core/TranslatablePluginTrait.php104
-rw-r--r--lib/plugins/core/WebServicePlugin.class.php14
23 files changed, 1425 insertions, 0 deletions
diff --git a/lib/plugins/core/AdminCourseAction.class.php b/lib/plugins/core/AdminCourseAction.class.php
new file mode 100644
index 0000000..046502c
--- /dev/null
+++ b/lib/plugins/core/AdminCourseAction.class.php
@@ -0,0 +1,22 @@
+<?php
+
+interface AdminCourseAction
+{
+ public function getAdminActionURL();
+
+ /**
+ * Defines if the Plugin wants to use the multimode to edit multiple courses at once.
+ * @return boolean|string: false, if multimode is not important, else true. But you can also set it to a string (means true) that is the label of the send-button like _("Veranstaltungen archivieren")
+ */
+ public function useMultimode();
+
+ /**
+ * Returns a template for a small table cell (the <td> wraps the template-content)
+ * in which you can set inputs and links to display special actions for an admin
+ * for the given course.
+ * @param $course_id
+ * @param null $values
+ * @return null|Flex_Template
+ */
+ public function getAdminCourseActionTemplate($course_id, $values = null);
+}
diff --git a/lib/plugins/core/AdminCourseContents.class.php b/lib/plugins/core/AdminCourseContents.class.php
new file mode 100644
index 0000000..065cc9e
--- /dev/null
+++ b/lib/plugins/core/AdminCourseContents.class.php
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * Interface AdminCourseContents
+ * With this interface a plugin is able to add columns to the course-overview table for admins and roots.
+ */
+interface AdminCourseContents
+{
+ /**
+ * The available columns for the course-overview table for admins. Index is the identifier of the column
+ * for the method adminAreaGetCourseContent. The value is the display name of the column.
+ * @return array : an associative array like array('index' => _("Translated display name"))
+ */
+ public function adminAvailableContents();
+
+ /**
+ * Returns the value of the additional column for the course-overview table in the admin-area.
+ * @param Course $course : A Course-object of the given ... course
+ * @param string $index : the index that comes from adminAvailableContents to identify the column.
+ * @return Flexi_Template | String : Either one will do, but string is preferred, because it can exported as CSV-file more easily.
+ */
+ public function adminAreaGetCourseContent($course, $index);
+}
diff --git a/lib/plugins/core/AdministrationPlugin.class.php b/lib/plugins/core/AdministrationPlugin.class.php
new file mode 100644
index 0000000..c9aa8da
--- /dev/null
+++ b/lib/plugins/core/AdministrationPlugin.class.php
@@ -0,0 +1,19 @@
+<?php
+# Lifter010: TODO
+/*
+ * AdministrationPlugin.class.php - administration plugin interface
+ *
+ * NOTE: This interface is deprecated, use SystemPlugin instead.
+ *
+ * Copyright (c) 2008 - Marcus Lunzenauer <mlunzena@uos.de>
+ * Copyright (c) 2009 - Elmar Ludwig
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+interface AdministrationPlugin
+{
+}
diff --git a/lib/plugins/core/CorePlugin.php b/lib/plugins/core/CorePlugin.php
new file mode 100644
index 0000000..e16b77a
--- /dev/null
+++ b/lib/plugins/core/CorePlugin.php
@@ -0,0 +1,151 @@
+<?php
+/**
+ * CorePlugin.class.php - base class
+ *
+ * @author André Noack <noack@data-quest.de>
+ * @copyright 2021 Authors
+ * @license GPL2 or any later version
+ */
+abstract class CorePlugin
+{
+
+ /**
+ * plugin meta data
+ */
+ protected $plugin_info;
+
+ /**
+ * plugin constructor
+ * TODO bindtextdomain()
+ */
+ public function __construct()
+ {
+ $plugin_manager = PluginManager::getInstance();
+ $this->plugin_info = $plugin_manager->getPluginInfo(static::class);
+ }
+
+ /**
+ * Return the ID of this plugin.
+ */
+ public function getPluginId()
+ {
+ return $this->plugin_info['id'];
+ }
+
+ public function isEnabled()
+ {
+ return $this->plugin_info['enabled'];
+ }
+
+ /**
+ * Return the name of this plugin.
+ */
+ public function getPluginName()
+ {
+ return $this->plugin_info['name'];
+ }
+
+
+ public function getPluginURL()
+ {
+ return $GLOBALS['ABSOLUTE_URI_STUDIP'];
+ }
+
+ /**
+ * Returns the version of this plugin as defined in manifest.
+ * @return string
+ */
+ public function getPluginVersion()
+ {
+ return '';
+ }
+
+ /**
+ * Checks if the plugin is a core-plugin. Returns true if this is the case.
+ *
+ * @return boolean
+ */
+ public function isCorePlugin()
+ {
+ return true;
+ }
+
+ /**
+ * Get the activation status of this plugin in the given context.
+ * This also checks the plugin default activations.
+ *
+ * @param $context context range id (optional)
+ */
+ public function isActivated($context = null)
+ {
+ $plugin_id = $this->getPluginId();
+ $plugin_manager = PluginManager::getInstance();
+
+ if (!isset($context)) {
+ $context = Context::getId();
+ }
+ $activated = $plugin_manager->isPluginActivated($plugin_id, $context);
+ return $activated;
+ }
+
+ /**
+ * Returns whether the plugin may be activated in a certain context.
+ *
+ * @param Range $context
+ * @return bool
+ */
+ public function isActivatableForContext(Range $context)
+ {
+ return true;
+ }
+
+ /**
+ * Callback function called after enabling a plugin.
+ * The plugin's ID is transmitted for convenience.
+ *
+ * @param $plugin_id string The ID of the plugin just enabled.
+ */
+ public static function onEnable($plugin_id)
+ {
+ }
+
+ /**
+ * Callback function called after disabling a plugin.
+ * The plugin's ID is transmitted for convenience.
+ *
+ * @param $plugin_id string The ID of the plugin just disabled.
+ */
+ public static function onDisable($plugin_id)
+ {
+ }
+
+ /**
+ * Callback function called after enabling a plugin.
+ * The plugin's ID is transmitted for convenience.
+ *
+ * @param $plugin_id string The ID of the plugin just enabled.
+ */
+ public static function onActivation($plugin_id, $range_id)
+ {
+ }
+
+ /**
+ * Callback function called after disabling a plugin.
+ * The plugin's ID is transmitted for convenience.
+ *
+ * @param $plugin_id string The ID of the plugin just disabled.
+ */
+ public static function onDeactivation($plugin_id, $range_id)
+ {
+ }
+
+ /**
+ * @param $range_id string
+ * @return bool
+ */
+ public static function checkActivation($range_id)
+ {
+ $core_plugin = PluginEngine::getPlugin(static::class);
+ return $core_plugin && $core_plugin->isActivated($range_id);
+ }
+}
diff --git a/lib/plugins/core/DetailspagePlugin.class.php b/lib/plugins/core/DetailspagePlugin.class.php
new file mode 100644
index 0000000..15eda09
--- /dev/null
+++ b/lib/plugins/core/DetailspagePlugin.class.php
@@ -0,0 +1,27 @@
+<?php
+/*
+ * DetailspagePlugin.class.php
+ *
+ * Copyright (c) 2019 - Rasmus Fuhse <fuhse@data-quest.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+interface DetailspagePlugin
+{
+ /**
+ * Return a template (an instance of the Flexi_Template class)
+ * to be rendered on the details page. Return NULL to
+ * render nothing for this plugin or this course.
+ *
+ * The template will automatically get a standard layout, which
+ * can be configured via attributes set on the template:
+ *
+ * title title to display, defaults to plugin name
+ *
+ * @return object template object to render or NULL
+ */
+ public function getDetailspageTemplate($course);
+}
diff --git a/lib/plugins/core/FileUploadHook.class.php b/lib/plugins/core/FileUploadHook.class.php
new file mode 100644
index 0000000..27323fd
--- /dev/null
+++ b/lib/plugins/core/FileUploadHook.class.php
@@ -0,0 +1,12 @@
+<?php
+interface FileUploadHook
+{
+ /**
+ * If this method returns a URL the new page will be shown right after adding a file
+ * into a filesystem.
+ *
+ * @param $file_ref
+ * @return null|string: URL or null if no page should be added
+ */
+ public function getAdditionalUploadWizardPage($file_ref);
+}
diff --git a/lib/plugins/core/FilesystemPlugin.class.php b/lib/plugins/core/FilesystemPlugin.class.php
new file mode 100644
index 0000000..6d4c46c
--- /dev/null
+++ b/lib/plugins/core/FilesystemPlugin.class.php
@@ -0,0 +1,82 @@
+<?php
+interface FilesystemPlugin
+{
+ /**
+ * Returns a Navigation-object. Only the title and the image will be used.
+ *
+ * @return null|Navigation with title and image
+ */
+ public function getFileSelectNavigation();
+
+ /**
+ * Returns an URL to a page, where the filesystem can be configured.
+ *
+ * @return mixed
+ */
+ public function filesystemConfigurationURL();
+
+ /**
+ * Determines if this filesystem plugin should be a source for copying or a search.
+ * This may be dependend on the current user and his/her configurations.
+ *
+ * @return boolean
+ */
+ public function isSource();
+
+ /**
+ * Determines if this filesystem-plugin should show up as a personal file-area and be a destination
+ * for copied files.
+ * This may be dependend on the current user and his/her configurations.
+ *
+ * @return boolean
+ */
+ public function isPersonalFileArea();
+
+ /**
+ * This method is used to get a folder-object for this plugin.
+ * Not recommended but still possible is to return a Flexi_Template for the folder, if you want to
+ * take care of the frontend of displaying the folder as well.
+ *
+ * @param null $folder_id : folder_id of folder to get or null if you want the top-folder
+ * @return FolderType|Flexi_Template
+ */
+ public function getFolder($folder_id = null);
+
+ /**
+ * @param $file_id : The id for the file in the given filesystem of the plugin.
+ * @return array : the already prepared File just like a file-upload-array
+ */
+ public function getPreparedFile($file_id, $with_blob = false);
+
+ /**
+ * Defines if the filesystem-plugin has a search-function.
+ *
+ * @return mixed
+ */
+ public function hasSearch();
+
+ /**
+ * Returns an array for each special search parameter. Each parameter is itself represented by as associative array
+ * like
+ * array(
+ * 'name' => "name of this parameter in the form",
+ * 'type' => "one of 'text', 'checkbox', 'select'",
+ * 'options' => array() //only neccesary if type is 'select' - a key-value array with the key key as the value of the select and the value as the label of the option
+ * 'placeholder' => "only possible for type 'text' but not mandatory"
+ * )
+ * This method can also return an empty array or null if no search parameters are needed or no search is provided at all.
+ *
+ * @return null|array(array(), ...)
+ */
+ public function getSearchParameters();
+
+ /**
+ * Returns a virtual folder that 'contains' all the files as a search-result. Only return null
+ * if search is not implemented.
+ *
+ * @param string $text a string
+ * @param array $parameters : an associative array of additional search parameters as defined in getSearchParameters()
+ * @return FolderType|null
+ */
+ public function search($text, $parameters = []);
+}
diff --git a/lib/plugins/core/ForumModule.class.php b/lib/plugins/core/ForumModule.class.php
new file mode 100644
index 0000000..33784db
--- /dev/null
+++ b/lib/plugins/core/ForumModule.class.php
@@ -0,0 +1,140 @@
+<?php
+/**
+ * ForumModule.class.php - Interface for all intersections between the Stud.IP
+ * Core and something that behaves like a forum
+ *
+ * Implement all interface methods and you can integrate your plugin like
+ * a real core-module into Stud.IP
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL version 3
+ * @category Stud.IP
+ */
+
+interface ForumModule extends StandardPlugin
+{
+ /**
+ * Issues can be connected with an entry in a forum. This method
+ * has to return an url to the connected topic for the passed issue_id.
+ * If no topic is connected, it has to return "false"
+ *
+ * @param string $issue_id
+ * @return mixed URL or false
+ */
+ function getLinkToThread($issue_id);
+
+ /**
+ * This method is called in case of an creation OR an update of an issue.
+ * Normally one would update the title and the content of the linked topic
+ * when called
+ *
+ * @param string $issue_id
+ * @param string $title the title of the issue
+ * @param string $content the description of the issue
+ */
+ function setThreadForIssue($issue_id, $title, $content);
+
+ /**
+ * Return the number of postings the connected topic contains for
+ * the issue with the passed id
+ *
+ * @param type $issue_id
+ *
+ * @return int
+ */
+ function getNumberOfPostingsForIssue($issue_id);
+
+ /**
+ * Return the number of postings for the passed user
+ *
+ * @param type $user_id
+ *
+ * @return int
+ */
+ function getNumberOfPostingsForUser($user_id);
+
+ /**
+ * Return the number of postings for the passed seminar
+ *
+ * @param type $seminar_id
+ *
+ * @return int
+ */
+ function getNumberOfPostingsForSeminar($seminar_id);
+
+ /**
+ * Return the number of all postings served by your module. The
+ * results are used for statistics.
+ *
+ * @return int
+ */
+ function getNumberOfPostings();
+
+ /**
+ * This function is called whenever Stud.IP needs to directly operate
+ * on your entries-table. Your entries-table MUST have at least fields
+ * for a date (a change-date is preferred, but make-date will suffice),
+ * posting-content, seminar_id and user_id.
+ *
+ * The returning array must have the following structure:
+ * Array (
+ * 'table' => 'your_entry_table,
+ * 'content' => 'your_content_field',
+ * 'chdate' => 'your_date_field',
+ * 'seminar_id' => 'your_seminar_id_field',
+ * 'user_id' => 'your_user_id_field'
+ * )
+ *
+ * @return array
+ */
+ function getEntryTableInfo();
+
+ /**
+ * The caller expects an array of the ten seminars with the most postings
+ * in your module.
+ *
+ * Return an array of the following structure:
+ * Array (
+ * Array (
+ * 'seminar_id' =>
+ * 'display' =>
+ * 'count' =>
+ * )
+ * )
+ *
+ * @return array
+ */
+ function getTopTenSeminars();
+
+ /**
+ * Is called when the data of a user is moved to another user.
+ * Update all user_ids with the passed new one.
+ *
+ * @param string $user_from the user_id of the user who has the data
+ * @param string $user_to the user_id of the user who shall receive the data
+ */
+ function migrateUser($user_from, $user_to);
+
+ /**
+ * Clean up everything for the passed seminar, because the seminar
+ * is beeing deleted.
+ *
+ * @param string $seminar_id
+ */
+ function deleteContents($seminar_id);
+
+ /**
+ * Return a complete HTML-Dump of all entries in the forum-module. This is
+ * used for archiving purposes, so make it pretty!
+ *
+ * @param string $seminar_id
+ *
+ * @return string a single-page HTML-view of all contents in one string
+ */
+ function getDump($seminar_id);
+} \ No newline at end of file
diff --git a/lib/plugins/core/HomepagePlugin.class.php b/lib/plugins/core/HomepagePlugin.class.php
new file mode 100644
index 0000000..74d0204
--- /dev/null
+++ b/lib/plugins/core/HomepagePlugin.class.php
@@ -0,0 +1,33 @@
+<?php
+# Lifter010: TODO
+/*
+ * HomepagePlugin.class.php - home page plugin interface
+ *
+ * Copyright (c) 2008 - Marcus Lunzenauer <mlunzena@uos.de>
+ * Copyright (c) 2009 - Elmar Ludwig
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+interface HomepagePlugin
+{
+ /**
+ * Return a template (an instance of the Flexi_Template class)
+ * to be rendered on the given user's home page. Return NULL to
+ * render nothing for this plugin.
+ *
+ * The template will automatically get a standard layout, which
+ * can be configured via attributes set on the template:
+ *
+ * title title to display, defaults to plugin name
+ * icon_url icon for this plugin (if any)
+ * admin_url admin link for this plugin (if any)
+ * admin_title title for admin link (default: Administration)
+ *
+ * @return object template object to render or NULL
+ */
+ function getHomepageTemplate($user_id);
+}
diff --git a/lib/plugins/core/LibraryPlugin.class.php b/lib/plugins/core/LibraryPlugin.class.php
new file mode 100644
index 0000000..a7fb873
--- /dev/null
+++ b/lib/plugins/core/LibraryPlugin.class.php
@@ -0,0 +1,55 @@
+<?php
+
+
+/*
+ * LibraryPlugin.class.php - A plugin class for library plugins.
+ *
+ * Copyright (c) 2020 Moritz Strohm
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+
+interface LibraryPlugin
+{
+ /**
+ * Generates the URL that leads to the plugin action to create a request.
+ * The URL may vary depending on the ID of the library file that shall be
+ * requested. Therefore, the library file ID is passed to this method.
+ *
+ * @param $library_file_id The library file ID to which a request URL shall
+ * be generated.
+ *
+ * @returns string The URL for the request action of the plugin.
+ */
+ public function getRequestURL(string $library_file_id) : string;
+
+
+ /**
+ * Generates the title for the plugin action to create a request.
+ * That title may vary depending on the library file that shall be requested.
+ * Therefore, the file is passed to this method.
+ *
+ * @param LibraryFile $file The file to which the request URL title shall be
+ * generated.
+ *
+ * @returns string The title for the request URL action of the plugin.
+ */
+ public function getRequestTitle() : string;
+
+
+ /**
+ * Generates the icon for the plugin action to create a request.
+ * That icon may vary depending on the library file that shall be requested.
+ * Therefore, the file is passed to this method.
+ *
+ * @param LibraryFile $file The file to which the request URL icon shall be
+ * generated.
+ *
+ * @returns Icon The icon for the request URL action of the plugin.
+ */
+ public function getRequestIcon() : Icon;
+}
diff --git a/lib/plugins/core/MetricsPlugin.class.php b/lib/plugins/core/MetricsPlugin.class.php
new file mode 100644
index 0000000..95edaf1
--- /dev/null
+++ b/lib/plugins/core/MetricsPlugin.class.php
@@ -0,0 +1,23 @@
+<?php
+/*
+ * MetricsPlugins take countings and measurements and transfer them to
+ * a specific backend like statsd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * @author <mlunzena@uos.de>
+ * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
+ * @category Stud.IP
+ */
+
+interface MetricsPlugin
+{
+ public function count($stat, $value, $sampleRate = null);
+
+ public function timing($stat, $time, $sampleRate = null);
+
+ public function gauge($stat, $value, $sampleRate = null);
+}
diff --git a/lib/plugins/core/PluginAssetsTrait.php b/lib/plugins/core/PluginAssetsTrait.php
new file mode 100644
index 0000000..326809c
--- /dev/null
+++ b/lib/plugins/core/PluginAssetsTrait.php
@@ -0,0 +1,215 @@
+<?php
+/**
+ * Trait for assets handling in plugins.
+ *
+ * @author Jan-Hendrik Willms <tleilax+studip@gmail.com>
+ * @license GPL2 or any later version
+ * @since Stud.IP 4.4
+ */
+trait PluginAssetsTrait
+{
+ /**
+ * Adds many stylesheeets at once.
+ * @param array $filenames List of relative filenames
+ * @param array $variables Optional array of variables to pass to the
+ * LESS compiler
+ * @param array $link_attr Attributes to pass to the link elements
+ * @param string $path Common path prefix for all filenames
+ */
+ protected function addStylesheets(array $filenames, array $variables = [], array $link_attr = [], $path = '')
+ {
+ if (Studip\ENV === 'development') {
+ foreach ($filenames as $filename) {
+ $this->addStylesheet("{$path}{$filename}", $variables, $link_attr);
+ }
+ }
+
+ $hash = substr(md5(serialize($filenames)), -8);
+ $filename = "combined-{$hash}.css";
+
+ // Get asset file from storage
+ $asset = Assets\Storage::getFactory()->createCSSFile(
+ $filename,
+ $this->createMetaData()
+ );
+
+ // Compile asset if neccessary
+ if ($asset->isNew()) {
+ $content = '';
+ foreach ($filenames as $filename) {
+ $file = $this->resolveFilename($filename, $path);
+ $content .= $this->readPluginAssetFile($file, $variables);
+ }
+ $asset->setContent($content);
+ }
+
+ $this->includeStyleAsset($asset, $link_attr);
+ }
+
+ /**
+ * Includes given stylesheet in page, compiles less if neccessary
+ *
+ * @param string $filename Name of the stylesheet (css or less) to include
+ * (relative to plugin directory)
+ * @param array $variables Optional array of variables to pass to the
+ * LESS compiler
+ * @param array $link_attr Attributes to pass to the link element
+ */
+ protected function addStylesheet($filename, array $variables = [], array $link_attr = [])
+ {
+ $extension = pathinfo($filename, PATHINFO_EXTENSION);
+ if (!in_array($extension, ['less', 'scss'])) {
+ PageLayout::addStylesheet(
+ "{$this->getPluginURL()}/{$filename}?v={$this->getPluginVersion()}",
+ $link_attr
+ );
+ return;
+ }
+
+ // Create absolute path to assets file
+ $file = $this->resolveFilename($filename);
+
+ // Get asset file from storage
+ $asset = Assets\Storage::getFactory()->createCSSFile(
+ $file,
+ $this->createMetaData()
+ );
+
+ // Compile asset if neccessary
+ if ($asset->isNew()) {
+ $css = $this->readPluginAssetFile($file, $variables);
+ $asset->setContent($css);
+ }
+
+ $this->includeStyleAsset($asset, $link_attr);
+ }
+
+ private function includeStyleAsset(Assets\PluginAsset $asset, array $link_attr)
+ {
+ // Include asset in page by reference or directly
+ $download_uri = $asset->getDownloadLink();
+ if ($download_uri === false) {
+ PageLayout::addStyle($asset->getContent(), $link_attr);
+ } else {
+ $link_attr['rel'] = 'stylesheet';
+ $link_attr['href'] = $download_uri;
+ $link_attr['type'] = 'text/css';
+ PageLayout::addHeadElement('link', $link_attr);
+ }
+ }
+
+ /**
+ * Adds many scripts at once.
+ * @param array $filenames List of relative filenames
+ * @param array $link_attr Attributes to pass to the script elements
+ * @param string $path Common path prefix for all filenames
+ */
+ protected function addScripts(array $filenames, array $link_attr = [], $path = '')
+ {
+ if (Studip\ENV === 'development') {
+ foreach ($filenames as $filename) {
+ $this->addScript("{$path}{$filename}", $link_attr);
+ }
+ return;
+ }
+
+ $hash = substr(md5(serialize($filenames)), -8);
+ $filename = "combined-{$hash}.js";
+
+ // Get asset file from storage
+ $asset = Assets\Storage::getFactory()->createJSFile(
+ $filename,
+ $this->createMetaData()
+ );
+
+ // Compile asset if neccessary
+ if ($asset->isNew()) {
+ $content = '';
+ foreach ($filenames as $filename) {
+ $file = $this->resolveFilename($filename, $path);
+ $content .= $this->readPluginAssetFile($file) . ';';
+ }
+ $asset->setContent($content);
+ }
+
+ // Include asset in page by reference or directly
+ $download_uri = $asset->getDownloadLink();
+ if ($download_uri === false) {
+ PageLayout::addHeadElement('script', $link_attr, $asset->getContent());
+ } else {
+ $link_attr['src'] = $download_uri;
+ PageLayout::addHeadElement('script', $link_attr);
+ }
+ }
+
+ /**
+ * Includes given script in page.
+ *
+ * @param string $filename Name of script file
+ * @param array $link_attr Attributes to pass to the script element
+ */
+ protected function addScript($filename, array $link_attr = [])
+ {
+ PageLayout::addScript(
+ "{$this->getPluginURL()}/{$filename}?v={$this->getPluginVersion()}",
+ $link_attr
+ );
+ }
+
+ /**
+ * Create metadata for plugin assets factory
+ * @return array
+ */
+ private function createMetaData()
+ {
+ return [
+ 'plugin_id' => $this->plugin_info['depends'] ?: $this->getPluginId(),
+ 'plugin_version' => $this->getPluginVersion(),
+ ];
+ }
+
+ /**
+ * Resolves relative filename to absolute filename.
+ *
+ * @param string $filename Relative filename
+ * @param string $path Optional relative path the file is stored in
+ * @return string
+ * @throws RuntimeException when absolute file is missing
+ */
+ private function resolveFilename($filename, $path = '')
+ {
+ $file = $GLOBALS['ABSOLUTE_PATH_STUDIP']
+ . $this->getPluginPath() . '/'
+ . "{$path}{$filename}";
+
+ // Fail if file does not exist
+ if (!file_exists($file)) {
+ throw new RuntimeException("Could not locate assets file '{$filename}'");
+ }
+
+ return $file;
+ }
+
+ /**
+ * Reads assets file (and compiles if neccessary).
+ * @param string $filename Name of the file to read
+ * @param array $variables Additional variables for compiler (if appropriate)
+ * @return string
+ */
+ private function readPluginAssetFile($filename, array $variables = [])
+ {
+ $contents = file_get_contents($filename);
+
+ $extension = pathinfo($filename, PATHINFO_EXTENSION);
+ if ($extension === 'less') {
+ $contents = Assets\LESSCompiler::getInstance()->compile($contents, $variables + [
+ 'plugin-path' => $this->getPluginURL(),
+ ]);
+ } elseif ($extension === 'scss') {
+ $contents = Assets\SASSCompiler::getInstance()->compile($contents, $variables + [
+ 'plugin-path' => '"' . $this->getPluginURL() . '"',
+ ]);
+ }
+ return $contents;
+ }
+}
diff --git a/lib/plugins/core/PortalPlugin.class.php b/lib/plugins/core/PortalPlugin.class.php
new file mode 100644
index 0000000..ed157a8
--- /dev/null
+++ b/lib/plugins/core/PortalPlugin.class.php
@@ -0,0 +1,33 @@
+<?php
+# Lifter010: TODO
+/*
+ * PortalPlugin.class.php - start / portal page plugin interface
+ *
+ * Copyright (c) 2008 - Marcus Lunzenauer <mlunzena@uos.de>
+ * Copyright (c) 2009 - Elmar Ludwig
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+interface PortalPlugin
+{
+ /**
+ * Return a template (an instance of the Flexi_Template class)
+ * to be rendered on the start or portal page. Return NULL to
+ * render nothing for this plugin.
+ *
+ * The template will automatically get a standard layout, which
+ * can be configured via attributes set on the template:
+ *
+ * title title to display, defaults to plugin name
+ * icon_url icon for this plugin (if any)
+ * admin_url admin link for this plugin (if any)
+ * admin_title title for admin link (default: Administration)
+ *
+ * @return object template object to render or NULL
+ */
+ function getPortalTemplate();
+}
diff --git a/lib/plugins/core/PrivacyPlugin.class.php b/lib/plugins/core/PrivacyPlugin.class.php
new file mode 100644
index 0000000..73a971d
--- /dev/null
+++ b/lib/plugins/core/PrivacyPlugin.class.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * PrivacyPlugin are able to handle user data according the privacy policy.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * @author Timo Hartge <hartge@data-quest.de>
+ * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
+ * @category Stud.IP
+ */
+
+interface PrivacyPlugin
+{
+ /**
+ * Export available data of a given user into a storage object
+ * (an instance of the StoredUserData class) for that user.
+ *
+ * @param StoredUserData $storage object to store data into
+ */
+ public function exportUserData(StoredUserData $storage);
+}
diff --git a/lib/plugins/core/QuestionnaireAssignmentPlugin.class.php b/lib/plugins/core/QuestionnaireAssignmentPlugin.class.php
new file mode 100644
index 0000000..6892f8a
--- /dev/null
+++ b/lib/plugins/core/QuestionnaireAssignmentPlugin.class.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * Interface QuestionnaireAssignmentPlugin
+ * Implement this interface if you want to relate Stud.IP-questionnaires to your plugin-contents.
+ * By storing an assignment you should set the range_type to something unique that is
+ * related to your plugin like "mytaskplugin". In all methods you should first check if the
+ * assignment is related to your plugin, because other QuestionnaireAssignmentPlugins might
+ * be installed as well.
+ */
+interface QuestionnaireAssignmentPlugin
+{
+ /**
+ * Returns if the questionnaire is viewable dependend on the assignment. Check for the range_type
+ * and range_id to see if the the assignment has to do with your plugin (and not with
+ * somebody else's plugin) and if type and id fit.
+ * @param QuestionnaireAssignment $questionnaire
+ * @return boolean
+ */
+ public function isQuestionnaireViewable(QuestionnaireAssignment $questionnaire);
+
+ /**
+ * Returns if the questionnaire is editable dependend on the assignment. Check for the range_type
+ * and range_id to see if the the assignment has to do with your plugin (and not with
+ * somebody else's plugin) and if type and id fit.
+ * @param QuestionnaireAssignment $questionnaire
+ * @return boolean
+ */
+ public function isQuestionnaireEditable(QuestionnaireAssignment $questionnaire);
+
+ /**
+ * The display name of the assignment.
+ * @param QuestionnaireAssignment $questionnaire
+ * @return string
+ */
+ public function getQuestionnaireAssignmentName(QuestionnaireAssignment $questionnaire);
+
+ /**
+ * This template will get displayed when someone at tools -> questionnaires
+ * wants to edit the contexts of the questionnaire. Maybe you don't want to provide a
+ * template here, so return null or just a readonly html-snippet.
+ * @param Questionnaire $questionnaire
+ * @return null|Flexi_Template
+ */
+ public function getQuestionnaireAssignmentEditTemplate(Questionnaire $questionnaire);
+
+ /**
+ * When the context of the questionnaire is stored at tools -> questionnaires (where
+ * the template from getQuestionnaireAssignmentEditTemplate was displayed) you should
+ * use this method to store your assignments as well.
+ * @param Questionnaire $questionnaire
+ * @return null
+ */
+ public function storeQuestionnaireAssignments(Questionnaire $questionnaire);
+}
diff --git a/lib/plugins/core/RESTAPIPlugin.class.php b/lib/plugins/core/RESTAPIPlugin.class.php
new file mode 100644
index 0000000..d395dea
--- /dev/null
+++ b/lib/plugins/core/RESTAPIPlugin.class.php
@@ -0,0 +1,23 @@
+<?php
+/*
+ * REST-API Plugins add maps to the REST-API router.
+ *
+ * Copyright (c) 2014 - Marcus Lunzenauer <mlunzena@uos.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+interface RESTAPIPlugin
+{
+ /**
+ * Returns one or more instances of RESTAPI\RouteMap to register
+ * to the Router.
+ *
+ * @return RouteMap|Array either a single instance of class
+ * RouteMap or an array of them
+ */
+ public function getRouteMaps();
+}
diff --git a/lib/plugins/core/Role.class.php b/lib/plugins/core/Role.class.php
new file mode 100644
index 0000000..3ca8a11
--- /dev/null
+++ b/lib/plugins/core/Role.class.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * Role.class.php
+ *
+ * @author Dennis Reil <dennis.reil@offis.de>
+ * @author Michael Riehemann <michael.riehemann@uni-oldenburg.de>
+ * @package pluginengine
+ * @subpackage core
+ * @copyright 2009 Stud.IP
+ * @license http://www.gnu.org/licenses/gpl.html GPL Licence 3
+ */
+class Role
+{
+ const UNKNOWN_ROLE_ID = null;
+
+ public $roleid;
+ public $rolename;
+ public $systemtype;
+
+ /**
+ * Constructor
+ */
+ public function __construct($id = self::UNKNOWN_ROLE_ID, $name = '', $system = false)
+ {
+ $this->setRoleid($id);
+ $this->setRolename($name);
+ $this->setSystemtype($system);
+ }
+
+ /**
+ * Returns the role's id.
+ *
+ * @return int
+ */
+ public function getRoleid()
+ {
+ return $this->roleid;
+ }
+
+ /**
+ * Set the role's id.
+ *
+ * @param int $newid
+ */
+ public function setRoleid($newid)
+ {
+ $this->roleid = $newid;
+ }
+
+ /**
+ * Returns the role's name.
+ *
+ * @return string
+ */
+ public function getRolename()
+ {
+ return $this->rolename;
+ }
+
+ /**
+ * Set the role's name.
+ *
+ * @param string $newrole
+ */
+ public function setRolename($newrole)
+ {
+ $this->rolename = $newrole;
+ }
+
+ /**
+ * Returns whether the role is a system role.
+ *
+ * @return boolean
+ */
+ public function getSystemtype()
+ {
+ return $this->systemtype;
+ }
+
+ /**
+ * Sets whether the role is a system role.
+ *
+ * @param boolean $newtype
+ */
+ public function setSystemtype($newtype)
+ {
+ $this->systemtype = (bool) $newtype;
+ }
+}
diff --git a/lib/plugins/core/ScorePlugin.class.php b/lib/plugins/core/ScorePlugin.class.php
new file mode 100644
index 0000000..064ddc3
--- /dev/null
+++ b/lib/plugins/core/ScorePlugin.class.php
@@ -0,0 +1,29 @@
+<?php
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+interface ScorePlugin
+{
+ /**
+ * Returns null or an array of associated arrays - each one to
+ * indicate a db-table in which the plugin stores user activities.
+ *
+ * For a bullitin-board-plugin this array could look like this:
+ *
+ * return array(
+ * array(
+ * 'table' => "bullitin_board_entries",
+ * 'user_id_column' => "user_id",
+ * 'date_column' => "mkdate",
+ * 'where' => "public = '1'" //only public entries should be counted
+ * )
+ * );
+ *
+ * @return null|array of associated arrays
+ */
+ function getPluginActivityTables();
+}
diff --git a/lib/plugins/core/StandardPlugin.class.php b/lib/plugins/core/StandardPlugin.class.php
new file mode 100644
index 0000000..960ffd0
--- /dev/null
+++ b/lib/plugins/core/StandardPlugin.class.php
@@ -0,0 +1,17 @@
+<?php
+# Lifter010: TODO
+/*
+ * StandardPlugin.class.php - course or institute plugin interface
+ *
+ * Copyright (c) 2008 - Marcus Lunzenauer <mlunzena@uos.de>
+ * Copyright (c) 2009 - Elmar Ludwig
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+interface StandardPlugin extends StudipModule
+{
+}
diff --git a/lib/plugins/core/StudIPPlugin.class.php b/lib/plugins/core/StudIPPlugin.class.php
new file mode 100644
index 0000000..2fa9703
--- /dev/null
+++ b/lib/plugins/core/StudIPPlugin.class.php
@@ -0,0 +1,218 @@
+<?php
+/**
+ * StudIPPlugin.class.php - generic plugin base class
+ *
+ * @author Elmar Ludwig <ludwig@uos.de>
+ * @copyright 2009 Authors
+ * @license GPL2 or any later version
+ */
+abstract class StudIPPlugin
+{
+ use PluginAssetsTrait;
+ use TranslatablePluginTrait;
+
+ /**
+ * plugin meta data
+ */
+ protected $plugin_info;
+
+ /**
+ * Plugin manifest
+ */
+ protected $manifest = null;
+
+ /**
+ * plugin constructor
+ */
+ public function __construct()
+ {
+ $plugin_manager = PluginManager::getInstance();
+ $this->plugin_info = $plugin_manager->getPluginInfo(static::class);
+ }
+
+ /**
+ * Return the ID of this plugin.
+ */
+ public function getPluginId()
+ {
+ return $this->plugin_info['id'];
+ }
+
+ public function isEnabled()
+ {
+ return $this->plugin_info['enabled'];
+ }
+
+ /**
+ * Return the name of this plugin.
+ */
+ public function getPluginName()
+ {
+ return $this->plugin_info['name'];
+ }
+
+ /**
+ * Return the filesystem path to this plugin.
+ */
+ public function getPluginPath()
+ {
+ return "plugins_packages/{$this->plugin_info['path']}";
+ }
+
+ /**
+ * Return the URL of this plugin. Can be used to refer to resources
+ * (images, style sheets, etc.) inside the installed plugin package.
+ */
+ public function getPluginURL()
+ {
+ return $GLOBALS['ABSOLUTE_URI_STUDIP'] . $this->getPluginPath();
+ }
+
+ /**
+ * Return metadata stored in the manifest of this plugin.
+ */
+ public function getMetadata()
+ {
+ if ($this->manifest === null) {
+ $plugin_manager = PluginManager::getInstance();
+ $this->manifest = $plugin_manager->getPluginManifest($this->getPluginPath());
+ }
+ return $this->manifest;
+ }
+
+ /**
+ * Returns the version of this plugin as defined in manifest.
+ * @return string
+ */
+ public function getPluginVersion()
+ {
+ return $this->getMetadata()['version'];
+ }
+
+ /**
+ * Checks if the plugin is a core-plugin. Returns true if this is the case.
+ *
+ * @return boolean
+ */
+ public function isCorePlugin()
+ {
+ return $this->plugin_info['core'];
+ }
+
+ /**
+ * Get the activation status of this plugin in the given context.
+ * This also checks the plugin default activations.
+ *
+ * @param $context context range id (optional)
+ * @param $type type of activation (optional), can be set to 'user'
+ * in order to point to a homepage plugin
+ */
+ public function isActivated($context = null, $type = 'sem')
+ {
+ $plugin_id = $this->getPluginId();
+ $plugin_manager = PluginManager::getInstance();
+
+ /*
+ * Context can be a Seminar ID or the current user ID if not set.
+ * Identification is done via the "username" parameter.
+ */
+ if (!isset($context)) {
+ if ($type === 'user') {
+ $context = get_userid(Request::username('username', $GLOBALS['user']->username));
+ } else {
+ $context = Context::getId();
+ }
+ }
+
+ if ($type === 'user') {
+ $activated = $plugin_manager->isPluginActivatedForUser($plugin_id, $context);
+ } else {
+ $activated = $plugin_manager->isPluginActivated($plugin_id, $context);
+ }
+
+ return $activated;
+ }
+
+ /**
+ * Returns whether the plugin may be activated in a certain context.
+ *
+ * @param Range $context
+ * @return bool
+ */
+ public function isActivatableForContext(Range $context)
+ {
+ return true;
+ }
+
+ /**
+ * This method dispatches all actions.
+ *
+ * @param string part of the dispatch path that was not consumed
+ *
+ * @return void
+ */
+ public function perform($unconsumed_path)
+ {
+ $args = explode('/', $unconsumed_path);
+ $action = $args[0] !== '' ? array_shift($args).'_action' : 'show_action';
+
+ if (!method_exists($this, $action)) {
+ $trails_root = $this->getPluginPath();
+ $trails_uri = rtrim(PluginEngine::getLink($this, [], null, true), '/');
+
+ $dispatcher = new Trails_Dispatcher($trails_root, $trails_uri, 'index');
+ $dispatcher->current_plugin = $this;
+ try {
+ $dispatcher->dispatch($unconsumed_path);
+ } catch (Trails_UnknownAction $exception) {
+ if (count($args) > 0) {
+ throw $exception;
+ } else {
+ throw new Exception(_('unbekannte Plugin-Aktion: ') . $unconsumed_path);
+ }
+ }
+ } else {
+ call_user_func_array([$this, $action], $args);
+ }
+ }
+
+ /**
+ * Callback function called after enabling a plugin.
+ * The plugin's ID is transmitted for convenience.
+ *
+ * @param $plugin_id string The ID of the plugin just enabled.
+ */
+ public static function onEnable($plugin_id)
+ {
+ }
+
+ /**
+ * Callback function called after disabling a plugin.
+ * The plugin's ID is transmitted for convenience.
+ *
+ * @param $plugin_id string The ID of the plugin just disabled.
+ */
+ public static function onDisable($plugin_id)
+ {
+ }
+
+ /**
+ * Callback function called after enabling a plugin.
+ * The plugin's ID is transmitted for convenience.
+ *
+ * @param $plugin_id string The ID of the plugin just enabled.
+ */
+ public static function onActivation($plugin_id, $range_id)
+ {
+ }
+
+ /**
+ * Callback function called after disabling a plugin.
+ * The plugin's ID is transmitted for convenience.
+ *
+ * @param $plugin_id string The ID of the plugin just disabled.
+ */
+ public static function onDeactivation($plugin_id, $range_id)
+ {
+ }
+}
diff --git a/lib/plugins/core/SystemPlugin.class.php b/lib/plugins/core/SystemPlugin.class.php
new file mode 100644
index 0000000..c204567
--- /dev/null
+++ b/lib/plugins/core/SystemPlugin.class.php
@@ -0,0 +1,17 @@
+<?php
+# Lifter010: TODO
+/*
+ * SystemPlugin.class.php - generic system plugin interface
+ *
+ * Copyright (c) 2008 - Marcus Lunzenauer <mlunzena@uos.de>
+ * Copyright (c) 2009 - Elmar Ludwig
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+interface SystemPlugin
+{
+}
diff --git a/lib/plugins/core/TranslatablePluginTrait.php b/lib/plugins/core/TranslatablePluginTrait.php
new file mode 100644
index 0000000..13e0903
--- /dev/null
+++ b/lib/plugins/core/TranslatablePluginTrait.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * Trait used to allow plugins to be translated in a generic way.
+ *
+ * @author Jan-Hendrik Willms <tleilax+studip@gmail.com>
+ * @license GPL2 or any later version
+ * @since Stud.IP 5.0
+ */
+trait TranslatablePluginTrait
+{
+ protected $translation_domain = null;
+
+ /**
+ * Initializes the translation for the plugin.
+ *
+ * @param string $domain
+ */
+ protected function initializeTranslation($domain)
+ {
+ bindtextdomain($domain, $this->getPluginPath() . '/locale');
+ bind_textdomain_codeset($domain, 'UTF-8');
+ }
+
+ /**
+ * Returns the defined translation domain from plugin manifest. If none
+ * is set, false is returned.
+ *
+ * @return false|string The translation domain from manifest, if set
+ */
+ protected function getTranslationDomain()
+ {
+ if ($this->translation_domain === null) {
+ $manifest = $this->getMetadata();
+ $this->translation_domain = $manifest['localedomain'] ?? false;
+
+ if ($this->translation_domain !== false) {
+ $this->initializeTranslation($this->translation_domain);
+ }
+ }
+ return $this->translation_domain;
+ }
+
+ /**
+ * Returns whether the plugin has a translation defined or not.
+ *
+ * @return bool
+ */
+ public function hasTranslation()
+ {
+ return $this->getTranslationDomain() !== false;
+ }
+
+ /**
+ * Plugin localization for a single string.
+ *
+ * @param string $string String to translate
+ * @return string
+ */
+ public function _($string)
+ {
+ $domain = $this->getTranslationDomain();
+ if (!$domain) {
+ return $string;
+ }
+
+ $result = dgettext($domain, $string);
+
+ // Fallback to possible translations from core system
+ if ($result === $string) {
+ $result = _($string);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Plugin localization for plural strings.
+ *
+ * @param string $string0 String to translate (singular)
+ * @param string $string1 String to translate (plural)
+ * @param mixed $n Quantity factor (may be an array or array-like)
+ * @return string
+ */
+ public function _n($string0, $string1, $n)
+ {
+ if (is_array($n)) {
+ $n = count($n);
+ }
+
+ $domain = $this->getTranslationDomain();
+ if (!$domain) {
+ return $n == 1 ? $string0 : $string1;
+ }
+
+ $result = dngettext($domain, $string0, $string1, $n);
+
+ // Fallback to possible translations from core system
+ if ($result === $string0 || $result === $string1) {
+ $result = ngettext($string0, $string1, $n);
+ }
+
+ return $result;
+ }
+}
diff --git a/lib/plugins/core/WebServicePlugin.class.php b/lib/plugins/core/WebServicePlugin.class.php
new file mode 100644
index 0000000..ff3e757
--- /dev/null
+++ b/lib/plugins/core/WebServicePlugin.class.php
@@ -0,0 +1,14 @@
+<?php
+/*
+ * Copyright (c) 2011 <mlunzena@uos.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+interface WebServicePlugin
+{
+ function getWebServices();
+}