Passed
Push — master ( dbaafc...766590 )
by John
13:16 queued 12s
created
lib/public/Comments/ICommentsManager.php 1 patch
Indentation   +270 added lines, -270 removed lines patch added patch discarded remove patch
@@ -39,294 +39,294 @@
 block discarded – undo
39 39
  */
40 40
 interface ICommentsManager {
41 41
 
42
-	/**
43
-	 * @const DELETED_USER type and id for a user that has been deleted
44
-	 * @see deleteReferencesOfActor
45
-	 * @since 9.0.0
46
-	 *
47
-	 * To be used as replacement for user type actors in deleteReferencesOfActor().
48
-	 *
49
-	 * User interfaces shall show "Deleted user" as display name, if needed.
50
-	 */
51
-	public const DELETED_USER = 'deleted_users';
42
+    /**
43
+     * @const DELETED_USER type and id for a user that has been deleted
44
+     * @see deleteReferencesOfActor
45
+     * @since 9.0.0
46
+     *
47
+     * To be used as replacement for user type actors in deleteReferencesOfActor().
48
+     *
49
+     * User interfaces shall show "Deleted user" as display name, if needed.
50
+     */
51
+    public const DELETED_USER = 'deleted_users';
52 52
 
53
-	/**
54
-	 * returns a comment instance
55
-	 *
56
-	 * @param string $id the ID of the comment
57
-	 * @return IComment
58
-	 * @throws NotFoundException
59
-	 * @since 9.0.0
60
-	 */
61
-	public function get($id);
53
+    /**
54
+     * returns a comment instance
55
+     *
56
+     * @param string $id the ID of the comment
57
+     * @return IComment
58
+     * @throws NotFoundException
59
+     * @since 9.0.0
60
+     */
61
+    public function get($id);
62 62
 
63
-	/**
64
-	 * returns the comment specified by the id and all it's child comments
65
-	 *
66
-	 * @param string $id
67
-	 * @param int $limit max number of entries to return, 0 returns all
68
-	 * @param int $offset the start entry
69
-	 * @return array
70
-	 * @since 9.0.0
71
-	 *
72
-	 * The return array looks like this
73
-	 * [
74
-	 * 	 'comment' => IComment, // root comment
75
-	 *   'replies' =>
76
-	 *   [
77
-	 *     0 =>
78
-	 *     [
79
-	 *       'comment' => IComment,
80
-	 *       'replies' =>
81
-	 *       [
82
-	 *         0 =>
83
-	 *         [
84
-	 *           'comment' => IComment,
85
-	 *           'replies' => [ … ]
86
-	 *         ],
87
-	 *         …
88
-	 *       ]
89
-	 *     ]
90
-	 *     1 =>
91
-	 *     [
92
-	 *       'comment' => IComment,
93
-	 *       'replies'=> [ … ]
94
-	 *     ],
95
-	 *     …
96
-	 *   ]
97
-	 * ]
98
-	 */
99
-	public function getTree($id, $limit = 0, $offset = 0);
63
+    /**
64
+     * returns the comment specified by the id and all it's child comments
65
+     *
66
+     * @param string $id
67
+     * @param int $limit max number of entries to return, 0 returns all
68
+     * @param int $offset the start entry
69
+     * @return array
70
+     * @since 9.0.0
71
+     *
72
+     * The return array looks like this
73
+     * [
74
+     * 	 'comment' => IComment, // root comment
75
+     *   'replies' =>
76
+     *   [
77
+     *     0 =>
78
+     *     [
79
+     *       'comment' => IComment,
80
+     *       'replies' =>
81
+     *       [
82
+     *         0 =>
83
+     *         [
84
+     *           'comment' => IComment,
85
+     *           'replies' => [ … ]
86
+     *         ],
87
+     *         …
88
+     *       ]
89
+     *     ]
90
+     *     1 =>
91
+     *     [
92
+     *       'comment' => IComment,
93
+     *       'replies'=> [ … ]
94
+     *     ],
95
+     *     …
96
+     *   ]
97
+     * ]
98
+     */
99
+    public function getTree($id, $limit = 0, $offset = 0);
100 100
 
101
-	/**
102
-	 * returns comments for a specific object (e.g. a file).
103
-	 *
104
-	 * The sort order is always newest to oldest.
105
-	 *
106
-	 * @param string $objectType the object type, e.g. 'files'
107
-	 * @param string $objectId the id of the object
108
-	 * @param int $limit optional, number of maximum comments to be returned. if
109
-	 * not specified, all comments are returned.
110
-	 * @param int $offset optional, starting point
111
-	 * @param \DateTime|null $notOlderThan optional, timestamp of the oldest comments
112
-	 * that may be returned
113
-	 * @return IComment[]
114
-	 * @since 9.0.0
115
-	 */
116
-	public function getForObject(
117
-			$objectType,
118
-			$objectId,
119
-			$limit = 0,
120
-			$offset = 0,
121
-			\DateTime $notOlderThan = null
122
-	);
101
+    /**
102
+     * returns comments for a specific object (e.g. a file).
103
+     *
104
+     * The sort order is always newest to oldest.
105
+     *
106
+     * @param string $objectType the object type, e.g. 'files'
107
+     * @param string $objectId the id of the object
108
+     * @param int $limit optional, number of maximum comments to be returned. if
109
+     * not specified, all comments are returned.
110
+     * @param int $offset optional, starting point
111
+     * @param \DateTime|null $notOlderThan optional, timestamp of the oldest comments
112
+     * that may be returned
113
+     * @return IComment[]
114
+     * @since 9.0.0
115
+     */
116
+    public function getForObject(
117
+            $objectType,
118
+            $objectId,
119
+            $limit = 0,
120
+            $offset = 0,
121
+            \DateTime $notOlderThan = null
122
+    );
123 123
 
124
-	/**
125
-	 * @param string $objectType the object type, e.g. 'files'
126
-	 * @param string $objectId the id of the object
127
-	 * @param int $lastKnownCommentId the last known comment (will be used as offset)
128
-	 * @param string $sortDirection direction of the comments (`asc` or `desc`)
129
-	 * @param int $limit optional, number of maximum comments to be returned. if
130
-	 * set to 0, all comments are returned.
131
-	 * @return IComment[]
132
-	 * @since 14.0.0
133
-	 */
134
-	public function getForObjectSince(
135
-		string $objectType,
136
-		string $objectId,
137
-		int $lastKnownCommentId,
138
-		string $sortDirection = 'asc',
139
-		int $limit = 30
140
-	): array;
124
+    /**
125
+     * @param string $objectType the object type, e.g. 'files'
126
+     * @param string $objectId the id of the object
127
+     * @param int $lastKnownCommentId the last known comment (will be used as offset)
128
+     * @param string $sortDirection direction of the comments (`asc` or `desc`)
129
+     * @param int $limit optional, number of maximum comments to be returned. if
130
+     * set to 0, all comments are returned.
131
+     * @return IComment[]
132
+     * @since 14.0.0
133
+     */
134
+    public function getForObjectSince(
135
+        string $objectType,
136
+        string $objectId,
137
+        int $lastKnownCommentId,
138
+        string $sortDirection = 'asc',
139
+        int $limit = 30
140
+    ): array;
141 141
 
142
-	/**
143
-	 * Search for comments with a given content
144
-	 *
145
-	 * @param string $search content to search for
146
-	 * @param string $objectType Limit the search by object type
147
-	 * @param string $objectId Limit the search by object id
148
-	 * @param string $verb Limit the verb of the comment
149
-	 * @param int $offset
150
-	 * @param int $limit
151
-	 * @return IComment[]
152
-	 * @since 14.0.0
153
-	 */
154
-	public function search(string $search, string $objectType, string $objectId, string $verb, int $offset, int $limit = 50): array;
142
+    /**
143
+     * Search for comments with a given content
144
+     *
145
+     * @param string $search content to search for
146
+     * @param string $objectType Limit the search by object type
147
+     * @param string $objectId Limit the search by object id
148
+     * @param string $verb Limit the verb of the comment
149
+     * @param int $offset
150
+     * @param int $limit
151
+     * @return IComment[]
152
+     * @since 14.0.0
153
+     */
154
+    public function search(string $search, string $objectType, string $objectId, string $verb, int $offset, int $limit = 50): array;
155 155
 
156
-	/**
157
-	 * @param $objectType string the object type, e.g. 'files'
158
-	 * @param $objectId string the id of the object
159
-	 * @param \DateTime|null $notOlderThan optional, timestamp of the oldest comments
160
-	 * that may be returned
161
-	 * @param string $verb Limit the verb of the comment - Added in 14.0.0
162
-	 * @return Int
163
-	 * @since 9.0.0
164
-	 */
165
-	public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null, $verb = '');
156
+    /**
157
+     * @param $objectType string the object type, e.g. 'files'
158
+     * @param $objectId string the id of the object
159
+     * @param \DateTime|null $notOlderThan optional, timestamp of the oldest comments
160
+     * that may be returned
161
+     * @param string $verb Limit the verb of the comment - Added in 14.0.0
162
+     * @return Int
163
+     * @since 9.0.0
164
+     */
165
+    public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null, $verb = '');
166 166
 
167
-	/**
168
-	 * Get the number of unread comments for all files in a folder
169
-	 *
170
-	 * @param int $folderId
171
-	 * @param IUser $user
172
-	 * @return array [$fileId => $unreadCount]
173
-	 * @since 12.0.0
174
-	 */
175
-	public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user);
167
+    /**
168
+     * Get the number of unread comments for all files in a folder
169
+     *
170
+     * @param int $folderId
171
+     * @param IUser $user
172
+     * @return array [$fileId => $unreadCount]
173
+     * @since 12.0.0
174
+     */
175
+    public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user);
176 176
 
177
-	/**
178
-	 * creates a new comment and returns it. At this point of time, it is not
179
-	 * saved in the used data storage. Use save() after setting other fields
180
-	 * of the comment (e.g. message or verb).
181
-	 *
182
-	 * @param string $actorType the actor type (e.g. 'users')
183
-	 * @param string $actorId a user id
184
-	 * @param string $objectType the object type the comment is attached to
185
-	 * @param string $objectId the object id the comment is attached to
186
-	 * @return IComment
187
-	 * @since 9.0.0
188
-	 */
189
-	public function create($actorType, $actorId, $objectType, $objectId);
177
+    /**
178
+     * creates a new comment and returns it. At this point of time, it is not
179
+     * saved in the used data storage. Use save() after setting other fields
180
+     * of the comment (e.g. message or verb).
181
+     *
182
+     * @param string $actorType the actor type (e.g. 'users')
183
+     * @param string $actorId a user id
184
+     * @param string $objectType the object type the comment is attached to
185
+     * @param string $objectId the object id the comment is attached to
186
+     * @return IComment
187
+     * @since 9.0.0
188
+     */
189
+    public function create($actorType, $actorId, $objectType, $objectId);
190 190
 
191
-	/**
192
-	 * permanently deletes the comment specified by the ID
193
-	 *
194
-	 * When the comment has child comments, their parent ID will be changed to
195
-	 * the parent ID of the item that is to be deleted.
196
-	 *
197
-	 * @param string $id
198
-	 * @return bool
199
-	 * @since 9.0.0
200
-	 */
201
-	public function delete($id);
191
+    /**
192
+     * permanently deletes the comment specified by the ID
193
+     *
194
+     * When the comment has child comments, their parent ID will be changed to
195
+     * the parent ID of the item that is to be deleted.
196
+     *
197
+     * @param string $id
198
+     * @return bool
199
+     * @since 9.0.0
200
+     */
201
+    public function delete($id);
202 202
 
203
-	/**
204
-	 * saves the comment permanently
205
-	 *
206
-	 * if the supplied comment has an empty ID, a new entry comment will be
207
-	 * saved and the instance updated with the new ID.
208
-	 *
209
-	 * Otherwise, an existing comment will be updated.
210
-	 *
211
-	 * Throws NotFoundException when a comment that is to be updated does not
212
-	 * exist anymore at this point of time.
213
-	 *
214
-	 * @param IComment $comment
215
-	 * @return bool
216
-	 * @throws NotFoundException
217
-	 * @since 9.0.0
218
-	 */
219
-	public function save(IComment $comment);
203
+    /**
204
+     * saves the comment permanently
205
+     *
206
+     * if the supplied comment has an empty ID, a new entry comment will be
207
+     * saved and the instance updated with the new ID.
208
+     *
209
+     * Otherwise, an existing comment will be updated.
210
+     *
211
+     * Throws NotFoundException when a comment that is to be updated does not
212
+     * exist anymore at this point of time.
213
+     *
214
+     * @param IComment $comment
215
+     * @return bool
216
+     * @throws NotFoundException
217
+     * @since 9.0.0
218
+     */
219
+    public function save(IComment $comment);
220 220
 
221
-	/**
222
-	 * removes references to specific actor (e.g. on user delete) of a comment.
223
-	 * The comment itself must not get lost/deleted.
224
-	 *
225
-	 * A 'users' type actor (type and id) should get replaced by the
226
-	 * value of the DELETED_USER constant of this interface.
227
-	 *
228
-	 * @param string $actorType the actor type (e.g. 'users')
229
-	 * @param string $actorId a user id
230
-	 * @return boolean
231
-	 * @since 9.0.0
232
-	 */
233
-	public function deleteReferencesOfActor($actorType, $actorId);
221
+    /**
222
+     * removes references to specific actor (e.g. on user delete) of a comment.
223
+     * The comment itself must not get lost/deleted.
224
+     *
225
+     * A 'users' type actor (type and id) should get replaced by the
226
+     * value of the DELETED_USER constant of this interface.
227
+     *
228
+     * @param string $actorType the actor type (e.g. 'users')
229
+     * @param string $actorId a user id
230
+     * @return boolean
231
+     * @since 9.0.0
232
+     */
233
+    public function deleteReferencesOfActor($actorType, $actorId);
234 234
 
235
-	/**
236
-	 * deletes all comments made of a specific object (e.g. on file delete)
237
-	 *
238
-	 * @param string $objectType the object type (e.g. 'files')
239
-	 * @param string $objectId e.g. the file id
240
-	 * @return boolean
241
-	 * @since 9.0.0
242
-	 */
243
-	public function deleteCommentsAtObject($objectType, $objectId);
235
+    /**
236
+     * deletes all comments made of a specific object (e.g. on file delete)
237
+     *
238
+     * @param string $objectType the object type (e.g. 'files')
239
+     * @param string $objectId e.g. the file id
240
+     * @return boolean
241
+     * @since 9.0.0
242
+     */
243
+    public function deleteCommentsAtObject($objectType, $objectId);
244 244
 
245
-	/**
246
-	 * sets the read marker for a given file to the specified date for the
247
-	 * provided user
248
-	 *
249
-	 * @param string $objectType
250
-	 * @param string $objectId
251
-	 * @param \DateTime $dateTime
252
-	 * @param \OCP\IUser $user
253
-	 * @since 9.0.0
254
-	 */
255
-	public function setReadMark($objectType, $objectId, \DateTime $dateTime, \OCP\IUser $user);
245
+    /**
246
+     * sets the read marker for a given file to the specified date for the
247
+     * provided user
248
+     *
249
+     * @param string $objectType
250
+     * @param string $objectId
251
+     * @param \DateTime $dateTime
252
+     * @param \OCP\IUser $user
253
+     * @since 9.0.0
254
+     */
255
+    public function setReadMark($objectType, $objectId, \DateTime $dateTime, \OCP\IUser $user);
256 256
 
257
-	/**
258
-	 * returns the read marker for a given file to the specified date for the
259
-	 * provided user. It returns null, when the marker is not present, i.e.
260
-	 * no comments were marked as read.
261
-	 *
262
-	 * @param string $objectType
263
-	 * @param string $objectId
264
-	 * @param \OCP\IUser $user
265
-	 * @return \DateTime|null
266
-	 * @since 9.0.0
267
-	 */
268
-	public function getReadMark($objectType, $objectId, \OCP\IUser $user);
257
+    /**
258
+     * returns the read marker for a given file to the specified date for the
259
+     * provided user. It returns null, when the marker is not present, i.e.
260
+     * no comments were marked as read.
261
+     *
262
+     * @param string $objectType
263
+     * @param string $objectId
264
+     * @param \OCP\IUser $user
265
+     * @return \DateTime|null
266
+     * @since 9.0.0
267
+     */
268
+    public function getReadMark($objectType, $objectId, \OCP\IUser $user);
269 269
 
270
-	/**
271
-	 * deletes the read markers for the specified user
272
-	 *
273
-	 * @param \OCP\IUser $user
274
-	 * @return bool
275
-	 * @since 9.0.0
276
-	 */
277
-	public function deleteReadMarksFromUser(\OCP\IUser $user);
270
+    /**
271
+     * deletes the read markers for the specified user
272
+     *
273
+     * @param \OCP\IUser $user
274
+     * @return bool
275
+     * @since 9.0.0
276
+     */
277
+    public function deleteReadMarksFromUser(\OCP\IUser $user);
278 278
 
279
-	/**
280
-	 * deletes the read markers on the specified object
281
-	 *
282
-	 * @param string $objectType
283
-	 * @param string $objectId
284
-	 * @return bool
285
-	 * @since 9.0.0
286
-	 */
287
-	public function deleteReadMarksOnObject($objectType, $objectId);
279
+    /**
280
+     * deletes the read markers on the specified object
281
+     *
282
+     * @param string $objectType
283
+     * @param string $objectId
284
+     * @return bool
285
+     * @since 9.0.0
286
+     */
287
+    public function deleteReadMarksOnObject($objectType, $objectId);
288 288
 
289
-	/**
290
-	 * registers an Entity to the manager, so event notifications can be send
291
-	 * to consumers of the comments infrastructure
292
-	 *
293
-	 * @param \Closure $closure
294
-	 * @since 11.0.0
295
-	 */
296
-	public function registerEventHandler(\Closure $closure);
289
+    /**
290
+     * registers an Entity to the manager, so event notifications can be send
291
+     * to consumers of the comments infrastructure
292
+     *
293
+     * @param \Closure $closure
294
+     * @since 11.0.0
295
+     */
296
+    public function registerEventHandler(\Closure $closure);
297 297
 
298
-	/**
299
-	 * registers a method that resolves an ID to a display name for a given type
300
-	 *
301
-	 * @param string $type
302
-	 * @param \Closure $closure
303
-	 * @throws \OutOfBoundsException
304
-	 * @since 11.0.0
305
-	 *
306
-	 * Only one resolver shall be registered per type. Otherwise a
307
-	 * \OutOfBoundsException has to thrown.
308
-	 */
309
-	public function registerDisplayNameResolver($type, \Closure $closure);
298
+    /**
299
+     * registers a method that resolves an ID to a display name for a given type
300
+     *
301
+     * @param string $type
302
+     * @param \Closure $closure
303
+     * @throws \OutOfBoundsException
304
+     * @since 11.0.0
305
+     *
306
+     * Only one resolver shall be registered per type. Otherwise a
307
+     * \OutOfBoundsException has to thrown.
308
+     */
309
+    public function registerDisplayNameResolver($type, \Closure $closure);
310 310
 
311
-	/**
312
-	 * resolves a given ID of a given Type to a display name.
313
-	 *
314
-	 * @param string $type
315
-	 * @param string $id
316
-	 * @return string
317
-	 * @throws \OutOfBoundsException
318
-	 * @since 11.0.0
319
-	 *
320
-	 * If a provided type was not registered, an \OutOfBoundsException shall
321
-	 * be thrown. It is upon the resolver discretion what to return of the
322
-	 * provided ID is unknown. It must be ensured that a string is returned.
323
-	 */
324
-	public function resolveDisplayName($type, $id);
311
+    /**
312
+     * resolves a given ID of a given Type to a display name.
313
+     *
314
+     * @param string $type
315
+     * @param string $id
316
+     * @return string
317
+     * @throws \OutOfBoundsException
318
+     * @since 11.0.0
319
+     *
320
+     * If a provided type was not registered, an \OutOfBoundsException shall
321
+     * be thrown. It is upon the resolver discretion what to return of the
322
+     * provided ID is unknown. It must be ensured that a string is returned.
323
+     */
324
+    public function resolveDisplayName($type, $id);
325 325
 
326
-	/**
327
-	 * Load the Comments app into the page
328
-	 *
329
-	 * @since 21.0.0
330
-	 */
331
-	public function load(): void;
326
+    /**
327
+     * Load the Comments app into the page
328
+     *
329
+     * @since 21.0.0
330
+     */
331
+    public function load(): void;
332 332
 }
Please login to merge, or discard this patch.
lib/private/Collaboration/Collaborators/UserPlugin.php 1 patch
Indentation   +209 added lines, -209 removed lines patch added patch discarded remove patch
@@ -43,213 +43,213 @@
 block discarded – undo
43 43
 use OCP\UserStatus\IManager as IUserStatusManager;
44 44
 
45 45
 class UserPlugin implements ISearchPlugin {
46
-	/* @var bool */
47
-	protected $shareWithGroupOnly;
48
-	protected $shareeEnumeration;
49
-	protected $shareeEnumerationInGroupOnly;
50
-
51
-	/** @var IConfig */
52
-	private $config;
53
-	/** @var IGroupManager */
54
-	private $groupManager;
55
-	/** @var IUserSession */
56
-	private $userSession;
57
-	/** @var IUserManager */
58
-	private $userManager;
59
-	/** @var IUserStatusManager */
60
-	private $userStatusManager;
61
-
62
-	/**
63
-	 * UserPlugin constructor.
64
-	 *
65
-	 * @param IConfig $config
66
-	 * @param IUserManager $userManager
67
-	 * @param IGroupManager $groupManager
68
-	 * @param IUserSession $userSession
69
-	 * @param IUserStatusManager $userStatusManager
70
-	 */
71
-	public function __construct(IConfig $config,
72
-								IUserManager $userManager,
73
-								IGroupManager $groupManager,
74
-								IUserSession $userSession,
75
-								IUserStatusManager $userStatusManager) {
76
-		$this->config = $config;
77
-
78
-		$this->groupManager = $groupManager;
79
-		$this->userSession = $userSession;
80
-		$this->userManager = $userManager;
81
-		$this->userStatusManager = $userStatusManager;
82
-
83
-		$this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
84
-		$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
85
-		$this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
86
-	}
87
-
88
-	public function search($search, $limit, $offset, ISearchResult $searchResult) {
89
-		$result = ['wide' => [], 'exact' => []];
90
-		$users = [];
91
-		$hasMoreResults = false;
92
-
93
-		$currentUserGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
94
-		if ($this->shareWithGroupOnly) {
95
-			// Search in all the groups this user is part of
96
-			foreach ($currentUserGroups as $userGroupId) {
97
-				$usersInGroup = $this->groupManager->displayNamesInGroup($userGroupId, $search, $limit, $offset);
98
-				foreach ($usersInGroup as $userId => $displayName) {
99
-					$userId = (string) $userId;
100
-					$user = $this->userManager->get($userId);
101
-					if (!$user->isEnabled()) {
102
-						// Ignore disabled users
103
-						continue;
104
-					}
105
-					$users[$userId] = $user;
106
-				}
107
-				if (count($usersInGroup) >= $limit) {
108
-					$hasMoreResults = true;
109
-				}
110
-			}
111
-		} else {
112
-			// Search in all users
113
-			$usersTmp = $this->userManager->searchDisplayName($search, $limit, $offset);
114
-			foreach ($usersTmp as $user) {
115
-				if ($user->isEnabled()) { // Don't keep deactivated users
116
-					$users[$user->getUID()] = $user;
117
-				}
118
-			}
119
-		}
120
-
121
-		$this->takeOutCurrentUser($users);
122
-
123
-		if (!$this->shareeEnumeration || count($users) < $limit) {
124
-			$hasMoreResults = true;
125
-		}
126
-
127
-		$foundUserById = false;
128
-		$lowerSearch = strtolower($search);
129
-		$userStatuses = $this->userStatusManager->getUserStatuses(array_keys($users));
130
-		foreach ($users as $uid => $user) {
131
-			$userDisplayName = $user->getDisplayName();
132
-			$userEmail = $user->getEMailAddress();
133
-			$uid = (string) $uid;
134
-
135
-			$status = [];
136
-			if (array_key_exists($uid, $userStatuses)) {
137
-				$userStatus = $userStatuses[$uid];
138
-				$status = [
139
-					'status' => $userStatus->getStatus(),
140
-					'message' => $userStatus->getMessage(),
141
-					'icon' => $userStatus->getIcon(),
142
-					'clearAt' => $userStatus->getClearAt()
143
-						? (int)$userStatus->getClearAt()->format('U')
144
-						: null,
145
-				];
146
-			}
147
-
148
-
149
-			if (
150
-				$lowerSearch !== '' && (strtolower($uid) === $lowerSearch ||
151
-				strtolower($userDisplayName) === $lowerSearch ||
152
-				strtolower($userEmail) === $lowerSearch)
153
-			) {
154
-				if (strtolower($uid) === $lowerSearch) {
155
-					$foundUserById = true;
156
-				}
157
-				$result['exact'][] = [
158
-					'label' => $userDisplayName,
159
-					'subline' => $status['message'] ?? '',
160
-					'icon' => 'icon-user',
161
-					'value' => [
162
-						'shareType' => IShare::TYPE_USER,
163
-						'shareWith' => $uid,
164
-					],
165
-					'status' => $status,
166
-				];
167
-			} else {
168
-				$addToWideResults = false;
169
-				if ($this->shareeEnumeration && !$this->shareeEnumerationInGroupOnly) {
170
-					$addToWideResults = true;
171
-				}
172
-
173
-				if ($this->shareeEnumerationInGroupOnly) {
174
-					$commonGroups = array_intersect($currentUserGroups, $this->groupManager->getUserGroupIds($user));
175
-					if (!empty($commonGroups)) {
176
-						$addToWideResults = true;
177
-					}
178
-				}
179
-
180
-				if ($addToWideResults) {
181
-					$result['wide'][] = [
182
-						'label' => $userDisplayName,
183
-						'subline' => $status['message'] ?? '',
184
-						'icon' => 'icon-user',
185
-						'value' => [
186
-							'shareType' => IShare::TYPE_USER,
187
-							'shareWith' => $uid,
188
-						],
189
-						'status' => $status,
190
-					];
191
-				}
192
-			}
193
-		}
194
-
195
-		if ($offset === 0 && !$foundUserById) {
196
-			// On page one we try if the search result has a direct hit on the
197
-			// user id and if so, we add that to the exact match list
198
-			$user = $this->userManager->get($search);
199
-			if ($user instanceof IUser) {
200
-				$addUser = true;
201
-
202
-				if ($this->shareWithGroupOnly) {
203
-					// Only add, if we have a common group
204
-					$commonGroups = array_intersect($currentUserGroups, $this->groupManager->getUserGroupIds($user));
205
-					$addUser = !empty($commonGroups);
206
-				}
207
-
208
-				if ($addUser) {
209
-					$status = [];
210
-					if (array_key_exists($user->getUID(), $userStatuses)) {
211
-						$userStatus = $userStatuses[$user->getUID()];
212
-						$status = [
213
-							'status' => $userStatus->getStatus(),
214
-							'message' => $userStatus->getMessage(),
215
-							'icon' => $userStatus->getIcon(),
216
-							'clearAt' => $userStatus->getClearAt()
217
-								? (int)$userStatus->getClearAt()->format('U')
218
-								: null,
219
-						];
220
-					}
221
-
222
-					$result['exact'][] = [
223
-						'label' => $user->getDisplayName(),
224
-						'icon' => 'icon-user',
225
-						'subline' => $status['message'] ?? '',
226
-						'value' => [
227
-							'shareType' => IShare::TYPE_USER,
228
-							'shareWith' => $user->getUID(),
229
-						],
230
-						'status' => $status,
231
-					];
232
-				}
233
-			}
234
-		}
235
-
236
-
237
-
238
-		$type = new SearchResultType('users');
239
-		$searchResult->addResultSet($type, $result['wide'], $result['exact']);
240
-		if (count($result['exact'])) {
241
-			$searchResult->markExactIdMatch($type);
242
-		}
243
-
244
-		return $hasMoreResults;
245
-	}
246
-
247
-	public function takeOutCurrentUser(array &$users) {
248
-		$currentUser = $this->userSession->getUser();
249
-		if (!is_null($currentUser)) {
250
-			if (isset($users[$currentUser->getUID()])) {
251
-				unset($users[$currentUser->getUID()]);
252
-			}
253
-		}
254
-	}
46
+    /* @var bool */
47
+    protected $shareWithGroupOnly;
48
+    protected $shareeEnumeration;
49
+    protected $shareeEnumerationInGroupOnly;
50
+
51
+    /** @var IConfig */
52
+    private $config;
53
+    /** @var IGroupManager */
54
+    private $groupManager;
55
+    /** @var IUserSession */
56
+    private $userSession;
57
+    /** @var IUserManager */
58
+    private $userManager;
59
+    /** @var IUserStatusManager */
60
+    private $userStatusManager;
61
+
62
+    /**
63
+     * UserPlugin constructor.
64
+     *
65
+     * @param IConfig $config
66
+     * @param IUserManager $userManager
67
+     * @param IGroupManager $groupManager
68
+     * @param IUserSession $userSession
69
+     * @param IUserStatusManager $userStatusManager
70
+     */
71
+    public function __construct(IConfig $config,
72
+                                IUserManager $userManager,
73
+                                IGroupManager $groupManager,
74
+                                IUserSession $userSession,
75
+                                IUserStatusManager $userStatusManager) {
76
+        $this->config = $config;
77
+
78
+        $this->groupManager = $groupManager;
79
+        $this->userSession = $userSession;
80
+        $this->userManager = $userManager;
81
+        $this->userStatusManager = $userStatusManager;
82
+
83
+        $this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes';
84
+        $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
85
+        $this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes';
86
+    }
87
+
88
+    public function search($search, $limit, $offset, ISearchResult $searchResult) {
89
+        $result = ['wide' => [], 'exact' => []];
90
+        $users = [];
91
+        $hasMoreResults = false;
92
+
93
+        $currentUserGroups = $this->groupManager->getUserGroupIds($this->userSession->getUser());
94
+        if ($this->shareWithGroupOnly) {
95
+            // Search in all the groups this user is part of
96
+            foreach ($currentUserGroups as $userGroupId) {
97
+                $usersInGroup = $this->groupManager->displayNamesInGroup($userGroupId, $search, $limit, $offset);
98
+                foreach ($usersInGroup as $userId => $displayName) {
99
+                    $userId = (string) $userId;
100
+                    $user = $this->userManager->get($userId);
101
+                    if (!$user->isEnabled()) {
102
+                        // Ignore disabled users
103
+                        continue;
104
+                    }
105
+                    $users[$userId] = $user;
106
+                }
107
+                if (count($usersInGroup) >= $limit) {
108
+                    $hasMoreResults = true;
109
+                }
110
+            }
111
+        } else {
112
+            // Search in all users
113
+            $usersTmp = $this->userManager->searchDisplayName($search, $limit, $offset);
114
+            foreach ($usersTmp as $user) {
115
+                if ($user->isEnabled()) { // Don't keep deactivated users
116
+                    $users[$user->getUID()] = $user;
117
+                }
118
+            }
119
+        }
120
+
121
+        $this->takeOutCurrentUser($users);
122
+
123
+        if (!$this->shareeEnumeration || count($users) < $limit) {
124
+            $hasMoreResults = true;
125
+        }
126
+
127
+        $foundUserById = false;
128
+        $lowerSearch = strtolower($search);
129
+        $userStatuses = $this->userStatusManager->getUserStatuses(array_keys($users));
130
+        foreach ($users as $uid => $user) {
131
+            $userDisplayName = $user->getDisplayName();
132
+            $userEmail = $user->getEMailAddress();
133
+            $uid = (string) $uid;
134
+
135
+            $status = [];
136
+            if (array_key_exists($uid, $userStatuses)) {
137
+                $userStatus = $userStatuses[$uid];
138
+                $status = [
139
+                    'status' => $userStatus->getStatus(),
140
+                    'message' => $userStatus->getMessage(),
141
+                    'icon' => $userStatus->getIcon(),
142
+                    'clearAt' => $userStatus->getClearAt()
143
+                        ? (int)$userStatus->getClearAt()->format('U')
144
+                        : null,
145
+                ];
146
+            }
147
+
148
+
149
+            if (
150
+                $lowerSearch !== '' && (strtolower($uid) === $lowerSearch ||
151
+                strtolower($userDisplayName) === $lowerSearch ||
152
+                strtolower($userEmail) === $lowerSearch)
153
+            ) {
154
+                if (strtolower($uid) === $lowerSearch) {
155
+                    $foundUserById = true;
156
+                }
157
+                $result['exact'][] = [
158
+                    'label' => $userDisplayName,
159
+                    'subline' => $status['message'] ?? '',
160
+                    'icon' => 'icon-user',
161
+                    'value' => [
162
+                        'shareType' => IShare::TYPE_USER,
163
+                        'shareWith' => $uid,
164
+                    ],
165
+                    'status' => $status,
166
+                ];
167
+            } else {
168
+                $addToWideResults = false;
169
+                if ($this->shareeEnumeration && !$this->shareeEnumerationInGroupOnly) {
170
+                    $addToWideResults = true;
171
+                }
172
+
173
+                if ($this->shareeEnumerationInGroupOnly) {
174
+                    $commonGroups = array_intersect($currentUserGroups, $this->groupManager->getUserGroupIds($user));
175
+                    if (!empty($commonGroups)) {
176
+                        $addToWideResults = true;
177
+                    }
178
+                }
179
+
180
+                if ($addToWideResults) {
181
+                    $result['wide'][] = [
182
+                        'label' => $userDisplayName,
183
+                        'subline' => $status['message'] ?? '',
184
+                        'icon' => 'icon-user',
185
+                        'value' => [
186
+                            'shareType' => IShare::TYPE_USER,
187
+                            'shareWith' => $uid,
188
+                        ],
189
+                        'status' => $status,
190
+                    ];
191
+                }
192
+            }
193
+        }
194
+
195
+        if ($offset === 0 && !$foundUserById) {
196
+            // On page one we try if the search result has a direct hit on the
197
+            // user id and if so, we add that to the exact match list
198
+            $user = $this->userManager->get($search);
199
+            if ($user instanceof IUser) {
200
+                $addUser = true;
201
+
202
+                if ($this->shareWithGroupOnly) {
203
+                    // Only add, if we have a common group
204
+                    $commonGroups = array_intersect($currentUserGroups, $this->groupManager->getUserGroupIds($user));
205
+                    $addUser = !empty($commonGroups);
206
+                }
207
+
208
+                if ($addUser) {
209
+                    $status = [];
210
+                    if (array_key_exists($user->getUID(), $userStatuses)) {
211
+                        $userStatus = $userStatuses[$user->getUID()];
212
+                        $status = [
213
+                            'status' => $userStatus->getStatus(),
214
+                            'message' => $userStatus->getMessage(),
215
+                            'icon' => $userStatus->getIcon(),
216
+                            'clearAt' => $userStatus->getClearAt()
217
+                                ? (int)$userStatus->getClearAt()->format('U')
218
+                                : null,
219
+                        ];
220
+                    }
221
+
222
+                    $result['exact'][] = [
223
+                        'label' => $user->getDisplayName(),
224
+                        'icon' => 'icon-user',
225
+                        'subline' => $status['message'] ?? '',
226
+                        'value' => [
227
+                            'shareType' => IShare::TYPE_USER,
228
+                            'shareWith' => $user->getUID(),
229
+                        ],
230
+                        'status' => $status,
231
+                    ];
232
+                }
233
+            }
234
+        }
235
+
236
+
237
+
238
+        $type = new SearchResultType('users');
239
+        $searchResult->addResultSet($type, $result['wide'], $result['exact']);
240
+        if (count($result['exact'])) {
241
+            $searchResult->markExactIdMatch($type);
242
+        }
243
+
244
+        return $hasMoreResults;
245
+    }
246
+
247
+    public function takeOutCurrentUser(array &$users) {
248
+        $currentUser = $this->userSession->getUser();
249
+        if (!is_null($currentUser)) {
250
+            if (isset($users[$currentUser->getUID()])) {
251
+                unset($users[$currentUser->getUID()]);
252
+            }
253
+        }
254
+    }
255 255
 }
Please login to merge, or discard this patch.
lib/private/Comments/Manager.php 1 patch
Indentation   +1090 added lines, -1090 removed lines patch added patch discarded remove patch
@@ -46,1094 +46,1094 @@
 block discarded – undo
46 46
 
47 47
 class Manager implements ICommentsManager {
48 48
 
49
-	/** @var  IDBConnection */
50
-	protected $dbConn;
51
-
52
-	/** @var  LoggerInterface */
53
-	protected $logger;
54
-
55
-	/** @var IConfig */
56
-	protected $config;
57
-
58
-	/** @var IInitialStateService */
59
-	protected $initialStateService;
60
-
61
-	/** @var IComment[] */
62
-	protected $commentsCache = [];
63
-
64
-	/** @var  \Closure[] */
65
-	protected $eventHandlerClosures = [];
66
-
67
-	/** @var  ICommentsEventHandler[] */
68
-	protected $eventHandlers = [];
69
-
70
-	/** @var \Closure[] */
71
-	protected $displayNameResolvers = [];
72
-
73
-	public function __construct(IDBConnection $dbConn,
74
-								LoggerInterface $logger,
75
-								IConfig $config,
76
-								IInitialStateService $initialStateService) {
77
-		$this->dbConn = $dbConn;
78
-		$this->logger = $logger;
79
-		$this->config = $config;
80
-		$this->initialStateService = $initialStateService;
81
-	}
82
-
83
-	/**
84
-	 * converts data base data into PHP native, proper types as defined by
85
-	 * IComment interface.
86
-	 *
87
-	 * @param array $data
88
-	 * @return array
89
-	 */
90
-	protected function normalizeDatabaseData(array $data) {
91
-		$data['id'] = (string)$data['id'];
92
-		$data['parent_id'] = (string)$data['parent_id'];
93
-		$data['topmost_parent_id'] = (string)$data['topmost_parent_id'];
94
-		$data['creation_timestamp'] = new \DateTime($data['creation_timestamp']);
95
-		if (!is_null($data['latest_child_timestamp'])) {
96
-			$data['latest_child_timestamp'] = new \DateTime($data['latest_child_timestamp']);
97
-		}
98
-		$data['children_count'] = (int)$data['children_count'];
99
-		$data['reference_id'] = $data['reference_id'] ?? null;
100
-		return $data;
101
-	}
102
-
103
-
104
-	/**
105
-	 * @param array $data
106
-	 * @return IComment
107
-	 */
108
-	public function getCommentFromData(array $data): IComment {
109
-		return new Comment($this->normalizeDatabaseData($data));
110
-	}
111
-
112
-	/**
113
-	 * prepares a comment for an insert or update operation after making sure
114
-	 * all necessary fields have a value assigned.
115
-	 *
116
-	 * @param IComment $comment
117
-	 * @return IComment returns the same updated IComment instance as provided
118
-	 *                  by parameter for convenience
119
-	 * @throws \UnexpectedValueException
120
-	 */
121
-	protected function prepareCommentForDatabaseWrite(IComment $comment) {
122
-		if (!$comment->getActorType()
123
-			|| $comment->getActorId() === ''
124
-			|| !$comment->getObjectType()
125
-			|| $comment->getObjectId() === ''
126
-			|| !$comment->getVerb()
127
-		) {
128
-			throw new \UnexpectedValueException('Actor, Object and Verb information must be provided for saving');
129
-		}
130
-
131
-		if ($comment->getId() === '') {
132
-			$comment->setChildrenCount(0);
133
-			$comment->setLatestChildDateTime(new \DateTime('0000-00-00 00:00:00', new \DateTimeZone('UTC')));
134
-			$comment->setLatestChildDateTime(null);
135
-		}
136
-
137
-		if (is_null($comment->getCreationDateTime())) {
138
-			$comment->setCreationDateTime(new \DateTime());
139
-		}
140
-
141
-		if ($comment->getParentId() !== '0') {
142
-			$comment->setTopmostParentId($this->determineTopmostParentId($comment->getParentId()));
143
-		} else {
144
-			$comment->setTopmostParentId('0');
145
-		}
146
-
147
-		$this->cache($comment);
148
-
149
-		return $comment;
150
-	}
151
-
152
-	/**
153
-	 * returns the topmost parent id of a given comment identified by ID
154
-	 *
155
-	 * @param string $id
156
-	 * @return string
157
-	 * @throws NotFoundException
158
-	 */
159
-	protected function determineTopmostParentId($id) {
160
-		$comment = $this->get($id);
161
-		if ($comment->getParentId() === '0') {
162
-			return $comment->getId();
163
-		}
164
-
165
-		return $this->determineTopmostParentId($comment->getParentId());
166
-	}
167
-
168
-	/**
169
-	 * updates child information of a comment
170
-	 *
171
-	 * @param string $id
172
-	 * @param \DateTime $cDateTime the date time of the most recent child
173
-	 * @throws NotFoundException
174
-	 */
175
-	protected function updateChildrenInformation($id, \DateTime $cDateTime) {
176
-		$qb = $this->dbConn->getQueryBuilder();
177
-		$query = $qb->select($qb->func()->count('id'))
178
-			->from('comments')
179
-			->where($qb->expr()->eq('parent_id', $qb->createParameter('id')))
180
-			->setParameter('id', $id);
181
-
182
-		$resultStatement = $query->execute();
183
-		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
184
-		$resultStatement->closeCursor();
185
-		$children = (int)$data[0];
186
-
187
-		$comment = $this->get($id);
188
-		$comment->setChildrenCount($children);
189
-		$comment->setLatestChildDateTime($cDateTime);
190
-		$this->save($comment);
191
-	}
192
-
193
-	/**
194
-	 * Tests whether actor or object type and id parameters are acceptable.
195
-	 * Throws exception if not.
196
-	 *
197
-	 * @param string $role
198
-	 * @param string $type
199
-	 * @param string $id
200
-	 * @throws \InvalidArgumentException
201
-	 */
202
-	protected function checkRoleParameters($role, $type, $id) {
203
-		if (
204
-			!is_string($type) || empty($type)
205
-			|| !is_string($id) || empty($id)
206
-		) {
207
-			throw new \InvalidArgumentException($role . ' parameters must be string and not empty');
208
-		}
209
-	}
210
-
211
-	/**
212
-	 * run-time caches a comment
213
-	 *
214
-	 * @param IComment $comment
215
-	 */
216
-	protected function cache(IComment $comment) {
217
-		$id = $comment->getId();
218
-		if (empty($id)) {
219
-			return;
220
-		}
221
-		$this->commentsCache[(string)$id] = $comment;
222
-	}
223
-
224
-	/**
225
-	 * removes an entry from the comments run time cache
226
-	 *
227
-	 * @param mixed $id the comment's id
228
-	 */
229
-	protected function uncache($id) {
230
-		$id = (string)$id;
231
-		if (isset($this->commentsCache[$id])) {
232
-			unset($this->commentsCache[$id]);
233
-		}
234
-	}
235
-
236
-	/**
237
-	 * returns a comment instance
238
-	 *
239
-	 * @param string $id the ID of the comment
240
-	 * @return IComment
241
-	 * @throws NotFoundException
242
-	 * @throws \InvalidArgumentException
243
-	 * @since 9.0.0
244
-	 */
245
-	public function get($id) {
246
-		if ((int)$id === 0) {
247
-			throw new \InvalidArgumentException('IDs must be translatable to a number in this implementation.');
248
-		}
249
-
250
-		if (isset($this->commentsCache[$id])) {
251
-			return $this->commentsCache[$id];
252
-		}
253
-
254
-		$qb = $this->dbConn->getQueryBuilder();
255
-		$resultStatement = $qb->select('*')
256
-			->from('comments')
257
-			->where($qb->expr()->eq('id', $qb->createParameter('id')))
258
-			->setParameter('id', $id, IQueryBuilder::PARAM_INT)
259
-			->execute();
260
-
261
-		$data = $resultStatement->fetch();
262
-		$resultStatement->closeCursor();
263
-		if (!$data) {
264
-			throw new NotFoundException();
265
-		}
266
-
267
-
268
-		$comment = $this->getCommentFromData($data);
269
-		$this->cache($comment);
270
-		return $comment;
271
-	}
272
-
273
-	/**
274
-	 * returns the comment specified by the id and all it's child comments.
275
-	 * At this point of time, we do only support one level depth.
276
-	 *
277
-	 * @param string $id
278
-	 * @param int $limit max number of entries to return, 0 returns all
279
-	 * @param int $offset the start entry
280
-	 * @return array
281
-	 * @since 9.0.0
282
-	 *
283
-	 * The return array looks like this
284
-	 * [
285
-	 *   'comment' => IComment, // root comment
286
-	 *   'replies' =>
287
-	 *   [
288
-	 *     0 =>
289
-	 *     [
290
-	 *       'comment' => IComment,
291
-	 *       'replies' => []
292
-	 *     ]
293
-	 *     1 =>
294
-	 *     [
295
-	 *       'comment' => IComment,
296
-	 *       'replies'=> []
297
-	 *     ],
298
-	 *     …
299
-	 *   ]
300
-	 * ]
301
-	 */
302
-	public function getTree($id, $limit = 0, $offset = 0) {
303
-		$tree = [];
304
-		$tree['comment'] = $this->get($id);
305
-		$tree['replies'] = [];
306
-
307
-		$qb = $this->dbConn->getQueryBuilder();
308
-		$query = $qb->select('*')
309
-			->from('comments')
310
-			->where($qb->expr()->eq('topmost_parent_id', $qb->createParameter('id')))
311
-			->orderBy('creation_timestamp', 'DESC')
312
-			->setParameter('id', $id);
313
-
314
-		if ($limit > 0) {
315
-			$query->setMaxResults($limit);
316
-		}
317
-		if ($offset > 0) {
318
-			$query->setFirstResult($offset);
319
-		}
320
-
321
-		$resultStatement = $query->execute();
322
-		while ($data = $resultStatement->fetch()) {
323
-			$comment = $this->getCommentFromData($data);
324
-			$this->cache($comment);
325
-			$tree['replies'][] = [
326
-				'comment' => $comment,
327
-				'replies' => []
328
-			];
329
-		}
330
-		$resultStatement->closeCursor();
331
-
332
-		return $tree;
333
-	}
334
-
335
-	/**
336
-	 * returns comments for a specific object (e.g. a file).
337
-	 *
338
-	 * The sort order is always newest to oldest.
339
-	 *
340
-	 * @param string $objectType the object type, e.g. 'files'
341
-	 * @param string $objectId the id of the object
342
-	 * @param int $limit optional, number of maximum comments to be returned. if
343
-	 * not specified, all comments are returned.
344
-	 * @param int $offset optional, starting point
345
-	 * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
346
-	 * that may be returned
347
-	 * @return IComment[]
348
-	 * @since 9.0.0
349
-	 */
350
-	public function getForObject(
351
-		$objectType,
352
-		$objectId,
353
-		$limit = 0,
354
-		$offset = 0,
355
-		\DateTime $notOlderThan = null
356
-	) {
357
-		$comments = [];
358
-
359
-		$qb = $this->dbConn->getQueryBuilder();
360
-		$query = $qb->select('*')
361
-			->from('comments')
362
-			->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
363
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
364
-			->orderBy('creation_timestamp', 'DESC')
365
-			->setParameter('type', $objectType)
366
-			->setParameter('id', $objectId);
367
-
368
-		if ($limit > 0) {
369
-			$query->setMaxResults($limit);
370
-		}
371
-		if ($offset > 0) {
372
-			$query->setFirstResult($offset);
373
-		}
374
-		if (!is_null($notOlderThan)) {
375
-			$query
376
-				->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
377
-				->setParameter('notOlderThan', $notOlderThan, 'datetime');
378
-		}
379
-
380
-		$resultStatement = $query->execute();
381
-		while ($data = $resultStatement->fetch()) {
382
-			$comment = $this->getCommentFromData($data);
383
-			$this->cache($comment);
384
-			$comments[] = $comment;
385
-		}
386
-		$resultStatement->closeCursor();
387
-
388
-		return $comments;
389
-	}
390
-
391
-	/**
392
-	 * @param string $objectType the object type, e.g. 'files'
393
-	 * @param string $objectId the id of the object
394
-	 * @param int $lastKnownCommentId the last known comment (will be used as offset)
395
-	 * @param string $sortDirection direction of the comments (`asc` or `desc`)
396
-	 * @param int $limit optional, number of maximum comments to be returned. if
397
-	 * set to 0, all comments are returned.
398
-	 * @return IComment[]
399
-	 * @return array
400
-	 */
401
-	public function getForObjectSince(
402
-		string $objectType,
403
-		string $objectId,
404
-		int $lastKnownCommentId,
405
-		string $sortDirection = 'asc',
406
-		int $limit = 30
407
-	): array {
408
-		$comments = [];
409
-
410
-		$query = $this->dbConn->getQueryBuilder();
411
-		$query->select('*')
412
-			->from('comments')
413
-			->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
414
-			->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
415
-			->orderBy('creation_timestamp', $sortDirection === 'desc' ? 'DESC' : 'ASC')
416
-			->addOrderBy('id', $sortDirection === 'desc' ? 'DESC' : 'ASC');
417
-
418
-		if ($limit > 0) {
419
-			$query->setMaxResults($limit);
420
-		}
421
-
422
-		$lastKnownComment = $lastKnownCommentId > 0 ? $this->getLastKnownComment(
423
-			$objectType,
424
-			$objectId,
425
-			$lastKnownCommentId
426
-		) : null;
427
-		if ($lastKnownComment instanceof IComment) {
428
-			$lastKnownCommentDateTime = $lastKnownComment->getCreationDateTime();
429
-			if ($sortDirection === 'desc') {
430
-				$query->andWhere(
431
-					$query->expr()->orX(
432
-						$query->expr()->lt(
433
-							'creation_timestamp',
434
-							$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
435
-							IQueryBuilder::PARAM_DATE
436
-						),
437
-						$query->expr()->andX(
438
-							$query->expr()->eq(
439
-								'creation_timestamp',
440
-								$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
441
-								IQueryBuilder::PARAM_DATE
442
-							),
443
-							$query->expr()->lt('id', $query->createNamedParameter($lastKnownCommentId))
444
-						)
445
-					)
446
-				);
447
-			} else {
448
-				$query->andWhere(
449
-					$query->expr()->orX(
450
-						$query->expr()->gt(
451
-							'creation_timestamp',
452
-							$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
453
-							IQueryBuilder::PARAM_DATE
454
-						),
455
-						$query->expr()->andX(
456
-							$query->expr()->eq(
457
-								'creation_timestamp',
458
-								$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
459
-								IQueryBuilder::PARAM_DATE
460
-							),
461
-							$query->expr()->gt('id', $query->createNamedParameter($lastKnownCommentId))
462
-						)
463
-					)
464
-				);
465
-			}
466
-		}
467
-
468
-		$resultStatement = $query->execute();
469
-		while ($data = $resultStatement->fetch()) {
470
-			$comment = $this->getCommentFromData($data);
471
-			$this->cache($comment);
472
-			$comments[] = $comment;
473
-		}
474
-		$resultStatement->closeCursor();
475
-
476
-		return $comments;
477
-	}
478
-
479
-	/**
480
-	 * @param string $objectType the object type, e.g. 'files'
481
-	 * @param string $objectId the id of the object
482
-	 * @param int $id the comment to look for
483
-	 * @return Comment|null
484
-	 */
485
-	protected function getLastKnownComment(string $objectType,
486
-										   string $objectId,
487
-										   int $id) {
488
-		$query = $this->dbConn->getQueryBuilder();
489
-		$query->select('*')
490
-			->from('comments')
491
-			->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
492
-			->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
493
-			->andWhere($query->expr()->eq('id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
494
-
495
-		$result = $query->execute();
496
-		$row = $result->fetch();
497
-		$result->closeCursor();
498
-
499
-		if ($row) {
500
-			$comment = $this->getCommentFromData($row);
501
-			$this->cache($comment);
502
-			return $comment;
503
-		}
504
-
505
-		return null;
506
-	}
507
-
508
-	/**
509
-	 * Search for comments with a given content
510
-	 *
511
-	 * @param string $search content to search for
512
-	 * @param string $objectType Limit the search by object type
513
-	 * @param string $objectId Limit the search by object id
514
-	 * @param string $verb Limit the verb of the comment
515
-	 * @param int $offset
516
-	 * @param int $limit
517
-	 * @return IComment[]
518
-	 */
519
-	public function search(string $search, string $objectType, string $objectId, string $verb, int $offset, int $limit = 50): array {
520
-		$query = $this->dbConn->getQueryBuilder();
521
-
522
-		$query->select('*')
523
-			->from('comments')
524
-			->where($query->expr()->iLike('message', $query->createNamedParameter(
525
-				'%' . $this->dbConn->escapeLikeParameter($search). '%'
526
-			)))
527
-			->orderBy('creation_timestamp', 'DESC')
528
-			->addOrderBy('id', 'DESC')
529
-			->setMaxResults($limit);
530
-
531
-		if ($objectType !== '') {
532
-			$query->andWhere($query->expr()->eq('object_type', $query->createNamedParameter($objectType)));
533
-		}
534
-		if ($objectId !== '') {
535
-			$query->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)));
536
-		}
537
-		if ($verb !== '') {
538
-			$query->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb)));
539
-		}
540
-		if ($offset !== 0) {
541
-			$query->setFirstResult($offset);
542
-		}
543
-
544
-		$comments = [];
545
-		$result = $query->execute();
546
-		while ($data = $result->fetch()) {
547
-			$comment = $this->getCommentFromData($data);
548
-			$this->cache($comment);
549
-			$comments[] = $comment;
550
-		}
551
-		$result->closeCursor();
552
-
553
-		return $comments;
554
-	}
555
-
556
-	/**
557
-	 * @param $objectType string the object type, e.g. 'files'
558
-	 * @param $objectId string the id of the object
559
-	 * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
560
-	 * that may be returned
561
-	 * @param string $verb Limit the verb of the comment - Added in 14.0.0
562
-	 * @return Int
563
-	 * @since 9.0.0
564
-	 */
565
-	public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null, $verb = '') {
566
-		$qb = $this->dbConn->getQueryBuilder();
567
-		$query = $qb->select($qb->func()->count('id'))
568
-			->from('comments')
569
-			->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
570
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
571
-			->setParameter('type', $objectType)
572
-			->setParameter('id', $objectId);
573
-
574
-		if (!is_null($notOlderThan)) {
575
-			$query
576
-				->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
577
-				->setParameter('notOlderThan', $notOlderThan, 'datetime');
578
-		}
579
-
580
-		if ($verb !== '') {
581
-			$query->andWhere($qb->expr()->eq('verb', $qb->createNamedParameter($verb)));
582
-		}
583
-
584
-		$resultStatement = $query->execute();
585
-		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
586
-		$resultStatement->closeCursor();
587
-		return (int)$data[0];
588
-	}
589
-
590
-	/**
591
-	 * Get the number of unread comments for all files in a folder
592
-	 *
593
-	 * @param int $folderId
594
-	 * @param IUser $user
595
-	 * @return array [$fileId => $unreadCount]
596
-	 */
597
-	public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) {
598
-		$qb = $this->dbConn->getQueryBuilder();
599
-
600
-		$query = $qb->select('f.fileid')
601
-			->addSelect($qb->func()->count('c.id', 'num_ids'))
602
-			->from('filecache', 'f')
603
-			->leftJoin('f', 'comments', 'c', $qb->expr()->andX(
604
-				$qb->expr()->eq('f.fileid', $qb->expr()->castColumn('c.object_id', IQueryBuilder::PARAM_INT)),
605
-				$qb->expr()->eq('c.object_type', $qb->createNamedParameter('files'))
606
-			))
607
-			->leftJoin('c', 'comments_read_markers', 'm', $qb->expr()->andX(
608
-				$qb->expr()->eq('c.object_id', 'm.object_id'),
609
-				$qb->expr()->eq('m.object_type', $qb->createNamedParameter('files'))
610
-			))
611
-			->where(
612
-				$qb->expr()->andX(
613
-					$qb->expr()->eq('f.parent', $qb->createNamedParameter($folderId)),
614
-					$qb->expr()->orX(
615
-						$qb->expr()->eq('c.object_type', $qb->createNamedParameter('files')),
616
-						$qb->expr()->isNull('c.object_type')
617
-					),
618
-					$qb->expr()->orX(
619
-						$qb->expr()->eq('m.object_type', $qb->createNamedParameter('files')),
620
-						$qb->expr()->isNull('m.object_type')
621
-					),
622
-					$qb->expr()->orX(
623
-						$qb->expr()->eq('m.user_id', $qb->createNamedParameter($user->getUID())),
624
-						$qb->expr()->isNull('m.user_id')
625
-					),
626
-					$qb->expr()->orX(
627
-						$qb->expr()->gt('c.creation_timestamp', 'm.marker_datetime'),
628
-						$qb->expr()->isNull('m.marker_datetime')
629
-					)
630
-				)
631
-			)->groupBy('f.fileid');
632
-
633
-		$resultStatement = $query->execute();
634
-
635
-		$results = [];
636
-		while ($row = $resultStatement->fetch()) {
637
-			$results[$row['fileid']] = (int) $row['num_ids'];
638
-		}
639
-		$resultStatement->closeCursor();
640
-		return $results;
641
-	}
642
-
643
-	/**
644
-	 * creates a new comment and returns it. At this point of time, it is not
645
-	 * saved in the used data storage. Use save() after setting other fields
646
-	 * of the comment (e.g. message or verb).
647
-	 *
648
-	 * @param string $actorType the actor type (e.g. 'users')
649
-	 * @param string $actorId a user id
650
-	 * @param string $objectType the object type the comment is attached to
651
-	 * @param string $objectId the object id the comment is attached to
652
-	 * @return IComment
653
-	 * @since 9.0.0
654
-	 */
655
-	public function create($actorType, $actorId, $objectType, $objectId) {
656
-		$comment = new Comment();
657
-		$comment
658
-			->setActor($actorType, $actorId)
659
-			->setObject($objectType, $objectId);
660
-		return $comment;
661
-	}
662
-
663
-	/**
664
-	 * permanently deletes the comment specified by the ID
665
-	 *
666
-	 * When the comment has child comments, their parent ID will be changed to
667
-	 * the parent ID of the item that is to be deleted.
668
-	 *
669
-	 * @param string $id
670
-	 * @return bool
671
-	 * @throws \InvalidArgumentException
672
-	 * @since 9.0.0
673
-	 */
674
-	public function delete($id) {
675
-		if (!is_string($id)) {
676
-			throw new \InvalidArgumentException('Parameter must be string');
677
-		}
678
-
679
-		try {
680
-			$comment = $this->get($id);
681
-		} catch (\Exception $e) {
682
-			// Ignore exceptions, we just don't fire a hook then
683
-			$comment = null;
684
-		}
685
-
686
-		$qb = $this->dbConn->getQueryBuilder();
687
-		$query = $qb->delete('comments')
688
-			->where($qb->expr()->eq('id', $qb->createParameter('id')))
689
-			->setParameter('id', $id);
690
-
691
-		try {
692
-			$affectedRows = $query->execute();
693
-			$this->uncache($id);
694
-		} catch (DriverException $e) {
695
-			$this->logger->error($e->getMessage(), [
696
-				'exception' => $e,
697
-				'app' => 'core_comments',
698
-			]);
699
-			return false;
700
-		}
701
-
702
-		if ($affectedRows > 0 && $comment instanceof IComment) {
703
-			$this->sendEvent(CommentsEvent::EVENT_DELETE, $comment);
704
-		}
705
-
706
-		return ($affectedRows > 0);
707
-	}
708
-
709
-	/**
710
-	 * saves the comment permanently
711
-	 *
712
-	 * if the supplied comment has an empty ID, a new entry comment will be
713
-	 * saved and the instance updated with the new ID.
714
-	 *
715
-	 * Otherwise, an existing comment will be updated.
716
-	 *
717
-	 * Throws NotFoundException when a comment that is to be updated does not
718
-	 * exist anymore at this point of time.
719
-	 *
720
-	 * @param IComment $comment
721
-	 * @return bool
722
-	 * @throws NotFoundException
723
-	 * @since 9.0.0
724
-	 */
725
-	public function save(IComment $comment) {
726
-		if ($this->prepareCommentForDatabaseWrite($comment)->getId() === '') {
727
-			$result = $this->insert($comment);
728
-		} else {
729
-			$result = $this->update($comment);
730
-		}
731
-
732
-		if ($result && !!$comment->getParentId()) {
733
-			$this->updateChildrenInformation(
734
-				$comment->getParentId(),
735
-				$comment->getCreationDateTime()
736
-			);
737
-			$this->cache($comment);
738
-		}
739
-
740
-		return $result;
741
-	}
742
-
743
-	/**
744
-	 * inserts the provided comment in the database
745
-	 *
746
-	 * @param IComment $comment
747
-	 * @return bool
748
-	 */
749
-	protected function insert(IComment $comment): bool {
750
-		try {
751
-			$result = $this->insertQuery($comment, true);
752
-		} catch (InvalidFieldNameException $e) {
753
-			// The reference id field was only added in Nextcloud 19.
754
-			// In order to not cause too long waiting times on the update,
755
-			// it was decided to only add it lazy, as it is also not a critical
756
-			// feature, but only helps to have a better experience while commenting.
757
-			// So in case the reference_id field is missing,
758
-			// we simply save the comment without that field.
759
-			$result = $this->insertQuery($comment, false);
760
-		}
761
-
762
-		return $result;
763
-	}
764
-
765
-	protected function insertQuery(IComment $comment, bool $tryWritingReferenceId): bool {
766
-		$qb = $this->dbConn->getQueryBuilder();
767
-
768
-		$values = [
769
-			'parent_id' => $qb->createNamedParameter($comment->getParentId()),
770
-			'topmost_parent_id' => $qb->createNamedParameter($comment->getTopmostParentId()),
771
-			'children_count' => $qb->createNamedParameter($comment->getChildrenCount()),
772
-			'actor_type' => $qb->createNamedParameter($comment->getActorType()),
773
-			'actor_id' => $qb->createNamedParameter($comment->getActorId()),
774
-			'message' => $qb->createNamedParameter($comment->getMessage()),
775
-			'verb' => $qb->createNamedParameter($comment->getVerb()),
776
-			'creation_timestamp' => $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'),
777
-			'latest_child_timestamp' => $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'),
778
-			'object_type' => $qb->createNamedParameter($comment->getObjectType()),
779
-			'object_id' => $qb->createNamedParameter($comment->getObjectId()),
780
-		];
781
-
782
-		if ($tryWritingReferenceId) {
783
-			$values['reference_id'] = $qb->createNamedParameter($comment->getReferenceId());
784
-		}
785
-
786
-		$affectedRows = $qb->insert('comments')
787
-			->values($values)
788
-			->execute();
789
-
790
-		if ($affectedRows > 0) {
791
-			$comment->setId((string)$qb->getLastInsertId());
792
-			$this->sendEvent(CommentsEvent::EVENT_ADD, $comment);
793
-		}
794
-
795
-		return $affectedRows > 0;
796
-	}
797
-
798
-	/**
799
-	 * updates a Comment data row
800
-	 *
801
-	 * @param IComment $comment
802
-	 * @return bool
803
-	 * @throws NotFoundException
804
-	 */
805
-	protected function update(IComment $comment) {
806
-		// for properly working preUpdate Events we need the old comments as is
807
-		// in the DB and overcome caching. Also avoid that outdated information stays.
808
-		$this->uncache($comment->getId());
809
-		$this->sendEvent(CommentsEvent::EVENT_PRE_UPDATE, $this->get($comment->getId()));
810
-		$this->uncache($comment->getId());
811
-
812
-		try {
813
-			$result = $this->updateQuery($comment, true);
814
-		} catch (InvalidFieldNameException $e) {
815
-			// See function insert() for explanation
816
-			$result = $this->updateQuery($comment, false);
817
-		}
818
-
819
-		$this->sendEvent(CommentsEvent::EVENT_UPDATE, $comment);
820
-
821
-		return $result;
822
-	}
823
-
824
-	protected function updateQuery(IComment $comment, bool $tryWritingReferenceId): bool {
825
-		$qb = $this->dbConn->getQueryBuilder();
826
-		$qb
827
-			->update('comments')
828
-			->set('parent_id', $qb->createNamedParameter($comment->getParentId()))
829
-			->set('topmost_parent_id', $qb->createNamedParameter($comment->getTopmostParentId()))
830
-			->set('children_count', $qb->createNamedParameter($comment->getChildrenCount()))
831
-			->set('actor_type', $qb->createNamedParameter($comment->getActorType()))
832
-			->set('actor_id', $qb->createNamedParameter($comment->getActorId()))
833
-			->set('message', $qb->createNamedParameter($comment->getMessage()))
834
-			->set('verb', $qb->createNamedParameter($comment->getVerb()))
835
-			->set('creation_timestamp', $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'))
836
-			->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'))
837
-			->set('object_type', $qb->createNamedParameter($comment->getObjectType()))
838
-			->set('object_id', $qb->createNamedParameter($comment->getObjectId()));
839
-
840
-		if ($tryWritingReferenceId) {
841
-			$qb->set('reference_id', $qb->createNamedParameter($comment->getReferenceId()));
842
-		}
843
-
844
-		$affectedRows = $qb->where($qb->expr()->eq('id', $qb->createNamedParameter($comment->getId())))
845
-			->execute();
846
-
847
-		if ($affectedRows === 0) {
848
-			throw new NotFoundException('Comment to update does ceased to exist');
849
-		}
850
-
851
-		return $affectedRows > 0;
852
-	}
853
-
854
-	/**
855
-	 * removes references to specific actor (e.g. on user delete) of a comment.
856
-	 * The comment itself must not get lost/deleted.
857
-	 *
858
-	 * @param string $actorType the actor type (e.g. 'users')
859
-	 * @param string $actorId a user id
860
-	 * @return boolean
861
-	 * @since 9.0.0
862
-	 */
863
-	public function deleteReferencesOfActor($actorType, $actorId) {
864
-		$this->checkRoleParameters('Actor', $actorType, $actorId);
865
-
866
-		$qb = $this->dbConn->getQueryBuilder();
867
-		$affectedRows = $qb
868
-			->update('comments')
869
-			->set('actor_type', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
870
-			->set('actor_id', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
871
-			->where($qb->expr()->eq('actor_type', $qb->createParameter('type')))
872
-			->andWhere($qb->expr()->eq('actor_id', $qb->createParameter('id')))
873
-			->setParameter('type', $actorType)
874
-			->setParameter('id', $actorId)
875
-			->execute();
876
-
877
-		$this->commentsCache = [];
878
-
879
-		return is_int($affectedRows);
880
-	}
881
-
882
-	/**
883
-	 * deletes all comments made of a specific object (e.g. on file delete)
884
-	 *
885
-	 * @param string $objectType the object type (e.g. 'files')
886
-	 * @param string $objectId e.g. the file id
887
-	 * @return boolean
888
-	 * @since 9.0.0
889
-	 */
890
-	public function deleteCommentsAtObject($objectType, $objectId) {
891
-		$this->checkRoleParameters('Object', $objectType, $objectId);
892
-
893
-		$qb = $this->dbConn->getQueryBuilder();
894
-		$affectedRows = $qb
895
-			->delete('comments')
896
-			->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
897
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
898
-			->setParameter('type', $objectType)
899
-			->setParameter('id', $objectId)
900
-			->execute();
901
-
902
-		$this->commentsCache = [];
903
-
904
-		return is_int($affectedRows);
905
-	}
906
-
907
-	/**
908
-	 * deletes the read markers for the specified user
909
-	 *
910
-	 * @param \OCP\IUser $user
911
-	 * @return bool
912
-	 * @since 9.0.0
913
-	 */
914
-	public function deleteReadMarksFromUser(IUser $user) {
915
-		$qb = $this->dbConn->getQueryBuilder();
916
-		$query = $qb->delete('comments_read_markers')
917
-			->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
918
-			->setParameter('user_id', $user->getUID());
919
-
920
-		try {
921
-			$affectedRows = $query->execute();
922
-		} catch (DriverException $e) {
923
-			$this->logger->error($e->getMessage(), [
924
-				'exception' => $e,
925
-				'app' => 'core_comments',
926
-			]);
927
-			return false;
928
-		}
929
-		return ($affectedRows > 0);
930
-	}
931
-
932
-	/**
933
-	 * sets the read marker for a given file to the specified date for the
934
-	 * provided user
935
-	 *
936
-	 * @param string $objectType
937
-	 * @param string $objectId
938
-	 * @param \DateTime $dateTime
939
-	 * @param IUser $user
940
-	 * @since 9.0.0
941
-	 */
942
-	public function setReadMark($objectType, $objectId, \DateTime $dateTime, IUser $user) {
943
-		$this->checkRoleParameters('Object', $objectType, $objectId);
944
-
945
-		$qb = $this->dbConn->getQueryBuilder();
946
-		$values = [
947
-			'user_id' => $qb->createNamedParameter($user->getUID()),
948
-			'marker_datetime' => $qb->createNamedParameter($dateTime, 'datetime'),
949
-			'object_type' => $qb->createNamedParameter($objectType),
950
-			'object_id' => $qb->createNamedParameter($objectId),
951
-		];
952
-
953
-		// Strategy: try to update, if this does not return affected rows, do an insert.
954
-		$affectedRows = $qb
955
-			->update('comments_read_markers')
956
-			->set('user_id', $values['user_id'])
957
-			->set('marker_datetime', $values['marker_datetime'])
958
-			->set('object_type', $values['object_type'])
959
-			->set('object_id', $values['object_id'])
960
-			->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
961
-			->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
962
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
963
-			->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR)
964
-			->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR)
965
-			->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR)
966
-			->execute();
967
-
968
-		if ($affectedRows > 0) {
969
-			return;
970
-		}
971
-
972
-		$qb->insert('comments_read_markers')
973
-			->values($values)
974
-			->execute();
975
-	}
976
-
977
-	/**
978
-	 * returns the read marker for a given file to the specified date for the
979
-	 * provided user. It returns null, when the marker is not present, i.e.
980
-	 * no comments were marked as read.
981
-	 *
982
-	 * @param string $objectType
983
-	 * @param string $objectId
984
-	 * @param IUser $user
985
-	 * @return \DateTime|null
986
-	 * @since 9.0.0
987
-	 */
988
-	public function getReadMark($objectType, $objectId, IUser $user) {
989
-		$qb = $this->dbConn->getQueryBuilder();
990
-		$resultStatement = $qb->select('marker_datetime')
991
-			->from('comments_read_markers')
992
-			->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
993
-			->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
994
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
995
-			->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR)
996
-			->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR)
997
-			->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR)
998
-			->execute();
999
-
1000
-		$data = $resultStatement->fetch();
1001
-		$resultStatement->closeCursor();
1002
-		if (!$data || is_null($data['marker_datetime'])) {
1003
-			return null;
1004
-		}
1005
-
1006
-		return new \DateTime($data['marker_datetime']);
1007
-	}
1008
-
1009
-	/**
1010
-	 * deletes the read markers on the specified object
1011
-	 *
1012
-	 * @param string $objectType
1013
-	 * @param string $objectId
1014
-	 * @return bool
1015
-	 * @since 9.0.0
1016
-	 */
1017
-	public function deleteReadMarksOnObject($objectType, $objectId) {
1018
-		$this->checkRoleParameters('Object', $objectType, $objectId);
1019
-
1020
-		$qb = $this->dbConn->getQueryBuilder();
1021
-		$query = $qb->delete('comments_read_markers')
1022
-			->where($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
1023
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
1024
-			->setParameter('object_type', $objectType)
1025
-			->setParameter('object_id', $objectId);
1026
-
1027
-		try {
1028
-			$affectedRows = $query->execute();
1029
-		} catch (DriverException $e) {
1030
-			$this->logger->error($e->getMessage(), [
1031
-				'exception' => $e,
1032
-				'app' => 'core_comments',
1033
-			]);
1034
-			return false;
1035
-		}
1036
-		return ($affectedRows > 0);
1037
-	}
1038
-
1039
-	/**
1040
-	 * registers an Entity to the manager, so event notifications can be send
1041
-	 * to consumers of the comments infrastructure
1042
-	 *
1043
-	 * @param \Closure $closure
1044
-	 */
1045
-	public function registerEventHandler(\Closure $closure) {
1046
-		$this->eventHandlerClosures[] = $closure;
1047
-		$this->eventHandlers = [];
1048
-	}
1049
-
1050
-	/**
1051
-	 * registers a method that resolves an ID to a display name for a given type
1052
-	 *
1053
-	 * @param string $type
1054
-	 * @param \Closure $closure
1055
-	 * @throws \OutOfBoundsException
1056
-	 * @since 11.0.0
1057
-	 *
1058
-	 * Only one resolver shall be registered per type. Otherwise a
1059
-	 * \OutOfBoundsException has to thrown.
1060
-	 */
1061
-	public function registerDisplayNameResolver($type, \Closure $closure) {
1062
-		if (!is_string($type)) {
1063
-			throw new \InvalidArgumentException('String expected.');
1064
-		}
1065
-		if (isset($this->displayNameResolvers[$type])) {
1066
-			throw new \OutOfBoundsException('Displayname resolver for this type already registered');
1067
-		}
1068
-		$this->displayNameResolvers[$type] = $closure;
1069
-	}
1070
-
1071
-	/**
1072
-	 * resolves a given ID of a given Type to a display name.
1073
-	 *
1074
-	 * @param string $type
1075
-	 * @param string $id
1076
-	 * @return string
1077
-	 * @throws \OutOfBoundsException
1078
-	 * @since 11.0.0
1079
-	 *
1080
-	 * If a provided type was not registered, an \OutOfBoundsException shall
1081
-	 * be thrown. It is upon the resolver discretion what to return of the
1082
-	 * provided ID is unknown. It must be ensured that a string is returned.
1083
-	 */
1084
-	public function resolveDisplayName($type, $id) {
1085
-		if (!is_string($type)) {
1086
-			throw new \InvalidArgumentException('String expected.');
1087
-		}
1088
-		if (!isset($this->displayNameResolvers[$type])) {
1089
-			throw new \OutOfBoundsException('No Displayname resolver for this type registered');
1090
-		}
1091
-		return (string)$this->displayNameResolvers[$type]($id);
1092
-	}
1093
-
1094
-	/**
1095
-	 * returns valid, registered entities
1096
-	 *
1097
-	 * @return \OCP\Comments\ICommentsEventHandler[]
1098
-	 */
1099
-	private function getEventHandlers() {
1100
-		if (!empty($this->eventHandlers)) {
1101
-			return $this->eventHandlers;
1102
-		}
1103
-
1104
-		$this->eventHandlers = [];
1105
-		foreach ($this->eventHandlerClosures as $name => $closure) {
1106
-			$entity = $closure();
1107
-			if (!($entity instanceof ICommentsEventHandler)) {
1108
-				throw new \InvalidArgumentException('The given entity does not implement the ICommentsEntity interface');
1109
-			}
1110
-			$this->eventHandlers[$name] = $entity;
1111
-		}
1112
-
1113
-		return $this->eventHandlers;
1114
-	}
1115
-
1116
-	/**
1117
-	 * sends notifications to the registered entities
1118
-	 *
1119
-	 * @param $eventType
1120
-	 * @param IComment $comment
1121
-	 */
1122
-	private function sendEvent($eventType, IComment $comment) {
1123
-		$entities = $this->getEventHandlers();
1124
-		$event = new CommentsEvent($eventType, $comment);
1125
-		foreach ($entities as $entity) {
1126
-			$entity->handle($event);
1127
-		}
1128
-	}
1129
-
1130
-	/**
1131
-	 * Load the Comments app into the page
1132
-	 *
1133
-	 * @since 21.0.0
1134
-	 */
1135
-	public function load(): void {
1136
-		$this->initialStateService->provideInitialState(Application::APP_ID, 'max-message-length', IComment::MAX_MESSAGE_LENGTH);
1137
-		Util::addScript(Application::APP_ID, 'comments-app');
1138
-	}
49
+    /** @var  IDBConnection */
50
+    protected $dbConn;
51
+
52
+    /** @var  LoggerInterface */
53
+    protected $logger;
54
+
55
+    /** @var IConfig */
56
+    protected $config;
57
+
58
+    /** @var IInitialStateService */
59
+    protected $initialStateService;
60
+
61
+    /** @var IComment[] */
62
+    protected $commentsCache = [];
63
+
64
+    /** @var  \Closure[] */
65
+    protected $eventHandlerClosures = [];
66
+
67
+    /** @var  ICommentsEventHandler[] */
68
+    protected $eventHandlers = [];
69
+
70
+    /** @var \Closure[] */
71
+    protected $displayNameResolvers = [];
72
+
73
+    public function __construct(IDBConnection $dbConn,
74
+                                LoggerInterface $logger,
75
+                                IConfig $config,
76
+                                IInitialStateService $initialStateService) {
77
+        $this->dbConn = $dbConn;
78
+        $this->logger = $logger;
79
+        $this->config = $config;
80
+        $this->initialStateService = $initialStateService;
81
+    }
82
+
83
+    /**
84
+     * converts data base data into PHP native, proper types as defined by
85
+     * IComment interface.
86
+     *
87
+     * @param array $data
88
+     * @return array
89
+     */
90
+    protected function normalizeDatabaseData(array $data) {
91
+        $data['id'] = (string)$data['id'];
92
+        $data['parent_id'] = (string)$data['parent_id'];
93
+        $data['topmost_parent_id'] = (string)$data['topmost_parent_id'];
94
+        $data['creation_timestamp'] = new \DateTime($data['creation_timestamp']);
95
+        if (!is_null($data['latest_child_timestamp'])) {
96
+            $data['latest_child_timestamp'] = new \DateTime($data['latest_child_timestamp']);
97
+        }
98
+        $data['children_count'] = (int)$data['children_count'];
99
+        $data['reference_id'] = $data['reference_id'] ?? null;
100
+        return $data;
101
+    }
102
+
103
+
104
+    /**
105
+     * @param array $data
106
+     * @return IComment
107
+     */
108
+    public function getCommentFromData(array $data): IComment {
109
+        return new Comment($this->normalizeDatabaseData($data));
110
+    }
111
+
112
+    /**
113
+     * prepares a comment for an insert or update operation after making sure
114
+     * all necessary fields have a value assigned.
115
+     *
116
+     * @param IComment $comment
117
+     * @return IComment returns the same updated IComment instance as provided
118
+     *                  by parameter for convenience
119
+     * @throws \UnexpectedValueException
120
+     */
121
+    protected function prepareCommentForDatabaseWrite(IComment $comment) {
122
+        if (!$comment->getActorType()
123
+            || $comment->getActorId() === ''
124
+            || !$comment->getObjectType()
125
+            || $comment->getObjectId() === ''
126
+            || !$comment->getVerb()
127
+        ) {
128
+            throw new \UnexpectedValueException('Actor, Object and Verb information must be provided for saving');
129
+        }
130
+
131
+        if ($comment->getId() === '') {
132
+            $comment->setChildrenCount(0);
133
+            $comment->setLatestChildDateTime(new \DateTime('0000-00-00 00:00:00', new \DateTimeZone('UTC')));
134
+            $comment->setLatestChildDateTime(null);
135
+        }
136
+
137
+        if (is_null($comment->getCreationDateTime())) {
138
+            $comment->setCreationDateTime(new \DateTime());
139
+        }
140
+
141
+        if ($comment->getParentId() !== '0') {
142
+            $comment->setTopmostParentId($this->determineTopmostParentId($comment->getParentId()));
143
+        } else {
144
+            $comment->setTopmostParentId('0');
145
+        }
146
+
147
+        $this->cache($comment);
148
+
149
+        return $comment;
150
+    }
151
+
152
+    /**
153
+     * returns the topmost parent id of a given comment identified by ID
154
+     *
155
+     * @param string $id
156
+     * @return string
157
+     * @throws NotFoundException
158
+     */
159
+    protected function determineTopmostParentId($id) {
160
+        $comment = $this->get($id);
161
+        if ($comment->getParentId() === '0') {
162
+            return $comment->getId();
163
+        }
164
+
165
+        return $this->determineTopmostParentId($comment->getParentId());
166
+    }
167
+
168
+    /**
169
+     * updates child information of a comment
170
+     *
171
+     * @param string $id
172
+     * @param \DateTime $cDateTime the date time of the most recent child
173
+     * @throws NotFoundException
174
+     */
175
+    protected function updateChildrenInformation($id, \DateTime $cDateTime) {
176
+        $qb = $this->dbConn->getQueryBuilder();
177
+        $query = $qb->select($qb->func()->count('id'))
178
+            ->from('comments')
179
+            ->where($qb->expr()->eq('parent_id', $qb->createParameter('id')))
180
+            ->setParameter('id', $id);
181
+
182
+        $resultStatement = $query->execute();
183
+        $data = $resultStatement->fetch(\PDO::FETCH_NUM);
184
+        $resultStatement->closeCursor();
185
+        $children = (int)$data[0];
186
+
187
+        $comment = $this->get($id);
188
+        $comment->setChildrenCount($children);
189
+        $comment->setLatestChildDateTime($cDateTime);
190
+        $this->save($comment);
191
+    }
192
+
193
+    /**
194
+     * Tests whether actor or object type and id parameters are acceptable.
195
+     * Throws exception if not.
196
+     *
197
+     * @param string $role
198
+     * @param string $type
199
+     * @param string $id
200
+     * @throws \InvalidArgumentException
201
+     */
202
+    protected function checkRoleParameters($role, $type, $id) {
203
+        if (
204
+            !is_string($type) || empty($type)
205
+            || !is_string($id) || empty($id)
206
+        ) {
207
+            throw new \InvalidArgumentException($role . ' parameters must be string and not empty');
208
+        }
209
+    }
210
+
211
+    /**
212
+     * run-time caches a comment
213
+     *
214
+     * @param IComment $comment
215
+     */
216
+    protected function cache(IComment $comment) {
217
+        $id = $comment->getId();
218
+        if (empty($id)) {
219
+            return;
220
+        }
221
+        $this->commentsCache[(string)$id] = $comment;
222
+    }
223
+
224
+    /**
225
+     * removes an entry from the comments run time cache
226
+     *
227
+     * @param mixed $id the comment's id
228
+     */
229
+    protected function uncache($id) {
230
+        $id = (string)$id;
231
+        if (isset($this->commentsCache[$id])) {
232
+            unset($this->commentsCache[$id]);
233
+        }
234
+    }
235
+
236
+    /**
237
+     * returns a comment instance
238
+     *
239
+     * @param string $id the ID of the comment
240
+     * @return IComment
241
+     * @throws NotFoundException
242
+     * @throws \InvalidArgumentException
243
+     * @since 9.0.0
244
+     */
245
+    public function get($id) {
246
+        if ((int)$id === 0) {
247
+            throw new \InvalidArgumentException('IDs must be translatable to a number in this implementation.');
248
+        }
249
+
250
+        if (isset($this->commentsCache[$id])) {
251
+            return $this->commentsCache[$id];
252
+        }
253
+
254
+        $qb = $this->dbConn->getQueryBuilder();
255
+        $resultStatement = $qb->select('*')
256
+            ->from('comments')
257
+            ->where($qb->expr()->eq('id', $qb->createParameter('id')))
258
+            ->setParameter('id', $id, IQueryBuilder::PARAM_INT)
259
+            ->execute();
260
+
261
+        $data = $resultStatement->fetch();
262
+        $resultStatement->closeCursor();
263
+        if (!$data) {
264
+            throw new NotFoundException();
265
+        }
266
+
267
+
268
+        $comment = $this->getCommentFromData($data);
269
+        $this->cache($comment);
270
+        return $comment;
271
+    }
272
+
273
+    /**
274
+     * returns the comment specified by the id and all it's child comments.
275
+     * At this point of time, we do only support one level depth.
276
+     *
277
+     * @param string $id
278
+     * @param int $limit max number of entries to return, 0 returns all
279
+     * @param int $offset the start entry
280
+     * @return array
281
+     * @since 9.0.0
282
+     *
283
+     * The return array looks like this
284
+     * [
285
+     *   'comment' => IComment, // root comment
286
+     *   'replies' =>
287
+     *   [
288
+     *     0 =>
289
+     *     [
290
+     *       'comment' => IComment,
291
+     *       'replies' => []
292
+     *     ]
293
+     *     1 =>
294
+     *     [
295
+     *       'comment' => IComment,
296
+     *       'replies'=> []
297
+     *     ],
298
+     *     …
299
+     *   ]
300
+     * ]
301
+     */
302
+    public function getTree($id, $limit = 0, $offset = 0) {
303
+        $tree = [];
304
+        $tree['comment'] = $this->get($id);
305
+        $tree['replies'] = [];
306
+
307
+        $qb = $this->dbConn->getQueryBuilder();
308
+        $query = $qb->select('*')
309
+            ->from('comments')
310
+            ->where($qb->expr()->eq('topmost_parent_id', $qb->createParameter('id')))
311
+            ->orderBy('creation_timestamp', 'DESC')
312
+            ->setParameter('id', $id);
313
+
314
+        if ($limit > 0) {
315
+            $query->setMaxResults($limit);
316
+        }
317
+        if ($offset > 0) {
318
+            $query->setFirstResult($offset);
319
+        }
320
+
321
+        $resultStatement = $query->execute();
322
+        while ($data = $resultStatement->fetch()) {
323
+            $comment = $this->getCommentFromData($data);
324
+            $this->cache($comment);
325
+            $tree['replies'][] = [
326
+                'comment' => $comment,
327
+                'replies' => []
328
+            ];
329
+        }
330
+        $resultStatement->closeCursor();
331
+
332
+        return $tree;
333
+    }
334
+
335
+    /**
336
+     * returns comments for a specific object (e.g. a file).
337
+     *
338
+     * The sort order is always newest to oldest.
339
+     *
340
+     * @param string $objectType the object type, e.g. 'files'
341
+     * @param string $objectId the id of the object
342
+     * @param int $limit optional, number of maximum comments to be returned. if
343
+     * not specified, all comments are returned.
344
+     * @param int $offset optional, starting point
345
+     * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
346
+     * that may be returned
347
+     * @return IComment[]
348
+     * @since 9.0.0
349
+     */
350
+    public function getForObject(
351
+        $objectType,
352
+        $objectId,
353
+        $limit = 0,
354
+        $offset = 0,
355
+        \DateTime $notOlderThan = null
356
+    ) {
357
+        $comments = [];
358
+
359
+        $qb = $this->dbConn->getQueryBuilder();
360
+        $query = $qb->select('*')
361
+            ->from('comments')
362
+            ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
363
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
364
+            ->orderBy('creation_timestamp', 'DESC')
365
+            ->setParameter('type', $objectType)
366
+            ->setParameter('id', $objectId);
367
+
368
+        if ($limit > 0) {
369
+            $query->setMaxResults($limit);
370
+        }
371
+        if ($offset > 0) {
372
+            $query->setFirstResult($offset);
373
+        }
374
+        if (!is_null($notOlderThan)) {
375
+            $query
376
+                ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
377
+                ->setParameter('notOlderThan', $notOlderThan, 'datetime');
378
+        }
379
+
380
+        $resultStatement = $query->execute();
381
+        while ($data = $resultStatement->fetch()) {
382
+            $comment = $this->getCommentFromData($data);
383
+            $this->cache($comment);
384
+            $comments[] = $comment;
385
+        }
386
+        $resultStatement->closeCursor();
387
+
388
+        return $comments;
389
+    }
390
+
391
+    /**
392
+     * @param string $objectType the object type, e.g. 'files'
393
+     * @param string $objectId the id of the object
394
+     * @param int $lastKnownCommentId the last known comment (will be used as offset)
395
+     * @param string $sortDirection direction of the comments (`asc` or `desc`)
396
+     * @param int $limit optional, number of maximum comments to be returned. if
397
+     * set to 0, all comments are returned.
398
+     * @return IComment[]
399
+     * @return array
400
+     */
401
+    public function getForObjectSince(
402
+        string $objectType,
403
+        string $objectId,
404
+        int $lastKnownCommentId,
405
+        string $sortDirection = 'asc',
406
+        int $limit = 30
407
+    ): array {
408
+        $comments = [];
409
+
410
+        $query = $this->dbConn->getQueryBuilder();
411
+        $query->select('*')
412
+            ->from('comments')
413
+            ->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
414
+            ->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
415
+            ->orderBy('creation_timestamp', $sortDirection === 'desc' ? 'DESC' : 'ASC')
416
+            ->addOrderBy('id', $sortDirection === 'desc' ? 'DESC' : 'ASC');
417
+
418
+        if ($limit > 0) {
419
+            $query->setMaxResults($limit);
420
+        }
421
+
422
+        $lastKnownComment = $lastKnownCommentId > 0 ? $this->getLastKnownComment(
423
+            $objectType,
424
+            $objectId,
425
+            $lastKnownCommentId
426
+        ) : null;
427
+        if ($lastKnownComment instanceof IComment) {
428
+            $lastKnownCommentDateTime = $lastKnownComment->getCreationDateTime();
429
+            if ($sortDirection === 'desc') {
430
+                $query->andWhere(
431
+                    $query->expr()->orX(
432
+                        $query->expr()->lt(
433
+                            'creation_timestamp',
434
+                            $query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
435
+                            IQueryBuilder::PARAM_DATE
436
+                        ),
437
+                        $query->expr()->andX(
438
+                            $query->expr()->eq(
439
+                                'creation_timestamp',
440
+                                $query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
441
+                                IQueryBuilder::PARAM_DATE
442
+                            ),
443
+                            $query->expr()->lt('id', $query->createNamedParameter($lastKnownCommentId))
444
+                        )
445
+                    )
446
+                );
447
+            } else {
448
+                $query->andWhere(
449
+                    $query->expr()->orX(
450
+                        $query->expr()->gt(
451
+                            'creation_timestamp',
452
+                            $query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
453
+                            IQueryBuilder::PARAM_DATE
454
+                        ),
455
+                        $query->expr()->andX(
456
+                            $query->expr()->eq(
457
+                                'creation_timestamp',
458
+                                $query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
459
+                                IQueryBuilder::PARAM_DATE
460
+                            ),
461
+                            $query->expr()->gt('id', $query->createNamedParameter($lastKnownCommentId))
462
+                        )
463
+                    )
464
+                );
465
+            }
466
+        }
467
+
468
+        $resultStatement = $query->execute();
469
+        while ($data = $resultStatement->fetch()) {
470
+            $comment = $this->getCommentFromData($data);
471
+            $this->cache($comment);
472
+            $comments[] = $comment;
473
+        }
474
+        $resultStatement->closeCursor();
475
+
476
+        return $comments;
477
+    }
478
+
479
+    /**
480
+     * @param string $objectType the object type, e.g. 'files'
481
+     * @param string $objectId the id of the object
482
+     * @param int $id the comment to look for
483
+     * @return Comment|null
484
+     */
485
+    protected function getLastKnownComment(string $objectType,
486
+                                            string $objectId,
487
+                                            int $id) {
488
+        $query = $this->dbConn->getQueryBuilder();
489
+        $query->select('*')
490
+            ->from('comments')
491
+            ->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
492
+            ->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
493
+            ->andWhere($query->expr()->eq('id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
494
+
495
+        $result = $query->execute();
496
+        $row = $result->fetch();
497
+        $result->closeCursor();
498
+
499
+        if ($row) {
500
+            $comment = $this->getCommentFromData($row);
501
+            $this->cache($comment);
502
+            return $comment;
503
+        }
504
+
505
+        return null;
506
+    }
507
+
508
+    /**
509
+     * Search for comments with a given content
510
+     *
511
+     * @param string $search content to search for
512
+     * @param string $objectType Limit the search by object type
513
+     * @param string $objectId Limit the search by object id
514
+     * @param string $verb Limit the verb of the comment
515
+     * @param int $offset
516
+     * @param int $limit
517
+     * @return IComment[]
518
+     */
519
+    public function search(string $search, string $objectType, string $objectId, string $verb, int $offset, int $limit = 50): array {
520
+        $query = $this->dbConn->getQueryBuilder();
521
+
522
+        $query->select('*')
523
+            ->from('comments')
524
+            ->where($query->expr()->iLike('message', $query->createNamedParameter(
525
+                '%' . $this->dbConn->escapeLikeParameter($search). '%'
526
+            )))
527
+            ->orderBy('creation_timestamp', 'DESC')
528
+            ->addOrderBy('id', 'DESC')
529
+            ->setMaxResults($limit);
530
+
531
+        if ($objectType !== '') {
532
+            $query->andWhere($query->expr()->eq('object_type', $query->createNamedParameter($objectType)));
533
+        }
534
+        if ($objectId !== '') {
535
+            $query->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)));
536
+        }
537
+        if ($verb !== '') {
538
+            $query->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb)));
539
+        }
540
+        if ($offset !== 0) {
541
+            $query->setFirstResult($offset);
542
+        }
543
+
544
+        $comments = [];
545
+        $result = $query->execute();
546
+        while ($data = $result->fetch()) {
547
+            $comment = $this->getCommentFromData($data);
548
+            $this->cache($comment);
549
+            $comments[] = $comment;
550
+        }
551
+        $result->closeCursor();
552
+
553
+        return $comments;
554
+    }
555
+
556
+    /**
557
+     * @param $objectType string the object type, e.g. 'files'
558
+     * @param $objectId string the id of the object
559
+     * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
560
+     * that may be returned
561
+     * @param string $verb Limit the verb of the comment - Added in 14.0.0
562
+     * @return Int
563
+     * @since 9.0.0
564
+     */
565
+    public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null, $verb = '') {
566
+        $qb = $this->dbConn->getQueryBuilder();
567
+        $query = $qb->select($qb->func()->count('id'))
568
+            ->from('comments')
569
+            ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
570
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
571
+            ->setParameter('type', $objectType)
572
+            ->setParameter('id', $objectId);
573
+
574
+        if (!is_null($notOlderThan)) {
575
+            $query
576
+                ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
577
+                ->setParameter('notOlderThan', $notOlderThan, 'datetime');
578
+        }
579
+
580
+        if ($verb !== '') {
581
+            $query->andWhere($qb->expr()->eq('verb', $qb->createNamedParameter($verb)));
582
+        }
583
+
584
+        $resultStatement = $query->execute();
585
+        $data = $resultStatement->fetch(\PDO::FETCH_NUM);
586
+        $resultStatement->closeCursor();
587
+        return (int)$data[0];
588
+    }
589
+
590
+    /**
591
+     * Get the number of unread comments for all files in a folder
592
+     *
593
+     * @param int $folderId
594
+     * @param IUser $user
595
+     * @return array [$fileId => $unreadCount]
596
+     */
597
+    public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) {
598
+        $qb = $this->dbConn->getQueryBuilder();
599
+
600
+        $query = $qb->select('f.fileid')
601
+            ->addSelect($qb->func()->count('c.id', 'num_ids'))
602
+            ->from('filecache', 'f')
603
+            ->leftJoin('f', 'comments', 'c', $qb->expr()->andX(
604
+                $qb->expr()->eq('f.fileid', $qb->expr()->castColumn('c.object_id', IQueryBuilder::PARAM_INT)),
605
+                $qb->expr()->eq('c.object_type', $qb->createNamedParameter('files'))
606
+            ))
607
+            ->leftJoin('c', 'comments_read_markers', 'm', $qb->expr()->andX(
608
+                $qb->expr()->eq('c.object_id', 'm.object_id'),
609
+                $qb->expr()->eq('m.object_type', $qb->createNamedParameter('files'))
610
+            ))
611
+            ->where(
612
+                $qb->expr()->andX(
613
+                    $qb->expr()->eq('f.parent', $qb->createNamedParameter($folderId)),
614
+                    $qb->expr()->orX(
615
+                        $qb->expr()->eq('c.object_type', $qb->createNamedParameter('files')),
616
+                        $qb->expr()->isNull('c.object_type')
617
+                    ),
618
+                    $qb->expr()->orX(
619
+                        $qb->expr()->eq('m.object_type', $qb->createNamedParameter('files')),
620
+                        $qb->expr()->isNull('m.object_type')
621
+                    ),
622
+                    $qb->expr()->orX(
623
+                        $qb->expr()->eq('m.user_id', $qb->createNamedParameter($user->getUID())),
624
+                        $qb->expr()->isNull('m.user_id')
625
+                    ),
626
+                    $qb->expr()->orX(
627
+                        $qb->expr()->gt('c.creation_timestamp', 'm.marker_datetime'),
628
+                        $qb->expr()->isNull('m.marker_datetime')
629
+                    )
630
+                )
631
+            )->groupBy('f.fileid');
632
+
633
+        $resultStatement = $query->execute();
634
+
635
+        $results = [];
636
+        while ($row = $resultStatement->fetch()) {
637
+            $results[$row['fileid']] = (int) $row['num_ids'];
638
+        }
639
+        $resultStatement->closeCursor();
640
+        return $results;
641
+    }
642
+
643
+    /**
644
+     * creates a new comment and returns it. At this point of time, it is not
645
+     * saved in the used data storage. Use save() after setting other fields
646
+     * of the comment (e.g. message or verb).
647
+     *
648
+     * @param string $actorType the actor type (e.g. 'users')
649
+     * @param string $actorId a user id
650
+     * @param string $objectType the object type the comment is attached to
651
+     * @param string $objectId the object id the comment is attached to
652
+     * @return IComment
653
+     * @since 9.0.0
654
+     */
655
+    public function create($actorType, $actorId, $objectType, $objectId) {
656
+        $comment = new Comment();
657
+        $comment
658
+            ->setActor($actorType, $actorId)
659
+            ->setObject($objectType, $objectId);
660
+        return $comment;
661
+    }
662
+
663
+    /**
664
+     * permanently deletes the comment specified by the ID
665
+     *
666
+     * When the comment has child comments, their parent ID will be changed to
667
+     * the parent ID of the item that is to be deleted.
668
+     *
669
+     * @param string $id
670
+     * @return bool
671
+     * @throws \InvalidArgumentException
672
+     * @since 9.0.0
673
+     */
674
+    public function delete($id) {
675
+        if (!is_string($id)) {
676
+            throw new \InvalidArgumentException('Parameter must be string');
677
+        }
678
+
679
+        try {
680
+            $comment = $this->get($id);
681
+        } catch (\Exception $e) {
682
+            // Ignore exceptions, we just don't fire a hook then
683
+            $comment = null;
684
+        }
685
+
686
+        $qb = $this->dbConn->getQueryBuilder();
687
+        $query = $qb->delete('comments')
688
+            ->where($qb->expr()->eq('id', $qb->createParameter('id')))
689
+            ->setParameter('id', $id);
690
+
691
+        try {
692
+            $affectedRows = $query->execute();
693
+            $this->uncache($id);
694
+        } catch (DriverException $e) {
695
+            $this->logger->error($e->getMessage(), [
696
+                'exception' => $e,
697
+                'app' => 'core_comments',
698
+            ]);
699
+            return false;
700
+        }
701
+
702
+        if ($affectedRows > 0 && $comment instanceof IComment) {
703
+            $this->sendEvent(CommentsEvent::EVENT_DELETE, $comment);
704
+        }
705
+
706
+        return ($affectedRows > 0);
707
+    }
708
+
709
+    /**
710
+     * saves the comment permanently
711
+     *
712
+     * if the supplied comment has an empty ID, a new entry comment will be
713
+     * saved and the instance updated with the new ID.
714
+     *
715
+     * Otherwise, an existing comment will be updated.
716
+     *
717
+     * Throws NotFoundException when a comment that is to be updated does not
718
+     * exist anymore at this point of time.
719
+     *
720
+     * @param IComment $comment
721
+     * @return bool
722
+     * @throws NotFoundException
723
+     * @since 9.0.0
724
+     */
725
+    public function save(IComment $comment) {
726
+        if ($this->prepareCommentForDatabaseWrite($comment)->getId() === '') {
727
+            $result = $this->insert($comment);
728
+        } else {
729
+            $result = $this->update($comment);
730
+        }
731
+
732
+        if ($result && !!$comment->getParentId()) {
733
+            $this->updateChildrenInformation(
734
+                $comment->getParentId(),
735
+                $comment->getCreationDateTime()
736
+            );
737
+            $this->cache($comment);
738
+        }
739
+
740
+        return $result;
741
+    }
742
+
743
+    /**
744
+     * inserts the provided comment in the database
745
+     *
746
+     * @param IComment $comment
747
+     * @return bool
748
+     */
749
+    protected function insert(IComment $comment): bool {
750
+        try {
751
+            $result = $this->insertQuery($comment, true);
752
+        } catch (InvalidFieldNameException $e) {
753
+            // The reference id field was only added in Nextcloud 19.
754
+            // In order to not cause too long waiting times on the update,
755
+            // it was decided to only add it lazy, as it is also not a critical
756
+            // feature, but only helps to have a better experience while commenting.
757
+            // So in case the reference_id field is missing,
758
+            // we simply save the comment without that field.
759
+            $result = $this->insertQuery($comment, false);
760
+        }
761
+
762
+        return $result;
763
+    }
764
+
765
+    protected function insertQuery(IComment $comment, bool $tryWritingReferenceId): bool {
766
+        $qb = $this->dbConn->getQueryBuilder();
767
+
768
+        $values = [
769
+            'parent_id' => $qb->createNamedParameter($comment->getParentId()),
770
+            'topmost_parent_id' => $qb->createNamedParameter($comment->getTopmostParentId()),
771
+            'children_count' => $qb->createNamedParameter($comment->getChildrenCount()),
772
+            'actor_type' => $qb->createNamedParameter($comment->getActorType()),
773
+            'actor_id' => $qb->createNamedParameter($comment->getActorId()),
774
+            'message' => $qb->createNamedParameter($comment->getMessage()),
775
+            'verb' => $qb->createNamedParameter($comment->getVerb()),
776
+            'creation_timestamp' => $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'),
777
+            'latest_child_timestamp' => $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'),
778
+            'object_type' => $qb->createNamedParameter($comment->getObjectType()),
779
+            'object_id' => $qb->createNamedParameter($comment->getObjectId()),
780
+        ];
781
+
782
+        if ($tryWritingReferenceId) {
783
+            $values['reference_id'] = $qb->createNamedParameter($comment->getReferenceId());
784
+        }
785
+
786
+        $affectedRows = $qb->insert('comments')
787
+            ->values($values)
788
+            ->execute();
789
+
790
+        if ($affectedRows > 0) {
791
+            $comment->setId((string)$qb->getLastInsertId());
792
+            $this->sendEvent(CommentsEvent::EVENT_ADD, $comment);
793
+        }
794
+
795
+        return $affectedRows > 0;
796
+    }
797
+
798
+    /**
799
+     * updates a Comment data row
800
+     *
801
+     * @param IComment $comment
802
+     * @return bool
803
+     * @throws NotFoundException
804
+     */
805
+    protected function update(IComment $comment) {
806
+        // for properly working preUpdate Events we need the old comments as is
807
+        // in the DB and overcome caching. Also avoid that outdated information stays.
808
+        $this->uncache($comment->getId());
809
+        $this->sendEvent(CommentsEvent::EVENT_PRE_UPDATE, $this->get($comment->getId()));
810
+        $this->uncache($comment->getId());
811
+
812
+        try {
813
+            $result = $this->updateQuery($comment, true);
814
+        } catch (InvalidFieldNameException $e) {
815
+            // See function insert() for explanation
816
+            $result = $this->updateQuery($comment, false);
817
+        }
818
+
819
+        $this->sendEvent(CommentsEvent::EVENT_UPDATE, $comment);
820
+
821
+        return $result;
822
+    }
823
+
824
+    protected function updateQuery(IComment $comment, bool $tryWritingReferenceId): bool {
825
+        $qb = $this->dbConn->getQueryBuilder();
826
+        $qb
827
+            ->update('comments')
828
+            ->set('parent_id', $qb->createNamedParameter($comment->getParentId()))
829
+            ->set('topmost_parent_id', $qb->createNamedParameter($comment->getTopmostParentId()))
830
+            ->set('children_count', $qb->createNamedParameter($comment->getChildrenCount()))
831
+            ->set('actor_type', $qb->createNamedParameter($comment->getActorType()))
832
+            ->set('actor_id', $qb->createNamedParameter($comment->getActorId()))
833
+            ->set('message', $qb->createNamedParameter($comment->getMessage()))
834
+            ->set('verb', $qb->createNamedParameter($comment->getVerb()))
835
+            ->set('creation_timestamp', $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'))
836
+            ->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'))
837
+            ->set('object_type', $qb->createNamedParameter($comment->getObjectType()))
838
+            ->set('object_id', $qb->createNamedParameter($comment->getObjectId()));
839
+
840
+        if ($tryWritingReferenceId) {
841
+            $qb->set('reference_id', $qb->createNamedParameter($comment->getReferenceId()));
842
+        }
843
+
844
+        $affectedRows = $qb->where($qb->expr()->eq('id', $qb->createNamedParameter($comment->getId())))
845
+            ->execute();
846
+
847
+        if ($affectedRows === 0) {
848
+            throw new NotFoundException('Comment to update does ceased to exist');
849
+        }
850
+
851
+        return $affectedRows > 0;
852
+    }
853
+
854
+    /**
855
+     * removes references to specific actor (e.g. on user delete) of a comment.
856
+     * The comment itself must not get lost/deleted.
857
+     *
858
+     * @param string $actorType the actor type (e.g. 'users')
859
+     * @param string $actorId a user id
860
+     * @return boolean
861
+     * @since 9.0.0
862
+     */
863
+    public function deleteReferencesOfActor($actorType, $actorId) {
864
+        $this->checkRoleParameters('Actor', $actorType, $actorId);
865
+
866
+        $qb = $this->dbConn->getQueryBuilder();
867
+        $affectedRows = $qb
868
+            ->update('comments')
869
+            ->set('actor_type', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
870
+            ->set('actor_id', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
871
+            ->where($qb->expr()->eq('actor_type', $qb->createParameter('type')))
872
+            ->andWhere($qb->expr()->eq('actor_id', $qb->createParameter('id')))
873
+            ->setParameter('type', $actorType)
874
+            ->setParameter('id', $actorId)
875
+            ->execute();
876
+
877
+        $this->commentsCache = [];
878
+
879
+        return is_int($affectedRows);
880
+    }
881
+
882
+    /**
883
+     * deletes all comments made of a specific object (e.g. on file delete)
884
+     *
885
+     * @param string $objectType the object type (e.g. 'files')
886
+     * @param string $objectId e.g. the file id
887
+     * @return boolean
888
+     * @since 9.0.0
889
+     */
890
+    public function deleteCommentsAtObject($objectType, $objectId) {
891
+        $this->checkRoleParameters('Object', $objectType, $objectId);
892
+
893
+        $qb = $this->dbConn->getQueryBuilder();
894
+        $affectedRows = $qb
895
+            ->delete('comments')
896
+            ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
897
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
898
+            ->setParameter('type', $objectType)
899
+            ->setParameter('id', $objectId)
900
+            ->execute();
901
+
902
+        $this->commentsCache = [];
903
+
904
+        return is_int($affectedRows);
905
+    }
906
+
907
+    /**
908
+     * deletes the read markers for the specified user
909
+     *
910
+     * @param \OCP\IUser $user
911
+     * @return bool
912
+     * @since 9.0.0
913
+     */
914
+    public function deleteReadMarksFromUser(IUser $user) {
915
+        $qb = $this->dbConn->getQueryBuilder();
916
+        $query = $qb->delete('comments_read_markers')
917
+            ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
918
+            ->setParameter('user_id', $user->getUID());
919
+
920
+        try {
921
+            $affectedRows = $query->execute();
922
+        } catch (DriverException $e) {
923
+            $this->logger->error($e->getMessage(), [
924
+                'exception' => $e,
925
+                'app' => 'core_comments',
926
+            ]);
927
+            return false;
928
+        }
929
+        return ($affectedRows > 0);
930
+    }
931
+
932
+    /**
933
+     * sets the read marker for a given file to the specified date for the
934
+     * provided user
935
+     *
936
+     * @param string $objectType
937
+     * @param string $objectId
938
+     * @param \DateTime $dateTime
939
+     * @param IUser $user
940
+     * @since 9.0.0
941
+     */
942
+    public function setReadMark($objectType, $objectId, \DateTime $dateTime, IUser $user) {
943
+        $this->checkRoleParameters('Object', $objectType, $objectId);
944
+
945
+        $qb = $this->dbConn->getQueryBuilder();
946
+        $values = [
947
+            'user_id' => $qb->createNamedParameter($user->getUID()),
948
+            'marker_datetime' => $qb->createNamedParameter($dateTime, 'datetime'),
949
+            'object_type' => $qb->createNamedParameter($objectType),
950
+            'object_id' => $qb->createNamedParameter($objectId),
951
+        ];
952
+
953
+        // Strategy: try to update, if this does not return affected rows, do an insert.
954
+        $affectedRows = $qb
955
+            ->update('comments_read_markers')
956
+            ->set('user_id', $values['user_id'])
957
+            ->set('marker_datetime', $values['marker_datetime'])
958
+            ->set('object_type', $values['object_type'])
959
+            ->set('object_id', $values['object_id'])
960
+            ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
961
+            ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
962
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
963
+            ->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR)
964
+            ->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR)
965
+            ->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR)
966
+            ->execute();
967
+
968
+        if ($affectedRows > 0) {
969
+            return;
970
+        }
971
+
972
+        $qb->insert('comments_read_markers')
973
+            ->values($values)
974
+            ->execute();
975
+    }
976
+
977
+    /**
978
+     * returns the read marker for a given file to the specified date for the
979
+     * provided user. It returns null, when the marker is not present, i.e.
980
+     * no comments were marked as read.
981
+     *
982
+     * @param string $objectType
983
+     * @param string $objectId
984
+     * @param IUser $user
985
+     * @return \DateTime|null
986
+     * @since 9.0.0
987
+     */
988
+    public function getReadMark($objectType, $objectId, IUser $user) {
989
+        $qb = $this->dbConn->getQueryBuilder();
990
+        $resultStatement = $qb->select('marker_datetime')
991
+            ->from('comments_read_markers')
992
+            ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
993
+            ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
994
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
995
+            ->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR)
996
+            ->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR)
997
+            ->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR)
998
+            ->execute();
999
+
1000
+        $data = $resultStatement->fetch();
1001
+        $resultStatement->closeCursor();
1002
+        if (!$data || is_null($data['marker_datetime'])) {
1003
+            return null;
1004
+        }
1005
+
1006
+        return new \DateTime($data['marker_datetime']);
1007
+    }
1008
+
1009
+    /**
1010
+     * deletes the read markers on the specified object
1011
+     *
1012
+     * @param string $objectType
1013
+     * @param string $objectId
1014
+     * @return bool
1015
+     * @since 9.0.0
1016
+     */
1017
+    public function deleteReadMarksOnObject($objectType, $objectId) {
1018
+        $this->checkRoleParameters('Object', $objectType, $objectId);
1019
+
1020
+        $qb = $this->dbConn->getQueryBuilder();
1021
+        $query = $qb->delete('comments_read_markers')
1022
+            ->where($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
1023
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
1024
+            ->setParameter('object_type', $objectType)
1025
+            ->setParameter('object_id', $objectId);
1026
+
1027
+        try {
1028
+            $affectedRows = $query->execute();
1029
+        } catch (DriverException $e) {
1030
+            $this->logger->error($e->getMessage(), [
1031
+                'exception' => $e,
1032
+                'app' => 'core_comments',
1033
+            ]);
1034
+            return false;
1035
+        }
1036
+        return ($affectedRows > 0);
1037
+    }
1038
+
1039
+    /**
1040
+     * registers an Entity to the manager, so event notifications can be send
1041
+     * to consumers of the comments infrastructure
1042
+     *
1043
+     * @param \Closure $closure
1044
+     */
1045
+    public function registerEventHandler(\Closure $closure) {
1046
+        $this->eventHandlerClosures[] = $closure;
1047
+        $this->eventHandlers = [];
1048
+    }
1049
+
1050
+    /**
1051
+     * registers a method that resolves an ID to a display name for a given type
1052
+     *
1053
+     * @param string $type
1054
+     * @param \Closure $closure
1055
+     * @throws \OutOfBoundsException
1056
+     * @since 11.0.0
1057
+     *
1058
+     * Only one resolver shall be registered per type. Otherwise a
1059
+     * \OutOfBoundsException has to thrown.
1060
+     */
1061
+    public function registerDisplayNameResolver($type, \Closure $closure) {
1062
+        if (!is_string($type)) {
1063
+            throw new \InvalidArgumentException('String expected.');
1064
+        }
1065
+        if (isset($this->displayNameResolvers[$type])) {
1066
+            throw new \OutOfBoundsException('Displayname resolver for this type already registered');
1067
+        }
1068
+        $this->displayNameResolvers[$type] = $closure;
1069
+    }
1070
+
1071
+    /**
1072
+     * resolves a given ID of a given Type to a display name.
1073
+     *
1074
+     * @param string $type
1075
+     * @param string $id
1076
+     * @return string
1077
+     * @throws \OutOfBoundsException
1078
+     * @since 11.0.0
1079
+     *
1080
+     * If a provided type was not registered, an \OutOfBoundsException shall
1081
+     * be thrown. It is upon the resolver discretion what to return of the
1082
+     * provided ID is unknown. It must be ensured that a string is returned.
1083
+     */
1084
+    public function resolveDisplayName($type, $id) {
1085
+        if (!is_string($type)) {
1086
+            throw new \InvalidArgumentException('String expected.');
1087
+        }
1088
+        if (!isset($this->displayNameResolvers[$type])) {
1089
+            throw new \OutOfBoundsException('No Displayname resolver for this type registered');
1090
+        }
1091
+        return (string)$this->displayNameResolvers[$type]($id);
1092
+    }
1093
+
1094
+    /**
1095
+     * returns valid, registered entities
1096
+     *
1097
+     * @return \OCP\Comments\ICommentsEventHandler[]
1098
+     */
1099
+    private function getEventHandlers() {
1100
+        if (!empty($this->eventHandlers)) {
1101
+            return $this->eventHandlers;
1102
+        }
1103
+
1104
+        $this->eventHandlers = [];
1105
+        foreach ($this->eventHandlerClosures as $name => $closure) {
1106
+            $entity = $closure();
1107
+            if (!($entity instanceof ICommentsEventHandler)) {
1108
+                throw new \InvalidArgumentException('The given entity does not implement the ICommentsEntity interface');
1109
+            }
1110
+            $this->eventHandlers[$name] = $entity;
1111
+        }
1112
+
1113
+        return $this->eventHandlers;
1114
+    }
1115
+
1116
+    /**
1117
+     * sends notifications to the registered entities
1118
+     *
1119
+     * @param $eventType
1120
+     * @param IComment $comment
1121
+     */
1122
+    private function sendEvent($eventType, IComment $comment) {
1123
+        $entities = $this->getEventHandlers();
1124
+        $event = new CommentsEvent($eventType, $comment);
1125
+        foreach ($entities as $entity) {
1126
+            $entity->handle($event);
1127
+        }
1128
+    }
1129
+
1130
+    /**
1131
+     * Load the Comments app into the page
1132
+     *
1133
+     * @since 21.0.0
1134
+     */
1135
+    public function load(): void {
1136
+        $this->initialStateService->provideInitialState(Application::APP_ID, 'max-message-length', IComment::MAX_MESSAGE_LENGTH);
1137
+        Util::addScript(Application::APP_ID, 'comments-app');
1138
+    }
1139 1139
 }
Please login to merge, or discard this patch.
lib/private/Comments/ManagerFactory.php 1 patch
Indentation   +28 added lines, -28 removed lines patch added patch discarded remove patch
@@ -33,34 +33,34 @@
 block discarded – undo
33 33
 
34 34
 class ManagerFactory implements ICommentsManagerFactory {
35 35
 
36
-	/**
37
-	 * Server container
38
-	 *
39
-	 * @var IServerContainer
40
-	 */
41
-	private $serverContainer;
36
+    /**
37
+     * Server container
38
+     *
39
+     * @var IServerContainer
40
+     */
41
+    private $serverContainer;
42 42
 
43
-	/**
44
-	 * Constructor for the comments manager factory
45
-	 *
46
-	 * @param IServerContainer $serverContainer server container
47
-	 */
48
-	public function __construct(IServerContainer $serverContainer) {
49
-		$this->serverContainer = $serverContainer;
50
-	}
43
+    /**
44
+     * Constructor for the comments manager factory
45
+     *
46
+     * @param IServerContainer $serverContainer server container
47
+     */
48
+    public function __construct(IServerContainer $serverContainer) {
49
+        $this->serverContainer = $serverContainer;
50
+    }
51 51
 
52
-	/**
53
-	 * creates and returns an instance of the ICommentsManager
54
-	 *
55
-	 * @return ICommentsManager
56
-	 * @since 9.0.0
57
-	 */
58
-	public function getManager() {
59
-		return new Manager(
60
-			$this->serverContainer->getDatabaseConnection(),
61
-			$this->serverContainer->get(LoggerInterface::class),
62
-			$this->serverContainer->getConfig(),
63
-			$this->serverContainer->get(IInitialStateService::class)
64
-		);
65
-	}
52
+    /**
53
+     * creates and returns an instance of the ICommentsManager
54
+     *
55
+     * @return ICommentsManager
56
+     * @since 9.0.0
57
+     */
58
+    public function getManager() {
59
+        return new Manager(
60
+            $this->serverContainer->getDatabaseConnection(),
61
+            $this->serverContainer->get(LoggerInterface::class),
62
+            $this->serverContainer->getConfig(),
63
+            $this->serverContainer->get(IInitialStateService::class)
64
+        );
65
+    }
66 66
 }
Please login to merge, or discard this patch.
apps/comments/lib/Listener/LoadSidebarScripts.php 1 patch
Indentation   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -36,23 +36,23 @@
 block discarded – undo
36 36
 
37 37
 class LoadSidebarScripts implements IEventListener {
38 38
 
39
-	/** @var ICommentsManager */
40
-	private $commentsManager;
39
+    /** @var ICommentsManager */
40
+    private $commentsManager;
41 41
 
42
-	public function __construct(ICommentsManager $commentsManager) {
43
-		$this->commentsManager = $commentsManager;
44
-	}
42
+    public function __construct(ICommentsManager $commentsManager) {
43
+        $this->commentsManager = $commentsManager;
44
+    }
45 45
 
46
-	public function handle(Event $event): void {
47
-		if (!($event instanceof LoadSidebar)) {
48
-			return;
49
-		}
46
+    public function handle(Event $event): void {
47
+        if (!($event instanceof LoadSidebar)) {
48
+            return;
49
+        }
50 50
 
51
-		$this->commentsManager->load();
51
+        $this->commentsManager->load();
52 52
 
53
-		// TODO: make sure to only include the sidebar script when
54
-		// we properly split it between files list and sidebar
55
-		Util::addScript(Application::APP_ID, 'comments');
56
-		Util::addScript(Application::APP_ID, 'comments-tab');
57
-	}
53
+        // TODO: make sure to only include the sidebar script when
54
+        // we properly split it between files list and sidebar
55
+        Util::addScript(Application::APP_ID, 'comments');
56
+        Util::addScript(Application::APP_ID, 'comments-tab');
57
+    }
58 58
 }
Please login to merge, or discard this patch.
core/Controller/AutoCompleteController.php 1 patch
Indentation   +84 added lines, -84 removed lines patch added patch discarded remove patch
@@ -39,88 +39,88 @@
 block discarded – undo
39 39
 use OCP\Share\IShare;
40 40
 
41 41
 class AutoCompleteController extends Controller {
42
-	/** @var ISearch */
43
-	private $collaboratorSearch;
44
-
45
-	/** @var IManager */
46
-	private $autoCompleteManager;
47
-
48
-	/** @var IEventDispatcher */
49
-	private $dispatcher;
50
-
51
-	public function __construct(string $appName,
52
-								IRequest $request,
53
-								ISearch $collaboratorSearch,
54
-								IManager $autoCompleteManager,
55
-								IEventDispatcher $dispatcher) {
56
-		parent::__construct($appName, $request);
57
-
58
-		$this->collaboratorSearch = $collaboratorSearch;
59
-		$this->autoCompleteManager = $autoCompleteManager;
60
-		$this->dispatcher = $dispatcher;
61
-	}
62
-
63
-	/**
64
-	 * @NoAdminRequired
65
-	 *
66
-	 * @param string $search
67
-	 * @param string $itemType
68
-	 * @param string $itemId
69
-	 * @param string|null $sorter can be piped, top prio first, e.g.: "commenters|share-recipients"
70
-	 * @param array $shareTypes
71
-	 * @param int $limit
72
-	 * @return DataResponse
73
-	 */
74
-	public function get($search, $itemType, $itemId, $sorter = null, $shareTypes = [IShare::TYPE_USER], $limit = 10): DataResponse {
75
-		// if enumeration/user listings are disabled, we'll receive an empty
76
-		// result from search() – thus nothing else to do here.
77
-		[$results,] = $this->collaboratorSearch->search($search, $shareTypes, false, $limit, 0);
78
-
79
-		$event = new AutoCompleteEvent([
80
-			'search' => $search,
81
-			'results' => $results,
82
-			'itemType' => $itemType,
83
-			'itemId' => $itemId,
84
-			'sorter' => $sorter,
85
-			'shareTypes' => $shareTypes,
86
-			'limit' => $limit,
87
-		]);
88
-		$this->dispatcher->dispatch(IManager::class . '::filterResults', $event);
89
-		$results = $event->getResults();
90
-
91
-		$exactMatches = $results['exact'];
92
-		unset($results['exact']);
93
-		$results = array_merge_recursive($exactMatches, $results);
94
-
95
-		if ($sorter !== null) {
96
-			$sorters = array_reverse(explode('|', $sorter));
97
-			$this->autoCompleteManager->runSorters($sorters, $results, [
98
-				'itemType' => $itemType,
99
-				'itemId' => $itemId,
100
-			]);
101
-		}
102
-
103
-		// transform to expected format
104
-		$results = $this->prepareResultArray($results);
105
-
106
-		return new DataResponse($results);
107
-	}
108
-
109
-
110
-	protected function prepareResultArray(array $results): array {
111
-		$output = [];
112
-		foreach ($results as $type => $subResult) {
113
-			foreach ($subResult as $result) {
114
-				$output[] = [
115
-					'id' => (string) $result['value']['shareWith'],
116
-					'label' => $result['label'],
117
-					'icon' => $result['icon'],
118
-					'source' => $type,
119
-					'status' => $result['status'],
120
-					'subline' => $result['subline']
121
-				];
122
-			}
123
-		}
124
-		return $output;
125
-	}
42
+    /** @var ISearch */
43
+    private $collaboratorSearch;
44
+
45
+    /** @var IManager */
46
+    private $autoCompleteManager;
47
+
48
+    /** @var IEventDispatcher */
49
+    private $dispatcher;
50
+
51
+    public function __construct(string $appName,
52
+                                IRequest $request,
53
+                                ISearch $collaboratorSearch,
54
+                                IManager $autoCompleteManager,
55
+                                IEventDispatcher $dispatcher) {
56
+        parent::__construct($appName, $request);
57
+
58
+        $this->collaboratorSearch = $collaboratorSearch;
59
+        $this->autoCompleteManager = $autoCompleteManager;
60
+        $this->dispatcher = $dispatcher;
61
+    }
62
+
63
+    /**
64
+     * @NoAdminRequired
65
+     *
66
+     * @param string $search
67
+     * @param string $itemType
68
+     * @param string $itemId
69
+     * @param string|null $sorter can be piped, top prio first, e.g.: "commenters|share-recipients"
70
+     * @param array $shareTypes
71
+     * @param int $limit
72
+     * @return DataResponse
73
+     */
74
+    public function get($search, $itemType, $itemId, $sorter = null, $shareTypes = [IShare::TYPE_USER], $limit = 10): DataResponse {
75
+        // if enumeration/user listings are disabled, we'll receive an empty
76
+        // result from search() – thus nothing else to do here.
77
+        [$results,] = $this->collaboratorSearch->search($search, $shareTypes, false, $limit, 0);
78
+
79
+        $event = new AutoCompleteEvent([
80
+            'search' => $search,
81
+            'results' => $results,
82
+            'itemType' => $itemType,
83
+            'itemId' => $itemId,
84
+            'sorter' => $sorter,
85
+            'shareTypes' => $shareTypes,
86
+            'limit' => $limit,
87
+        ]);
88
+        $this->dispatcher->dispatch(IManager::class . '::filterResults', $event);
89
+        $results = $event->getResults();
90
+
91
+        $exactMatches = $results['exact'];
92
+        unset($results['exact']);
93
+        $results = array_merge_recursive($exactMatches, $results);
94
+
95
+        if ($sorter !== null) {
96
+            $sorters = array_reverse(explode('|', $sorter));
97
+            $this->autoCompleteManager->runSorters($sorters, $results, [
98
+                'itemType' => $itemType,
99
+                'itemId' => $itemId,
100
+            ]);
101
+        }
102
+
103
+        // transform to expected format
104
+        $results = $this->prepareResultArray($results);
105
+
106
+        return new DataResponse($results);
107
+    }
108
+
109
+
110
+    protected function prepareResultArray(array $results): array {
111
+        $output = [];
112
+        foreach ($results as $type => $subResult) {
113
+            foreach ($subResult as $result) {
114
+                $output[] = [
115
+                    'id' => (string) $result['value']['shareWith'],
116
+                    'label' => $result['label'],
117
+                    'icon' => $result['icon'],
118
+                    'source' => $type,
119
+                    'status' => $result['status'],
120
+                    'subline' => $result['subline']
121
+                ];
122
+            }
123
+        }
124
+        return $output;
125
+    }
126 126
 }
Please login to merge, or discard this patch.