aboutsummaryrefslogtreecommitdiff
path: root/lib/plugins/engine/PluginManager.class.php
diff options
context:
space:
mode:
Diffstat (limited to 'lib/plugins/engine/PluginManager.class.php')
-rw-r--r--lib/plugins/engine/PluginManager.class.php713
1 files changed, 0 insertions, 713 deletions
diff --git a/lib/plugins/engine/PluginManager.class.php b/lib/plugins/engine/PluginManager.class.php
deleted file mode 100644
index be4f766..0000000
--- a/lib/plugins/engine/PluginManager.class.php
+++ /dev/null
@@ -1,713 +0,0 @@
-<?php
-# Lifter010: TODO
-/*
- * PluginManager.class.php - plugin manager for Stud.IP
- *
- * 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.
- */
-
-class PluginManager
-{
- /**
- * meta data of installed plugins
- */
- private $plugins;
-
- /**
- * cache of created plugin instances
- */
- private $plugin_cache;
-
- /**
- * cache of activated plugins by context
- */
- private $plugins_activated_cache;
-
- /**
- * Returns the PluginManager singleton instance.
- */
- public static function getInstance ()
- {
- static $instance;
-
- if (isset($instance)) {
- return $instance;
- }
-
- return $instance = new PluginManager();
- }
-
- /**
- * Initialize a new PluginManager instance.
- */
- private function __construct ()
- {
- $this->readPluginInfos();
- $this->plugin_cache = [];
-
- $this->plugins_activated_cache = new StudipCachedArray('/PluginActivations');
- }
-
- /**
- * Comparison function used to order plugins by position.
- */
- private static function positionCompare ($plugin1, $plugin2)
- {
- return $plugin1['position'] - $plugin2['position'];
- }
-
- /**
- * Read meta data for all plugins registered in the data base.
- */
- private function readPluginInfos ()
- {
- $db = DBManager::get();
- $this->plugins = [];
-
- $result = $db->query('SELECT * FROM plugins ORDER BY pluginname');
-
- foreach ($result as $plugin) {
- $id = (int) $plugin['pluginid'];
-
- $this->plugins[$id] = [
- 'id' => $id,
- 'name' => $plugin['pluginname'],
- 'class' => $plugin['pluginclassname'],
- 'path' => $plugin['pluginpath'],
- 'type' => explode(',', $plugin['plugintype']),
- 'enabled' => $plugin['enabled'] === 'yes',
- 'position' => $plugin['navigationpos'],
- 'depends' => (int) $plugin['dependentonid'],
- 'core' => $plugin['pluginpath'] === '',
- 'automatic_update_url' => $plugin['automatic_update_url'],
- 'automatic_update_secret' => $plugin['automatic_update_secret'],
- 'description' => $plugin['description'],
- 'description_mode' => $plugin['description_mode'] ?? null,
- 'highlight_until' => $plugin['highlight_until'] ?? null,
- 'highlight_text' => $plugin['highlight_text'] ?? null,
- ];
- }
- }
-
- /**
- * @addtogroup notifications
- *
- * Enabling or disabling a plugin triggers a PluginDidEnable or
- * respectively PluginDidDisable notification. The plugin's ID
- * is transmitted as subject of the notification.
- */
- /**
- * Set the enabled/disabled status of the given plugin.
- *
- * If the plugin implements the method "onEnable" or "onDisable", this
- * method will be called accordingly. If the method returns false or
- * throws and exception, the plugin's activation state is not updated.
- *
- * @param int $id id of the plugin
- * @param bool $enabled plugin status (true or false)
- * @param bool $force force (de)activation regardless of the result
- * of on(en|dis)able
- * @return bool indicating whether the plugin was updated or null if the
- * passed state equals the current state or if the plugin is
- * missing.
- */
- public function setPluginEnabled ($id, $enabled, $force = false)
- {
- $info = $this->getPluginInfoById($id);
- $plugin_class = null;
-
- // Plugin is not present or no changes
- if (!$info || $info['enabled'] == $enabled) {
- return null;
- }
-
- if ($info['core'] || !$this->isPluginsDisabled()) {
- $plugin_class = $this->loadPlugin($info['class'], $info['path']);
- }
-
- if ($plugin_class) {
- $method = $enabled ? 'onEnable' : 'onDisable';
- $result = $plugin_class->getMethod($method)->invoke(null, $id);
-
- // if callback returns false, don't enable or disable the plugin
- if ($result === false && !$force) {
- return false;
- }
- }
-
- // Update plugin
- $state = $enabled ? 'yes' : 'no';
-
- $query = "UPDATE plugins SET enabled = ? WHERE pluginid = ?";
- DBManager::get()->execute($query, [$state, $id]);
-
- $this->plugins[$id]['enabled'] = (boolean) $enabled;
-
- NotificationCenter::postNotification(
- $enabled ? 'PluginDidEnable' : 'PluginDidDisable',
- $id
- );
-
- return true;
- }
-
- /**
- * Set the navigation position of the given plugin.
- *
- * @param int $id id of the plugin
- * @param int $position plugin navigation position
- * @return bool indicating whether any change occured
- */
- public function setPluginPosition ($id, $position)
- {
- $info = $this->getPluginInfoById($id);
- $position = (int) $position;
-
- if (!$info || $info['position'] == $position) {
- return false;
- }
-
- $query = "UPDATE plugins SET navigationpos = ? WHERE pluginid = ?";
- DBManager::get()->execute($query, [$position, $id]);
-
- $this->plugins[$id]['position'] = $position;
- $this->readPluginInfos();
-
- return true;
- }
-
- /**
- * Get the activation status of a plugin in the given context.
- * This also checks the plugin default activations and sem_class-settings.
- *
- * @param int $id id of the plugin
- * @param string $context range id
- * @returns bool
- */
- public function isPluginActivated ($id, $context)
- {
- if (!$context) {
- return null;
- }
- if (!isset($this->plugins_activated_cache[$context])) {
- $query = "SELECT plugin_id, 1 as state
- FROM tools_activated
- WHERE range_id = ?";
- $statement = DBManager::get()->prepare($query);
- $statement->execute([$context]);
- $this->plugins_activated_cache[$context] = $statement->fetchGrouped(PDO::FETCH_COLUMN);
- }
- return isset($this->plugins_activated_cache[$context][$id]);
- }
-
- /**
- * Get the activation status of a plugin for the given user.
- * This also checks the plugin default activations and sem_class-settings.
- *
- * @param int $pluginId id of the plugin
- * @param string $userId id of the user
- */
- public function isPluginActivatedForUser($pluginId, $userId)
- {
- if (!$userId) {
- $userId = $GLOBALS['user']->id;
- }
- if (!isset($this->plugins_activated_cache[$userId])) {
- $query = "SELECT pluginid, state
- FROM plugins_activated
- WHERE range_type = 'user'
- AND range_id = ?";
- $statement = DBManager::get()->prepare($query);
- $statement->execute([$userId]);
- $this->plugins_activated_cache[$userId] = $statement->fetchGrouped(PDO::FETCH_COLUMN);
- }
- $state = $this->plugins_activated_cache[$userId][$pluginId] ?? null;
- if ($state === null) {
- $activated = (bool) Config::get()->HOMEPAGEPLUGIN_DEFAULT_ACTIVATION;
- } else {
- $activated = (bool) $state;
- }
-
- return $activated;
- }
-
- /**
- * Sets the activation status of a plugin in the given context.
- *
- * @param int $id id of the plugin
- * @param string $rangeId context range id
- * @param bool $active plugin status (true or false)
- */
- public function setPluginActivated ($id, $rangeId, $active)
- {
- unset($this->plugins_activated_cache[$rangeId]);
- $activation = ToolActivation::find([$rangeId, $id]);
- if (!$activation) {
- $range = get_object_by_range_id($rangeId);
- $activation = new ToolActivation();
- $activation->range_id = $rangeId;
- $activation->plugin_id = $id;
- $activation->range_type = $range->getRangeType();
- }
- $plugin = $this->getPluginById($id);
-
- if ($active) {
- call_user_func([get_class($plugin), 'onActivation'], $id, $rangeId);
- StudipLog::log('PLUGIN_ENABLE', $rangeId, $id, User::findCurrent()->id);
- NotificationCenter::postNotification('PluginDidActivate', $rangeId, $id);
- return $activation->store();
- } else {
- call_user_func([get_class($plugin), 'onDeactivation'], $id, $rangeId);
- StudipLog::log('PLUGIN_DISABLE', $rangeId, $id, User::findCurrent()->id);
- NotificationCenter::postNotification('PluginDidDeactivate', $rangeId, $id);
- return $activation->delete();
- }
- }
-
- /**
- * Sets the activation status of a plugin in the given context.
- *
- * @param int $pluginid id of the plugin
- * @param string $user_id user id
- * @param bool $active plugin status (true or false)
- */
- public function setPluginActivatedForUser($pluginid, $user_id, $active)
- {
- $db = DBManager::get();
- $state = $active ? 1 : 0;
- unset($this->plugins_activated_cache[$user_id]);
-
- $query = "REPLACE INTO plugins_activated (pluginid, range_type, range_id, state)
- VALUES (?, 'user', ?, ?)";
- $result = $db->execute($query, [$pluginid, $user_id, $state]);
-
- if ($result > 0) {
- $plugin = $this->getPluginById($pluginid);
- if ($active) {
- call_user_func([get_class($plugin), 'onActivation'], $pluginid, $user_id);
- } else {
- call_user_func([get_class($plugin), 'onDeactivation'], $pluginid, $user_id);
- }
- }
-
- return $result;
- }
-
- /**
- * Deactivate all plugins for the given range.
- *
- * @param string $range_type Type of range (sem, inst or user)
- * @param string $range_id Id of range
- * @return int number of deactivated/removed plugins for range
- */
- public function deactivateAllPluginsForRange($range_type, $range_id)
- {
- unset($this->plugins_activated_cache[$range_id]);
-
- $query = "DELETE FROM `plugins_activated`
- WHERE `range_type` = :range_type
- AND `range_id` = :range_id";
- $statement = DBManager::get()->prepare($query);
- $statement->bindValue(':range_type', $range_type);
- $statement->bindValue(':range_id', $range_id);
- $statement->execute();
-
- return $statement->rowCount();
- }
-
- /**
- * Disable loading of all non-core plugins for the current session.
- *
- * @param bool $status true: disable non-core plugins
- */
- public function setPluginsDisabled($status)
- {
- $_SESSION['plugins_disabled'] = (bool) $status;
- }
-
- /**
- * Check whether loading of non-core plugins is currently disabled.
- */
- public function isPluginsDisabled()
- {
- return $_SESSION['plugins_disabled'] ?? false;
- }
-
- /**
- * Load a plugin class from the given file system path and
- * return the ReflectionClass instance for the plugin.
- *
- * @param string $class plugin class name
- * @param string $path plugin relative path
- */
- private function loadPlugin ($class, $path)
- {
- if ($path) {
- $basepath = Config::get()->PLUGINS_PATH;
- } else {
- $basepath = $GLOBALS['STUDIP_BASE_PATH'];
- $path = 'lib/modules';
- }
-
- $pluginfile = $basepath.'/'.$path.'/'.$class.'.class.php';
-
- if (!file_exists($pluginfile)) {
- $pluginfile = $basepath.'/'.$path.'/'.$class.'.php';
-
- if (!file_exists($pluginfile)) {
- return null;
- }
- }
-
- require_once $pluginfile;
-
- return new ReflectionClass($class);
- }
-
- /**
- * Determine the type of a plugin to be installed.
- *
- * @param string $class plugin class name
- * @param string $path plugin relative path
- */
- private function getPluginType ($class, $path)
- {
- $plugin_class = $this->loadPlugin($class, $path);
- $types = [];
-
- if ($plugin_class) {
- $plugin_base = new ReflectionClass('StudIPPlugin');
- $interfaces = $plugin_class->getInterfaces();
-
- if ($plugin_class->isSubclassOf($plugin_base)) {
- foreach ($interfaces as $interface) {
- $types[] = $interface->getName();
- }
- }
- }
-
- sort($types);
-
- return $types;
- }
-
- /**
- * Register a new plugin or update an existing plugin entry in the
- * data base. Returns the id of the new or updated plugin.
- *
- * @param string $name plugin name
- * @param string $class plugin class name
- * @param string $path plugin relative path
- * @param int $depends id of plugin this plugin depends on
- */
- public function registerPlugin ($name, $class, $path, $depends = null)
- {
- $db = DBManager::get();
- $info = $this->getPluginInfo($class);
- $type = $this->getPluginType($class, $path);
- $position = 1;
-
- // plugin must implement at least one interface
- if (count($type) == 0) {
- throw new Exception(_("Plugin implementiert kein gültiges Interface."));
- }
-
- if ($info) {
- $id = $info['id'];
- $sql = 'UPDATE plugins SET pluginname = ?, pluginpath = ?,
- plugintype = ? WHERE pluginid = ?';
- $stmt = $db->prepare($sql);
- $stmt->execute([$name, $path, join(',', $type), $id]);
-
- $this->plugins[$id]['name'] = $name;
- $this->plugins[$id]['path'] = $path;
- $this->plugins[$id]['type'] = $type;
-
- return $id;
- }
-
- foreach ($this->plugins as $plugin) {
- $common_types = array_intersect($type, $plugin['type']);
-
- if (count($common_types) > 0 && $plugin['position'] >= $position) {
- $position = $plugin['position'] + 1;
- }
- }
-
- $sql = 'INSERT INTO plugins (
- pluginname, pluginclassname, pluginpath,
- plugintype, navigationpos, dependentonid
- ) VALUES (?,?,?,?,?,?)';
- $stmt = $db->prepare($sql);
- $stmt->execute([$name, $class, $path, join(',', $type), $position, $depends]);
- $id = $db->lastInsertId();
-
- $this->plugins[$id] = [
- 'id' => $id,
- 'name' => $name,
- 'class' => $class,
- 'path' => $path,
- 'type' => $type,
- 'enabled' => false,
- 'position' => $position,
- 'depends' => $depends
- ];
-
- $this->readPluginInfos();
-
- $db->exec("INSERT INTO roles_plugins (roleid, pluginid)
- SELECT roleid, $id FROM roles WHERE `system` = 'y' AND rolename != 'Nobody'");
-
- return $id;
- }
-
- /**
- * Remove registration for the given plugin from the data base.
- *
- * @param int $id id of the plugin
- */
- public function unregisterPlugin ($id)
- {
- $info = $this->getPluginInfoById($id);
-
- if ($info) {
- $db = DBManager::get();
-
- $db->execute("DELETE FROM plugins WHERE pluginid = ?", [$id]);
- $db->execute("DELETE FROM plugins_activated WHERE pluginid = ?", [$id]);
- $db->execute("DELETE FROM roles_plugins WHERE pluginid = ?", [$id]);
-
- unset($this->plugins[$id]);
-
- unset($this->plugins_activated_cache[$id]);
- }
- }
-
- /**
- * Get meta data for the plugin specified by plugin class name.
- *
- * @param string $class class name of plugin
- */
- public function getPluginInfo ($class)
- {
- foreach ($this->plugins as $plugin) {
- if (strcasecmp($plugin['class'], $class) == 0) {
- return $plugin;
- }
- }
-
- return null;
- }
-
- /**
- * Get meta data for the plugin specified by plugin id.
- *
- * @param int $id id of the plugin
- */
- public function getPluginInfoById ($id)
- {
- if (isset($this->plugins[$id])) {
- return $this->plugins[$id];
- }
-
- return null;
- }
-
- /**
- * Get meta data for all plugins of the specified type. A type of null
- * returns meta data for all installed plugins.
- *
- * @param string $type plugin type or null (all types)
- */
- public function getPluginInfos ($type = null)
- {
- $result = [];
-
- foreach ($this->plugins as $id => $plugin) {
- if ($type === null || in_array($type, $plugin['type'])) {
- $result[$id] = $plugin;
- }
- }
-
- return $result;
- }
-
- /**
- * Check user access permission for the given plugin.
- *
- * @param array $plugin plugin meta data
- * @param string $user_id id of user
- * @return bool
- */
- protected function checkUserAccess ($plugin, $user_id)
- {
- if (!$plugin['enabled']) {
- return false;
- }
-
- $plugin_roles = RolePersistence::getAssignedPluginRoles($plugin['id']);
- $user_roles = RolePersistence::getAssignedRoles($user_id, true);
-
- foreach ($plugin_roles as $plugin_role) {
- foreach ($user_roles as $user_role) {
- if ($plugin_role->getRoleid() === $user_role->getRoleid()) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Get instance of the plugin specified by plugin meta data.
- *
- * @param array $plugin_info plugin meta data
- * @return object
- */
- protected function getCachedPlugin ($plugin_info)
- {
- $class = $plugin_info['class'];
- $path = $plugin_info['path'];
- $plugin_class = '';
- $plugin = null;
-
- if (isset($this->plugin_cache[$class])) {
- return $this->plugin_cache[$class];
- }
-
- if ($plugin_info['core'] || !$this->isPluginsDisabled()) {
- $plugin_class = $this->loadPlugin($class, $path);
- }
-
- if ($plugin_class) {
- $plugin = $plugin_class->newInstance();
- }
-
- return $this->plugin_cache[$class] = $plugin;
- }
-
- /**
- * Get instance of the plugin specified by plugin class name.
- *
- * @param string $class class name of plugin
- * @return object
- */
- public function getPlugin ($class)
- {
- $user = $GLOBALS['user']->id;
- $plugin_info = $this->getPluginInfo($class);
- $plugin = null;
-
- if (isset($plugin_info) && $this->checkUserAccess($plugin_info, $user)) {
- $plugin = $this->getCachedPlugin($plugin_info);
- }
-
- return $plugin;
- }
-
- /**
- * Get instance of the plugin specified by plugin id.
- *
- * @param int $id id of the plugin
- * @return object $plugin
- */
- public function getPluginById ($id)
- {
- $user = $GLOBALS['user']->id;
- $plugin_info = $this->getPluginInfoById($id);
- $plugin = null;
-
- if (isset($plugin_info) && $this->checkUserAccess($plugin_info, $user)) {
- $plugin = $this->getCachedPlugin($plugin_info);
- }
-
- return $plugin;
- }
-
- /**
- * Get instances of all plugins of the specified type. A type of null
- * returns all enabled plugins. The optional context parameter can be
- * used to get only plugins that are activated in the given context.
- *
- * @param string $type plugin type or null (all types)
- * @param string $context context range id (optional)
- */
- public function getPlugins ($type, $context = null)
- {
- $user = isset($GLOBALS['user']) ? $GLOBALS['user']->id : 'nobody';
- $plugin_info = $this->getPluginInfos($type);
- $plugins = [];
-
- usort($plugin_info, [self::class, 'positionCompare']);
-
- foreach ($plugin_info as $info) {
- $activated = $context == null
- || $this->isPluginActivated($info['id'], $context);
-
- if ($this->checkUserAccess($info, $user) && $activated) {
- $plugin = $this->getCachedPlugin($info);
-
- if ($plugin !== null) {
- $plugins[] = $plugin;
- }
- }
- }
-
- return $plugins;
- }
-
- /**
- * Read the manifest of the plugin in the given directory.
- * Returns null if the manifest cannot be found.
- *
- * @return array containing the manifest information
- */
- public function getPluginManifest($plugindir)
- {
- if (!file_exists($plugindir . '/plugin.manifest')) {
- return null;
- }
- $manifest = file($plugindir . '/plugin.manifest');
- $result = [];
-
- if ($manifest === false) {
- return null;
- }
-
- foreach ($manifest as $line) {
- $key_and_value = explode('=', $line);
- $key = trim($key_and_value[0]);
- $value = trim($key_and_value[1] ?? '');
-
- // skip empty lines and comments
- if ($key === '' || $key[0] === '#') {
- continue;
- }
-
- $key_array = explode('.',$key,2);
- if(count($key_array) > 1){
- if($key_array[0] === 'screenshots'){
- $screenshot_data['source'] = $key_array[1];
- $screenshot_data['title'] = $value;
- $result['screenshots']['pictures'][] = $screenshot_data;
- }
- } elseif($key === 'screenshots') {
- $result['screenshots']['path'] = $value;
- } elseif ($key === 'pluginclassname' && isset($result[$key])) {
- $result['additionalclasses'][] = $value;
- } elseif ($key === 'screenshot' && isset($result[$key])) {
- $result['additionalscreenshots'][] = $value;
- } else {
- $result[$key] = $value;
- }
- }
-
- return $result;
- }
-}