* @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 * * @property int $id alias column for event_id * @property int $event_id database column * @property string $user_id database column * @property string $action_id database column * @property string|null $affected_range_id database column * @property string|null $coaffected_range_id database column * @property string|null $info database column * @property string|null $dbg_info database column * @property int $mkdate database column * @property LogAction $action belongs_to LogAction * @property User $user belongs_to User */ class LogEvent extends SimpleORMap implements PrivacyObject { protected static function configure($config = []) { $config['db_table'] = 'log_events'; $config['belongs_to']['action'] = [ 'class_name' => LogAction::class, 'foreign_key' => 'action_id', ]; $config['belongs_to']['user'] = [ 'class_name' => User::class, 'foreign_key' => 'user_id', ]; parent::configure($config); } protected $formatted_text = ''; /** * Returns the number of log events counted by actions as an array where * the ey is the action id and the value is the number of events for * this action. * * @return array Number of loge events for all actions */ public static function countByActions() { $query = "SELECT action_id, COUNT(*) FROM log_events GROUP BY action_id"; $statement = DBManager::get()->query($query); return $statement->fetchGrouped(PDO::FETCH_COLUMN); } /** * Deletes all expired events. * * @return int Number of deleted events. */ public static function deleteExpired() { $sql = "DELETE log_events FROM log_events JOIN log_actions USING(action_id) WHERE log_actions.expires > 0 AND log_events.mkdate + log_actions.expires < UNIX_TIMESTAMP()"; return DBManager::get()->exec($sql); } /** * Returns the formatted log event. Fills the action template with data * of this event. * * @return string The formatted log event. */ public function formatEvent() { $text = $this->formatObject(); $patterns = [ '/%affected/', '/%coaffected/', '/%info/', '/%dbg_info/' ]; $replacements = [ $this->affected_range_id, $this->coaffected_range_id, htmlReady($this->info), htmlReady($this->dbg_info) ]; $replace_callbacks = [ '/%sem\(%affected\)/', '/%sem\(%coaffected\)/', '/%studyarea\(%affected\)/', '/%studyarea\(%coaffected\)/', '/%res\(%affected\)/', '/%res\(%coaffected\)/', '/%inst\(%affected\)/', '/%inst\(%coaffected\)/', '/%user\(%affected\)/', '/%user\(%coaffected\)/', '/%user/', '/%singledate\(%affected\)/', '/%semester\(%coaffected\)/', '/%plugin\(%coaffected\)/', '/%group\(%coaffected\)/', ]; $text = preg_replace_callback($replace_callbacks, [$this, 'formatCallback'], $text); return preg_replace($patterns, $replacements, $text); } /** * @param $m * @return string */ protected function formatCallback($m) { $map = [ 'sem' => 'Seminar', 'res' => 'Resource', 'inst' => 'Institute', 'user' => 'Username', 'group' => 'Statusgruppe' ]; $ret = ''; if (preg_match_all('/%([a-z]+)/', $m[0], $found)) { if (isset($found[1][0])) { $funcname = 'format' . (isset($map[$found[1][0]]) ? $map[$found[1][0]] : $found[1][0]); if (isset($found[1][1])) { $param = $found[1][1] . '_range_id'; } else { $param = 'user_id'; } if (is_callable([$this, $funcname])) { $ret = call_user_func([$this, $funcname], $param); } } } return $ret; } /** * Returns the name of the resource for the resource id found in the * given field or the resource id if the resource is unknown. * * @param string $field The name of the table field. * @return string The name of the resource or resource id. */ protected function formatResource($field) { $resource = Resource::find($this->$field); if ($resource && $resource->name) { return sprintf( '%s', Resource::getLinkForAction('show', $resource->id), htmlReady($resource->name) ); } return $this->$field; } /** * Returns the name of the user with the id found in the given field. * * @param string $field The name of the table field. * @return string The name of the user. */ protected function formatUsername($field) { return '' . htmlReady(get_fullname($this->$field)) . ''; } /** * Returns the name of the seminar for the id found in the given * field or the id if the seminar is unknown. * * @param string $field The name of the table field. * @return string The name of seminar or the id. */ protected function formatSeminar($field) { $course = Course::find($this->$field); if (!$course) { return $this->$field; } return sprintf('%s %s (%s)', URLHelper::getLink('dispatch.php/course/details', ['sem_id' => $course->getId()]), htmlReady($course->VeranstaltungsNummer), htmlReady(my_substr($course->name, 0, 100)), htmlReady($course->start_semester->name)); } /** * Returns the name of the institute for the id found in the given * field or the id if the institute is unknown. * * @param string $field The name of the table field. * @return string The name of institute or the id. */ protected function formatInstitute($field) { $institute = Institute::find($this->$field); if (!$institute) { return $this->$field; } return sprintf('%s', URLHelper::getLink('dispatch.php/institute/overview', ['auswahl' => $institute->getId()]), htmlReady(my_substr($institute->name, 0, 100))); } /** * Returns the name of the study area for the id found in the given * field or the id if the study area is unknown. * * @param string $field The name of the table field. * @return string The name of seminar or the id. */ protected function formatStudyarea($field) { $study_area = StudipStudyArea::find($this->$field); if (!$study_area) { return $this->$field; } return '' . htmlReady($study_area->getPath(' > ')) . ''; } /** * Returns the singledate for the id found in the given field. * * @param string $field The name of the table field. * @return string The singledate. */ protected function formatSingledate($field) { $termin = new SingleDate($this->$field); return '' . $termin->toString() . ''; } /** * Returns the name of the plugin for the id found in the given * field or the id if the plugin is unknown. * * @param string $field The name of the table field. * @return string The name of plugin or the id. */ protected function formatPlugin($field) { $plugin_manager = PluginManager::getInstance(); $plugin_info = $plugin_manager->getPluginInfoById($this->$field); return $plugin_info ? '' . htmlReady($plugin_info['name']) . '' : $this->$field; } /** * Returns the name of the semester for the id found in the given * field or the id if the seminar is unknown. * * @param string $field The name of the table field. * @return string The name of semester or the id. */ protected function formatSemester($field) { $all_semester = Semester::findAllVisible(false); foreach ($all_semester as $val) { if (!empty($val['beginn']) && ($val['beginn'] == $this->$field)) { return '' . htmlReady($val['name']) . ''; } } return htmlReady($this->$field); } /** * Returns the name of the statusgroup for the id found in the given * field or the id if the group is unknown. * * @param string $field The name of the table field. * @return string The name of statusgruppe or the id. */ protected function formatStatusgruppe($field) { $group = Statusgruppen::find($this->$field); if (!$group) { return $this->$field; } $course = Course::find($group->range_id); return sprintf( '%s', URLHelper::getLink('dispatch.php/course/statusgroups', [ 'contentbox_open' => $group->getId() ]), htmlReady($group->name. ($course ? " (VA: ".$course->name.")" : "")) ); } protected function formatObject() { if ($this->action) { switch ($this->action->type) { case 'plugin': $plugin_manager = PluginManager::getInstance(); $plugin_info = $plugin_manager->getPluginInfo($this->action->class); $class_name = $plugin_info['class']; $plugin = $plugin_manager->getPlugin($class_name); if ($plugin instanceof Loggable) { return $class_name::logFormat($this); } break; case 'file': if (file_exists($this->action->filename)) { require_once $this->action->filename; $class_name = $this->action->class; if ($class_name && in_array(Loggable::class, class_implements($class_name))) { return $class_name::logFormat($this); } } break; case 'core': $class_name = $this->action->class; if ($class_name && in_array(Loggable::class, class_implements($class_name))) { return $class_name::logFormat($this); } break; } } return $this->action->info_template; } /** * 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 static function exportUserData(StoredUserData $storage) { $user_id = $storage->user_id; $templates = []; $query = "SELECT * FROM log_events WHERE :user_id IN (user_id, affected_range_id, coaffected_range_id)"; $log = DBManager::get()->fetchAll($query, [':user_id' => $user_id]); foreach ($log as $pos => $event) { if (!array_key_exists($event['action_id'], $templates)) { $log_action = LogAction::find($event["action_id"]); $templates[$event['action_id']] = $log_action->info_template; } $template = $templates[$event['action_id']]; $log_event = LogEvent::find($event['event_id']); // anonymize $was_censored = false; if ($event['user_id'] && substr_count($template, '%user ') && $event['user_id'] !== $user_id) { $event['user_id'] = preg_replace('/[^w]/', '#', $event['user_id']); $log_event->user_id = $event['user_id']; $was_censored = true; } if ($event['affected_range_id'] && substr_count($template, '%user(%affected)') && $event['affected_range_id'] !== $user_id) { $event['affected_range_id'] = preg_replace('/[^w]/', '#', $event['affected_range_id']); $log_event->affected_range_id = $event['affected_range_id']; $was_censored = true; } if ($event['coaffected_range_id'] && substr_count($template, '%user(%coaffected)') && $event['coaffected_range_id'] !== $user_id) { $event['coaffected_range_id'] = preg_replace('/[^w]/', '#', $event['coaffected_range_id']); $log_event->coaffected_range_id = $event['coaffected_range_id']; $was_censored = true; } //censore possible info if ($was_censored) { if (!empty($event['info'])) { $event['info'] = preg_replace('/[^w]/', '#', $event['info']); } if (!empty($event["dbg_info"])) { $event['dbg_info'] = preg_replace('/[^w]/', '#', $event['dbg_info']); } } $a['readable_entry'] = html_entity_decode(strip_tags(str_replace('
', PHP_EOL, $log_event->formatEvent()))); $log[$pos]= array_merge($a, $event); } if ($log) { $storage->addTabularData(_('Logs'), 'log_events', $log); } } }