2424
2525namespace OCA \Comments \Notification ;
2626
27+ use OCP \Comments \IComment ;
2728use OCP \Comments \ICommentsManager ;
2829use OCP \Comments \NotFoundException ;
2930use OCP \Files \IRootFolder ;
3031use OCP \IURLGenerator ;
32+ use OCP \IUser ;
3133use OCP \IUserManager ;
3234use OCP \L10N \IFactory ;
3335use OCP \Notification \INotification ;
@@ -83,17 +85,17 @@ public function prepare(INotification $notification, $languageCode) {
8385 $ l = $ this ->l10nFactory ->get ('comments ' , $ languageCode );
8486 $ displayName = $ comment ->getActorId ();
8587 $ isDeletedActor = $ comment ->getActorType () === ICommentsManager::DELETED_USER ;
86- if ($ comment ->getActorType () === 'users ' ) {
88+ if ($ comment ->getActorType () === 'users ' ) {
8789 $ commenter = $ this ->userManager ->get ($ comment ->getActorId ());
88- if (! is_null ( $ commenter) ) {
90+ if ( $ commenter instanceof IUser ) {
8991 $ displayName = $ commenter ->getDisplayName ();
9092 }
9193 }
9294
9395 switch ($ notification ->getSubject ()) {
9496 case 'mention ' :
9597 $ parameters = $ notification ->getSubjectParameters ();
96- if ($ parameters [0 ] !== 'files ' ) {
98+ if ($ parameters [0 ] !== 'files ' ) {
9799 throw new \InvalidArgumentException ('Unsupported comment object ' );
98100 }
99101 $ userFolder = $ this ->rootFolder ->getUserFolder ($ notification ->getUser ());
@@ -103,47 +105,41 @@ public function prepare(INotification $notification, $languageCode) {
103105 }
104106 $ node = $ nodes [0 ];
105107
108+ $ path = rtrim ($ node ->getPath (), '/ ' );
109+ if (strpos ($ path , '/ ' . $ notification ->getUser () . '/files/ ' ) === 0 ) {
110+ // Remove /user/files/...
111+ $ fullPath = $ path ;
112+ list (,,, $ path ) = explode ('/ ' , $ fullPath , 4 );
113+ }
114+
115+ $ subjectParameters = [
116+ 'file ' => [
117+ 'type ' => 'file ' ,
118+ 'id ' => $ comment ->getObjectId (),
119+ 'name ' => $ node ->getName (),
120+ 'path ' => $ path ,
121+ 'link ' => $ this ->url ->linkToRouteAbsolute ('files.viewcontroller.showFile ' , ['fileid ' => $ comment ->getObjectId ()]),
122+ ],
123+ ];
124+
106125 if ($ isDeletedActor ) {
107- $ notification ->setParsedSubject ($ l ->t (
108- 'You were mentioned on “%s”, in a comment by a user that has since been deleted ' ,
109- [$ node ->getName ()]
110- ))
111- ->setRichSubject (
112- $ l ->t ('You were mentioned on “{file}”, in a comment by a user that has since been deleted ' ),
113- [
114- 'file ' => [
115- 'type ' => 'file ' ,
116- 'id ' => $ comment ->getObjectId (),
117- 'name ' => $ node ->getName (),
118- 'path ' => $ node ->getPath (),
119- 'link ' => $ this ->url ->linkToRouteAbsolute ('files.viewcontroller.showFile ' , ['fileid ' => $ comment ->getObjectId ()]),
120- ],
121- ]
122- );
126+ $ subject = $ l ->t ('You were mentioned on “{file}”, in a comment by a user that has since been deleted ' );
123127 } else {
124- $ notification ->setParsedSubject ($ l ->t (
125- '%1$s mentioned you in a comment on “%2$s” ' ,
126- [$ displayName , $ node ->getName ()]
127- ))
128- ->setRichSubject (
129- $ l ->t ('{user} mentioned you in a comment on “{file}” ' ),
130- [
131- 'user ' => [
132- 'type ' => 'user ' ,
133- 'id ' => $ comment ->getActorId (),
134- 'name ' => $ displayName ,
135- ],
136- 'file ' => [
137- 'type ' => 'file ' ,
138- 'id ' => $ comment ->getObjectId (),
139- 'name ' => $ node ->getName (),
140- 'path ' => $ node ->getPath (),
141- 'link ' => $ this ->url ->linkToRouteAbsolute ('files.viewcontroller.showFile ' , ['fileid ' => $ comment ->getObjectId ()]),
142- ],
143- ]
144- );
128+ $ subject = $ l ->t ('{user} mentioned you in a comment on “{file}” ' );
129+ $ subjectParameters ['user ' ] = [
130+ 'type ' => 'user ' ,
131+ 'id ' => $ comment ->getActorId (),
132+ 'name ' => $ displayName ,
133+ ];
145134 }
146- $ notification ->setIcon ($ this ->url ->getAbsoluteURL ($ this ->url ->imagePath ('core ' , 'actions/comment.svg ' )))
135+
136+ list ($ message , $ messageParameters ) = $ this ->commentToRichMessage ($ comment );
137+
138+ $ notification ->setRichSubject ($ subject , $ subjectParameters )
139+ ->setParsedSubject ($ this ->richToParsed ($ subject , $ subjectParameters ))
140+ ->setRichMessage ($ message , $ messageParameters )
141+ ->setParsedMessage ($ this ->richToParsed ($ message , $ messageParameters ))
142+ ->setIcon ($ this ->url ->getAbsoluteURL ($ this ->url ->imagePath ('core ' , 'actions/comment.svg ' )))
147143 ->setLink ($ this ->url ->linkToRouteAbsolute (
148144 'comments.Notifications.view ' ,
149145 ['id ' => $ comment ->getId ()])
@@ -157,4 +153,66 @@ public function prepare(INotification $notification, $languageCode) {
157153 }
158154
159155 }
156+
157+ public function commentToRichMessage (IComment $ comment ): array {
158+ $ message = $ comment ->getMessage ();
159+ $ messageParameters = [];
160+
161+ $ mentionTypeCount = [];
162+
163+ $ mentions = $ comment ->getMentions ();
164+ foreach ($ mentions as $ mention ) {
165+ if ($ mention ['type ' ] === 'user ' ) {
166+ $ user = $ this ->userManager ->get ($ mention ['id ' ]);
167+ if (!$ user instanceof IUser) {
168+ continue ;
169+ }
170+ }
171+
172+ if (!array_key_exists ($ mention ['type ' ], $ mentionTypeCount )) {
173+ $ mentionTypeCount [$ mention ['type ' ]] = 0 ;
174+ }
175+ $ mentionTypeCount [$ mention ['type ' ]]++;
176+
177+ // To keep a limited character set in parameter IDs ([a-zA-Z0-9-])
178+ // the mention parameter ID does not include the mention ID (which
179+ // could contain characters like '@' for user IDs) but a one-based
180+ // index of the mentions of that type.
181+ $ mentionParameterId = 'mention- ' . $ mention ['type ' ] . $ mentionTypeCount [$ mention ['type ' ]];
182+
183+ $ message = str_replace ('@ ' . $ mention ['id ' ], '{ ' . $ mentionParameterId . '} ' , $ message );
184+
185+ try {
186+ $ displayName = $ this ->commentsManager ->resolveDisplayName ($ mention ['type ' ], $ mention ['id ' ]);
187+ } catch (\OutOfBoundsException $ e ) {
188+ // There is no registered display name resolver for the mention
189+ // type, so the client decides what to display.
190+ $ displayName = '' ;
191+ }
192+
193+ $ messageParameters [$ mentionParameterId ] = [
194+ 'type ' => $ mention ['type ' ],
195+ 'id ' => $ mention ['id ' ],
196+ 'name ' => $ displayName
197+ ];
198+ }
199+
200+ return [$ message , $ messageParameters ];
201+ }
202+
203+ public function richToParsed (string $ message , array $ parameters ): string {
204+ $ placeholders = $ replacements = [];
205+ foreach ($ parameters as $ placeholder => $ parameter ) {
206+ $ placeholders [] = '{ ' . $ placeholder . '} ' ;
207+ if ($ parameter ['type ' ] === 'user ' ) {
208+ $ replacements [] = '@ ' . $ parameter ['name ' ];
209+ } else if ($ parameter ['type ' ] === 'file ' ) {
210+ $ replacements [] = $ parameter ['path ' ];
211+ } else {
212+ $ replacements [] = $ parameter ['name ' ];
213+ }
214+ }
215+
216+ return str_replace ($ placeholders , $ replacements , $ message );
217+ }
160218}
0 commit comments