Skip to content
Snippets Groups Projects
Commit e160ba5f authored by Jan-Hendrik Willms's avatar Jan-Hendrik Willms
Browse files

migrate from storing last visit dates of blubber threads in config_values to...

Closes #744

Merge request studip/studip!1219
parent 3d8cb20a
No related branches found
No related tags found
No related merge requests found
...@@ -18,7 +18,7 @@ class Blubber extends \RESTAPI\RouteMap ...@@ -18,7 +18,7 @@ class Blubber extends \RESTAPI\RouteMap
* *
* @get /blubber/threads/:thread_id * @get /blubber/threads/:thread_id
* @param string $thread_id id of the blubber thread or "global" if you want public threads (not comments). Remind the global thread is a virtual thread with a special behaviour. * @param string $thread_id id of the blubber thread or "global" if you want public threads (not comments). Remind the global thread is a virtual thread with a special behaviour.
* @return Array the blubber as array * @return array the blubber as array
*/ */
public function getThreadData($thread_id) public function getThreadData($thread_id)
{ {
...@@ -31,7 +31,6 @@ class Blubber extends \RESTAPI\RouteMap ...@@ -31,7 +31,6 @@ class Blubber extends \RESTAPI\RouteMap
$thread = \BlubberThread::upgradeThread($thread); $thread = \BlubberThread::upgradeThread($thread);
if (!$thread->isReadable()) { if (!$thread->isReadable()) {
$this->error(401); $this->error(401);
return;
} }
$json = $thread->getJSONData(50, null, \Request::get("search")); $json = $thread->getJSONData(50, null, \Request::get("search"));
...@@ -46,7 +45,7 @@ class Blubber extends \RESTAPI\RouteMap ...@@ -46,7 +45,7 @@ class Blubber extends \RESTAPI\RouteMap
* Get threads * Get threads
* *
* @get /blubber/threads * @get /blubber/threads
* @return Array the stream as array * @return array the stream as array
*/ */
public function getMyThreads() public function getMyThreads()
{ {
...@@ -83,7 +82,7 @@ class Blubber extends \RESTAPI\RouteMap ...@@ -83,7 +82,7 @@ class Blubber extends \RESTAPI\RouteMap
* *
* @post /blubber/threads/:thread_id/comments * @post /blubber/threads/:thread_id/comments
* @param string $thread_id id of the blubber thread * @param string $thread_id id of the blubber thread
* @return Array the comment as array * @return array the comment as array
*/ */
public function postComment($thread_id) public function postComment($thread_id)
{ {
...@@ -93,13 +92,11 @@ class Blubber extends \RESTAPI\RouteMap ...@@ -93,13 +92,11 @@ class Blubber extends \RESTAPI\RouteMap
if (!trim($this->data['content'])) { if (!trim($this->data['content'])) {
$this->error(406); $this->error(406);
return false;
} }
$thread = \BlubberThread::find($thread_id); $thread = \BlubberThread::find($thread_id);
if (!$thread->isCommentable()) { if (!$thread->isCommentable()) {
$this->error(401); $this->error(401);
return;
} }
$comment = new \BlubberComment(); $comment = new \BlubberComment();
...@@ -109,7 +106,7 @@ class Blubber extends \RESTAPI\RouteMap ...@@ -109,7 +106,7 @@ class Blubber extends \RESTAPI\RouteMap
$comment['external_contact'] = 0; $comment['external_contact'] = 0;
$comment->store(); $comment->store();
$GLOBALS['user']->cfg->store("BLUBBERTHREAD_VISITED_".$thread_id, time()); $thread->setLastVisit();
return $comment->getJSONData(); return $comment->getJSONData();
} }
...@@ -122,14 +119,13 @@ class Blubber extends \RESTAPI\RouteMap ...@@ -122,14 +119,13 @@ class Blubber extends \RESTAPI\RouteMap
* @param string $thread_id id of the blubber thread * @param string $thread_id id of the blubber thread
* @param string $comment id of the comment * @param string $comment id of the comment
* *
* @return Array the comment as array * @return array the comment as array
*/ */
public function editComment($thread_id, $comment_id) public function editComment($thread_id, $comment_id)
{ {
$comment = \BlubberComment::find($comment_id); $comment = \BlubberComment::find($comment_id);
if (!$comment->isWritable()) { if (!$comment->isWritable()) {
$this->error(401); $this->error(401);
return;
} }
$old_content = $comment['content']; $old_content = $comment['content'];
$comment['content'] = $this->data['content']; $comment['content'] = $this->data['content'];
...@@ -176,7 +172,7 @@ class Blubber extends \RESTAPI\RouteMap ...@@ -176,7 +172,7 @@ class Blubber extends \RESTAPI\RouteMap
* *
* @param string $thread_id id of the blubber thread * @param string $thread_id id of the blubber thread
* *
* @return Array the comments as array * @return array the comments as array
*/ */
public function getComments($thread_id) public function getComments($thread_id)
{ {
...@@ -187,7 +183,6 @@ class Blubber extends \RESTAPI\RouteMap ...@@ -187,7 +183,6 @@ class Blubber extends \RESTAPI\RouteMap
$thread = new \BlubberThread($thread_id); $thread = new \BlubberThread($thread_id);
if (!$thread->isReadable()) { if (!$thread->isReadable()) {
$this->error(401); $this->error(401);
return;
} }
$modifier = \Request::get('modifier'); $modifier = \Request::get('modifier');
...@@ -228,7 +223,7 @@ class Blubber extends \RESTAPI\RouteMap ...@@ -228,7 +223,7 @@ class Blubber extends \RESTAPI\RouteMap
FROM blubber_comments FROM blubber_comments
WHERE blubber_comments.thread_id = :thread_id WHERE blubber_comments.thread_id = :thread_id
AND blubber_comments.mkdate >= :timestamp AND blubber_comments.mkdate >= :timestamp
ORDER BY mkdate ASC ORDER BY mkdate
LIMIT :limit"; LIMIT :limit";
$comments = \DBManager::get()->fetchAll($query, [ $comments = \DBManager::get()->fetchAll($query, [
'thread_id' => $thread_id, 'thread_id' => $thread_id,
......
<?php
final class MigrateBlubberUserConfigToObjectUserVisits extends Migration
{
public function description()
{
return 'Migrates the blubber visited entrires from config_values to user_entries';
}
protected function up()
{
$query = "SELECT `pluginid`
FROM `plugins`
WHERE `pluginclassname` = 'Blubber'";
$blubber_plugin_id = DBManager::get()->fetchColumn($query);
$query = "INSERT INTO `object_user_visits` (
`object_id`,
`user_id`,
`plugin_id`,
`visitdate`,
`last_visitdate`
)
SELECT SUBSTR(`field`, 23) AS `object_id`,
`range_id` AS `user_id`,
? AS `plugin_id`,
`value` AS `visitdate`,
`value` AS `last_visitdate`
FROM `config_values`
WHERE `field` LIKE 'BLUBBERTHREAD\\_VISITED\\_%'";
DBManager::get()->execute($query, [$blubber_plugin_id]);
$query = "DELETE FROM `config_values`
WHERE `field` LIKE 'BLUBBERTHREAD\\_VISITED\\_%'";
DBManager::get()->exec($query);
}
protected function down()
{
$query = "SELECT `pluginid`
FROM `plugins`
WHERE `pluginclassname` = 'Blubber'";
$blubber_plugin_id = DBManager::get()->fetchColumn($query);
$query = "INSERT INTO `config_values` (
`field`,
`range_id`,
`value`,
`mkdate`,
`chdate`,
`comment`
)
SELECT CONCAT('BLUBBERTHREAD_VISITED_', `object_id`) AS `field`,
`user_id` AS `range_id`,
`visitdate` AS `value`,
UNIX_TIMESTAMP() AS `mkdate`,
UNIX_TIMESTAMP() AS `chdate`,
'' AS `comment`
FROM `object_user_visits`
WHERE `plugin_id` = ?";
DBManager::get()->execute($query, [$blubber_plugin_id]);
$query = "DELETE FROM `object_user_visits`
WHERE `plugin_id` = ?";
DBManager::get()->execute($query, [$blubber_plugin_id]);
}
}
<?php <?php
/**
* @property BlubberThread[] $elements
*/
class BlubberThreadsWidget extends SidebarWidget class BlubberThreadsWidget extends SidebarWidget
{ {
protected $active_thread = null; protected $active_thread = null;
protected $with_composer = false; protected $with_composer = false;
/**
* @param BlubberThread $thread
*/
public function addThread($thread) public function addThread($thread)
{ {
$this->elements[] = $thread; $this->elements[] = $thread;
...@@ -32,18 +38,18 @@ class BlubberThreadsWidget extends SidebarWidget ...@@ -32,18 +38,18 @@ class BlubberThreadsWidget extends SidebarWidget
foreach ($this->elements as $thread) { foreach ($this->elements as $thread) {
$unseen_comments = BlubberComment::countBySQL("thread_id = ? AND mkdate >= ?", [ $unseen_comments = BlubberComment::countBySQL("thread_id = ? AND mkdate >= ?", [
$thread->getId(), $thread->getId(),
$thread->getLastVisit() ?: object_get_visit_threshold() $thread->getLastVisit()
]); ]);
$json[] = [ $json[] = [
'thread_id' => $thread->getId(), 'thread_id' => $thread->getId(),
'avatar' => $thread->getAvatar(), 'avatar' => $thread->getAvatar(),
'name' => $thread->getName(), 'name' => $thread->getName(),
'timestamp' => (int) $thread->getLatestActivity(), 'timestamp' => (int) $thread->getLatestActivity(),
'mkdate' => (int) $thread->mkdate, 'mkdate' => (int) $thread->mkdate,
'unseen_comments' => $unseen_comments, 'unseen_comments' => $unseen_comments,
'notifications' => $thread->id === 'global' || ($thread->context_type === 'course' && !$GLOBALS['perm']->have_perm('admin')), 'notifications' => $thread->id === 'global' || ($thread->context_type === 'course' && !$GLOBALS['perm']->have_perm('admin')),
'followed' => $thread->isFollowedByUser(), 'followed' => $thread->isFollowedByUser(),
]; ];
} }
......
...@@ -41,14 +41,17 @@ class BlubberThread extends SimpleORMap implements PrivacyObject ...@@ -41,14 +41,17 @@ class BlubberThread extends SimpleORMap implements PrivacyObject
'foreign_key' => 'user_id', 'foreign_key' => 'user_id',
'assoc_foreign_key' => 'user_id', 'assoc_foreign_key' => 'user_id',
]; ];
$config['has_many']['visits'] = [
'class_name' => ObjectUserVisit::class,
'assoc_foreign_key' => 'object_id',
'on_delete' => 'delete',
];
$config['serialized_fields']['metadata'] = 'JSONArrayObject'; $config['serialized_fields']['metadata'] = 'JSONArrayObject';
parent::configure($config); parent::configure($config);
} }
protected $last_visit = null;
/** /**
* Recognizes mentions in blubber as @username or @"Firstname lastname" * Recognizes mentions in blubber as @username or @"Firstname lastname"
* and turns them into usual studip-links. The mentioned person is notified by * and turns them into usual studip-links. The mentioned person is notified by
...@@ -95,6 +98,9 @@ class BlubberThread extends SimpleORMap implements PrivacyObject ...@@ -95,6 +98,9 @@ class BlubberThread extends SimpleORMap implements PrivacyObject
return $matches[0]; return $matches[0];
} }
/**
* @return BlubberThread[]
*/
public static function findBySQL($sql, $params = []) public static function findBySQL($sql, $params = [])
{ {
return parent::findAndMapBySQL(function ($thread) { return parent::findAndMapBySQL(function ($thread) {
...@@ -102,6 +108,9 @@ class BlubberThread extends SimpleORMap implements PrivacyObject ...@@ -102,6 +108,9 @@ class BlubberThread extends SimpleORMap implements PrivacyObject
}, $sql, $params); }, $sql, $params);
} }
/**
* @return BlubberThread|null
*/
public static function find($id) public static function find($id)
{ {
return self::upgradeThread(parent::find($id)); return self::upgradeThread(parent::find($id));
...@@ -598,7 +607,39 @@ class BlubberThread extends SimpleORMap implements PrivacyObject ...@@ -598,7 +607,39 @@ class BlubberThread extends SimpleORMap implements PrivacyObject
*/ */
public function getLastVisit(string $user_id = null) public function getLastVisit(string $user_id = null)
{ {
return UserConfig::get($user_id ?? $GLOBALS['user']->id)->getValue("BLUBBERTHREAD_VISITED_".$this->getId()); return object_get_visit(
$this->id,
$this->getBlubberPluginId(),
'',
'',
$user_id ?? User::findCurrent()->id
);
}
/**
* Sets the last visit timestamp for this thread
*
* @param string|null $user_id
*/
public function setLastVisit(string $user_id = null): void
{
object_set_visit(
$this->id,
$this->getBlubberPluginId(),
$user_id ?? User::findCurrent()->id
);
}
/**
* Returns the id of the blubber plugin.
*
* @return int Id of the plugin
*/
protected function getBlubberPluginId(): int
{
$plugin_info = PluginManager::getInstance()->getPluginInfo(Blubber::class);
return (int) $plugin_info['id'];
} }
public function notifyUsersForNewComment($comment) public function notifyUsersForNewComment($comment)
...@@ -843,7 +884,7 @@ class BlubberThread extends SimpleORMap implements PrivacyObject ...@@ -843,7 +884,7 @@ class BlubberThread extends SimpleORMap implements PrivacyObject
'more_down' => 0, 'more_down' => 0,
'unseen_comments' => BlubberComment::countBySQL("thread_id = ? AND mkdate >= ? AND user_id != ?", [ 'unseen_comments' => BlubberComment::countBySQL("thread_id = ? AND mkdate >= ? AND user_id != ?", [
$this->getId(), $this->getId(),
$this->getLastVisit() ?: object_get_visit_threshold(), $this->getLastVisit(),
$user_id $user_id
]), ]),
'notifications' => $this->mayDisableNotifications(), 'notifications' => $this->mayDisableNotifications(),
...@@ -919,10 +960,8 @@ class BlubberThread extends SimpleORMap implements PrivacyObject ...@@ -919,10 +960,8 @@ class BlubberThread extends SimpleORMap implements PrivacyObject
'user_id' => $user_id, 'user_id' => $user_id,
'html_id' => "blubberthread_".$this->getId() 'html_id' => "blubberthread_".$this->getId()
]); ]);
$this->last_visit[$user_id] = empty($this->last_visit[$user_id])
? object_get_visit($this->getId(), "blubberthread", "last", "", $user_id) $this->setLastVisit($user_id);
: $this->last_visit[$user_id];
UserConfig::get($user_id)->store("BLUBBERTHREAD_VISITED_".$this->getId(), time());
} }
public function getHashtags($since = null) public function getHashtags($since = null)
......
<?php
/**
* @property array $id
* @property string $object_id
* @property string $user_id
* @property int $plugin_id
* @property int $visitdate
* @property int $last_visitdate
* @property User $user
*/
class ObjectUserVisit extends SimpleORMap
{
protected static function configure($config = [])
{
$config['db_table'] = 'object_user_visits';
$config['belongs_to'] = [
'user' => [
'class_name' => User::class,
'foreign_key' => 'user_id',
'assoc_foreign_key' => 'user_id',
]
];
parent::configure($config);
}
}
...@@ -59,7 +59,11 @@ class Blubber extends CorePlugin implements StudipModule ...@@ -59,7 +59,11 @@ class Blubber extends CorePlugin implements StudipModule
'me' => $user_id, 'me' => $user_id,
]); ]);
foreach ($comments as $comment) { foreach ($comments as $comment) {
if ($comment->thread->isVisibleInStream() && $comment->thread->isReadable() && ($comment->thread->getLatestActivity() > UserConfig::get($user_id)->getValue("BLUBBERTHREAD_VISITED_".$comment['thread_id']))) { if (
$comment->thread->isVisibleInStream()
&& $comment->thread->isReadable()
&& $comment->thread->getLatestActivity() > $comment->thread->getLastVisit()
) {
$icon->setImage(Icon::create('blubber', Icon::ROLE_NEW, ['title' => _('Es gibt neue Blubber')])); $icon->setImage(Icon::create('blubber', Icon::ROLE_NEW, ['title' => _('Es gibt neue Blubber')]));
$icon->setTitle(_('Es gibt neue Blubber')); $icon->setTitle(_('Es gibt neue Blubber'));
$icon->setBadgeNumber(count($comments)); $icon->setBadgeNumber(count($comments));
...@@ -83,7 +87,11 @@ class Blubber extends CorePlugin implements StudipModule ...@@ -83,7 +87,11 @@ class Blubber extends CorePlugin implements StudipModule
'me' => $GLOBALS['user']->id, 'me' => $GLOBALS['user']->id,
]); ]);
foreach ($threads as $thread) { foreach ($threads as $thread) {
if ($thread->isVisibleInStream() && $thread->isReadable() && ($thread['mkdate'] > UserConfig::get($user_id)->getValue("BLUBBERTHREAD_VISITED_".$thread->getId()))) { if (
$thread->isVisibleInStream()
&& $thread->isReadable()
&& $thread->mkdate > $thread->getLastVisit()
) {
$icon->setImage(Icon::create('blubber', Icon::ROLE_ATTENTION, ['title' => _('Es gibt neue Blubber')])); $icon->setImage(Icon::create('blubber', Icon::ROLE_ATTENTION, ['title' => _('Es gibt neue Blubber')]));
$icon->setTitle(_('Es gibt neue Blubber')); $icon->setTitle(_('Es gibt neue Blubber'));
break; break;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment