-
-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Notifications for simple @-mentioning in comments #1449
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@blizzz, thanks for your PR! By analyzing the annotation information on this pull request, we identified @nickvergessen to be a potential reviewer |
|
|
||
| /** | ||
| * @author Arthur Schiwon <blizzz@arthur-schiwon.de> | ||
| * |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing @license
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done (this is for me, Github keeps showing me the dealt-with comments despite code changes, making it hard to track whats left…)
apps/comments/appinfo/app.php
Outdated
| $notificationManager = \OC::$server->getNotificationManager(); | ||
| $notificationManager->registerNotifier( | ||
| function() { | ||
| return new \OCA\Comments\Notification\Notifier( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use $application->getContainer()->query('OCA\Comments\Notification\Notifier') for automatic DI?
Or even better $application->getContainer()->query(\OCA\Comments\Notification\Notifier::class)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
apps/comments/appinfo/app.php
Outdated
| $notificationListener = function(\OCP\Comments\CommentsEvent $event) { | ||
| $application = new \OCP\AppFramework\App('comments'); | ||
| /** @var \OCA\Comments\Notification\Listener $listener */ | ||
| $listener = $application->getContainer()->query('OCA\Comments\Notification\Listener'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use \OCA\Comments\Notification\Listener::class instead of magic string?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 for better maintainability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
|
||
| $application = new Application(); | ||
| $application->registerRoutes($this, ['routes' => [ | ||
| ['name' => 'Notifications#view', 'url' => '/notifications/view/{id}', 'verb' => 'GET'], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please include the type in the url and dispatch an event on the endpoint.
Comments are already used by other apps, which would like to redirect to other parts then
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ID is a unique comment ID, not coupled to Actor or Object type. And the URL is still within apps/comments/. Still an issue?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm should be fine then I guess
| parent::__construct('comments', $urlParams); | ||
| $container = $this->getContainer(); | ||
|
|
||
| $container->registerService('NotificationsController', function(IContainer $c) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use magic instead:
$container->registerAlias('NotificationsController', \OCA\Comments\Controller\Notifications::class);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| try { | ||
| $comment = $this->commentsManager->get($id); | ||
| if($comment->getObjectType() !== 'files') { | ||
| return new NotFoundResponse(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as mentioned above, dispatch an event, so announcements can redirect to the given announcement
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now this should not be a problem anymore, because the code path is a result from a registered EventHandler. So, if a different app wants to work with Notifications, it will react upon any event, create the notification pointing to a controller of its own. Thus, to be considered done.
| $notification = $this->notificationManager->createNotification(); | ||
| $notification->setApp('comments') | ||
| ->setObject('comment', $comment->getId()) | ||
| ->setSubject('mention', [$comment->getObjectType(), $comment->getObjectId()] ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would remove this, object+user should be fine already, but I guess we will never change that data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible to change the data in theory. Currently it does not happen in files and it would not be reasonable either (unless you introduce moving comments from one file to the other…). The notification data itself does not change. If setting the subject with 'mention' alone works, it would be the safer approach indeed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
| $comment = $event->getComment(); | ||
|
|
||
| if($comment->getObjectType() !== 'files') { | ||
| // we only support notifications for files at this point |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now, this is also dependent on the registered EventHandler, custom types/apps would need to register their own. → Done.
| $notification | ||
| ->setApp('comments') | ||
| ->setObject('comment', $comment->getId()) | ||
| ->setSubject('mention', [ $comment->getObjectType(), $comment->getObjectId() ]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should listen to delete files hook, and then delete the notifications? But could also be a step 2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, that already works 😎
When files are deleted, the related comments are deleted, too. And this triggers deletion of notifications. Tested :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw, even works for Unshared files.
| $displayName = $commenter->getDisplayName(); | ||
| } | ||
| } else if($comment->getActorType() === ICommentsManager::DELETED_USER) { | ||
| $displayName = $l->t('a now deleted user'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will only work in english. I'd to a switch with the full message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, missing context for translators :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
As discussed with @nickvergessen: To be user to be integrated with other apps, we extend the API to register a CommentEntity. This will be notified on events. Therefore, we can remove the usage of the EventDispatcher and specific/coupled implementations. (So far we have one client using Comments infrastructure except of Files which is the Announcement Center – this is were improvement suggestions come from).
Updates inline |
e0b5bcc to
a8f41c8
Compare
41076b8 to
1317bbe
Compare
|
@nickvergessen reevaluate your review, please. 🎆 |
|
|
||
| $dir = $this->folder->getRelativePath($files[0]->getParent()->getPath()); | ||
| $url = $this->urlGenerator->linkToRouteAbsolute( | ||
| 'files.view.index', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd use
$link = $this->urlGenerator->linkToRouteAbsolute(
'files.viewcontroller.showFile',
['fileId' => $comment->getObjectId()]
);this automatically highlights the row in the file list and will also in the future open the sidebar.
Maybe we can also add a #comments-tab or something, so it can automatically open the comments tab in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have it locally, push later today.
in the future open the sidebar.
Maybe we can also add a #comments-tab or something, so it can automatically open the comments tab in this case.
Are there already issues or PRs on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No issues/PRs as far as I know
|
Other then that works well, will also try to get this working for the announcements later today. Todos for follow up PRs
|
| if($event->getEvent() === CommentsEvent::EVENT_DELETE) { | ||
| $this->notificationManager->markProcessed($notification); | ||
| } else { | ||
| $this->notificationManager->notify($notification); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit odd, but if I see this correctly, when you modify a comment so someone is not mentioned anymore, the notification is not removed, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's right. (As comparison, Github does not behave differently, which does not mean it is correct however).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so the issue is that we have garbage in the DB.
|
|
||
| $notification->setUser($user); | ||
| if($event->getEvent() === CommentsEvent::EVENT_DELETE) { | ||
| $this->notificationManager->markProcessed($notification); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also this is not reached, when deleting a comment, because your EventHandler does only handle add?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting point. I believe to remember that it was needed. However, deleting a comment indeed does not end up here. And that's probably a bug. While the notification is not shown to the user, it still is present in the database.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the deletion handler. We could also hook in an activity thing and log about deleted activities if it makes sense. i tried this a bit, but could not get my head around formatting 🙊
|
@blizzz could you check out the comments? Thanks :) |
|
Regarding the UI of the notification, it needs to look a bit nicer like this:
Smiley is a placeholder for the avatar, and image for the filetype. Remember that usernames need to always have avatars next to them. And ideally filenames should always have a connection to their filetype icons or previews! As the first step, the wording should be fixed to the above. :) (That way there is important info directly at the beginning of the message: Someone mentioned you…) |
|
@jancborchardt thanks for having a look!
IIRC notifications accept plain text only at the moment. Thus, it's out of scope here. It makes sense however, I agree! @jancborchardt might be an addition to #753
Good point.
|
(WIP) notify user when mentioned in comments Fix doc, and create absolute URL for as notification link. PSR-4 compatibility changes also move notification creation to comments app Do not notify yourself unit test for controller and application smaller fixes - translatable app name - remove doubles in mention array - micro perf optimization - display name: special label for deleted users, keep user id for users that could not be fetched from userManager Comment Notification-Listener Unit Test fix email adresses remove notification when triggering comment was deleted add and adjust tests add missing @license tags simplify NotificationsController registration appinfo simplification, php docs make string easier to translate adjust test replace dispatcher-based listeners with a registration method and interface safer to not pass optional data parameter to setSubject for marking as processed. ID and mention suffices Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de> update comment Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
See 3. from #753
I'll mention it there as well. |
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
4fc4f02 to
a9671a4
Compare
|
@jancborchardt here you go (the user id in brackets is custom ldap setting, by default you see the normal display name, so don't be afraid) |
* notifications can be cleaned up, no polluted DB * updating comments will re-notify users or remove notifications, depending on the message Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
|
Added a pre-update event so, so that there will be no orphaned notifications in the DB. Also users are getting either re-notified, notified, and un-notifies, depending on whether they are still mentioned, newly mentioned or removed. @nickvergessen how's your satisfaction grade now? :) |
Current coverage is 57.43% (diff: 95.85%)@@ master #1449 diff @@
==========================================
Files 1070 1081 +11
Lines 60505 62974 +2469
Methods 6829 7186 +357
Messages 0 0
Branches 0 0
==========================================
+ Hits 34026 36168 +2142
- Misses 26479 26806 +327
Partials 0 0
|
| * @param string $message | ||
| * @return string[] containing the mentions, e.g. ['@alice', '@bob'] | ||
| */ | ||
| public function extractMentions($message) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I am currently looking into 2. and 4. from #753 and extractMentions() can be well used in other code parts. Listeners is the wrong place to be, thus.
It could be a direct method of a IComment and I think it makes most sense. However this extends the API with a method. Except we add an additional interface, IMentionable within the Comments namespace. It would be an optional ability and we remain backwards compatibility. Downside: for now it would be just one method (more might come with further implementing #753, but it is unlikely). A future change would cause the same dilemma. Now the time is not bad since I have not heard about a single 3rd party Comments implementation.
Other places would be the Comments Manager (similar issue, and makes less sense to me) or we introduce a public Utility class (might get too close to our implementation, limiting flexibility). Or it would be an interface as well and we gain too much additional overhead…
=> I work on it on the subsequent PR, does not need to be dealt with here. For now I'll extend IComment, but I am not fixed on this, can be discussed and easily moved around.
apps/comments/lib/EventHandler.php
Outdated
|
|
||
| $eventType = $event->getEvent(); | ||
| if( $eventType === CommentsEvent::EVENT_ADD | ||
| && $event instanceof CommentsEvent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not necessary on all the ifs because you typehint it in the methods signature ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Legay from when i had the EntityEvent in mind… thanks for noticing 🙇♂️
apps/comments/lib/EventHandler.php
Outdated
| * @param CommentsEvent $event | ||
| */ | ||
| private function activityHandler(CommentsEvent $event) { | ||
| $c = $this->app->getContainer(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is hacky, why not inject the actual objects?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, why? 🤔 🔕 🖊️
| public function evaluate(CommentsEvent $event) { | ||
| $comment = $event->getComment(); | ||
|
|
||
| if($comment->getObjectType() !== 'files') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has already been taken care of
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
| [ $displayName, $fileName ] | ||
| ); | ||
| } | ||
| $notification->setParsedSubject($subject); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could do:
$notification->setParsedMessage($comment->getMessage());Then the notification also contains the text of the comment. I think that makes actually sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might reveal sensitive information, when popping up on a big screen? It might be also too much text for a notification, so should be trimmed down.
Facebook shows the first few words at the end on their notification, Diaspora a bit similar, but then this is how they tell apart different posts, there is no name or title. Imho the filename is sufficient and we should not put more information here. At least in the first iteration. If it proves to suck we still can adjust, my feeling is less is more however.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
trimming is something the notification API listeners take care of ;)
Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
|
@nickvergessen should be fine now. |
|
👍 |
|
Another reviewer? @jancborchardt @rullzer @LukasReschke perhaps? |
|
Tested and works 👍 |

Contributes to #753
The PR implements notification for @-mentioning against User IDs (according to step 1 in #753).
Upon click the user is brought to the Files app, in the dir of the file or folder commented on. the file or folder is also highlighted.
When a comment containing a mention is deleted, the notification is also removed, if applicable.
It does not include or implement a subscription system.
Please test and review @nickvergessen (most code you have seen at owncloud/core#24495 already) @schiessle @jancborchardt