Completed
Push — master ( 5262ba...247b25 )
by
unknown
30:03 queued 13s
created
apps/files_sharing/lib/Controller/ShareesAPIController.php 1 patch
Indentation   +359 added lines, -359 removed lines patch added patch discarded remove patch
@@ -39,363 +39,363 @@
 block discarded – undo
39 39
  */
40 40
 class ShareesAPIController extends OCSController {
41 41
 
42
-	/** @var int */
43
-	protected $offset = 0;
44
-
45
-	/** @var int */
46
-	protected $limit = 10;
47
-
48
-	/** @var Files_SharingShareesSearchResult */
49
-	protected $result = [
50
-		'exact' => [
51
-			'users' => [],
52
-			'groups' => [],
53
-			'remotes' => [],
54
-			'remote_groups' => [],
55
-			'emails' => [],
56
-			'circles' => [],
57
-			'rooms' => [],
58
-		],
59
-		'users' => [],
60
-		'groups' => [],
61
-		'remotes' => [],
62
-		'remote_groups' => [],
63
-		'emails' => [],
64
-		'lookup' => [],
65
-		'circles' => [],
66
-		'rooms' => [],
67
-		'lookupEnabled' => false,
68
-	];
69
-
70
-	protected $reachedEndFor = [];
71
-
72
-	public function __construct(
73
-		string $appName,
74
-		IRequest $request,
75
-		protected ?string $userId,
76
-		protected IConfig $config,
77
-		protected IURLGenerator $urlGenerator,
78
-		protected IManager $shareManager,
79
-		protected ISearch $collaboratorSearch,
80
-	) {
81
-		parent::__construct($appName, $request);
82
-	}
83
-
84
-	/**
85
-	 * Search for sharees
86
-	 *
87
-	 * @param string $search Text to search for
88
-	 * @param string|null $itemType Limit to specific item types
89
-	 * @param int $page Page offset for searching
90
-	 * @param int $perPage Limit amount of search results per page
91
-	 * @param int|list<int>|null $shareType Limit to specific share types
92
-	 * @param bool $lookup If a global lookup should be performed too
93
-	 * @return DataResponse<Http::STATUS_OK, Files_SharingShareesSearchResult, array{Link?: string}>
94
-	 * @throws OCSBadRequestException Invalid search parameters
95
-	 *
96
-	 * 200: Sharees search result returned
97
-	 */
98
-	#[NoAdminRequired]
99
-	public function search(string $search = '', ?string $itemType = null, int $page = 1, int $perPage = 200, $shareType = null, bool $lookup = false): DataResponse {
100
-
101
-		// only search for string larger than a given threshold
102
-		$threshold = $this->config->getSystemValueInt('sharing.minSearchStringLength', 0);
103
-		if (strlen($search) < $threshold) {
104
-			return new DataResponse($this->result);
105
-		}
106
-
107
-		if ($this->shareManager->sharingDisabledForUser($this->userId)) {
108
-			return new DataResponse($this->result);
109
-		}
110
-
111
-		// never return more than the max. number of results configured in the config.php
112
-		$maxResults = $this->config->getSystemValueInt('sharing.maxAutocompleteResults', Constants::SHARING_MAX_AUTOCOMPLETE_RESULTS_DEFAULT);
113
-		if ($maxResults > 0) {
114
-			$perPage = min($perPage, $maxResults);
115
-		}
116
-		if ($perPage <= 0) {
117
-			throw new OCSBadRequestException('Invalid perPage argument');
118
-		}
119
-		if ($page <= 0) {
120
-			throw new OCSBadRequestException('Invalid page');
121
-		}
122
-
123
-		$shareTypes = [
124
-			IShare::TYPE_USER,
125
-		];
126
-
127
-		if ($itemType === null) {
128
-			throw new OCSBadRequestException('Missing itemType');
129
-		} elseif ($itemType === 'file' || $itemType === 'folder') {
130
-			if ($this->shareManager->allowGroupSharing()) {
131
-				$shareTypes[] = IShare::TYPE_GROUP;
132
-			}
133
-
134
-			if ($this->isRemoteSharingAllowed($itemType)) {
135
-				$shareTypes[] = IShare::TYPE_REMOTE;
136
-			}
137
-
138
-			if ($this->isRemoteGroupSharingAllowed($itemType)) {
139
-				$shareTypes[] = IShare::TYPE_REMOTE_GROUP;
140
-			}
141
-
142
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
143
-				$shareTypes[] = IShare::TYPE_EMAIL;
144
-			}
145
-
146
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_ROOM)) {
147
-				$shareTypes[] = IShare::TYPE_ROOM;
148
-			}
149
-
150
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_SCIENCEMESH)) {
151
-				$shareTypes[] = IShare::TYPE_SCIENCEMESH;
152
-			}
153
-		} else {
154
-			if ($this->shareManager->allowGroupSharing()) {
155
-				$shareTypes[] = IShare::TYPE_GROUP;
156
-			}
157
-			$shareTypes[] = IShare::TYPE_EMAIL;
158
-		}
159
-
160
-		// FIXME: DI
161
-		if (Server::get(IAppManager::class)->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
162
-			$shareTypes[] = IShare::TYPE_CIRCLE;
163
-		}
164
-
165
-		if ($this->shareManager->shareProviderExists(IShare::TYPE_SCIENCEMESH)) {
166
-			$shareTypes[] = IShare::TYPE_SCIENCEMESH;
167
-		}
168
-
169
-		if ($itemType === 'calendar') {
170
-			$shareTypes[] = IShare::TYPE_REMOTE;
171
-		}
172
-
173
-		if ($shareType !== null && is_array($shareType)) {
174
-			$shareTypes = array_intersect($shareTypes, $shareType);
175
-		} elseif (is_numeric($shareType)) {
176
-			$shareTypes = array_intersect($shareTypes, [(int)$shareType]);
177
-		}
178
-		sort($shareTypes);
179
-
180
-		$this->limit = $perPage;
181
-		$this->offset = $perPage * ($page - 1);
182
-
183
-		// In global scale mode we always search the lookup server
184
-		$this->result['lookupEnabled'] = Server::get(GlobalScaleIConfig::class)->isGlobalScaleEnabled();
185
-		// TODO: Reconsider using lookup server for non-global-scale federation
186
-
187
-		[$result, $hasMoreResults] = $this->collaboratorSearch->search($search, $shareTypes, $this->result['lookupEnabled'], $this->limit, $this->offset);
188
-
189
-		// extra treatment for 'exact' subarray, with a single merge expected keys might be lost
190
-		if (isset($result['exact'])) {
191
-			$result['exact'] = array_merge($this->result['exact'], $result['exact']);
192
-		}
193
-		$this->result = array_merge($this->result, $result);
194
-		$response = new DataResponse($this->result);
195
-
196
-		if ($hasMoreResults) {
197
-			$response->setHeaders(['Link' => $this->getPaginationLink($page, [
198
-				'search' => $search,
199
-				'itemType' => $itemType,
200
-				'shareType' => $shareTypes,
201
-				'perPage' => $perPage,
202
-			])]);
203
-		}
204
-
205
-		return $response;
206
-	}
207
-
208
-	/**
209
-	 * @param string $user
210
-	 * @param int $shareType
211
-	 *
212
-	 * @return Generator<array<string>>
213
-	 */
214
-	private function getAllShareesByType(string $user, int $shareType): Generator {
215
-		$offset = 0;
216
-		$pageSize = 50;
217
-
218
-		while (count($page = $this->shareManager->getSharesBy(
219
-			$user,
220
-			$shareType,
221
-			null,
222
-			false,
223
-			$pageSize,
224
-			$offset
225
-		))) {
226
-			foreach ($page as $share) {
227
-				yield [$share->getSharedWith(), $share->getSharedWithDisplayName() ?? $share->getSharedWith()];
228
-			}
229
-
230
-			$offset += $pageSize;
231
-		}
232
-	}
233
-
234
-	private function sortShareesByFrequency(array $sharees): array {
235
-		usort($sharees, function (array $s1, array $s2): int {
236
-			return $s2['count'] - $s1['count'];
237
-		});
238
-		return $sharees;
239
-	}
240
-
241
-	private $searchResultTypeMap = [
242
-		IShare::TYPE_USER => 'users',
243
-		IShare::TYPE_GROUP => 'groups',
244
-		IShare::TYPE_REMOTE => 'remotes',
245
-		IShare::TYPE_REMOTE_GROUP => 'remote_groups',
246
-		IShare::TYPE_EMAIL => 'emails',
247
-	];
248
-
249
-	private function getAllSharees(string $user, array $shareTypes): ISearchResult {
250
-		$result = [];
251
-		foreach ($shareTypes as $shareType) {
252
-			$sharees = $this->getAllShareesByType($user, $shareType);
253
-			$shareTypeResults = [];
254
-			foreach ($sharees as [$sharee, $displayname]) {
255
-				if (!isset($this->searchResultTypeMap[$shareType]) || trim($sharee) === '') {
256
-					continue;
257
-				}
258
-
259
-				if (!isset($shareTypeResults[$sharee])) {
260
-					$shareTypeResults[$sharee] = [
261
-						'count' => 1,
262
-						'label' => $displayname,
263
-						'value' => [
264
-							'shareType' => $shareType,
265
-							'shareWith' => $sharee,
266
-						],
267
-					];
268
-				} else {
269
-					$shareTypeResults[$sharee]['count']++;
270
-				}
271
-			}
272
-			$result = array_merge($result, array_values($shareTypeResults));
273
-		}
274
-
275
-		$top5 = array_slice(
276
-			$this->sortShareesByFrequency($result),
277
-			0,
278
-			5
279
-		);
280
-
281
-		$searchResult = new SearchResult();
282
-		foreach ($this->searchResultTypeMap as $int => $str) {
283
-			$searchResult->addResultSet(new SearchResultType($str), [], []);
284
-			foreach ($top5 as $x) {
285
-				if ($x['value']['shareType'] === $int) {
286
-					$searchResult->addResultSet(new SearchResultType($str), [], [$x]);
287
-				}
288
-			}
289
-		}
290
-		return $searchResult;
291
-	}
292
-
293
-	/**
294
-	 * Find recommended sharees
295
-	 *
296
-	 * @param string $itemType Limit to specific item types
297
-	 * @param int|list<int>|null $shareType Limit to specific share types
298
-	 * @return DataResponse<Http::STATUS_OK, Files_SharingShareesRecommendedResult, array{}>
299
-	 *
300
-	 * 200: Recommended sharees returned
301
-	 */
302
-	#[NoAdminRequired]
303
-	public function findRecommended(string $itemType, $shareType = null): DataResponse {
304
-		$shareTypes = [
305
-			IShare::TYPE_USER,
306
-		];
307
-
308
-		if ($itemType === 'file' || $itemType === 'folder') {
309
-			if ($this->shareManager->allowGroupSharing()) {
310
-				$shareTypes[] = IShare::TYPE_GROUP;
311
-			}
312
-
313
-			if ($this->isRemoteSharingAllowed($itemType)) {
314
-				$shareTypes[] = IShare::TYPE_REMOTE;
315
-			}
316
-
317
-			if ($this->isRemoteGroupSharingAllowed($itemType)) {
318
-				$shareTypes[] = IShare::TYPE_REMOTE_GROUP;
319
-			}
320
-
321
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
322
-				$shareTypes[] = IShare::TYPE_EMAIL;
323
-			}
324
-
325
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_ROOM)) {
326
-				$shareTypes[] = IShare::TYPE_ROOM;
327
-			}
328
-		} else {
329
-			$shareTypes[] = IShare::TYPE_GROUP;
330
-			$shareTypes[] = IShare::TYPE_EMAIL;
331
-		}
332
-
333
-		// FIXME: DI
334
-		if (Server::get(IAppManager::class)->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
335
-			$shareTypes[] = IShare::TYPE_CIRCLE;
336
-		}
337
-
338
-		if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
339
-			$shareTypes = array_intersect($shareTypes, $_GET['shareType']);
340
-			sort($shareTypes);
341
-		} elseif (is_numeric($shareType)) {
342
-			$shareTypes = array_intersect($shareTypes, [(int)$shareType]);
343
-			sort($shareTypes);
344
-		}
345
-
346
-		return new DataResponse(
347
-			$this->getAllSharees($this->userId, $shareTypes)->asArray()
348
-		);
349
-	}
350
-
351
-	/**
352
-	 * Method to get out the static call for better testing
353
-	 *
354
-	 * @param string $itemType
355
-	 * @return bool
356
-	 */
357
-	protected function isRemoteSharingAllowed(string $itemType): bool {
358
-		try {
359
-			// FIXME: static foo makes unit testing unnecessarily difficult
360
-			$backend = Share::getBackend($itemType);
361
-			return $backend->isShareTypeAllowed(IShare::TYPE_REMOTE);
362
-		} catch (\Exception $e) {
363
-			return false;
364
-		}
365
-	}
366
-
367
-	protected function isRemoteGroupSharingAllowed(string $itemType): bool {
368
-		try {
369
-			// FIXME: static foo makes unit testing unnecessarily difficult
370
-			$backend = Share::getBackend($itemType);
371
-			return $backend->isShareTypeAllowed(IShare::TYPE_REMOTE_GROUP);
372
-		} catch (\Exception $e) {
373
-			return false;
374
-		}
375
-	}
376
-
377
-
378
-	/**
379
-	 * Generates a bunch of pagination links for the current page
380
-	 *
381
-	 * @param int $page Current page
382
-	 * @param array $params Parameters for the URL
383
-	 * @return string
384
-	 */
385
-	protected function getPaginationLink(int $page, array $params): string {
386
-		if ($this->isV2()) {
387
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
388
-		} else {
389
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
390
-		}
391
-		$params['page'] = $page + 1;
392
-		return '<' . $url . http_build_query($params) . '>; rel="next"';
393
-	}
394
-
395
-	/**
396
-	 * @return bool
397
-	 */
398
-	protected function isV2(): bool {
399
-		return $this->request->getScriptName() === '/ocs/v2.php';
400
-	}
42
+    /** @var int */
43
+    protected $offset = 0;
44
+
45
+    /** @var int */
46
+    protected $limit = 10;
47
+
48
+    /** @var Files_SharingShareesSearchResult */
49
+    protected $result = [
50
+        'exact' => [
51
+            'users' => [],
52
+            'groups' => [],
53
+            'remotes' => [],
54
+            'remote_groups' => [],
55
+            'emails' => [],
56
+            'circles' => [],
57
+            'rooms' => [],
58
+        ],
59
+        'users' => [],
60
+        'groups' => [],
61
+        'remotes' => [],
62
+        'remote_groups' => [],
63
+        'emails' => [],
64
+        'lookup' => [],
65
+        'circles' => [],
66
+        'rooms' => [],
67
+        'lookupEnabled' => false,
68
+    ];
69
+
70
+    protected $reachedEndFor = [];
71
+
72
+    public function __construct(
73
+        string $appName,
74
+        IRequest $request,
75
+        protected ?string $userId,
76
+        protected IConfig $config,
77
+        protected IURLGenerator $urlGenerator,
78
+        protected IManager $shareManager,
79
+        protected ISearch $collaboratorSearch,
80
+    ) {
81
+        parent::__construct($appName, $request);
82
+    }
83
+
84
+    /**
85
+     * Search for sharees
86
+     *
87
+     * @param string $search Text to search for
88
+     * @param string|null $itemType Limit to specific item types
89
+     * @param int $page Page offset for searching
90
+     * @param int $perPage Limit amount of search results per page
91
+     * @param int|list<int>|null $shareType Limit to specific share types
92
+     * @param bool $lookup If a global lookup should be performed too
93
+     * @return DataResponse<Http::STATUS_OK, Files_SharingShareesSearchResult, array{Link?: string}>
94
+     * @throws OCSBadRequestException Invalid search parameters
95
+     *
96
+     * 200: Sharees search result returned
97
+     */
98
+    #[NoAdminRequired]
99
+    public function search(string $search = '', ?string $itemType = null, int $page = 1, int $perPage = 200, $shareType = null, bool $lookup = false): DataResponse {
100
+
101
+        // only search for string larger than a given threshold
102
+        $threshold = $this->config->getSystemValueInt('sharing.minSearchStringLength', 0);
103
+        if (strlen($search) < $threshold) {
104
+            return new DataResponse($this->result);
105
+        }
106
+
107
+        if ($this->shareManager->sharingDisabledForUser($this->userId)) {
108
+            return new DataResponse($this->result);
109
+        }
110
+
111
+        // never return more than the max. number of results configured in the config.php
112
+        $maxResults = $this->config->getSystemValueInt('sharing.maxAutocompleteResults', Constants::SHARING_MAX_AUTOCOMPLETE_RESULTS_DEFAULT);
113
+        if ($maxResults > 0) {
114
+            $perPage = min($perPage, $maxResults);
115
+        }
116
+        if ($perPage <= 0) {
117
+            throw new OCSBadRequestException('Invalid perPage argument');
118
+        }
119
+        if ($page <= 0) {
120
+            throw new OCSBadRequestException('Invalid page');
121
+        }
122
+
123
+        $shareTypes = [
124
+            IShare::TYPE_USER,
125
+        ];
126
+
127
+        if ($itemType === null) {
128
+            throw new OCSBadRequestException('Missing itemType');
129
+        } elseif ($itemType === 'file' || $itemType === 'folder') {
130
+            if ($this->shareManager->allowGroupSharing()) {
131
+                $shareTypes[] = IShare::TYPE_GROUP;
132
+            }
133
+
134
+            if ($this->isRemoteSharingAllowed($itemType)) {
135
+                $shareTypes[] = IShare::TYPE_REMOTE;
136
+            }
137
+
138
+            if ($this->isRemoteGroupSharingAllowed($itemType)) {
139
+                $shareTypes[] = IShare::TYPE_REMOTE_GROUP;
140
+            }
141
+
142
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
143
+                $shareTypes[] = IShare::TYPE_EMAIL;
144
+            }
145
+
146
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_ROOM)) {
147
+                $shareTypes[] = IShare::TYPE_ROOM;
148
+            }
149
+
150
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_SCIENCEMESH)) {
151
+                $shareTypes[] = IShare::TYPE_SCIENCEMESH;
152
+            }
153
+        } else {
154
+            if ($this->shareManager->allowGroupSharing()) {
155
+                $shareTypes[] = IShare::TYPE_GROUP;
156
+            }
157
+            $shareTypes[] = IShare::TYPE_EMAIL;
158
+        }
159
+
160
+        // FIXME: DI
161
+        if (Server::get(IAppManager::class)->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
162
+            $shareTypes[] = IShare::TYPE_CIRCLE;
163
+        }
164
+
165
+        if ($this->shareManager->shareProviderExists(IShare::TYPE_SCIENCEMESH)) {
166
+            $shareTypes[] = IShare::TYPE_SCIENCEMESH;
167
+        }
168
+
169
+        if ($itemType === 'calendar') {
170
+            $shareTypes[] = IShare::TYPE_REMOTE;
171
+        }
172
+
173
+        if ($shareType !== null && is_array($shareType)) {
174
+            $shareTypes = array_intersect($shareTypes, $shareType);
175
+        } elseif (is_numeric($shareType)) {
176
+            $shareTypes = array_intersect($shareTypes, [(int)$shareType]);
177
+        }
178
+        sort($shareTypes);
179
+
180
+        $this->limit = $perPage;
181
+        $this->offset = $perPage * ($page - 1);
182
+
183
+        // In global scale mode we always search the lookup server
184
+        $this->result['lookupEnabled'] = Server::get(GlobalScaleIConfig::class)->isGlobalScaleEnabled();
185
+        // TODO: Reconsider using lookup server for non-global-scale federation
186
+
187
+        [$result, $hasMoreResults] = $this->collaboratorSearch->search($search, $shareTypes, $this->result['lookupEnabled'], $this->limit, $this->offset);
188
+
189
+        // extra treatment for 'exact' subarray, with a single merge expected keys might be lost
190
+        if (isset($result['exact'])) {
191
+            $result['exact'] = array_merge($this->result['exact'], $result['exact']);
192
+        }
193
+        $this->result = array_merge($this->result, $result);
194
+        $response = new DataResponse($this->result);
195
+
196
+        if ($hasMoreResults) {
197
+            $response->setHeaders(['Link' => $this->getPaginationLink($page, [
198
+                'search' => $search,
199
+                'itemType' => $itemType,
200
+                'shareType' => $shareTypes,
201
+                'perPage' => $perPage,
202
+            ])]);
203
+        }
204
+
205
+        return $response;
206
+    }
207
+
208
+    /**
209
+     * @param string $user
210
+     * @param int $shareType
211
+     *
212
+     * @return Generator<array<string>>
213
+     */
214
+    private function getAllShareesByType(string $user, int $shareType): Generator {
215
+        $offset = 0;
216
+        $pageSize = 50;
217
+
218
+        while (count($page = $this->shareManager->getSharesBy(
219
+            $user,
220
+            $shareType,
221
+            null,
222
+            false,
223
+            $pageSize,
224
+            $offset
225
+        ))) {
226
+            foreach ($page as $share) {
227
+                yield [$share->getSharedWith(), $share->getSharedWithDisplayName() ?? $share->getSharedWith()];
228
+            }
229
+
230
+            $offset += $pageSize;
231
+        }
232
+    }
233
+
234
+    private function sortShareesByFrequency(array $sharees): array {
235
+        usort($sharees, function (array $s1, array $s2): int {
236
+            return $s2['count'] - $s1['count'];
237
+        });
238
+        return $sharees;
239
+    }
240
+
241
+    private $searchResultTypeMap = [
242
+        IShare::TYPE_USER => 'users',
243
+        IShare::TYPE_GROUP => 'groups',
244
+        IShare::TYPE_REMOTE => 'remotes',
245
+        IShare::TYPE_REMOTE_GROUP => 'remote_groups',
246
+        IShare::TYPE_EMAIL => 'emails',
247
+    ];
248
+
249
+    private function getAllSharees(string $user, array $shareTypes): ISearchResult {
250
+        $result = [];
251
+        foreach ($shareTypes as $shareType) {
252
+            $sharees = $this->getAllShareesByType($user, $shareType);
253
+            $shareTypeResults = [];
254
+            foreach ($sharees as [$sharee, $displayname]) {
255
+                if (!isset($this->searchResultTypeMap[$shareType]) || trim($sharee) === '') {
256
+                    continue;
257
+                }
258
+
259
+                if (!isset($shareTypeResults[$sharee])) {
260
+                    $shareTypeResults[$sharee] = [
261
+                        'count' => 1,
262
+                        'label' => $displayname,
263
+                        'value' => [
264
+                            'shareType' => $shareType,
265
+                            'shareWith' => $sharee,
266
+                        ],
267
+                    ];
268
+                } else {
269
+                    $shareTypeResults[$sharee]['count']++;
270
+                }
271
+            }
272
+            $result = array_merge($result, array_values($shareTypeResults));
273
+        }
274
+
275
+        $top5 = array_slice(
276
+            $this->sortShareesByFrequency($result),
277
+            0,
278
+            5
279
+        );
280
+
281
+        $searchResult = new SearchResult();
282
+        foreach ($this->searchResultTypeMap as $int => $str) {
283
+            $searchResult->addResultSet(new SearchResultType($str), [], []);
284
+            foreach ($top5 as $x) {
285
+                if ($x['value']['shareType'] === $int) {
286
+                    $searchResult->addResultSet(new SearchResultType($str), [], [$x]);
287
+                }
288
+            }
289
+        }
290
+        return $searchResult;
291
+    }
292
+
293
+    /**
294
+     * Find recommended sharees
295
+     *
296
+     * @param string $itemType Limit to specific item types
297
+     * @param int|list<int>|null $shareType Limit to specific share types
298
+     * @return DataResponse<Http::STATUS_OK, Files_SharingShareesRecommendedResult, array{}>
299
+     *
300
+     * 200: Recommended sharees returned
301
+     */
302
+    #[NoAdminRequired]
303
+    public function findRecommended(string $itemType, $shareType = null): DataResponse {
304
+        $shareTypes = [
305
+            IShare::TYPE_USER,
306
+        ];
307
+
308
+        if ($itemType === 'file' || $itemType === 'folder') {
309
+            if ($this->shareManager->allowGroupSharing()) {
310
+                $shareTypes[] = IShare::TYPE_GROUP;
311
+            }
312
+
313
+            if ($this->isRemoteSharingAllowed($itemType)) {
314
+                $shareTypes[] = IShare::TYPE_REMOTE;
315
+            }
316
+
317
+            if ($this->isRemoteGroupSharingAllowed($itemType)) {
318
+                $shareTypes[] = IShare::TYPE_REMOTE_GROUP;
319
+            }
320
+
321
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
322
+                $shareTypes[] = IShare::TYPE_EMAIL;
323
+            }
324
+
325
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_ROOM)) {
326
+                $shareTypes[] = IShare::TYPE_ROOM;
327
+            }
328
+        } else {
329
+            $shareTypes[] = IShare::TYPE_GROUP;
330
+            $shareTypes[] = IShare::TYPE_EMAIL;
331
+        }
332
+
333
+        // FIXME: DI
334
+        if (Server::get(IAppManager::class)->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
335
+            $shareTypes[] = IShare::TYPE_CIRCLE;
336
+        }
337
+
338
+        if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
339
+            $shareTypes = array_intersect($shareTypes, $_GET['shareType']);
340
+            sort($shareTypes);
341
+        } elseif (is_numeric($shareType)) {
342
+            $shareTypes = array_intersect($shareTypes, [(int)$shareType]);
343
+            sort($shareTypes);
344
+        }
345
+
346
+        return new DataResponse(
347
+            $this->getAllSharees($this->userId, $shareTypes)->asArray()
348
+        );
349
+    }
350
+
351
+    /**
352
+     * Method to get out the static call for better testing
353
+     *
354
+     * @param string $itemType
355
+     * @return bool
356
+     */
357
+    protected function isRemoteSharingAllowed(string $itemType): bool {
358
+        try {
359
+            // FIXME: static foo makes unit testing unnecessarily difficult
360
+            $backend = Share::getBackend($itemType);
361
+            return $backend->isShareTypeAllowed(IShare::TYPE_REMOTE);
362
+        } catch (\Exception $e) {
363
+            return false;
364
+        }
365
+    }
366
+
367
+    protected function isRemoteGroupSharingAllowed(string $itemType): bool {
368
+        try {
369
+            // FIXME: static foo makes unit testing unnecessarily difficult
370
+            $backend = Share::getBackend($itemType);
371
+            return $backend->isShareTypeAllowed(IShare::TYPE_REMOTE_GROUP);
372
+        } catch (\Exception $e) {
373
+            return false;
374
+        }
375
+    }
376
+
377
+
378
+    /**
379
+     * Generates a bunch of pagination links for the current page
380
+     *
381
+     * @param int $page Current page
382
+     * @param array $params Parameters for the URL
383
+     * @return string
384
+     */
385
+    protected function getPaginationLink(int $page, array $params): string {
386
+        if ($this->isV2()) {
387
+            $url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
388
+        } else {
389
+            $url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
390
+        }
391
+        $params['page'] = $page + 1;
392
+        return '<' . $url . http_build_query($params) . '>; rel="next"';
393
+    }
394
+
395
+    /**
396
+     * @return bool
397
+     */
398
+    protected function isV2(): bool {
399
+        return $this->request->getScriptName() === '/ocs/v2.php';
400
+    }
401 401
 }
Please login to merge, or discard this patch.
apps/dav/lib/Migration/Version1034Date20250605132605.php 1 patch
Indentation   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -16,87 +16,87 @@
 block discarded – undo
16 16
 use OCP\Migration\SimpleMigrationStep;
17 17
 
18 18
 class Version1034Date20250605132605 extends SimpleMigrationStep {
19
-	/**
20
-	 * @param IOutput $output
21
-	 * @param Closure(): ISchemaWrapper $schemaClosure
22
-	 * @param array $options
23
-	 * @return null|ISchemaWrapper
24
-	 */
25
-	public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
26
-		/** @var ISchemaWrapper $schema */
27
-		$schema = $schemaClosure();
19
+    /**
20
+     * @param IOutput $output
21
+     * @param Closure(): ISchemaWrapper $schemaClosure
22
+     * @param array $options
23
+     * @return null|ISchemaWrapper
24
+     */
25
+    public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
26
+        /** @var ISchemaWrapper $schema */
27
+        $schema = $schemaClosure();
28 28
 
29
-		$davSharesTable = $schema->getTable('dav_shares');
30
-		if (!$davSharesTable->hasColumn('token')) {
31
-			$davSharesTable->addColumn('token', Types::STRING, [
32
-				'notnull' => false,
33
-				'default' => null,
34
-				'length' => 255,
35
-			]);
36
-		}
29
+        $davSharesTable = $schema->getTable('dav_shares');
30
+        if (!$davSharesTable->hasColumn('token')) {
31
+            $davSharesTable->addColumn('token', Types::STRING, [
32
+                'notnull' => false,
33
+                'default' => null,
34
+                'length' => 255,
35
+            ]);
36
+        }
37 37
 
38
-		if (!$schema->hasTable('calendars_federated')) {
39
-			$federatedCalendarsTable = $schema->createTable('calendars_federated');
40
-			$federatedCalendarsTable->addColumn('id', Types::BIGINT, [
41
-				'autoincrement' => true,
42
-				'notnull' => true,
43
-				'unsigned' => true,
44
-			]);
45
-			$federatedCalendarsTable->addColumn('display_name', Types::STRING, [
46
-				'notnull' => true,
47
-				'length' => 255,
48
-			]);
49
-			$federatedCalendarsTable->addColumn('color', Types::STRING, [
50
-				'notnull' => false,
51
-				'length' => 7,
52
-				'default' => null,
53
-			]);
54
-			$federatedCalendarsTable->addColumn('uri', Types::STRING, [
55
-				'notnull' => true,
56
-				'length' => 255,
57
-			]);
58
-			$federatedCalendarsTable->addColumn('principaluri', Types::STRING, [
59
-				'notnull' => true,
60
-				'length' => 255,
61
-			]);
62
-			$federatedCalendarsTable->addColumn('remote_Url', Types::STRING, [
63
-				'notnull' => true,
64
-				'length' => 255,
65
-			]);
66
-			$federatedCalendarsTable->addColumn('token', Types::STRING, [
67
-				'notnull' => true,
68
-				'length' => 255,
69
-			]);
70
-			$federatedCalendarsTable->addColumn('sync_token', Types::INTEGER, [
71
-				'notnull' => true,
72
-				'unsigned' => true,
73
-				'default' => 0,
74
-			]);
75
-			$federatedCalendarsTable->addColumn('last_sync', Types::BIGINT, [
76
-				'notnull' => false,
77
-				'unsigned' => true,
78
-				'default' => null,
79
-			]);
80
-			$federatedCalendarsTable->addColumn('shared_by', Types::STRING, [
81
-				'notnull' => true,
82
-				'length' => 255,
83
-			]);
84
-			$federatedCalendarsTable->addColumn('shared_by_display_name', Types::STRING, [
85
-				'notnull' => true,
86
-				'length' => 255,
87
-			]);
88
-			$federatedCalendarsTable->addColumn('components', Types::STRING, [
89
-				'notnull' => true,
90
-				'length' => 255,
91
-			]);
92
-			$federatedCalendarsTable->addColumn('permissions', Types::INTEGER, [
93
-				'notnull' => true,
94
-			]);
95
-			$federatedCalendarsTable->setPrimaryKey(['id']);
96
-			$federatedCalendarsTable->addIndex(['principaluri', 'uri'], 'fedcals_uris_index');
97
-			$federatedCalendarsTable->addIndex(['last_sync'], 'fedcals_last_sync_index');
98
-		}
38
+        if (!$schema->hasTable('calendars_federated')) {
39
+            $federatedCalendarsTable = $schema->createTable('calendars_federated');
40
+            $federatedCalendarsTable->addColumn('id', Types::BIGINT, [
41
+                'autoincrement' => true,
42
+                'notnull' => true,
43
+                'unsigned' => true,
44
+            ]);
45
+            $federatedCalendarsTable->addColumn('display_name', Types::STRING, [
46
+                'notnull' => true,
47
+                'length' => 255,
48
+            ]);
49
+            $federatedCalendarsTable->addColumn('color', Types::STRING, [
50
+                'notnull' => false,
51
+                'length' => 7,
52
+                'default' => null,
53
+            ]);
54
+            $federatedCalendarsTable->addColumn('uri', Types::STRING, [
55
+                'notnull' => true,
56
+                'length' => 255,
57
+            ]);
58
+            $federatedCalendarsTable->addColumn('principaluri', Types::STRING, [
59
+                'notnull' => true,
60
+                'length' => 255,
61
+            ]);
62
+            $federatedCalendarsTable->addColumn('remote_Url', Types::STRING, [
63
+                'notnull' => true,
64
+                'length' => 255,
65
+            ]);
66
+            $federatedCalendarsTable->addColumn('token', Types::STRING, [
67
+                'notnull' => true,
68
+                'length' => 255,
69
+            ]);
70
+            $federatedCalendarsTable->addColumn('sync_token', Types::INTEGER, [
71
+                'notnull' => true,
72
+                'unsigned' => true,
73
+                'default' => 0,
74
+            ]);
75
+            $federatedCalendarsTable->addColumn('last_sync', Types::BIGINT, [
76
+                'notnull' => false,
77
+                'unsigned' => true,
78
+                'default' => null,
79
+            ]);
80
+            $federatedCalendarsTable->addColumn('shared_by', Types::STRING, [
81
+                'notnull' => true,
82
+                'length' => 255,
83
+            ]);
84
+            $federatedCalendarsTable->addColumn('shared_by_display_name', Types::STRING, [
85
+                'notnull' => true,
86
+                'length' => 255,
87
+            ]);
88
+            $federatedCalendarsTable->addColumn('components', Types::STRING, [
89
+                'notnull' => true,
90
+                'length' => 255,
91
+            ]);
92
+            $federatedCalendarsTable->addColumn('permissions', Types::INTEGER, [
93
+                'notnull' => true,
94
+            ]);
95
+            $federatedCalendarsTable->setPrimaryKey(['id']);
96
+            $federatedCalendarsTable->addIndex(['principaluri', 'uri'], 'fedcals_uris_index');
97
+            $federatedCalendarsTable->addIndex(['last_sync'], 'fedcals_last_sync_index');
98
+        }
99 99
 
100
-		return $schema;
101
-	}
100
+        return $schema;
101
+    }
102 102
 }
Please login to merge, or discard this patch.
apps/dav/lib/Command/CreateCalendar.php 1 patch
Indentation   +54 added lines, -54 removed lines patch added patch discarded remove patch
@@ -30,60 +30,60 @@
 block discarded – undo
30 30
 use Symfony\Component\Console\Output\OutputInterface;
31 31
 
32 32
 class CreateCalendar extends Command {
33
-	public function __construct(
34
-		protected IUserManager $userManager,
35
-		private IGroupManager $groupManager,
36
-		protected IDBConnection $dbConnection,
37
-	) {
38
-		parent::__construct();
39
-	}
33
+    public function __construct(
34
+        protected IUserManager $userManager,
35
+        private IGroupManager $groupManager,
36
+        protected IDBConnection $dbConnection,
37
+    ) {
38
+        parent::__construct();
39
+    }
40 40
 
41
-	protected function configure(): void {
42
-		$this
43
-			->setName('dav:create-calendar')
44
-			->setDescription('Create a dav calendar')
45
-			->addArgument('user',
46
-				InputArgument::REQUIRED,
47
-				'User for whom the calendar will be created')
48
-			->addArgument('name',
49
-				InputArgument::REQUIRED,
50
-				'Name of the calendar');
51
-	}
41
+    protected function configure(): void {
42
+        $this
43
+            ->setName('dav:create-calendar')
44
+            ->setDescription('Create a dav calendar')
45
+            ->addArgument('user',
46
+                InputArgument::REQUIRED,
47
+                'User for whom the calendar will be created')
48
+            ->addArgument('name',
49
+                InputArgument::REQUIRED,
50
+                'Name of the calendar');
51
+    }
52 52
 
53
-	protected function execute(InputInterface $input, OutputInterface $output): int {
54
-		$user = $input->getArgument('user');
55
-		if (!$this->userManager->userExists($user)) {
56
-			throw new \InvalidArgumentException("User <$user> in unknown.");
57
-		}
58
-		$principalBackend = new Principal(
59
-			$this->userManager,
60
-			$this->groupManager,
61
-			Server::get(IAccountManager::class),
62
-			Server::get(\OCP\Share\IManager::class),
63
-			Server::get(IUserSession::class),
64
-			Server::get(IAppManager::class),
65
-			Server::get(ProxyMapper::class),
66
-			Server::get(KnownUserService::class),
67
-			Server::get(IConfig::class),
68
-			\OC::$server->getL10NFactory(),
69
-		);
70
-		$random = Server::get(ISecureRandom::class);
71
-		$logger = Server::get(LoggerInterface::class);
72
-		$dispatcher = Server::get(IEventDispatcher::class);
73
-		$config = Server::get(IConfig::class);
74
-		$name = $input->getArgument('name');
75
-		$caldav = new CalDavBackend(
76
-			$this->dbConnection,
77
-			$principalBackend,
78
-			$this->userManager,
79
-			$random,
80
-			$logger,
81
-			$dispatcher,
82
-			$config,
83
-			Server::get(Backend::class),
84
-			Server::get(FederatedCalendarMapper::class),
85
-		);
86
-		$caldav->createCalendar("principals/users/$user", $name, []);
87
-		return self::SUCCESS;
88
-	}
53
+    protected function execute(InputInterface $input, OutputInterface $output): int {
54
+        $user = $input->getArgument('user');
55
+        if (!$this->userManager->userExists($user)) {
56
+            throw new \InvalidArgumentException("User <$user> in unknown.");
57
+        }
58
+        $principalBackend = new Principal(
59
+            $this->userManager,
60
+            $this->groupManager,
61
+            Server::get(IAccountManager::class),
62
+            Server::get(\OCP\Share\IManager::class),
63
+            Server::get(IUserSession::class),
64
+            Server::get(IAppManager::class),
65
+            Server::get(ProxyMapper::class),
66
+            Server::get(KnownUserService::class),
67
+            Server::get(IConfig::class),
68
+            \OC::$server->getL10NFactory(),
69
+        );
70
+        $random = Server::get(ISecureRandom::class);
71
+        $logger = Server::get(LoggerInterface::class);
72
+        $dispatcher = Server::get(IEventDispatcher::class);
73
+        $config = Server::get(IConfig::class);
74
+        $name = $input->getArgument('name');
75
+        $caldav = new CalDavBackend(
76
+            $this->dbConnection,
77
+            $principalBackend,
78
+            $this->userManager,
79
+            $random,
80
+            $logger,
81
+            $dispatcher,
82
+            $config,
83
+            Server::get(Backend::class),
84
+            Server::get(FederatedCalendarMapper::class),
85
+        );
86
+        $caldav->createCalendar("principals/users/$user", $name, []);
87
+        return self::SUCCESS;
88
+    }
89 89
 }
Please login to merge, or discard this patch.
apps/dav/lib/Service/ASyncService.php 2 patches
Indentation   +134 added lines, -134 removed lines patch added patch discarded remove patch
@@ -20,24 +20,24 @@  discard block
 block discarded – undo
20 20
  * Abstract sync service to sync CalDAV and CardDAV data from federated instances.
21 21
  */
22 22
 abstract class ASyncService {
23
-	private ?IClient $client = null;
23
+    private ?IClient $client = null;
24 24
 
25
-	public function __construct(
26
-		protected IClientService $clientService,
27
-		protected IConfig $config,
28
-	) {
29
-	}
25
+    public function __construct(
26
+        protected IClientService $clientService,
27
+        protected IConfig $config,
28
+    ) {
29
+    }
30 30
 
31
-	private function getClient(): IClient {
32
-		if ($this->client === null) {
33
-			$this->client = $this->clientService->newClient();
34
-		}
31
+    private function getClient(): IClient {
32
+        if ($this->client === null) {
33
+            $this->client = $this->clientService->newClient();
34
+        }
35 35
 
36
-		return $this->client;
37
-	}
36
+        return $this->client;
37
+    }
38 38
 
39
-	protected function prepareUri(string $host, string $path): string {
40
-		/*
39
+    protected function prepareUri(string $host, string $path): string {
40
+        /*
41 41
 		 * The trailing slash is important for merging the uris together.
42 42
 		 *
43 43
 		 * $host is stored in oc_trusted_servers.url and usually without a trailing slash.
@@ -58,121 +58,121 @@  discard block
 block discarded – undo
58 58
 		 * The response from the remote usually contains the webroot already and must be normalized to:
59 59
 		 * https://server.internal/cloud/remote.php/dav/addressbooks/system/system/system/Database:alice.vcf
60 60
 		 */
61
-		$host = rtrim($host, '/') . '/';
62
-
63
-		$uri = \GuzzleHttp\Psr7\UriResolver::resolve(
64
-			\GuzzleHttp\Psr7\Utils::uriFor($host),
65
-			\GuzzleHttp\Psr7\Utils::uriFor($path)
66
-		);
67
-
68
-		return (string)$uri;
69
-	}
70
-
71
-	/**
72
-	 * @return array{response: array<string, array<array-key, mixed>>, token: ?string, truncated: bool}
73
-	 */
74
-	protected function requestSyncReport(
75
-		string $absoluteUrl,
76
-		string $userName,
77
-		string $sharedSecret,
78
-		?string $syncToken,
79
-	): array {
80
-		$client = $this->getClient();
81
-
82
-		$options = [
83
-			'auth' => [$userName, $sharedSecret],
84
-			'body' => $this->buildSyncCollectionRequestBody($syncToken),
85
-			'headers' => ['Content-Type' => 'application/xml'],
86
-			'timeout' => $this->config->getSystemValueInt(
87
-				'carddav_sync_request_timeout',
88
-				IClient::DEFAULT_REQUEST_TIMEOUT,
89
-			),
90
-			'verify' => !$this->config->getSystemValue(
91
-				'sharing.federation.allowSelfSignedCertificates',
92
-				false,
93
-			),
94
-		];
95
-
96
-		$response = $client->request(
97
-			'REPORT',
98
-			$absoluteUrl,
99
-			$options,
100
-		);
101
-
102
-		$body = $response->getBody();
103
-		assert(is_string($body));
104
-
105
-		return $this->parseMultiStatus($body, $absoluteUrl);
106
-	}
107
-
108
-	protected function download(
109
-		string $absoluteUrl,
110
-		string $userName,
111
-		string $sharedSecret,
112
-	): string {
113
-		$client = $this->getClient();
114
-
115
-		$options = [
116
-			'auth' => [$userName, $sharedSecret],
117
-			'verify' => !$this->config->getSystemValue(
118
-				'sharing.federation.allowSelfSignedCertificates',
119
-				false,
120
-			),
121
-		];
122
-
123
-		$response = $client->get(
124
-			$absoluteUrl,
125
-			$options,
126
-		);
127
-
128
-		return (string)$response->getBody();
129
-	}
130
-
131
-	private function buildSyncCollectionRequestBody(?string $syncToken): string {
132
-		$dom = new \DOMDocument('1.0', 'UTF-8');
133
-		$dom->formatOutput = true;
134
-		$root = $dom->createElementNS('DAV:', 'd:sync-collection');
135
-		$sync = $dom->createElement('d:sync-token', $syncToken ?? '');
136
-		$prop = $dom->createElement('d:prop');
137
-		$cont = $dom->createElement('d:getcontenttype');
138
-		$etag = $dom->createElement('d:getetag');
139
-
140
-		$prop->appendChild($cont);
141
-		$prop->appendChild($etag);
142
-		$root->appendChild($sync);
143
-		$root->appendChild($prop);
144
-		$dom->appendChild($root);
145
-		return $dom->saveXML();
146
-	}
147
-
148
-	/**
149
-	 * @return array{response: array<string, array<array-key, mixed>>, token: ?string, truncated: bool}
150
-	 * @throws ParseException
151
-	 */
152
-	private function parseMultiStatus(string $body, string $resourceUrl): array {
153
-		/** @var MultiStatus $multiStatus */
154
-		$multiStatus = (new SabreXmlService())->expect('{DAV:}multistatus', $body);
155
-
156
-		$result = [];
157
-		$truncated = false;
158
-
159
-		foreach ($multiStatus->getResponses() as $response) {
160
-			$href = $response->getHref();
161
-			if ($response->getHttpStatus() === '507' && $this->isResponseForRequestUri($href, $resourceUrl)) {
162
-				$truncated = true;
163
-			} else {
164
-				$result[$response->getHref()] = $response->getResponseProperties();
165
-			}
166
-		}
167
-
168
-		return ['response' => $result, 'token' => $multiStatus->getSyncToken(), 'truncated' => $truncated];
169
-	}
170
-
171
-	/**
172
-	 * Determines whether the provided response URI corresponds to the given request URI.
173
-	 */
174
-	private function isResponseForRequestUri(string $responseUri, string $requestUri): bool {
175
-		/*
61
+        $host = rtrim($host, '/') . '/';
62
+
63
+        $uri = \GuzzleHttp\Psr7\UriResolver::resolve(
64
+            \GuzzleHttp\Psr7\Utils::uriFor($host),
65
+            \GuzzleHttp\Psr7\Utils::uriFor($path)
66
+        );
67
+
68
+        return (string)$uri;
69
+    }
70
+
71
+    /**
72
+     * @return array{response: array<string, array<array-key, mixed>>, token: ?string, truncated: bool}
73
+     */
74
+    protected function requestSyncReport(
75
+        string $absoluteUrl,
76
+        string $userName,
77
+        string $sharedSecret,
78
+        ?string $syncToken,
79
+    ): array {
80
+        $client = $this->getClient();
81
+
82
+        $options = [
83
+            'auth' => [$userName, $sharedSecret],
84
+            'body' => $this->buildSyncCollectionRequestBody($syncToken),
85
+            'headers' => ['Content-Type' => 'application/xml'],
86
+            'timeout' => $this->config->getSystemValueInt(
87
+                'carddav_sync_request_timeout',
88
+                IClient::DEFAULT_REQUEST_TIMEOUT,
89
+            ),
90
+            'verify' => !$this->config->getSystemValue(
91
+                'sharing.federation.allowSelfSignedCertificates',
92
+                false,
93
+            ),
94
+        ];
95
+
96
+        $response = $client->request(
97
+            'REPORT',
98
+            $absoluteUrl,
99
+            $options,
100
+        );
101
+
102
+        $body = $response->getBody();
103
+        assert(is_string($body));
104
+
105
+        return $this->parseMultiStatus($body, $absoluteUrl);
106
+    }
107
+
108
+    protected function download(
109
+        string $absoluteUrl,
110
+        string $userName,
111
+        string $sharedSecret,
112
+    ): string {
113
+        $client = $this->getClient();
114
+
115
+        $options = [
116
+            'auth' => [$userName, $sharedSecret],
117
+            'verify' => !$this->config->getSystemValue(
118
+                'sharing.federation.allowSelfSignedCertificates',
119
+                false,
120
+            ),
121
+        ];
122
+
123
+        $response = $client->get(
124
+            $absoluteUrl,
125
+            $options,
126
+        );
127
+
128
+        return (string)$response->getBody();
129
+    }
130
+
131
+    private function buildSyncCollectionRequestBody(?string $syncToken): string {
132
+        $dom = new \DOMDocument('1.0', 'UTF-8');
133
+        $dom->formatOutput = true;
134
+        $root = $dom->createElementNS('DAV:', 'd:sync-collection');
135
+        $sync = $dom->createElement('d:sync-token', $syncToken ?? '');
136
+        $prop = $dom->createElement('d:prop');
137
+        $cont = $dom->createElement('d:getcontenttype');
138
+        $etag = $dom->createElement('d:getetag');
139
+
140
+        $prop->appendChild($cont);
141
+        $prop->appendChild($etag);
142
+        $root->appendChild($sync);
143
+        $root->appendChild($prop);
144
+        $dom->appendChild($root);
145
+        return $dom->saveXML();
146
+    }
147
+
148
+    /**
149
+     * @return array{response: array<string, array<array-key, mixed>>, token: ?string, truncated: bool}
150
+     * @throws ParseException
151
+     */
152
+    private function parseMultiStatus(string $body, string $resourceUrl): array {
153
+        /** @var MultiStatus $multiStatus */
154
+        $multiStatus = (new SabreXmlService())->expect('{DAV:}multistatus', $body);
155
+
156
+        $result = [];
157
+        $truncated = false;
158
+
159
+        foreach ($multiStatus->getResponses() as $response) {
160
+            $href = $response->getHref();
161
+            if ($response->getHttpStatus() === '507' && $this->isResponseForRequestUri($href, $resourceUrl)) {
162
+                $truncated = true;
163
+            } else {
164
+                $result[$response->getHref()] = $response->getResponseProperties();
165
+            }
166
+        }
167
+
168
+        return ['response' => $result, 'token' => $multiStatus->getSyncToken(), 'truncated' => $truncated];
169
+    }
170
+
171
+    /**
172
+     * Determines whether the provided response URI corresponds to the given request URI.
173
+     */
174
+    private function isResponseForRequestUri(string $responseUri, string $requestUri): bool {
175
+        /*
176 176
 		 * Example response uri:
177 177
 		 *
178 178
 		 * /remote.php/dav/addressbooks/system/system/system/
@@ -186,9 +186,9 @@  discard block
 block discarded – undo
186 186
 		 * https://github.com/nextcloud/3rdparty/blob/e0a509739b13820f0a62ff9cad5d0fede00e76ee/sabre/dav/lib/DAV/Sync/Plugin.php#L172-L174
187 187
 		 * https://github.com/nextcloud/server/blob/b40acb34a39592070d8455eb91c5364c07928c50/apps/federation/lib/SyncFederationAddressBooks.php#L41
188 188
 		 */
189
-		return str_ends_with(
190
-			rtrim($requestUri, '/'),
191
-			rtrim($responseUri, '/'),
192
-		);
193
-	}
189
+        return str_ends_with(
190
+            rtrim($requestUri, '/'),
191
+            rtrim($responseUri, '/'),
192
+        );
193
+    }
194 194
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -58,14 +58,14 @@  discard block
 block discarded – undo
58 58
 		 * The response from the remote usually contains the webroot already and must be normalized to:
59 59
 		 * https://server.internal/cloud/remote.php/dav/addressbooks/system/system/system/Database:alice.vcf
60 60
 		 */
61
-		$host = rtrim($host, '/') . '/';
61
+		$host = rtrim($host, '/').'/';
62 62
 
63 63
 		$uri = \GuzzleHttp\Psr7\UriResolver::resolve(
64 64
 			\GuzzleHttp\Psr7\Utils::uriFor($host),
65 65
 			\GuzzleHttp\Psr7\Utils::uriFor($path)
66 66
 		);
67 67
 
68
-		return (string)$uri;
68
+		return (string) $uri;
69 69
 	}
70 70
 
71 71
 	/**
@@ -125,7 +125,7 @@  discard block
 block discarded – undo
125 125
 			$options,
126 126
 		);
127 127
 
128
-		return (string)$response->getBody();
128
+		return (string) $response->getBody();
129 129
 	}
130 130
 
131 131
 	private function buildSyncCollectionRequestBody(?string $syncToken): string {
Please login to merge, or discard this patch.
apps/dav/lib/BackgroundJob/FederatedCalendarPeriodicSyncJob.php 2 patches
Indentation   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -18,45 +18,45 @@
 block discarded – undo
18 18
 use Psr\Log\LoggerInterface;
19 19
 
20 20
 class FederatedCalendarPeriodicSyncJob extends TimedJob {
21
-	private const DOWNLOAD_LIMIT = 500;
22
-
23
-	public function __construct(
24
-		ITimeFactory $time,
25
-		private readonly FederatedCalendarSyncService $syncService,
26
-		private readonly FederatedCalendarMapper $federatedCalendarMapper,
27
-		private readonly CalendarFederationConfig $calendarFederationConfig,
28
-		private readonly LoggerInterface $logger,
29
-	) {
30
-		parent::__construct($time);
31
-
32
-		$this->setTimeSensitivity(self::TIME_SENSITIVE);
33
-		$this->setAllowParallelRuns(false);
34
-		$this->setInterval(3600);
35
-	}
36
-
37
-	protected function run($argument): void {
38
-		if (!$this->calendarFederationConfig->isFederationEnabled()) {
39
-			return;
40
-		}
41
-
42
-		$downloadedEvents = 0;
43
-		$oneHourAgo = $this->time->getTime() - 3600;
44
-		$calendars = $this->federatedCalendarMapper->findUnsyncedSinceBefore($oneHourAgo);
45
-		foreach ($calendars as $calendar) {
46
-			try {
47
-				$downloadedEvents += $this->syncService->syncOne($calendar);
48
-			} catch (ClientExceptionInterface $e) {
49
-				$name = $calendar->getUri();
50
-				$this->logger->error("Failed to sync federated calendar $name: " . $e->getMessage(), [
51
-					'exception' => $e,
52
-					'calendar' => $calendar->toCalendarInfo(),
53
-				]);
54
-			}
55
-
56
-			// Prevent stalling the background job queue for too long
57
-			if ($downloadedEvents >= self::DOWNLOAD_LIMIT) {
58
-				break;
59
-			}
60
-		}
61
-	}
21
+    private const DOWNLOAD_LIMIT = 500;
22
+
23
+    public function __construct(
24
+        ITimeFactory $time,
25
+        private readonly FederatedCalendarSyncService $syncService,
26
+        private readonly FederatedCalendarMapper $federatedCalendarMapper,
27
+        private readonly CalendarFederationConfig $calendarFederationConfig,
28
+        private readonly LoggerInterface $logger,
29
+    ) {
30
+        parent::__construct($time);
31
+
32
+        $this->setTimeSensitivity(self::TIME_SENSITIVE);
33
+        $this->setAllowParallelRuns(false);
34
+        $this->setInterval(3600);
35
+    }
36
+
37
+    protected function run($argument): void {
38
+        if (!$this->calendarFederationConfig->isFederationEnabled()) {
39
+            return;
40
+        }
41
+
42
+        $downloadedEvents = 0;
43
+        $oneHourAgo = $this->time->getTime() - 3600;
44
+        $calendars = $this->federatedCalendarMapper->findUnsyncedSinceBefore($oneHourAgo);
45
+        foreach ($calendars as $calendar) {
46
+            try {
47
+                $downloadedEvents += $this->syncService->syncOne($calendar);
48
+            } catch (ClientExceptionInterface $e) {
49
+                $name = $calendar->getUri();
50
+                $this->logger->error("Failed to sync federated calendar $name: " . $e->getMessage(), [
51
+                    'exception' => $e,
52
+                    'calendar' => $calendar->toCalendarInfo(),
53
+                ]);
54
+            }
55
+
56
+            // Prevent stalling the background job queue for too long
57
+            if ($downloadedEvents >= self::DOWNLOAD_LIMIT) {
58
+                break;
59
+            }
60
+        }
61
+    }
62 62
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -47,7 +47,7 @@
 block discarded – undo
47 47
 				$downloadedEvents += $this->syncService->syncOne($calendar);
48 48
 			} catch (ClientExceptionInterface $e) {
49 49
 				$name = $calendar->getUri();
50
-				$this->logger->error("Failed to sync federated calendar $name: " . $e->getMessage(), [
50
+				$this->logger->error("Failed to sync federated calendar $name: ".$e->getMessage(), [
51 51
 					'exception' => $e,
52 52
 					'calendar' => $calendar->toCalendarInfo(),
53 53
 				]);
Please login to merge, or discard this patch.
apps/dav/lib/BackgroundJob/FederatedCalendarSyncJob.php 2 patches
Indentation   +38 added lines, -38 removed lines patch added patch discarded remove patch
@@ -19,49 +19,49 @@
 block discarded – undo
19 19
 use Psr\Log\LoggerInterface;
20 20
 
21 21
 class FederatedCalendarSyncJob extends QueuedJob {
22
-	public const ARGUMENT_ID = 'id';
22
+    public const ARGUMENT_ID = 'id';
23 23
 
24
-	public function __construct(
25
-		ITimeFactory $time,
26
-		private readonly FederatedCalendarSyncService $syncService,
27
-		private readonly FederatedCalendarMapper $federatedCalendarMapper,
28
-		private readonly CalendarFederationConfig $calendarFederationConfig,
29
-		private readonly LoggerInterface $logger,
30
-	) {
31
-		parent::__construct($time);
24
+    public function __construct(
25
+        ITimeFactory $time,
26
+        private readonly FederatedCalendarSyncService $syncService,
27
+        private readonly FederatedCalendarMapper $federatedCalendarMapper,
28
+        private readonly CalendarFederationConfig $calendarFederationConfig,
29
+        private readonly LoggerInterface $logger,
30
+    ) {
31
+        parent::__construct($time);
32 32
 
33
-		$this->setAllowParallelRuns(false);
34
-	}
33
+        $this->setAllowParallelRuns(false);
34
+    }
35 35
 
36
-	protected function run($argument): void {
37
-		if (!$this->calendarFederationConfig->isFederationEnabled()) {
38
-			return;
39
-		}
36
+    protected function run($argument): void {
37
+        if (!$this->calendarFederationConfig->isFederationEnabled()) {
38
+            return;
39
+        }
40 40
 
41
-		$id = $argument[self::ARGUMENT_ID] ?? null;
42
-		if (!is_numeric($id)) {
43
-			return;
44
-		}
41
+        $id = $argument[self::ARGUMENT_ID] ?? null;
42
+        if (!is_numeric($id)) {
43
+            return;
44
+        }
45 45
 
46
-		$id = (int)$id;
47
-		try {
48
-			$calendar = $this->federatedCalendarMapper->find($id);
49
-		} catch (DoesNotExistException $e) {
50
-			return;
51
-		}
46
+        $id = (int)$id;
47
+        try {
48
+            $calendar = $this->federatedCalendarMapper->find($id);
49
+        } catch (DoesNotExistException $e) {
50
+            return;
51
+        }
52 52
 
53
-		try {
54
-			$this->syncService->syncOne($calendar);
55
-		} catch (ClientExceptionInterface $e) {
56
-			$name = $calendar->getUri();
57
-			$this->logger->error("Failed to sync federated calendar $name: " . $e->getMessage(), [
58
-				'exception' => $e,
59
-				'calendar' => $calendar->toCalendarInfo(),
60
-			]);
53
+        try {
54
+            $this->syncService->syncOne($calendar);
55
+        } catch (ClientExceptionInterface $e) {
56
+            $name = $calendar->getUri();
57
+            $this->logger->error("Failed to sync federated calendar $name: " . $e->getMessage(), [
58
+                'exception' => $e,
59
+                'calendar' => $calendar->toCalendarInfo(),
60
+            ]);
61 61
 
62
-			// Let the periodic background job pick up the calendar at a later point
63
-			$calendar->setLastSync(1);
64
-			$this->federatedCalendarMapper->update($calendar);
65
-		}
66
-	}
62
+            // Let the periodic background job pick up the calendar at a later point
63
+            $calendar->setLastSync(1);
64
+            $this->federatedCalendarMapper->update($calendar);
65
+        }
66
+    }
67 67
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -43,7 +43,7 @@  discard block
 block discarded – undo
43 43
 			return;
44 44
 		}
45 45
 
46
-		$id = (int)$id;
46
+		$id = (int) $id;
47 47
 		try {
48 48
 			$calendar = $this->federatedCalendarMapper->find($id);
49 49
 		} catch (DoesNotExistException $e) {
@@ -54,7 +54,7 @@  discard block
 block discarded – undo
54 54
 			$this->syncService->syncOne($calendar);
55 55
 		} catch (ClientExceptionInterface $e) {
56 56
 			$name = $calendar->getUri();
57
-			$this->logger->error("Failed to sync federated calendar $name: " . $e->getMessage(), [
57
+			$this->logger->error("Failed to sync federated calendar $name: ".$e->getMessage(), [
58 58
 				'exception' => $e,
59 59
 				'calendar' => $calendar->toCalendarInfo(),
60 60
 			]);
Please login to merge, or discard this patch.
apps/dav/lib/AppInfo/Application.php 1 patch
Indentation   +187 added lines, -187 removed lines patch added patch discarded remove patch
@@ -108,196 +108,196 @@
 block discarded – undo
108 108
 use function is_null;
109 109
 
110 110
 class Application extends App implements IBootstrap {
111
-	public const APP_ID = 'dav';
112
-
113
-	public function __construct() {
114
-		parent::__construct(self::APP_ID);
115
-	}
116
-
117
-	public function register(IRegistrationContext $context): void {
118
-		$context->registerServiceAlias('CardDAVSyncService', SyncService::class);
119
-		$context->registerService(AppCalendarPlugin::class, function (ContainerInterface $c) {
120
-			return new AppCalendarPlugin(
121
-				$c->get(ICalendarManager::class),
122
-				$c->get(LoggerInterface::class)
123
-			);
124
-		});
125
-
126
-		/*
111
+    public const APP_ID = 'dav';
112
+
113
+    public function __construct() {
114
+        parent::__construct(self::APP_ID);
115
+    }
116
+
117
+    public function register(IRegistrationContext $context): void {
118
+        $context->registerServiceAlias('CardDAVSyncService', SyncService::class);
119
+        $context->registerService(AppCalendarPlugin::class, function (ContainerInterface $c) {
120
+            return new AppCalendarPlugin(
121
+                $c->get(ICalendarManager::class),
122
+                $c->get(LoggerInterface::class)
123
+            );
124
+        });
125
+
126
+        /*
127 127
 		 * Register capabilities
128 128
 		 */
129
-		$context->registerCapability(Capabilities::class);
129
+        $context->registerCapability(Capabilities::class);
130 130
 
131
-		/*
131
+        /*
132 132
 		 * Register Search Providers
133 133
 		 */
134
-		$context->registerSearchProvider(ContactsSearchProvider::class);
135
-		$context->registerSearchProvider(EventsSearchProvider::class);
136
-		$context->registerSearchProvider(TasksSearchProvider::class);
137
-
138
-		/**
139
-		 * Register event listeners
140
-		 */
141
-		$context->registerEventListener(AddMissingIndicesEvent::class, AddMissingIndicesListener::class);
142
-
143
-		$context->registerEventListener(CalendarCreatedEvent::class, ActivityUpdaterListener::class);
144
-		$context->registerEventListener(CalendarDeletedEvent::class, ActivityUpdaterListener::class);
145
-		$context->registerEventListener(CalendarDeletedEvent::class, CalendarObjectReminderUpdaterListener::class);
146
-		$context->registerEventListener(CalendarDeletedEvent::class, CalendarDeletionDefaultUpdaterListener::class);
147
-		$context->registerEventListener(CalendarMovedToTrashEvent::class, ActivityUpdaterListener::class);
148
-		$context->registerEventListener(CalendarMovedToTrashEvent::class, CalendarObjectReminderUpdaterListener::class);
149
-		$context->registerEventListener(CalendarUpdatedEvent::class, ActivityUpdaterListener::class);
150
-		$context->registerEventListener(CalendarRestoredEvent::class, ActivityUpdaterListener::class);
151
-		$context->registerEventListener(CalendarRestoredEvent::class, CalendarObjectReminderUpdaterListener::class);
152
-		$context->registerEventListener(CalendarObjectCreatedEvent::class, ActivityUpdaterListener::class);
153
-		$context->registerEventListener(CalendarObjectCreatedEvent::class, CalendarContactInteractionListener::class);
154
-		$context->registerEventListener(CalendarObjectCreatedEvent::class, CalendarObjectReminderUpdaterListener::class);
155
-		$context->registerEventListener(CalendarObjectUpdatedEvent::class, ActivityUpdaterListener::class);
156
-		$context->registerEventListener(CalendarObjectUpdatedEvent::class, CalendarContactInteractionListener::class);
157
-		$context->registerEventListener(CalendarObjectUpdatedEvent::class, CalendarObjectReminderUpdaterListener::class);
158
-		$context->registerEventListener(CalendarObjectDeletedEvent::class, ActivityUpdaterListener::class);
159
-		$context->registerEventListener(CalendarObjectDeletedEvent::class, CalendarObjectReminderUpdaterListener::class);
160
-		$context->registerEventListener(CalendarObjectMovedEvent::class, ActivityUpdaterListener::class);
161
-		$context->registerEventListener(CalendarObjectMovedEvent::class, CalendarObjectReminderUpdaterListener::class);
162
-		$context->registerEventListener(CalendarObjectMovedToTrashEvent::class, ActivityUpdaterListener::class);
163
-		$context->registerEventListener(CalendarObjectMovedToTrashEvent::class, CalendarObjectReminderUpdaterListener::class);
164
-		$context->registerEventListener(CalendarObjectRestoredEvent::class, ActivityUpdaterListener::class);
165
-		$context->registerEventListener(CalendarObjectRestoredEvent::class, CalendarObjectReminderUpdaterListener::class);
166
-		$context->registerEventListener(CalendarShareUpdatedEvent::class, CalendarContactInteractionListener::class);
167
-		$context->registerEventListener(CalendarPublishedEvent::class, CalendarPublicationListener::class);
168
-		$context->registerEventListener(CalendarUnpublishedEvent::class, CalendarPublicationListener::class);
169
-		$context->registerEventListener(CalendarShareUpdatedEvent::class, CalendarShareUpdateListener::class);
170
-
171
-		$context->registerEventListener(SubscriptionCreatedEvent::class, SubscriptionListener::class);
172
-		$context->registerEventListener(SubscriptionDeletedEvent::class, SubscriptionListener::class);
173
-
174
-
175
-		$context->registerEventListener(AddressBookCreatedEvent::class, AddressbookListener::class);
176
-		$context->registerEventListener(AddressBookDeletedEvent::class, AddressbookListener::class);
177
-		$context->registerEventListener(AddressBookUpdatedEvent::class, AddressbookListener::class);
178
-		$context->registerEventListener(AddressBookShareUpdatedEvent::class, AddressbookListener::class);
179
-		$context->registerEventListener(CardCreatedEvent::class, CardListener::class);
180
-		$context->registerEventListener(CardDeletedEvent::class, CardListener::class);
181
-		$context->registerEventListener(CardUpdatedEvent::class, CardListener::class);
182
-		$context->registerEventListener(CardCreatedEvent::class, BirthdayListener::class);
183
-		$context->registerEventListener(CardDeletedEvent::class, BirthdayListener::class);
184
-		$context->registerEventListener(CardUpdatedEvent::class, BirthdayListener::class);
185
-		$context->registerEventListener(CardDeletedEvent::class, ClearPhotoCacheListener::class);
186
-		$context->registerEventListener(CardUpdatedEvent::class, ClearPhotoCacheListener::class);
187
-		$context->registerEventListener(TrustedServerRemovedEvent::class, TrustedServerRemovedListener::class);
188
-
189
-		$context->registerEventListener(BeforePreferenceDeletedEvent::class, UserPreferenceListener::class);
190
-		$context->registerEventListener(BeforePreferenceSetEvent::class, UserPreferenceListener::class);
191
-
192
-		$context->registerEventListener(OutOfOfficeChangedEvent::class, OutOfOfficeListener::class);
193
-		$context->registerEventListener(OutOfOfficeClearedEvent::class, OutOfOfficeListener::class);
194
-		$context->registerEventListener(OutOfOfficeScheduledEvent::class, OutOfOfficeListener::class);
195
-
196
-		$context->registerEventListener(UserFirstTimeLoggedInEvent::class, UserEventsListener::class);
197
-		$context->registerEventListener(UserIdAssignedEvent::class, UserEventsListener::class);
198
-		$context->registerEventListener(BeforeUserIdUnassignedEvent::class, UserEventsListener::class);
199
-		$context->registerEventListener(UserIdUnassignedEvent::class, UserEventsListener::class);
200
-		$context->registerEventListener(BeforeUserDeletedEvent::class, UserEventsListener::class);
201
-		$context->registerEventListener(UserDeletedEvent::class, UserEventsListener::class);
202
-		$context->registerEventListener(UserCreatedEvent::class, UserEventsListener::class);
203
-		$context->registerEventListener(UserChangedEvent::class, UserEventsListener::class);
204
-		$context->registerEventListener(UserUpdatedEvent::class, UserEventsListener::class);
205
-
206
-		$context->registerEventListener(SabrePluginAuthInitEvent::class, SabrePluginAuthInitListener::class);
207
-
208
-		$context->registerEventListener(CalendarObjectCreatedEvent::class, CalendarFederationNotificationListener::class);
209
-		$context->registerEventListener(CalendarObjectUpdatedEvent::class, CalendarFederationNotificationListener::class);
210
-		$context->registerEventListener(CalendarObjectDeletedEvent::class, CalendarFederationNotificationListener::class);
211
-
212
-		$context->registerNotifierService(Notifier::class);
213
-
214
-		$context->registerCalendarProvider(CalendarProvider::class);
215
-		$context->registerCalendarProvider(CachedSubscriptionProvider::class);
216
-
217
-		$context->registerUserMigrator(CalendarMigrator::class);
218
-		$context->registerUserMigrator(ContactsMigrator::class);
219
-
220
-		$context->registerSetupCheck(NeedsSystemAddressBookSync::class);
221
-		$context->registerSetupCheck(WebdavEndpoint::class);
222
-
223
-		// register admin settings form and listener(s)
224
-		$context->registerDeclarativeSettings(SystemAddressBookSettings::class);
225
-		$context->registerEventListener(DeclarativeSettingsGetValueEvent::class, DavAdminSettingsListener::class);
226
-		$context->registerEventListener(DeclarativeSettingsSetValueEvent::class, DavAdminSettingsListener::class);
227
-	}
228
-
229
-	public function boot(IBootContext $context): void {
230
-		// Load all dav apps
231
-		$context->getServerContainer()->get(IAppManager::class)->loadApps(['dav']);
232
-
233
-		$context->injectFn($this->registerContactsManager(...));
234
-		$context->injectFn($this->registerCalendarManager(...));
235
-		$context->injectFn($this->registerCalendarReminders(...));
236
-		$context->injectFn($this->registerCloudFederationProvider(...));
237
-	}
238
-
239
-	public function registerContactsManager(IContactsManager $cm, IAppContainer $container): void {
240
-		$cm->register(function () use ($container, $cm): void {
241
-			$user = Server::get(IUserSession::class)->getUser();
242
-			if (!is_null($user)) {
243
-				$this->setupContactsProvider($cm, $container, $user->getUID());
244
-			} else {
245
-				$this->setupSystemContactsProvider($cm, $container);
246
-			}
247
-		});
248
-	}
249
-
250
-	private function setupContactsProvider(IContactsManager $contactsManager,
251
-		IAppContainer $container,
252
-		string $userID): void {
253
-		/** @var ContactsManager $cm */
254
-		$cm = $container->query(ContactsManager::class);
255
-		$urlGenerator = $container->getServer()->getURLGenerator();
256
-		$cm->setupContactsProvider($contactsManager, $userID, $urlGenerator);
257
-	}
258
-
259
-	private function setupSystemContactsProvider(IContactsManager $contactsManager, IAppContainer $container): void {
260
-		/** @var ContactsManager $cm */
261
-		$cm = $container->query(ContactsManager::class);
262
-		$urlGenerator = $container->getServer()->getURLGenerator();
263
-		$cm->setupSystemContactsProvider($contactsManager, null, $urlGenerator);
264
-	}
265
-
266
-	public function registerCalendarManager(ICalendarManager $calendarManager,
267
-		IAppContainer $container): void {
268
-		$calendarManager->register(function () use ($container, $calendarManager): void {
269
-			$user = Server::get(IUserSession::class)->getUser();
270
-			if ($user !== null) {
271
-				$this->setupCalendarProvider($calendarManager, $container, $user->getUID());
272
-			}
273
-		});
274
-	}
275
-
276
-	private function setupCalendarProvider(ICalendarManager $calendarManager,
277
-		IAppContainer $container,
278
-		$userId) {
279
-		$cm = $container->query(CalendarManager::class);
280
-		$cm->setupCalendarProvider($calendarManager, $userId);
281
-	}
282
-
283
-	public function registerCalendarReminders(NotificationProviderManager $manager,
284
-		LoggerInterface $logger): void {
285
-		try {
286
-			$manager->registerProvider(AudioProvider::class);
287
-			$manager->registerProvider(EmailProvider::class);
288
-			$manager->registerProvider(PushProvider::class);
289
-		} catch (Throwable $ex) {
290
-			$logger->error($ex->getMessage(), ['exception' => $ex]);
291
-		}
292
-	}
293
-
294
-	public function registerCloudFederationProvider(
295
-		ICloudFederationProviderManager $manager,
296
-	): void {
297
-		$manager->addCloudFederationProvider(
298
-			CalendarFederationProvider::PROVIDER_ID,
299
-			'Calendar Federation',
300
-			static fn () => Server::get(CalendarFederationProvider::class),
301
-		);
302
-	}
134
+        $context->registerSearchProvider(ContactsSearchProvider::class);
135
+        $context->registerSearchProvider(EventsSearchProvider::class);
136
+        $context->registerSearchProvider(TasksSearchProvider::class);
137
+
138
+        /**
139
+         * Register event listeners
140
+         */
141
+        $context->registerEventListener(AddMissingIndicesEvent::class, AddMissingIndicesListener::class);
142
+
143
+        $context->registerEventListener(CalendarCreatedEvent::class, ActivityUpdaterListener::class);
144
+        $context->registerEventListener(CalendarDeletedEvent::class, ActivityUpdaterListener::class);
145
+        $context->registerEventListener(CalendarDeletedEvent::class, CalendarObjectReminderUpdaterListener::class);
146
+        $context->registerEventListener(CalendarDeletedEvent::class, CalendarDeletionDefaultUpdaterListener::class);
147
+        $context->registerEventListener(CalendarMovedToTrashEvent::class, ActivityUpdaterListener::class);
148
+        $context->registerEventListener(CalendarMovedToTrashEvent::class, CalendarObjectReminderUpdaterListener::class);
149
+        $context->registerEventListener(CalendarUpdatedEvent::class, ActivityUpdaterListener::class);
150
+        $context->registerEventListener(CalendarRestoredEvent::class, ActivityUpdaterListener::class);
151
+        $context->registerEventListener(CalendarRestoredEvent::class, CalendarObjectReminderUpdaterListener::class);
152
+        $context->registerEventListener(CalendarObjectCreatedEvent::class, ActivityUpdaterListener::class);
153
+        $context->registerEventListener(CalendarObjectCreatedEvent::class, CalendarContactInteractionListener::class);
154
+        $context->registerEventListener(CalendarObjectCreatedEvent::class, CalendarObjectReminderUpdaterListener::class);
155
+        $context->registerEventListener(CalendarObjectUpdatedEvent::class, ActivityUpdaterListener::class);
156
+        $context->registerEventListener(CalendarObjectUpdatedEvent::class, CalendarContactInteractionListener::class);
157
+        $context->registerEventListener(CalendarObjectUpdatedEvent::class, CalendarObjectReminderUpdaterListener::class);
158
+        $context->registerEventListener(CalendarObjectDeletedEvent::class, ActivityUpdaterListener::class);
159
+        $context->registerEventListener(CalendarObjectDeletedEvent::class, CalendarObjectReminderUpdaterListener::class);
160
+        $context->registerEventListener(CalendarObjectMovedEvent::class, ActivityUpdaterListener::class);
161
+        $context->registerEventListener(CalendarObjectMovedEvent::class, CalendarObjectReminderUpdaterListener::class);
162
+        $context->registerEventListener(CalendarObjectMovedToTrashEvent::class, ActivityUpdaterListener::class);
163
+        $context->registerEventListener(CalendarObjectMovedToTrashEvent::class, CalendarObjectReminderUpdaterListener::class);
164
+        $context->registerEventListener(CalendarObjectRestoredEvent::class, ActivityUpdaterListener::class);
165
+        $context->registerEventListener(CalendarObjectRestoredEvent::class, CalendarObjectReminderUpdaterListener::class);
166
+        $context->registerEventListener(CalendarShareUpdatedEvent::class, CalendarContactInteractionListener::class);
167
+        $context->registerEventListener(CalendarPublishedEvent::class, CalendarPublicationListener::class);
168
+        $context->registerEventListener(CalendarUnpublishedEvent::class, CalendarPublicationListener::class);
169
+        $context->registerEventListener(CalendarShareUpdatedEvent::class, CalendarShareUpdateListener::class);
170
+
171
+        $context->registerEventListener(SubscriptionCreatedEvent::class, SubscriptionListener::class);
172
+        $context->registerEventListener(SubscriptionDeletedEvent::class, SubscriptionListener::class);
173
+
174
+
175
+        $context->registerEventListener(AddressBookCreatedEvent::class, AddressbookListener::class);
176
+        $context->registerEventListener(AddressBookDeletedEvent::class, AddressbookListener::class);
177
+        $context->registerEventListener(AddressBookUpdatedEvent::class, AddressbookListener::class);
178
+        $context->registerEventListener(AddressBookShareUpdatedEvent::class, AddressbookListener::class);
179
+        $context->registerEventListener(CardCreatedEvent::class, CardListener::class);
180
+        $context->registerEventListener(CardDeletedEvent::class, CardListener::class);
181
+        $context->registerEventListener(CardUpdatedEvent::class, CardListener::class);
182
+        $context->registerEventListener(CardCreatedEvent::class, BirthdayListener::class);
183
+        $context->registerEventListener(CardDeletedEvent::class, BirthdayListener::class);
184
+        $context->registerEventListener(CardUpdatedEvent::class, BirthdayListener::class);
185
+        $context->registerEventListener(CardDeletedEvent::class, ClearPhotoCacheListener::class);
186
+        $context->registerEventListener(CardUpdatedEvent::class, ClearPhotoCacheListener::class);
187
+        $context->registerEventListener(TrustedServerRemovedEvent::class, TrustedServerRemovedListener::class);
188
+
189
+        $context->registerEventListener(BeforePreferenceDeletedEvent::class, UserPreferenceListener::class);
190
+        $context->registerEventListener(BeforePreferenceSetEvent::class, UserPreferenceListener::class);
191
+
192
+        $context->registerEventListener(OutOfOfficeChangedEvent::class, OutOfOfficeListener::class);
193
+        $context->registerEventListener(OutOfOfficeClearedEvent::class, OutOfOfficeListener::class);
194
+        $context->registerEventListener(OutOfOfficeScheduledEvent::class, OutOfOfficeListener::class);
195
+
196
+        $context->registerEventListener(UserFirstTimeLoggedInEvent::class, UserEventsListener::class);
197
+        $context->registerEventListener(UserIdAssignedEvent::class, UserEventsListener::class);
198
+        $context->registerEventListener(BeforeUserIdUnassignedEvent::class, UserEventsListener::class);
199
+        $context->registerEventListener(UserIdUnassignedEvent::class, UserEventsListener::class);
200
+        $context->registerEventListener(BeforeUserDeletedEvent::class, UserEventsListener::class);
201
+        $context->registerEventListener(UserDeletedEvent::class, UserEventsListener::class);
202
+        $context->registerEventListener(UserCreatedEvent::class, UserEventsListener::class);
203
+        $context->registerEventListener(UserChangedEvent::class, UserEventsListener::class);
204
+        $context->registerEventListener(UserUpdatedEvent::class, UserEventsListener::class);
205
+
206
+        $context->registerEventListener(SabrePluginAuthInitEvent::class, SabrePluginAuthInitListener::class);
207
+
208
+        $context->registerEventListener(CalendarObjectCreatedEvent::class, CalendarFederationNotificationListener::class);
209
+        $context->registerEventListener(CalendarObjectUpdatedEvent::class, CalendarFederationNotificationListener::class);
210
+        $context->registerEventListener(CalendarObjectDeletedEvent::class, CalendarFederationNotificationListener::class);
211
+
212
+        $context->registerNotifierService(Notifier::class);
213
+
214
+        $context->registerCalendarProvider(CalendarProvider::class);
215
+        $context->registerCalendarProvider(CachedSubscriptionProvider::class);
216
+
217
+        $context->registerUserMigrator(CalendarMigrator::class);
218
+        $context->registerUserMigrator(ContactsMigrator::class);
219
+
220
+        $context->registerSetupCheck(NeedsSystemAddressBookSync::class);
221
+        $context->registerSetupCheck(WebdavEndpoint::class);
222
+
223
+        // register admin settings form and listener(s)
224
+        $context->registerDeclarativeSettings(SystemAddressBookSettings::class);
225
+        $context->registerEventListener(DeclarativeSettingsGetValueEvent::class, DavAdminSettingsListener::class);
226
+        $context->registerEventListener(DeclarativeSettingsSetValueEvent::class, DavAdminSettingsListener::class);
227
+    }
228
+
229
+    public function boot(IBootContext $context): void {
230
+        // Load all dav apps
231
+        $context->getServerContainer()->get(IAppManager::class)->loadApps(['dav']);
232
+
233
+        $context->injectFn($this->registerContactsManager(...));
234
+        $context->injectFn($this->registerCalendarManager(...));
235
+        $context->injectFn($this->registerCalendarReminders(...));
236
+        $context->injectFn($this->registerCloudFederationProvider(...));
237
+    }
238
+
239
+    public function registerContactsManager(IContactsManager $cm, IAppContainer $container): void {
240
+        $cm->register(function () use ($container, $cm): void {
241
+            $user = Server::get(IUserSession::class)->getUser();
242
+            if (!is_null($user)) {
243
+                $this->setupContactsProvider($cm, $container, $user->getUID());
244
+            } else {
245
+                $this->setupSystemContactsProvider($cm, $container);
246
+            }
247
+        });
248
+    }
249
+
250
+    private function setupContactsProvider(IContactsManager $contactsManager,
251
+        IAppContainer $container,
252
+        string $userID): void {
253
+        /** @var ContactsManager $cm */
254
+        $cm = $container->query(ContactsManager::class);
255
+        $urlGenerator = $container->getServer()->getURLGenerator();
256
+        $cm->setupContactsProvider($contactsManager, $userID, $urlGenerator);
257
+    }
258
+
259
+    private function setupSystemContactsProvider(IContactsManager $contactsManager, IAppContainer $container): void {
260
+        /** @var ContactsManager $cm */
261
+        $cm = $container->query(ContactsManager::class);
262
+        $urlGenerator = $container->getServer()->getURLGenerator();
263
+        $cm->setupSystemContactsProvider($contactsManager, null, $urlGenerator);
264
+    }
265
+
266
+    public function registerCalendarManager(ICalendarManager $calendarManager,
267
+        IAppContainer $container): void {
268
+        $calendarManager->register(function () use ($container, $calendarManager): void {
269
+            $user = Server::get(IUserSession::class)->getUser();
270
+            if ($user !== null) {
271
+                $this->setupCalendarProvider($calendarManager, $container, $user->getUID());
272
+            }
273
+        });
274
+    }
275
+
276
+    private function setupCalendarProvider(ICalendarManager $calendarManager,
277
+        IAppContainer $container,
278
+        $userId) {
279
+        $cm = $container->query(CalendarManager::class);
280
+        $cm->setupCalendarProvider($calendarManager, $userId);
281
+    }
282
+
283
+    public function registerCalendarReminders(NotificationProviderManager $manager,
284
+        LoggerInterface $logger): void {
285
+        try {
286
+            $manager->registerProvider(AudioProvider::class);
287
+            $manager->registerProvider(EmailProvider::class);
288
+            $manager->registerProvider(PushProvider::class);
289
+        } catch (Throwable $ex) {
290
+            $logger->error($ex->getMessage(), ['exception' => $ex]);
291
+        }
292
+    }
293
+
294
+    public function registerCloudFederationProvider(
295
+        ICloudFederationProviderManager $manager,
296
+    ): void {
297
+        $manager->addCloudFederationProvider(
298
+            CalendarFederationProvider::PROVIDER_ID,
299
+            'Calendar Federation',
300
+            static fn () => Server::get(CalendarFederationProvider::class),
301
+        );
302
+    }
303 303
 }
Please login to merge, or discard this patch.
apps/dav/lib/CalDAV/SyncServiceResult.php 1 patch
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -10,17 +10,17 @@
 block discarded – undo
10 10
 namespace OCA\DAV\CalDAV;
11 11
 
12 12
 final class SyncServiceResult {
13
-	public function __construct(
14
-		private readonly string $syncToken,
15
-		private readonly int $downloadedEvents,
16
-	) {
17
-	}
13
+    public function __construct(
14
+        private readonly string $syncToken,
15
+        private readonly int $downloadedEvents,
16
+    ) {
17
+    }
18 18
 
19
-	public function getSyncToken(): string {
20
-		return $this->syncToken;
21
-	}
19
+    public function getSyncToken(): string {
20
+        return $this->syncToken;
21
+    }
22 22
 
23
-	public function getDownloadedEvents(): int {
24
-		return $this->downloadedEvents;
25
-	}
23
+    public function getDownloadedEvents(): int {
24
+        return $this->downloadedEvents;
25
+    }
26 26
 }
Please login to merge, or discard this patch.
apps/dav/lib/CalDAV/AppCalendar/AppCalendarPlugin.php 2 patches
Indentation   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -19,45 +19,45 @@
 block discarded – undo
19 19
 
20 20
 /* Plugin for wrapping application generated calendars registered in nextcloud core (OCP\Calendar\ICalendarProvider) */
21 21
 class AppCalendarPlugin implements ICalendarProvider {
22
-	public function __construct(
23
-		protected IManager $manager,
24
-		protected LoggerInterface $logger,
25
-	) {
26
-	}
27
-
28
-	public function getAppID(): string {
29
-		return 'dav-wrapper';
30
-	}
31
-
32
-	public function fetchAllForCalendarHome(string $principalUri): array {
33
-		return array_map(function ($calendar) use (&$principalUri) {
34
-			return new AppCalendar($this->getAppID(), $calendar, $principalUri);
35
-		}, $this->getWrappedCalendars($principalUri));
36
-	}
37
-
38
-	public function hasCalendarInCalendarHome(string $principalUri, string $calendarUri): bool {
39
-		return count($this->getWrappedCalendars($principalUri, [ $calendarUri ])) > 0;
40
-	}
41
-
42
-	public function getCalendarInCalendarHome(string $principalUri, string $calendarUri): ?ExternalCalendar {
43
-		$calendars = $this->getWrappedCalendars($principalUri, [ $calendarUri ]);
44
-		if (count($calendars) > 0) {
45
-			return new AppCalendar($this->getAppID(), $calendars[0], $principalUri);
46
-		}
47
-
48
-		return null;
49
-	}
50
-
51
-	protected function getWrappedCalendars(string $principalUri, array $calendarUris = []): array {
52
-		return array_values(
53
-			array_filter($this->manager->getCalendarsForPrincipal($principalUri, $calendarUris), function ($c) {
54
-				// We must not provide a wrapper for DAV calendars
55
-				return !(
56
-					($c instanceof CalendarImpl)
57
-					|| ($c instanceof CachedSubscriptionImpl)
58
-					|| ($c instanceof FederatedCalendarImpl)
59
-				);
60
-			})
61
-		);
62
-	}
22
+    public function __construct(
23
+        protected IManager $manager,
24
+        protected LoggerInterface $logger,
25
+    ) {
26
+    }
27
+
28
+    public function getAppID(): string {
29
+        return 'dav-wrapper';
30
+    }
31
+
32
+    public function fetchAllForCalendarHome(string $principalUri): array {
33
+        return array_map(function ($calendar) use (&$principalUri) {
34
+            return new AppCalendar($this->getAppID(), $calendar, $principalUri);
35
+        }, $this->getWrappedCalendars($principalUri));
36
+    }
37
+
38
+    public function hasCalendarInCalendarHome(string $principalUri, string $calendarUri): bool {
39
+        return count($this->getWrappedCalendars($principalUri, [ $calendarUri ])) > 0;
40
+    }
41
+
42
+    public function getCalendarInCalendarHome(string $principalUri, string $calendarUri): ?ExternalCalendar {
43
+        $calendars = $this->getWrappedCalendars($principalUri, [ $calendarUri ]);
44
+        if (count($calendars) > 0) {
45
+            return new AppCalendar($this->getAppID(), $calendars[0], $principalUri);
46
+        }
47
+
48
+        return null;
49
+    }
50
+
51
+    protected function getWrappedCalendars(string $principalUri, array $calendarUris = []): array {
52
+        return array_values(
53
+            array_filter($this->manager->getCalendarsForPrincipal($principalUri, $calendarUris), function ($c) {
54
+                // We must not provide a wrapper for DAV calendars
55
+                return !(
56
+                    ($c instanceof CalendarImpl)
57
+                    || ($c instanceof CachedSubscriptionImpl)
58
+                    || ($c instanceof FederatedCalendarImpl)
59
+                );
60
+            })
61
+        );
62
+    }
63 63
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -30,17 +30,17 @@  discard block
 block discarded – undo
30 30
 	}
31 31
 
32 32
 	public function fetchAllForCalendarHome(string $principalUri): array {
33
-		return array_map(function ($calendar) use (&$principalUri) {
33
+		return array_map(function($calendar) use (&$principalUri) {
34 34
 			return new AppCalendar($this->getAppID(), $calendar, $principalUri);
35 35
 		}, $this->getWrappedCalendars($principalUri));
36 36
 	}
37 37
 
38 38
 	public function hasCalendarInCalendarHome(string $principalUri, string $calendarUri): bool {
39
-		return count($this->getWrappedCalendars($principalUri, [ $calendarUri ])) > 0;
39
+		return count($this->getWrappedCalendars($principalUri, [$calendarUri])) > 0;
40 40
 	}
41 41
 
42 42
 	public function getCalendarInCalendarHome(string $principalUri, string $calendarUri): ?ExternalCalendar {
43
-		$calendars = $this->getWrappedCalendars($principalUri, [ $calendarUri ]);
43
+		$calendars = $this->getWrappedCalendars($principalUri, [$calendarUri]);
44 44
 		if (count($calendars) > 0) {
45 45
 			return new AppCalendar($this->getAppID(), $calendars[0], $principalUri);
46 46
 		}
@@ -50,7 +50,7 @@  discard block
 block discarded – undo
50 50
 
51 51
 	protected function getWrappedCalendars(string $principalUri, array $calendarUris = []): array {
52 52
 		return array_values(
53
-			array_filter($this->manager->getCalendarsForPrincipal($principalUri, $calendarUris), function ($c) {
53
+			array_filter($this->manager->getCalendarsForPrincipal($principalUri, $calendarUris), function($c) {
54 54
 				// We must not provide a wrapper for DAV calendars
55 55
 				return !(
56 56
 					($c instanceof CalendarImpl)
Please login to merge, or discard this patch.