Passed
Push — master ( f0dd71...c56a27 )
by Christoph
11:49 queued 12s
created
apps/settings/lib/Controller/AppSettingsController.php 2 patches
Indentation   +502 added lines, -502 removed lines patch added patch discarded remove patch
@@ -56,507 +56,507 @@
 block discarded – undo
56 56
 
57 57
 class AppSettingsController extends Controller {
58 58
 
59
-	/** @var \OCP\IL10N */
60
-	private $l10n;
61
-	/** @var IConfig */
62
-	private $config;
63
-	/** @var INavigationManager */
64
-	private $navigationManager;
65
-	/** @var IAppManager */
66
-	private $appManager;
67
-	/** @var CategoryFetcher */
68
-	private $categoryFetcher;
69
-	/** @var AppFetcher */
70
-	private $appFetcher;
71
-	/** @var IFactory */
72
-	private $l10nFactory;
73
-	/** @var BundleFetcher */
74
-	private $bundleFetcher;
75
-	/** @var Installer */
76
-	private $installer;
77
-	/** @var IURLGenerator */
78
-	private $urlGenerator;
79
-	/** @var ILogger */
80
-	private $logger;
81
-
82
-	/** @var array */
83
-	private $allApps = [];
84
-
85
-	/**
86
-	 * @param string $appName
87
-	 * @param IRequest $request
88
-	 * @param IL10N $l10n
89
-	 * @param IConfig $config
90
-	 * @param INavigationManager $navigationManager
91
-	 * @param IAppManager $appManager
92
-	 * @param CategoryFetcher $categoryFetcher
93
-	 * @param AppFetcher $appFetcher
94
-	 * @param IFactory $l10nFactory
95
-	 * @param BundleFetcher $bundleFetcher
96
-	 * @param Installer $installer
97
-	 * @param IURLGenerator $urlGenerator
98
-	 * @param ILogger $logger
99
-	 */
100
-	public function __construct(string $appName,
101
-								IRequest $request,
102
-								IL10N $l10n,
103
-								IConfig $config,
104
-								INavigationManager $navigationManager,
105
-								IAppManager $appManager,
106
-								CategoryFetcher $categoryFetcher,
107
-								AppFetcher $appFetcher,
108
-								IFactory $l10nFactory,
109
-								BundleFetcher $bundleFetcher,
110
-								Installer $installer,
111
-								IURLGenerator $urlGenerator,
112
-								ILogger $logger) {
113
-		parent::__construct($appName, $request);
114
-		$this->l10n = $l10n;
115
-		$this->config = $config;
116
-		$this->navigationManager = $navigationManager;
117
-		$this->appManager = $appManager;
118
-		$this->categoryFetcher = $categoryFetcher;
119
-		$this->appFetcher = $appFetcher;
120
-		$this->l10nFactory = $l10nFactory;
121
-		$this->bundleFetcher = $bundleFetcher;
122
-		$this->installer = $installer;
123
-		$this->urlGenerator = $urlGenerator;
124
-		$this->logger = $logger;
125
-	}
126
-
127
-	/**
128
-	 * @NoCSRFRequired
129
-	 *
130
-	 * @return TemplateResponse
131
-	 */
132
-	public function viewApps(): TemplateResponse {
133
-		\OC_Util::addScript('settings', 'apps');
134
-		$params = [];
135
-		$params['appstoreEnabled'] = $this->config->getSystemValue('appstoreenabled', true) === true;
136
-		$params['updateCount'] = count($this->getAppsWithUpdates());
137
-		$params['developerDocumentation'] = $this->urlGenerator->linkToDocs('developer-manual');
138
-		$params['bundles'] = $this->getBundles();
139
-		$this->navigationManager->setActiveEntry('core_apps');
140
-
141
-		$templateResponse = new TemplateResponse('settings', 'settings-vue', ['serverData' => $params]);
142
-		$policy = new ContentSecurityPolicy();
143
-		$policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com');
144
-		$templateResponse->setContentSecurityPolicy($policy);
145
-
146
-		return $templateResponse;
147
-	}
148
-
149
-	private function getAppsWithUpdates() {
150
-		$appClass = new \OC_App();
151
-		$apps = $appClass->listAllApps();
152
-		foreach($apps as $key => $app) {
153
-			$newVersion = $this->installer->isUpdateAvailable($app['id']);
154
-			if($newVersion === false) {
155
-				unset($apps[$key]);
156
-			}
157
-		}
158
-		return $apps;
159
-	}
160
-
161
-	private function getBundles() {
162
-		$result = [];
163
-		$bundles = $this->bundleFetcher->getBundles();
164
-		foreach ($bundles as $bundle) {
165
-			$result[] = [
166
-				'name' => $bundle->getName(),
167
-				'id' => $bundle->getIdentifier(),
168
-				'appIdentifiers' => $bundle->getAppIdentifiers()
169
-			];
170
-		}
171
-		return $result;
172
-
173
-	}
174
-
175
-	/**
176
-	 * Get all available categories
177
-	 *
178
-	 * @return JSONResponse
179
-	 */
180
-	public function listCategories(): JSONResponse {
181
-		return new JSONResponse($this->getAllCategories());
182
-	}
183
-
184
-	private function getAllCategories() {
185
-		$currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
186
-
187
-		$formattedCategories = [];
188
-		$categories = $this->categoryFetcher->get();
189
-		foreach($categories as $category) {
190
-			$formattedCategories[] = [
191
-				'id' => $category['id'],
192
-				'ident' => $category['id'],
193
-				'displayName' => isset($category['translations'][$currentLanguage]['name']) ? $category['translations'][$currentLanguage]['name'] : $category['translations']['en']['name'],
194
-			];
195
-		}
196
-
197
-		return $formattedCategories;
198
-	}
199
-
200
-	private function fetchApps() {
201
-		$appClass = new \OC_App();
202
-		$apps = $appClass->listAllApps();
203
-		foreach ($apps as $app) {
204
-			$app['installed'] = true;
205
-			$this->allApps[$app['id']] = $app;
206
-		}
207
-
208
-		$apps = $this->getAppsForCategory('');
209
-		foreach ($apps as $app) {
210
-			$app['appstore'] = true;
211
-			if (!array_key_exists($app['id'], $this->allApps)) {
212
-				$this->allApps[$app['id']] = $app;
213
-			} else {
214
-				$this->allApps[$app['id']] = array_merge($app, $this->allApps[$app['id']]);
215
-			}
216
-		}
217
-
218
-		// add bundle information
219
-		$bundles = $this->bundleFetcher->getBundles();
220
-		foreach($bundles as $bundle) {
221
-			foreach($bundle->getAppIdentifiers() as $identifier) {
222
-				foreach($this->allApps as &$app) {
223
-					if($app['id'] === $identifier) {
224
-						$app['bundleIds'][] = $bundle->getIdentifier();
225
-						continue;
226
-					}
227
-				}
228
-			}
229
-		}
230
-	}
231
-
232
-	private function getAllApps() {
233
-		return $this->allApps;
234
-	}
235
-	/**
236
-	 * Get all available apps in a category
237
-	 *
238
-	 * @param string $category
239
-	 * @return JSONResponse
240
-	 * @throws \Exception
241
-	 */
242
-	public function listApps(): JSONResponse {
243
-
244
-		$this->fetchApps();
245
-		$apps = $this->getAllApps();
246
-
247
-		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($this->config), $this->l10n);
248
-
249
-		// Extend existing app details
250
-		$apps = array_map(function ($appData) use ($dependencyAnalyzer) {
251
-			if (isset($appData['appstoreData'])) {
252
-				$appstoreData = $appData['appstoreData'];
253
-				$appData['screenshot'] = isset($appstoreData['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/' . base64_encode($appstoreData['screenshots'][0]['url']) : '';
254
-				$appData['category'] = $appstoreData['categories'];
255
-			}
256
-
257
-			$newVersion = $this->installer->isUpdateAvailable($appData['id']);
258
-			if($newVersion) {
259
-				$appData['update'] = $newVersion;
260
-			}
261
-
262
-			// fix groups to be an array
263
-			$groups = [];
264
-			if (is_string($appData['groups'])) {
265
-				$groups = json_decode($appData['groups']);
266
-			}
267
-			$appData['groups'] = $groups;
268
-			$appData['canUnInstall'] = !$appData['active'] && $appData['removable'];
269
-
270
-			// fix licence vs license
271
-			if (isset($appData['license']) && !isset($appData['licence'])) {
272
-				$appData['licence'] = $appData['license'];
273
-			}
274
-
275
-			$ignoreMaxApps = $this->config->getSystemValue('app_install_overwrite', []);
276
-			if (!is_array($ignoreMaxApps)) {
277
-				$this->logger->warning('The value given for app_install_overwrite is not an array. Ignoring...');
278
-				$ignoreMaxApps = [];
279
-			}
280
-			$ignoreMax = in_array($appData['id'], $ignoreMaxApps);
281
-
282
-			// analyse dependencies
283
-			$missing = $dependencyAnalyzer->analyze($appData, $ignoreMax);
284
-			$appData['canInstall'] = empty($missing);
285
-			$appData['missingDependencies'] = $missing;
286
-
287
-			$appData['missingMinOwnCloudVersion'] = !isset($appData['dependencies']['nextcloud']['@attributes']['min-version']);
288
-			$appData['missingMaxOwnCloudVersion'] = !isset($appData['dependencies']['nextcloud']['@attributes']['max-version']);
289
-			$appData['isCompatible'] = $dependencyAnalyzer->isMarkedCompatible($appData);
290
-
291
-			return $appData;
292
-		}, $apps);
293
-
294
-		usort($apps, [$this, 'sortApps']);
295
-
296
-		return new JSONResponse(['apps' => $apps, 'status' => 'success']);
297
-	}
298
-
299
-	/**
300
-	 * Get all apps for a category from the app store
301
-	 *
302
-	 * @param string $requestedCategory
303
-	 * @return array
304
-	 * @throws \Exception
305
-	 */
306
-	private function getAppsForCategory($requestedCategory = ''): array {
307
-		$versionParser = new VersionParser();
308
-		$formattedApps = [];
309
-		$apps = $this->appFetcher->get();
310
-		foreach($apps as $app) {
311
-			// Skip all apps not in the requested category
312
-			if ($requestedCategory !== '') {
313
-				$isInCategory = false;
314
-				foreach($app['categories'] as $category) {
315
-					if($category === $requestedCategory) {
316
-						$isInCategory = true;
317
-					}
318
-				}
319
-				if(!$isInCategory) {
320
-					continue;
321
-				}
322
-			}
323
-
324
-			if (!isset($app['releases'][0]['rawPlatformVersionSpec'])) {
325
-				continue;
326
-			}
327
-			$nextCloudVersion = $versionParser->getVersion($app['releases'][0]['rawPlatformVersionSpec']);
328
-			$nextCloudVersionDependencies = [];
329
-			if($nextCloudVersion->getMinimumVersion() !== '') {
330
-				$nextCloudVersionDependencies['nextcloud']['@attributes']['min-version'] = $nextCloudVersion->getMinimumVersion();
331
-			}
332
-			if($nextCloudVersion->getMaximumVersion() !== '') {
333
-				$nextCloudVersionDependencies['nextcloud']['@attributes']['max-version'] = $nextCloudVersion->getMaximumVersion();
334
-			}
335
-			$phpVersion = $versionParser->getVersion($app['releases'][0]['rawPhpVersionSpec']);
336
-			$existsLocally = \OC_App::getAppPath($app['id']) !== false;
337
-			$phpDependencies = [];
338
-			if($phpVersion->getMinimumVersion() !== '') {
339
-				$phpDependencies['php']['@attributes']['min-version'] = $phpVersion->getMinimumVersion();
340
-			}
341
-			if($phpVersion->getMaximumVersion() !== '') {
342
-				$phpDependencies['php']['@attributes']['max-version'] = $phpVersion->getMaximumVersion();
343
-			}
344
-			if(isset($app['releases'][0]['minIntSize'])) {
345
-				$phpDependencies['php']['@attributes']['min-int-size'] = $app['releases'][0]['minIntSize'];
346
-			}
347
-			$authors = '';
348
-			foreach($app['authors'] as $key => $author) {
349
-				$authors .= $author['name'];
350
-				if($key !== count($app['authors']) - 1) {
351
-					$authors .= ', ';
352
-				}
353
-			}
354
-
355
-			$currentLanguage = substr(\OC::$server->getL10NFactory()->findLanguage(), 0, 2);
356
-			$enabledValue = $this->config->getAppValue($app['id'], 'enabled', 'no');
357
-			$groups = null;
358
-			if($enabledValue !== 'no' && $enabledValue !== 'yes') {
359
-				$groups = $enabledValue;
360
-			}
361
-
362
-			$currentVersion = '';
363
-			if($this->appManager->isInstalled($app['id'])) {
364
-				$currentVersion = $this->appManager->getAppVersion($app['id']);
365
-			} else {
366
-				$currentLanguage = $app['releases'][0]['version'];
367
-			}
368
-
369
-			$formattedApps[] = [
370
-				'id' => $app['id'],
371
-				'name' => isset($app['translations'][$currentLanguage]['name']) ? $app['translations'][$currentLanguage]['name'] : $app['translations']['en']['name'],
372
-				'description' => isset($app['translations'][$currentLanguage]['description']) ? $app['translations'][$currentLanguage]['description'] : $app['translations']['en']['description'],
373
-				'summary' => isset($app['translations'][$currentLanguage]['summary']) ? $app['translations'][$currentLanguage]['summary'] : $app['translations']['en']['summary'],
374
-				'license' => $app['releases'][0]['licenses'],
375
-				'author' => $authors,
376
-				'shipped' => false,
377
-				'version' => $currentVersion,
378
-				'default_enable' => '',
379
-				'types' => [],
380
-				'documentation' => [
381
-					'admin' => $app['adminDocs'],
382
-					'user' => $app['userDocs'],
383
-					'developer' => $app['developerDocs']
384
-				],
385
-				'website' => $app['website'],
386
-				'bugs' => $app['issueTracker'],
387
-				'detailpage' => $app['website'],
388
-				'dependencies' => array_merge(
389
-					$nextCloudVersionDependencies,
390
-					$phpDependencies
391
-				),
392
-				'level' => ($app['isFeatured'] === true) ? 200 : 100,
393
-				'missingMaxOwnCloudVersion' => false,
394
-				'missingMinOwnCloudVersion' => false,
395
-				'canInstall' => true,
396
-				'screenshot' => isset($app['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/'.base64_encode($app['screenshots'][0]['url']) : '',
397
-				'score' => $app['ratingOverall'],
398
-				'ratingNumOverall' => $app['ratingNumOverall'],
399
-				'ratingNumThresholdReached' => $app['ratingNumOverall'] > 5,
400
-				'removable' => $existsLocally,
401
-				'active' => $this->appManager->isEnabledForUser($app['id']),
402
-				'needsDownload' => !$existsLocally,
403
-				'groups' => $groups,
404
-				'fromAppStore' => true,
405
-				'appstoreData' => $app,
406
-			];
407
-		}
408
-
409
-		return $formattedApps;
410
-	}
411
-
412
-	/**
413
-	 * @PasswordConfirmationRequired
414
-	 *
415
-	 * @param string $appId
416
-	 * @param array $groups
417
-	 * @return JSONResponse
418
-	 */
419
-	public function enableApp(string $appId, array $groups = []): JSONResponse {
420
-		return $this->enableApps([$appId], $groups);
421
-	}
422
-
423
-	/**
424
-	 * Enable one or more apps
425
-	 *
426
-	 * apps will be enabled for specific groups only if $groups is defined
427
-	 *
428
-	 * @PasswordConfirmationRequired
429
-	 * @param array $appIds
430
-	 * @param array $groups
431
-	 * @return JSONResponse
432
-	 */
433
-	public function enableApps(array $appIds, array $groups = []): JSONResponse {
434
-		try {
435
-			$updateRequired = false;
436
-
437
-			foreach ($appIds as $appId) {
438
-				$appId = OC_App::cleanAppId($appId);
439
-
440
-				// Check if app is already downloaded
441
-				/** @var Installer $installer */
442
-				$installer = \OC::$server->query(Installer::class);
443
-				$isDownloaded = $installer->isDownloaded($appId);
444
-
445
-				if(!$isDownloaded) {
446
-					$installer->downloadApp($appId);
447
-				}
448
-
449
-				$installer->installApp($appId);
450
-
451
-				if (count($groups) > 0) {
452
-					$this->appManager->enableAppForGroups($appId, $this->getGroupList($groups));
453
-				} else {
454
-					$this->appManager->enableApp($appId);
455
-				}
456
-				if (\OC_App::shouldUpgrade($appId)) {
457
-					$updateRequired = true;
458
-				}
459
-			}
460
-			return new JSONResponse(['data' => ['update_required' => $updateRequired]]);
461
-
462
-		} catch (\Exception $e) {
463
-			$this->logger->logException($e);
464
-			return new JSONResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR);
465
-		}
466
-	}
467
-
468
-	private function getGroupList(array $groups) {
469
-		$groupManager = \OC::$server->getGroupManager();
470
-		$groupsList = [];
471
-		foreach ($groups as $group) {
472
-			$groupItem = $groupManager->get($group);
473
-			if ($groupItem instanceof \OCP\IGroup) {
474
-				$groupsList[] = $groupManager->get($group);
475
-			}
476
-		}
477
-		return $groupsList;
478
-	}
479
-
480
-	/**
481
-	 * @PasswordConfirmationRequired
482
-	 *
483
-	 * @param string $appId
484
-	 * @return JSONResponse
485
-	 */
486
-	public function disableApp(string $appId): JSONResponse {
487
-		return $this->disableApps([$appId]);
488
-	}
489
-
490
-	/**
491
-	 * @PasswordConfirmationRequired
492
-	 *
493
-	 * @param array $appIds
494
-	 * @return JSONResponse
495
-	 */
496
-	public function disableApps(array $appIds): JSONResponse {
497
-		try {
498
-			foreach ($appIds as $appId) {
499
-				$appId = OC_App::cleanAppId($appId);
500
-				$this->appManager->disableApp($appId);
501
-			}
502
-			return new JSONResponse([]);
503
-		} catch (\Exception $e) {
504
-			$this->logger->logException($e);
505
-			return new JSONResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR);
506
-		}
507
-	}
508
-
509
-	/**
510
-	 * @PasswordConfirmationRequired
511
-	 *
512
-	 * @param string $appId
513
-	 * @return JSONResponse
514
-	 */
515
-	public function uninstallApp(string $appId): JSONResponse {
516
-		$appId = OC_App::cleanAppId($appId);
517
-		$result = $this->installer->removeApp($appId);
518
-		if($result !== false) {
519
-			$this->appManager->clearAppsCache();
520
-			return new JSONResponse(['data' => ['appid' => $appId]]);
521
-		}
522
-		return new JSONResponse(['data' => ['message' => $this->l10n->t('Couldn\'t remove app.')]], Http::STATUS_INTERNAL_SERVER_ERROR);
523
-	}
524
-
525
-	/**
526
-	 * @param string $appId
527
-	 * @return JSONResponse
528
-	 */
529
-	public function updateApp(string $appId): JSONResponse {
530
-		$appId = OC_App::cleanAppId($appId);
531
-
532
-		$this->config->setSystemValue('maintenance', true);
533
-		try {
534
-			$result = $this->installer->updateAppstoreApp($appId);
535
-			$this->config->setSystemValue('maintenance', false);
536
-		} catch (\Exception $ex) {
537
-			$this->config->setSystemValue('maintenance', false);
538
-			return new JSONResponse(['data' => ['message' => $ex->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR);
539
-		}
540
-
541
-		if ($result !== false) {
542
-			return new JSONResponse(['data' => ['appid' => $appId]]);
543
-		}
544
-		return new JSONResponse(['data' => ['message' => $this->l10n->t('Couldn\'t update app.')]], Http::STATUS_INTERNAL_SERVER_ERROR);
545
-	}
546
-
547
-	private function sortApps($a, $b) {
548
-		$a = (string)$a['name'];
549
-		$b = (string)$b['name'];
550
-		if ($a === $b) {
551
-			return 0;
552
-		}
553
-		return ($a < $b) ? -1 : 1;
554
-	}
555
-
556
-	public function force(string $appId): JSONResponse {
557
-		$appId = OC_App::cleanAppId($appId);
558
-		$this->appManager->ignoreNextcloudRequirementForApp($appId);
559
-		return new JSONResponse();
560
-	}
59
+    /** @var \OCP\IL10N */
60
+    private $l10n;
61
+    /** @var IConfig */
62
+    private $config;
63
+    /** @var INavigationManager */
64
+    private $navigationManager;
65
+    /** @var IAppManager */
66
+    private $appManager;
67
+    /** @var CategoryFetcher */
68
+    private $categoryFetcher;
69
+    /** @var AppFetcher */
70
+    private $appFetcher;
71
+    /** @var IFactory */
72
+    private $l10nFactory;
73
+    /** @var BundleFetcher */
74
+    private $bundleFetcher;
75
+    /** @var Installer */
76
+    private $installer;
77
+    /** @var IURLGenerator */
78
+    private $urlGenerator;
79
+    /** @var ILogger */
80
+    private $logger;
81
+
82
+    /** @var array */
83
+    private $allApps = [];
84
+
85
+    /**
86
+     * @param string $appName
87
+     * @param IRequest $request
88
+     * @param IL10N $l10n
89
+     * @param IConfig $config
90
+     * @param INavigationManager $navigationManager
91
+     * @param IAppManager $appManager
92
+     * @param CategoryFetcher $categoryFetcher
93
+     * @param AppFetcher $appFetcher
94
+     * @param IFactory $l10nFactory
95
+     * @param BundleFetcher $bundleFetcher
96
+     * @param Installer $installer
97
+     * @param IURLGenerator $urlGenerator
98
+     * @param ILogger $logger
99
+     */
100
+    public function __construct(string $appName,
101
+                                IRequest $request,
102
+                                IL10N $l10n,
103
+                                IConfig $config,
104
+                                INavigationManager $navigationManager,
105
+                                IAppManager $appManager,
106
+                                CategoryFetcher $categoryFetcher,
107
+                                AppFetcher $appFetcher,
108
+                                IFactory $l10nFactory,
109
+                                BundleFetcher $bundleFetcher,
110
+                                Installer $installer,
111
+                                IURLGenerator $urlGenerator,
112
+                                ILogger $logger) {
113
+        parent::__construct($appName, $request);
114
+        $this->l10n = $l10n;
115
+        $this->config = $config;
116
+        $this->navigationManager = $navigationManager;
117
+        $this->appManager = $appManager;
118
+        $this->categoryFetcher = $categoryFetcher;
119
+        $this->appFetcher = $appFetcher;
120
+        $this->l10nFactory = $l10nFactory;
121
+        $this->bundleFetcher = $bundleFetcher;
122
+        $this->installer = $installer;
123
+        $this->urlGenerator = $urlGenerator;
124
+        $this->logger = $logger;
125
+    }
126
+
127
+    /**
128
+     * @NoCSRFRequired
129
+     *
130
+     * @return TemplateResponse
131
+     */
132
+    public function viewApps(): TemplateResponse {
133
+        \OC_Util::addScript('settings', 'apps');
134
+        $params = [];
135
+        $params['appstoreEnabled'] = $this->config->getSystemValue('appstoreenabled', true) === true;
136
+        $params['updateCount'] = count($this->getAppsWithUpdates());
137
+        $params['developerDocumentation'] = $this->urlGenerator->linkToDocs('developer-manual');
138
+        $params['bundles'] = $this->getBundles();
139
+        $this->navigationManager->setActiveEntry('core_apps');
140
+
141
+        $templateResponse = new TemplateResponse('settings', 'settings-vue', ['serverData' => $params]);
142
+        $policy = new ContentSecurityPolicy();
143
+        $policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com');
144
+        $templateResponse->setContentSecurityPolicy($policy);
145
+
146
+        return $templateResponse;
147
+    }
148
+
149
+    private function getAppsWithUpdates() {
150
+        $appClass = new \OC_App();
151
+        $apps = $appClass->listAllApps();
152
+        foreach($apps as $key => $app) {
153
+            $newVersion = $this->installer->isUpdateAvailable($app['id']);
154
+            if($newVersion === false) {
155
+                unset($apps[$key]);
156
+            }
157
+        }
158
+        return $apps;
159
+    }
160
+
161
+    private function getBundles() {
162
+        $result = [];
163
+        $bundles = $this->bundleFetcher->getBundles();
164
+        foreach ($bundles as $bundle) {
165
+            $result[] = [
166
+                'name' => $bundle->getName(),
167
+                'id' => $bundle->getIdentifier(),
168
+                'appIdentifiers' => $bundle->getAppIdentifiers()
169
+            ];
170
+        }
171
+        return $result;
172
+
173
+    }
174
+
175
+    /**
176
+     * Get all available categories
177
+     *
178
+     * @return JSONResponse
179
+     */
180
+    public function listCategories(): JSONResponse {
181
+        return new JSONResponse($this->getAllCategories());
182
+    }
183
+
184
+    private function getAllCategories() {
185
+        $currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
186
+
187
+        $formattedCategories = [];
188
+        $categories = $this->categoryFetcher->get();
189
+        foreach($categories as $category) {
190
+            $formattedCategories[] = [
191
+                'id' => $category['id'],
192
+                'ident' => $category['id'],
193
+                'displayName' => isset($category['translations'][$currentLanguage]['name']) ? $category['translations'][$currentLanguage]['name'] : $category['translations']['en']['name'],
194
+            ];
195
+        }
196
+
197
+        return $formattedCategories;
198
+    }
199
+
200
+    private function fetchApps() {
201
+        $appClass = new \OC_App();
202
+        $apps = $appClass->listAllApps();
203
+        foreach ($apps as $app) {
204
+            $app['installed'] = true;
205
+            $this->allApps[$app['id']] = $app;
206
+        }
207
+
208
+        $apps = $this->getAppsForCategory('');
209
+        foreach ($apps as $app) {
210
+            $app['appstore'] = true;
211
+            if (!array_key_exists($app['id'], $this->allApps)) {
212
+                $this->allApps[$app['id']] = $app;
213
+            } else {
214
+                $this->allApps[$app['id']] = array_merge($app, $this->allApps[$app['id']]);
215
+            }
216
+        }
217
+
218
+        // add bundle information
219
+        $bundles = $this->bundleFetcher->getBundles();
220
+        foreach($bundles as $bundle) {
221
+            foreach($bundle->getAppIdentifiers() as $identifier) {
222
+                foreach($this->allApps as &$app) {
223
+                    if($app['id'] === $identifier) {
224
+                        $app['bundleIds'][] = $bundle->getIdentifier();
225
+                        continue;
226
+                    }
227
+                }
228
+            }
229
+        }
230
+    }
231
+
232
+    private function getAllApps() {
233
+        return $this->allApps;
234
+    }
235
+    /**
236
+     * Get all available apps in a category
237
+     *
238
+     * @param string $category
239
+     * @return JSONResponse
240
+     * @throws \Exception
241
+     */
242
+    public function listApps(): JSONResponse {
243
+
244
+        $this->fetchApps();
245
+        $apps = $this->getAllApps();
246
+
247
+        $dependencyAnalyzer = new DependencyAnalyzer(new Platform($this->config), $this->l10n);
248
+
249
+        // Extend existing app details
250
+        $apps = array_map(function ($appData) use ($dependencyAnalyzer) {
251
+            if (isset($appData['appstoreData'])) {
252
+                $appstoreData = $appData['appstoreData'];
253
+                $appData['screenshot'] = isset($appstoreData['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/' . base64_encode($appstoreData['screenshots'][0]['url']) : '';
254
+                $appData['category'] = $appstoreData['categories'];
255
+            }
256
+
257
+            $newVersion = $this->installer->isUpdateAvailable($appData['id']);
258
+            if($newVersion) {
259
+                $appData['update'] = $newVersion;
260
+            }
261
+
262
+            // fix groups to be an array
263
+            $groups = [];
264
+            if (is_string($appData['groups'])) {
265
+                $groups = json_decode($appData['groups']);
266
+            }
267
+            $appData['groups'] = $groups;
268
+            $appData['canUnInstall'] = !$appData['active'] && $appData['removable'];
269
+
270
+            // fix licence vs license
271
+            if (isset($appData['license']) && !isset($appData['licence'])) {
272
+                $appData['licence'] = $appData['license'];
273
+            }
274
+
275
+            $ignoreMaxApps = $this->config->getSystemValue('app_install_overwrite', []);
276
+            if (!is_array($ignoreMaxApps)) {
277
+                $this->logger->warning('The value given for app_install_overwrite is not an array. Ignoring...');
278
+                $ignoreMaxApps = [];
279
+            }
280
+            $ignoreMax = in_array($appData['id'], $ignoreMaxApps);
281
+
282
+            // analyse dependencies
283
+            $missing = $dependencyAnalyzer->analyze($appData, $ignoreMax);
284
+            $appData['canInstall'] = empty($missing);
285
+            $appData['missingDependencies'] = $missing;
286
+
287
+            $appData['missingMinOwnCloudVersion'] = !isset($appData['dependencies']['nextcloud']['@attributes']['min-version']);
288
+            $appData['missingMaxOwnCloudVersion'] = !isset($appData['dependencies']['nextcloud']['@attributes']['max-version']);
289
+            $appData['isCompatible'] = $dependencyAnalyzer->isMarkedCompatible($appData);
290
+
291
+            return $appData;
292
+        }, $apps);
293
+
294
+        usort($apps, [$this, 'sortApps']);
295
+
296
+        return new JSONResponse(['apps' => $apps, 'status' => 'success']);
297
+    }
298
+
299
+    /**
300
+     * Get all apps for a category from the app store
301
+     *
302
+     * @param string $requestedCategory
303
+     * @return array
304
+     * @throws \Exception
305
+     */
306
+    private function getAppsForCategory($requestedCategory = ''): array {
307
+        $versionParser = new VersionParser();
308
+        $formattedApps = [];
309
+        $apps = $this->appFetcher->get();
310
+        foreach($apps as $app) {
311
+            // Skip all apps not in the requested category
312
+            if ($requestedCategory !== '') {
313
+                $isInCategory = false;
314
+                foreach($app['categories'] as $category) {
315
+                    if($category === $requestedCategory) {
316
+                        $isInCategory = true;
317
+                    }
318
+                }
319
+                if(!$isInCategory) {
320
+                    continue;
321
+                }
322
+            }
323
+
324
+            if (!isset($app['releases'][0]['rawPlatformVersionSpec'])) {
325
+                continue;
326
+            }
327
+            $nextCloudVersion = $versionParser->getVersion($app['releases'][0]['rawPlatformVersionSpec']);
328
+            $nextCloudVersionDependencies = [];
329
+            if($nextCloudVersion->getMinimumVersion() !== '') {
330
+                $nextCloudVersionDependencies['nextcloud']['@attributes']['min-version'] = $nextCloudVersion->getMinimumVersion();
331
+            }
332
+            if($nextCloudVersion->getMaximumVersion() !== '') {
333
+                $nextCloudVersionDependencies['nextcloud']['@attributes']['max-version'] = $nextCloudVersion->getMaximumVersion();
334
+            }
335
+            $phpVersion = $versionParser->getVersion($app['releases'][0]['rawPhpVersionSpec']);
336
+            $existsLocally = \OC_App::getAppPath($app['id']) !== false;
337
+            $phpDependencies = [];
338
+            if($phpVersion->getMinimumVersion() !== '') {
339
+                $phpDependencies['php']['@attributes']['min-version'] = $phpVersion->getMinimumVersion();
340
+            }
341
+            if($phpVersion->getMaximumVersion() !== '') {
342
+                $phpDependencies['php']['@attributes']['max-version'] = $phpVersion->getMaximumVersion();
343
+            }
344
+            if(isset($app['releases'][0]['minIntSize'])) {
345
+                $phpDependencies['php']['@attributes']['min-int-size'] = $app['releases'][0]['minIntSize'];
346
+            }
347
+            $authors = '';
348
+            foreach($app['authors'] as $key => $author) {
349
+                $authors .= $author['name'];
350
+                if($key !== count($app['authors']) - 1) {
351
+                    $authors .= ', ';
352
+                }
353
+            }
354
+
355
+            $currentLanguage = substr(\OC::$server->getL10NFactory()->findLanguage(), 0, 2);
356
+            $enabledValue = $this->config->getAppValue($app['id'], 'enabled', 'no');
357
+            $groups = null;
358
+            if($enabledValue !== 'no' && $enabledValue !== 'yes') {
359
+                $groups = $enabledValue;
360
+            }
361
+
362
+            $currentVersion = '';
363
+            if($this->appManager->isInstalled($app['id'])) {
364
+                $currentVersion = $this->appManager->getAppVersion($app['id']);
365
+            } else {
366
+                $currentLanguage = $app['releases'][0]['version'];
367
+            }
368
+
369
+            $formattedApps[] = [
370
+                'id' => $app['id'],
371
+                'name' => isset($app['translations'][$currentLanguage]['name']) ? $app['translations'][$currentLanguage]['name'] : $app['translations']['en']['name'],
372
+                'description' => isset($app['translations'][$currentLanguage]['description']) ? $app['translations'][$currentLanguage]['description'] : $app['translations']['en']['description'],
373
+                'summary' => isset($app['translations'][$currentLanguage]['summary']) ? $app['translations'][$currentLanguage]['summary'] : $app['translations']['en']['summary'],
374
+                'license' => $app['releases'][0]['licenses'],
375
+                'author' => $authors,
376
+                'shipped' => false,
377
+                'version' => $currentVersion,
378
+                'default_enable' => '',
379
+                'types' => [],
380
+                'documentation' => [
381
+                    'admin' => $app['adminDocs'],
382
+                    'user' => $app['userDocs'],
383
+                    'developer' => $app['developerDocs']
384
+                ],
385
+                'website' => $app['website'],
386
+                'bugs' => $app['issueTracker'],
387
+                'detailpage' => $app['website'],
388
+                'dependencies' => array_merge(
389
+                    $nextCloudVersionDependencies,
390
+                    $phpDependencies
391
+                ),
392
+                'level' => ($app['isFeatured'] === true) ? 200 : 100,
393
+                'missingMaxOwnCloudVersion' => false,
394
+                'missingMinOwnCloudVersion' => false,
395
+                'canInstall' => true,
396
+                'screenshot' => isset($app['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/'.base64_encode($app['screenshots'][0]['url']) : '',
397
+                'score' => $app['ratingOverall'],
398
+                'ratingNumOverall' => $app['ratingNumOverall'],
399
+                'ratingNumThresholdReached' => $app['ratingNumOverall'] > 5,
400
+                'removable' => $existsLocally,
401
+                'active' => $this->appManager->isEnabledForUser($app['id']),
402
+                'needsDownload' => !$existsLocally,
403
+                'groups' => $groups,
404
+                'fromAppStore' => true,
405
+                'appstoreData' => $app,
406
+            ];
407
+        }
408
+
409
+        return $formattedApps;
410
+    }
411
+
412
+    /**
413
+     * @PasswordConfirmationRequired
414
+     *
415
+     * @param string $appId
416
+     * @param array $groups
417
+     * @return JSONResponse
418
+     */
419
+    public function enableApp(string $appId, array $groups = []): JSONResponse {
420
+        return $this->enableApps([$appId], $groups);
421
+    }
422
+
423
+    /**
424
+     * Enable one or more apps
425
+     *
426
+     * apps will be enabled for specific groups only if $groups is defined
427
+     *
428
+     * @PasswordConfirmationRequired
429
+     * @param array $appIds
430
+     * @param array $groups
431
+     * @return JSONResponse
432
+     */
433
+    public function enableApps(array $appIds, array $groups = []): JSONResponse {
434
+        try {
435
+            $updateRequired = false;
436
+
437
+            foreach ($appIds as $appId) {
438
+                $appId = OC_App::cleanAppId($appId);
439
+
440
+                // Check if app is already downloaded
441
+                /** @var Installer $installer */
442
+                $installer = \OC::$server->query(Installer::class);
443
+                $isDownloaded = $installer->isDownloaded($appId);
444
+
445
+                if(!$isDownloaded) {
446
+                    $installer->downloadApp($appId);
447
+                }
448
+
449
+                $installer->installApp($appId);
450
+
451
+                if (count($groups) > 0) {
452
+                    $this->appManager->enableAppForGroups($appId, $this->getGroupList($groups));
453
+                } else {
454
+                    $this->appManager->enableApp($appId);
455
+                }
456
+                if (\OC_App::shouldUpgrade($appId)) {
457
+                    $updateRequired = true;
458
+                }
459
+            }
460
+            return new JSONResponse(['data' => ['update_required' => $updateRequired]]);
461
+
462
+        } catch (\Exception $e) {
463
+            $this->logger->logException($e);
464
+            return new JSONResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR);
465
+        }
466
+    }
467
+
468
+    private function getGroupList(array $groups) {
469
+        $groupManager = \OC::$server->getGroupManager();
470
+        $groupsList = [];
471
+        foreach ($groups as $group) {
472
+            $groupItem = $groupManager->get($group);
473
+            if ($groupItem instanceof \OCP\IGroup) {
474
+                $groupsList[] = $groupManager->get($group);
475
+            }
476
+        }
477
+        return $groupsList;
478
+    }
479
+
480
+    /**
481
+     * @PasswordConfirmationRequired
482
+     *
483
+     * @param string $appId
484
+     * @return JSONResponse
485
+     */
486
+    public function disableApp(string $appId): JSONResponse {
487
+        return $this->disableApps([$appId]);
488
+    }
489
+
490
+    /**
491
+     * @PasswordConfirmationRequired
492
+     *
493
+     * @param array $appIds
494
+     * @return JSONResponse
495
+     */
496
+    public function disableApps(array $appIds): JSONResponse {
497
+        try {
498
+            foreach ($appIds as $appId) {
499
+                $appId = OC_App::cleanAppId($appId);
500
+                $this->appManager->disableApp($appId);
501
+            }
502
+            return new JSONResponse([]);
503
+        } catch (\Exception $e) {
504
+            $this->logger->logException($e);
505
+            return new JSONResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR);
506
+        }
507
+    }
508
+
509
+    /**
510
+     * @PasswordConfirmationRequired
511
+     *
512
+     * @param string $appId
513
+     * @return JSONResponse
514
+     */
515
+    public function uninstallApp(string $appId): JSONResponse {
516
+        $appId = OC_App::cleanAppId($appId);
517
+        $result = $this->installer->removeApp($appId);
518
+        if($result !== false) {
519
+            $this->appManager->clearAppsCache();
520
+            return new JSONResponse(['data' => ['appid' => $appId]]);
521
+        }
522
+        return new JSONResponse(['data' => ['message' => $this->l10n->t('Couldn\'t remove app.')]], Http::STATUS_INTERNAL_SERVER_ERROR);
523
+    }
524
+
525
+    /**
526
+     * @param string $appId
527
+     * @return JSONResponse
528
+     */
529
+    public function updateApp(string $appId): JSONResponse {
530
+        $appId = OC_App::cleanAppId($appId);
531
+
532
+        $this->config->setSystemValue('maintenance', true);
533
+        try {
534
+            $result = $this->installer->updateAppstoreApp($appId);
535
+            $this->config->setSystemValue('maintenance', false);
536
+        } catch (\Exception $ex) {
537
+            $this->config->setSystemValue('maintenance', false);
538
+            return new JSONResponse(['data' => ['message' => $ex->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR);
539
+        }
540
+
541
+        if ($result !== false) {
542
+            return new JSONResponse(['data' => ['appid' => $appId]]);
543
+        }
544
+        return new JSONResponse(['data' => ['message' => $this->l10n->t('Couldn\'t update app.')]], Http::STATUS_INTERNAL_SERVER_ERROR);
545
+    }
546
+
547
+    private function sortApps($a, $b) {
548
+        $a = (string)$a['name'];
549
+        $b = (string)$b['name'];
550
+        if ($a === $b) {
551
+            return 0;
552
+        }
553
+        return ($a < $b) ? -1 : 1;
554
+    }
555
+
556
+    public function force(string $appId): JSONResponse {
557
+        $appId = OC_App::cleanAppId($appId);
558
+        $this->appManager->ignoreNextcloudRequirementForApp($appId);
559
+        return new JSONResponse();
560
+    }
561 561
 
562 562
 }
Please login to merge, or discard this patch.
Spacing   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -149,9 +149,9 @@  discard block
 block discarded – undo
149 149
 	private function getAppsWithUpdates() {
150 150
 		$appClass = new \OC_App();
151 151
 		$apps = $appClass->listAllApps();
152
-		foreach($apps as $key => $app) {
152
+		foreach ($apps as $key => $app) {
153 153
 			$newVersion = $this->installer->isUpdateAvailable($app['id']);
154
-			if($newVersion === false) {
154
+			if ($newVersion === false) {
155 155
 				unset($apps[$key]);
156 156
 			}
157 157
 		}
@@ -186,7 +186,7 @@  discard block
 block discarded – undo
186 186
 
187 187
 		$formattedCategories = [];
188 188
 		$categories = $this->categoryFetcher->get();
189
-		foreach($categories as $category) {
189
+		foreach ($categories as $category) {
190 190
 			$formattedCategories[] = [
191 191
 				'id' => $category['id'],
192 192
 				'ident' => $category['id'],
@@ -217,10 +217,10 @@  discard block
 block discarded – undo
217 217
 
218 218
 		// add bundle information
219 219
 		$bundles = $this->bundleFetcher->getBundles();
220
-		foreach($bundles as $bundle) {
221
-			foreach($bundle->getAppIdentifiers() as $identifier) {
222
-				foreach($this->allApps as &$app) {
223
-					if($app['id'] === $identifier) {
220
+		foreach ($bundles as $bundle) {
221
+			foreach ($bundle->getAppIdentifiers() as $identifier) {
222
+				foreach ($this->allApps as &$app) {
223
+					if ($app['id'] === $identifier) {
224 224
 						$app['bundleIds'][] = $bundle->getIdentifier();
225 225
 						continue;
226 226
 					}
@@ -247,15 +247,15 @@  discard block
 block discarded – undo
247 247
 		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($this->config), $this->l10n);
248 248
 
249 249
 		// Extend existing app details
250
-		$apps = array_map(function ($appData) use ($dependencyAnalyzer) {
250
+		$apps = array_map(function($appData) use ($dependencyAnalyzer) {
251 251
 			if (isset($appData['appstoreData'])) {
252 252
 				$appstoreData = $appData['appstoreData'];
253
-				$appData['screenshot'] = isset($appstoreData['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/' . base64_encode($appstoreData['screenshots'][0]['url']) : '';
253
+				$appData['screenshot'] = isset($appstoreData['screenshots'][0]['url']) ? 'https://usercontent.apps.nextcloud.com/'.base64_encode($appstoreData['screenshots'][0]['url']) : '';
254 254
 				$appData['category'] = $appstoreData['categories'];
255 255
 			}
256 256
 
257 257
 			$newVersion = $this->installer->isUpdateAvailable($appData['id']);
258
-			if($newVersion) {
258
+			if ($newVersion) {
259 259
 				$appData['update'] = $newVersion;
260 260
 			}
261 261
 
@@ -307,16 +307,16 @@  discard block
 block discarded – undo
307 307
 		$versionParser = new VersionParser();
308 308
 		$formattedApps = [];
309 309
 		$apps = $this->appFetcher->get();
310
-		foreach($apps as $app) {
310
+		foreach ($apps as $app) {
311 311
 			// Skip all apps not in the requested category
312 312
 			if ($requestedCategory !== '') {
313 313
 				$isInCategory = false;
314
-				foreach($app['categories'] as $category) {
315
-					if($category === $requestedCategory) {
314
+				foreach ($app['categories'] as $category) {
315
+					if ($category === $requestedCategory) {
316 316
 						$isInCategory = true;
317 317
 					}
318 318
 				}
319
-				if(!$isInCategory) {
319
+				if (!$isInCategory) {
320 320
 					continue;
321 321
 				}
322 322
 			}
@@ -326,28 +326,28 @@  discard block
 block discarded – undo
326 326
 			}
327 327
 			$nextCloudVersion = $versionParser->getVersion($app['releases'][0]['rawPlatformVersionSpec']);
328 328
 			$nextCloudVersionDependencies = [];
329
-			if($nextCloudVersion->getMinimumVersion() !== '') {
329
+			if ($nextCloudVersion->getMinimumVersion() !== '') {
330 330
 				$nextCloudVersionDependencies['nextcloud']['@attributes']['min-version'] = $nextCloudVersion->getMinimumVersion();
331 331
 			}
332
-			if($nextCloudVersion->getMaximumVersion() !== '') {
332
+			if ($nextCloudVersion->getMaximumVersion() !== '') {
333 333
 				$nextCloudVersionDependencies['nextcloud']['@attributes']['max-version'] = $nextCloudVersion->getMaximumVersion();
334 334
 			}
335 335
 			$phpVersion = $versionParser->getVersion($app['releases'][0]['rawPhpVersionSpec']);
336 336
 			$existsLocally = \OC_App::getAppPath($app['id']) !== false;
337 337
 			$phpDependencies = [];
338
-			if($phpVersion->getMinimumVersion() !== '') {
338
+			if ($phpVersion->getMinimumVersion() !== '') {
339 339
 				$phpDependencies['php']['@attributes']['min-version'] = $phpVersion->getMinimumVersion();
340 340
 			}
341
-			if($phpVersion->getMaximumVersion() !== '') {
341
+			if ($phpVersion->getMaximumVersion() !== '') {
342 342
 				$phpDependencies['php']['@attributes']['max-version'] = $phpVersion->getMaximumVersion();
343 343
 			}
344
-			if(isset($app['releases'][0]['minIntSize'])) {
344
+			if (isset($app['releases'][0]['minIntSize'])) {
345 345
 				$phpDependencies['php']['@attributes']['min-int-size'] = $app['releases'][0]['minIntSize'];
346 346
 			}
347 347
 			$authors = '';
348
-			foreach($app['authors'] as $key => $author) {
348
+			foreach ($app['authors'] as $key => $author) {
349 349
 				$authors .= $author['name'];
350
-				if($key !== count($app['authors']) - 1) {
350
+				if ($key !== count($app['authors']) - 1) {
351 351
 					$authors .= ', ';
352 352
 				}
353 353
 			}
@@ -355,12 +355,12 @@  discard block
 block discarded – undo
355 355
 			$currentLanguage = substr(\OC::$server->getL10NFactory()->findLanguage(), 0, 2);
356 356
 			$enabledValue = $this->config->getAppValue($app['id'], 'enabled', 'no');
357 357
 			$groups = null;
358
-			if($enabledValue !== 'no' && $enabledValue !== 'yes') {
358
+			if ($enabledValue !== 'no' && $enabledValue !== 'yes') {
359 359
 				$groups = $enabledValue;
360 360
 			}
361 361
 
362 362
 			$currentVersion = '';
363
-			if($this->appManager->isInstalled($app['id'])) {
363
+			if ($this->appManager->isInstalled($app['id'])) {
364 364
 				$currentVersion = $this->appManager->getAppVersion($app['id']);
365 365
 			} else {
366 366
 				$currentLanguage = $app['releases'][0]['version'];
@@ -442,7 +442,7 @@  discard block
 block discarded – undo
442 442
 				$installer = \OC::$server->query(Installer::class);
443 443
 				$isDownloaded = $installer->isDownloaded($appId);
444 444
 
445
-				if(!$isDownloaded) {
445
+				if (!$isDownloaded) {
446 446
 					$installer->downloadApp($appId);
447 447
 				}
448 448
 
@@ -515,7 +515,7 @@  discard block
 block discarded – undo
515 515
 	public function uninstallApp(string $appId): JSONResponse {
516 516
 		$appId = OC_App::cleanAppId($appId);
517 517
 		$result = $this->installer->removeApp($appId);
518
-		if($result !== false) {
518
+		if ($result !== false) {
519 519
 			$this->appManager->clearAppsCache();
520 520
 			return new JSONResponse(['data' => ['appid' => $appId]]);
521 521
 		}
@@ -545,8 +545,8 @@  discard block
 block discarded – undo
545 545
 	}
546 546
 
547 547
 	private function sortApps($a, $b) {
548
-		$a = (string)$a['name'];
549
-		$b = (string)$b['name'];
548
+		$a = (string) $a['name'];
549
+		$b = (string) $b['name'];
550 550
 		if ($a === $b) {
551 551
 			return 0;
552 552
 		}
Please login to merge, or discard this patch.
apps/workflowengine/lib/Check/AbstractStringCheck.php 1 patch
Indentation   +82 added lines, -82 removed lines patch added patch discarded remove patch
@@ -27,96 +27,96 @@
 block discarded – undo
27 27
 
28 28
 abstract class AbstractStringCheck implements ICheck {
29 29
 
30
-	/** @var array[] Nested array: [Pattern => [ActualValue => Regex Result]] */
31
-	protected $matches;
30
+    /** @var array[] Nested array: [Pattern => [ActualValue => Regex Result]] */
31
+    protected $matches;
32 32
 
33
-	/** @var IL10N */
34
-	protected $l;
33
+    /** @var IL10N */
34
+    protected $l;
35 35
 
36
-	/**
37
-	 * @param IL10N $l
38
-	 */
39
-	public function __construct(IL10N $l) {
40
-		$this->l = $l;
41
-	}
36
+    /**
37
+     * @param IL10N $l
38
+     */
39
+    public function __construct(IL10N $l) {
40
+        $this->l = $l;
41
+    }
42 42
 
43
-	/**
44
-	 * @return string
45
-	 */
46
-	abstract protected function getActualValue();
43
+    /**
44
+     * @return string
45
+     */
46
+    abstract protected function getActualValue();
47 47
 
48
-	/**
49
-	 * @param string $operator
50
-	 * @param string $value
51
-	 * @return bool
52
-	 */
53
-	public function executeCheck($operator, $value) {
54
-		$actualValue = $this->getActualValue();
55
-		return $this->executeStringCheck($operator, $value, $actualValue);
56
-	}
48
+    /**
49
+     * @param string $operator
50
+     * @param string $value
51
+     * @return bool
52
+     */
53
+    public function executeCheck($operator, $value) {
54
+        $actualValue = $this->getActualValue();
55
+        return $this->executeStringCheck($operator, $value, $actualValue);
56
+    }
57 57
 
58
-	/**
59
-	 * @param string $operator
60
-	 * @param string $checkValue
61
-	 * @param string $actualValue
62
-	 * @return bool
63
-	 */
64
-	protected function executeStringCheck($operator, $checkValue, $actualValue) {
65
-		if ($operator === 'is') {
66
-			return $checkValue === $actualValue;
67
-		} else if ($operator === '!is') {
68
-			return $checkValue !== $actualValue;
69
-		} else {
70
-			$match = $this->match($checkValue, $actualValue);
71
-			if ($operator === 'matches') {
72
-				return $match === 1;
73
-			} else {
74
-				return $match === 0;
75
-			}
76
-		}
77
-	}
58
+    /**
59
+     * @param string $operator
60
+     * @param string $checkValue
61
+     * @param string $actualValue
62
+     * @return bool
63
+     */
64
+    protected function executeStringCheck($operator, $checkValue, $actualValue) {
65
+        if ($operator === 'is') {
66
+            return $checkValue === $actualValue;
67
+        } else if ($operator === '!is') {
68
+            return $checkValue !== $actualValue;
69
+        } else {
70
+            $match = $this->match($checkValue, $actualValue);
71
+            if ($operator === 'matches') {
72
+                return $match === 1;
73
+            } else {
74
+                return $match === 0;
75
+            }
76
+        }
77
+    }
78 78
 
79
-	/**
80
-	 * @param string $operator
81
-	 * @param string $value
82
-	 * @throws \UnexpectedValueException
83
-	 */
84
-	public function validateCheck($operator, $value) {
85
-		if (!in_array($operator, ['is', '!is', 'matches', '!matches'])) {
86
-			throw new \UnexpectedValueException($this->l->t('The given operator is invalid'), 1);
87
-		}
79
+    /**
80
+     * @param string $operator
81
+     * @param string $value
82
+     * @throws \UnexpectedValueException
83
+     */
84
+    public function validateCheck($operator, $value) {
85
+        if (!in_array($operator, ['is', '!is', 'matches', '!matches'])) {
86
+            throw new \UnexpectedValueException($this->l->t('The given operator is invalid'), 1);
87
+        }
88 88
 
89
-		if (in_array($operator, ['matches', '!matches']) &&
90
-			  @preg_match($value, null) === false) {
91
-			throw new \UnexpectedValueException($this->l->t('The given regular expression is invalid'), 2);
92
-		}
93
-	}
89
+        if (in_array($operator, ['matches', '!matches']) &&
90
+              @preg_match($value, null) === false) {
91
+            throw new \UnexpectedValueException($this->l->t('The given regular expression is invalid'), 2);
92
+        }
93
+    }
94 94
 
95
-	public function supportedEntities(): array {
96
-		// universal by default
97
-		return [];
98
-	}
95
+    public function supportedEntities(): array {
96
+        // universal by default
97
+        return [];
98
+    }
99 99
 
100
-	public function isAvailableForScope(int $scope): bool {
101
-		// admin only by default
102
-		return $scope === IManager::SCOPE_ADMIN;
103
-	}
100
+    public function isAvailableForScope(int $scope): bool {
101
+        // admin only by default
102
+        return $scope === IManager::SCOPE_ADMIN;
103
+    }
104 104
 
105
-	/**
106
-	 * @param string $pattern
107
-	 * @param string $subject
108
-	 * @return int|bool
109
-	 */
110
-	protected function match($pattern, $subject) {
111
-		$patternHash = md5($pattern);
112
-		$subjectHash = md5($subject);
113
-		if (isset($this->matches[$patternHash][$subjectHash])) {
114
-			return $this->matches[$patternHash][$subjectHash];
115
-		}
116
-		if (!isset($this->matches[$patternHash])) {
117
-			$this->matches[$patternHash] = [];
118
-		}
119
-		$this->matches[$patternHash][$subjectHash] = preg_match($pattern, $subject);
120
-		return $this->matches[$patternHash][$subjectHash];
121
-	}
105
+    /**
106
+     * @param string $pattern
107
+     * @param string $subject
108
+     * @return int|bool
109
+     */
110
+    protected function match($pattern, $subject) {
111
+        $patternHash = md5($pattern);
112
+        $subjectHash = md5($subject);
113
+        if (isset($this->matches[$patternHash][$subjectHash])) {
114
+            return $this->matches[$patternHash][$subjectHash];
115
+        }
116
+        if (!isset($this->matches[$patternHash])) {
117
+            $this->matches[$patternHash] = [];
118
+        }
119
+        $this->matches[$patternHash][$subjectHash] = preg_match($pattern, $subject);
120
+        return $this->matches[$patternHash][$subjectHash];
121
+    }
122 122
 }
Please login to merge, or discard this patch.
apps/workflowengine/lib/Settings/ASettings.php 2 patches
Indentation   +152 added lines, -152 removed lines patch added patch discarded remove patch
@@ -41,156 +41,156 @@
 block discarded – undo
41 41
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
42 42
 
43 43
 abstract class ASettings implements ISettings {
44
-	/** @var IL10N */
45
-	private $l10n;
46
-
47
-	/** @var string */
48
-	private $appName;
49
-
50
-	/** @var EventDispatcherInterface */
51
-	private $eventDispatcher;
52
-
53
-	/** @var Manager */
54
-	protected $manager;
55
-
56
-	/** @var IInitialStateService */
57
-	private $initialStateService;
58
-
59
-	/** @var IConfig */
60
-	private $config;
61
-
62
-	/**
63
-	 * @param string $appName
64
-	 * @param IL10N $l
65
-	 * @param EventDispatcherInterface $eventDispatcher
66
-	 * @param Manager $manager
67
-	 * @param IInitialStateService $initialStateService
68
-	 * @param IConfig $config
69
-	 */
70
-	public function __construct(
71
-		$appName,
72
-		IL10N $l,
73
-		EventDispatcherInterface $eventDispatcher,
74
-		Manager $manager,
75
-		IInitialStateService $initialStateService,
76
-		IConfig $config
77
-	) {
78
-		$this->appName = $appName;
79
-		$this->l10n = $l;
80
-		$this->eventDispatcher = $eventDispatcher;
81
-		$this->manager = $manager;
82
-		$this->initialStateService = $initialStateService;
83
-		$this->config = $config;
84
-	}
85
-
86
-	abstract function getScope(): int;
87
-
88
-	/**
89
-	 * @return TemplateResponse
90
-	 */
91
-	public function getForm() {
92
-		$this->eventDispatcher->dispatch('OCP\WorkflowEngine::loadAdditionalSettingScripts');
93
-
94
-		$entities = $this->manager->getEntitiesList();
95
-		$this->initialStateService->provideInitialState(
96
-			Application::APP_ID,
97
-			'entities',
98
-			$this->entitiesToArray($entities)
99
-		);
100
-
101
-		$operators = $this->manager->getOperatorList();
102
-		$this->initialStateService->provideInitialState(
103
-			Application::APP_ID,
104
-			'operators',
105
-			$this->operatorsToArray($operators)
106
-		);
107
-
108
-		$checks = $this->manager->getCheckList();
109
-		$this->initialStateService->provideInitialState(
110
-			Application::APP_ID,
111
-			'checks',
112
-			$this->checksToArray($checks)
113
-		);
114
-
115
-		$this->initialStateService->provideInitialState(
116
-			Application::APP_ID,
117
-			'scope',
118
-			$this->getScope()
119
-		);
120
-
121
-		$this->initialStateService->provideInitialState(
122
-			Application::APP_ID,
123
-			'appstoreenabled',
124
-			$this->config->getSystemValueBool('appstoreenabled', true)
125
-		);
126
-
127
-		return new TemplateResponse(Application::APP_ID, 'settings', [], 'blank');
128
-	}
129
-
130
-	/**
131
-	 * @return string the section ID, e.g. 'sharing'
132
-	 */
133
-	public function getSection() {
134
-		return 'workflow';
135
-	}
136
-
137
-	/**
138
-	 * @return int whether the form should be rather on the top or bottom of
139
-	 * the admin section. The forms are arranged in ascending order of the
140
-	 * priority values. It is required to return a value between 0 and 100.
141
-	 *
142
-	 * E.g.: 70
143
-	 */
144
-	public function getPriority() {
145
-		return 0;
146
-	}
147
-
148
-	private function entitiesToArray(array $entities) {
149
-		return array_map(function (IEntity $entity) {
150
-			$events = array_map(function (IEntityEvent $entityEvent) {
151
-				return [
152
-					'eventName' => $entityEvent->getEventName(),
153
-					'displayName' => $entityEvent->getDisplayName()
154
-				];
155
-			}, $entity->getEvents());
156
-
157
-			return [
158
-				'id' => get_class($entity),
159
-				'icon' => $entity->getIcon(),
160
-				'name' => $entity->getName(),
161
-				'events' => $events,
162
-			];
163
-		}, $entities);
164
-	}
165
-
166
-	private function operatorsToArray(array $operators) {
167
-		$operators = array_filter($operators, function (IOperation $operator) {
168
-			return $operator->isAvailableForScope($this->getScope());
169
-		});
170
-
171
-		return array_map(function (IOperation $operator) {
172
-			return [
173
-				'id' => get_class($operator),
174
-				'icon' => $operator->getIcon(),
175
-				'name' => $operator->getDisplayName(),
176
-				'description' => $operator->getDescription(),
177
-				'fixedEntity' => $operator instanceof ISpecificOperation ? $operator->getEntityId() : '',
178
-				'isComplex' => $operator instanceof IComplexOperation,
179
-				'triggerHint' => $operator instanceof IComplexOperation ? $operator->getTriggerHint() : '',
180
-			];
181
-		}, $operators);
182
-	}
183
-
184
-	private function checksToArray(array $checks) {
185
-		$checks = array_filter($checks, function (ICheck $check) {
186
-			return $check->isAvailableForScope($this->getScope());
187
-		});
188
-
189
-		return array_map(function (ICheck $check) {
190
-			return [
191
-				'id' => get_class($check),
192
-				'supportedEntities' => $check->supportedEntities(),
193
-			];
194
-		}, $checks);
195
-	}
44
+    /** @var IL10N */
45
+    private $l10n;
46
+
47
+    /** @var string */
48
+    private $appName;
49
+
50
+    /** @var EventDispatcherInterface */
51
+    private $eventDispatcher;
52
+
53
+    /** @var Manager */
54
+    protected $manager;
55
+
56
+    /** @var IInitialStateService */
57
+    private $initialStateService;
58
+
59
+    /** @var IConfig */
60
+    private $config;
61
+
62
+    /**
63
+     * @param string $appName
64
+     * @param IL10N $l
65
+     * @param EventDispatcherInterface $eventDispatcher
66
+     * @param Manager $manager
67
+     * @param IInitialStateService $initialStateService
68
+     * @param IConfig $config
69
+     */
70
+    public function __construct(
71
+        $appName,
72
+        IL10N $l,
73
+        EventDispatcherInterface $eventDispatcher,
74
+        Manager $manager,
75
+        IInitialStateService $initialStateService,
76
+        IConfig $config
77
+    ) {
78
+        $this->appName = $appName;
79
+        $this->l10n = $l;
80
+        $this->eventDispatcher = $eventDispatcher;
81
+        $this->manager = $manager;
82
+        $this->initialStateService = $initialStateService;
83
+        $this->config = $config;
84
+    }
85
+
86
+    abstract function getScope(): int;
87
+
88
+    /**
89
+     * @return TemplateResponse
90
+     */
91
+    public function getForm() {
92
+        $this->eventDispatcher->dispatch('OCP\WorkflowEngine::loadAdditionalSettingScripts');
93
+
94
+        $entities = $this->manager->getEntitiesList();
95
+        $this->initialStateService->provideInitialState(
96
+            Application::APP_ID,
97
+            'entities',
98
+            $this->entitiesToArray($entities)
99
+        );
100
+
101
+        $operators = $this->manager->getOperatorList();
102
+        $this->initialStateService->provideInitialState(
103
+            Application::APP_ID,
104
+            'operators',
105
+            $this->operatorsToArray($operators)
106
+        );
107
+
108
+        $checks = $this->manager->getCheckList();
109
+        $this->initialStateService->provideInitialState(
110
+            Application::APP_ID,
111
+            'checks',
112
+            $this->checksToArray($checks)
113
+        );
114
+
115
+        $this->initialStateService->provideInitialState(
116
+            Application::APP_ID,
117
+            'scope',
118
+            $this->getScope()
119
+        );
120
+
121
+        $this->initialStateService->provideInitialState(
122
+            Application::APP_ID,
123
+            'appstoreenabled',
124
+            $this->config->getSystemValueBool('appstoreenabled', true)
125
+        );
126
+
127
+        return new TemplateResponse(Application::APP_ID, 'settings', [], 'blank');
128
+    }
129
+
130
+    /**
131
+     * @return string the section ID, e.g. 'sharing'
132
+     */
133
+    public function getSection() {
134
+        return 'workflow';
135
+    }
136
+
137
+    /**
138
+     * @return int whether the form should be rather on the top or bottom of
139
+     * the admin section. The forms are arranged in ascending order of the
140
+     * priority values. It is required to return a value between 0 and 100.
141
+     *
142
+     * E.g.: 70
143
+     */
144
+    public function getPriority() {
145
+        return 0;
146
+    }
147
+
148
+    private function entitiesToArray(array $entities) {
149
+        return array_map(function (IEntity $entity) {
150
+            $events = array_map(function (IEntityEvent $entityEvent) {
151
+                return [
152
+                    'eventName' => $entityEvent->getEventName(),
153
+                    'displayName' => $entityEvent->getDisplayName()
154
+                ];
155
+            }, $entity->getEvents());
156
+
157
+            return [
158
+                'id' => get_class($entity),
159
+                'icon' => $entity->getIcon(),
160
+                'name' => $entity->getName(),
161
+                'events' => $events,
162
+            ];
163
+        }, $entities);
164
+    }
165
+
166
+    private function operatorsToArray(array $operators) {
167
+        $operators = array_filter($operators, function (IOperation $operator) {
168
+            return $operator->isAvailableForScope($this->getScope());
169
+        });
170
+
171
+        return array_map(function (IOperation $operator) {
172
+            return [
173
+                'id' => get_class($operator),
174
+                'icon' => $operator->getIcon(),
175
+                'name' => $operator->getDisplayName(),
176
+                'description' => $operator->getDescription(),
177
+                'fixedEntity' => $operator instanceof ISpecificOperation ? $operator->getEntityId() : '',
178
+                'isComplex' => $operator instanceof IComplexOperation,
179
+                'triggerHint' => $operator instanceof IComplexOperation ? $operator->getTriggerHint() : '',
180
+            ];
181
+        }, $operators);
182
+    }
183
+
184
+    private function checksToArray(array $checks) {
185
+        $checks = array_filter($checks, function (ICheck $check) {
186
+            return $check->isAvailableForScope($this->getScope());
187
+        });
188
+
189
+        return array_map(function (ICheck $check) {
190
+            return [
191
+                'id' => get_class($check),
192
+                'supportedEntities' => $check->supportedEntities(),
193
+            ];
194
+        }, $checks);
195
+    }
196 196
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -146,8 +146,8 @@  discard block
 block discarded – undo
146 146
 	}
147 147
 
148 148
 	private function entitiesToArray(array $entities) {
149
-		return array_map(function (IEntity $entity) {
150
-			$events = array_map(function (IEntityEvent $entityEvent) {
149
+		return array_map(function(IEntity $entity) {
150
+			$events = array_map(function(IEntityEvent $entityEvent) {
151 151
 				return [
152 152
 					'eventName' => $entityEvent->getEventName(),
153 153
 					'displayName' => $entityEvent->getDisplayName()
@@ -164,11 +164,11 @@  discard block
 block discarded – undo
164 164
 	}
165 165
 
166 166
 	private function operatorsToArray(array $operators) {
167
-		$operators = array_filter($operators, function (IOperation $operator) {
167
+		$operators = array_filter($operators, function(IOperation $operator) {
168 168
 			return $operator->isAvailableForScope($this->getScope());
169 169
 		});
170 170
 
171
-		return array_map(function (IOperation $operator) {
171
+		return array_map(function(IOperation $operator) {
172 172
 			return [
173 173
 				'id' => get_class($operator),
174 174
 				'icon' => $operator->getIcon(),
@@ -182,11 +182,11 @@  discard block
 block discarded – undo
182 182
 	}
183 183
 
184 184
 	private function checksToArray(array $checks) {
185
-		$checks = array_filter($checks, function (ICheck $check) {
185
+		$checks = array_filter($checks, function(ICheck $check) {
186 186
 			return $check->isAvailableForScope($this->getScope());
187 187
 		});
188 188
 
189
-		return array_map(function (ICheck $check) {
189
+		return array_map(function(ICheck $check) {
190 190
 			return [
191 191
 				'id' => get_class($check),
192 192
 				'supportedEntities' => $check->supportedEntities(),
Please login to merge, or discard this patch.
apps/accessibility/lib/Controller/ConfigController.php 2 patches
Indentation   +116 added lines, -116 removed lines patch added patch discarded remove patch
@@ -40,121 +40,121 @@
 block discarded – undo
40 40
 
41 41
 class ConfigController extends OCSController {
42 42
 
43
-	/** @var string */
44
-	protected $appName;
45
-
46
-	/** @var string */
47
-	protected $userId;
48
-
49
-	/** @var string */
50
-	protected $serverRoot;
51
-
52
-	/** @var IConfig */
53
-	private $config;
54
-
55
-	/** @var IUserSession */
56
-	private $userSession;
57
-
58
-	/** @var AccessibilityProvider */
59
-	private $accessibilityProvider;
60
-
61
-	/**
62
-	 * Config constructor.
63
-	 *
64
-	 * @param string $appName
65
-	 * @param IRequest $request
66
-	 * @param IConfig $config
67
-	 * @param IUserSession $userSession
68
-	 * @param AccessibilityProvider $accessibilityProvider
69
-	 */
70
-	public function __construct(string $appName,
71
-								IRequest $request,
72
-								IConfig $config,
73
-								IUserSession $userSession,
74
-								AccessibilityProvider $accessibilityProvider) {
75
-		parent::__construct($appName, $request);
76
-		$this->appName               = $appName;
77
-		$this->config                = $config;
78
-		$this->userSession           = $userSession;
79
-		$this->accessibilityProvider = $accessibilityProvider;
80
-		$this->userId				 = $userSession->getUser()->getUID();
81
-	}
82
-
83
-	/**
84
-	 * @NoAdminRequired
85
-	 *
86
-	 * Get user accessibility config
87
-	 *
88
-	 * @param string $key theme or font
89
-	 * @return DataResponse
90
-	 */
91
-	public function getConfig(): DataResponse {
92
-		return new DataResponse([
93
-			'highcontrast' => $this->config->getUserValue($this->userId, $this->appName, 'highcontrast', false),
94
-			'theme' => $this->config->getUserValue($this->userId, $this->appName, 'theme', false),
95
-			'font' => $this->config->getUserValue($this->userId, $this->appName, 'font', false)
96
-		]);
97
-	}
98
-
99
-	/**
100
-	 * @NoAdminRequired
101
-	 *
102
-	 * Set theme or font config
103
-	 *
104
-	 * @param string $key theme or font
105
-	 * @return DataResponse
106
-	 * @throws Exception
107
-	 */
108
-	public function setConfig(string $key, $value): DataResponse {
109
-		if ($key === 'theme' || $key === 'font' || $key === 'highcontrast') {
110
-
111
-			if ($value === false || $value === '') {
112
-				throw new OCSBadRequestException('Invalid value: ' . $value);
113
-			}
114
-
115
-			$themes = $this->accessibilityProvider->getThemes();
116
-			$highcontrast = [$this->accessibilityProvider->getHighContrast()];
117
-			$fonts  = $this->accessibilityProvider->getFonts();
118
-
119
-			$availableOptions = array_map(function ($option) {
120
-				return $option['id'];
121
-			}, array_merge($themes, $highcontrast, $fonts));
122
-
123
-			if (in_array($value, $availableOptions)) {
124
-				$this->config->setUserValue($this->userId, $this->appName, $key, $value);
125
-				return new DataResponse();
126
-			}
127
-
128
-			throw new OCSBadRequestException('Invalid value: ' . $value);
129
-		}
130
-
131
-		throw new OCSBadRequestException('Invalid key: ' . $key);
132
-	}
133
-
134
-	/**
135
-	 * @NoAdminRequired
136
-	 *
137
-	 * Unset theme or font config
138
-	 *
139
-	 * @param string $key theme or font
140
-	 * @return DataResponse
141
-	 * @throws Exception
142
-	 */
143
-	public function deleteConfig(string $key): DataResponse {
144
-		if ($key === 'theme' || $key === 'font' || $key === 'highcontrast') {
145
-
146
-			$this->config->deleteUserValue($this->userId, $this->appName, $key);
147
-			$userValues = $this->config->getUserKeys($this->userId, $this->appName);
148
-
149
-			// remove hash if no settings selected
150
-			if (count($userValues) === 1 && $userValues[0] === 'icons-css') {
151
-				$this->config->deleteUserValue($this->userId, $this->appName, 'icons-css');
152
-			}
153
-
154
-			return new DataResponse();
155
-		}
156
-
157
-		throw new OCSBadRequestException('Invalid key: ' . $key);
158
-	}
43
+    /** @var string */
44
+    protected $appName;
45
+
46
+    /** @var string */
47
+    protected $userId;
48
+
49
+    /** @var string */
50
+    protected $serverRoot;
51
+
52
+    /** @var IConfig */
53
+    private $config;
54
+
55
+    /** @var IUserSession */
56
+    private $userSession;
57
+
58
+    /** @var AccessibilityProvider */
59
+    private $accessibilityProvider;
60
+
61
+    /**
62
+     * Config constructor.
63
+     *
64
+     * @param string $appName
65
+     * @param IRequest $request
66
+     * @param IConfig $config
67
+     * @param IUserSession $userSession
68
+     * @param AccessibilityProvider $accessibilityProvider
69
+     */
70
+    public function __construct(string $appName,
71
+                                IRequest $request,
72
+                                IConfig $config,
73
+                                IUserSession $userSession,
74
+                                AccessibilityProvider $accessibilityProvider) {
75
+        parent::__construct($appName, $request);
76
+        $this->appName               = $appName;
77
+        $this->config                = $config;
78
+        $this->userSession           = $userSession;
79
+        $this->accessibilityProvider = $accessibilityProvider;
80
+        $this->userId				 = $userSession->getUser()->getUID();
81
+    }
82
+
83
+    /**
84
+     * @NoAdminRequired
85
+     *
86
+     * Get user accessibility config
87
+     *
88
+     * @param string $key theme or font
89
+     * @return DataResponse
90
+     */
91
+    public function getConfig(): DataResponse {
92
+        return new DataResponse([
93
+            'highcontrast' => $this->config->getUserValue($this->userId, $this->appName, 'highcontrast', false),
94
+            'theme' => $this->config->getUserValue($this->userId, $this->appName, 'theme', false),
95
+            'font' => $this->config->getUserValue($this->userId, $this->appName, 'font', false)
96
+        ]);
97
+    }
98
+
99
+    /**
100
+     * @NoAdminRequired
101
+     *
102
+     * Set theme or font config
103
+     *
104
+     * @param string $key theme or font
105
+     * @return DataResponse
106
+     * @throws Exception
107
+     */
108
+    public function setConfig(string $key, $value): DataResponse {
109
+        if ($key === 'theme' || $key === 'font' || $key === 'highcontrast') {
110
+
111
+            if ($value === false || $value === '') {
112
+                throw new OCSBadRequestException('Invalid value: ' . $value);
113
+            }
114
+
115
+            $themes = $this->accessibilityProvider->getThemes();
116
+            $highcontrast = [$this->accessibilityProvider->getHighContrast()];
117
+            $fonts  = $this->accessibilityProvider->getFonts();
118
+
119
+            $availableOptions = array_map(function ($option) {
120
+                return $option['id'];
121
+            }, array_merge($themes, $highcontrast, $fonts));
122
+
123
+            if (in_array($value, $availableOptions)) {
124
+                $this->config->setUserValue($this->userId, $this->appName, $key, $value);
125
+                return new DataResponse();
126
+            }
127
+
128
+            throw new OCSBadRequestException('Invalid value: ' . $value);
129
+        }
130
+
131
+        throw new OCSBadRequestException('Invalid key: ' . $key);
132
+    }
133
+
134
+    /**
135
+     * @NoAdminRequired
136
+     *
137
+     * Unset theme or font config
138
+     *
139
+     * @param string $key theme or font
140
+     * @return DataResponse
141
+     * @throws Exception
142
+     */
143
+    public function deleteConfig(string $key): DataResponse {
144
+        if ($key === 'theme' || $key === 'font' || $key === 'highcontrast') {
145
+
146
+            $this->config->deleteUserValue($this->userId, $this->appName, $key);
147
+            $userValues = $this->config->getUserKeys($this->userId, $this->appName);
148
+
149
+            // remove hash if no settings selected
150
+            if (count($userValues) === 1 && $userValues[0] === 'icons-css') {
151
+                $this->config->deleteUserValue($this->userId, $this->appName, 'icons-css');
152
+            }
153
+
154
+            return new DataResponse();
155
+        }
156
+
157
+        throw new OCSBadRequestException('Invalid key: ' . $key);
158
+    }
159 159
 
160 160
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -77,7 +77,7 @@  discard block
 block discarded – undo
77 77
 		$this->config                = $config;
78 78
 		$this->userSession           = $userSession;
79 79
 		$this->accessibilityProvider = $accessibilityProvider;
80
-		$this->userId				 = $userSession->getUser()->getUID();
80
+		$this->userId = $userSession->getUser()->getUID();
81 81
 	}
82 82
 
83 83
 	/**
@@ -109,14 +109,14 @@  discard block
 block discarded – undo
109 109
 		if ($key === 'theme' || $key === 'font' || $key === 'highcontrast') {
110 110
 
111 111
 			if ($value === false || $value === '') {
112
-				throw new OCSBadRequestException('Invalid value: ' . $value);
112
+				throw new OCSBadRequestException('Invalid value: '.$value);
113 113
 			}
114 114
 
115 115
 			$themes = $this->accessibilityProvider->getThemes();
116 116
 			$highcontrast = [$this->accessibilityProvider->getHighContrast()];
117 117
 			$fonts  = $this->accessibilityProvider->getFonts();
118 118
 
119
-			$availableOptions = array_map(function ($option) {
119
+			$availableOptions = array_map(function($option) {
120 120
 				return $option['id'];
121 121
 			}, array_merge($themes, $highcontrast, $fonts));
122 122
 
@@ -125,10 +125,10 @@  discard block
 block discarded – undo
125 125
 				return new DataResponse();
126 126
 			}
127 127
 
128
-			throw new OCSBadRequestException('Invalid value: ' . $value);
128
+			throw new OCSBadRequestException('Invalid value: '.$value);
129 129
 		}
130 130
 
131
-		throw new OCSBadRequestException('Invalid key: ' . $key);
131
+		throw new OCSBadRequestException('Invalid key: '.$key);
132 132
 	}
133 133
 
134 134
 	/**
@@ -154,7 +154,7 @@  discard block
 block discarded – undo
154 154
 			return new DataResponse();
155 155
 		}
156 156
 
157
-		throw new OCSBadRequestException('Invalid key: ' . $key);
157
+		throw new OCSBadRequestException('Invalid key: '.$key);
158 158
 	}
159 159
 
160 160
 }
Please login to merge, or discard this patch.
apps/accessibility/lib/Controller/AccessibilityController.php 1 patch
Indentation   +256 added lines, -256 removed lines patch added patch discarded remove patch
@@ -53,271 +53,271 @@
 block discarded – undo
53 53
 
54 54
 class AccessibilityController extends Controller {
55 55
 
56
-	/** @var string */
57
-	protected $appName;
58
-
59
-	/** @var string */
60
-	protected $serverRoot;
61
-
62
-	/** @var IConfig */
63
-	private $config;
64
-
65
-	/** @var IUserManager */
66
-	private $userManager;
67
-
68
-	/** @var ILogger */
69
-	private $logger;
70
-
71
-	/** @var IURLGenerator */
72
-	private $urlGenerator;
73
-
74
-	/** @var ITimeFactory */
75
-	protected $timeFactory;
76
-
77
-	/** @var IUserSession */
78
-	private $userSession;
79
-
80
-	/** @var IAppManager */
81
-	private $appManager;
82
-
83
-	/** @var IconsCacher */
84
-	protected $iconsCacher;
85
-
86
-	/** @var \OC_Defaults */
87
-	private $defaults;
88
-
89
-	/** @var null|string */
90
-	private $injectedVariables;
91
-
92
-	/**
93
-	 * Account constructor.
94
-	 *
95
-	 * @param string $appName
96
-	 * @param IRequest $request
97
-	 * @param IConfig $config
98
-	 * @param IUserManager $userManager
99
-	 * @param ILogger $logger
100
-	 * @param IURLGenerator $urlGenerator
101
-	 * @param ITimeFactory $timeFactory
102
-	 * @param IUserSession $userSession
103
-	 * @param IAppManager $appManager
104
-	 * @param \OC_Defaults $defaults
105
-	 */
106
-	public function __construct(string $appName,
107
-								IRequest $request,
108
-								IConfig $config,
109
-								IUserManager $userManager,
110
-								ILogger $logger,
111
-								IURLGenerator $urlGenerator,
112
-								ITimeFactory $timeFactory,
113
-								IUserSession $userSession,
114
-								IAppManager $appManager,
115
-								IconsCacher $iconsCacher,
116
-								\OC_Defaults $defaults) {
117
-		parent::__construct($appName, $request);
118
-		$this->appName      = $appName;
119
-		$this->config       = $config;
120
-		$this->userManager  = $userManager;
121
-		$this->logger       = $logger;
122
-		$this->urlGenerator = $urlGenerator;
123
-		$this->timeFactory  = $timeFactory;
124
-		$this->userSession  = $userSession;
125
-		$this->appManager   = $appManager;
126
-		$this->iconsCacher  = $iconsCacher;
127
-		$this->defaults     = $defaults;
128
-
129
-		$this->serverRoot = \OC::$SERVERROOT;
130
-		$this->appRoot    = $this->appManager->getAppPath($this->appName);
131
-	}
132
-
133
-	/**
134
-	 * @NoAdminRequired
135
-	 * @NoCSRFRequired
136
-	 * @NoSameSiteCookieRequired
137
-	 *
138
-	 * @return DataDisplayResponse
139
-	 */
140
-	public function getCss(): DataDisplayResponse {
141
-		$css        = '';
142
-		$imports    = '';
143
-		$userValues = $this->getUserValues();
144
-
145
-		foreach ($userValues as $key => $scssFile) {
146
-			if ($scssFile !== false) {
147
-				if ($scssFile === 'highcontrast' && in_array('dark', $userValues)) {
148
-					$scssFile .= 'dark';
149
-				}
150
-				$imports .= '@import "' . $scssFile . '";';
151
-			}
152
-		}
153
-
154
-		if ($imports !== '') {
155
-			$scss = new Compiler();
156
-			$scss->setImportPaths([
157
-				$this->appRoot . '/css/',
158
-				$this->serverRoot . '/core/css/'
159
-			]);
160
-
161
-			// Continue after throw
162
-			$scss->setIgnoreErrors(true);
163
-			$scss->setFormatter(Crunched::class);
164
-
165
-			// Import theme, variables and compile css4 variables
166
-			try {
167
-				$css .= $scss->compile(
168
-					$imports .
169
-					$this->getInjectedVariables() .
170
-					'@import "variables.scss";' .
171
-					'@import "css-variables.scss";'
172
-				);
173
-			} catch (ParserException $e) {
174
-				$this->logger->error($e->getMessage(), ['app' => 'core']);
175
-			}
176
-		}
177
-
178
-		// We don't want to override vars with url since path is different
179
-		$css = $this->filterOutRule('/--[a-z-:]+url\([^;]+\)/mi', $css);
180
-
181
-		// Rebase all urls
182
-		$appWebRoot = substr($this->appRoot, strlen($this->serverRoot) - strlen(\OC::$WEBROOT));
183
-		$css        = $this->rebaseUrls($css, $appWebRoot . '/css');
184
-
185
-		if (in_array('dark', $userValues) && $this->iconsCacher->getCachedList() && $this->iconsCacher->getCachedList()->getSize() > 0) {
186
-			$iconsCss = $this->invertSvgIconsColor($this->iconsCacher->getCachedList()->getContent());
187
-			$css = $css . $iconsCss;
188
-		}
189
-
190
-		$response = new DataDisplayResponse($css, Http::STATUS_OK, ['Content-Type' => 'text/css']);
191
-
192
-		// Set cache control
193
-		$ttl = 31536000;
194
-		$response->addHeader('Cache-Control', 'max-age=' . $ttl . ', immutable');
195
-		$expires = new \DateTime();
196
-		$expires->setTimestamp($this->timeFactory->getTime());
197
-		$expires->add(new \DateInterval('PT' . $ttl . 'S'));
198
-		$response->addHeader('Expires', $expires->format(\DateTime::RFC1123));
199
-		$response->addHeader('Pragma', 'cache');
200
-
201
-		// store current cache hash
202
-		$this->config->setUserValue($this->userSession->getUser()->getUID(), $this->appName, 'icons-css', md5($css));
203
-
204
-		return $response;
205
-	}
206
-
207
-	/**
208
-	 * @NoCSRFRequired
209
-	 * @PublicPage
210
-	 * @NoSameSiteCookieRequired
211
-	 *
212
-	 * @return DataDownloadResponse
213
-	 */
214
-	public function getJavascript(): DataDownloadResponse {
215
-		$user = $this->userSession->getUser();
216
-
217
-		if ($user === null) {
218
-			$theme = false;
219
-			$highcontrast = false;
220
-		} else {
221
-			$theme = $this->config->getUserValue($user->getUID(), $this->appName, 'theme', false);
222
-			$highcontrast = $this->config->getUserValue($user->getUID(), $this->appName, 'highcontrast', false) !== false;
223
-		}
224
-		if ($theme !== false) {
225
-			$responseJS = '(function() {
56
+    /** @var string */
57
+    protected $appName;
58
+
59
+    /** @var string */
60
+    protected $serverRoot;
61
+
62
+    /** @var IConfig */
63
+    private $config;
64
+
65
+    /** @var IUserManager */
66
+    private $userManager;
67
+
68
+    /** @var ILogger */
69
+    private $logger;
70
+
71
+    /** @var IURLGenerator */
72
+    private $urlGenerator;
73
+
74
+    /** @var ITimeFactory */
75
+    protected $timeFactory;
76
+
77
+    /** @var IUserSession */
78
+    private $userSession;
79
+
80
+    /** @var IAppManager */
81
+    private $appManager;
82
+
83
+    /** @var IconsCacher */
84
+    protected $iconsCacher;
85
+
86
+    /** @var \OC_Defaults */
87
+    private $defaults;
88
+
89
+    /** @var null|string */
90
+    private $injectedVariables;
91
+
92
+    /**
93
+     * Account constructor.
94
+     *
95
+     * @param string $appName
96
+     * @param IRequest $request
97
+     * @param IConfig $config
98
+     * @param IUserManager $userManager
99
+     * @param ILogger $logger
100
+     * @param IURLGenerator $urlGenerator
101
+     * @param ITimeFactory $timeFactory
102
+     * @param IUserSession $userSession
103
+     * @param IAppManager $appManager
104
+     * @param \OC_Defaults $defaults
105
+     */
106
+    public function __construct(string $appName,
107
+                                IRequest $request,
108
+                                IConfig $config,
109
+                                IUserManager $userManager,
110
+                                ILogger $logger,
111
+                                IURLGenerator $urlGenerator,
112
+                                ITimeFactory $timeFactory,
113
+                                IUserSession $userSession,
114
+                                IAppManager $appManager,
115
+                                IconsCacher $iconsCacher,
116
+                                \OC_Defaults $defaults) {
117
+        parent::__construct($appName, $request);
118
+        $this->appName      = $appName;
119
+        $this->config       = $config;
120
+        $this->userManager  = $userManager;
121
+        $this->logger       = $logger;
122
+        $this->urlGenerator = $urlGenerator;
123
+        $this->timeFactory  = $timeFactory;
124
+        $this->userSession  = $userSession;
125
+        $this->appManager   = $appManager;
126
+        $this->iconsCacher  = $iconsCacher;
127
+        $this->defaults     = $defaults;
128
+
129
+        $this->serverRoot = \OC::$SERVERROOT;
130
+        $this->appRoot    = $this->appManager->getAppPath($this->appName);
131
+    }
132
+
133
+    /**
134
+     * @NoAdminRequired
135
+     * @NoCSRFRequired
136
+     * @NoSameSiteCookieRequired
137
+     *
138
+     * @return DataDisplayResponse
139
+     */
140
+    public function getCss(): DataDisplayResponse {
141
+        $css        = '';
142
+        $imports    = '';
143
+        $userValues = $this->getUserValues();
144
+
145
+        foreach ($userValues as $key => $scssFile) {
146
+            if ($scssFile !== false) {
147
+                if ($scssFile === 'highcontrast' && in_array('dark', $userValues)) {
148
+                    $scssFile .= 'dark';
149
+                }
150
+                $imports .= '@import "' . $scssFile . '";';
151
+            }
152
+        }
153
+
154
+        if ($imports !== '') {
155
+            $scss = new Compiler();
156
+            $scss->setImportPaths([
157
+                $this->appRoot . '/css/',
158
+                $this->serverRoot . '/core/css/'
159
+            ]);
160
+
161
+            // Continue after throw
162
+            $scss->setIgnoreErrors(true);
163
+            $scss->setFormatter(Crunched::class);
164
+
165
+            // Import theme, variables and compile css4 variables
166
+            try {
167
+                $css .= $scss->compile(
168
+                    $imports .
169
+                    $this->getInjectedVariables() .
170
+                    '@import "variables.scss";' .
171
+                    '@import "css-variables.scss";'
172
+                );
173
+            } catch (ParserException $e) {
174
+                $this->logger->error($e->getMessage(), ['app' => 'core']);
175
+            }
176
+        }
177
+
178
+        // We don't want to override vars with url since path is different
179
+        $css = $this->filterOutRule('/--[a-z-:]+url\([^;]+\)/mi', $css);
180
+
181
+        // Rebase all urls
182
+        $appWebRoot = substr($this->appRoot, strlen($this->serverRoot) - strlen(\OC::$WEBROOT));
183
+        $css        = $this->rebaseUrls($css, $appWebRoot . '/css');
184
+
185
+        if (in_array('dark', $userValues) && $this->iconsCacher->getCachedList() && $this->iconsCacher->getCachedList()->getSize() > 0) {
186
+            $iconsCss = $this->invertSvgIconsColor($this->iconsCacher->getCachedList()->getContent());
187
+            $css = $css . $iconsCss;
188
+        }
189
+
190
+        $response = new DataDisplayResponse($css, Http::STATUS_OK, ['Content-Type' => 'text/css']);
191
+
192
+        // Set cache control
193
+        $ttl = 31536000;
194
+        $response->addHeader('Cache-Control', 'max-age=' . $ttl . ', immutable');
195
+        $expires = new \DateTime();
196
+        $expires->setTimestamp($this->timeFactory->getTime());
197
+        $expires->add(new \DateInterval('PT' . $ttl . 'S'));
198
+        $response->addHeader('Expires', $expires->format(\DateTime::RFC1123));
199
+        $response->addHeader('Pragma', 'cache');
200
+
201
+        // store current cache hash
202
+        $this->config->setUserValue($this->userSession->getUser()->getUID(), $this->appName, 'icons-css', md5($css));
203
+
204
+        return $response;
205
+    }
206
+
207
+    /**
208
+     * @NoCSRFRequired
209
+     * @PublicPage
210
+     * @NoSameSiteCookieRequired
211
+     *
212
+     * @return DataDownloadResponse
213
+     */
214
+    public function getJavascript(): DataDownloadResponse {
215
+        $user = $this->userSession->getUser();
216
+
217
+        if ($user === null) {
218
+            $theme = false;
219
+            $highcontrast = false;
220
+        } else {
221
+            $theme = $this->config->getUserValue($user->getUID(), $this->appName, 'theme', false);
222
+            $highcontrast = $this->config->getUserValue($user->getUID(), $this->appName, 'highcontrast', false) !== false;
223
+        }
224
+        if ($theme !== false) {
225
+            $responseJS = '(function() {
226 226
 	OCA.Accessibility = {
227 227
 		highcontrast: ' . json_encode($highcontrast) . ',
228 228
 		theme: ' . json_encode($theme) . ',
229 229
 	};
230 230
 	document.body.classList.add(' . json_encode($theme) . ');
231 231
 })();';
232
-		} else {
233
-			$responseJS = '(function() {
232
+        } else {
233
+            $responseJS = '(function() {
234 234
 	OCA.Accessibility = {
235 235
 		highcontrast: ' . json_encode($highcontrast) . ',
236 236
 		theme: ' . json_encode($theme) . ',
237 237
 	};
238 238
 })();';
239
-		}
240
-		$response = new DataDownloadResponse($responseJS, 'javascript', 'text/javascript');
241
-		$response->cacheFor(3600);
242
-		return $response;
243
-	}
244
-
245
-	/**
246
-	 * Return an array with the user theme & font settings
247
-	 *
248
-	 * @return array
249
-	 */
250
-	private function getUserValues(): array {
251
-		$userTheme = $this->config->getUserValue($this->userSession->getUser()->getUID(), $this->appName, 'theme', false);
252
-		$userFont  = $this->config->getUserValue($this->userSession->getUser()->getUID(), $this->appName, 'font', false);
253
-		$userHighContrast = $this->config->getUserValue($this->userSession->getUser()->getUID(), $this->appName, 'highcontrast', false);
254
-
255
-		return [$userTheme, $userHighContrast, $userFont];
256
-	}
257
-
258
-	/**
259
-	 * Remove all matches from the $rule regex
260
-	 *
261
-	 * @param string $rule regex to match
262
-	 * @param string $css string to parse
263
-	 * @return string
264
-	 */
265
-	private function filterOutRule(string $rule, string $css): string {
266
-		return preg_replace($rule, '', $css);
267
-	}
268
-
269
-	/**
270
-	 * Add the correct uri prefix to make uri valid again
271
-	 *
272
-	 * @param string $css
273
-	 * @param string $webDir
274
-	 * @return string
275
-	 */
276
-	private function rebaseUrls(string $css, string $webDir): string {
277
-		$re    = '/url\([\'"]([^\/][\.\w?=\/-]*)[\'"]\)/x';
278
-		$subst = 'url(\'' . $webDir . '/$1\')';
279
-
280
-		return preg_replace($re, $subst, $css);
281
-	}
282
-
283
-	/**
284
-	 * Remove all matches from the $rule regex
285
-	 *
286
-	 * @param string $css string to parse
287
-	 * @return string
288
-	 */
289
-	private function invertSvgIconsColor(string $css) {
290
-		return str_replace(
291
-			['color=000&', 'color=fff&', 'color=***&'],
292
-			['color=***&', 'color=000&', 'color=fff&'],
293
-			str_replace(
294
-				['color=000000&', 'color=ffffff&', 'color=******&'],
295
-				['color=******&', 'color=000000&', 'color=ffffff&'],
296
-				$css
297
-			)
298
-		);
299
-	}
300
-
301
-	/**
302
-	 * @return string SCSS code for variables from OC_Defaults
303
-	 */
304
-	private function getInjectedVariables(): string {
305
-		if ($this->injectedVariables !== null) {
306
-			return $this->injectedVariables;
307
-		}
308
-		$variables = '';
309
-		foreach ($this->defaults->getScssVariables() as $key => $value) {
310
-			$variables .= '$' . $key . ': ' . $value . ';';
311
-		}
312
-
313
-		// check for valid variables / otherwise fall back to defaults
314
-		try {
315
-			$scss = new Compiler();
316
-			$scss->compile($variables);
317
-			$this->injectedVariables = $variables;
318
-		} catch (ParserException $e) {
319
-			$this->logger->logException($e, ['app' => 'core']);
320
-		}
321
-		return $variables;
322
-	}
239
+        }
240
+        $response = new DataDownloadResponse($responseJS, 'javascript', 'text/javascript');
241
+        $response->cacheFor(3600);
242
+        return $response;
243
+    }
244
+
245
+    /**
246
+     * Return an array with the user theme & font settings
247
+     *
248
+     * @return array
249
+     */
250
+    private function getUserValues(): array {
251
+        $userTheme = $this->config->getUserValue($this->userSession->getUser()->getUID(), $this->appName, 'theme', false);
252
+        $userFont  = $this->config->getUserValue($this->userSession->getUser()->getUID(), $this->appName, 'font', false);
253
+        $userHighContrast = $this->config->getUserValue($this->userSession->getUser()->getUID(), $this->appName, 'highcontrast', false);
254
+
255
+        return [$userTheme, $userHighContrast, $userFont];
256
+    }
257
+
258
+    /**
259
+     * Remove all matches from the $rule regex
260
+     *
261
+     * @param string $rule regex to match
262
+     * @param string $css string to parse
263
+     * @return string
264
+     */
265
+    private function filterOutRule(string $rule, string $css): string {
266
+        return preg_replace($rule, '', $css);
267
+    }
268
+
269
+    /**
270
+     * Add the correct uri prefix to make uri valid again
271
+     *
272
+     * @param string $css
273
+     * @param string $webDir
274
+     * @return string
275
+     */
276
+    private function rebaseUrls(string $css, string $webDir): string {
277
+        $re    = '/url\([\'"]([^\/][\.\w?=\/-]*)[\'"]\)/x';
278
+        $subst = 'url(\'' . $webDir . '/$1\')';
279
+
280
+        return preg_replace($re, $subst, $css);
281
+    }
282
+
283
+    /**
284
+     * Remove all matches from the $rule regex
285
+     *
286
+     * @param string $css string to parse
287
+     * @return string
288
+     */
289
+    private function invertSvgIconsColor(string $css) {
290
+        return str_replace(
291
+            ['color=000&', 'color=fff&', 'color=***&'],
292
+            ['color=***&', 'color=000&', 'color=fff&'],
293
+            str_replace(
294
+                ['color=000000&', 'color=ffffff&', 'color=******&'],
295
+                ['color=******&', 'color=000000&', 'color=ffffff&'],
296
+                $css
297
+            )
298
+        );
299
+    }
300
+
301
+    /**
302
+     * @return string SCSS code for variables from OC_Defaults
303
+     */
304
+    private function getInjectedVariables(): string {
305
+        if ($this->injectedVariables !== null) {
306
+            return $this->injectedVariables;
307
+        }
308
+        $variables = '';
309
+        foreach ($this->defaults->getScssVariables() as $key => $value) {
310
+            $variables .= '$' . $key . ': ' . $value . ';';
311
+        }
312
+
313
+        // check for valid variables / otherwise fall back to defaults
314
+        try {
315
+            $scss = new Compiler();
316
+            $scss->compile($variables);
317
+            $this->injectedVariables = $variables;
318
+        } catch (ParserException $e) {
319
+            $this->logger->logException($e, ['app' => 'core']);
320
+        }
321
+        return $variables;
322
+    }
323 323
 }
Please login to merge, or discard this patch.
apps/accessibility/lib/Migration/RepairUserConfig.php 2 patches
Indentation   +47 added lines, -47 removed lines patch added patch discarded remove patch
@@ -35,56 +35,56 @@
 block discarded – undo
35 35
 
36 36
 class RepairUserConfig implements IRepairStep {
37 37
 
38
-	/** @var IUserManager */
39
-	protected $userManager;
38
+    /** @var IUserManager */
39
+    protected $userManager;
40 40
 
41
-	/** @var IConfig */
42
-	protected $config;
41
+    /** @var IConfig */
42
+    protected $config;
43 43
 
44
-	/**
45
-	 * MigrateUserConfig constructor.
46
-	 *
47
-	 * @param IConfig $config
48
-	 * @param IUserManager $userManager
49
-	 */
50
-	public function __construct(IConfig $config,
51
-								IUserManager $userManager) {
52
-		$this->config = $config;
53
-		$this->userManager = $userManager;
54
-	}
44
+    /**
45
+     * MigrateUserConfig constructor.
46
+     *
47
+     * @param IConfig $config
48
+     * @param IUserManager $userManager
49
+     */
50
+    public function __construct(IConfig $config,
51
+                                IUserManager $userManager) {
52
+        $this->config = $config;
53
+        $this->userManager = $userManager;
54
+    }
55 55
 
56
-	/**
57
-	 * Returns the step's name
58
-	 *
59
-	 * @return string
60
-	 * @since 9.1.0
61
-	 */
62
-	public function getName() {
63
-		return 'Migrate old user config';
64
-	}
56
+    /**
57
+     * Returns the step's name
58
+     *
59
+     * @return string
60
+     * @since 9.1.0
61
+     */
62
+    public function getName() {
63
+        return 'Migrate old user config';
64
+    }
65 65
 
66
-	/**
67
-	 * Run repair step.
68
-	 * Must throw exception on error.
69
-	 *
70
-	 * @param IOutput $output
71
-	 * @throws \Exception in case of failure
72
-	 * @since 9.1.0
73
-	 */
74
-	public function run(IOutput $output) {
75
-		$output->startProgress();
76
-		$this->userManager->callForSeenUsers(function (IUser $user) use ($output) {
77
-			$theme = $this->config->getUserValue($user->getUID(), Application::APP_NAME, 'theme', false);
78
-			if ($theme === 'themedark') {
79
-				$this->config->setUserValue($user->getUID(), Application::APP_NAME, 'theme', 'dark');
80
-			}
81
-			if ($theme === 'themehighcontrast') {
82
-				$this->config->setUserValue($user->getUID(), Application::APP_NAME, 'highcontrast', 'highcontrast');
83
-				$this->config->deleteUserValue($user->getUID(), Application::APP_NAME, 'theme');
84
-			}
85
-			$output->advance();
86
-		});
87
-		$output->finishProgress();
88
-	}
66
+    /**
67
+     * Run repair step.
68
+     * Must throw exception on error.
69
+     *
70
+     * @param IOutput $output
71
+     * @throws \Exception in case of failure
72
+     * @since 9.1.0
73
+     */
74
+    public function run(IOutput $output) {
75
+        $output->startProgress();
76
+        $this->userManager->callForSeenUsers(function (IUser $user) use ($output) {
77
+            $theme = $this->config->getUserValue($user->getUID(), Application::APP_NAME, 'theme', false);
78
+            if ($theme === 'themedark') {
79
+                $this->config->setUserValue($user->getUID(), Application::APP_NAME, 'theme', 'dark');
80
+            }
81
+            if ($theme === 'themehighcontrast') {
82
+                $this->config->setUserValue($user->getUID(), Application::APP_NAME, 'highcontrast', 'highcontrast');
83
+                $this->config->deleteUserValue($user->getUID(), Application::APP_NAME, 'theme');
84
+            }
85
+            $output->advance();
86
+        });
87
+        $output->finishProgress();
88
+    }
89 89
 
90 90
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -73,7 +73,7 @@
 block discarded – undo
73 73
 	 */
74 74
 	public function run(IOutput $output) {
75 75
 		$output->startProgress();
76
-		$this->userManager->callForSeenUsers(function (IUser $user) use ($output) {
76
+		$this->userManager->callForSeenUsers(function(IUser $user) use ($output) {
77 77
 			$theme = $this->config->getUserValue($user->getUID(), Application::APP_NAME, 'theme', false);
78 78
 			if ($theme === 'themedark') {
79 79
 				$this->config->setUserValue($user->getUID(), Application::APP_NAME, 'theme', 'dark');
Please login to merge, or discard this patch.
apps/files_sharing/lib/AppInfo/Application.php 2 patches
Indentation   +238 added lines, -238 removed lines patch added patch discarded remove patch
@@ -66,242 +66,242 @@
 block discarded – undo
66 66
 
67 67
 class Application extends App {
68 68
 
69
-	const APP_ID = 'files_sharing';
70
-
71
-	public function __construct(array $urlParams = []) {
72
-		parent::__construct(self::APP_ID, $urlParams);
73
-
74
-		$container = $this->getContainer();
75
-
76
-		/** @var IServerContainer $server */
77
-		$server = $container->getServer();
78
-
79
-		/** @var IEventDispatcher $dispatcher */
80
-		$dispatcher = $container->query(IEventDispatcher::class);
81
-		$mountProviderCollection = $server->getMountProviderCollection();
82
-		$notifications = $server->getNotificationManager();
83
-
84
-		/**
85
-		 * Controllers
86
-		 */
87
-		$container->registerService('ShareController', function (SimpleContainer $c) use ($server) {
88
-			$federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application();
89
-			return new ShareController(
90
-				$c->query('AppName'),
91
-				$c->query('Request'),
92
-				$server->getConfig(),
93
-				$server->getURLGenerator(),
94
-				$server->getUserManager(),
95
-				$server->getLogger(),
96
-				$server->getActivityManager(),
97
-				$server->getShareManager(),
98
-				$server->getSession(),
99
-				$server->getPreviewManager(),
100
-				$server->getRootFolder(),
101
-				$federatedSharingApp->getFederatedShareProvider(),
102
-				$server->getEventDispatcher(),
103
-				$server->getL10N($c->query('AppName')),
104
-				$server->query(Defaults::class)
105
-			);
106
-		});
107
-		$container->registerService('ExternalSharesController', function (SimpleContainer $c) {
108
-			return new ExternalSharesController(
109
-				$c->query('AppName'),
110
-				$c->query('Request'),
111
-				$c->query('ExternalManager'),
112
-				$c->query('HttpClientService')
113
-			);
114
-		});
115
-
116
-		/**
117
-		 * Core class wrappers
118
-		 */
119
-		$container->registerService('HttpClientService', function (SimpleContainer $c) use ($server) {
120
-			return $server->getHTTPClientService();
121
-		});
122
-		$container->registerService(ICloudIdManager::class, function (SimpleContainer $c) use ($server) {
123
-			return $server->getCloudIdManager();
124
-		});
125
-		$container->registerService('ExternalManager', function (SimpleContainer $c) use ($server) {
126
-			$user = $server->getUserSession()->getUser();
127
-			$uid = $user ? $user->getUID() : null;
128
-			return new \OCA\Files_Sharing\External\Manager(
129
-				$server->getDatabaseConnection(),
130
-				\OC\Files\Filesystem::getMountManager(),
131
-				\OC\Files\Filesystem::getLoader(),
132
-				$server->getHTTPClientService(),
133
-				$server->getNotificationManager(),
134
-				$server->query(\OCP\OCS\IDiscoveryService::class),
135
-				$server->getCloudFederationProviderManager(),
136
-				$server->getCloudFederationFactory(),
137
-				$server->getGroupManager(),
138
-				$server->getUserManager(),
139
-				$uid
140
-			);
141
-		});
142
-		$container->registerAlias(Manager::class, 'ExternalManager');
143
-
144
-		/**
145
-		 * Middleware
146
-		 */
147
-		$container->registerService('SharingCheckMiddleware', function (SimpleContainer $c) use ($server) {
148
-			return new SharingCheckMiddleware(
149
-				$c->query('AppName'),
150
-				$server->getConfig(),
151
-				$server->getAppManager(),
152
-				$server->query(IControllerMethodReflector::class),
153
-				$server->getShareManager(),
154
-				$server->getRequest()
155
-			);
156
-		});
157
-
158
-		$container->registerService(ShareInfoMiddleware::class, function () use ($server) {
159
-			return new ShareInfoMiddleware(
160
-				$server->getShareManager()
161
-			);
162
-		});
163
-
164
-		// Execute middlewares
165
-		$container->registerMiddleWare('SharingCheckMiddleware');
166
-		$container->registerMiddleWare(OCSShareAPIMiddleware::class);
167
-		$container->registerMiddleWare(ShareInfoMiddleware::class);
168
-
169
-		$container->registerService('MountProvider', function (IContainer $c) {
170
-			/** @var \OCP\IServerContainer $server */
171
-			$server = $c->query('ServerContainer');
172
-			return new MountProvider(
173
-				$server->getConfig(),
174
-				$server->getShareManager(),
175
-				$server->getLogger()
176
-			);
177
-		});
178
-
179
-		$container->registerService('ExternalMountProvider', function (IContainer $c) {
180
-			/** @var \OCP\IServerContainer $server */
181
-			$server = $c->query('ServerContainer');
182
-			return new \OCA\Files_Sharing\External\MountProvider(
183
-				$server->getDatabaseConnection(),
184
-				function () use ($c) {
185
-					return $c->query('ExternalManager');
186
-				},
187
-				$server->getCloudIdManager()
188
-			);
189
-		});
190
-
191
-		/**
192
-		 * Register capabilities
193
-		 */
194
-		$container->registerCapability(Capabilities::class);
195
-
196
-		$notifications->registerNotifierService(Notifier::class);
197
-
198
-		$this->registerMountProviders($mountProviderCollection);
199
-		$this->registerEventsScripts($dispatcher);
200
-		$this->setupSharingMenus();
201
-
202
-		/**
203
-		 * Always add main sharing script
204
-		 */
205
-		Util::addScript(self::APP_ID, 'dist/main');
206
-	}
207
-
208
-	protected function registerMountProviders(IMountProviderCollection $mountProviderCollection) {
209
-		$mountProviderCollection->registerProvider($this->getContainer()->query('MountProvider'));
210
-		$mountProviderCollection->registerProvider($this->getContainer()->query('ExternalMountProvider'));
211
-	}
212
-
213
-	protected function registerEventsScripts(IEventDispatcher $dispatcher) {
214
-		// sidebar and files scripts
215
-		$dispatcher->addServiceListener(LoadAdditionalScriptsEvent::class, LoadAdditionalListener::class);
216
-		$dispatcher->addServiceListener(LoadSidebar::class, LoadSidebarListener::class);
217
-		$dispatcher->addServiceListener(ShareCreatedEvent::class, ShareInteractionListener::class);
218
-		$dispatcher->addListener('\OCP\Collaboration\Resources::loadAdditionalScripts', function () {
219
-			\OCP\Util::addScript('files_sharing', 'dist/collaboration');
220
-		});
221
-		$dispatcher->addServiceListener(ShareCreatedEvent::class, UserShareAcceptanceListener::class);
222
-		$dispatcher->addServiceListener(UserAddedEvent::class, UserAddedToGroupListener::class);
223
-
224
-		// notifications api to accept incoming user shares
225
-		$dispatcher->addListener('OCP\Share::postShare', function (GenericEvent $event) {
226
-			/** @var Listener $listener */
227
-			$listener = $this->getContainer()->query(Listener::class);
228
-			$listener->shareNotification($event);
229
-		});
230
-		$dispatcher->addListener(IGroup::class . '::postAddUser', function (GenericEvent $event) {
231
-			/** @var Listener $listener */
232
-			$listener = $this->getContainer()->query(Listener::class);
233
-			$listener->userAddedToGroup($event);
234
-		});
235
-	}
236
-
237
-	protected function setupSharingMenus() {
238
-		$config = \OC::$server->getConfig();
239
-		$l = \OC::$server->getL10N('files_sharing');
240
-
241
-		if ($config->getAppValue('core', 'shareapi_enabled', 'yes') !== 'yes') {
242
-			return;
243
-		}
244
-
245
-		$sharingSublistArray = [];
246
-
247
-		if (\OCP\Util::isSharingDisabledForUser() === false) {
248
-			array_push($sharingSublistArray, [
249
-				'id' => 'sharingout',
250
-				'appname' => 'files_sharing',
251
-				'script' => 'list.php',
252
-				'order' => 16,
253
-				'name' => $l->t('Shared with others'),
254
-			]);
255
-		}
256
-
257
-		array_push($sharingSublistArray, [
258
-			'id' => 'sharingin',
259
-			'appname' => 'files_sharing',
260
-			'script' => 'list.php',
261
-			'order' => 15,
262
-			'name' => $l->t('Shared with you'),
263
-		]);
264
-
265
-		if (\OCP\Util::isSharingDisabledForUser() === false) {
266
-			// Check if sharing by link is enabled
267
-			if ($config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes') {
268
-				array_push($sharingSublistArray, [
269
-					'id' => 'sharinglinks',
270
-					'appname' => 'files_sharing',
271
-					'script' => 'list.php',
272
-					'order' => 17,
273
-					'name' => $l->t('Shared by link'),
274
-				]);
275
-			}
276
-		}
277
-
278
-		array_push($sharingSublistArray, [
279
-			'id' => 'deletedshares',
280
-			'appname' => 'files_sharing',
281
-			'script' => 'list.php',
282
-			'order' => 19,
283
-			'name' => $l->t('Deleted shares'),
284
-		]);
285
-
286
-		array_push($sharingSublistArray, [
287
-			'id' => 'pendingshares',
288
-			'appname' => 'files_sharing',
289
-			'script' => 'list.php',
290
-			'order' => 19,
291
-			'name' => $l->t('Pending shares'),
292
-		]);
293
-
294
-
295
-		// show_Quick_Access stored as string
296
-		\OCA\Files\App::getNavigationManager()->add([
297
-			'id' => 'shareoverview',
298
-			'appname' => 'files_sharing',
299
-			'script' => 'list.php',
300
-			'order' => 18,
301
-			'name' => $l->t('Shares'),
302
-			'classes' => 'collapsible',
303
-			'sublist' => $sharingSublistArray,
304
-			'expandedState' => 'show_sharing_menu'
305
-		]);
306
-	}
69
+    const APP_ID = 'files_sharing';
70
+
71
+    public function __construct(array $urlParams = []) {
72
+        parent::__construct(self::APP_ID, $urlParams);
73
+
74
+        $container = $this->getContainer();
75
+
76
+        /** @var IServerContainer $server */
77
+        $server = $container->getServer();
78
+
79
+        /** @var IEventDispatcher $dispatcher */
80
+        $dispatcher = $container->query(IEventDispatcher::class);
81
+        $mountProviderCollection = $server->getMountProviderCollection();
82
+        $notifications = $server->getNotificationManager();
83
+
84
+        /**
85
+         * Controllers
86
+         */
87
+        $container->registerService('ShareController', function (SimpleContainer $c) use ($server) {
88
+            $federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application();
89
+            return new ShareController(
90
+                $c->query('AppName'),
91
+                $c->query('Request'),
92
+                $server->getConfig(),
93
+                $server->getURLGenerator(),
94
+                $server->getUserManager(),
95
+                $server->getLogger(),
96
+                $server->getActivityManager(),
97
+                $server->getShareManager(),
98
+                $server->getSession(),
99
+                $server->getPreviewManager(),
100
+                $server->getRootFolder(),
101
+                $federatedSharingApp->getFederatedShareProvider(),
102
+                $server->getEventDispatcher(),
103
+                $server->getL10N($c->query('AppName')),
104
+                $server->query(Defaults::class)
105
+            );
106
+        });
107
+        $container->registerService('ExternalSharesController', function (SimpleContainer $c) {
108
+            return new ExternalSharesController(
109
+                $c->query('AppName'),
110
+                $c->query('Request'),
111
+                $c->query('ExternalManager'),
112
+                $c->query('HttpClientService')
113
+            );
114
+        });
115
+
116
+        /**
117
+         * Core class wrappers
118
+         */
119
+        $container->registerService('HttpClientService', function (SimpleContainer $c) use ($server) {
120
+            return $server->getHTTPClientService();
121
+        });
122
+        $container->registerService(ICloudIdManager::class, function (SimpleContainer $c) use ($server) {
123
+            return $server->getCloudIdManager();
124
+        });
125
+        $container->registerService('ExternalManager', function (SimpleContainer $c) use ($server) {
126
+            $user = $server->getUserSession()->getUser();
127
+            $uid = $user ? $user->getUID() : null;
128
+            return new \OCA\Files_Sharing\External\Manager(
129
+                $server->getDatabaseConnection(),
130
+                \OC\Files\Filesystem::getMountManager(),
131
+                \OC\Files\Filesystem::getLoader(),
132
+                $server->getHTTPClientService(),
133
+                $server->getNotificationManager(),
134
+                $server->query(\OCP\OCS\IDiscoveryService::class),
135
+                $server->getCloudFederationProviderManager(),
136
+                $server->getCloudFederationFactory(),
137
+                $server->getGroupManager(),
138
+                $server->getUserManager(),
139
+                $uid
140
+            );
141
+        });
142
+        $container->registerAlias(Manager::class, 'ExternalManager');
143
+
144
+        /**
145
+         * Middleware
146
+         */
147
+        $container->registerService('SharingCheckMiddleware', function (SimpleContainer $c) use ($server) {
148
+            return new SharingCheckMiddleware(
149
+                $c->query('AppName'),
150
+                $server->getConfig(),
151
+                $server->getAppManager(),
152
+                $server->query(IControllerMethodReflector::class),
153
+                $server->getShareManager(),
154
+                $server->getRequest()
155
+            );
156
+        });
157
+
158
+        $container->registerService(ShareInfoMiddleware::class, function () use ($server) {
159
+            return new ShareInfoMiddleware(
160
+                $server->getShareManager()
161
+            );
162
+        });
163
+
164
+        // Execute middlewares
165
+        $container->registerMiddleWare('SharingCheckMiddleware');
166
+        $container->registerMiddleWare(OCSShareAPIMiddleware::class);
167
+        $container->registerMiddleWare(ShareInfoMiddleware::class);
168
+
169
+        $container->registerService('MountProvider', function (IContainer $c) {
170
+            /** @var \OCP\IServerContainer $server */
171
+            $server = $c->query('ServerContainer');
172
+            return new MountProvider(
173
+                $server->getConfig(),
174
+                $server->getShareManager(),
175
+                $server->getLogger()
176
+            );
177
+        });
178
+
179
+        $container->registerService('ExternalMountProvider', function (IContainer $c) {
180
+            /** @var \OCP\IServerContainer $server */
181
+            $server = $c->query('ServerContainer');
182
+            return new \OCA\Files_Sharing\External\MountProvider(
183
+                $server->getDatabaseConnection(),
184
+                function () use ($c) {
185
+                    return $c->query('ExternalManager');
186
+                },
187
+                $server->getCloudIdManager()
188
+            );
189
+        });
190
+
191
+        /**
192
+         * Register capabilities
193
+         */
194
+        $container->registerCapability(Capabilities::class);
195
+
196
+        $notifications->registerNotifierService(Notifier::class);
197
+
198
+        $this->registerMountProviders($mountProviderCollection);
199
+        $this->registerEventsScripts($dispatcher);
200
+        $this->setupSharingMenus();
201
+
202
+        /**
203
+         * Always add main sharing script
204
+         */
205
+        Util::addScript(self::APP_ID, 'dist/main');
206
+    }
207
+
208
+    protected function registerMountProviders(IMountProviderCollection $mountProviderCollection) {
209
+        $mountProviderCollection->registerProvider($this->getContainer()->query('MountProvider'));
210
+        $mountProviderCollection->registerProvider($this->getContainer()->query('ExternalMountProvider'));
211
+    }
212
+
213
+    protected function registerEventsScripts(IEventDispatcher $dispatcher) {
214
+        // sidebar and files scripts
215
+        $dispatcher->addServiceListener(LoadAdditionalScriptsEvent::class, LoadAdditionalListener::class);
216
+        $dispatcher->addServiceListener(LoadSidebar::class, LoadSidebarListener::class);
217
+        $dispatcher->addServiceListener(ShareCreatedEvent::class, ShareInteractionListener::class);
218
+        $dispatcher->addListener('\OCP\Collaboration\Resources::loadAdditionalScripts', function () {
219
+            \OCP\Util::addScript('files_sharing', 'dist/collaboration');
220
+        });
221
+        $dispatcher->addServiceListener(ShareCreatedEvent::class, UserShareAcceptanceListener::class);
222
+        $dispatcher->addServiceListener(UserAddedEvent::class, UserAddedToGroupListener::class);
223
+
224
+        // notifications api to accept incoming user shares
225
+        $dispatcher->addListener('OCP\Share::postShare', function (GenericEvent $event) {
226
+            /** @var Listener $listener */
227
+            $listener = $this->getContainer()->query(Listener::class);
228
+            $listener->shareNotification($event);
229
+        });
230
+        $dispatcher->addListener(IGroup::class . '::postAddUser', function (GenericEvent $event) {
231
+            /** @var Listener $listener */
232
+            $listener = $this->getContainer()->query(Listener::class);
233
+            $listener->userAddedToGroup($event);
234
+        });
235
+    }
236
+
237
+    protected function setupSharingMenus() {
238
+        $config = \OC::$server->getConfig();
239
+        $l = \OC::$server->getL10N('files_sharing');
240
+
241
+        if ($config->getAppValue('core', 'shareapi_enabled', 'yes') !== 'yes') {
242
+            return;
243
+        }
244
+
245
+        $sharingSublistArray = [];
246
+
247
+        if (\OCP\Util::isSharingDisabledForUser() === false) {
248
+            array_push($sharingSublistArray, [
249
+                'id' => 'sharingout',
250
+                'appname' => 'files_sharing',
251
+                'script' => 'list.php',
252
+                'order' => 16,
253
+                'name' => $l->t('Shared with others'),
254
+            ]);
255
+        }
256
+
257
+        array_push($sharingSublistArray, [
258
+            'id' => 'sharingin',
259
+            'appname' => 'files_sharing',
260
+            'script' => 'list.php',
261
+            'order' => 15,
262
+            'name' => $l->t('Shared with you'),
263
+        ]);
264
+
265
+        if (\OCP\Util::isSharingDisabledForUser() === false) {
266
+            // Check if sharing by link is enabled
267
+            if ($config->getAppValue('core', 'shareapi_allow_links', 'yes') === 'yes') {
268
+                array_push($sharingSublistArray, [
269
+                    'id' => 'sharinglinks',
270
+                    'appname' => 'files_sharing',
271
+                    'script' => 'list.php',
272
+                    'order' => 17,
273
+                    'name' => $l->t('Shared by link'),
274
+                ]);
275
+            }
276
+        }
277
+
278
+        array_push($sharingSublistArray, [
279
+            'id' => 'deletedshares',
280
+            'appname' => 'files_sharing',
281
+            'script' => 'list.php',
282
+            'order' => 19,
283
+            'name' => $l->t('Deleted shares'),
284
+        ]);
285
+
286
+        array_push($sharingSublistArray, [
287
+            'id' => 'pendingshares',
288
+            'appname' => 'files_sharing',
289
+            'script' => 'list.php',
290
+            'order' => 19,
291
+            'name' => $l->t('Pending shares'),
292
+        ]);
293
+
294
+
295
+        // show_Quick_Access stored as string
296
+        \OCA\Files\App::getNavigationManager()->add([
297
+            'id' => 'shareoverview',
298
+            'appname' => 'files_sharing',
299
+            'script' => 'list.php',
300
+            'order' => 18,
301
+            'name' => $l->t('Shares'),
302
+            'classes' => 'collapsible',
303
+            'sublist' => $sharingSublistArray,
304
+            'expandedState' => 'show_sharing_menu'
305
+        ]);
306
+    }
307 307
 }
Please login to merge, or discard this patch.
Spacing   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -84,7 +84,7 @@  discard block
 block discarded – undo
84 84
 		/**
85 85
 		 * Controllers
86 86
 		 */
87
-		$container->registerService('ShareController', function (SimpleContainer $c) use ($server) {
87
+		$container->registerService('ShareController', function(SimpleContainer $c) use ($server) {
88 88
 			$federatedSharingApp = new \OCA\FederatedFileSharing\AppInfo\Application();
89 89
 			return new ShareController(
90 90
 				$c->query('AppName'),
@@ -104,7 +104,7 @@  discard block
 block discarded – undo
104 104
 				$server->query(Defaults::class)
105 105
 			);
106 106
 		});
107
-		$container->registerService('ExternalSharesController', function (SimpleContainer $c) {
107
+		$container->registerService('ExternalSharesController', function(SimpleContainer $c) {
108 108
 			return new ExternalSharesController(
109 109
 				$c->query('AppName'),
110 110
 				$c->query('Request'),
@@ -116,13 +116,13 @@  discard block
 block discarded – undo
116 116
 		/**
117 117
 		 * Core class wrappers
118 118
 		 */
119
-		$container->registerService('HttpClientService', function (SimpleContainer $c) use ($server) {
119
+		$container->registerService('HttpClientService', function(SimpleContainer $c) use ($server) {
120 120
 			return $server->getHTTPClientService();
121 121
 		});
122
-		$container->registerService(ICloudIdManager::class, function (SimpleContainer $c) use ($server) {
122
+		$container->registerService(ICloudIdManager::class, function(SimpleContainer $c) use ($server) {
123 123
 			return $server->getCloudIdManager();
124 124
 		});
125
-		$container->registerService('ExternalManager', function (SimpleContainer $c) use ($server) {
125
+		$container->registerService('ExternalManager', function(SimpleContainer $c) use ($server) {
126 126
 			$user = $server->getUserSession()->getUser();
127 127
 			$uid = $user ? $user->getUID() : null;
128 128
 			return new \OCA\Files_Sharing\External\Manager(
@@ -144,7 +144,7 @@  discard block
 block discarded – undo
144 144
 		/**
145 145
 		 * Middleware
146 146
 		 */
147
-		$container->registerService('SharingCheckMiddleware', function (SimpleContainer $c) use ($server) {
147
+		$container->registerService('SharingCheckMiddleware', function(SimpleContainer $c) use ($server) {
148 148
 			return new SharingCheckMiddleware(
149 149
 				$c->query('AppName'),
150 150
 				$server->getConfig(),
@@ -155,7 +155,7 @@  discard block
 block discarded – undo
155 155
 			);
156 156
 		});
157 157
 
158
-		$container->registerService(ShareInfoMiddleware::class, function () use ($server) {
158
+		$container->registerService(ShareInfoMiddleware::class, function() use ($server) {
159 159
 			return new ShareInfoMiddleware(
160 160
 				$server->getShareManager()
161 161
 			);
@@ -166,7 +166,7 @@  discard block
 block discarded – undo
166 166
 		$container->registerMiddleWare(OCSShareAPIMiddleware::class);
167 167
 		$container->registerMiddleWare(ShareInfoMiddleware::class);
168 168
 
169
-		$container->registerService('MountProvider', function (IContainer $c) {
169
+		$container->registerService('MountProvider', function(IContainer $c) {
170 170
 			/** @var \OCP\IServerContainer $server */
171 171
 			$server = $c->query('ServerContainer');
172 172
 			return new MountProvider(
@@ -176,12 +176,12 @@  discard block
 block discarded – undo
176 176
 			);
177 177
 		});
178 178
 
179
-		$container->registerService('ExternalMountProvider', function (IContainer $c) {
179
+		$container->registerService('ExternalMountProvider', function(IContainer $c) {
180 180
 			/** @var \OCP\IServerContainer $server */
181 181
 			$server = $c->query('ServerContainer');
182 182
 			return new \OCA\Files_Sharing\External\MountProvider(
183 183
 				$server->getDatabaseConnection(),
184
-				function () use ($c) {
184
+				function() use ($c) {
185 185
 					return $c->query('ExternalManager');
186 186
 				},
187 187
 				$server->getCloudIdManager()
@@ -215,19 +215,19 @@  discard block
 block discarded – undo
215 215
 		$dispatcher->addServiceListener(LoadAdditionalScriptsEvent::class, LoadAdditionalListener::class);
216 216
 		$dispatcher->addServiceListener(LoadSidebar::class, LoadSidebarListener::class);
217 217
 		$dispatcher->addServiceListener(ShareCreatedEvent::class, ShareInteractionListener::class);
218
-		$dispatcher->addListener('\OCP\Collaboration\Resources::loadAdditionalScripts', function () {
218
+		$dispatcher->addListener('\OCP\Collaboration\Resources::loadAdditionalScripts', function() {
219 219
 			\OCP\Util::addScript('files_sharing', 'dist/collaboration');
220 220
 		});
221 221
 		$dispatcher->addServiceListener(ShareCreatedEvent::class, UserShareAcceptanceListener::class);
222 222
 		$dispatcher->addServiceListener(UserAddedEvent::class, UserAddedToGroupListener::class);
223 223
 
224 224
 		// notifications api to accept incoming user shares
225
-		$dispatcher->addListener('OCP\Share::postShare', function (GenericEvent $event) {
225
+		$dispatcher->addListener('OCP\Share::postShare', function(GenericEvent $event) {
226 226
 			/** @var Listener $listener */
227 227
 			$listener = $this->getContainer()->query(Listener::class);
228 228
 			$listener->shareNotification($event);
229 229
 		});
230
-		$dispatcher->addListener(IGroup::class . '::postAddUser', function (GenericEvent $event) {
230
+		$dispatcher->addListener(IGroup::class.'::postAddUser', function(GenericEvent $event) {
231 231
 			/** @var Listener $listener */
232 232
 			$listener = $this->getContainer()->query(Listener::class);
233 233
 			$listener->userAddedToGroup($event);
Please login to merge, or discard this patch.
apps/files_sharing/lib/Controller/ShareesAPIController.php 2 patches
Indentation   +369 added lines, -369 removed lines patch added patch discarded remove patch
@@ -53,373 +53,373 @@
 block discarded – undo
53 53
 
54 54
 class ShareesAPIController extends OCSController {
55 55
 
56
-	/** @var userId */
57
-	protected $userId;
58
-
59
-	/** @var IConfig */
60
-	protected $config;
61
-
62
-	/** @var IURLGenerator */
63
-	protected $urlGenerator;
64
-
65
-	/** @var IManager */
66
-	protected $shareManager;
67
-
68
-	/** @var int */
69
-	protected $offset = 0;
70
-
71
-	/** @var int */
72
-	protected $limit = 10;
73
-
74
-	/** @var array */
75
-	protected $result = [
76
-		'exact' => [
77
-			'users' => [],
78
-			'groups' => [],
79
-			'remotes' => [],
80
-			'remote_groups' => [],
81
-			'emails' => [],
82
-			'circles' => [],
83
-			'rooms' => [],
84
-		],
85
-		'users' => [],
86
-		'groups' => [],
87
-		'remotes' => [],
88
-		'remote_groups' => [],
89
-		'emails' => [],
90
-		'lookup' => [],
91
-		'circles' => [],
92
-		'rooms' => [],
93
-		'lookupEnabled' => false,
94
-	];
95
-
96
-	protected $reachedEndFor = [];
97
-	/** @var ISearch */
98
-	private $collaboratorSearch;
99
-
100
-	/**
101
-	 * @param string $UserId
102
-	 * @param string $appName
103
-	 * @param IRequest $request
104
-	 * @param IConfig $config
105
-	 * @param IURLGenerator $urlGenerator
106
-	 * @param IManager $shareManager
107
-	 * @param ISearch $collaboratorSearch
108
-	 */
109
-	public function __construct(
110
-		$UserId,
111
-		string $appName,
112
-		IRequest $request,
113
-		IConfig $config,
114
-		IURLGenerator $urlGenerator,
115
-		IManager $shareManager,
116
-		ISearch $collaboratorSearch
117
-	) {
118
-		parent::__construct($appName, $request);
119
-		$this->userId = $UserId;
120
-		$this->config = $config;
121
-		$this->urlGenerator = $urlGenerator;
122
-		$this->shareManager = $shareManager;
123
-		$this->collaboratorSearch = $collaboratorSearch;
124
-	}
125
-
126
-	/**
127
-	 * @NoAdminRequired
128
-	 *
129
-	 * @param string $search
130
-	 * @param string $itemType
131
-	 * @param int $page
132
-	 * @param int $perPage
133
-	 * @param int|int[] $shareType
134
-	 * @param bool $lookup
135
-	 * @return DataResponse
136
-	 * @throws OCSBadRequestException
137
-	 */
138
-	public function search(string $search = '', string $itemType = null, int $page = 1, int $perPage = 200, $shareType = null, bool $lookup = true): DataResponse {
139
-
140
-		// only search for string larger than a given threshold
141
-		$threshold = (int)$this->config->getSystemValue('sharing.minSearchStringLength', 0);
142
-		if (strlen($search) < $threshold) {
143
-			return new DataResponse($this->result);
144
-		}
145
-
146
-		// never return more than the max. number of results configured in the config.php
147
-		$maxResults = (int)$this->config->getSystemValue('sharing.maxAutocompleteResults', 0);
148
-		if ($maxResults > 0) {
149
-			$perPage = min($perPage, $maxResults);
150
-		}
151
-		if ($perPage <= 0) {
152
-			throw new OCSBadRequestException('Invalid perPage argument');
153
-		}
154
-		if ($page <= 0) {
155
-			throw new OCSBadRequestException('Invalid page');
156
-		}
157
-
158
-		$shareTypes = [
159
-			Share::SHARE_TYPE_USER,
160
-		];
161
-
162
-		if ($itemType === null) {
163
-			throw new OCSBadRequestException('Missing itemType');
164
-		} elseif ($itemType === 'file' || $itemType === 'folder') {
165
-			if ($this->shareManager->allowGroupSharing()) {
166
-				$shareTypes[] = Share::SHARE_TYPE_GROUP;
167
-			}
168
-
169
-			if ($this->isRemoteSharingAllowed($itemType)) {
170
-				$shareTypes[] = Share::SHARE_TYPE_REMOTE;
171
-			}
172
-
173
-			if ($this->isRemoteGroupSharingAllowed($itemType)) {
174
-				$shareTypes[] = Share::SHARE_TYPE_REMOTE_GROUP;
175
-			}
176
-
177
-			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
178
-				$shareTypes[] = Share::SHARE_TYPE_EMAIL;
179
-			}
180
-
181
-			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_ROOM)) {
182
-				$shareTypes[] = Share::SHARE_TYPE_ROOM;
183
-			}
184
-		} else {
185
-			$shareTypes[] = Share::SHARE_TYPE_GROUP;
186
-			$shareTypes[] = Share::SHARE_TYPE_EMAIL;
187
-		}
188
-
189
-		// FIXME: DI
190
-		if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
191
-			$shareTypes[] = Share::SHARE_TYPE_CIRCLE;
192
-		}
193
-
194
-		if ($shareType !== null && is_array($shareType)) {
195
-			$shareTypes = array_intersect($shareTypes, $shareType);
196
-		} else if (is_numeric($shareType)) {
197
-			$shareTypes = array_intersect($shareTypes, [(int) $shareType]);
198
-		}
199
-		sort($shareTypes);
200
-
201
-		$this->limit = (int) $perPage;
202
-		$this->offset = $perPage * ($page - 1);
203
-
204
-		// In global scale mode we always search the loogup server
205
-		if ($this->config->getSystemValueBool('gs.enabled', false)) {
206
-			$lookup = true;
207
-			$this->result['lookupEnabled'] = true;
208
-		} else {
209
-			$this->result['lookupEnabled'] = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes') === 'yes';
210
-		}
211
-
212
-		list($result, $hasMoreResults) = $this->collaboratorSearch->search($search, $shareTypes, $lookup, $this->limit, $this->offset);
213
-
214
-		// extra treatment for 'exact' subarray, with a single merge expected keys might be lost
215
-		if(isset($result['exact'])) {
216
-			$result['exact'] = array_merge($this->result['exact'], $result['exact']);
217
-		}
218
-		$this->result = array_merge($this->result, $result);
219
-		$response = new DataResponse($this->result);
220
-
221
-		if ($hasMoreResults) {
222
-			$response->addHeader('Link', $this->getPaginationLink($page, [
223
-				'search' => $search,
224
-				'itemType' => $itemType,
225
-				'shareType' => $shareTypes,
226
-				'perPage' => $perPage,
227
-			]));
228
-		}
229
-
230
-		return $response;
231
-	}
232
-
233
-	/**
234
-	 * @param string $user
235
-	 * @param int $shareType
236
-	 *
237
-	 * @return Generator<array<string>>
238
-	 */
239
-	private function getAllShareesByType(string $user, int $shareType): Generator {
240
-		$offset = 0;
241
-		$pageSize = 50;
242
-
243
-		while (count($page = $this->shareManager->getSharesBy(
244
-			$user,
245
-			$shareType,
246
-			null,
247
-			false,
248
-			$pageSize,
249
-			$offset
250
-		))) {
251
-			foreach ($page as $share) {
252
-				yield [$share->getSharedWith(), $share->getSharedWithDisplayName() ?? $share->getSharedWith()];
253
-			}
254
-
255
-			$offset += $pageSize;
256
-		}
257
-	}
258
-
259
-	private function sortShareesByFrequency(array $sharees): array {
260
-		usort($sharees, function (array $s1, array $s2) {
261
-			return $s2['count'] - $s1['count'];
262
-		});
263
-		return $sharees;
264
-	}
265
-
266
-	private $searchResultTypeMap = [
267
-		Share::SHARE_TYPE_USER => 'users',
268
-		Share::SHARE_TYPE_GROUP => 'groups',
269
-		Share::SHARE_TYPE_REMOTE => 'remotes',
270
-		Share::SHARE_TYPE_REMOTE_GROUP => 'remote_groups',
271
-		Share::SHARE_TYPE_EMAIL => 'emails',
272
-	];
273
-
274
-	private function getAllSharees(string $user, array $shareTypes): ISearchResult {
275
-		$result = [];
276
-		foreach ($shareTypes as $shareType) {
277
-			$sharees = $this->getAllShareesByType($user, $shareType);
278
-			$shareTypeResults = [];
279
-			foreach ($sharees as list($sharee, $displayname)) {
280
-				if (!isset($this->searchResultTypeMap[$shareType])) {
281
-					continue;
282
-				}
283
-
284
-				if (!isset($shareTypeResults[$sharee])) {
285
-					$shareTypeResults[$sharee] = [
286
-						'count' => 1,
287
-						'label' => $displayname,
288
-						'value' => [
289
-							'shareType' => $shareType,
290
-							'shareWith' => $sharee,
291
-						],
292
-					];
293
-				} else {
294
-					$shareTypeResults[$sharee]['count']++;
295
-				}
296
-			}
297
-			$result = array_merge($result, array_values($shareTypeResults));
298
-		}
299
-
300
-		$top5 = array_slice(
301
-			$this->sortShareesByFrequency($result),
302
-			0,
303
-			5
304
-		);
305
-
306
-		$searchResult = new SearchResult();
307
-		foreach ($this->searchResultTypeMap as $int => $str) {
308
-			$searchResult->addResultSet(new SearchResultType($str), [], []);
309
-			foreach ($top5 as $x) {
310
-				if ($x['value']['shareType'] === $int) {
311
-					$searchResult->addResultSet(new SearchResultType($str), [], [$x]);
312
-				}
313
-			}
314
-		}
315
-		return $searchResult;
316
-	}
317
-
318
-	/**
319
-	 * @NoAdminRequired
320
-	 *
321
-	 * @param string $itemType
322
-	 * @return DataResponse
323
-	 * @throws OCSBadRequestException
324
-	 */
325
-	public function findRecommended(string $itemType = null, $shareType = null): DataResponse {
326
-		$shareTypes = [
327
-			Share::SHARE_TYPE_USER,
328
-		];
329
-
330
-		if ($itemType === null) {
331
-			throw new OCSBadRequestException('Missing itemType');
332
-		} elseif ($itemType === 'file' || $itemType === 'folder') {
333
-			if ($this->shareManager->allowGroupSharing()) {
334
-				$shareTypes[] = Share::SHARE_TYPE_GROUP;
335
-			}
336
-
337
-			if ($this->isRemoteSharingAllowed($itemType)) {
338
-				$shareTypes[] = Share::SHARE_TYPE_REMOTE;
339
-			}
340
-
341
-			if ($this->isRemoteGroupSharingAllowed($itemType)) {
342
-				$shareTypes[] = Share::SHARE_TYPE_REMOTE_GROUP;
343
-			}
344
-
345
-			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
346
-				$shareTypes[] = Share::SHARE_TYPE_EMAIL;
347
-			}
348
-
349
-			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_ROOM)) {
350
-				$shareTypes[] = Share::SHARE_TYPE_ROOM;
351
-			}
352
-		} else {
353
-			$shareTypes[] = Share::SHARE_TYPE_GROUP;
354
-			$shareTypes[] = Share::SHARE_TYPE_EMAIL;
355
-		}
356
-
357
-		// FIXME: DI
358
-		if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
359
-			$shareTypes[] = Share::SHARE_TYPE_CIRCLE;
360
-		}
361
-
362
-		if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
363
-			$shareTypes = array_intersect($shareTypes, $_GET['shareType']);
364
-			sort($shareTypes);
365
-		} else if (is_numeric($shareType)) {
366
-			$shareTypes = array_intersect($shareTypes, [(int) $shareType]);
367
-			sort($shareTypes);
368
-		}
369
-
370
-		return new DataResponse(
371
-			$this->getAllSharees($this->userId, $shareTypes)->asArray()
372
-		);
373
-	}
374
-
375
-	/**
376
-	 * Method to get out the static call for better testing
377
-	 *
378
-	 * @param string $itemType
379
-	 * @return bool
380
-	 */
381
-	protected function isRemoteSharingAllowed(string $itemType): bool {
382
-		try {
383
-			// FIXME: static foo makes unit testing unnecessarily difficult
384
-			$backend = \OC\Share\Share::getBackend($itemType);
385
-			return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE);
386
-		} catch (\Exception $e) {
387
-			return false;
388
-		}
389
-	}
390
-
391
-	protected function isRemoteGroupSharingAllowed(string $itemType): bool {
392
-		try {
393
-			// FIXME: static foo makes unit testing unnecessarily difficult
394
-			$backend = \OC\Share\Share::getBackend($itemType);
395
-			return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE_GROUP);
396
-		} catch (\Exception $e) {
397
-			return false;
398
-		}
399
-	}
400
-
401
-
402
-	/**
403
-	 * Generates a bunch of pagination links for the current page
404
-	 *
405
-	 * @param int $page Current page
406
-	 * @param array $params Parameters for the URL
407
-	 * @return string
408
-	 */
409
-	protected function getPaginationLink(int $page, array $params): string {
410
-		if ($this->isV2()) {
411
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
412
-		} else {
413
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
414
-		}
415
-		$params['page'] = $page + 1;
416
-		return '<' . $url . http_build_query($params) . '>; rel="next"';
417
-	}
418
-
419
-	/**
420
-	 * @return bool
421
-	 */
422
-	protected function isV2(): bool {
423
-		return $this->request->getScriptName() === '/ocs/v2.php';
424
-	}
56
+    /** @var userId */
57
+    protected $userId;
58
+
59
+    /** @var IConfig */
60
+    protected $config;
61
+
62
+    /** @var IURLGenerator */
63
+    protected $urlGenerator;
64
+
65
+    /** @var IManager */
66
+    protected $shareManager;
67
+
68
+    /** @var int */
69
+    protected $offset = 0;
70
+
71
+    /** @var int */
72
+    protected $limit = 10;
73
+
74
+    /** @var array */
75
+    protected $result = [
76
+        'exact' => [
77
+            'users' => [],
78
+            'groups' => [],
79
+            'remotes' => [],
80
+            'remote_groups' => [],
81
+            'emails' => [],
82
+            'circles' => [],
83
+            'rooms' => [],
84
+        ],
85
+        'users' => [],
86
+        'groups' => [],
87
+        'remotes' => [],
88
+        'remote_groups' => [],
89
+        'emails' => [],
90
+        'lookup' => [],
91
+        'circles' => [],
92
+        'rooms' => [],
93
+        'lookupEnabled' => false,
94
+    ];
95
+
96
+    protected $reachedEndFor = [];
97
+    /** @var ISearch */
98
+    private $collaboratorSearch;
99
+
100
+    /**
101
+     * @param string $UserId
102
+     * @param string $appName
103
+     * @param IRequest $request
104
+     * @param IConfig $config
105
+     * @param IURLGenerator $urlGenerator
106
+     * @param IManager $shareManager
107
+     * @param ISearch $collaboratorSearch
108
+     */
109
+    public function __construct(
110
+        $UserId,
111
+        string $appName,
112
+        IRequest $request,
113
+        IConfig $config,
114
+        IURLGenerator $urlGenerator,
115
+        IManager $shareManager,
116
+        ISearch $collaboratorSearch
117
+    ) {
118
+        parent::__construct($appName, $request);
119
+        $this->userId = $UserId;
120
+        $this->config = $config;
121
+        $this->urlGenerator = $urlGenerator;
122
+        $this->shareManager = $shareManager;
123
+        $this->collaboratorSearch = $collaboratorSearch;
124
+    }
125
+
126
+    /**
127
+     * @NoAdminRequired
128
+     *
129
+     * @param string $search
130
+     * @param string $itemType
131
+     * @param int $page
132
+     * @param int $perPage
133
+     * @param int|int[] $shareType
134
+     * @param bool $lookup
135
+     * @return DataResponse
136
+     * @throws OCSBadRequestException
137
+     */
138
+    public function search(string $search = '', string $itemType = null, int $page = 1, int $perPage = 200, $shareType = null, bool $lookup = true): DataResponse {
139
+
140
+        // only search for string larger than a given threshold
141
+        $threshold = (int)$this->config->getSystemValue('sharing.minSearchStringLength', 0);
142
+        if (strlen($search) < $threshold) {
143
+            return new DataResponse($this->result);
144
+        }
145
+
146
+        // never return more than the max. number of results configured in the config.php
147
+        $maxResults = (int)$this->config->getSystemValue('sharing.maxAutocompleteResults', 0);
148
+        if ($maxResults > 0) {
149
+            $perPage = min($perPage, $maxResults);
150
+        }
151
+        if ($perPage <= 0) {
152
+            throw new OCSBadRequestException('Invalid perPage argument');
153
+        }
154
+        if ($page <= 0) {
155
+            throw new OCSBadRequestException('Invalid page');
156
+        }
157
+
158
+        $shareTypes = [
159
+            Share::SHARE_TYPE_USER,
160
+        ];
161
+
162
+        if ($itemType === null) {
163
+            throw new OCSBadRequestException('Missing itemType');
164
+        } elseif ($itemType === 'file' || $itemType === 'folder') {
165
+            if ($this->shareManager->allowGroupSharing()) {
166
+                $shareTypes[] = Share::SHARE_TYPE_GROUP;
167
+            }
168
+
169
+            if ($this->isRemoteSharingAllowed($itemType)) {
170
+                $shareTypes[] = Share::SHARE_TYPE_REMOTE;
171
+            }
172
+
173
+            if ($this->isRemoteGroupSharingAllowed($itemType)) {
174
+                $shareTypes[] = Share::SHARE_TYPE_REMOTE_GROUP;
175
+            }
176
+
177
+            if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
178
+                $shareTypes[] = Share::SHARE_TYPE_EMAIL;
179
+            }
180
+
181
+            if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_ROOM)) {
182
+                $shareTypes[] = Share::SHARE_TYPE_ROOM;
183
+            }
184
+        } else {
185
+            $shareTypes[] = Share::SHARE_TYPE_GROUP;
186
+            $shareTypes[] = Share::SHARE_TYPE_EMAIL;
187
+        }
188
+
189
+        // FIXME: DI
190
+        if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
191
+            $shareTypes[] = Share::SHARE_TYPE_CIRCLE;
192
+        }
193
+
194
+        if ($shareType !== null && is_array($shareType)) {
195
+            $shareTypes = array_intersect($shareTypes, $shareType);
196
+        } else if (is_numeric($shareType)) {
197
+            $shareTypes = array_intersect($shareTypes, [(int) $shareType]);
198
+        }
199
+        sort($shareTypes);
200
+
201
+        $this->limit = (int) $perPage;
202
+        $this->offset = $perPage * ($page - 1);
203
+
204
+        // In global scale mode we always search the loogup server
205
+        if ($this->config->getSystemValueBool('gs.enabled', false)) {
206
+            $lookup = true;
207
+            $this->result['lookupEnabled'] = true;
208
+        } else {
209
+            $this->result['lookupEnabled'] = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes') === 'yes';
210
+        }
211
+
212
+        list($result, $hasMoreResults) = $this->collaboratorSearch->search($search, $shareTypes, $lookup, $this->limit, $this->offset);
213
+
214
+        // extra treatment for 'exact' subarray, with a single merge expected keys might be lost
215
+        if(isset($result['exact'])) {
216
+            $result['exact'] = array_merge($this->result['exact'], $result['exact']);
217
+        }
218
+        $this->result = array_merge($this->result, $result);
219
+        $response = new DataResponse($this->result);
220
+
221
+        if ($hasMoreResults) {
222
+            $response->addHeader('Link', $this->getPaginationLink($page, [
223
+                'search' => $search,
224
+                'itemType' => $itemType,
225
+                'shareType' => $shareTypes,
226
+                'perPage' => $perPage,
227
+            ]));
228
+        }
229
+
230
+        return $response;
231
+    }
232
+
233
+    /**
234
+     * @param string $user
235
+     * @param int $shareType
236
+     *
237
+     * @return Generator<array<string>>
238
+     */
239
+    private function getAllShareesByType(string $user, int $shareType): Generator {
240
+        $offset = 0;
241
+        $pageSize = 50;
242
+
243
+        while (count($page = $this->shareManager->getSharesBy(
244
+            $user,
245
+            $shareType,
246
+            null,
247
+            false,
248
+            $pageSize,
249
+            $offset
250
+        ))) {
251
+            foreach ($page as $share) {
252
+                yield [$share->getSharedWith(), $share->getSharedWithDisplayName() ?? $share->getSharedWith()];
253
+            }
254
+
255
+            $offset += $pageSize;
256
+        }
257
+    }
258
+
259
+    private function sortShareesByFrequency(array $sharees): array {
260
+        usort($sharees, function (array $s1, array $s2) {
261
+            return $s2['count'] - $s1['count'];
262
+        });
263
+        return $sharees;
264
+    }
265
+
266
+    private $searchResultTypeMap = [
267
+        Share::SHARE_TYPE_USER => 'users',
268
+        Share::SHARE_TYPE_GROUP => 'groups',
269
+        Share::SHARE_TYPE_REMOTE => 'remotes',
270
+        Share::SHARE_TYPE_REMOTE_GROUP => 'remote_groups',
271
+        Share::SHARE_TYPE_EMAIL => 'emails',
272
+    ];
273
+
274
+    private function getAllSharees(string $user, array $shareTypes): ISearchResult {
275
+        $result = [];
276
+        foreach ($shareTypes as $shareType) {
277
+            $sharees = $this->getAllShareesByType($user, $shareType);
278
+            $shareTypeResults = [];
279
+            foreach ($sharees as list($sharee, $displayname)) {
280
+                if (!isset($this->searchResultTypeMap[$shareType])) {
281
+                    continue;
282
+                }
283
+
284
+                if (!isset($shareTypeResults[$sharee])) {
285
+                    $shareTypeResults[$sharee] = [
286
+                        'count' => 1,
287
+                        'label' => $displayname,
288
+                        'value' => [
289
+                            'shareType' => $shareType,
290
+                            'shareWith' => $sharee,
291
+                        ],
292
+                    ];
293
+                } else {
294
+                    $shareTypeResults[$sharee]['count']++;
295
+                }
296
+            }
297
+            $result = array_merge($result, array_values($shareTypeResults));
298
+        }
299
+
300
+        $top5 = array_slice(
301
+            $this->sortShareesByFrequency($result),
302
+            0,
303
+            5
304
+        );
305
+
306
+        $searchResult = new SearchResult();
307
+        foreach ($this->searchResultTypeMap as $int => $str) {
308
+            $searchResult->addResultSet(new SearchResultType($str), [], []);
309
+            foreach ($top5 as $x) {
310
+                if ($x['value']['shareType'] === $int) {
311
+                    $searchResult->addResultSet(new SearchResultType($str), [], [$x]);
312
+                }
313
+            }
314
+        }
315
+        return $searchResult;
316
+    }
317
+
318
+    /**
319
+     * @NoAdminRequired
320
+     *
321
+     * @param string $itemType
322
+     * @return DataResponse
323
+     * @throws OCSBadRequestException
324
+     */
325
+    public function findRecommended(string $itemType = null, $shareType = null): DataResponse {
326
+        $shareTypes = [
327
+            Share::SHARE_TYPE_USER,
328
+        ];
329
+
330
+        if ($itemType === null) {
331
+            throw new OCSBadRequestException('Missing itemType');
332
+        } elseif ($itemType === 'file' || $itemType === 'folder') {
333
+            if ($this->shareManager->allowGroupSharing()) {
334
+                $shareTypes[] = Share::SHARE_TYPE_GROUP;
335
+            }
336
+
337
+            if ($this->isRemoteSharingAllowed($itemType)) {
338
+                $shareTypes[] = Share::SHARE_TYPE_REMOTE;
339
+            }
340
+
341
+            if ($this->isRemoteGroupSharingAllowed($itemType)) {
342
+                $shareTypes[] = Share::SHARE_TYPE_REMOTE_GROUP;
343
+            }
344
+
345
+            if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
346
+                $shareTypes[] = Share::SHARE_TYPE_EMAIL;
347
+            }
348
+
349
+            if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_ROOM)) {
350
+                $shareTypes[] = Share::SHARE_TYPE_ROOM;
351
+            }
352
+        } else {
353
+            $shareTypes[] = Share::SHARE_TYPE_GROUP;
354
+            $shareTypes[] = Share::SHARE_TYPE_EMAIL;
355
+        }
356
+
357
+        // FIXME: DI
358
+        if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
359
+            $shareTypes[] = Share::SHARE_TYPE_CIRCLE;
360
+        }
361
+
362
+        if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
363
+            $shareTypes = array_intersect($shareTypes, $_GET['shareType']);
364
+            sort($shareTypes);
365
+        } else if (is_numeric($shareType)) {
366
+            $shareTypes = array_intersect($shareTypes, [(int) $shareType]);
367
+            sort($shareTypes);
368
+        }
369
+
370
+        return new DataResponse(
371
+            $this->getAllSharees($this->userId, $shareTypes)->asArray()
372
+        );
373
+    }
374
+
375
+    /**
376
+     * Method to get out the static call for better testing
377
+     *
378
+     * @param string $itemType
379
+     * @return bool
380
+     */
381
+    protected function isRemoteSharingAllowed(string $itemType): bool {
382
+        try {
383
+            // FIXME: static foo makes unit testing unnecessarily difficult
384
+            $backend = \OC\Share\Share::getBackend($itemType);
385
+            return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE);
386
+        } catch (\Exception $e) {
387
+            return false;
388
+        }
389
+    }
390
+
391
+    protected function isRemoteGroupSharingAllowed(string $itemType): bool {
392
+        try {
393
+            // FIXME: static foo makes unit testing unnecessarily difficult
394
+            $backend = \OC\Share\Share::getBackend($itemType);
395
+            return $backend->isShareTypeAllowed(Share::SHARE_TYPE_REMOTE_GROUP);
396
+        } catch (\Exception $e) {
397
+            return false;
398
+        }
399
+    }
400
+
401
+
402
+    /**
403
+     * Generates a bunch of pagination links for the current page
404
+     *
405
+     * @param int $page Current page
406
+     * @param array $params Parameters for the URL
407
+     * @return string
408
+     */
409
+    protected function getPaginationLink(int $page, array $params): string {
410
+        if ($this->isV2()) {
411
+            $url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
412
+        } else {
413
+            $url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
414
+        }
415
+        $params['page'] = $page + 1;
416
+        return '<' . $url . http_build_query($params) . '>; rel="next"';
417
+    }
418
+
419
+    /**
420
+     * @return bool
421
+     */
422
+    protected function isV2(): bool {
423
+        return $this->request->getScriptName() === '/ocs/v2.php';
424
+    }
425 425
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -138,13 +138,13 @@  discard block
 block discarded – undo
138 138
 	public function search(string $search = '', string $itemType = null, int $page = 1, int $perPage = 200, $shareType = null, bool $lookup = true): DataResponse {
139 139
 
140 140
 		// only search for string larger than a given threshold
141
-		$threshold = (int)$this->config->getSystemValue('sharing.minSearchStringLength', 0);
141
+		$threshold = (int) $this->config->getSystemValue('sharing.minSearchStringLength', 0);
142 142
 		if (strlen($search) < $threshold) {
143 143
 			return new DataResponse($this->result);
144 144
 		}
145 145
 
146 146
 		// never return more than the max. number of results configured in the config.php
147
-		$maxResults = (int)$this->config->getSystemValue('sharing.maxAutocompleteResults', 0);
147
+		$maxResults = (int) $this->config->getSystemValue('sharing.maxAutocompleteResults', 0);
148 148
 		if ($maxResults > 0) {
149 149
 			$perPage = min($perPage, $maxResults);
150 150
 		}
@@ -212,7 +212,7 @@  discard block
 block discarded – undo
212 212
 		list($result, $hasMoreResults) = $this->collaboratorSearch->search($search, $shareTypes, $lookup, $this->limit, $this->offset);
213 213
 
214 214
 		// extra treatment for 'exact' subarray, with a single merge expected keys might be lost
215
-		if(isset($result['exact'])) {
215
+		if (isset($result['exact'])) {
216 216
 			$result['exact'] = array_merge($this->result['exact'], $result['exact']);
217 217
 		}
218 218
 		$this->result = array_merge($this->result, $result);
@@ -257,7 +257,7 @@  discard block
 block discarded – undo
257 257
 	}
258 258
 
259 259
 	private function sortShareesByFrequency(array $sharees): array {
260
-		usort($sharees, function (array $s1, array $s2) {
260
+		usort($sharees, function(array $s1, array $s2) {
261 261
 			return $s2['count'] - $s1['count'];
262 262
 		});
263 263
 		return $sharees;
@@ -408,12 +408,12 @@  discard block
 block discarded – undo
408 408
 	 */
409 409
 	protected function getPaginationLink(int $page, array $params): string {
410 410
 		if ($this->isV2()) {
411
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
411
+			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees').'?';
412 412
 		} else {
413
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
413
+			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees').'?';
414 414
 		}
415 415
 		$params['page'] = $page + 1;
416
-		return '<' . $url . http_build_query($params) . '>; rel="next"';
416
+		return '<'.$url.http_build_query($params).'>; rel="next"';
417 417
 	}
418 418
 
419 419
 	/**
Please login to merge, or discard this patch.
apps/files_sharing/lib/Controller/ShareAPIController.php 2 patches
Indentation   +1576 added lines, -1576 removed lines patch added patch discarded remove patch
@@ -76,1584 +76,1584 @@
 block discarded – undo
76 76
  */
77 77
 class ShareAPIController extends OCSController {
78 78
 
79
-	/** @var IManager */
80
-	private $shareManager;
81
-	/** @var IGroupManager */
82
-	private $groupManager;
83
-	/** @var IUserManager */
84
-	private $userManager;
85
-	/** @var IRootFolder */
86
-	private $rootFolder;
87
-	/** @var IURLGenerator */
88
-	private $urlGenerator;
89
-	/** @var string */
90
-	private $currentUser;
91
-	/** @var IL10N */
92
-	private $l;
93
-	/** @var \OCP\Files\Node */
94
-	private $lockedNode;
95
-	/** @var IConfig */
96
-	private $config;
97
-	/** @var IAppManager */
98
-	private $appManager;
99
-	/** @var IServerContainer */
100
-	private $serverContainer;
101
-
102
-	/**
103
-	 * Share20OCS constructor.
104
-	 *
105
-	 * @param string $appName
106
-	 * @param IRequest $request
107
-	 * @param IManager $shareManager
108
-	 * @param IGroupManager $groupManager
109
-	 * @param IUserManager $userManager
110
-	 * @param IRootFolder $rootFolder
111
-	 * @param IURLGenerator $urlGenerator
112
-	 * @param string $userId
113
-	 * @param IL10N $l10n
114
-	 * @param IConfig $config
115
-	 * @param IAppManager $appManager
116
-	 * @param IServerContainer $serverContainer
117
-	 */
118
-	public function __construct(
119
-		string $appName,
120
-		IRequest $request,
121
-		IManager $shareManager,
122
-		IGroupManager $groupManager,
123
-		IUserManager $userManager,
124
-		IRootFolder $rootFolder,
125
-		IURLGenerator $urlGenerator,
126
-		string $userId = null,
127
-		IL10N $l10n,
128
-		IConfig $config,
129
-		IAppManager $appManager,
130
-		IServerContainer $serverContainer
131
-	) {
132
-		parent::__construct($appName, $request);
133
-
134
-		$this->shareManager = $shareManager;
135
-		$this->userManager = $userManager;
136
-		$this->groupManager = $groupManager;
137
-		$this->request = $request;
138
-		$this->rootFolder = $rootFolder;
139
-		$this->urlGenerator = $urlGenerator;
140
-		$this->currentUser = $userId;
141
-		$this->l = $l10n;
142
-		$this->config = $config;
143
-		$this->appManager = $appManager;
144
-		$this->serverContainer = $serverContainer;
145
-	}
146
-
147
-	/**
148
-	 * Convert an IShare to an array for OCS output
149
-	 *
150
-	 * @param \OCP\Share\IShare $share
151
-	 * @param Node|null $recipientNode
152
-	 * @return array
153
-	 * @throws NotFoundException In case the node can't be resolved.
154
-	 *
155
-	 * @suppress PhanUndeclaredClassMethod
156
-	 */
157
-	protected function formatShare(\OCP\Share\IShare $share, Node $recipientNode = null): array {
158
-		$sharedBy = $this->userManager->get($share->getSharedBy());
159
-		$shareOwner = $this->userManager->get($share->getShareOwner());
160
-
161
-		$result = [
162
-			'id' => $share->getId(),
163
-			'share_type' => $share->getShareType(),
164
-			'uid_owner' => $share->getSharedBy(),
165
-			'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
166
-			// recipient permissions
167
-			'permissions' => $share->getPermissions(),
168
-			// current user permissions on this share
169
-			'can_edit' => $this->canEditShare($share),
170
-			'can_delete' => $this->canDeleteShare($share),
171
-			'stime' => $share->getShareTime()->getTimestamp(),
172
-			'parent' => null,
173
-			'expiration' => null,
174
-			'token' => null,
175
-			'uid_file_owner' => $share->getShareOwner(),
176
-			'note' => $share->getNote(),
177
-			'label' => $share->getLabel(),
178
-			'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
179
-		];
180
-
181
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
182
-		if ($recipientNode) {
183
-			$node = $recipientNode;
184
-		} else {
185
-			$nodes = $userFolder->getById($share->getNodeId());
186
-			if (empty($nodes)) {
187
-				// fallback to guessing the path
188
-				$node = $userFolder->get($share->getTarget());
189
-				if ($node === null || $share->getTarget() === '') {
190
-					throw new NotFoundException();
191
-				}
192
-			} else {
193
-				$node = reset($nodes);
194
-			}
195
-		}
196
-
197
-		$result['path'] = $userFolder->getRelativePath($node->getPath());
198
-		if ($node instanceof \OCP\Files\Folder) {
199
-			$result['item_type'] = 'folder';
200
-		} else {
201
-			$result['item_type'] = 'file';
202
-		}
203
-
204
-		$result['mimetype'] = $node->getMimetype();
205
-		$result['storage_id'] = $node->getStorage()->getId();
206
-		$result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
207
-		$result['item_source'] = $node->getId();
208
-		$result['file_source'] = $node->getId();
209
-		$result['file_parent'] = $node->getParent()->getId();
210
-		$result['file_target'] = $share->getTarget();
211
-
212
-		$expiration = $share->getExpirationDate();
213
-		if ($expiration !== null) {
214
-			$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
215
-		}
216
-
217
-		if ($share->getShareType() === Share::SHARE_TYPE_USER) {
218
-			$sharedWith = $this->userManager->get($share->getSharedWith());
219
-			$result['share_with'] = $share->getSharedWith();
220
-			$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
221
-		} else if ($share->getShareType() === Share::SHARE_TYPE_GROUP) {
222
-			$group = $this->groupManager->get($share->getSharedWith());
223
-			$result['share_with'] = $share->getSharedWith();
224
-			$result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
225
-		} else if ($share->getShareType() === IShare::TYPE_LINK) {
226
-
227
-			// "share_with" and "share_with_displayname" for passwords of link
228
-			// shares was deprecated in Nextcloud 15, use "password" instead.
229
-			$result['share_with'] = $share->getPassword();
230
-			$result['share_with_displayname'] = '(' . $this->l->t('Shared link') . ')';
231
-
232
-			$result['password'] = $share->getPassword();
233
-
234
-			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
235
-
236
-			$result['token'] = $share->getToken();
237
-			$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
238
-		} else if ($share->getShareType() === Share::SHARE_TYPE_REMOTE || $share->getShareType() === Share::SHARE_TYPE_REMOTE_GROUP) {
239
-			$result['share_with'] = $share->getSharedWith();
240
-			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
241
-			$result['token'] = $share->getToken();
242
-		} else if ($share->getShareType() === Share::SHARE_TYPE_EMAIL) {
243
-			$result['share_with'] = $share->getSharedWith();
244
-			$result['password'] = $share->getPassword();
245
-			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
246
-			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
247
-			$result['token'] = $share->getToken();
248
-		} else if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) {
249
-			// getSharedWith() returns either "name (type, owner)" or
250
-			// "name (type, owner) [id]", depending on the Circles app version.
251
-			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
252
-
253
-			$result['share_with_displayname'] = $share->getSharedWithDisplayName();
254
-			if (empty($result['share_with_displayname'])) {
255
-				$displayNameLength = ($hasCircleId ? strrpos($share->getSharedWith(), ' ') : strlen($share->getSharedWith()));
256
-				$result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
257
-			}
258
-
259
-			$result['share_with_avatar'] = $share->getSharedWithAvatar();
260
-
261
-			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
262
-			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
263
-			if (is_bool($shareWithLength)) {
264
-				$shareWithLength = -1;
265
-			}
266
-			$result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
267
-		} else if ($share->getShareType() === Share::SHARE_TYPE_ROOM) {
268
-			$result['share_with'] = $share->getSharedWith();
269
-			$result['share_with_displayname'] = '';
270
-
271
-			try {
272
-				$result = array_merge($result, $this->getRoomShareHelper()->formatShare($share));
273
-			} catch (QueryException $e) {}
274
-		}
275
-
276
-
277
-		$result['mail_send'] = $share->getMailSend() ? 1 : 0;
278
-		$result['hide_download'] = $share->getHideDownload() ? 1 : 0;
279
-
280
-		return $result;
281
-	}
282
-
283
-	/**
284
-	 * Check if one of the users address books knows the exact property, if
285
-	 * yes we return the full name.
286
-	 *
287
-	 * @param string $query
288
-	 * @param string $property
289
-	 * @return string
290
-	 */
291
-	private function getDisplayNameFromAddressBook(string $query, string $property): string {
292
-		// FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
293
-		$result = \OC::$server->getContactsManager()->search($query, [$property]);
294
-		foreach ($result as $r) {
295
-			foreach ($r[$property] as $value) {
296
-				if ($value === $query) {
297
-					return $r['FN'];
298
-				}
299
-			}
300
-		}
301
-
302
-		return $query;
303
-	}
304
-
305
-	/**
306
-	 * Get a specific share by id
307
-	 *
308
-	 * @NoAdminRequired
309
-	 *
310
-	 * @param string $id
311
-	 * @return DataResponse
312
-	 * @throws OCSNotFoundException
313
-	 */
314
-	public function getShare(string $id): DataResponse {
315
-		try {
316
-			$share = $this->getShareById($id);
317
-		} catch (ShareNotFound $e) {
318
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
319
-		}
320
-
321
-		try {
322
-			if ($this->canAccessShare($share)) {
323
-				$share = $this->formatShare($share);
324
-				return new DataResponse([$share]);
325
-			}
326
-		} catch (NotFoundException $e) {
327
-			// Fall trough
328
-		}
329
-
330
-		throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
331
-	}
332
-
333
-	/**
334
-	 * Delete a share
335
-	 *
336
-	 * @NoAdminRequired
337
-	 *
338
-	 * @param string $id
339
-	 * @return DataResponse
340
-	 * @throws OCSNotFoundException
341
-	 */
342
-	public function deleteShare(string $id): DataResponse {
343
-		try {
344
-			$share = $this->getShareById($id);
345
-		} catch (ShareNotFound $e) {
346
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
347
-		}
348
-
349
-		try {
350
-			$this->lock($share->getNode());
351
-		} catch (LockedException $e) {
352
-			throw new OCSNotFoundException($this->l->t('Could not delete share'));
353
-		}
354
-
355
-		if (!$this->canAccessShare($share)) {
356
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
357
-		}
358
-
359
-		// if it's a group share or a room share
360
-		// we don't delete the share, but only the
361
-		// mount point. Allowing it to be restored
362
-		// from the deleted shares
363
-		if ($this->canDeleteShareFromSelf($share)) {
364
-			$this->shareManager->deleteFromSelf($share, $this->currentUser);
365
-		} else {
366
-			if (!$this->canDeleteShare($share)) {
367
-				throw new OCSForbiddenException($this->l->t('Could not delete share'));
368
-			}
369
-
370
-			$this->shareManager->deleteShare($share);
371
-		}
372
-
373
-		return new DataResponse();
374
-	}
375
-
376
-	/**
377
-	 * @NoAdminRequired
378
-	 *
379
-	 * @param string $path
380
-	 * @param int $permissions
381
-	 * @param int $shareType
382
-	 * @param string $shareWith
383
-	 * @param string $publicUpload
384
-	 * @param string $password
385
-	 * @param string $sendPasswordByTalk
386
-	 * @param string $expireDate
387
-	 * @param string $label
388
-	 *
389
-	 * @return DataResponse
390
-	 * @throws NotFoundException
391
-	 * @throws OCSBadRequestException
392
-	 * @throws OCSException
393
-	 * @throws OCSForbiddenException
394
-	 * @throws OCSNotFoundException
395
-	 * @throws InvalidPathException
396
-	 * @suppress PhanUndeclaredClassMethod
397
-	 */
398
-	public function createShare(
399
-		string $path = null,
400
-		int $permissions = null,
401
-		int $shareType = -1,
402
-		string $shareWith = null,
403
-		string $publicUpload = 'false',
404
-		string $password = '',
405
-		string $sendPasswordByTalk = null,
406
-		string $expireDate = '',
407
-		string $label = ''
408
-	): DataResponse {
409
-		$share = $this->shareManager->newShare();
410
-
411
-		if ($permissions === null) {
412
-			$permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
413
-		}
414
-
415
-		// Verify path
416
-		if ($path === null) {
417
-			throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
418
-		}
419
-
420
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
421
-		try {
422
-			$path = $userFolder->get($path);
423
-		} catch (NotFoundException $e) {
424
-			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
425
-		}
426
-
427
-		$share->setNode($path);
428
-
429
-		try {
430
-			$this->lock($share->getNode());
431
-		} catch (LockedException $e) {
432
-			throw new OCSNotFoundException($this->l->t('Could not create share'));
433
-		}
434
-
435
-		if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) {
436
-			throw new OCSNotFoundException($this->l->t('invalid permissions'));
437
-		}
438
-
439
-		// Shares always require read permissions
440
-		$permissions |= Constants::PERMISSION_READ;
441
-
442
-		if ($path instanceof \OCP\Files\File) {
443
-			// Single file shares should never have delete or create permissions
444
-			$permissions &= ~Constants::PERMISSION_DELETE;
445
-			$permissions &= ~Constants::PERMISSION_CREATE;
446
-		}
447
-
448
-		/**
449
-		 * Hack for https://github.com/owncloud/core/issues/22587
450
-		 * We check the permissions via webdav. But the permissions of the mount point
451
-		 * do not equal the share permissions. Here we fix that for federated mounts.
452
-		 */
453
-		if ($path->getStorage()->instanceOfStorage(Storage::class)) {
454
-			$permissions &= ~($permissions & ~$path->getPermissions());
455
-		}
456
-
457
-		if ($shareType === Share::SHARE_TYPE_USER) {
458
-			// Valid user is required to share
459
-			if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
460
-				throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
461
-			}
462
-			$share->setSharedWith($shareWith);
463
-			$share->setPermissions($permissions);
464
-		} else if ($shareType === Share::SHARE_TYPE_GROUP) {
465
-			if (!$this->shareManager->allowGroupSharing()) {
466
-				throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
467
-			}
468
-
469
-			// Valid group is required to share
470
-			if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
471
-				throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
472
-			}
473
-			$share->setSharedWith($shareWith);
474
-			$share->setPermissions($permissions);
475
-		} else if ($shareType === Share::SHARE_TYPE_LINK
476
-			|| $shareType === Share::SHARE_TYPE_EMAIL) {
477
-
478
-			// Can we even share links?
479
-			if (!$this->shareManager->shareApiAllowLinks()) {
480
-				throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
481
-			}
482
-
483
-			if ($publicUpload === 'true') {
484
-				// Check if public upload is allowed
485
-				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
486
-					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
487
-				}
488
-
489
-				// Public upload can only be set for folders
490
-				if ($path instanceof \OCP\Files\File) {
491
-					throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
492
-				}
493
-
494
-				$share->setPermissions(
495
-					Constants::PERMISSION_READ |
496
-					Constants::PERMISSION_CREATE |
497
-					Constants::PERMISSION_UPDATE |
498
-					Constants::PERMISSION_DELETE
499
-				);
500
-			} else {
501
-				$share->setPermissions(Constants::PERMISSION_READ);
502
-			}
503
-
504
-			// Set password
505
-			if ($password !== '') {
506
-				$share->setPassword($password);
507
-			}
508
-
509
-			// Only share by mail have a recipient
510
-			if ($shareType === Share::SHARE_TYPE_EMAIL) {
511
-				$share->setSharedWith($shareWith);
512
-			} else {
513
-				// Only link share have a label
514
-				if (!empty($label)) {
515
-					$share->setLabel($label);
516
-				}
517
-			}
518
-
519
-			if ($sendPasswordByTalk === 'true') {
520
-				if (!$this->appManager->isEnabledForUser('spreed')) {
521
-					throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
522
-				}
523
-
524
-				$share->setSendPasswordByTalk(true);
525
-			}
526
-
527
-			//Expire date
528
-			if ($expireDate !== '') {
529
-				try {
530
-					$expireDate = $this->parseDate($expireDate);
531
-					$share->setExpirationDate($expireDate);
532
-				} catch (\Exception $e) {
533
-					throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
534
-				}
535
-			}
536
-		} else if ($shareType === Share::SHARE_TYPE_REMOTE) {
537
-			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
538
-				throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
539
-			}
540
-
541
-			$share->setSharedWith($shareWith);
542
-			$share->setPermissions($permissions);
543
-		} else if ($shareType === Share::SHARE_TYPE_REMOTE_GROUP) {
544
-			if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
545
-				throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
546
-			}
547
-
548
-			$share->setSharedWith($shareWith);
549
-			$share->setPermissions($permissions);
550
-		} else if ($shareType === Share::SHARE_TYPE_CIRCLE) {
551
-			if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
552
-				throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
553
-			}
554
-
555
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith);
556
-
557
-			// Valid circle is required to share
558
-			if ($circle === null) {
559
-				throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
560
-			}
561
-			$share->setSharedWith($shareWith);
562
-			$share->setPermissions($permissions);
563
-		} else if ($shareType === Share::SHARE_TYPE_ROOM) {
564
-			try {
565
-				$this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
566
-			} catch (QueryException $e) {
567
-				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
568
-			}
569
-		} else {
570
-			throw new OCSBadRequestException($this->l->t('Unknown share type'));
571
-		}
572
-
573
-		$share->setShareType($shareType);
574
-		$share->setSharedBy($this->currentUser);
575
-
576
-		try {
577
-			$share = $this->shareManager->createShare($share);
578
-		} catch (GenericShareException $e) {
579
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
580
-			throw new OCSException($e->getHint(), $code);
581
-		} catch (\Exception $e) {
582
-			throw new OCSForbiddenException($e->getMessage(), $e);
583
-		}
584
-
585
-		$output = $this->formatShare($share);
586
-
587
-		return new DataResponse($output);
588
-	}
589
-
590
-	/**
591
-	 * @param null|Node $node
592
-	 * @param boolean $includeTags
593
-	 *
594
-	 * @return array
595
-	 */
596
-	private function getSharedWithMe($node, bool $includeTags): array {
597
-
598
-		$userShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_USER, $node, -1, 0);
599
-		$groupShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_GROUP, $node, -1, 0);
600
-		$circleShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_CIRCLE, $node, -1, 0);
601
-		$roomShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_ROOM, $node, -1, 0);
602
-
603
-		$shares = array_merge($userShares, $groupShares, $circleShares, $roomShares);
604
-
605
-		$shares = array_filter($shares, function (IShare $share) {
606
-			return $share->getShareOwner() !== $this->currentUser;
607
-		});
608
-
609
-		$formatted = [];
610
-		foreach ($shares as $share) {
611
-			if ($this->canAccessShare($share)) {
612
-				try {
613
-					$formatted[] = $this->formatShare($share);
614
-				} catch (NotFoundException $e) {
615
-					// Ignore this share
616
-				}
617
-			}
618
-		}
619
-
620
-		if ($includeTags) {
621
-			$formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
622
-		}
623
-
624
-		return $formatted;
625
-	}
626
-
627
-	/**
628
-	 * @param \OCP\Files\Node $folder
629
-	 *
630
-	 * @return array
631
-	 * @throws OCSBadRequestException
632
-	 * @throws NotFoundException
633
-	 */
634
-	private function getSharesInDir(Node $folder): array {
635
-		if (!($folder instanceof \OCP\Files\Folder)) {
636
-			throw new OCSBadRequestException($this->l->t('Not a directory'));
637
-		}
638
-
639
-		$nodes = $folder->getDirectoryListing();
640
-
641
-		/** @var \OCP\Share\IShare[] $shares */
642
-		$shares = array_reduce($nodes, function ($carry, $node) {
643
-			$carry = array_merge($carry, $this->getAllShares($node, true));
644
-			return $carry;
645
-		}, []);
646
-
647
-		// filter out duplicate shares
648
-		$known = [];
649
-
650
-
651
-		$formatted = $miniFormatted = [];
652
-		$resharingRight = false;
653
-		$known = [];
654
-		foreach ($shares as $share) {
655
-			if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
656
-				continue;
657
-			}
658
-
659
-			try {
660
-				$format = $this->formatShare($share);
661
-
662
-				$known[] = $share->getId();
663
-				$formatted[] = $format;
664
-				if ($share->getSharedBy() === $this->currentUser) {
665
-					$miniFormatted[] = $format;
666
-				}
667
-				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $folder)) {
668
-					$resharingRight = true;
669
-				}
670
-			} catch (\Exception $e) {
671
-				//Ignore this share
672
-			}
673
-		}
674
-
675
-		if (!$resharingRight) {
676
-			$formatted = $miniFormatted;
677
-		}
678
-
679
-		return $formatted;
680
-	}
681
-
682
-	/**
683
-	 * The getShares function.
684
-	 *
685
-	 * @NoAdminRequired
686
-	 *
687
-	 * @param string $shared_with_me
688
-	 * @param string $reshares
689
-	 * @param string $subfiles
690
-	 * @param string $path
691
-	 *
692
-	 * - Get shares by the current user
693
-	 * - Get shares by the current user and reshares (?reshares=true)
694
-	 * - Get shares with the current user (?shared_with_me=true)
695
-	 * - Get shares for a specific path (?path=...)
696
-	 * - Get all shares in a folder (?subfiles=true&path=..)
697
-	 *
698
-	 * @param string $include_tags
699
-	 *
700
-	 * @return DataResponse
701
-	 * @throws NotFoundException
702
-	 * @throws OCSBadRequestException
703
-	 * @throws OCSNotFoundException
704
-	 */
705
-	public function getShares(
706
-		string $shared_with_me = 'false',
707
-		string $reshares = 'false',
708
-		string $subfiles = 'false',
709
-		string $path = '',
710
-		string $include_tags = 'false'
711
-	): DataResponse {
712
-
713
-		$node = null;
714
-		if ($path !== '') {
715
-			$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
716
-			try {
717
-				$node = $userFolder->get($path);
718
-				$this->lock($node);
719
-			} catch (NotFoundException $e) {
720
-				throw new OCSNotFoundException(
721
-					$this->l->t('Wrong path, file/folder doesn\'t exist')
722
-				);
723
-			} catch (LockedException $e) {
724
-				throw new OCSNotFoundException($this->l->t('Could not lock node'));
725
-			}
726
-		}
727
-
728
-		$shares = $this->getFormattedShares(
729
-			$this->currentUser,
730
-			$node,
731
-			($shared_with_me === 'true'),
732
-			($reshares === 'true'),
733
-			($subfiles === 'true'),
734
-			($include_tags === 'true')
735
-		);
736
-
737
-		return new DataResponse($shares);
738
-	}
739
-
740
-
741
-	/**
742
-	 * @param string $viewer
743
-	 * @param Node $node
744
-	 * @param bool $sharedWithMe
745
-	 * @param bool $reShares
746
-	 * @param bool $subFiles
747
-	 * @param bool $includeTags
748
-	 *
749
-	 * @return array
750
-	 * @throws NotFoundException
751
-	 * @throws OCSBadRequestException
752
-	 */
753
-	private function getFormattedShares(
754
-		string $viewer, $node = null, bool $sharedWithMe = false, bool $reShares = false,
755
-		bool $subFiles = false, bool $includeTags = false
756
-	): array {
757
-
758
-		if ($sharedWithMe) {
759
-			return $this->getSharedWithMe($node, $includeTags);
760
-		}
761
-
762
-		if ($subFiles) {
763
-			return $this->getSharesInDir($node);
764
-		}
765
-
766
-		$shares = $this->getSharesFromNode($viewer, $node, $reShares);
767
-
768
-		$known = $formatted = $miniFormatted = [];
769
-		$resharingRight = false;
770
-		foreach ($shares as $share) {
771
-			try {
772
-				$share->getNode();
773
-			} catch (NotFoundException $e) {
774
-				/*
79
+    /** @var IManager */
80
+    private $shareManager;
81
+    /** @var IGroupManager */
82
+    private $groupManager;
83
+    /** @var IUserManager */
84
+    private $userManager;
85
+    /** @var IRootFolder */
86
+    private $rootFolder;
87
+    /** @var IURLGenerator */
88
+    private $urlGenerator;
89
+    /** @var string */
90
+    private $currentUser;
91
+    /** @var IL10N */
92
+    private $l;
93
+    /** @var \OCP\Files\Node */
94
+    private $lockedNode;
95
+    /** @var IConfig */
96
+    private $config;
97
+    /** @var IAppManager */
98
+    private $appManager;
99
+    /** @var IServerContainer */
100
+    private $serverContainer;
101
+
102
+    /**
103
+     * Share20OCS constructor.
104
+     *
105
+     * @param string $appName
106
+     * @param IRequest $request
107
+     * @param IManager $shareManager
108
+     * @param IGroupManager $groupManager
109
+     * @param IUserManager $userManager
110
+     * @param IRootFolder $rootFolder
111
+     * @param IURLGenerator $urlGenerator
112
+     * @param string $userId
113
+     * @param IL10N $l10n
114
+     * @param IConfig $config
115
+     * @param IAppManager $appManager
116
+     * @param IServerContainer $serverContainer
117
+     */
118
+    public function __construct(
119
+        string $appName,
120
+        IRequest $request,
121
+        IManager $shareManager,
122
+        IGroupManager $groupManager,
123
+        IUserManager $userManager,
124
+        IRootFolder $rootFolder,
125
+        IURLGenerator $urlGenerator,
126
+        string $userId = null,
127
+        IL10N $l10n,
128
+        IConfig $config,
129
+        IAppManager $appManager,
130
+        IServerContainer $serverContainer
131
+    ) {
132
+        parent::__construct($appName, $request);
133
+
134
+        $this->shareManager = $shareManager;
135
+        $this->userManager = $userManager;
136
+        $this->groupManager = $groupManager;
137
+        $this->request = $request;
138
+        $this->rootFolder = $rootFolder;
139
+        $this->urlGenerator = $urlGenerator;
140
+        $this->currentUser = $userId;
141
+        $this->l = $l10n;
142
+        $this->config = $config;
143
+        $this->appManager = $appManager;
144
+        $this->serverContainer = $serverContainer;
145
+    }
146
+
147
+    /**
148
+     * Convert an IShare to an array for OCS output
149
+     *
150
+     * @param \OCP\Share\IShare $share
151
+     * @param Node|null $recipientNode
152
+     * @return array
153
+     * @throws NotFoundException In case the node can't be resolved.
154
+     *
155
+     * @suppress PhanUndeclaredClassMethod
156
+     */
157
+    protected function formatShare(\OCP\Share\IShare $share, Node $recipientNode = null): array {
158
+        $sharedBy = $this->userManager->get($share->getSharedBy());
159
+        $shareOwner = $this->userManager->get($share->getShareOwner());
160
+
161
+        $result = [
162
+            'id' => $share->getId(),
163
+            'share_type' => $share->getShareType(),
164
+            'uid_owner' => $share->getSharedBy(),
165
+            'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
166
+            // recipient permissions
167
+            'permissions' => $share->getPermissions(),
168
+            // current user permissions on this share
169
+            'can_edit' => $this->canEditShare($share),
170
+            'can_delete' => $this->canDeleteShare($share),
171
+            'stime' => $share->getShareTime()->getTimestamp(),
172
+            'parent' => null,
173
+            'expiration' => null,
174
+            'token' => null,
175
+            'uid_file_owner' => $share->getShareOwner(),
176
+            'note' => $share->getNote(),
177
+            'label' => $share->getLabel(),
178
+            'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
179
+        ];
180
+
181
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
182
+        if ($recipientNode) {
183
+            $node = $recipientNode;
184
+        } else {
185
+            $nodes = $userFolder->getById($share->getNodeId());
186
+            if (empty($nodes)) {
187
+                // fallback to guessing the path
188
+                $node = $userFolder->get($share->getTarget());
189
+                if ($node === null || $share->getTarget() === '') {
190
+                    throw new NotFoundException();
191
+                }
192
+            } else {
193
+                $node = reset($nodes);
194
+            }
195
+        }
196
+
197
+        $result['path'] = $userFolder->getRelativePath($node->getPath());
198
+        if ($node instanceof \OCP\Files\Folder) {
199
+            $result['item_type'] = 'folder';
200
+        } else {
201
+            $result['item_type'] = 'file';
202
+        }
203
+
204
+        $result['mimetype'] = $node->getMimetype();
205
+        $result['storage_id'] = $node->getStorage()->getId();
206
+        $result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
207
+        $result['item_source'] = $node->getId();
208
+        $result['file_source'] = $node->getId();
209
+        $result['file_parent'] = $node->getParent()->getId();
210
+        $result['file_target'] = $share->getTarget();
211
+
212
+        $expiration = $share->getExpirationDate();
213
+        if ($expiration !== null) {
214
+            $result['expiration'] = $expiration->format('Y-m-d 00:00:00');
215
+        }
216
+
217
+        if ($share->getShareType() === Share::SHARE_TYPE_USER) {
218
+            $sharedWith = $this->userManager->get($share->getSharedWith());
219
+            $result['share_with'] = $share->getSharedWith();
220
+            $result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
221
+        } else if ($share->getShareType() === Share::SHARE_TYPE_GROUP) {
222
+            $group = $this->groupManager->get($share->getSharedWith());
223
+            $result['share_with'] = $share->getSharedWith();
224
+            $result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
225
+        } else if ($share->getShareType() === IShare::TYPE_LINK) {
226
+
227
+            // "share_with" and "share_with_displayname" for passwords of link
228
+            // shares was deprecated in Nextcloud 15, use "password" instead.
229
+            $result['share_with'] = $share->getPassword();
230
+            $result['share_with_displayname'] = '(' . $this->l->t('Shared link') . ')';
231
+
232
+            $result['password'] = $share->getPassword();
233
+
234
+            $result['send_password_by_talk'] = $share->getSendPasswordByTalk();
235
+
236
+            $result['token'] = $share->getToken();
237
+            $result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
238
+        } else if ($share->getShareType() === Share::SHARE_TYPE_REMOTE || $share->getShareType() === Share::SHARE_TYPE_REMOTE_GROUP) {
239
+            $result['share_with'] = $share->getSharedWith();
240
+            $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
241
+            $result['token'] = $share->getToken();
242
+        } else if ($share->getShareType() === Share::SHARE_TYPE_EMAIL) {
243
+            $result['share_with'] = $share->getSharedWith();
244
+            $result['password'] = $share->getPassword();
245
+            $result['send_password_by_talk'] = $share->getSendPasswordByTalk();
246
+            $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
247
+            $result['token'] = $share->getToken();
248
+        } else if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) {
249
+            // getSharedWith() returns either "name (type, owner)" or
250
+            // "name (type, owner) [id]", depending on the Circles app version.
251
+            $hasCircleId = (substr($share->getSharedWith(), -1) === ']');
252
+
253
+            $result['share_with_displayname'] = $share->getSharedWithDisplayName();
254
+            if (empty($result['share_with_displayname'])) {
255
+                $displayNameLength = ($hasCircleId ? strrpos($share->getSharedWith(), ' ') : strlen($share->getSharedWith()));
256
+                $result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
257
+            }
258
+
259
+            $result['share_with_avatar'] = $share->getSharedWithAvatar();
260
+
261
+            $shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
262
+            $shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
263
+            if (is_bool($shareWithLength)) {
264
+                $shareWithLength = -1;
265
+            }
266
+            $result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
267
+        } else if ($share->getShareType() === Share::SHARE_TYPE_ROOM) {
268
+            $result['share_with'] = $share->getSharedWith();
269
+            $result['share_with_displayname'] = '';
270
+
271
+            try {
272
+                $result = array_merge($result, $this->getRoomShareHelper()->formatShare($share));
273
+            } catch (QueryException $e) {}
274
+        }
275
+
276
+
277
+        $result['mail_send'] = $share->getMailSend() ? 1 : 0;
278
+        $result['hide_download'] = $share->getHideDownload() ? 1 : 0;
279
+
280
+        return $result;
281
+    }
282
+
283
+    /**
284
+     * Check if one of the users address books knows the exact property, if
285
+     * yes we return the full name.
286
+     *
287
+     * @param string $query
288
+     * @param string $property
289
+     * @return string
290
+     */
291
+    private function getDisplayNameFromAddressBook(string $query, string $property): string {
292
+        // FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
293
+        $result = \OC::$server->getContactsManager()->search($query, [$property]);
294
+        foreach ($result as $r) {
295
+            foreach ($r[$property] as $value) {
296
+                if ($value === $query) {
297
+                    return $r['FN'];
298
+                }
299
+            }
300
+        }
301
+
302
+        return $query;
303
+    }
304
+
305
+    /**
306
+     * Get a specific share by id
307
+     *
308
+     * @NoAdminRequired
309
+     *
310
+     * @param string $id
311
+     * @return DataResponse
312
+     * @throws OCSNotFoundException
313
+     */
314
+    public function getShare(string $id): DataResponse {
315
+        try {
316
+            $share = $this->getShareById($id);
317
+        } catch (ShareNotFound $e) {
318
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
319
+        }
320
+
321
+        try {
322
+            if ($this->canAccessShare($share)) {
323
+                $share = $this->formatShare($share);
324
+                return new DataResponse([$share]);
325
+            }
326
+        } catch (NotFoundException $e) {
327
+            // Fall trough
328
+        }
329
+
330
+        throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
331
+    }
332
+
333
+    /**
334
+     * Delete a share
335
+     *
336
+     * @NoAdminRequired
337
+     *
338
+     * @param string $id
339
+     * @return DataResponse
340
+     * @throws OCSNotFoundException
341
+     */
342
+    public function deleteShare(string $id): DataResponse {
343
+        try {
344
+            $share = $this->getShareById($id);
345
+        } catch (ShareNotFound $e) {
346
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
347
+        }
348
+
349
+        try {
350
+            $this->lock($share->getNode());
351
+        } catch (LockedException $e) {
352
+            throw new OCSNotFoundException($this->l->t('Could not delete share'));
353
+        }
354
+
355
+        if (!$this->canAccessShare($share)) {
356
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
357
+        }
358
+
359
+        // if it's a group share or a room share
360
+        // we don't delete the share, but only the
361
+        // mount point. Allowing it to be restored
362
+        // from the deleted shares
363
+        if ($this->canDeleteShareFromSelf($share)) {
364
+            $this->shareManager->deleteFromSelf($share, $this->currentUser);
365
+        } else {
366
+            if (!$this->canDeleteShare($share)) {
367
+                throw new OCSForbiddenException($this->l->t('Could not delete share'));
368
+            }
369
+
370
+            $this->shareManager->deleteShare($share);
371
+        }
372
+
373
+        return new DataResponse();
374
+    }
375
+
376
+    /**
377
+     * @NoAdminRequired
378
+     *
379
+     * @param string $path
380
+     * @param int $permissions
381
+     * @param int $shareType
382
+     * @param string $shareWith
383
+     * @param string $publicUpload
384
+     * @param string $password
385
+     * @param string $sendPasswordByTalk
386
+     * @param string $expireDate
387
+     * @param string $label
388
+     *
389
+     * @return DataResponse
390
+     * @throws NotFoundException
391
+     * @throws OCSBadRequestException
392
+     * @throws OCSException
393
+     * @throws OCSForbiddenException
394
+     * @throws OCSNotFoundException
395
+     * @throws InvalidPathException
396
+     * @suppress PhanUndeclaredClassMethod
397
+     */
398
+    public function createShare(
399
+        string $path = null,
400
+        int $permissions = null,
401
+        int $shareType = -1,
402
+        string $shareWith = null,
403
+        string $publicUpload = 'false',
404
+        string $password = '',
405
+        string $sendPasswordByTalk = null,
406
+        string $expireDate = '',
407
+        string $label = ''
408
+    ): DataResponse {
409
+        $share = $this->shareManager->newShare();
410
+
411
+        if ($permissions === null) {
412
+            $permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
413
+        }
414
+
415
+        // Verify path
416
+        if ($path === null) {
417
+            throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
418
+        }
419
+
420
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
421
+        try {
422
+            $path = $userFolder->get($path);
423
+        } catch (NotFoundException $e) {
424
+            throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
425
+        }
426
+
427
+        $share->setNode($path);
428
+
429
+        try {
430
+            $this->lock($share->getNode());
431
+        } catch (LockedException $e) {
432
+            throw new OCSNotFoundException($this->l->t('Could not create share'));
433
+        }
434
+
435
+        if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) {
436
+            throw new OCSNotFoundException($this->l->t('invalid permissions'));
437
+        }
438
+
439
+        // Shares always require read permissions
440
+        $permissions |= Constants::PERMISSION_READ;
441
+
442
+        if ($path instanceof \OCP\Files\File) {
443
+            // Single file shares should never have delete or create permissions
444
+            $permissions &= ~Constants::PERMISSION_DELETE;
445
+            $permissions &= ~Constants::PERMISSION_CREATE;
446
+        }
447
+
448
+        /**
449
+         * Hack for https://github.com/owncloud/core/issues/22587
450
+         * We check the permissions via webdav. But the permissions of the mount point
451
+         * do not equal the share permissions. Here we fix that for federated mounts.
452
+         */
453
+        if ($path->getStorage()->instanceOfStorage(Storage::class)) {
454
+            $permissions &= ~($permissions & ~$path->getPermissions());
455
+        }
456
+
457
+        if ($shareType === Share::SHARE_TYPE_USER) {
458
+            // Valid user is required to share
459
+            if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
460
+                throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
461
+            }
462
+            $share->setSharedWith($shareWith);
463
+            $share->setPermissions($permissions);
464
+        } else if ($shareType === Share::SHARE_TYPE_GROUP) {
465
+            if (!$this->shareManager->allowGroupSharing()) {
466
+                throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
467
+            }
468
+
469
+            // Valid group is required to share
470
+            if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
471
+                throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
472
+            }
473
+            $share->setSharedWith($shareWith);
474
+            $share->setPermissions($permissions);
475
+        } else if ($shareType === Share::SHARE_TYPE_LINK
476
+            || $shareType === Share::SHARE_TYPE_EMAIL) {
477
+
478
+            // Can we even share links?
479
+            if (!$this->shareManager->shareApiAllowLinks()) {
480
+                throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
481
+            }
482
+
483
+            if ($publicUpload === 'true') {
484
+                // Check if public upload is allowed
485
+                if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
486
+                    throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
487
+                }
488
+
489
+                // Public upload can only be set for folders
490
+                if ($path instanceof \OCP\Files\File) {
491
+                    throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
492
+                }
493
+
494
+                $share->setPermissions(
495
+                    Constants::PERMISSION_READ |
496
+                    Constants::PERMISSION_CREATE |
497
+                    Constants::PERMISSION_UPDATE |
498
+                    Constants::PERMISSION_DELETE
499
+                );
500
+            } else {
501
+                $share->setPermissions(Constants::PERMISSION_READ);
502
+            }
503
+
504
+            // Set password
505
+            if ($password !== '') {
506
+                $share->setPassword($password);
507
+            }
508
+
509
+            // Only share by mail have a recipient
510
+            if ($shareType === Share::SHARE_TYPE_EMAIL) {
511
+                $share->setSharedWith($shareWith);
512
+            } else {
513
+                // Only link share have a label
514
+                if (!empty($label)) {
515
+                    $share->setLabel($label);
516
+                }
517
+            }
518
+
519
+            if ($sendPasswordByTalk === 'true') {
520
+                if (!$this->appManager->isEnabledForUser('spreed')) {
521
+                    throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
522
+                }
523
+
524
+                $share->setSendPasswordByTalk(true);
525
+            }
526
+
527
+            //Expire date
528
+            if ($expireDate !== '') {
529
+                try {
530
+                    $expireDate = $this->parseDate($expireDate);
531
+                    $share->setExpirationDate($expireDate);
532
+                } catch (\Exception $e) {
533
+                    throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
534
+                }
535
+            }
536
+        } else if ($shareType === Share::SHARE_TYPE_REMOTE) {
537
+            if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
538
+                throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
539
+            }
540
+
541
+            $share->setSharedWith($shareWith);
542
+            $share->setPermissions($permissions);
543
+        } else if ($shareType === Share::SHARE_TYPE_REMOTE_GROUP) {
544
+            if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
545
+                throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
546
+            }
547
+
548
+            $share->setSharedWith($shareWith);
549
+            $share->setPermissions($permissions);
550
+        } else if ($shareType === Share::SHARE_TYPE_CIRCLE) {
551
+            if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
552
+                throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
553
+            }
554
+
555
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith);
556
+
557
+            // Valid circle is required to share
558
+            if ($circle === null) {
559
+                throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
560
+            }
561
+            $share->setSharedWith($shareWith);
562
+            $share->setPermissions($permissions);
563
+        } else if ($shareType === Share::SHARE_TYPE_ROOM) {
564
+            try {
565
+                $this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
566
+            } catch (QueryException $e) {
567
+                throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
568
+            }
569
+        } else {
570
+            throw new OCSBadRequestException($this->l->t('Unknown share type'));
571
+        }
572
+
573
+        $share->setShareType($shareType);
574
+        $share->setSharedBy($this->currentUser);
575
+
576
+        try {
577
+            $share = $this->shareManager->createShare($share);
578
+        } catch (GenericShareException $e) {
579
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
580
+            throw new OCSException($e->getHint(), $code);
581
+        } catch (\Exception $e) {
582
+            throw new OCSForbiddenException($e->getMessage(), $e);
583
+        }
584
+
585
+        $output = $this->formatShare($share);
586
+
587
+        return new DataResponse($output);
588
+    }
589
+
590
+    /**
591
+     * @param null|Node $node
592
+     * @param boolean $includeTags
593
+     *
594
+     * @return array
595
+     */
596
+    private function getSharedWithMe($node, bool $includeTags): array {
597
+
598
+        $userShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_USER, $node, -1, 0);
599
+        $groupShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_GROUP, $node, -1, 0);
600
+        $circleShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_CIRCLE, $node, -1, 0);
601
+        $roomShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_ROOM, $node, -1, 0);
602
+
603
+        $shares = array_merge($userShares, $groupShares, $circleShares, $roomShares);
604
+
605
+        $shares = array_filter($shares, function (IShare $share) {
606
+            return $share->getShareOwner() !== $this->currentUser;
607
+        });
608
+
609
+        $formatted = [];
610
+        foreach ($shares as $share) {
611
+            if ($this->canAccessShare($share)) {
612
+                try {
613
+                    $formatted[] = $this->formatShare($share);
614
+                } catch (NotFoundException $e) {
615
+                    // Ignore this share
616
+                }
617
+            }
618
+        }
619
+
620
+        if ($includeTags) {
621
+            $formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
622
+        }
623
+
624
+        return $formatted;
625
+    }
626
+
627
+    /**
628
+     * @param \OCP\Files\Node $folder
629
+     *
630
+     * @return array
631
+     * @throws OCSBadRequestException
632
+     * @throws NotFoundException
633
+     */
634
+    private function getSharesInDir(Node $folder): array {
635
+        if (!($folder instanceof \OCP\Files\Folder)) {
636
+            throw new OCSBadRequestException($this->l->t('Not a directory'));
637
+        }
638
+
639
+        $nodes = $folder->getDirectoryListing();
640
+
641
+        /** @var \OCP\Share\IShare[] $shares */
642
+        $shares = array_reduce($nodes, function ($carry, $node) {
643
+            $carry = array_merge($carry, $this->getAllShares($node, true));
644
+            return $carry;
645
+        }, []);
646
+
647
+        // filter out duplicate shares
648
+        $known = [];
649
+
650
+
651
+        $formatted = $miniFormatted = [];
652
+        $resharingRight = false;
653
+        $known = [];
654
+        foreach ($shares as $share) {
655
+            if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
656
+                continue;
657
+            }
658
+
659
+            try {
660
+                $format = $this->formatShare($share);
661
+
662
+                $known[] = $share->getId();
663
+                $formatted[] = $format;
664
+                if ($share->getSharedBy() === $this->currentUser) {
665
+                    $miniFormatted[] = $format;
666
+                }
667
+                if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $folder)) {
668
+                    $resharingRight = true;
669
+                }
670
+            } catch (\Exception $e) {
671
+                //Ignore this share
672
+            }
673
+        }
674
+
675
+        if (!$resharingRight) {
676
+            $formatted = $miniFormatted;
677
+        }
678
+
679
+        return $formatted;
680
+    }
681
+
682
+    /**
683
+     * The getShares function.
684
+     *
685
+     * @NoAdminRequired
686
+     *
687
+     * @param string $shared_with_me
688
+     * @param string $reshares
689
+     * @param string $subfiles
690
+     * @param string $path
691
+     *
692
+     * - Get shares by the current user
693
+     * - Get shares by the current user and reshares (?reshares=true)
694
+     * - Get shares with the current user (?shared_with_me=true)
695
+     * - Get shares for a specific path (?path=...)
696
+     * - Get all shares in a folder (?subfiles=true&path=..)
697
+     *
698
+     * @param string $include_tags
699
+     *
700
+     * @return DataResponse
701
+     * @throws NotFoundException
702
+     * @throws OCSBadRequestException
703
+     * @throws OCSNotFoundException
704
+     */
705
+    public function getShares(
706
+        string $shared_with_me = 'false',
707
+        string $reshares = 'false',
708
+        string $subfiles = 'false',
709
+        string $path = '',
710
+        string $include_tags = 'false'
711
+    ): DataResponse {
712
+
713
+        $node = null;
714
+        if ($path !== '') {
715
+            $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
716
+            try {
717
+                $node = $userFolder->get($path);
718
+                $this->lock($node);
719
+            } catch (NotFoundException $e) {
720
+                throw new OCSNotFoundException(
721
+                    $this->l->t('Wrong path, file/folder doesn\'t exist')
722
+                );
723
+            } catch (LockedException $e) {
724
+                throw new OCSNotFoundException($this->l->t('Could not lock node'));
725
+            }
726
+        }
727
+
728
+        $shares = $this->getFormattedShares(
729
+            $this->currentUser,
730
+            $node,
731
+            ($shared_with_me === 'true'),
732
+            ($reshares === 'true'),
733
+            ($subfiles === 'true'),
734
+            ($include_tags === 'true')
735
+        );
736
+
737
+        return new DataResponse($shares);
738
+    }
739
+
740
+
741
+    /**
742
+     * @param string $viewer
743
+     * @param Node $node
744
+     * @param bool $sharedWithMe
745
+     * @param bool $reShares
746
+     * @param bool $subFiles
747
+     * @param bool $includeTags
748
+     *
749
+     * @return array
750
+     * @throws NotFoundException
751
+     * @throws OCSBadRequestException
752
+     */
753
+    private function getFormattedShares(
754
+        string $viewer, $node = null, bool $sharedWithMe = false, bool $reShares = false,
755
+        bool $subFiles = false, bool $includeTags = false
756
+    ): array {
757
+
758
+        if ($sharedWithMe) {
759
+            return $this->getSharedWithMe($node, $includeTags);
760
+        }
761
+
762
+        if ($subFiles) {
763
+            return $this->getSharesInDir($node);
764
+        }
765
+
766
+        $shares = $this->getSharesFromNode($viewer, $node, $reShares);
767
+
768
+        $known = $formatted = $miniFormatted = [];
769
+        $resharingRight = false;
770
+        foreach ($shares as $share) {
771
+            try {
772
+                $share->getNode();
773
+            } catch (NotFoundException $e) {
774
+                /*
775 775
 				 * Ignore shares where we can't get the node
776 776
 				 * For example delted shares
777 777
 				 */
778
-				continue;
779
-			}
780
-
781
-			if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
782
-				continue;
783
-			}
784
-
785
-			$known[] = $share->getId();
786
-			try {
787
-				/** @var IShare $share */
788
-				$format = $this->formatShare($share, $node);
789
-				$formatted[] = $format;
790
-
791
-				// let's also build a list of shares created
792
-				// by the current user only, in case
793
-				// there is no resharing rights
794
-				if ($share->getSharedBy() === $this->currentUser) {
795
-					$miniFormatted[] = $format;
796
-				}
797
-
798
-				// check if one of those share is shared with me
799
-				// and if I have resharing rights on it
800
-				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $node)) {
801
-					$resharingRight = true;
802
-				}
803
-			} catch (InvalidPathException | NotFoundException $e) {
804
-			}
805
-		}
806
-
807
-		if (!$resharingRight) {
808
-			$formatted = $miniFormatted;
809
-		}
810
-
811
-		if ($includeTags) {
812
-			$formatted =
813
-				Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
814
-		}
815
-
816
-		return $formatted;
817
-	}
818
-
819
-
820
-	/**
821
-	 * The getInheritedShares function.
822
-	 * returns all shares relative to a file, including parent folders shares rights.
823
-	 *
824
-	 * @NoAdminRequired
825
-	 *
826
-	 * @param string $path
827
-	 *
828
-	 * - Get shares by the current user
829
-	 * - Get shares by the current user and reshares (?reshares=true)
830
-	 * - Get shares with the current user (?shared_with_me=true)
831
-	 * - Get shares for a specific path (?path=...)
832
-	 * - Get all shares in a folder (?subfiles=true&path=..)
833
-	 *
834
-	 * @return DataResponse
835
-	 * @throws InvalidPathException
836
-	 * @throws NotFoundException
837
-	 * @throws OCSNotFoundException
838
-	 * @throws OCSBadRequestException
839
-	 * @throws SharingRightsException
840
-	 */
841
-	public function getInheritedShares(string $path): DataResponse {
842
-
843
-		// get Node from (string) path.
844
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
845
-		try {
846
-			$node = $userFolder->get($path);
847
-			$this->lock($node);
848
-		} catch (\OCP\Files\NotFoundException $e) {
849
-			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
850
-		} catch (LockedException $e) {
851
-			throw new OCSNotFoundException($this->l->t('Could not lock path'));
852
-		}
853
-
854
-		// current User has resharing rights ?
855
-		$this->confirmSharingRights($node);
856
-
857
-		// initiate real owner.
858
-		$owner = $node->getOwner()
859
-					  ->getUID();
860
-		if (!$this->userManager->userExists($owner)) {
861
-			return new DataResponse([]);
862
-		}
863
-
864
-		// get node based on the owner, fix owner in case of external storage
865
-		$userFolder = $this->rootFolder->getUserFolder($owner);
866
-		if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
867
-			$owner = $node->getOwner()
868
-						  ->getUID();
869
-			$userFolder = $this->rootFolder->getUserFolder($owner);
870
-			$nodes = $userFolder->getById($node->getId());
871
-			$node = array_shift($nodes);
872
-		}
873
-		$basePath = $userFolder->getPath();
874
-
875
-		// generate node list for each parent folders
876
-		/** @var Node[] $nodes */
877
-		$nodes = [];
878
-		while ($node->getPath() !== $basePath) {
879
-			$node = $node->getParent();
880
-			$nodes[] = $node;
881
-		}
882
-
883
-		// for each nodes, retrieve shares.
884
-		$shares = [];
885
-		foreach ($nodes as $node) {
886
-			$getShares = $this->getFormattedShares($owner, $node, false, true);
887
-			$this->mergeFormattedShares($shares, $getShares);
888
-		}
889
-
890
-		return new DataResponse(array_values($shares));
891
-	}
892
-
893
-
894
-	/**
895
-	 * @NoAdminRequired
896
-	 *
897
-	 * @param string $id
898
-	 * @param int $permissions
899
-	 * @param string $password
900
-	 * @param string $sendPasswordByTalk
901
-	 * @param string $publicUpload
902
-	 * @param string $expireDate
903
-	 * @param string $note
904
-	 * @param string $label
905
-	 * @param string $hideDownload
906
-	 * @return DataResponse
907
-	 * @throws LockedException
908
-	 * @throws NotFoundException
909
-	 * @throws OCSBadRequestException
910
-	 * @throws OCSForbiddenException
911
-	 * @throws OCSNotFoundException
912
-	 */
913
-	public function updateShare(
914
-		string $id,
915
-		int $permissions = null,
916
-		string $password = null,
917
-		string $sendPasswordByTalk = null,
918
-		string $publicUpload = null,
919
-		string $expireDate = null,
920
-		string $note = null,
921
-		string $label = null,
922
-		string $hideDownload = null
923
-	): DataResponse {
924
-		try {
925
-			$share = $this->getShareById($id);
926
-		} catch (ShareNotFound $e) {
927
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
928
-		}
929
-
930
-		$this->lock($share->getNode());
931
-
932
-		if (!$this->canAccessShare($share, false)) {
933
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
934
-		}
935
-
936
-		if (!$this->canEditShare($share)) {
937
-			throw new OCSForbiddenException('You are not allowed to edit incoming shares');
938
-		}
939
-
940
-		if (
941
-			$permissions === null &&
942
-			$password === null &&
943
-			$sendPasswordByTalk === null &&
944
-			$publicUpload === null &&
945
-			$expireDate === null &&
946
-			$note === null &&
947
-			$label === null &&
948
-			$hideDownload === null
949
-		) {
950
-			throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
951
-		}
952
-
953
-		if ($note !== null) {
954
-			$share->setNote($note);
955
-		}
956
-
957
-		/**
958
-		 * expirationdate, password and publicUpload only make sense for link shares
959
-		 */
960
-		if ($share->getShareType() === Share::SHARE_TYPE_LINK
961
-			|| $share->getShareType() === Share::SHARE_TYPE_EMAIL) {
962
-
963
-			/**
964
-			 * We do not allow editing link shares that the current user
965
-			 * doesn't own. This is confusing and lead to errors when
966
-			 * someone else edit a password or expiration date without
967
-			 * the share owner knowing about it.
968
-			 * We only allow deletion
969
-			 */
970
-
971
-			if ($share->getSharedBy() !== $this->currentUser) {
972
-				throw new OCSForbiddenException('You are not allowed to edit link shares that you don\'t own');
973
-			}
974
-
975
-			// Update hide download state
976
-			if ($hideDownload === 'true') {
977
-				$share->setHideDownload(true);
978
-			} else if ($hideDownload === 'false') {
979
-				$share->setHideDownload(false);
980
-			}
981
-
982
-			$newPermissions = null;
983
-			if ($publicUpload === 'true') {
984
-				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
985
-			} else if ($publicUpload === 'false') {
986
-				$newPermissions = Constants::PERMISSION_READ;
987
-			}
988
-
989
-			if ($permissions !== null) {
990
-				$newPermissions = (int) $permissions;
991
-				$newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE;
992
-			}
993
-
994
-			if ($newPermissions !== null &&
995
-				!in_array($newPermissions, [
996
-					Constants::PERMISSION_READ,
997
-					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy
998
-					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct
999
-					Constants::PERMISSION_CREATE, // hidden file list
1000
-					Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files
1001
-				], true)
1002
-			) {
1003
-				throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
1004
-			}
1005
-
1006
-			if (
1007
-				// legacy
1008
-				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) ||
1009
-				// correct
1010
-				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
1011
-			) {
1012
-				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
1013
-					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
1014
-				}
1015
-
1016
-				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
1017
-					throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
1018
-				}
1019
-
1020
-				// normalize to correct public upload permissions
1021
-				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1022
-			}
1023
-
1024
-			if ($newPermissions !== null) {
1025
-				$share->setPermissions($newPermissions);
1026
-				$permissions = $newPermissions;
1027
-			}
1028
-
1029
-			if ($expireDate === '') {
1030
-				$share->setExpirationDate(null);
1031
-			} else if ($expireDate !== null) {
1032
-				try {
1033
-					$expireDate = $this->parseDate($expireDate);
1034
-				} catch (\Exception $e) {
1035
-					throw new OCSBadRequestException($e->getMessage(), $e);
1036
-				}
1037
-				$share->setExpirationDate($expireDate);
1038
-			}
1039
-
1040
-			if ($password === '') {
1041
-				$share->setPassword(null);
1042
-			} else if ($password !== null) {
1043
-				$share->setPassword($password);
1044
-			}
1045
-
1046
-			// only link shares have labels
1047
-			if ($share->getShareType() === Share::SHARE_TYPE_LINK && $label !== null) {
1048
-				$share->setLabel($label);
1049
-			}
1050
-
1051
-			if ($sendPasswordByTalk === 'true') {
1052
-				if (!$this->appManager->isEnabledForUser('spreed')) {
1053
-					throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
1054
-				}
1055
-
1056
-				$share->setSendPasswordByTalk(true);
1057
-			} else if ($sendPasswordByTalk !== null) {
1058
-				$share->setSendPasswordByTalk(false);
1059
-			}
1060
-		}
1061
-
1062
-		// NOT A LINK SHARE
1063
-		else {
1064
-			if ($permissions !== null) {
1065
-				$permissions = (int) $permissions;
1066
-				$share->setPermissions($permissions);
1067
-			}
1068
-
1069
-			if ($expireDate === '') {
1070
-				$share->setExpirationDate(null);
1071
-			} else if ($expireDate !== null) {
1072
-				try {
1073
-					$expireDate = $this->parseDate($expireDate);
1074
-				} catch (\Exception $e) {
1075
-					throw new OCSBadRequestException($e->getMessage(), $e);
1076
-				}
1077
-				$share->setExpirationDate($expireDate);
1078
-			}
1079
-		}
1080
-
1081
-		try {
1082
-			$share = $this->shareManager->updateShare($share);
1083
-		} catch (GenericShareException $e) {
1084
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
1085
-			throw new OCSException($e->getHint(), $code);
1086
-		} catch (\Exception $e) {
1087
-			throw new OCSBadRequestException($e->getMessage(), $e);
1088
-		}
1089
-
1090
-		return new DataResponse($this->formatShare($share));
1091
-	}
1092
-
1093
-	/**
1094
-	 * @NoAdminRequired
1095
-	 */
1096
-	public function pendingShares(): DataResponse {
1097
-		$pendingShares = [];
1098
-
1099
-		$shareTypes = [
1100
-			IShare::TYPE_USER,
1101
-			IShare::TYPE_GROUP
1102
-		];
1103
-
1104
-		foreach ($shareTypes as $shareType) {
1105
-			$shares = $this->shareManager->getSharedWith($this->currentUser, $shareType, null, -1, 0);
1106
-
1107
-			foreach ($shares as $share) {
1108
-				if ($share->getStatus() === IShare::STATUS_PENDING || $share->getStatus() === IShare::STATUS_REJECTED) {
1109
-					$pendingShares[] = $share;
1110
-				}
1111
-			}
1112
-		}
1113
-
1114
-		$result = array_filter(array_map(function (IShare $share) {
1115
-			$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1116
-			$nodes = $userFolder->getById($share->getNodeId());
1117
-			if (empty($nodes)) {
1118
-				// fallback to guessing the path
1119
-				$node = $userFolder->get($share->getTarget());
1120
-				if ($node === null || $share->getTarget() === '') {
1121
-					return null;
1122
-				}
1123
-			} else {
1124
-				$node = $nodes[0];
1125
-			}
1126
-
1127
-			try {
1128
-				$formattedShare = $this->formatShare($share, $node);
1129
-				$formattedShare['status'] = $share->getStatus();
1130
-				$formattedShare['path'] = $share->getNode()->getName();
1131
-				$formattedShare['permissions'] = 0;
1132
-				return $formattedShare;
1133
-			} catch (NotFoundException $e) {
1134
-				return null;
1135
-			}
1136
-		}, $pendingShares), function ($entry) {
1137
-			return $entry !== null;
1138
-		});
1139
-
1140
-		return new DataResponse($result);
1141
-	}
1142
-
1143
-	/**
1144
-	 * @NoAdminRequired
1145
-	 *
1146
-	 * @param string $id
1147
-	 * @return DataResponse
1148
-	 * @throws OCSNotFoundException
1149
-	 * @throws OCSException
1150
-	 * @throws OCSBadRequestException
1151
-	 */
1152
-	public function acceptShare(string $id): DataResponse {
1153
-		try {
1154
-			$share = $this->getShareById($id);
1155
-		} catch (ShareNotFound $e) {
1156
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1157
-		}
1158
-
1159
-		if (!$this->canAccessShare($share)) {
1160
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1161
-		}
1162
-
1163
-		try {
1164
-			$this->shareManager->acceptShare($share, $this->currentUser);
1165
-		} catch (GenericShareException $e) {
1166
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
1167
-			throw new OCSException($e->getHint(), $code);
1168
-		} catch (\Exception $e) {
1169
-			throw new OCSBadRequestException($e->getMessage(), $e);
1170
-		}
1171
-
1172
-		return new DataResponse();
1173
-	}
1174
-
1175
-	/**
1176
-	 * Does the user have read permission on the share
1177
-	 *
1178
-	 * @param \OCP\Share\IShare $share the share to check
1179
-	 * @param boolean $checkGroups check groups as well?
1180
-	 * @return boolean
1181
-	 * @throws NotFoundException
1182
-	 *
1183
-	 * @suppress PhanUndeclaredClassMethod
1184
-	 */
1185
-	protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool {
1186
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1187
-		if ($share->getPermissions() === 0) {
1188
-			return false;
1189
-		}
1190
-
1191
-		// Owner of the file and the sharer of the file can always get share
1192
-		if ($share->getShareOwner() === $this->currentUser
1193
-			|| $share->getSharedBy() === $this->currentUser) {
1194
-			return true;
1195
-		}
1196
-
1197
-		// If the share is shared with you, you can access it!
1198
-		if ($share->getShareType() === Share::SHARE_TYPE_USER
1199
-			&& $share->getSharedWith() === $this->currentUser) {
1200
-			return true;
1201
-		}
1202
-
1203
-		// Have reshare rights on the shared file/folder ?
1204
-		// Does the currentUser have access to the shared file?
1205
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
1206
-		$files = $userFolder->getById($share->getNodeId());
1207
-		if (!empty($files) && $this->shareProviderResharingRights($this->currentUser, $share, $files[0])) {
1208
-			return true;
1209
-		}
1210
-
1211
-		// If in the recipient group, you can see the share
1212
-		if ($checkGroups && $share->getShareType() === Share::SHARE_TYPE_GROUP) {
1213
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1214
-			$user = $this->userManager->get($this->currentUser);
1215
-			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1216
-				return true;
1217
-			}
1218
-		}
1219
-
1220
-		if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) {
1221
-			// TODO: have a sanity check like above?
1222
-			return true;
1223
-		}
1224
-
1225
-		if ($share->getShareType() === Share::SHARE_TYPE_ROOM) {
1226
-			try {
1227
-				return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1228
-			} catch (QueryException $e) {
1229
-				return false;
1230
-			}
1231
-		}
1232
-
1233
-		return false;
1234
-	}
1235
-
1236
-	/**
1237
-	 * Does the user have edit permission on the share
1238
-	 *
1239
-	 * @param \OCP\Share\IShare $share the share to check
1240
-	 * @return boolean
1241
-	 */
1242
-	protected function canEditShare(\OCP\Share\IShare $share): bool {
1243
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1244
-		if ($share->getPermissions() === 0) {
1245
-			return false;
1246
-		}
1247
-
1248
-		// The owner of the file and the creator of the share
1249
-		// can always edit the share
1250
-		if ($share->getShareOwner() === $this->currentUser ||
1251
-			$share->getSharedBy() === $this->currentUser
1252
-		) {
1253
-			return true;
1254
-		}
1255
-
1256
-		//! we do NOT support some kind of `admin` in groups.
1257
-		//! You cannot edit shares shared to a group you're
1258
-		//! a member of if you're not the share owner or the file owner!
1259
-
1260
-		return false;
1261
-	}
1262
-
1263
-	/**
1264
-	 * Does the user have delete permission on the share
1265
-	 *
1266
-	 * @param \OCP\Share\IShare $share the share to check
1267
-	 * @return boolean
1268
-	 */
1269
-	protected function canDeleteShare(\OCP\Share\IShare $share): bool {
1270
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1271
-		if ($share->getPermissions() === 0) {
1272
-			return false;
1273
-		}
1274
-
1275
-		// if the user is the recipient, i can unshare
1276
-		// the share with self
1277
-		if ($share->getShareType() === Share::SHARE_TYPE_USER &&
1278
-			$share->getSharedWith() === $this->currentUser
1279
-		) {
1280
-			return true;
1281
-		}
1282
-
1283
-		// The owner of the file and the creator of the share
1284
-		// can always delete the share
1285
-		if ($share->getShareOwner() === $this->currentUser ||
1286
-			$share->getSharedBy() === $this->currentUser
1287
-		) {
1288
-			return true;
1289
-		}
1290
-
1291
-		return false;
1292
-	}
1293
-
1294
-	/**
1295
-	 * Does the user have delete permission on the share
1296
-	 * This differs from the canDeleteShare function as it only
1297
-	 * remove the share for the current user. It does NOT
1298
-	 * completely delete the share but only the mount point.
1299
-	 * It can then be restored from the deleted shares section.
1300
-	 *
1301
-	 * @param \OCP\Share\IShare $share the share to check
1302
-	 * @return boolean
1303
-	 *
1304
-	 * @suppress PhanUndeclaredClassMethod
1305
-	 */
1306
-	protected function canDeleteShareFromSelf(\OCP\Share\IShare $share): bool {
1307
-		if ($share->getShareType() !== IShare::TYPE_GROUP &&
1308
-			$share->getShareType() !== IShare::TYPE_ROOM
1309
-		) {
1310
-			return false;
1311
-		}
1312
-
1313
-		if ($share->getShareOwner() === $this->currentUser ||
1314
-			$share->getSharedBy() === $this->currentUser
1315
-		) {
1316
-			// Delete the whole share, not just for self
1317
-			return false;
1318
-		}
1319
-
1320
-		// If in the recipient group, you can delete the share from self
1321
-		if ($share->getShareType() === Share::SHARE_TYPE_GROUP) {
1322
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1323
-			$user = $this->userManager->get($this->currentUser);
1324
-			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1325
-				return true;
1326
-			}
1327
-		}
1328
-
1329
-		if ($share->getShareType() === Share::SHARE_TYPE_ROOM) {
1330
-			try {
1331
-				return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1332
-			} catch (QueryException $e) {
1333
-				return false;
1334
-			}
1335
-		}
1336
-
1337
-		return false;
1338
-	}
1339
-
1340
-	/**
1341
-	 * Make sure that the passed date is valid ISO 8601
1342
-	 * So YYYY-MM-DD
1343
-	 * If not throw an exception
1344
-	 *
1345
-	 * @param string $expireDate
1346
-	 *
1347
-	 * @throws \Exception
1348
-	 * @return \DateTime
1349
-	 */
1350
-	private function parseDate(string $expireDate): \DateTime {
1351
-		try {
1352
-			$date = new \DateTime($expireDate);
1353
-		} catch (\Exception $e) {
1354
-			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1355
-		}
1356
-
1357
-		if ($date === false) {
1358
-			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1359
-		}
1360
-
1361
-		$date->setTime(0, 0, 0);
1362
-
1363
-		return $date;
1364
-	}
1365
-
1366
-	/**
1367
-	 * Since we have multiple providers but the OCS Share API v1 does
1368
-	 * not support this we need to check all backends.
1369
-	 *
1370
-	 * @param string $id
1371
-	 * @return \OCP\Share\IShare
1372
-	 * @throws ShareNotFound
1373
-	 */
1374
-	private function getShareById(string $id): IShare {
1375
-		$share = null;
1376
-
1377
-		// First check if it is an internal share.
1378
-		try {
1379
-			$share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser);
1380
-			return $share;
1381
-		} catch (ShareNotFound $e) {
1382
-			// Do nothing, just try the other share type
1383
-		}
1384
-
1385
-
1386
-		try {
1387
-			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) {
1388
-				$share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
1389
-				return $share;
1390
-			}
1391
-		} catch (ShareNotFound $e) {
1392
-			// Do nothing, just try the other share type
1393
-		}
1394
-
1395
-		try {
1396
-			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
1397
-				$share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
1398
-				return $share;
1399
-			}
1400
-		} catch (ShareNotFound $e) {
1401
-			// Do nothing, just try the other share type
1402
-		}
1403
-
1404
-		try {
1405
-			$share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser);
1406
-			return $share;
1407
-		} catch (ShareNotFound $e) {
1408
-			// Do nothing, just try the other share type
1409
-		}
1410
-
1411
-		if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1412
-			throw new ShareNotFound();
1413
-		}
1414
-		$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser);
1415
-
1416
-		return $share;
1417
-	}
1418
-
1419
-	/**
1420
-	 * Lock a Node
1421
-	 *
1422
-	 * @param \OCP\Files\Node $node
1423
-	 * @throws LockedException
1424
-	 */
1425
-	private function lock(\OCP\Files\Node $node) {
1426
-		$node->lock(ILockingProvider::LOCK_SHARED);
1427
-		$this->lockedNode = $node;
1428
-	}
1429
-
1430
-	/**
1431
-	 * Cleanup the remaining locks
1432
-	 * @throws @LockedException
1433
-	 */
1434
-	public function cleanup() {
1435
-		if ($this->lockedNode !== null) {
1436
-			$this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1437
-		}
1438
-	}
1439
-
1440
-	/**
1441
-	 * Returns the helper of ShareAPIController for room shares.
1442
-	 *
1443
-	 * If the Talk application is not enabled or the helper is not available
1444
-	 * a QueryException is thrown instead.
1445
-	 *
1446
-	 * @return \OCA\Talk\Share\Helper\ShareAPIController
1447
-	 * @throws QueryException
1448
-	 */
1449
-	private function getRoomShareHelper() {
1450
-		if (!$this->appManager->isEnabledForUser('spreed')) {
1451
-			throw new QueryException();
1452
-		}
1453
-
1454
-		return $this->serverContainer->query('\OCA\Talk\Share\Helper\ShareAPIController');
1455
-	}
1456
-
1457
-
1458
-	/**
1459
-	 * @param string $viewer
1460
-	 * @param Node $node
1461
-	 * @param bool $reShares
1462
-	 *
1463
-	 * @return IShare[]
1464
-	 */
1465
-	private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1466
-
1467
-		$providers = [
1468
-			Share::SHARE_TYPE_USER,
1469
-			Share::SHARE_TYPE_GROUP,
1470
-			Share::SHARE_TYPE_LINK,
1471
-			Share::SHARE_TYPE_EMAIL,
1472
-			Share::SHARE_TYPE_EMAIL,
1473
-			Share::SHARE_TYPE_CIRCLE,
1474
-			Share::SHARE_TYPE_ROOM
1475
-		];
1476
-
1477
-		// Should we assume that the (currentUser) viewer is the owner of the node !?
1478
-		$shares = [];
1479
-		foreach ($providers as $provider) {
1480
-			if (!$this->shareManager->shareProviderExists($provider)) {
1481
-				continue;
1482
-			}
1483
-
1484
-			$providerShares =
1485
-				$this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
1486
-			$shares = array_merge($shares, $providerShares);
1487
-		}
1488
-
1489
-		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1490
-			$federatedShares = $this->shareManager->getSharesBy(
1491
-				$this->currentUser, Share::SHARE_TYPE_REMOTE, $node, $reShares, -1, 0
1492
-			);
1493
-			$shares = array_merge($shares, $federatedShares);
1494
-		}
1495
-
1496
-		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1497
-			$federatedShares = $this->shareManager->getSharesBy(
1498
-				$this->currentUser, Share::SHARE_TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
1499
-			);
1500
-			$shares = array_merge($shares, $federatedShares);
1501
-		}
1502
-
1503
-		return $shares;
1504
-	}
1505
-
1506
-
1507
-	/**
1508
-	 * @param Node $node
1509
-	 *
1510
-	 * @throws SharingRightsException
1511
-	 */
1512
-	private function confirmSharingRights(Node $node): void {
1513
-		if (!$this->hasResharingRights($this->currentUser, $node)) {
1514
-			throw new SharingRightsException('no sharing rights on this item');
1515
-		}
1516
-	}
1517
-
1518
-
1519
-	/**
1520
-	 * @param string $viewer
1521
-	 * @param Node $node
1522
-	 *
1523
-	 * @return bool
1524
-	 */
1525
-	private function hasResharingRights($viewer, $node): bool {
1526
-		if ($viewer === $node->getOwner()->getUID()) {
1527
-			return true;
1528
-		}
1529
-
1530
-		foreach ([$node, $node->getParent()] as $node) {
1531
-			$shares = $this->getSharesFromNode($viewer, $node, true);
1532
-			foreach ($shares as $share) {
1533
-				try {
1534
-					if ($this->shareProviderResharingRights($viewer, $share, $node)) {
1535
-						return true;
1536
-					}
1537
-				} catch (InvalidPathException | NotFoundException $e) {
1538
-				}
1539
-			}
1540
-		}
1541
-
1542
-		return false;
1543
-	}
1544
-
1545
-
1546
-	/**
1547
-	 * Returns if we can find resharing rights in an IShare object for a specific user.
1548
-	 *
1549
-	 * @suppress PhanUndeclaredClassMethod
1550
-	 *
1551
-	 * @param string $userId
1552
-	 * @param IShare $share
1553
-	 * @param Node $node
1554
-	 *
1555
-	 * @return bool
1556
-	 * @throws NotFoundException
1557
-	 * @throws InvalidPathException
1558
-	 */
1559
-	private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1560
-		if ($share->getShareOwner() === $userId) {
1561
-			return true;
1562
-		}
1563
-
1564
-		// we check that current user have parent resharing rights on the current file
1565
-		if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
1566
-			return true;
1567
-		}
1568
-
1569
-		if ((\OCP\Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1570
-			return false;
1571
-		}
1572
-
1573
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() === $userId) {
1574
-			return true;
1575
-		}
1576
-
1577
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
1578
-			return true;
1579
-		}
1580
-
1581
-		if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles')
1582
-			&& class_exists('\OCA\Circles\Api\v1\Circles')) {
1583
-
1584
-			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
1585
-			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1586
-			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1587
-			if (is_bool($shareWithLength)) {
1588
-				$shareWithLength = -1;
1589
-			}
1590
-			$sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1591
-			try {
1592
-				$member = \OCA\Circles\Api\v1\Circles::getMember($sharedWith, $userId, 1);
1593
-				if ($member->getLevel() >= 4) {
1594
-					return true;
1595
-				}
1596
-				return false;
1597
-			} catch (QueryException $e) {
1598
-				return false;
1599
-			}
1600
-		}
1601
-
1602
-		return false;
1603
-	}
1604
-
1605
-	/**
1606
-	 * Get all the shares for the current user
1607
-	 *
1608
-	 * @param Node|null $path
1609
-	 * @param boolean $reshares
1610
-	 * @return void
1611
-	 */
1612
-	private function getAllShares(?Node $path = null, bool $reshares = false) {
1613
-		// Get all shares
1614
-		$userShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
1615
-		$groupShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
1616
-		$linkShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
1617
-
1618
-		// EMAIL SHARES
1619
-		$mailShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_EMAIL, $path, $reshares, -1, 0);
1620
-
1621
-		// CIRCLE SHARES
1622
-		$circleShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_CIRCLE, $path, $reshares, -1, 0);
1623
-
1624
-		// TALK SHARES
1625
-		$roomShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_ROOM, $path, $reshares, -1, 0);
1626
-
1627
-		// FEDERATION
1628
-		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1629
-			$federatedShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);
1630
-		} else {
1631
-			$federatedShares = [];
1632
-		}
1633
-		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1634
-			$federatedGroupShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
1635
-		} else {
1636
-			$federatedGroupShares = [];
1637
-		}
1638
-
1639
-		return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $federatedShares, $federatedGroupShares);
1640
-	}
1641
-
1642
-
1643
-	/**
1644
-	 * merging already formatted shares.
1645
-	 * We'll make an associative array to easily detect duplicate Ids.
1646
-	 * Keys _needs_ to be removed after all shares are retrieved and merged.
1647
-	 *
1648
-	 * @param array $shares
1649
-	 * @param array $newShares
1650
-	 */
1651
-	private function mergeFormattedShares(array &$shares, array $newShares) {
1652
-		foreach ($newShares as $newShare) {
1653
-			if (!array_key_exists($newShare['id'], $shares)) {
1654
-				$shares[$newShare['id']] = $newShare;
1655
-			}
1656
-		}
1657
-	}
778
+                continue;
779
+            }
780
+
781
+            if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
782
+                continue;
783
+            }
784
+
785
+            $known[] = $share->getId();
786
+            try {
787
+                /** @var IShare $share */
788
+                $format = $this->formatShare($share, $node);
789
+                $formatted[] = $format;
790
+
791
+                // let's also build a list of shares created
792
+                // by the current user only, in case
793
+                // there is no resharing rights
794
+                if ($share->getSharedBy() === $this->currentUser) {
795
+                    $miniFormatted[] = $format;
796
+                }
797
+
798
+                // check if one of those share is shared with me
799
+                // and if I have resharing rights on it
800
+                if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $node)) {
801
+                    $resharingRight = true;
802
+                }
803
+            } catch (InvalidPathException | NotFoundException $e) {
804
+            }
805
+        }
806
+
807
+        if (!$resharingRight) {
808
+            $formatted = $miniFormatted;
809
+        }
810
+
811
+        if ($includeTags) {
812
+            $formatted =
813
+                Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
814
+        }
815
+
816
+        return $formatted;
817
+    }
818
+
819
+
820
+    /**
821
+     * The getInheritedShares function.
822
+     * returns all shares relative to a file, including parent folders shares rights.
823
+     *
824
+     * @NoAdminRequired
825
+     *
826
+     * @param string $path
827
+     *
828
+     * - Get shares by the current user
829
+     * - Get shares by the current user and reshares (?reshares=true)
830
+     * - Get shares with the current user (?shared_with_me=true)
831
+     * - Get shares for a specific path (?path=...)
832
+     * - Get all shares in a folder (?subfiles=true&path=..)
833
+     *
834
+     * @return DataResponse
835
+     * @throws InvalidPathException
836
+     * @throws NotFoundException
837
+     * @throws OCSNotFoundException
838
+     * @throws OCSBadRequestException
839
+     * @throws SharingRightsException
840
+     */
841
+    public function getInheritedShares(string $path): DataResponse {
842
+
843
+        // get Node from (string) path.
844
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
845
+        try {
846
+            $node = $userFolder->get($path);
847
+            $this->lock($node);
848
+        } catch (\OCP\Files\NotFoundException $e) {
849
+            throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
850
+        } catch (LockedException $e) {
851
+            throw new OCSNotFoundException($this->l->t('Could not lock path'));
852
+        }
853
+
854
+        // current User has resharing rights ?
855
+        $this->confirmSharingRights($node);
856
+
857
+        // initiate real owner.
858
+        $owner = $node->getOwner()
859
+                        ->getUID();
860
+        if (!$this->userManager->userExists($owner)) {
861
+            return new DataResponse([]);
862
+        }
863
+
864
+        // get node based on the owner, fix owner in case of external storage
865
+        $userFolder = $this->rootFolder->getUserFolder($owner);
866
+        if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
867
+            $owner = $node->getOwner()
868
+                            ->getUID();
869
+            $userFolder = $this->rootFolder->getUserFolder($owner);
870
+            $nodes = $userFolder->getById($node->getId());
871
+            $node = array_shift($nodes);
872
+        }
873
+        $basePath = $userFolder->getPath();
874
+
875
+        // generate node list for each parent folders
876
+        /** @var Node[] $nodes */
877
+        $nodes = [];
878
+        while ($node->getPath() !== $basePath) {
879
+            $node = $node->getParent();
880
+            $nodes[] = $node;
881
+        }
882
+
883
+        // for each nodes, retrieve shares.
884
+        $shares = [];
885
+        foreach ($nodes as $node) {
886
+            $getShares = $this->getFormattedShares($owner, $node, false, true);
887
+            $this->mergeFormattedShares($shares, $getShares);
888
+        }
889
+
890
+        return new DataResponse(array_values($shares));
891
+    }
892
+
893
+
894
+    /**
895
+     * @NoAdminRequired
896
+     *
897
+     * @param string $id
898
+     * @param int $permissions
899
+     * @param string $password
900
+     * @param string $sendPasswordByTalk
901
+     * @param string $publicUpload
902
+     * @param string $expireDate
903
+     * @param string $note
904
+     * @param string $label
905
+     * @param string $hideDownload
906
+     * @return DataResponse
907
+     * @throws LockedException
908
+     * @throws NotFoundException
909
+     * @throws OCSBadRequestException
910
+     * @throws OCSForbiddenException
911
+     * @throws OCSNotFoundException
912
+     */
913
+    public function updateShare(
914
+        string $id,
915
+        int $permissions = null,
916
+        string $password = null,
917
+        string $sendPasswordByTalk = null,
918
+        string $publicUpload = null,
919
+        string $expireDate = null,
920
+        string $note = null,
921
+        string $label = null,
922
+        string $hideDownload = null
923
+    ): DataResponse {
924
+        try {
925
+            $share = $this->getShareById($id);
926
+        } catch (ShareNotFound $e) {
927
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
928
+        }
929
+
930
+        $this->lock($share->getNode());
931
+
932
+        if (!$this->canAccessShare($share, false)) {
933
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
934
+        }
935
+
936
+        if (!$this->canEditShare($share)) {
937
+            throw new OCSForbiddenException('You are not allowed to edit incoming shares');
938
+        }
939
+
940
+        if (
941
+            $permissions === null &&
942
+            $password === null &&
943
+            $sendPasswordByTalk === null &&
944
+            $publicUpload === null &&
945
+            $expireDate === null &&
946
+            $note === null &&
947
+            $label === null &&
948
+            $hideDownload === null
949
+        ) {
950
+            throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
951
+        }
952
+
953
+        if ($note !== null) {
954
+            $share->setNote($note);
955
+        }
956
+
957
+        /**
958
+         * expirationdate, password and publicUpload only make sense for link shares
959
+         */
960
+        if ($share->getShareType() === Share::SHARE_TYPE_LINK
961
+            || $share->getShareType() === Share::SHARE_TYPE_EMAIL) {
962
+
963
+            /**
964
+             * We do not allow editing link shares that the current user
965
+             * doesn't own. This is confusing and lead to errors when
966
+             * someone else edit a password or expiration date without
967
+             * the share owner knowing about it.
968
+             * We only allow deletion
969
+             */
970
+
971
+            if ($share->getSharedBy() !== $this->currentUser) {
972
+                throw new OCSForbiddenException('You are not allowed to edit link shares that you don\'t own');
973
+            }
974
+
975
+            // Update hide download state
976
+            if ($hideDownload === 'true') {
977
+                $share->setHideDownload(true);
978
+            } else if ($hideDownload === 'false') {
979
+                $share->setHideDownload(false);
980
+            }
981
+
982
+            $newPermissions = null;
983
+            if ($publicUpload === 'true') {
984
+                $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
985
+            } else if ($publicUpload === 'false') {
986
+                $newPermissions = Constants::PERMISSION_READ;
987
+            }
988
+
989
+            if ($permissions !== null) {
990
+                $newPermissions = (int) $permissions;
991
+                $newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE;
992
+            }
993
+
994
+            if ($newPermissions !== null &&
995
+                !in_array($newPermissions, [
996
+                    Constants::PERMISSION_READ,
997
+                    Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy
998
+                    Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct
999
+                    Constants::PERMISSION_CREATE, // hidden file list
1000
+                    Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files
1001
+                ], true)
1002
+            ) {
1003
+                throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
1004
+            }
1005
+
1006
+            if (
1007
+                // legacy
1008
+                $newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) ||
1009
+                // correct
1010
+                $newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
1011
+            ) {
1012
+                if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
1013
+                    throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
1014
+                }
1015
+
1016
+                if (!($share->getNode() instanceof \OCP\Files\Folder)) {
1017
+                    throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
1018
+                }
1019
+
1020
+                // normalize to correct public upload permissions
1021
+                $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1022
+            }
1023
+
1024
+            if ($newPermissions !== null) {
1025
+                $share->setPermissions($newPermissions);
1026
+                $permissions = $newPermissions;
1027
+            }
1028
+
1029
+            if ($expireDate === '') {
1030
+                $share->setExpirationDate(null);
1031
+            } else if ($expireDate !== null) {
1032
+                try {
1033
+                    $expireDate = $this->parseDate($expireDate);
1034
+                } catch (\Exception $e) {
1035
+                    throw new OCSBadRequestException($e->getMessage(), $e);
1036
+                }
1037
+                $share->setExpirationDate($expireDate);
1038
+            }
1039
+
1040
+            if ($password === '') {
1041
+                $share->setPassword(null);
1042
+            } else if ($password !== null) {
1043
+                $share->setPassword($password);
1044
+            }
1045
+
1046
+            // only link shares have labels
1047
+            if ($share->getShareType() === Share::SHARE_TYPE_LINK && $label !== null) {
1048
+                $share->setLabel($label);
1049
+            }
1050
+
1051
+            if ($sendPasswordByTalk === 'true') {
1052
+                if (!$this->appManager->isEnabledForUser('spreed')) {
1053
+                    throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
1054
+                }
1055
+
1056
+                $share->setSendPasswordByTalk(true);
1057
+            } else if ($sendPasswordByTalk !== null) {
1058
+                $share->setSendPasswordByTalk(false);
1059
+            }
1060
+        }
1061
+
1062
+        // NOT A LINK SHARE
1063
+        else {
1064
+            if ($permissions !== null) {
1065
+                $permissions = (int) $permissions;
1066
+                $share->setPermissions($permissions);
1067
+            }
1068
+
1069
+            if ($expireDate === '') {
1070
+                $share->setExpirationDate(null);
1071
+            } else if ($expireDate !== null) {
1072
+                try {
1073
+                    $expireDate = $this->parseDate($expireDate);
1074
+                } catch (\Exception $e) {
1075
+                    throw new OCSBadRequestException($e->getMessage(), $e);
1076
+                }
1077
+                $share->setExpirationDate($expireDate);
1078
+            }
1079
+        }
1080
+
1081
+        try {
1082
+            $share = $this->shareManager->updateShare($share);
1083
+        } catch (GenericShareException $e) {
1084
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
1085
+            throw new OCSException($e->getHint(), $code);
1086
+        } catch (\Exception $e) {
1087
+            throw new OCSBadRequestException($e->getMessage(), $e);
1088
+        }
1089
+
1090
+        return new DataResponse($this->formatShare($share));
1091
+    }
1092
+
1093
+    /**
1094
+     * @NoAdminRequired
1095
+     */
1096
+    public function pendingShares(): DataResponse {
1097
+        $pendingShares = [];
1098
+
1099
+        $shareTypes = [
1100
+            IShare::TYPE_USER,
1101
+            IShare::TYPE_GROUP
1102
+        ];
1103
+
1104
+        foreach ($shareTypes as $shareType) {
1105
+            $shares = $this->shareManager->getSharedWith($this->currentUser, $shareType, null, -1, 0);
1106
+
1107
+            foreach ($shares as $share) {
1108
+                if ($share->getStatus() === IShare::STATUS_PENDING || $share->getStatus() === IShare::STATUS_REJECTED) {
1109
+                    $pendingShares[] = $share;
1110
+                }
1111
+            }
1112
+        }
1113
+
1114
+        $result = array_filter(array_map(function (IShare $share) {
1115
+            $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1116
+            $nodes = $userFolder->getById($share->getNodeId());
1117
+            if (empty($nodes)) {
1118
+                // fallback to guessing the path
1119
+                $node = $userFolder->get($share->getTarget());
1120
+                if ($node === null || $share->getTarget() === '') {
1121
+                    return null;
1122
+                }
1123
+            } else {
1124
+                $node = $nodes[0];
1125
+            }
1126
+
1127
+            try {
1128
+                $formattedShare = $this->formatShare($share, $node);
1129
+                $formattedShare['status'] = $share->getStatus();
1130
+                $formattedShare['path'] = $share->getNode()->getName();
1131
+                $formattedShare['permissions'] = 0;
1132
+                return $formattedShare;
1133
+            } catch (NotFoundException $e) {
1134
+                return null;
1135
+            }
1136
+        }, $pendingShares), function ($entry) {
1137
+            return $entry !== null;
1138
+        });
1139
+
1140
+        return new DataResponse($result);
1141
+    }
1142
+
1143
+    /**
1144
+     * @NoAdminRequired
1145
+     *
1146
+     * @param string $id
1147
+     * @return DataResponse
1148
+     * @throws OCSNotFoundException
1149
+     * @throws OCSException
1150
+     * @throws OCSBadRequestException
1151
+     */
1152
+    public function acceptShare(string $id): DataResponse {
1153
+        try {
1154
+            $share = $this->getShareById($id);
1155
+        } catch (ShareNotFound $e) {
1156
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1157
+        }
1158
+
1159
+        if (!$this->canAccessShare($share)) {
1160
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1161
+        }
1162
+
1163
+        try {
1164
+            $this->shareManager->acceptShare($share, $this->currentUser);
1165
+        } catch (GenericShareException $e) {
1166
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
1167
+            throw new OCSException($e->getHint(), $code);
1168
+        } catch (\Exception $e) {
1169
+            throw new OCSBadRequestException($e->getMessage(), $e);
1170
+        }
1171
+
1172
+        return new DataResponse();
1173
+    }
1174
+
1175
+    /**
1176
+     * Does the user have read permission on the share
1177
+     *
1178
+     * @param \OCP\Share\IShare $share the share to check
1179
+     * @param boolean $checkGroups check groups as well?
1180
+     * @return boolean
1181
+     * @throws NotFoundException
1182
+     *
1183
+     * @suppress PhanUndeclaredClassMethod
1184
+     */
1185
+    protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool {
1186
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1187
+        if ($share->getPermissions() === 0) {
1188
+            return false;
1189
+        }
1190
+
1191
+        // Owner of the file and the sharer of the file can always get share
1192
+        if ($share->getShareOwner() === $this->currentUser
1193
+            || $share->getSharedBy() === $this->currentUser) {
1194
+            return true;
1195
+        }
1196
+
1197
+        // If the share is shared with you, you can access it!
1198
+        if ($share->getShareType() === Share::SHARE_TYPE_USER
1199
+            && $share->getSharedWith() === $this->currentUser) {
1200
+            return true;
1201
+        }
1202
+
1203
+        // Have reshare rights on the shared file/folder ?
1204
+        // Does the currentUser have access to the shared file?
1205
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
1206
+        $files = $userFolder->getById($share->getNodeId());
1207
+        if (!empty($files) && $this->shareProviderResharingRights($this->currentUser, $share, $files[0])) {
1208
+            return true;
1209
+        }
1210
+
1211
+        // If in the recipient group, you can see the share
1212
+        if ($checkGroups && $share->getShareType() === Share::SHARE_TYPE_GROUP) {
1213
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1214
+            $user = $this->userManager->get($this->currentUser);
1215
+            if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1216
+                return true;
1217
+            }
1218
+        }
1219
+
1220
+        if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) {
1221
+            // TODO: have a sanity check like above?
1222
+            return true;
1223
+        }
1224
+
1225
+        if ($share->getShareType() === Share::SHARE_TYPE_ROOM) {
1226
+            try {
1227
+                return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1228
+            } catch (QueryException $e) {
1229
+                return false;
1230
+            }
1231
+        }
1232
+
1233
+        return false;
1234
+    }
1235
+
1236
+    /**
1237
+     * Does the user have edit permission on the share
1238
+     *
1239
+     * @param \OCP\Share\IShare $share the share to check
1240
+     * @return boolean
1241
+     */
1242
+    protected function canEditShare(\OCP\Share\IShare $share): bool {
1243
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1244
+        if ($share->getPermissions() === 0) {
1245
+            return false;
1246
+        }
1247
+
1248
+        // The owner of the file and the creator of the share
1249
+        // can always edit the share
1250
+        if ($share->getShareOwner() === $this->currentUser ||
1251
+            $share->getSharedBy() === $this->currentUser
1252
+        ) {
1253
+            return true;
1254
+        }
1255
+
1256
+        //! we do NOT support some kind of `admin` in groups.
1257
+        //! You cannot edit shares shared to a group you're
1258
+        //! a member of if you're not the share owner or the file owner!
1259
+
1260
+        return false;
1261
+    }
1262
+
1263
+    /**
1264
+     * Does the user have delete permission on the share
1265
+     *
1266
+     * @param \OCP\Share\IShare $share the share to check
1267
+     * @return boolean
1268
+     */
1269
+    protected function canDeleteShare(\OCP\Share\IShare $share): bool {
1270
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1271
+        if ($share->getPermissions() === 0) {
1272
+            return false;
1273
+        }
1274
+
1275
+        // if the user is the recipient, i can unshare
1276
+        // the share with self
1277
+        if ($share->getShareType() === Share::SHARE_TYPE_USER &&
1278
+            $share->getSharedWith() === $this->currentUser
1279
+        ) {
1280
+            return true;
1281
+        }
1282
+
1283
+        // The owner of the file and the creator of the share
1284
+        // can always delete the share
1285
+        if ($share->getShareOwner() === $this->currentUser ||
1286
+            $share->getSharedBy() === $this->currentUser
1287
+        ) {
1288
+            return true;
1289
+        }
1290
+
1291
+        return false;
1292
+    }
1293
+
1294
+    /**
1295
+     * Does the user have delete permission on the share
1296
+     * This differs from the canDeleteShare function as it only
1297
+     * remove the share for the current user. It does NOT
1298
+     * completely delete the share but only the mount point.
1299
+     * It can then be restored from the deleted shares section.
1300
+     *
1301
+     * @param \OCP\Share\IShare $share the share to check
1302
+     * @return boolean
1303
+     *
1304
+     * @suppress PhanUndeclaredClassMethod
1305
+     */
1306
+    protected function canDeleteShareFromSelf(\OCP\Share\IShare $share): bool {
1307
+        if ($share->getShareType() !== IShare::TYPE_GROUP &&
1308
+            $share->getShareType() !== IShare::TYPE_ROOM
1309
+        ) {
1310
+            return false;
1311
+        }
1312
+
1313
+        if ($share->getShareOwner() === $this->currentUser ||
1314
+            $share->getSharedBy() === $this->currentUser
1315
+        ) {
1316
+            // Delete the whole share, not just for self
1317
+            return false;
1318
+        }
1319
+
1320
+        // If in the recipient group, you can delete the share from self
1321
+        if ($share->getShareType() === Share::SHARE_TYPE_GROUP) {
1322
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1323
+            $user = $this->userManager->get($this->currentUser);
1324
+            if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1325
+                return true;
1326
+            }
1327
+        }
1328
+
1329
+        if ($share->getShareType() === Share::SHARE_TYPE_ROOM) {
1330
+            try {
1331
+                return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1332
+            } catch (QueryException $e) {
1333
+                return false;
1334
+            }
1335
+        }
1336
+
1337
+        return false;
1338
+    }
1339
+
1340
+    /**
1341
+     * Make sure that the passed date is valid ISO 8601
1342
+     * So YYYY-MM-DD
1343
+     * If not throw an exception
1344
+     *
1345
+     * @param string $expireDate
1346
+     *
1347
+     * @throws \Exception
1348
+     * @return \DateTime
1349
+     */
1350
+    private function parseDate(string $expireDate): \DateTime {
1351
+        try {
1352
+            $date = new \DateTime($expireDate);
1353
+        } catch (\Exception $e) {
1354
+            throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1355
+        }
1356
+
1357
+        if ($date === false) {
1358
+            throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1359
+        }
1360
+
1361
+        $date->setTime(0, 0, 0);
1362
+
1363
+        return $date;
1364
+    }
1365
+
1366
+    /**
1367
+     * Since we have multiple providers but the OCS Share API v1 does
1368
+     * not support this we need to check all backends.
1369
+     *
1370
+     * @param string $id
1371
+     * @return \OCP\Share\IShare
1372
+     * @throws ShareNotFound
1373
+     */
1374
+    private function getShareById(string $id): IShare {
1375
+        $share = null;
1376
+
1377
+        // First check if it is an internal share.
1378
+        try {
1379
+            $share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser);
1380
+            return $share;
1381
+        } catch (ShareNotFound $e) {
1382
+            // Do nothing, just try the other share type
1383
+        }
1384
+
1385
+
1386
+        try {
1387
+            if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) {
1388
+                $share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
1389
+                return $share;
1390
+            }
1391
+        } catch (ShareNotFound $e) {
1392
+            // Do nothing, just try the other share type
1393
+        }
1394
+
1395
+        try {
1396
+            if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
1397
+                $share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
1398
+                return $share;
1399
+            }
1400
+        } catch (ShareNotFound $e) {
1401
+            // Do nothing, just try the other share type
1402
+        }
1403
+
1404
+        try {
1405
+            $share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser);
1406
+            return $share;
1407
+        } catch (ShareNotFound $e) {
1408
+            // Do nothing, just try the other share type
1409
+        }
1410
+
1411
+        if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1412
+            throw new ShareNotFound();
1413
+        }
1414
+        $share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser);
1415
+
1416
+        return $share;
1417
+    }
1418
+
1419
+    /**
1420
+     * Lock a Node
1421
+     *
1422
+     * @param \OCP\Files\Node $node
1423
+     * @throws LockedException
1424
+     */
1425
+    private function lock(\OCP\Files\Node $node) {
1426
+        $node->lock(ILockingProvider::LOCK_SHARED);
1427
+        $this->lockedNode = $node;
1428
+    }
1429
+
1430
+    /**
1431
+     * Cleanup the remaining locks
1432
+     * @throws @LockedException
1433
+     */
1434
+    public function cleanup() {
1435
+        if ($this->lockedNode !== null) {
1436
+            $this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1437
+        }
1438
+    }
1439
+
1440
+    /**
1441
+     * Returns the helper of ShareAPIController for room shares.
1442
+     *
1443
+     * If the Talk application is not enabled or the helper is not available
1444
+     * a QueryException is thrown instead.
1445
+     *
1446
+     * @return \OCA\Talk\Share\Helper\ShareAPIController
1447
+     * @throws QueryException
1448
+     */
1449
+    private function getRoomShareHelper() {
1450
+        if (!$this->appManager->isEnabledForUser('spreed')) {
1451
+            throw new QueryException();
1452
+        }
1453
+
1454
+        return $this->serverContainer->query('\OCA\Talk\Share\Helper\ShareAPIController');
1455
+    }
1456
+
1457
+
1458
+    /**
1459
+     * @param string $viewer
1460
+     * @param Node $node
1461
+     * @param bool $reShares
1462
+     *
1463
+     * @return IShare[]
1464
+     */
1465
+    private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1466
+
1467
+        $providers = [
1468
+            Share::SHARE_TYPE_USER,
1469
+            Share::SHARE_TYPE_GROUP,
1470
+            Share::SHARE_TYPE_LINK,
1471
+            Share::SHARE_TYPE_EMAIL,
1472
+            Share::SHARE_TYPE_EMAIL,
1473
+            Share::SHARE_TYPE_CIRCLE,
1474
+            Share::SHARE_TYPE_ROOM
1475
+        ];
1476
+
1477
+        // Should we assume that the (currentUser) viewer is the owner of the node !?
1478
+        $shares = [];
1479
+        foreach ($providers as $provider) {
1480
+            if (!$this->shareManager->shareProviderExists($provider)) {
1481
+                continue;
1482
+            }
1483
+
1484
+            $providerShares =
1485
+                $this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
1486
+            $shares = array_merge($shares, $providerShares);
1487
+        }
1488
+
1489
+        if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1490
+            $federatedShares = $this->shareManager->getSharesBy(
1491
+                $this->currentUser, Share::SHARE_TYPE_REMOTE, $node, $reShares, -1, 0
1492
+            );
1493
+            $shares = array_merge($shares, $federatedShares);
1494
+        }
1495
+
1496
+        if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1497
+            $federatedShares = $this->shareManager->getSharesBy(
1498
+                $this->currentUser, Share::SHARE_TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
1499
+            );
1500
+            $shares = array_merge($shares, $federatedShares);
1501
+        }
1502
+
1503
+        return $shares;
1504
+    }
1505
+
1506
+
1507
+    /**
1508
+     * @param Node $node
1509
+     *
1510
+     * @throws SharingRightsException
1511
+     */
1512
+    private function confirmSharingRights(Node $node): void {
1513
+        if (!$this->hasResharingRights($this->currentUser, $node)) {
1514
+            throw new SharingRightsException('no sharing rights on this item');
1515
+        }
1516
+    }
1517
+
1518
+
1519
+    /**
1520
+     * @param string $viewer
1521
+     * @param Node $node
1522
+     *
1523
+     * @return bool
1524
+     */
1525
+    private function hasResharingRights($viewer, $node): bool {
1526
+        if ($viewer === $node->getOwner()->getUID()) {
1527
+            return true;
1528
+        }
1529
+
1530
+        foreach ([$node, $node->getParent()] as $node) {
1531
+            $shares = $this->getSharesFromNode($viewer, $node, true);
1532
+            foreach ($shares as $share) {
1533
+                try {
1534
+                    if ($this->shareProviderResharingRights($viewer, $share, $node)) {
1535
+                        return true;
1536
+                    }
1537
+                } catch (InvalidPathException | NotFoundException $e) {
1538
+                }
1539
+            }
1540
+        }
1541
+
1542
+        return false;
1543
+    }
1544
+
1545
+
1546
+    /**
1547
+     * Returns if we can find resharing rights in an IShare object for a specific user.
1548
+     *
1549
+     * @suppress PhanUndeclaredClassMethod
1550
+     *
1551
+     * @param string $userId
1552
+     * @param IShare $share
1553
+     * @param Node $node
1554
+     *
1555
+     * @return bool
1556
+     * @throws NotFoundException
1557
+     * @throws InvalidPathException
1558
+     */
1559
+    private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1560
+        if ($share->getShareOwner() === $userId) {
1561
+            return true;
1562
+        }
1563
+
1564
+        // we check that current user have parent resharing rights on the current file
1565
+        if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
1566
+            return true;
1567
+        }
1568
+
1569
+        if ((\OCP\Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1570
+            return false;
1571
+        }
1572
+
1573
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_USER && $share->getSharedWith() === $userId) {
1574
+            return true;
1575
+        }
1576
+
1577
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
1578
+            return true;
1579
+        }
1580
+
1581
+        if ($share->getShareType() === \OCP\Share::SHARE_TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles')
1582
+            && class_exists('\OCA\Circles\Api\v1\Circles')) {
1583
+
1584
+            $hasCircleId = (substr($share->getSharedWith(), -1) === ']');
1585
+            $shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1586
+            $shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1587
+            if (is_bool($shareWithLength)) {
1588
+                $shareWithLength = -1;
1589
+            }
1590
+            $sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1591
+            try {
1592
+                $member = \OCA\Circles\Api\v1\Circles::getMember($sharedWith, $userId, 1);
1593
+                if ($member->getLevel() >= 4) {
1594
+                    return true;
1595
+                }
1596
+                return false;
1597
+            } catch (QueryException $e) {
1598
+                return false;
1599
+            }
1600
+        }
1601
+
1602
+        return false;
1603
+    }
1604
+
1605
+    /**
1606
+     * Get all the shares for the current user
1607
+     *
1608
+     * @param Node|null $path
1609
+     * @param boolean $reshares
1610
+     * @return void
1611
+     */
1612
+    private function getAllShares(?Node $path = null, bool $reshares = false) {
1613
+        // Get all shares
1614
+        $userShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_USER, $path, $reshares, -1, 0);
1615
+        $groupShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0);
1616
+        $linkShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0);
1617
+
1618
+        // EMAIL SHARES
1619
+        $mailShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_EMAIL, $path, $reshares, -1, 0);
1620
+
1621
+        // CIRCLE SHARES
1622
+        $circleShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_CIRCLE, $path, $reshares, -1, 0);
1623
+
1624
+        // TALK SHARES
1625
+        $roomShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_ROOM, $path, $reshares, -1, 0);
1626
+
1627
+        // FEDERATION
1628
+        if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1629
+            $federatedShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0);
1630
+        } else {
1631
+            $federatedShares = [];
1632
+        }
1633
+        if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1634
+            $federatedGroupShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
1635
+        } else {
1636
+            $federatedGroupShares = [];
1637
+        }
1638
+
1639
+        return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $federatedShares, $federatedGroupShares);
1640
+    }
1641
+
1642
+
1643
+    /**
1644
+     * merging already formatted shares.
1645
+     * We'll make an associative array to easily detect duplicate Ids.
1646
+     * Keys _needs_ to be removed after all shares are retrieved and merged.
1647
+     *
1648
+     * @param array $shares
1649
+     * @param array $newShares
1650
+     */
1651
+    private function mergeFormattedShares(array &$shares, array $newShares) {
1652
+        foreach ($newShares as $newShare) {
1653
+            if (!array_key_exists($newShare['id'], $shares)) {
1654
+                $shares[$newShare['id']] = $newShare;
1655
+            }
1656
+        }
1657
+    }
1658 1658
 
1659 1659
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -227,7 +227,7 @@  discard block
 block discarded – undo
227 227
 			// "share_with" and "share_with_displayname" for passwords of link
228 228
 			// shares was deprecated in Nextcloud 15, use "password" instead.
229 229
 			$result['share_with'] = $share->getPassword();
230
-			$result['share_with_displayname'] = '(' . $this->l->t('Shared link') . ')';
230
+			$result['share_with_displayname'] = '('.$this->l->t('Shared link').')';
231 231
 
232 232
 			$result['password'] = $share->getPassword();
233 233
 
@@ -602,7 +602,7 @@  discard block
 block discarded – undo
602 602
 
603 603
 		$shares = array_merge($userShares, $groupShares, $circleShares, $roomShares);
604 604
 
605
-		$shares = array_filter($shares, function (IShare $share) {
605
+		$shares = array_filter($shares, function(IShare $share) {
606 606
 			return $share->getShareOwner() !== $this->currentUser;
607 607
 		});
608 608
 
@@ -639,7 +639,7 @@  discard block
 block discarded – undo
639 639
 		$nodes = $folder->getDirectoryListing();
640 640
 
641 641
 		/** @var \OCP\Share\IShare[] $shares */
642
-		$shares = array_reduce($nodes, function ($carry, $node) {
642
+		$shares = array_reduce($nodes, function($carry, $node) {
643 643
 			$carry = array_merge($carry, $this->getAllShares($node, true));
644 644
 			return $carry;
645 645
 		}, []);
@@ -1111,7 +1111,7 @@  discard block
 block discarded – undo
1111 1111
 			}
1112 1112
 		}
1113 1113
 
1114
-		$result = array_filter(array_map(function (IShare $share) {
1114
+		$result = array_filter(array_map(function(IShare $share) {
1115 1115
 			$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1116 1116
 			$nodes = $userFolder->getById($share->getNodeId());
1117 1117
 			if (empty($nodes)) {
@@ -1133,7 +1133,7 @@  discard block
 block discarded – undo
1133 1133
 			} catch (NotFoundException $e) {
1134 1134
 				return null;
1135 1135
 			}
1136
-		}, $pendingShares), function ($entry) {
1136
+		}, $pendingShares), function($entry) {
1137 1137
 			return $entry !== null;
1138 1138
 		});
1139 1139
 
@@ -1376,7 +1376,7 @@  discard block
 block discarded – undo
1376 1376
 
1377 1377
 		// First check if it is an internal share.
1378 1378
 		try {
1379
-			$share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser);
1379
+			$share = $this->shareManager->getShareById('ocinternal:'.$id, $this->currentUser);
1380 1380
 			return $share;
1381 1381
 		} catch (ShareNotFound $e) {
1382 1382
 			// Do nothing, just try the other share type
@@ -1385,7 +1385,7 @@  discard block
 block discarded – undo
1385 1385
 
1386 1386
 		try {
1387 1387
 			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) {
1388
-				$share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
1388
+				$share = $this->shareManager->getShareById('ocCircleShare:'.$id, $this->currentUser);
1389 1389
 				return $share;
1390 1390
 			}
1391 1391
 		} catch (ShareNotFound $e) {
@@ -1394,7 +1394,7 @@  discard block
 block discarded – undo
1394 1394
 
1395 1395
 		try {
1396 1396
 			if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) {
1397
-				$share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
1397
+				$share = $this->shareManager->getShareById('ocMailShare:'.$id, $this->currentUser);
1398 1398
 				return $share;
1399 1399
 			}
1400 1400
 		} catch (ShareNotFound $e) {
@@ -1402,7 +1402,7 @@  discard block
 block discarded – undo
1402 1402
 		}
1403 1403
 
1404 1404
 		try {
1405
-			$share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser);
1405
+			$share = $this->shareManager->getShareById('ocRoomShare:'.$id, $this->currentUser);
1406 1406
 			return $share;
1407 1407
 		} catch (ShareNotFound $e) {
1408 1408
 			// Do nothing, just try the other share type
@@ -1411,7 +1411,7 @@  discard block
 block discarded – undo
1411 1411
 		if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1412 1412
 			throw new ShareNotFound();
1413 1413
 		}
1414
-		$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser);
1414
+		$share = $this->shareManager->getShareById('ocFederatedSharing:'.$id, $this->currentUser);
1415 1415
 
1416 1416
 		return $share;
1417 1417
 	}
Please login to merge, or discard this patch.