aboutsummaryrefslogtreecommitdiff
path: root/lib/activities
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/activities
current code from svn, revision 62608
Diffstat (limited to 'lib/activities')
-rw-r--r--lib/activities/Activity.php192
-rw-r--r--lib/activities/ActivityObserver.php43
-rw-r--r--lib/activities/ActivityProvider.php25
-rw-r--r--lib/activities/Context.php124
-rw-r--r--lib/activities/CourseContext.php83
-rwxr-xr-xlib/activities/CoursewareContext.php56
-rwxr-xr-xlib/activities/CoursewareProvider.php38
-rw-r--r--lib/activities/DocumentsProvider.php131
-rw-r--r--lib/activities/Filter.php89
-rw-r--r--lib/activities/ForumProvider.php54
-rw-r--r--lib/activities/InstituteContext.php80
-rw-r--r--lib/activities/MessageProvider.php82
-rw-r--r--lib/activities/NewsProvider.php134
-rw-r--r--lib/activities/ParticipantsProvider.php84
-rw-r--r--lib/activities/ScheduleProvider.php83
-rw-r--r--lib/activities/Stream.php190
-rw-r--r--lib/activities/SystemContext.php56
-rw-r--r--lib/activities/UserContext.php74
-rw-r--r--lib/activities/WikiProvider.php125
19 files changed, 1743 insertions, 0 deletions
diff --git a/lib/activities/Activity.php b/lib/activities/Activity.php
new file mode 100644
index 0000000..b8ed662
--- /dev/null
+++ b/lib/activities/Activity.php
@@ -0,0 +1,192 @@
+<?php
+
+/**
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @license GPL 2 or later
+ */
+
+namespace Studip\Activity;
+
+class Activity extends \SimpleORMap
+{
+ public
+ $object_url,
+ $object_route;
+
+ private $context_object;
+
+ const GC_MAX_DAYS = 366; // Garbage collector removes activities after 366 days
+
+ private static $allowed_verbs = [
+ 'answered',
+ 'attempted',
+ 'attended',
+ 'completed',
+ 'created',
+ 'deleted',
+ 'edited',
+ 'experienced',
+ 'failed',
+ 'imported',
+ 'interacted',
+ 'passed',
+ 'shared',
+ 'sent',
+ 'voided'
+ ];
+
+ /**
+ * {@inheritdoc}
+ */
+ protected static function configure($config = [])
+ {
+ $config['db_table'] = 'activities';
+ $config['additional_fields']['object_url'] = ['get' => 'getUrlList'];
+ $config['additional_fields']['object_route'] = ['get' => 'getRoute'];
+
+ parent::configure($config);
+ }
+
+ /**
+ * return a string representation for this activity
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->content['content'];
+ }
+
+ /**
+ * set one of the allowed verbs
+ *
+ * @param string $verb
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function setVerb($verb)
+ {
+ if (is_null($verb)) {
+ return;
+ }
+
+ if (in_array($verb, self::$allowed_verbs) === false) {
+ throw new \InvalidArgumentException("That verb is not allowed.");
+ }
+
+ $this->content['verb'] = $verb;
+ }
+
+ /**
+ * Add a url to the list of urls
+ *
+ * @param type $url
+ * @param type $name
+ */
+ public function addUrl($url, $name)
+ {
+ $this->object_url[$url] = $name;
+ }
+
+ /**
+ * Return assoc array of urls
+ * [[url => description]]
+ *
+ * @return Array
+ */
+ public function getUrlList()
+ {
+ return $this->object_url ?: [];
+ }
+
+ /**
+ * Return api route of the content object
+ *
+ * @return string
+ */
+ public function getRoute()
+ {
+ return $this->object_route;
+ }
+
+ public function setContextObject(Context $context)
+ {
+ $this->context_object = $context;
+ }
+
+ public function getContextObject()
+ {
+ return $this->context_object;
+ }
+
+ /**
+ * Returns a format string as placeholder for the object in question
+ * (in a grammatical / lexical sense)
+ *
+ * @return string
+ */
+ public function verbToText()
+ {
+ $translation = [
+ 'answered' => _('beantwortete %s'),
+ 'attempted' => _('versuchte %s'),
+ 'attended' => _('nahm teil an %s'),
+ 'completed' => _('beendete %s'),
+ 'created' => _('erstellte %s'),
+ 'deleted' => _('löschte %s'),
+ 'edited' => _('bearbeitete %s'),
+ 'experienced' => _('erlebte %s'),
+ 'failed' => _('verfehlte %s'),
+ 'imported' => _('importierte %s'),
+ 'interacted' => _('interagierte mit %s'),
+ 'passed' => _('bestand %s'),
+ 'shared' => _('teilte %s'),
+ 'sent' => _('sendete %s'),
+ 'voided' => _('löschte %s')
+ ];
+
+ return ($translation[$this->verb]);
+ }
+
+ /**
+ * Garbage collector for the activities.
+ * Removes all activites older than GC_MAX_DAYS (default: 366).
+ */
+ public static function doGarbageCollect()
+ {
+ $stmt = \DBManager::get()->prepare('DELETE FROM activities WHERE mkdate < ?');
+
+ $stmt->execute([
+ time() - self::GC_MAX_DAYS * 24 * 60 * 60]
+ );
+
+ //Expire Cache
+ \StudipCacheFactory::getCache()->expire('activity/oldest_activity');
+ }
+
+ /**
+ * Returns the oldest existing activity
+ *
+ * @return Array
+ */
+ public static function getOldestActivity()
+ {
+ $cache = \StudipCacheFactory::getCache();
+ $cache_key = 'activity/oldest_activity';
+
+ if (!$activity = unserialize($cache->read($cache_key))) {
+ $activity = self::findBySQL('1 ORDER BY mkdate ASC LIMIT 1');
+
+ if (!empty($activity)) {
+ $cache->write($cache_key, serialize($activity));
+ } else {
+ return false;
+ }
+ }
+
+ return $activity;
+ }
+
+
+}
diff --git a/lib/activities/ActivityObserver.php b/lib/activities/ActivityObserver.php
new file mode 100644
index 0000000..80652cf
--- /dev/null
+++ b/lib/activities/ActivityObserver.php
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @license GPL 2 or later
+ */
+
+
+namespace Studip\Activity;
+
+class ActivityObserver
+{
+ /**
+ * Register for Notifications the providers shall respond to
+ *
+ */
+ public static function initialize()
+ {
+ \NotificationCenter::addObserver('Studip\Activity\MessageProvider', 'postActivity','MessageDidSend');
+
+ // Notifications for ParticipantsProvider
+ \NotificationCenter::addObserver('\Studip\Activity\ParticipantsProvider', 'postActivity','UserDidEnterCourse');
+ \NotificationCenter::addObserver('\Studip\Activity\ParticipantsProvider', 'postActivity','UserDidLeaveCourse');
+
+ //Notifications for DocumentsProvider
+ \NotificationCenter::addObserver('\Studip\Activity\DocumentsProvider', 'postActivity','FileRefDidCreate');
+ \NotificationCenter::addObserver('\Studip\Activity\DocumentsProvider', 'postActivity','FileRefDidUpdate');
+ \NotificationCenter::addObserver('\Studip\Activity\DocumentsProvider', 'postActivity','FileRefDidDelete');
+
+ //Notifications for NewsProvider
+ \NotificationCenter::addObserver('\Studip\Activity\NewsProvider', 'postActivity','StudipNewsDidCreate');
+
+ //Notifications for WikiProvider
+ \NotificationCenter::addObserver('\Studip\Activity\WikiProvider', 'postActivity','WikiPageDidCreate');
+ \NotificationCenter::addObserver('\Studip\Activity\WikiProvider', 'postActivity','WikiPageDidDelete');
+ //this is rather pointless and annoying
+ //\NotificationCenter::addObserver('\Studip\Activity\WikiProvider', 'postActivity','WikiPageDidUpdate');
+
+ //Notifications for ScheduleProvider (Course)
+ \NotificationCenter::addObserver('\Studip\Activity\ScheduleProvider', 'postActivity','CourseDidChangeSchedule');
+ }
+}
diff --git a/lib/activities/ActivityProvider.php b/lib/activities/ActivityProvider.php
new file mode 100644
index 0000000..16d474a
--- /dev/null
+++ b/lib/activities/ActivityProvider.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @license GPL 2 or later
+ */
+
+
+namespace Studip\Activity;
+
+interface ActivityProvider
+{
+ /**
+ * Fill in the url, route and any lengthy content for the passed activity
+ *
+ * @param Studip\Activity\Activity $activity
+ */
+ public function getActivityDetails($activity);
+
+ /**
+ * Human readable name for the current provider to be used in the activity-title
+ */
+ public static function getLexicalField();
+}
diff --git a/lib/activities/Context.php b/lib/activities/Context.php
new file mode 100644
index 0000000..3f84452
--- /dev/null
+++ b/lib/activities/Context.php
@@ -0,0 +1,124 @@
+<?php
+
+/**
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @license GPL 2 or later
+ */
+
+namespace Studip\Activity;
+
+abstract class Context
+{
+ protected
+ $provider,
+ $observer;
+
+
+ /**
+ * return array, listing all active providers in this context
+ *
+ * @return array
+ */
+ abstract protected function getProvider();
+
+ /**
+ * get id denoting the context (user_id, course_id, institute_id, ...)
+ *
+ * @return string
+ */
+ abstract public function getRangeId();
+
+ /**
+ * get type of context (f.e. user, system, course, institute, ...)
+ *
+ * @return string
+ */
+ abstract public function getContextType();
+
+ /**
+ * get type of context (f.e. user, system, course, institute, ...)
+ *
+ * @return string
+ */
+ abstract public function getContextFullname($format = 'default');
+
+ /**
+ * Return user for who wants to watch his and related activities
+ *
+ * @return object a user object
+ */
+ public function getObserver()
+ {
+ return $this->observer;
+ }
+
+ /**
+ * get list of activities as array for the current context
+ *
+ * @param \Studip\Activity\Filter $filter
+ *
+ * @return array
+ */
+ public function getActivities(Filter $filter)
+ {
+ $providers = $this->filterProvider($this->getProvider(), $filter);
+ $activities = Activity::findAndMapBySQL(
+ function ($activity) use ($providers) {
+ if (isset($providers[$activity->provider])) { // provider is available
+ $activity->setContextObject($this);
+ if ($providers[$activity->provider]->getActivityDetails($activity)) {
+ return $activity;
+ }
+ }
+ },
+ 'context = ? AND context_id = ? AND mkdate >= ? AND mkdate <= ? ORDER BY mkdate DESC'
+ ,
+ [$this->getContextType(), $this->getRangeId(), $filter->getStartDate(), $filter->getEndDate()]);
+ return array_filter($activities);
+ }
+
+ /**
+ * Add a provider to this context
+ *
+ * @param string $provider the name for the provider
+ * @param string $class_name the class that belongs to the provider
+ */
+ protected function addProvider($class_name)
+ {
+ $reflectionClass = new \ReflectionClass($class_name);
+ $this->provider[$class_name] = $reflectionClass->newInstanceArgs();
+ }
+
+ /**
+ * Filter the passed the providers to match the passed filter
+ *
+ * @param type $providers
+ * @param \Studip\Activity\Filter $filter
+ * @return type
+ */
+ protected function filterProvider($providers, Filter $filter)
+ {
+ $filtered_providers = [];
+
+ if (empty($filter->getType())) {
+ $filtered_providers = $providers;
+ } else {
+ foreach ($providers as $provider) {
+ $ctype = $this->getContextType();
+ $filtered_classes = $filter->getType()->$ctype;
+
+ if (is_array($filtered_classes)) {
+ foreach ($filtered_classes as $class) {
+ $iclass = 'Studip\\Activity\\' .ucfirst($class) .'Provider';
+ if ($provider instanceof $iclass) {
+ $filtered_providers[$iclass] = $provider;
+ }
+ }
+ }
+ }
+ }
+
+ return $filtered_providers;
+ }
+}
diff --git a/lib/activities/CourseContext.php b/lib/activities/CourseContext.php
new file mode 100644
index 0000000..3822847
--- /dev/null
+++ b/lib/activities/CourseContext.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @license GPL 2 or later
+ */
+
+namespace Studip\Activity;
+
+class CourseContext extends Context
+{
+ private
+ $course;
+
+ /**
+ * create new course-context
+ *
+ * @param string $seminar_id
+ */
+ function __construct($course, $observer)
+ {
+ $this->course = $course;
+ $this->observer = $observer;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getProvider()
+ {
+ if (!$this->provider) {
+ $course = $this->course;
+
+ $module_provider = [
+ 'CoreForum' => 'ForumProvider',
+ 'CoreParticipants' => 'ParticipantsProvider',
+ 'CoreDocuments' => 'DocumentsProvider',
+ 'CoreWiki' => 'WikiProvider',
+ 'CoreSchedule' => 'ScheduleProvider'
+ ];
+
+ foreach ($course->tools as $tool) {
+ $studip_module = $tool->getStudipModule();
+ if($studip_module) {
+ if (isset($module_provider[get_class($studip_module)])) {
+ $this->addProvider('Studip\Activity\\'. $module_provider[get_class($studip_module)]);
+ } elseif ($studip_module instanceof ActivityProvider) {
+ $this->provider[$studip_module->getPluginName()] = $studip_module;
+ }
+ }
+ }
+ //news
+ $this->addProvider('Studip\Activity\NewsProvider');
+ }
+
+ return $this->provider;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRangeId()
+ {
+ return $this->course->id;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getContextType()
+ {
+ return \Context::COURSE;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getContextFullname($format = 'default')
+ {
+ return $this->course->getFullname($format);
+ }
+}
diff --git a/lib/activities/CoursewareContext.php b/lib/activities/CoursewareContext.php
new file mode 100755
index 0000000..a7bd83b
--- /dev/null
+++ b/lib/activities/CoursewareContext.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Studip\Activity;
+
+class CoursewareContext extends Context
+{
+
+ public function __construct($courseware, $observer)
+ {
+ $this->courseware = $courseware;
+ $this->observer = $observer;
+
+ $id = explode('_' , $this->courseware->id);
+ $this->context = $id[0];
+ $this->range_id = $id[1];
+ }
+
+ protected function getProvider()
+ {
+ $this->addProvider('Studip\Activity\CoursewareProvider');
+
+ return $this->provider;
+ }
+
+ public function getRangeId()
+ {
+ return $this->range_id;
+ }
+
+ public function getContextType()
+ {
+ if($this->context == 'user') {
+ return \Context::USER;
+ }
+
+ if ($this->content == 'course') {
+ return \Context::COURSE;
+ }
+ }
+
+ public function getContextFullname($format = 'default')
+ {
+ if($this->context == 'user') {
+ $user = \User::find($this->range_id);
+
+ return $user->getFullname($format);
+ }
+
+ if($this->context == 'course') {
+ $course = \Course::find($this->range_id);
+
+ return $course->getFullname($format);
+ }
+ }
+
+} \ No newline at end of file
diff --git a/lib/activities/CoursewareProvider.php b/lib/activities/CoursewareProvider.php
new file mode 100755
index 0000000..5e5faae
--- /dev/null
+++ b/lib/activities/CoursewareProvider.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Studip\Activity;
+
+
+class CoursewareProvider implements ActivityProvider
+{
+
+ public function getActivityDetails($activity)
+ {
+ $structural_element = \Courseware\StructuralElement::find($activity->object_id);
+ if (!$structural_element) {
+ return false;
+ }
+ $payload = json_decode($structural_element['payload']);
+
+ $activity->content = formatReady($payload['description']);
+
+ if ($activity->context == "course") {
+ $url = \URLHelper::getURL('dispatch.php/course/courseware/?cid='). $activity->context_id . '#/structural_element/' . $structural_element->id;
+ $activity->object_url = [
+ $url => _('Zur Courseware in der Veranstaltung')
+ ];
+ } elseif ($activity->context == "user") {
+ $url = \URLHelper::getURL('dispatch.php/contents/my_contents'). '#/structural_element/' . $structural_element->id;
+ $activity->object_url = [
+ $url => _('Zur eigenen Courseware')
+ ];
+ }
+
+ return true;
+ }
+
+ public static function getLexicalField()
+ {
+ return _('eine Courseware-Aktivität');
+ }
+} \ No newline at end of file
diff --git a/lib/activities/DocumentsProvider.php b/lib/activities/DocumentsProvider.php
new file mode 100644
index 0000000..0a770de
--- /dev/null
+++ b/lib/activities/DocumentsProvider.php
@@ -0,0 +1,131 @@
+<?php
+
+/**
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @license GPL 2 or later
+ */
+
+namespace Studip\Activity;
+
+class DocumentsProvider implements ActivityProvider
+{
+
+ /**
+ * get the details for the passed activity
+ *
+ * @param object $activity the activity to fill with details, passed by reference
+ */
+ public function getActivityDetails($activity)
+ {
+ $activity->content = \htmlReady($activity->content);
+
+ $document = \FileRef::find($activity->object_id);
+
+ // check, if current observer has access to document
+ if (!$document || !$activity->getContextObject() || !$document->folder->getTypedFolder()->isFileDownloadable($document, $activity->getContextObject()->getObserver()->id)) {
+ return false;
+ }
+
+ if ($activity->context == "course") {
+ $url = \URLHelper::getUrl("dispatch.php/course/files/flat?cid={$activity->context_id}");
+ $route = \URLHelper::getURL('api.php/file/' . $activity->object_id, NULL, true);
+
+ $activity->object_url = [
+ $url => _('Zum Dateibereich der Veranstaltung')
+ ];
+ } elseif ($activity->context == "institute") {
+ $url = \URLHelper::getUrl("dispatch.php/institute/files/flat?cid={$activity->context_id}");
+ $route= null;
+
+ $activity->object_url = [
+ $url => _('Zum Dateibereich der Einrichtung')
+ ];
+ }
+
+ $activity->object_route = $route;
+
+ return true;
+ }
+
+ /**
+ * posts an activity for a given notification event
+ *
+ * @param String $event a notification for an activity
+ * @param \FileRef $document information which a relevant for the activity
+ */
+ public static function postActivity($event, $file_ref)
+ {
+ $user_id = $file_ref->user_id;
+ $file_name = $file_ref->name;
+ $course_id = $file_ref->folder->range_id;
+ $file_id = $file_ref->id;
+
+ $type = $file_ref->folder->range_type;
+ if ($type == 'course') {
+ $course = \Course::find($course_id);
+ } elseif ($type == 'institute') {
+ $course = \Institute::find($course_id);
+ }
+
+ if (!isset($course)) {
+ return;
+ }
+
+ if (in_array($event, ['FileRefDidCreate'])) {
+ $verb = 'created';
+ if ($type == 'course') {
+ $summary = _('Die Datei %s wurde von %s in der Veranstaltung "%s" hochgeladen.');
+ } else {
+ $summary = _('Die Datei %s wurde von %s in der Einrichtung "%s" hochgeladen.');
+ }
+ $summary = sprintf($summary,$file_name, get_fullname($user_id) ,$course->name);
+ $mkdate = $file_ref->mkdate;
+ } elseif (in_array($event, ['FileRefDidUpdate'])) {
+ $verb = 'edited';
+ if ($type == 'course') {
+ $summary = _('Die Datei %s wurde von %s in der Veranstaltung "%s" aktualisiert.');
+ } else {
+ $summary = _('Die Datei %s wurde von %s in der Einrichtung "%s" aktualisiert.');
+ }
+ $summary = sprintf($summary,$file_name, get_fullname($user_id), $course->name);
+ $mkdate = $file_ref->chdate;
+ } elseif (in_array($event, ['FileRefDidDelete'])) {
+ $verb = 'voided';
+ if ($type == 'course') {
+ $summary = _('Die Datei %s wurde von %s in der Veranstaltung "%s" gelöscht.');
+ } else {
+ $summary = _('Die Datei %s wurde von %s in der Einrichtung "%s" gelöscht.');
+ }
+ $summary = sprintf($summary,$file_name, get_fullname($user_id), $course->name);
+ $mkdate = $file_ref->chdate;
+ } else {
+ return;
+ }
+
+ if (isset($verb)) {
+ $activity = Activity::create(
+ [
+ 'provider' => __CLASS__,
+ 'context' => $type,
+ 'context_id' => $course_id,
+ 'content' => $summary,
+ 'actor_type' => 'user', // who initiated the activity?
+ 'actor_id' => $user_id, // id of initiator
+ 'verb' => $verb, // the activity type
+ 'object_id' => $file_id, // the id of the referenced object
+ 'object_type' => 'documents', // type of activity object
+ 'mkdate' => $mkdate
+ ]
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getLexicalField()
+ {
+ return _('eine Datei');
+ }
+}
diff --git a/lib/activities/Filter.php b/lib/activities/Filter.php
new file mode 100644
index 0000000..8e1947e
--- /dev/null
+++ b/lib/activities/Filter.php
@@ -0,0 +1,89 @@
+<?php
+/**
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @license GPL 2 or later
+ */
+
+namespace Studip\Activity;
+
+class Filter
+{
+ private
+ $start_date,
+ $end_date,
+ $type,
+ $verb;
+
+ /**
+ *
+ * @param string $start_date
+ */
+ public function setStartDate($start_date)
+ {
+ $this->start_date = $start_date;
+ }
+
+ /**
+ *
+ * @return string
+ */
+ public function getStartDate()
+ {
+ return $this->start_date;
+ }
+
+ /**
+ *
+ * @param string $end_date
+ */
+ public function setEndDate($end_date)
+ {
+ $this->end_date = $end_date;
+ }
+
+ /**
+ *
+ * @return string
+ */
+ public function getEndDate()
+ {
+ return $this->end_date;
+ }
+
+ /**
+ *
+ * @param string $type
+ */
+ public function setType($type)
+ {
+ $this->type = $type;
+ }
+
+ /**
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ *
+ * @return string
+ */
+ public function getVerb()
+ {
+ return $this->verb;
+ }
+
+ /**
+ *
+ * @param string $verb
+ */
+ public function setVerb($verb)
+ {
+ $this->verb = $verb;
+ }
+}
diff --git a/lib/activities/ForumProvider.php b/lib/activities/ForumProvider.php
new file mode 100644
index 0000000..49260c3
--- /dev/null
+++ b/lib/activities/ForumProvider.php
@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @license GPL 2 or later3
+ */
+
+
+namespace Studip\Activity;
+
+require_once 'public/plugins_packages/core/Forum/models/ForumEntry.php';
+
+class ForumProvider implements ActivityProvider
+{
+ /**
+ * get the details for the passed activity
+ *
+ * @param object $activity the activity to fill with details, passed by reference
+ */
+ public function getActivityDetails($activity)
+ {
+ $post = \ForumEntry::getEntry($activity->object_id);
+
+ if (!$post) {
+ return false;
+ }
+
+ $activity->content = formatReady($post['content']);
+
+ $url = \PluginEngine::getURL('CoreForum', [], 'index/index/' . $post['topic_id']
+ .'?cid='. $post['seminar_id'] .'&highlight_topic='. $post['topic_id']
+ .'#'. $post['topic_id']);
+
+ $route = \URLHelper::getURL('api.php/forum_entry/' . $post['topic_id'], NULL, true);
+
+ $activity->object_url = [
+ $url => _('Zum Forum der Veranstaltung')
+ ];
+
+ $activity->object_route = $route;
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getLexicalField()
+ {
+ return _('einen Forenbeitrag');
+ }
+
+}
diff --git a/lib/activities/InstituteContext.php b/lib/activities/InstituteContext.php
new file mode 100644
index 0000000..9b7d5c4
--- /dev/null
+++ b/lib/activities/InstituteContext.php
@@ -0,0 +1,80 @@
+<?php
+
+/**
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @license GPL 2 or later
+ */
+
+namespace Studip\Activity;
+
+class InstituteContext extends Context
+{
+ private $institute;
+
+ /**
+ * create new institute-context
+ *
+ * @param string $institute_id
+ */
+ public function __construct($institute, $observer)
+ {
+ $this->institute = $institute;
+ $this->observer = $observer;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getProvider()
+ {
+ if (!$this->provider) {
+ $institute = $this->institute;
+
+ $module_provider = [
+ 'CoreForum' => 'ForumProvider',
+ 'CoreDocuments' => 'DocumentsProvider',
+ 'CoreWiki' => 'WikiProvider',
+ ];
+
+ foreach ($institute->tools as $tool) {
+ $studip_module = $tool->getStudipModule();
+ if($studip_module) {
+ if (isset($module_provider[get_class($studip_module)])) {
+ $this->addProvider('Studip\Activity\\'. $module_provider[get_class($studip_module)]);
+ } elseif ($studip_module instanceof ActivityProvider) {
+ $this->provider[$studip_module->getPluginName()] = $studip_module;
+ }
+ }
+ }
+ //news
+ $this->addProvider('Studip\Activity\NewsProvider');
+ }
+
+ return $this->provider;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRangeId()
+ {
+ return $this->institute->id;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getContextType()
+ {
+ return \Context::INSTITUTE;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getContextFullname($format = 'default')
+ {
+ return $this->institute->getFullname($format);
+ }
+}
diff --git a/lib/activities/MessageProvider.php b/lib/activities/MessageProvider.php
new file mode 100644
index 0000000..9d16831
--- /dev/null
+++ b/lib/activities/MessageProvider.php
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @license GPL 2 or later
+ */
+
+namespace Studip\Activity;
+
+class MessageProvider implements ActivityProvider
+{
+ /**
+ * get the details for the passed activity
+ *
+ * @param object $activity the acitivty to fill with details, passed by reference
+ */
+ public function getActivityDetails($activity)
+ {
+ $message = \Message::find($activity->object_id);
+
+ if (!$message
+ || !$activity->getContextObject()
+ || !$message->permissionToRead($activity->getContextObject()->getObserver()->id))
+ {
+ return false;
+ }
+
+ $activity->content = formatReady($message->message);
+
+ $url = \URLHelper::getUrl("dispatch.php/messages/read/{$message->id}", ['cid' => null]);
+
+ $route = \URLHelper::getURL('api.php/message/' . $message->id, NULL, true);
+
+ $activity->object_url = [
+ $url => _('Zur Nachricht')
+ ];
+
+ $activity->object_route = $route;
+
+ return true;
+ }
+
+
+ /**
+ * posts an activity for a given notification event
+ *
+ * @param String $event a notification for an activity
+ * @param Array $info information which a relevant for the activity
+ */
+ public static function postActivity($event, $message_id, $data)
+ {
+ foreach ($data['rec_id'] as $rec_id) {
+
+ // activity for receipent
+ $activity = Activity::create(
+ [
+ 'provider' => __CLASS__,
+ 'context' => 'user',
+ 'context_id' => $rec_id,
+ 'content' => NULL,
+ 'actor_type' => 'user', // who initiated the activity?
+ 'actor_id' => $data['user_id'], // id of initiator
+ 'verb' => 'sent', // the activity type
+ 'object_id' => $message_id, // the id of the referenced object
+ 'object_type' => 'message', // type of activity object
+ 'mkdate' => time()
+ ]
+ );
+ }
+
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getLexicalField()
+ {
+ return _('eine Nachricht');
+ }
+
+}
diff --git a/lib/activities/NewsProvider.php b/lib/activities/NewsProvider.php
new file mode 100644
index 0000000..eed7fe7
--- /dev/null
+++ b/lib/activities/NewsProvider.php
@@ -0,0 +1,134 @@
+<?php
+
+/**
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @license GPL 2 or later
+ */
+
+namespace Studip\Activity;
+
+class NewsProvider implements ActivityProvider
+{
+ private function getUrlForContext($news, $activity)
+ {
+ switch ($activity->context) {
+ case 'course':
+ return [
+ \URLHelper::getUrl('dispatch.php/course/overview/?cid=' . $activity->context_id . '&contentbox_type=news&contentbox_open=' . $activity->object_id) => _('Ankündigungen in der Veranstaltung')
+ ];
+ break;
+
+ case 'institute':
+ return [
+ \URLHelper::getUrl('dispatch.php/institute/overview?auswahl=' . $activity->context_id) => _('Ankündigungen in der Einrichtung')
+ ];
+ break;
+
+ case 'system':
+ return [
+ \URLHelper::getUrl('dispatch.php/start?contentbox_type=news&contentbox_open='. $news->getId() .'#'. $news->getId()) => _('Ankündigungen auf der Startseite')
+ ];
+ break;
+
+ case 'user':
+ return [
+ \URLHelper::getUrl('dispatch.php/profile/?username='. get_username($activity->context_id)
+ . '&contentbox_type=news&contentbox_open='. $news->getId() .'#'. $news->getId()) => _('Ankündigungen auf der Profilseite')
+ ];
+ break;
+ }
+ }
+
+ /**
+ * posts an activity for a given notification event
+ *
+ * @param String $event a notification for an activity
+ * @param String $news
+ */
+ public static function postActivity($event, $news)
+ {
+ // delete any old activities for this id
+ $activities = Activity::findBySql('object_id = ?', [$news->id]);
+
+ foreach ($activities as $activity) {
+ $activity->delete();
+ }
+
+ $mkdate = time();
+
+ // iterate over every news-range and create approbriate activity
+ foreach ($news->news_ranges as $range) {
+ $context_id = $range->range_id;
+
+ switch ($range->type) {
+ case 'user':
+ $context = 'user';
+ break;
+ case 'inst':
+ case 'fak':
+ $context = 'institute';
+ break;
+ case 'sem':
+ $context = 'course';
+ break;
+ case 'global':
+ $context = 'system';
+ $context_id = 'system';
+ break;
+ }
+ if (isset($context)) {
+ $activity = Activity::create(
+ [
+ 'provider' => __CLASS__,
+ 'context' => $context,
+ 'context_id' => $context_id,
+ 'content' => null,
+ 'actor_type' => 'user', // who initiated the activity?
+ 'actor_id' => $news->user_id, // id of initiator
+ 'verb' => 'created', // the activity type
+ 'object_id' => $news->id, // the id of the referenced object
+ 'object_type' => 'news', // type of activity object
+ 'mkdate' => $mkdate
+ ]
+ );
+ }
+
+ }
+ }
+
+
+ /**
+ * get the details for the passed activity
+ *
+ * @param object $activity the activity to fill with details, passed by reference
+ */
+ public function getActivityDetails($activity)
+ {
+ $news = new \StudipNews($activity->object_id);
+
+ // do not show unpublished news
+ if ($news->date > time()) {
+ return false;
+ }
+
+ $activity->content = '<b>' . htmlReady((string) $news->topic)
+ .'</b><br>'. formatReady((string) $news->body);
+
+ $url = self::getUrlForContext($news, $activity);
+ $route = \URLHelper::getURL('api.php/news/' . $news->id, NULL, true);
+
+ $activity->object_url = $url;
+ $activity->object_route = $route;
+
+ return true;
+ }
+ /**
+ * {@inheritdoc}
+ */
+ public static function getLexicalField()
+ {
+ return _('eine Ankündigung');
+ }
+
+}
diff --git a/lib/activities/ParticipantsProvider.php b/lib/activities/ParticipantsProvider.php
new file mode 100644
index 0000000..50bad46
--- /dev/null
+++ b/lib/activities/ParticipantsProvider.php
@@ -0,0 +1,84 @@
+<?php
+
+/**
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @license GPL 2 or later
+ */
+
+namespace Studip\Activity;
+
+class ParticipantsProvider implements ActivityProvider
+{
+
+ /**
+ * posts an activity for a given notification event
+ *
+ * @param String $event a notification for an activity
+ * @param String $course_id
+ * @param String $user_id
+ */
+ public static function postActivity($event, $course_id, $user_id)
+ {
+ $course = \Course::find($course_id);
+
+ if ($event == 'UserDidEnterCourse') {
+ $verb = 'created';
+ $summary = _('%s wurde in die Veranstaltung "%s" eingetragen.');
+ $summary = sprintf($summary, get_fullname($user_id), $course->name);
+ } elseif ($event == 'UserDidLeaveCourse') {
+ $verb = 'voided';
+ $summary = _('%s wurde aus der Veranstaltung "%s" ausgetragen.');
+ $summary = sprintf($summary, get_fullname($user_id), $course->name);
+ }
+
+ $type = get_object_type($course_id);
+
+ $activity = Activity::create(
+ [
+ 'provider' => __CLASS__,
+ 'context' => ($type == 'sem') ? 'course' : 'institute',
+ 'context_id' => $course_id,
+ 'content' => $summary,
+ 'actor_type' => 'user', // who initiated the activity?
+ 'actor_id' => $GLOBALS['user']->id, // id of initiator
+ 'verb' => $verb, // the activity type
+ 'object_id' => $course_id, // the id of the referenced object
+ 'object_type' => 'participants', // type of activity object
+ 'mkdate' => time(),
+ ]
+ );
+
+ }
+
+ /**
+ * get the details for the passed activity
+ *
+ * @param object $activity the activity to fill with details, passed by reference
+ */
+ public function getActivityDetails($activity)
+ {
+ $activity->content = htmlReady($activity->content);
+
+ $url = \URLHelper::getUrl("dispatch.php/course/members/index", ['cid' => $activity->context_id]);
+
+ $route = \URLHelper::getURL('api.php/course/' . $activity->context_id, NULL, true);
+
+ $activity->object_url = [
+ $url => _('Zur Veranstaltung')
+ ];
+
+ $activity->object_route = $route;
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getLexicalField()
+ {
+ return _('eine/n Teilnehmer/in');
+ }
+
+}
diff --git a/lib/activities/ScheduleProvider.php b/lib/activities/ScheduleProvider.php
new file mode 100644
index 0000000..208b9b3
--- /dev/null
+++ b/lib/activities/ScheduleProvider.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @license GPL 2 or later
+ */
+
+namespace Studip\Activity;
+
+class ScheduleProvider implements ActivityProvider
+{
+ /**
+ * get the details for the passed activity
+ *
+ * @param object $activity the activity to fill with details, passed by reference
+ */
+ public function getActivityDetails($activity)
+ {
+ $activity->content = htmlReady($activity->content);
+
+ $url = \URLHelper::getUrl("dispatch.php/course/dates?cid={$activity->context_id}");
+ $route = \URLHelper::getURL('api.php/course/' . $activity->context_id . '/events', NULL, true);
+
+ $activity->object_url = [
+ $url => _('Zum Ablaufplan der Veranstaltung')
+ ];
+
+ $activity->object_route = $route;
+
+ return true;
+ }
+
+ /**
+ * posts an activity for a given notification event
+ *
+ * @param String $event a notification for an activity
+ * @param Array $sem Seminar-class for the notification
+ */
+ public static function postActivity($event, $sem)
+ {
+ $range_id = $sem->getId();
+
+ $type = get_object_type($range_id);
+ if ($type == 'sem') {
+ $course = \Course::find($range_id);
+ }
+
+ $user_id = $GLOBALS['user']->id;
+ $mkdate = time();
+
+ if ($event == 'CourseDidChangeSchedule') {
+ $verb = 'edited';
+ $summary = _('Der Ablaufplan wurde in der Veranstaltung "%s" von %s aktualisiert.');
+ $summary = sprintf($summary, $course->name, get_fullname($user_id));
+ }
+
+ $activity = Activity::create(
+ [
+ 'provider' => __CLASS__,
+ 'context' => ($type == 'sem') ? 'course' : 'institute',
+ 'context_id' => $range_id,
+ 'content' => $summary,
+ 'actor_type' => 'user', // who initiated the activity?
+ 'actor_id' => $user_id, // id of initiator
+ 'verb' => $verb, // the activity type
+ 'object_id' => $range_id, // the id of the referenced object
+ 'object_type' => 'schedule', // type of activity object
+ 'mkdate' => $mkdate
+ ]
+ );
+
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getLexicalField()
+ {
+ return _('einen Eintrag im Ablaufplan');
+ }
+
+}
diff --git a/lib/activities/Stream.php b/lib/activities/Stream.php
new file mode 100644
index 0000000..27daf76
--- /dev/null
+++ b/lib/activities/Stream.php
@@ -0,0 +1,190 @@
+<?php
+
+/**
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @license GPL 2 or later
+ */
+
+namespace Studip\Activity;
+
+class Stream implements \ArrayAccess, \Countable, \IteratorAggregate
+{
+ private $activities;
+
+ /**
+ * creates a stream representing the activities for the passed contexts,
+ * filter by time (if any)
+ *
+ * @param array $contexts All contexts that need to be considered
+ * @param \Studip\Activity\Filter $filter
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function __construct($contexts, Filter $filter)
+ {
+ if (!is_array($contexts)) {
+ $contexts = [$contexts];
+ }
+
+ foreach ($contexts as $context) {
+ if (!$context instanceof Context) {
+ throw new \InvalidArgumentException();
+ }
+ }
+
+ if (!$filter instanceof Filter) {
+ throw new \InvalidArgumentException();
+ }
+
+ //fetch avaible contextes in given timespan
+ $available_contexts = \DBManager::get()->fetchGroupedPairs(
+ "SELECT DISTINCT context,context_id FROM activities WHERE mkdate BETWEEN ? AND ?",
+ [$filter->getStartDate(), $filter->getEndDate()]);
+
+ //fetch activities only for contextes with known activities
+ $activities = array_flatten(array_values(array_filter(array_map(
+ function ($context) use ($filter, $available_contexts) {
+ if (isset($available_contexts[$context->getContextType()])
+ && in_array($context->getRangeId(), $available_contexts[$context->getContextType()])) {
+ return $context->getActivities($filter);
+ }
+ }, $contexts))
+ ));
+
+ $new_activities = [];
+
+ foreach ($activities as $activity) {
+ // generate an id for the activity, considering some basic object parameters
+ $id = md5($activity->provider . $activity->content .
+ $activity->verb . $activity->object_type . $activity->mkdate);
+
+ if ($new_activities[$id]) {
+ $url = key($activity->object_url);
+ $name = current($activity->object_url);
+ next($activity->object_url);
+ $new_activities[$id]->addUrl($url, $name);
+ } else {
+ $new_activities[$id] = $activity;
+ }
+ }
+
+ // sort activites by their mkdate
+ usort($new_activities, function($a, $b) {
+ return $b->mkdate - $a->mkdate;
+ });
+
+ $this->activities = $new_activities;
+ }
+
+ /**
+ * ArrayAccess: Check whether the given offset exists.
+ */
+ public function offsetExists($offset)
+ {
+ return isset($this->activities[$offset]);
+ }
+
+ /**
+ * ArrayAccess: Get the value at the given offset.
+ */
+ public function offsetGet($offset)
+ {
+ return $this->activities[$offset];
+ }
+
+ /**
+ * ArrayAccess: Set the value at the given offset.
+ */
+ public function offsetSet($offset, $value)
+ {
+ $this->activities[$offset] = $value;
+ }
+
+ /**
+ * ArrayAccess: unset the value at the given offset (not applicable)
+ */
+ public function offsetUnset($offset)
+ {
+ unset($this->activities[$offset]);
+ }
+
+ /**
+ * IteratorAggregate
+ */
+ public function getIterator()
+ {
+ return new \ArrayIterator($this->activities);
+ }
+
+ /**
+ * Countable
+ */
+ public function count()
+ {
+ return sizeof($this->activities);
+ }
+
+ /**
+ * return representation of the current stream as an array
+ *
+ * @return array
+ */
+ public function toArray()
+ {
+ $activities = [];
+
+ foreach ($this as $key => $activity) {
+ $activities[$key] = $activity->toArray();
+
+ // add i18n auto generated title prefix
+ $title = '';
+
+ // $class = '\\Studip\\Activity\\' . ucfirst($activity->provider) . 'Provider';
+ $class = $activity->provider;
+ $object_text = $class::getLexicalField();
+
+ if (in_array($activity->actor_id, ['____%system%____', 'system']) !== false) {
+ $actor = _('Stud.IP');
+ } elseif ($activity->actor_type === 'anonymous') {
+ $actor = _('Anonym');
+ } else {
+ $actor = get_fullname($activity->actor_id);
+ }
+ $context_name = $activity->getContextObject()->getContextFullname();
+
+ switch ($activity->context) {
+ case 'course':
+ $title = $actor .' '
+ . sprintf($activity->verbToText(),
+ $object_text . sprintf(_(' im Kurs "%s"'), $context_name)
+ );
+ break;
+
+ case 'institute':
+ $title = $actor .' '
+ . sprintf($activity->verbToText(),
+ $object_text . sprintf(_(' in der Einrichtung "%s"'), $context_name)
+ );
+ break;
+
+ case 'system':
+ $title = $actor .' '
+ . sprintf($activity->verbToText(), _('allen')) .' '
+ . $object_text;
+ break;
+
+ case 'user':
+ $title = $actor .' '
+ . sprintf($activity->verbToText(), $context_name) .' '
+ . $object_text;
+ break;
+
+ }
+
+ $activities[$key]['title'] = $title;
+ }
+
+ return $activities;
+ }
+}
diff --git a/lib/activities/SystemContext.php b/lib/activities/SystemContext.php
new file mode 100644
index 0000000..ddc5872
--- /dev/null
+++ b/lib/activities/SystemContext.php
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @license GPL 2 or later
+ */
+
+namespace Studip\Activity;
+
+class SystemContext extends Context
+{
+ /**
+ * create new user-context
+ *
+ * @param string $user_id
+ */
+ public function __construct($observer)
+ {
+ $this->observer = $observer;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getProvider()
+ {
+ $this->addProvider('Studip\Activity\NewsProvider');
+
+ return $this->provider;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRangeId()
+ {
+ return 'system';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getContextType()
+ {
+ return 'system';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getContextFullname($format = 'default')
+ {
+ return _('Stud.IP');
+ }
+}
diff --git a/lib/activities/UserContext.php b/lib/activities/UserContext.php
new file mode 100644
index 0000000..0ff8921
--- /dev/null
+++ b/lib/activities/UserContext.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @author Till Glöggler <gloeggler@elan-ev.de>
+ * @license GPL 2 or later
+ */
+
+namespace Studip\Activity;
+
+class UserContext extends Context
+{
+ private $user;
+
+ /**
+ * create new user-context
+ *
+ * @param string $user_id
+ */
+ public function __construct($user, $observer)
+ {
+ $this->user = $user;
+ $this->observer = $observer;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRangeId()
+ {
+ return $this->user->id;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getProvider()
+ {
+
+ if (!$this->provider) {
+ $this->addProvider('Studip\Activity\NewsProvider');
+
+ if ($this->user->id === $this->observer->id) {
+ $this->addProvider('Studip\Activity\MessageProvider');
+ }
+
+ foreach (\PluginManager::getInstance()->getPlugins(ActivityProvider::class) as $plugin) {
+ if ($plugin instanceof \HomepagePlugin
+ && $plugin->isActivated($this->user->id, 'user')
+ ) {
+ $this->provider[] = $plugin;
+ }
+ }
+ }
+
+ return $this->provider;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getContextType()
+ {
+ return \Context::USER;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getContextFullname($format = 'default')
+ {
+ return $this->user->getFullname($format);
+ }
+}
diff --git a/lib/activities/WikiProvider.php b/lib/activities/WikiProvider.php
new file mode 100644
index 0000000..e412279
--- /dev/null
+++ b/lib/activities/WikiProvider.php
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * @author Till Glöggler <tgloeggl@uos.de>
+ * @author André Klaßen <klassen@elan-ev.de>
+ * @license GPL 2 or later
+ */
+
+namespace Studip\Activity;
+
+class WikiProvider implements ActivityProvider
+{
+ /**
+ * get the details for the passed activity
+ *
+ * @param object $activity the activity to fill with details, passed by reference
+ */
+ public function getActivityDetails($activity)
+ {
+ // Check visibility of wiki page
+ $page = \WikiPage::findLatestPage($activity->context_id, $activity->object_id);
+ if ($page && !$page->isVisibleTo($GLOBALS['user'])) {
+ return false;
+ }
+
+ $activity->content = \htmlReady($activity->content);
+
+ if ($activity->context === 'course') {
+ $url = \URLHelper::getURL('wiki.php', ['cid' => $activity->context_id, 'keyword' => $activity->object_id]);
+ $route = \URLHelper::getURL("api.php/course/{$activity->context_id}/wiki/{$activity->object_id}", null, true);
+
+ $activity->object_url = [
+ $url => _('Zum Wiki der Veranstaltung'),
+ ];
+
+ $activity->object_route = $route;
+
+ } elseif ($activity->context === 'institute') {
+ $url = \URLHelper::getURL('wiki.php', ['cid' => $activity->context_id, 'keyword' => $activity->object_id]);
+ $route= null;
+
+ $activity->object_url = [
+ $url => _('Zum Wiki der Einrichtung')
+ ];
+
+ $activity->object_route = $route;
+ }
+
+ return true;
+ }
+
+ /**
+ * posts an activity for a given notification event
+ *
+ * @param String $event a notification for an activity
+ * @param \WikiPage $info information which a relevant for the activity
+ */
+ public static function postActivity($event, $info)
+ {
+ $range_id = $info['range_id'];
+ $keyword = $info['keyword'];
+
+ $type = get_object_type($range_id);
+ if ($type === 'sem') {
+ $course = \Course::find($range_id);
+ } else {
+ $course = \Institute::find($range_id);
+ }
+
+ $user_id = $GLOBALS['user']->id;
+ $mkdate = time();
+
+
+ if ($event === 'WikiPageDidCreate' && $info['version'] > 1) {
+ $event = 'WikiPageDidUpdate';
+ }
+
+ if ($event === 'WikiPageDidCreate') {
+ $verb = 'created';
+ if ($type === 'sem') {
+ $summary = _('Die Wiki-Seite %s wurde von %s in der Veranstaltung "%s" angelegt.');
+ } else {
+ $summary = _('Die Wiki-Seite %s wurde von %s in der Einrichtung "%s" angelegt.');
+ }
+ } elseif ($event === 'WikiPageDidUpdate') {
+ $verb = 'edited';
+ if ($type === 'sem') {
+ $summary = _('Die Wiki-Seite %s wurde von %s in der Veranstaltung "%s" aktualisiert.');
+ } else {
+ $summary = _('Die Wiki-Seite %s wurde von %s in der Einrichtung "%s" aktualisiert.');
+ }
+ } elseif ($event === 'WikiPageDidDelete') {
+ $verb = 'voided';
+ if ($type === 'sem') {
+ $summary = _('Die Wiki-Seite %s wurde von %s in der Veranstaltung "%s" gelöscht.');
+ } else {
+ $summary = _('Die Wiki-Seite %s wurde von %s in der Einrichtung "%s" gelöscht.');
+ }
+ }
+
+ $summary = sprintf($summary, $keyword, get_fullname($user_id), $course->name);
+
+ $activity = Activity::create([
+ 'provider' => __CLASS__,
+ 'context' => $type === 'sem' ? 'course' : 'institute',
+ 'context_id' => $range_id,
+ 'content' => $summary,
+ 'actor_type' => 'user', // who initiated the activity?
+ 'actor_id' => $user_id, // id of initiator
+ 'verb' => $verb, // the activity type
+ 'object_id' => $keyword, // the id of the referenced object
+ 'object_type' => 'wiki', // type of activity object
+ 'mkdate' => $mkdate,
+ ]);
+
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function getLexicalField()
+ {
+ return _('eine Wiki-Seite');
+ }
+}