diff options
Diffstat (limited to 'lib/classes/StudipLog.php')
| -rw-r--r-- | lib/classes/StudipLog.php | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/lib/classes/StudipLog.php b/lib/classes/StudipLog.php new file mode 100644 index 0000000..7a520c9 --- /dev/null +++ b/lib/classes/StudipLog.php @@ -0,0 +1,380 @@ +<?php +/** + * StudipLog + * Internal API for the Stud.IP logging functions. + * + * 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 Peter Thienel <thienel@data-quest.de> + * @copyright 2013 Stud.IP Core-Group + * @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2 + * @category Stud.IP + * @since 3.0 + */ + +class StudipLog +{ + /** + * Magic log, intercepts all undefined static method calls + * called method name must be the name of a log action + * + * @param string $name + * @param array $arguments + * @return boolean True if event was written or false if logging is disabled + */ + public static function __callStatic($name, $arguments) + { + $log_action_name = mb_strtoupper($name); + $log_action = LogAction::findByName($log_action_name); + if ($log_action) { + return call_user_func_array('StudipLog::log', array_merge([$log_action_name], $arguments)); + } + throw new BadMethodCallException('Unknown method called: ' + . $log_action_name); + } + + /** + * Logs an event to the database after a certain action took place along with + * the ids of the range object the action possibly affected. You can provide + * additional info as well as debug information. + * + * @param String $action_name Name of the action that took place + * @param mixed $affected Range id that was affected by the action, if any + * @param mixed $coaffected Range id that was possibly affected as well + * @param mixed $info Information to add to the event + * @param mixed $dbg_info Debug information to add to the event + * @param mixed $user_id Provide null for the current user id + **/ + public static function log( + $action_name, + $affected = null, + $coaffected = null, + $info = null, + $dbg_info = null, + $user_id = null + ) { + if (!Config::get()->LOG_ENABLE) { + return false; + } + + // automagically set current user as agent + if (!$user_id) { + $user_id = $GLOBALS['user']->id; + } + + $log_action = LogAction::findOneByName($action_name); + if (!$log_action) { + // Action doesn't exist -> LOG_ERROR + $debug = sprintf( + 'StudipLog::log(%s,%s,%s,%s,%s) for user %s', + $action_name, + $affected, + $coaffected, + $info, + $dbg_info, + $user_id + ); + self::log('LOG_ERROR', null, null, null, $debug); + return false; + } + + if (!$log_action->isActive()) { + return false; + } + + $log_event = new LogEvent(); + $log_event->user_id = $user_id; + $log_event->action_id = $log_action->getId(); + $log_event->affected_range_id = $affected; + $log_event->coaffected_range_id = $coaffected; + $log_event->info = $info; + $log_event->dbg_info = $dbg_info; + $log_event->store(); + return true; + } + + /** + * Registers a new log action in database. + * Use this function to register log actions for Stud.IP core objects. + * + * @param string $name The name of the action. + * @param string $description The action's description. + * @param string $info_template The template + * @param string $class Name of the core class. + */ + public static function registerAction($name, $description, $info_template, + $class) + { + $action = new LogAction(); + $action->name = $name; + $action->description = $description; + $action->info_template = $info_template; + $action->class = $class; + $action->type = 'core'; + $action->store(); + } + + /** + * Registers a new log action in database. + * Use this function to register log actions for plugin classes. + * + * @param string $name The name of the action. + * @param string $description The action's description. + * @param string $info_template The template + * @param string $plugin_class_name Name of the plugin class. + */ + public static function registerActionPlugin($name, $description, + $info_template, $plugin_class_name) + { + $action = new LogAction(); + $action->name = $name; + $action->description = $description; + $action->info_template = $info_template; + $action->class = $plugin_class_name; + $action->type = 'plugin'; + $action->store(); + } + + /** + * Registers a new log action in database. + * Use this function to register log actions for arbitrary objects. + * + * @param string $name The name of the action. + * @param string $description The action's description. + * @param string $info_template The template + * @param string $filename Path to the file with the class (relative + * to Stud.IP root). + * @param string $class Name of class to be logged. + */ + public static function registerActionFile($name, $description, + $info_template, $filename, $class) + { + $path_file = $GLOBALS['STUDIP_BASE_PATH'] . '/' . $filename; + if (!file_exists($path_file)) { + $message = sprintf('Task class file "%s" does not exist.', + $path_file); + throw new InvalidArgumentException($message); + } + $action = new LogAction(); + $action->name = $name; + $action->description = $description; + $action->info_template = $info_template; + $action->filename = $path_file; + $action->class = $class; + $action->type = 'file'; + $action->store(); + } + + /** + * Removes the action from database. + * Deletes all related log events also. + * + * @param string $name The name of the log action. + * @return mixed Number of deleted objects or false if action is unknown. + */ + public static function unregisterAction($name) + { + $action = LogAction::findOneByName($name); + if ($action) { + return $action->delete(); + } + return false; + } + + /** + * Finds all seminars by given search string. Searches for the name of + * existing or already deleted seminars. + * + * @param string $needle The needle to search for. + * @return array + */ + public static function searchSeminar($needle) + { + $result = []; + + // search for active seminars + $courses = Course::findBySQL("VeranstaltungsNummer LIKE CONCAT('%', :needle, '%') + OR seminare.Name LIKE CONCAT('%', :needle, '%') ORDER BY start_time DESC", + [':needle' => $needle]); + + foreach ($courses as $course) { + $title = sprintf('%s %s (%s)', + $course->VeranstaltungsNummer, + my_substr($course->name, 0, 40), + $course->start_semester->name); + $result[] = [$course->getId(), $title]; + } + + // search deleted seminars + // SemName and Number is part of info field, old id (still in DB) is in affected column + $log_action_ids_archived_seminar = SimpleORMapCollection::createFromArray( + LogAction::findBySQL( + "name IN ('SEM_ARCHIVE', 'SEM_DELETE_FROM_ARCHIVE')")) + ->pluck('action_id'); + $log_events_archived_seminar = LogEvent::findBySQL("info LIKE CONCAT('%', ?, '%') + AND action_id IN (?) ", + [$needle, $log_action_ids_archived_seminar]); + foreach ($log_events_archived_seminar as $log_event) { + $title = sprintf('%s (%s)', my_substr($log_event->info, 0, 40), _('gelöscht')); + $result[] = [$log_event->affected_range_id, $title]; + } + + return $result; + } + + /** + * Finds all institutes by given search string. Searches for the name of + * existing or already deleted institutes. + * + * @param type $needle The needle to search for. + * @return array + */ + public static function searchInstitute($needle) + { + $result = []; + + $institutes = Institute::findBySQL( + "name LIKE CONCAT('%', ?, '%') ORDER BY name", [$needle]); + foreach ($institutes as $institute) { + $result[] = [$institute->getId(), my_substr($institute->name, 0, 28)]; + } + + // search for deleted institutes + // Name of deleted institute is part of info field, + // old id (still in DB) is in affected column + $log_action_delete_institute = LogAction::findOneByName('INST_DEL'); + $log_events_delete_institute = LogEvent::findBySQL( + "action_id = ? AND info LIKE CONCAT('%', ?, '%')", + [$log_action_delete_institute->getId(), $needle]); + foreach ($log_events_delete_institute as $log_event) { + $title = sprintf('%s (%s)', $log_event->info, _('gelöscht')); + $result[] = [$log_event->affected_range_id, $title]; + } + + return $result; + } + + /** + * Finds all users by given search string. Searches for the users id, + * part of the name or the username. + * + * @param type $needle The needle to search for. + * @return array + */ + public static function searchUser($needle) + { + $users = User::findBySQL( + "Nachname LIKE CONCAT('%', :needle, '%') + OR Vorname LIKE CONCAT('%', :needle, '%') + OR CONCAT(Nachname, ', ', Vorname) LIKE CONCAT('%', :needle, '%') + OR CONCAT(Vorname, ' ', Nachname) LIKE CONCAT('%', :needle, '%') + OR username LIKE CONCAT('%', :needle, '%') + ORDER BY Nachname DESC, Vorname DESC", + [':needle' => $needle] + ); + + $result = []; + foreach ($users as $user) { + $name = sprintf( + '%s (%s)', + my_substr($user->getFullName(), 0, 20), + $user->username + ); + $result[] = [$user->getId(), $name]; + } + + // search for deleted users + // + // The name of the user is part of info field, + // old id (still in DB) is in affected column. + // + // The log action "USER_DEL" was removed from the list of initially + // registered log actions in the past. + // Search for the user if it is still in database. If not, the search + // for deleted users is not possible. + $log_action_deleted_user = LogAction::findOneByName('USER_DEL'); + if ($log_action_deleted_user) { + $log_events_deleted_user = LogEvent::findBySQL( + "action_id = ? AND info LIKE CONCAT('%', ?, '%')", + [$log_action_deleted_user->getId(), $needle] + ); + foreach ($log_events_deleted_user as $log_event) { + $name = sprintf('%s (%s)', $log_event->info, _('gelöscht')); + $result[] = [$log_event->affected_range_id, $name]; + } + } + + return $result; + } + + /** + * Finds all resources by given search string. The search string can be + * either a resource id or part of the name. + * + * @param string $needle The needle to search for. + * @return array + */ + public static function searchResource($needle) + { + $result = []; + + $query = "SELECT id, name FROM resources WHERE name LIKE CONCAT('%', ?, '%') ORDER by name"; + $statement = DBManager::get()->prepare($query); + $statement->execute([$needle]); + + while ($row = $statement->fetch(PDO::FETCH_ASSOC)) { + $result[] = [$row['id'], my_substr($row['name'], 0, 30)]; + } + + return $result; + } + + /** + * Finds all objects related to the given action by search string. + * The search string can be either a part of the name or the id + * of the object. + * + * Calls the method Loggable::logSearch() to retrieve the result. + * + * @param string $needle + * @param type $action_id + * @return type + */ + public static function searchObjectByAction($needle, $action_id) + { + $action = LogAction::find($action_id); + + if ($action) { + switch ($action->type) { + case 'plugin': + $plugin_manager = PluginManager::getInstance(); + $plugin_info = $plugin_manager->getPluginInfo($action->class); + $class_name = $plugin_info['class']; + $plugin = $plugin_manager->getPlugin($class_name); + if ($plugin instanceof Loggable) { + return $class_name::logSearch($needle, $action->name); + } + break; + case 'file': + if (!file_exists($action->filename)) { + require_once($action->filename); + $class_name = $action->class; + if ($class_name instanceof Loggable) { + return $class_name::logSearch($needle, $action->name); + } + } + break; + case 'core': + $class_name = $action->class; + $interfaces = class_implements($class_name); + if (isset($interfaces['Loggable'])) { + return $class_name::logSearch($needle, $action->name); + } + } + } + return []; + } +} |
