Passed
Push — master ( 98d2f3...812bc8 )
by Blizzz
13:53 queued 11s
created
apps/provisioning_api/lib/Controller/UsersController.php 1 patch
Indentation   +1013 added lines, -1013 removed lines patch added patch discarded remove patch
@@ -75,1017 +75,1017 @@
 block discarded – undo
75 75
 
76 76
 class UsersController extends AUserData {
77 77
 
78
-	/** @var IAppManager */
79
-	private $appManager;
80
-	/** @var IURLGenerator */
81
-	protected $urlGenerator;
82
-	/** @var LoggerInterface */
83
-	private $logger;
84
-	/** @var IFactory */
85
-	protected $l10nFactory;
86
-	/** @var NewUserMailHelper */
87
-	private $newUserMailHelper;
88
-	/** @var FederatedShareProviderFactory */
89
-	private $federatedShareProviderFactory;
90
-	/** @var ISecureRandom */
91
-	private $secureRandom;
92
-	/** @var RemoteWipe */
93
-	private $remoteWipe;
94
-	/** @var KnownUserService */
95
-	private $knownUserService;
96
-	/** @var IEventDispatcher */
97
-	private $eventDispatcher;
98
-
99
-	public function __construct(string $appName,
100
-								IRequest $request,
101
-								IUserManager $userManager,
102
-								IConfig $config,
103
-								IAppManager $appManager,
104
-								IGroupManager $groupManager,
105
-								IUserSession $userSession,
106
-								AccountManager $accountManager,
107
-								IURLGenerator $urlGenerator,
108
-								LoggerInterface $logger,
109
-								IFactory $l10nFactory,
110
-								NewUserMailHelper $newUserMailHelper,
111
-								FederatedShareProviderFactory $federatedShareProviderFactory,
112
-								ISecureRandom $secureRandom,
113
-								RemoteWipe $remoteWipe,
114
-								KnownUserService $knownUserService,
115
-								IEventDispatcher $eventDispatcher) {
116
-		parent::__construct($appName,
117
-							$request,
118
-							$userManager,
119
-							$config,
120
-							$groupManager,
121
-							$userSession,
122
-							$accountManager,
123
-							$l10nFactory);
124
-
125
-		$this->appManager = $appManager;
126
-		$this->urlGenerator = $urlGenerator;
127
-		$this->logger = $logger;
128
-		$this->l10nFactory = $l10nFactory;
129
-		$this->newUserMailHelper = $newUserMailHelper;
130
-		$this->federatedShareProviderFactory = $federatedShareProviderFactory;
131
-		$this->secureRandom = $secureRandom;
132
-		$this->remoteWipe = $remoteWipe;
133
-		$this->knownUserService = $knownUserService;
134
-		$this->eventDispatcher = $eventDispatcher;
135
-	}
136
-
137
-	/**
138
-	 * @NoAdminRequired
139
-	 *
140
-	 * returns a list of users
141
-	 *
142
-	 * @param string $search
143
-	 * @param int $limit
144
-	 * @param int $offset
145
-	 * @return DataResponse
146
-	 */
147
-	public function getUsers(string $search = '', int $limit = null, int $offset = 0): DataResponse {
148
-		$user = $this->userSession->getUser();
149
-		$users = [];
150
-
151
-		// Admin? Or SubAdmin?
152
-		$uid = $user->getUID();
153
-		$subAdminManager = $this->groupManager->getSubAdmin();
154
-		if ($this->groupManager->isAdmin($uid)) {
155
-			$users = $this->userManager->search($search, $limit, $offset);
156
-		} elseif ($subAdminManager->isSubAdmin($user)) {
157
-			$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($user);
158
-			foreach ($subAdminOfGroups as $key => $group) {
159
-				$subAdminOfGroups[$key] = $group->getGID();
160
-			}
161
-
162
-			$users = [];
163
-			foreach ($subAdminOfGroups as $group) {
164
-				$users = array_merge($users, $this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
165
-			}
166
-		}
167
-
168
-		$users = array_keys($users);
169
-
170
-		return new DataResponse([
171
-			'users' => $users
172
-		]);
173
-	}
174
-
175
-	/**
176
-	 * @NoAdminRequired
177
-	 *
178
-	 * returns a list of users and their data
179
-	 */
180
-	public function getUsersDetails(string $search = '', int $limit = null, int $offset = 0): DataResponse {
181
-		$currentUser = $this->userSession->getUser();
182
-		$users = [];
183
-
184
-		// Admin? Or SubAdmin?
185
-		$uid = $currentUser->getUID();
186
-		$subAdminManager = $this->groupManager->getSubAdmin();
187
-		if ($this->groupManager->isAdmin($uid)) {
188
-			$users = $this->userManager->search($search, $limit, $offset);
189
-			$users = array_keys($users);
190
-		} elseif ($subAdminManager->isSubAdmin($currentUser)) {
191
-			$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
192
-			foreach ($subAdminOfGroups as $key => $group) {
193
-				$subAdminOfGroups[$key] = $group->getGID();
194
-			}
195
-
196
-			$users = [];
197
-			foreach ($subAdminOfGroups as $group) {
198
-				$users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
199
-			}
200
-			$users = array_merge(...$users);
201
-		}
202
-
203
-		$usersDetails = [];
204
-		foreach ($users as $userId) {
205
-			$userId = (string) $userId;
206
-			$userData = $this->getUserData($userId);
207
-			// Do not insert empty entry
208
-			if (!empty($userData)) {
209
-				$usersDetails[$userId] = $userData;
210
-			} else {
211
-				// Logged user does not have permissions to see this user
212
-				// only showing its id
213
-				$usersDetails[$userId] = ['id' => $userId];
214
-			}
215
-		}
216
-
217
-		return new DataResponse([
218
-			'users' => $usersDetails
219
-		]);
220
-	}
221
-
222
-
223
-	/**
224
-	 * @NoAdminRequired
225
-	 * @NoSubAdminRequired
226
-	 *
227
-	 * @param string $location
228
-	 * @param array $search
229
-	 * @return DataResponse
230
-	 */
231
-	public function searchByPhoneNumbers(string $location, array $search): DataResponse {
232
-		$phoneUtil = PhoneNumberUtil::getInstance();
233
-
234
-		if ($phoneUtil->getCountryCodeForRegion($location) === 0) {
235
-			// Not a valid region code
236
-			return new DataResponse([], Http::STATUS_BAD_REQUEST);
237
-		}
238
-
239
-		/** @var IUser $user */
240
-		$user = $this->userSession->getUser();
241
-		$knownTo = $user->getUID();
242
-
243
-		$normalizedNumberToKey = [];
244
-		foreach ($search as $key => $phoneNumbers) {
245
-			foreach ($phoneNumbers as $phone) {
246
-				try {
247
-					$phoneNumber = $phoneUtil->parse($phone, $location);
248
-					if ($phoneNumber instanceof PhoneNumber && $phoneUtil->isValidNumber($phoneNumber)) {
249
-						$normalizedNumber = $phoneUtil->format($phoneNumber, PhoneNumberFormat::E164);
250
-						$normalizedNumberToKey[$normalizedNumber] = (string) $key;
251
-					}
252
-				} catch (NumberParseException $e) {
253
-				}
254
-			}
255
-		}
256
-
257
-		$phoneNumbers = array_keys($normalizedNumberToKey);
258
-
259
-		if (empty($phoneNumbers)) {
260
-			return new DataResponse();
261
-		}
262
-
263
-		// Cleanup all previous entries and only allow new matches
264
-		$this->knownUserService->deleteKnownTo($knownTo);
265
-
266
-		$userMatches = $this->accountManager->searchUsers(IAccountManager::PROPERTY_PHONE, $phoneNumbers);
267
-
268
-		if (empty($userMatches)) {
269
-			return new DataResponse();
270
-		}
271
-
272
-		$cloudUrl = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/');
273
-		if (strpos($cloudUrl, 'http://') === 0) {
274
-			$cloudUrl = substr($cloudUrl, strlen('http://'));
275
-		} elseif (strpos($cloudUrl, 'https://') === 0) {
276
-			$cloudUrl = substr($cloudUrl, strlen('https://'));
277
-		}
278
-
279
-		$matches = [];
280
-		foreach ($userMatches as $phone => $userId) {
281
-			// Not using the ICloudIdManager as that would run a search for each contact to find the display name in the address book
282
-			$matches[$normalizedNumberToKey[$phone]] = $userId . '@' . $cloudUrl;
283
-			$this->knownUserService->storeIsKnownToUser($knownTo, $userId);
284
-		}
285
-
286
-		return new DataResponse($matches);
287
-	}
288
-
289
-	/**
290
-	 * @throws OCSException
291
-	 */
292
-	private function createNewUserId(): string {
293
-		$attempts = 0;
294
-		do {
295
-			$uidCandidate = $this->secureRandom->generate(10, ISecureRandom::CHAR_HUMAN_READABLE);
296
-			if (!$this->userManager->userExists($uidCandidate)) {
297
-				return $uidCandidate;
298
-			}
299
-			$attempts++;
300
-		} while ($attempts < 10);
301
-		throw new OCSException('Could not create non-existing user id', 111);
302
-	}
303
-
304
-	/**
305
-	 * @PasswordConfirmationRequired
306
-	 * @NoAdminRequired
307
-	 *
308
-	 * @param string $userid
309
-	 * @param string $password
310
-	 * @param string $displayName
311
-	 * @param string $email
312
-	 * @param array $groups
313
-	 * @param array $subadmin
314
-	 * @param string $quota
315
-	 * @param string $language
316
-	 * @return DataResponse
317
-	 * @throws OCSException
318
-	 */
319
-	public function addUser(string $userid,
320
-							string $password = '',
321
-							string $displayName = '',
322
-							string $email = '',
323
-							array $groups = [],
324
-							array $subadmin = [],
325
-							string $quota = '',
326
-							string $language = ''): DataResponse {
327
-		$user = $this->userSession->getUser();
328
-		$isAdmin = $this->groupManager->isAdmin($user->getUID());
329
-		$subAdminManager = $this->groupManager->getSubAdmin();
330
-
331
-		if (empty($userid) && $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes') {
332
-			$userid = $this->createNewUserId();
333
-		}
334
-
335
-		if ($this->userManager->userExists($userid)) {
336
-			$this->logger->error('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']);
337
-			throw new OCSException('User already exists', 102);
338
-		}
339
-
340
-		if ($groups !== []) {
341
-			foreach ($groups as $group) {
342
-				if (!$this->groupManager->groupExists($group)) {
343
-					throw new OCSException('group '.$group.' does not exist', 104);
344
-				}
345
-				if (!$isAdmin && !$subAdminManager->isSubAdminOfGroup($user, $this->groupManager->get($group))) {
346
-					throw new OCSException('insufficient privileges for group '. $group, 105);
347
-				}
348
-			}
349
-		} else {
350
-			if (!$isAdmin) {
351
-				throw new OCSException('no group specified (required for subadmins)', 106);
352
-			}
353
-		}
354
-
355
-		$subadminGroups = [];
356
-		if ($subadmin !== []) {
357
-			foreach ($subadmin as $groupid) {
358
-				$group = $this->groupManager->get($groupid);
359
-				// Check if group exists
360
-				if ($group === null) {
361
-					throw new OCSException('Subadmin group does not exist',  102);
362
-				}
363
-				// Check if trying to make subadmin of admin group
364
-				if ($group->getGID() === 'admin') {
365
-					throw new OCSException('Cannot create subadmins for admin group', 103);
366
-				}
367
-				// Check if has permission to promote subadmins
368
-				if (!$subAdminManager->isSubAdminOfGroup($user, $group) && !$isAdmin) {
369
-					throw new OCSForbiddenException('No permissions to promote subadmins');
370
-				}
371
-				$subadminGroups[] = $group;
372
-			}
373
-		}
374
-
375
-		$generatePasswordResetToken = false;
376
-		if ($password === '') {
377
-			if ($email === '') {
378
-				throw new OCSException('To send a password link to the user an email address is required.', 108);
379
-			}
380
-
381
-			$passwordEvent = new GenerateSecurePasswordEvent();
382
-			$this->eventDispatcher->dispatchTyped($passwordEvent);
383
-
384
-			$password = $passwordEvent->getPassword();
385
-			if ($password === null) {
386
-				// Fallback: ensure to pass password_policy in any case
387
-				$password = $this->secureRandom->generate(10)
388
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_UPPER)
389
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_LOWER)
390
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_DIGITS)
391
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_SYMBOLS);
392
-			}
393
-			$generatePasswordResetToken = true;
394
-		}
395
-
396
-		if ($email === '' && $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes') {
397
-			throw new OCSException('Required email address was not provided', 110);
398
-		}
399
-
400
-		try {
401
-			$newUser = $this->userManager->createUser($userid, $password);
402
-			$this->logger->info('Successful addUser call with userid: ' . $userid, ['app' => 'ocs_api']);
403
-
404
-			foreach ($groups as $group) {
405
-				$this->groupManager->get($group)->addUser($newUser);
406
-				$this->logger->info('Added userid ' . $userid . ' to group ' . $group, ['app' => 'ocs_api']);
407
-			}
408
-			foreach ($subadminGroups as $group) {
409
-				$subAdminManager->createSubAdmin($newUser, $group);
410
-			}
411
-
412
-			if ($displayName !== '') {
413
-				$this->editUser($userid, 'display', $displayName);
414
-			}
415
-
416
-			if ($quota !== '') {
417
-				$this->editUser($userid, 'quota', $quota);
418
-			}
419
-
420
-			if ($language !== '') {
421
-				$this->editUser($userid, 'language', $language);
422
-			}
423
-
424
-			// Send new user mail only if a mail is set
425
-			if ($email !== '') {
426
-				$newUser->setEMailAddress($email);
427
-				if ($this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes') {
428
-					try {
429
-						$emailTemplate = $this->newUserMailHelper->generateTemplate($newUser, $generatePasswordResetToken);
430
-						$this->newUserMailHelper->sendMail($newUser, $emailTemplate);
431
-					} catch (\Exception $e) {
432
-						// Mail could be failing hard or just be plain not configured
433
-						// Logging error as it is the hardest of the two
434
-						$this->logger->error("Unable to send the invitation mail to $email",
435
-							[
436
-								'app' => 'ocs_api',
437
-								'exception' => $e,
438
-							]
439
-						);
440
-					}
441
-				}
442
-			}
443
-
444
-			return new DataResponse(['id' => $userid]);
445
-		} catch (HintException $e) {
446
-			$this->logger->warning('Failed addUser attempt with hint exception.',
447
-				[
448
-					'app' => 'ocs_api',
449
-					'exception' => $e,
450
-				]
451
-			);
452
-			throw new OCSException($e->getHint(), 107);
453
-		} catch (OCSException $e) {
454
-			$this->logger->warning('Failed addUser attempt with ocs exeption.',
455
-				[
456
-					'app' => 'ocs_api',
457
-					'exception' => $e,
458
-				]
459
-			);
460
-			throw $e;
461
-		} catch (\InvalidArgumentException $e) {
462
-			$this->logger->error('Failed addUser attempt with invalid argument exeption.',
463
-				[
464
-					'app' => 'ocs_api',
465
-					'exception' => $e,
466
-				]
467
-			);
468
-			throw new OCSException($e->getMessage(), 101);
469
-		} catch (\Exception $e) {
470
-			$this->logger->error('Failed addUser attempt with exception.',
471
-				[
472
-					'app' => 'ocs_api',
473
-					'exception' => $e
474
-				]
475
-			);
476
-			throw new OCSException('Bad request', 101);
477
-		}
478
-	}
479
-
480
-	/**
481
-	 * @NoAdminRequired
482
-	 * @NoSubAdminRequired
483
-	 *
484
-	 * gets user info
485
-	 *
486
-	 * @param string $userId
487
-	 * @return DataResponse
488
-	 * @throws OCSException
489
-	 */
490
-	public function getUser(string $userId): DataResponse {
491
-		$data = $this->getUserData($userId);
492
-		// getUserData returns empty array if not enough permissions
493
-		if (empty($data)) {
494
-			throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
495
-		}
496
-		return new DataResponse($data);
497
-	}
498
-
499
-	/**
500
-	 * @NoAdminRequired
501
-	 * @NoSubAdminRequired
502
-	 *
503
-	 * gets user info from the currently logged in user
504
-	 *
505
-	 * @return DataResponse
506
-	 * @throws OCSException
507
-	 */
508
-	public function getCurrentUser(): DataResponse {
509
-		$user = $this->userSession->getUser();
510
-		if ($user) {
511
-			$data = $this->getUserData($user->getUID());
512
-			// rename "displayname" to "display-name" only for this call to keep
513
-			// the API stable.
514
-			$data['display-name'] = $data['displayname'];
515
-			unset($data['displayname']);
516
-			return new DataResponse($data);
517
-		}
518
-
519
-		throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
520
-	}
521
-
522
-	/**
523
-	 * @NoAdminRequired
524
-	 * @NoSubAdminRequired
525
-	 */
526
-	public function getEditableFields(): DataResponse {
527
-		$permittedFields = [];
528
-
529
-		// Editing self (display, email)
530
-		if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
531
-			$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
532
-			$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
533
-		}
534
-
535
-		if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
536
-			$shareProvider = $this->federatedShareProviderFactory->get();
537
-			if ($shareProvider->isLookupServerUploadEnabled()) {
538
-				$permittedFields[] = IAccountManager::PROPERTY_PHONE;
539
-				$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
540
-				$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
541
-				$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
542
-			}
543
-		}
544
-
545
-		return new DataResponse($permittedFields);
546
-	}
547
-
548
-	/**
549
-	 * @NoAdminRequired
550
-	 * @NoSubAdminRequired
551
-	 * @PasswordConfirmationRequired
552
-	 *
553
-	 * edit users
554
-	 *
555
-	 * @param string $userId
556
-	 * @param string $key
557
-	 * @param string $value
558
-	 * @return DataResponse
559
-	 * @throws OCSException
560
-	 */
561
-	public function editUser(string $userId, string $key, string $value): DataResponse {
562
-		$currentLoggedInUser = $this->userSession->getUser();
563
-
564
-		$targetUser = $this->userManager->get($userId);
565
-		if ($targetUser === null) {
566
-			throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
567
-		}
568
-
569
-		$permittedFields = [];
570
-		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
571
-			// Editing self (display, email)
572
-			if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
573
-				$permittedFields[] = 'display';
574
-				$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
575
-				$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
576
-			}
577
-
578
-			$permittedFields[] = 'password';
579
-			if ($this->config->getSystemValue('force_language', false) === false ||
580
-				$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
581
-				$permittedFields[] = 'language';
582
-			}
583
-
584
-			if ($this->config->getSystemValue('force_locale', false) === false ||
585
-				$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
586
-				$permittedFields[] = 'locale';
587
-			}
588
-
589
-			if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
590
-				$shareProvider = $this->federatedShareProviderFactory->get();
591
-				if ($shareProvider->isLookupServerUploadEnabled()) {
592
-					$permittedFields[] = IAccountManager::PROPERTY_PHONE;
593
-					$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
594
-					$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
595
-					$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
596
-				}
597
-			}
598
-
599
-			// If admin they can edit their own quota
600
-			if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
601
-				$permittedFields[] = 'quota';
602
-			}
603
-		} else {
604
-			// Check if admin / subadmin
605
-			$subAdminManager = $this->groupManager->getSubAdmin();
606
-			if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())
607
-			|| $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
608
-				// They have permissions over the user
609
-				$permittedFields[] = 'display';
610
-				$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
611
-				$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
612
-				$permittedFields[] = 'password';
613
-				$permittedFields[] = 'language';
614
-				$permittedFields[] = 'locale';
615
-				$permittedFields[] = IAccountManager::PROPERTY_PHONE;
616
-				$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
617
-				$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
618
-				$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
619
-				$permittedFields[] = 'quota';
620
-			} else {
621
-				// No rights
622
-				throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
623
-			}
624
-		}
625
-		// Check if permitted to edit this field
626
-		if (!in_array($key, $permittedFields)) {
627
-			throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
628
-		}
629
-		// Process the edit
630
-		switch ($key) {
631
-			case 'display':
632
-			case IAccountManager::PROPERTY_DISPLAYNAME:
633
-				$targetUser->setDisplayName($value);
634
-				break;
635
-			case 'quota':
636
-				$quota = $value;
637
-				if ($quota !== 'none' && $quota !== 'default') {
638
-					if (is_numeric($quota)) {
639
-						$quota = (float) $quota;
640
-					} else {
641
-						$quota = \OCP\Util::computerFileSize($quota);
642
-					}
643
-					if ($quota === false) {
644
-						throw new OCSException('Invalid quota value '.$value, 103);
645
-					}
646
-					if ($quota === -1) {
647
-						$quota = 'none';
648
-					} else {
649
-						$quota = \OCP\Util::humanFileSize($quota);
650
-					}
651
-				}
652
-				$targetUser->setQuota($quota);
653
-				break;
654
-			case 'password':
655
-				try {
656
-					if (!$targetUser->canChangePassword()) {
657
-						throw new OCSException('Setting the password is not supported by the users backend', 103);
658
-					}
659
-					$targetUser->setPassword($value);
660
-				} catch (HintException $e) { // password policy error
661
-					throw new OCSException($e->getMessage(), 103);
662
-				}
663
-				break;
664
-			case 'language':
665
-				$languagesCodes = $this->l10nFactory->findAvailableLanguages();
666
-				if (!in_array($value, $languagesCodes, true) && $value !== 'en') {
667
-					throw new OCSException('Invalid language', 102);
668
-				}
669
-				$this->config->setUserValue($targetUser->getUID(), 'core', 'lang', $value);
670
-				break;
671
-			case 'locale':
672
-				if (!$this->l10nFactory->localeExists($value)) {
673
-					throw new OCSException('Invalid locale', 102);
674
-				}
675
-				$this->config->setUserValue($targetUser->getUID(), 'core', 'locale', $value);
676
-				break;
677
-			case IAccountManager::PROPERTY_EMAIL:
678
-				if (filter_var($value, FILTER_VALIDATE_EMAIL) || $value === '') {
679
-					$targetUser->setEMailAddress($value);
680
-				} else {
681
-					throw new OCSException('', 102);
682
-				}
683
-				break;
684
-			case IAccountManager::PROPERTY_PHONE:
685
-			case IAccountManager::PROPERTY_ADDRESS:
686
-			case IAccountManager::PROPERTY_WEBSITE:
687
-			case IAccountManager::PROPERTY_TWITTER:
688
-				$userAccount = $this->accountManager->getUser($targetUser);
689
-				if ($userAccount[$key]['value'] !== $value) {
690
-					$userAccount[$key]['value'] = $value;
691
-					try {
692
-						$this->accountManager->updateUser($targetUser, $userAccount, true);
693
-
694
-						if ($key === IAccountManager::PROPERTY_PHONE) {
695
-							$this->knownUserService->deleteByContactUserId($targetUser->getUID());
696
-						}
697
-					} catch (\InvalidArgumentException $e) {
698
-						throw new OCSException('Invalid ' . $e->getMessage(), 102);
699
-					}
700
-				}
701
-				break;
702
-			default:
703
-				throw new OCSException('', 103);
704
-		}
705
-		return new DataResponse();
706
-	}
707
-
708
-	/**
709
-	 * @PasswordConfirmationRequired
710
-	 * @NoAdminRequired
711
-	 *
712
-	 * @param string $userId
713
-	 *
714
-	 * @return DataResponse
715
-	 *
716
-	 * @throws OCSException
717
-	 */
718
-	public function wipeUserDevices(string $userId): DataResponse {
719
-		/** @var IUser $currentLoggedInUser */
720
-		$currentLoggedInUser = $this->userSession->getUser();
721
-
722
-		$targetUser = $this->userManager->get($userId);
723
-
724
-		if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
725
-			throw new OCSException('', 101);
726
-		}
727
-
728
-		// If not permitted
729
-		$subAdminManager = $this->groupManager->getSubAdmin();
730
-		if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
731
-			throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
732
-		}
733
-
734
-		$this->remoteWipe->markAllTokensForWipe($targetUser);
735
-
736
-		return new DataResponse();
737
-	}
738
-
739
-	/**
740
-	 * @PasswordConfirmationRequired
741
-	 * @NoAdminRequired
742
-	 *
743
-	 * @param string $userId
744
-	 * @return DataResponse
745
-	 * @throws OCSException
746
-	 */
747
-	public function deleteUser(string $userId): DataResponse {
748
-		$currentLoggedInUser = $this->userSession->getUser();
749
-
750
-		$targetUser = $this->userManager->get($userId);
751
-
752
-		if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
753
-			throw new OCSException('', 101);
754
-		}
755
-
756
-		// If not permitted
757
-		$subAdminManager = $this->groupManager->getSubAdmin();
758
-		if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
759
-			throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
760
-		}
761
-
762
-		// Go ahead with the delete
763
-		if ($targetUser->delete()) {
764
-			return new DataResponse();
765
-		} else {
766
-			throw new OCSException('', 101);
767
-		}
768
-	}
769
-
770
-	/**
771
-	 * @PasswordConfirmationRequired
772
-	 * @NoAdminRequired
773
-	 *
774
-	 * @param string $userId
775
-	 * @return DataResponse
776
-	 * @throws OCSException
777
-	 * @throws OCSForbiddenException
778
-	 */
779
-	public function disableUser(string $userId): DataResponse {
780
-		return $this->setEnabled($userId, false);
781
-	}
782
-
783
-	/**
784
-	 * @PasswordConfirmationRequired
785
-	 * @NoAdminRequired
786
-	 *
787
-	 * @param string $userId
788
-	 * @return DataResponse
789
-	 * @throws OCSException
790
-	 * @throws OCSForbiddenException
791
-	 */
792
-	public function enableUser(string $userId): DataResponse {
793
-		return $this->setEnabled($userId, true);
794
-	}
795
-
796
-	/**
797
-	 * @param string $userId
798
-	 * @param bool $value
799
-	 * @return DataResponse
800
-	 * @throws OCSException
801
-	 */
802
-	private function setEnabled(string $userId, bool $value): DataResponse {
803
-		$currentLoggedInUser = $this->userSession->getUser();
804
-
805
-		$targetUser = $this->userManager->get($userId);
806
-		if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
807
-			throw new OCSException('', 101);
808
-		}
809
-
810
-		// If not permitted
811
-		$subAdminManager = $this->groupManager->getSubAdmin();
812
-		if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
813
-			throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
814
-		}
815
-
816
-		// enable/disable the user now
817
-		$targetUser->setEnabled($value);
818
-		return new DataResponse();
819
-	}
820
-
821
-	/**
822
-	 * @NoAdminRequired
823
-	 * @NoSubAdminRequired
824
-	 *
825
-	 * @param string $userId
826
-	 * @return DataResponse
827
-	 * @throws OCSException
828
-	 */
829
-	public function getUsersGroups(string $userId): DataResponse {
830
-		$loggedInUser = $this->userSession->getUser();
831
-
832
-		$targetUser = $this->userManager->get($userId);
833
-		if ($targetUser === null) {
834
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
835
-		}
836
-
837
-		if ($targetUser->getUID() === $loggedInUser->getUID() || $this->groupManager->isAdmin($loggedInUser->getUID())) {
838
-			// Self lookup or admin lookup
839
-			return new DataResponse([
840
-				'groups' => $this->groupManager->getUserGroupIds($targetUser)
841
-			]);
842
-		} else {
843
-			$subAdminManager = $this->groupManager->getSubAdmin();
844
-
845
-			// Looking up someone else
846
-			if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
847
-				// Return the group that the method caller is subadmin of for the user in question
848
-				/** @var IGroup[] $getSubAdminsGroups */
849
-				$getSubAdminsGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
850
-				foreach ($getSubAdminsGroups as $key => $group) {
851
-					$getSubAdminsGroups[$key] = $group->getGID();
852
-				}
853
-				$groups = array_intersect(
854
-					$getSubAdminsGroups,
855
-					$this->groupManager->getUserGroupIds($targetUser)
856
-				);
857
-				return new DataResponse(['groups' => $groups]);
858
-			} else {
859
-				// Not permitted
860
-				throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
861
-			}
862
-		}
863
-	}
864
-
865
-	/**
866
-	 * @PasswordConfirmationRequired
867
-	 * @NoAdminRequired
868
-	 *
869
-	 * @param string $userId
870
-	 * @param string $groupid
871
-	 * @return DataResponse
872
-	 * @throws OCSException
873
-	 */
874
-	public function addToGroup(string $userId, string $groupid = ''): DataResponse {
875
-		if ($groupid === '') {
876
-			throw new OCSException('', 101);
877
-		}
878
-
879
-		$group = $this->groupManager->get($groupid);
880
-		$targetUser = $this->userManager->get($userId);
881
-		if ($group === null) {
882
-			throw new OCSException('', 102);
883
-		}
884
-		if ($targetUser === null) {
885
-			throw new OCSException('', 103);
886
-		}
887
-
888
-		// If they're not an admin, check they are a subadmin of the group in question
889
-		$loggedInUser = $this->userSession->getUser();
890
-		$subAdminManager = $this->groupManager->getSubAdmin();
891
-		if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
892
-			throw new OCSException('', 104);
893
-		}
894
-
895
-		// Add user to group
896
-		$group->addUser($targetUser);
897
-		return new DataResponse();
898
-	}
899
-
900
-	/**
901
-	 * @PasswordConfirmationRequired
902
-	 * @NoAdminRequired
903
-	 *
904
-	 * @param string $userId
905
-	 * @param string $groupid
906
-	 * @return DataResponse
907
-	 * @throws OCSException
908
-	 */
909
-	public function removeFromGroup(string $userId, string $groupid): DataResponse {
910
-		$loggedInUser = $this->userSession->getUser();
911
-
912
-		if ($groupid === null || trim($groupid) === '') {
913
-			throw new OCSException('', 101);
914
-		}
915
-
916
-		$group = $this->groupManager->get($groupid);
917
-		if ($group === null) {
918
-			throw new OCSException('', 102);
919
-		}
920
-
921
-		$targetUser = $this->userManager->get($userId);
922
-		if ($targetUser === null) {
923
-			throw new OCSException('', 103);
924
-		}
925
-
926
-		// If they're not an admin, check they are a subadmin of the group in question
927
-		$subAdminManager = $this->groupManager->getSubAdmin();
928
-		if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
929
-			throw new OCSException('', 104);
930
-		}
931
-
932
-		// Check they aren't removing themselves from 'admin' or their 'subadmin; group
933
-		if ($targetUser->getUID() === $loggedInUser->getUID()) {
934
-			if ($this->groupManager->isAdmin($loggedInUser->getUID())) {
935
-				if ($group->getGID() === 'admin') {
936
-					throw new OCSException('Cannot remove yourself from the admin group', 105);
937
-				}
938
-			} else {
939
-				// Not an admin, so the user must be a subadmin of this group, but that is not allowed.
940
-				throw new OCSException('Cannot remove yourself from this group as you are a SubAdmin', 105);
941
-			}
942
-		} elseif (!$this->groupManager->isAdmin($loggedInUser->getUID())) {
943
-			/** @var IGroup[] $subAdminGroups */
944
-			$subAdminGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
945
-			$subAdminGroups = array_map(function (IGroup $subAdminGroup) {
946
-				return $subAdminGroup->getGID();
947
-			}, $subAdminGroups);
948
-			$userGroups = $this->groupManager->getUserGroupIds($targetUser);
949
-			$userSubAdminGroups = array_intersect($subAdminGroups, $userGroups);
950
-
951
-			if (count($userSubAdminGroups) <= 1) {
952
-				// Subadmin must not be able to remove a user from all their subadmin groups.
953
-				throw new OCSException('Not viable to remove user from the last group you are SubAdmin of', 105);
954
-			}
955
-		}
956
-
957
-		// Remove user from group
958
-		$group->removeUser($targetUser);
959
-		return new DataResponse();
960
-	}
961
-
962
-	/**
963
-	 * Creates a subadmin
964
-	 *
965
-	 * @PasswordConfirmationRequired
966
-	 *
967
-	 * @param string $userId
968
-	 * @param string $groupid
969
-	 * @return DataResponse
970
-	 * @throws OCSException
971
-	 */
972
-	public function addSubAdmin(string $userId, string $groupid): DataResponse {
973
-		$group = $this->groupManager->get($groupid);
974
-		$user = $this->userManager->get($userId);
975
-
976
-		// Check if the user exists
977
-		if ($user === null) {
978
-			throw new OCSException('User does not exist', 101);
979
-		}
980
-		// Check if group exists
981
-		if ($group === null) {
982
-			throw new OCSException('Group does not exist',  102);
983
-		}
984
-		// Check if trying to make subadmin of admin group
985
-		if ($group->getGID() === 'admin') {
986
-			throw new OCSException('Cannot create subadmins for admin group', 103);
987
-		}
988
-
989
-		$subAdminManager = $this->groupManager->getSubAdmin();
990
-
991
-		// We cannot be subadmin twice
992
-		if ($subAdminManager->isSubAdminOfGroup($user, $group)) {
993
-			return new DataResponse();
994
-		}
995
-		// Go
996
-		$subAdminManager->createSubAdmin($user, $group);
997
-		return new DataResponse();
998
-	}
999
-
1000
-	/**
1001
-	 * Removes a subadmin from a group
1002
-	 *
1003
-	 * @PasswordConfirmationRequired
1004
-	 *
1005
-	 * @param string $userId
1006
-	 * @param string $groupid
1007
-	 * @return DataResponse
1008
-	 * @throws OCSException
1009
-	 */
1010
-	public function removeSubAdmin(string $userId, string $groupid): DataResponse {
1011
-		$group = $this->groupManager->get($groupid);
1012
-		$user = $this->userManager->get($userId);
1013
-		$subAdminManager = $this->groupManager->getSubAdmin();
1014
-
1015
-		// Check if the user exists
1016
-		if ($user === null) {
1017
-			throw new OCSException('User does not exist', 101);
1018
-		}
1019
-		// Check if the group exists
1020
-		if ($group === null) {
1021
-			throw new OCSException('Group does not exist', 101);
1022
-		}
1023
-		// Check if they are a subadmin of this said group
1024
-		if (!$subAdminManager->isSubAdminOfGroup($user, $group)) {
1025
-			throw new OCSException('User is not a subadmin of this group', 102);
1026
-		}
1027
-
1028
-		// Go
1029
-		$subAdminManager->deleteSubAdmin($user, $group);
1030
-		return new DataResponse();
1031
-	}
1032
-
1033
-	/**
1034
-	 * Get the groups a user is a subadmin of
1035
-	 *
1036
-	 * @param string $userId
1037
-	 * @return DataResponse
1038
-	 * @throws OCSException
1039
-	 */
1040
-	public function getUserSubAdminGroups(string $userId): DataResponse {
1041
-		$groups = $this->getUserSubAdminGroupsData($userId);
1042
-		return new DataResponse($groups);
1043
-	}
1044
-
1045
-	/**
1046
-	 * @NoAdminRequired
1047
-	 * @PasswordConfirmationRequired
1048
-	 *
1049
-	 * resend welcome message
1050
-	 *
1051
-	 * @param string $userId
1052
-	 * @return DataResponse
1053
-	 * @throws OCSException
1054
-	 */
1055
-	public function resendWelcomeMessage(string $userId): DataResponse {
1056
-		$currentLoggedInUser = $this->userSession->getUser();
1057
-
1058
-		$targetUser = $this->userManager->get($userId);
1059
-		if ($targetUser === null) {
1060
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1061
-		}
1062
-
1063
-		// Check if admin / subadmin
1064
-		$subAdminManager = $this->groupManager->getSubAdmin();
1065
-		if (!$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
1066
-			&& !$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
1067
-			// No rights
1068
-			throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
1069
-		}
1070
-
1071
-		$email = $targetUser->getEMailAddress();
1072
-		if ($email === '' || $email === null) {
1073
-			throw new OCSException('Email address not available', 101);
1074
-		}
1075
-
1076
-		try {
1077
-			$emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, false);
1078
-			$this->newUserMailHelper->sendMail($targetUser, $emailTemplate);
1079
-		} catch (\Exception $e) {
1080
-			$this->logger->error("Can't send new user mail to $email",
1081
-				[
1082
-					'app' => 'settings',
1083
-					'exception' => $e,
1084
-				]
1085
-			);
1086
-			throw new OCSException('Sending email failed', 102);
1087
-		}
1088
-
1089
-		return new DataResponse();
1090
-	}
78
+    /** @var IAppManager */
79
+    private $appManager;
80
+    /** @var IURLGenerator */
81
+    protected $urlGenerator;
82
+    /** @var LoggerInterface */
83
+    private $logger;
84
+    /** @var IFactory */
85
+    protected $l10nFactory;
86
+    /** @var NewUserMailHelper */
87
+    private $newUserMailHelper;
88
+    /** @var FederatedShareProviderFactory */
89
+    private $federatedShareProviderFactory;
90
+    /** @var ISecureRandom */
91
+    private $secureRandom;
92
+    /** @var RemoteWipe */
93
+    private $remoteWipe;
94
+    /** @var KnownUserService */
95
+    private $knownUserService;
96
+    /** @var IEventDispatcher */
97
+    private $eventDispatcher;
98
+
99
+    public function __construct(string $appName,
100
+                                IRequest $request,
101
+                                IUserManager $userManager,
102
+                                IConfig $config,
103
+                                IAppManager $appManager,
104
+                                IGroupManager $groupManager,
105
+                                IUserSession $userSession,
106
+                                AccountManager $accountManager,
107
+                                IURLGenerator $urlGenerator,
108
+                                LoggerInterface $logger,
109
+                                IFactory $l10nFactory,
110
+                                NewUserMailHelper $newUserMailHelper,
111
+                                FederatedShareProviderFactory $federatedShareProviderFactory,
112
+                                ISecureRandom $secureRandom,
113
+                                RemoteWipe $remoteWipe,
114
+                                KnownUserService $knownUserService,
115
+                                IEventDispatcher $eventDispatcher) {
116
+        parent::__construct($appName,
117
+                            $request,
118
+                            $userManager,
119
+                            $config,
120
+                            $groupManager,
121
+                            $userSession,
122
+                            $accountManager,
123
+                            $l10nFactory);
124
+
125
+        $this->appManager = $appManager;
126
+        $this->urlGenerator = $urlGenerator;
127
+        $this->logger = $logger;
128
+        $this->l10nFactory = $l10nFactory;
129
+        $this->newUserMailHelper = $newUserMailHelper;
130
+        $this->federatedShareProviderFactory = $federatedShareProviderFactory;
131
+        $this->secureRandom = $secureRandom;
132
+        $this->remoteWipe = $remoteWipe;
133
+        $this->knownUserService = $knownUserService;
134
+        $this->eventDispatcher = $eventDispatcher;
135
+    }
136
+
137
+    /**
138
+     * @NoAdminRequired
139
+     *
140
+     * returns a list of users
141
+     *
142
+     * @param string $search
143
+     * @param int $limit
144
+     * @param int $offset
145
+     * @return DataResponse
146
+     */
147
+    public function getUsers(string $search = '', int $limit = null, int $offset = 0): DataResponse {
148
+        $user = $this->userSession->getUser();
149
+        $users = [];
150
+
151
+        // Admin? Or SubAdmin?
152
+        $uid = $user->getUID();
153
+        $subAdminManager = $this->groupManager->getSubAdmin();
154
+        if ($this->groupManager->isAdmin($uid)) {
155
+            $users = $this->userManager->search($search, $limit, $offset);
156
+        } elseif ($subAdminManager->isSubAdmin($user)) {
157
+            $subAdminOfGroups = $subAdminManager->getSubAdminsGroups($user);
158
+            foreach ($subAdminOfGroups as $key => $group) {
159
+                $subAdminOfGroups[$key] = $group->getGID();
160
+            }
161
+
162
+            $users = [];
163
+            foreach ($subAdminOfGroups as $group) {
164
+                $users = array_merge($users, $this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
165
+            }
166
+        }
167
+
168
+        $users = array_keys($users);
169
+
170
+        return new DataResponse([
171
+            'users' => $users
172
+        ]);
173
+    }
174
+
175
+    /**
176
+     * @NoAdminRequired
177
+     *
178
+     * returns a list of users and their data
179
+     */
180
+    public function getUsersDetails(string $search = '', int $limit = null, int $offset = 0): DataResponse {
181
+        $currentUser = $this->userSession->getUser();
182
+        $users = [];
183
+
184
+        // Admin? Or SubAdmin?
185
+        $uid = $currentUser->getUID();
186
+        $subAdminManager = $this->groupManager->getSubAdmin();
187
+        if ($this->groupManager->isAdmin($uid)) {
188
+            $users = $this->userManager->search($search, $limit, $offset);
189
+            $users = array_keys($users);
190
+        } elseif ($subAdminManager->isSubAdmin($currentUser)) {
191
+            $subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
192
+            foreach ($subAdminOfGroups as $key => $group) {
193
+                $subAdminOfGroups[$key] = $group->getGID();
194
+            }
195
+
196
+            $users = [];
197
+            foreach ($subAdminOfGroups as $group) {
198
+                $users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
199
+            }
200
+            $users = array_merge(...$users);
201
+        }
202
+
203
+        $usersDetails = [];
204
+        foreach ($users as $userId) {
205
+            $userId = (string) $userId;
206
+            $userData = $this->getUserData($userId);
207
+            // Do not insert empty entry
208
+            if (!empty($userData)) {
209
+                $usersDetails[$userId] = $userData;
210
+            } else {
211
+                // Logged user does not have permissions to see this user
212
+                // only showing its id
213
+                $usersDetails[$userId] = ['id' => $userId];
214
+            }
215
+        }
216
+
217
+        return new DataResponse([
218
+            'users' => $usersDetails
219
+        ]);
220
+    }
221
+
222
+
223
+    /**
224
+     * @NoAdminRequired
225
+     * @NoSubAdminRequired
226
+     *
227
+     * @param string $location
228
+     * @param array $search
229
+     * @return DataResponse
230
+     */
231
+    public function searchByPhoneNumbers(string $location, array $search): DataResponse {
232
+        $phoneUtil = PhoneNumberUtil::getInstance();
233
+
234
+        if ($phoneUtil->getCountryCodeForRegion($location) === 0) {
235
+            // Not a valid region code
236
+            return new DataResponse([], Http::STATUS_BAD_REQUEST);
237
+        }
238
+
239
+        /** @var IUser $user */
240
+        $user = $this->userSession->getUser();
241
+        $knownTo = $user->getUID();
242
+
243
+        $normalizedNumberToKey = [];
244
+        foreach ($search as $key => $phoneNumbers) {
245
+            foreach ($phoneNumbers as $phone) {
246
+                try {
247
+                    $phoneNumber = $phoneUtil->parse($phone, $location);
248
+                    if ($phoneNumber instanceof PhoneNumber && $phoneUtil->isValidNumber($phoneNumber)) {
249
+                        $normalizedNumber = $phoneUtil->format($phoneNumber, PhoneNumberFormat::E164);
250
+                        $normalizedNumberToKey[$normalizedNumber] = (string) $key;
251
+                    }
252
+                } catch (NumberParseException $e) {
253
+                }
254
+            }
255
+        }
256
+
257
+        $phoneNumbers = array_keys($normalizedNumberToKey);
258
+
259
+        if (empty($phoneNumbers)) {
260
+            return new DataResponse();
261
+        }
262
+
263
+        // Cleanup all previous entries and only allow new matches
264
+        $this->knownUserService->deleteKnownTo($knownTo);
265
+
266
+        $userMatches = $this->accountManager->searchUsers(IAccountManager::PROPERTY_PHONE, $phoneNumbers);
267
+
268
+        if (empty($userMatches)) {
269
+            return new DataResponse();
270
+        }
271
+
272
+        $cloudUrl = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/');
273
+        if (strpos($cloudUrl, 'http://') === 0) {
274
+            $cloudUrl = substr($cloudUrl, strlen('http://'));
275
+        } elseif (strpos($cloudUrl, 'https://') === 0) {
276
+            $cloudUrl = substr($cloudUrl, strlen('https://'));
277
+        }
278
+
279
+        $matches = [];
280
+        foreach ($userMatches as $phone => $userId) {
281
+            // Not using the ICloudIdManager as that would run a search for each contact to find the display name in the address book
282
+            $matches[$normalizedNumberToKey[$phone]] = $userId . '@' . $cloudUrl;
283
+            $this->knownUserService->storeIsKnownToUser($knownTo, $userId);
284
+        }
285
+
286
+        return new DataResponse($matches);
287
+    }
288
+
289
+    /**
290
+     * @throws OCSException
291
+     */
292
+    private function createNewUserId(): string {
293
+        $attempts = 0;
294
+        do {
295
+            $uidCandidate = $this->secureRandom->generate(10, ISecureRandom::CHAR_HUMAN_READABLE);
296
+            if (!$this->userManager->userExists($uidCandidate)) {
297
+                return $uidCandidate;
298
+            }
299
+            $attempts++;
300
+        } while ($attempts < 10);
301
+        throw new OCSException('Could not create non-existing user id', 111);
302
+    }
303
+
304
+    /**
305
+     * @PasswordConfirmationRequired
306
+     * @NoAdminRequired
307
+     *
308
+     * @param string $userid
309
+     * @param string $password
310
+     * @param string $displayName
311
+     * @param string $email
312
+     * @param array $groups
313
+     * @param array $subadmin
314
+     * @param string $quota
315
+     * @param string $language
316
+     * @return DataResponse
317
+     * @throws OCSException
318
+     */
319
+    public function addUser(string $userid,
320
+                            string $password = '',
321
+                            string $displayName = '',
322
+                            string $email = '',
323
+                            array $groups = [],
324
+                            array $subadmin = [],
325
+                            string $quota = '',
326
+                            string $language = ''): DataResponse {
327
+        $user = $this->userSession->getUser();
328
+        $isAdmin = $this->groupManager->isAdmin($user->getUID());
329
+        $subAdminManager = $this->groupManager->getSubAdmin();
330
+
331
+        if (empty($userid) && $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes') {
332
+            $userid = $this->createNewUserId();
333
+        }
334
+
335
+        if ($this->userManager->userExists($userid)) {
336
+            $this->logger->error('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']);
337
+            throw new OCSException('User already exists', 102);
338
+        }
339
+
340
+        if ($groups !== []) {
341
+            foreach ($groups as $group) {
342
+                if (!$this->groupManager->groupExists($group)) {
343
+                    throw new OCSException('group '.$group.' does not exist', 104);
344
+                }
345
+                if (!$isAdmin && !$subAdminManager->isSubAdminOfGroup($user, $this->groupManager->get($group))) {
346
+                    throw new OCSException('insufficient privileges for group '. $group, 105);
347
+                }
348
+            }
349
+        } else {
350
+            if (!$isAdmin) {
351
+                throw new OCSException('no group specified (required for subadmins)', 106);
352
+            }
353
+        }
354
+
355
+        $subadminGroups = [];
356
+        if ($subadmin !== []) {
357
+            foreach ($subadmin as $groupid) {
358
+                $group = $this->groupManager->get($groupid);
359
+                // Check if group exists
360
+                if ($group === null) {
361
+                    throw new OCSException('Subadmin group does not exist',  102);
362
+                }
363
+                // Check if trying to make subadmin of admin group
364
+                if ($group->getGID() === 'admin') {
365
+                    throw new OCSException('Cannot create subadmins for admin group', 103);
366
+                }
367
+                // Check if has permission to promote subadmins
368
+                if (!$subAdminManager->isSubAdminOfGroup($user, $group) && !$isAdmin) {
369
+                    throw new OCSForbiddenException('No permissions to promote subadmins');
370
+                }
371
+                $subadminGroups[] = $group;
372
+            }
373
+        }
374
+
375
+        $generatePasswordResetToken = false;
376
+        if ($password === '') {
377
+            if ($email === '') {
378
+                throw new OCSException('To send a password link to the user an email address is required.', 108);
379
+            }
380
+
381
+            $passwordEvent = new GenerateSecurePasswordEvent();
382
+            $this->eventDispatcher->dispatchTyped($passwordEvent);
383
+
384
+            $password = $passwordEvent->getPassword();
385
+            if ($password === null) {
386
+                // Fallback: ensure to pass password_policy in any case
387
+                $password = $this->secureRandom->generate(10)
388
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_UPPER)
389
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_LOWER)
390
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_DIGITS)
391
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_SYMBOLS);
392
+            }
393
+            $generatePasswordResetToken = true;
394
+        }
395
+
396
+        if ($email === '' && $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes') {
397
+            throw new OCSException('Required email address was not provided', 110);
398
+        }
399
+
400
+        try {
401
+            $newUser = $this->userManager->createUser($userid, $password);
402
+            $this->logger->info('Successful addUser call with userid: ' . $userid, ['app' => 'ocs_api']);
403
+
404
+            foreach ($groups as $group) {
405
+                $this->groupManager->get($group)->addUser($newUser);
406
+                $this->logger->info('Added userid ' . $userid . ' to group ' . $group, ['app' => 'ocs_api']);
407
+            }
408
+            foreach ($subadminGroups as $group) {
409
+                $subAdminManager->createSubAdmin($newUser, $group);
410
+            }
411
+
412
+            if ($displayName !== '') {
413
+                $this->editUser($userid, 'display', $displayName);
414
+            }
415
+
416
+            if ($quota !== '') {
417
+                $this->editUser($userid, 'quota', $quota);
418
+            }
419
+
420
+            if ($language !== '') {
421
+                $this->editUser($userid, 'language', $language);
422
+            }
423
+
424
+            // Send new user mail only if a mail is set
425
+            if ($email !== '') {
426
+                $newUser->setEMailAddress($email);
427
+                if ($this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes') {
428
+                    try {
429
+                        $emailTemplate = $this->newUserMailHelper->generateTemplate($newUser, $generatePasswordResetToken);
430
+                        $this->newUserMailHelper->sendMail($newUser, $emailTemplate);
431
+                    } catch (\Exception $e) {
432
+                        // Mail could be failing hard or just be plain not configured
433
+                        // Logging error as it is the hardest of the two
434
+                        $this->logger->error("Unable to send the invitation mail to $email",
435
+                            [
436
+                                'app' => 'ocs_api',
437
+                                'exception' => $e,
438
+                            ]
439
+                        );
440
+                    }
441
+                }
442
+            }
443
+
444
+            return new DataResponse(['id' => $userid]);
445
+        } catch (HintException $e) {
446
+            $this->logger->warning('Failed addUser attempt with hint exception.',
447
+                [
448
+                    'app' => 'ocs_api',
449
+                    'exception' => $e,
450
+                ]
451
+            );
452
+            throw new OCSException($e->getHint(), 107);
453
+        } catch (OCSException $e) {
454
+            $this->logger->warning('Failed addUser attempt with ocs exeption.',
455
+                [
456
+                    'app' => 'ocs_api',
457
+                    'exception' => $e,
458
+                ]
459
+            );
460
+            throw $e;
461
+        } catch (\InvalidArgumentException $e) {
462
+            $this->logger->error('Failed addUser attempt with invalid argument exeption.',
463
+                [
464
+                    'app' => 'ocs_api',
465
+                    'exception' => $e,
466
+                ]
467
+            );
468
+            throw new OCSException($e->getMessage(), 101);
469
+        } catch (\Exception $e) {
470
+            $this->logger->error('Failed addUser attempt with exception.',
471
+                [
472
+                    'app' => 'ocs_api',
473
+                    'exception' => $e
474
+                ]
475
+            );
476
+            throw new OCSException('Bad request', 101);
477
+        }
478
+    }
479
+
480
+    /**
481
+     * @NoAdminRequired
482
+     * @NoSubAdminRequired
483
+     *
484
+     * gets user info
485
+     *
486
+     * @param string $userId
487
+     * @return DataResponse
488
+     * @throws OCSException
489
+     */
490
+    public function getUser(string $userId): DataResponse {
491
+        $data = $this->getUserData($userId);
492
+        // getUserData returns empty array if not enough permissions
493
+        if (empty($data)) {
494
+            throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
495
+        }
496
+        return new DataResponse($data);
497
+    }
498
+
499
+    /**
500
+     * @NoAdminRequired
501
+     * @NoSubAdminRequired
502
+     *
503
+     * gets user info from the currently logged in user
504
+     *
505
+     * @return DataResponse
506
+     * @throws OCSException
507
+     */
508
+    public function getCurrentUser(): DataResponse {
509
+        $user = $this->userSession->getUser();
510
+        if ($user) {
511
+            $data = $this->getUserData($user->getUID());
512
+            // rename "displayname" to "display-name" only for this call to keep
513
+            // the API stable.
514
+            $data['display-name'] = $data['displayname'];
515
+            unset($data['displayname']);
516
+            return new DataResponse($data);
517
+        }
518
+
519
+        throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
520
+    }
521
+
522
+    /**
523
+     * @NoAdminRequired
524
+     * @NoSubAdminRequired
525
+     */
526
+    public function getEditableFields(): DataResponse {
527
+        $permittedFields = [];
528
+
529
+        // Editing self (display, email)
530
+        if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
531
+            $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
532
+            $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
533
+        }
534
+
535
+        if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
536
+            $shareProvider = $this->federatedShareProviderFactory->get();
537
+            if ($shareProvider->isLookupServerUploadEnabled()) {
538
+                $permittedFields[] = IAccountManager::PROPERTY_PHONE;
539
+                $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
540
+                $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
541
+                $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
542
+            }
543
+        }
544
+
545
+        return new DataResponse($permittedFields);
546
+    }
547
+
548
+    /**
549
+     * @NoAdminRequired
550
+     * @NoSubAdminRequired
551
+     * @PasswordConfirmationRequired
552
+     *
553
+     * edit users
554
+     *
555
+     * @param string $userId
556
+     * @param string $key
557
+     * @param string $value
558
+     * @return DataResponse
559
+     * @throws OCSException
560
+     */
561
+    public function editUser(string $userId, string $key, string $value): DataResponse {
562
+        $currentLoggedInUser = $this->userSession->getUser();
563
+
564
+        $targetUser = $this->userManager->get($userId);
565
+        if ($targetUser === null) {
566
+            throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
567
+        }
568
+
569
+        $permittedFields = [];
570
+        if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
571
+            // Editing self (display, email)
572
+            if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
573
+                $permittedFields[] = 'display';
574
+                $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
575
+                $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
576
+            }
577
+
578
+            $permittedFields[] = 'password';
579
+            if ($this->config->getSystemValue('force_language', false) === false ||
580
+                $this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
581
+                $permittedFields[] = 'language';
582
+            }
583
+
584
+            if ($this->config->getSystemValue('force_locale', false) === false ||
585
+                $this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
586
+                $permittedFields[] = 'locale';
587
+            }
588
+
589
+            if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
590
+                $shareProvider = $this->federatedShareProviderFactory->get();
591
+                if ($shareProvider->isLookupServerUploadEnabled()) {
592
+                    $permittedFields[] = IAccountManager::PROPERTY_PHONE;
593
+                    $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
594
+                    $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
595
+                    $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
596
+                }
597
+            }
598
+
599
+            // If admin they can edit their own quota
600
+            if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
601
+                $permittedFields[] = 'quota';
602
+            }
603
+        } else {
604
+            // Check if admin / subadmin
605
+            $subAdminManager = $this->groupManager->getSubAdmin();
606
+            if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())
607
+            || $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
608
+                // They have permissions over the user
609
+                $permittedFields[] = 'display';
610
+                $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
611
+                $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
612
+                $permittedFields[] = 'password';
613
+                $permittedFields[] = 'language';
614
+                $permittedFields[] = 'locale';
615
+                $permittedFields[] = IAccountManager::PROPERTY_PHONE;
616
+                $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
617
+                $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
618
+                $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
619
+                $permittedFields[] = 'quota';
620
+            } else {
621
+                // No rights
622
+                throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
623
+            }
624
+        }
625
+        // Check if permitted to edit this field
626
+        if (!in_array($key, $permittedFields)) {
627
+            throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
628
+        }
629
+        // Process the edit
630
+        switch ($key) {
631
+            case 'display':
632
+            case IAccountManager::PROPERTY_DISPLAYNAME:
633
+                $targetUser->setDisplayName($value);
634
+                break;
635
+            case 'quota':
636
+                $quota = $value;
637
+                if ($quota !== 'none' && $quota !== 'default') {
638
+                    if (is_numeric($quota)) {
639
+                        $quota = (float) $quota;
640
+                    } else {
641
+                        $quota = \OCP\Util::computerFileSize($quota);
642
+                    }
643
+                    if ($quota === false) {
644
+                        throw new OCSException('Invalid quota value '.$value, 103);
645
+                    }
646
+                    if ($quota === -1) {
647
+                        $quota = 'none';
648
+                    } else {
649
+                        $quota = \OCP\Util::humanFileSize($quota);
650
+                    }
651
+                }
652
+                $targetUser->setQuota($quota);
653
+                break;
654
+            case 'password':
655
+                try {
656
+                    if (!$targetUser->canChangePassword()) {
657
+                        throw new OCSException('Setting the password is not supported by the users backend', 103);
658
+                    }
659
+                    $targetUser->setPassword($value);
660
+                } catch (HintException $e) { // password policy error
661
+                    throw new OCSException($e->getMessage(), 103);
662
+                }
663
+                break;
664
+            case 'language':
665
+                $languagesCodes = $this->l10nFactory->findAvailableLanguages();
666
+                if (!in_array($value, $languagesCodes, true) && $value !== 'en') {
667
+                    throw new OCSException('Invalid language', 102);
668
+                }
669
+                $this->config->setUserValue($targetUser->getUID(), 'core', 'lang', $value);
670
+                break;
671
+            case 'locale':
672
+                if (!$this->l10nFactory->localeExists($value)) {
673
+                    throw new OCSException('Invalid locale', 102);
674
+                }
675
+                $this->config->setUserValue($targetUser->getUID(), 'core', 'locale', $value);
676
+                break;
677
+            case IAccountManager::PROPERTY_EMAIL:
678
+                if (filter_var($value, FILTER_VALIDATE_EMAIL) || $value === '') {
679
+                    $targetUser->setEMailAddress($value);
680
+                } else {
681
+                    throw new OCSException('', 102);
682
+                }
683
+                break;
684
+            case IAccountManager::PROPERTY_PHONE:
685
+            case IAccountManager::PROPERTY_ADDRESS:
686
+            case IAccountManager::PROPERTY_WEBSITE:
687
+            case IAccountManager::PROPERTY_TWITTER:
688
+                $userAccount = $this->accountManager->getUser($targetUser);
689
+                if ($userAccount[$key]['value'] !== $value) {
690
+                    $userAccount[$key]['value'] = $value;
691
+                    try {
692
+                        $this->accountManager->updateUser($targetUser, $userAccount, true);
693
+
694
+                        if ($key === IAccountManager::PROPERTY_PHONE) {
695
+                            $this->knownUserService->deleteByContactUserId($targetUser->getUID());
696
+                        }
697
+                    } catch (\InvalidArgumentException $e) {
698
+                        throw new OCSException('Invalid ' . $e->getMessage(), 102);
699
+                    }
700
+                }
701
+                break;
702
+            default:
703
+                throw new OCSException('', 103);
704
+        }
705
+        return new DataResponse();
706
+    }
707
+
708
+    /**
709
+     * @PasswordConfirmationRequired
710
+     * @NoAdminRequired
711
+     *
712
+     * @param string $userId
713
+     *
714
+     * @return DataResponse
715
+     *
716
+     * @throws OCSException
717
+     */
718
+    public function wipeUserDevices(string $userId): DataResponse {
719
+        /** @var IUser $currentLoggedInUser */
720
+        $currentLoggedInUser = $this->userSession->getUser();
721
+
722
+        $targetUser = $this->userManager->get($userId);
723
+
724
+        if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
725
+            throw new OCSException('', 101);
726
+        }
727
+
728
+        // If not permitted
729
+        $subAdminManager = $this->groupManager->getSubAdmin();
730
+        if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
731
+            throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
732
+        }
733
+
734
+        $this->remoteWipe->markAllTokensForWipe($targetUser);
735
+
736
+        return new DataResponse();
737
+    }
738
+
739
+    /**
740
+     * @PasswordConfirmationRequired
741
+     * @NoAdminRequired
742
+     *
743
+     * @param string $userId
744
+     * @return DataResponse
745
+     * @throws OCSException
746
+     */
747
+    public function deleteUser(string $userId): DataResponse {
748
+        $currentLoggedInUser = $this->userSession->getUser();
749
+
750
+        $targetUser = $this->userManager->get($userId);
751
+
752
+        if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
753
+            throw new OCSException('', 101);
754
+        }
755
+
756
+        // If not permitted
757
+        $subAdminManager = $this->groupManager->getSubAdmin();
758
+        if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
759
+            throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
760
+        }
761
+
762
+        // Go ahead with the delete
763
+        if ($targetUser->delete()) {
764
+            return new DataResponse();
765
+        } else {
766
+            throw new OCSException('', 101);
767
+        }
768
+    }
769
+
770
+    /**
771
+     * @PasswordConfirmationRequired
772
+     * @NoAdminRequired
773
+     *
774
+     * @param string $userId
775
+     * @return DataResponse
776
+     * @throws OCSException
777
+     * @throws OCSForbiddenException
778
+     */
779
+    public function disableUser(string $userId): DataResponse {
780
+        return $this->setEnabled($userId, false);
781
+    }
782
+
783
+    /**
784
+     * @PasswordConfirmationRequired
785
+     * @NoAdminRequired
786
+     *
787
+     * @param string $userId
788
+     * @return DataResponse
789
+     * @throws OCSException
790
+     * @throws OCSForbiddenException
791
+     */
792
+    public function enableUser(string $userId): DataResponse {
793
+        return $this->setEnabled($userId, true);
794
+    }
795
+
796
+    /**
797
+     * @param string $userId
798
+     * @param bool $value
799
+     * @return DataResponse
800
+     * @throws OCSException
801
+     */
802
+    private function setEnabled(string $userId, bool $value): DataResponse {
803
+        $currentLoggedInUser = $this->userSession->getUser();
804
+
805
+        $targetUser = $this->userManager->get($userId);
806
+        if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
807
+            throw new OCSException('', 101);
808
+        }
809
+
810
+        // If not permitted
811
+        $subAdminManager = $this->groupManager->getSubAdmin();
812
+        if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
813
+            throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
814
+        }
815
+
816
+        // enable/disable the user now
817
+        $targetUser->setEnabled($value);
818
+        return new DataResponse();
819
+    }
820
+
821
+    /**
822
+     * @NoAdminRequired
823
+     * @NoSubAdminRequired
824
+     *
825
+     * @param string $userId
826
+     * @return DataResponse
827
+     * @throws OCSException
828
+     */
829
+    public function getUsersGroups(string $userId): DataResponse {
830
+        $loggedInUser = $this->userSession->getUser();
831
+
832
+        $targetUser = $this->userManager->get($userId);
833
+        if ($targetUser === null) {
834
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
835
+        }
836
+
837
+        if ($targetUser->getUID() === $loggedInUser->getUID() || $this->groupManager->isAdmin($loggedInUser->getUID())) {
838
+            // Self lookup or admin lookup
839
+            return new DataResponse([
840
+                'groups' => $this->groupManager->getUserGroupIds($targetUser)
841
+            ]);
842
+        } else {
843
+            $subAdminManager = $this->groupManager->getSubAdmin();
844
+
845
+            // Looking up someone else
846
+            if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
847
+                // Return the group that the method caller is subadmin of for the user in question
848
+                /** @var IGroup[] $getSubAdminsGroups */
849
+                $getSubAdminsGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
850
+                foreach ($getSubAdminsGroups as $key => $group) {
851
+                    $getSubAdminsGroups[$key] = $group->getGID();
852
+                }
853
+                $groups = array_intersect(
854
+                    $getSubAdminsGroups,
855
+                    $this->groupManager->getUserGroupIds($targetUser)
856
+                );
857
+                return new DataResponse(['groups' => $groups]);
858
+            } else {
859
+                // Not permitted
860
+                throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
861
+            }
862
+        }
863
+    }
864
+
865
+    /**
866
+     * @PasswordConfirmationRequired
867
+     * @NoAdminRequired
868
+     *
869
+     * @param string $userId
870
+     * @param string $groupid
871
+     * @return DataResponse
872
+     * @throws OCSException
873
+     */
874
+    public function addToGroup(string $userId, string $groupid = ''): DataResponse {
875
+        if ($groupid === '') {
876
+            throw new OCSException('', 101);
877
+        }
878
+
879
+        $group = $this->groupManager->get($groupid);
880
+        $targetUser = $this->userManager->get($userId);
881
+        if ($group === null) {
882
+            throw new OCSException('', 102);
883
+        }
884
+        if ($targetUser === null) {
885
+            throw new OCSException('', 103);
886
+        }
887
+
888
+        // If they're not an admin, check they are a subadmin of the group in question
889
+        $loggedInUser = $this->userSession->getUser();
890
+        $subAdminManager = $this->groupManager->getSubAdmin();
891
+        if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
892
+            throw new OCSException('', 104);
893
+        }
894
+
895
+        // Add user to group
896
+        $group->addUser($targetUser);
897
+        return new DataResponse();
898
+    }
899
+
900
+    /**
901
+     * @PasswordConfirmationRequired
902
+     * @NoAdminRequired
903
+     *
904
+     * @param string $userId
905
+     * @param string $groupid
906
+     * @return DataResponse
907
+     * @throws OCSException
908
+     */
909
+    public function removeFromGroup(string $userId, string $groupid): DataResponse {
910
+        $loggedInUser = $this->userSession->getUser();
911
+
912
+        if ($groupid === null || trim($groupid) === '') {
913
+            throw new OCSException('', 101);
914
+        }
915
+
916
+        $group = $this->groupManager->get($groupid);
917
+        if ($group === null) {
918
+            throw new OCSException('', 102);
919
+        }
920
+
921
+        $targetUser = $this->userManager->get($userId);
922
+        if ($targetUser === null) {
923
+            throw new OCSException('', 103);
924
+        }
925
+
926
+        // If they're not an admin, check they are a subadmin of the group in question
927
+        $subAdminManager = $this->groupManager->getSubAdmin();
928
+        if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
929
+            throw new OCSException('', 104);
930
+        }
931
+
932
+        // Check they aren't removing themselves from 'admin' or their 'subadmin; group
933
+        if ($targetUser->getUID() === $loggedInUser->getUID()) {
934
+            if ($this->groupManager->isAdmin($loggedInUser->getUID())) {
935
+                if ($group->getGID() === 'admin') {
936
+                    throw new OCSException('Cannot remove yourself from the admin group', 105);
937
+                }
938
+            } else {
939
+                // Not an admin, so the user must be a subadmin of this group, but that is not allowed.
940
+                throw new OCSException('Cannot remove yourself from this group as you are a SubAdmin', 105);
941
+            }
942
+        } elseif (!$this->groupManager->isAdmin($loggedInUser->getUID())) {
943
+            /** @var IGroup[] $subAdminGroups */
944
+            $subAdminGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
945
+            $subAdminGroups = array_map(function (IGroup $subAdminGroup) {
946
+                return $subAdminGroup->getGID();
947
+            }, $subAdminGroups);
948
+            $userGroups = $this->groupManager->getUserGroupIds($targetUser);
949
+            $userSubAdminGroups = array_intersect($subAdminGroups, $userGroups);
950
+
951
+            if (count($userSubAdminGroups) <= 1) {
952
+                // Subadmin must not be able to remove a user from all their subadmin groups.
953
+                throw new OCSException('Not viable to remove user from the last group you are SubAdmin of', 105);
954
+            }
955
+        }
956
+
957
+        // Remove user from group
958
+        $group->removeUser($targetUser);
959
+        return new DataResponse();
960
+    }
961
+
962
+    /**
963
+     * Creates a subadmin
964
+     *
965
+     * @PasswordConfirmationRequired
966
+     *
967
+     * @param string $userId
968
+     * @param string $groupid
969
+     * @return DataResponse
970
+     * @throws OCSException
971
+     */
972
+    public function addSubAdmin(string $userId, string $groupid): DataResponse {
973
+        $group = $this->groupManager->get($groupid);
974
+        $user = $this->userManager->get($userId);
975
+
976
+        // Check if the user exists
977
+        if ($user === null) {
978
+            throw new OCSException('User does not exist', 101);
979
+        }
980
+        // Check if group exists
981
+        if ($group === null) {
982
+            throw new OCSException('Group does not exist',  102);
983
+        }
984
+        // Check if trying to make subadmin of admin group
985
+        if ($group->getGID() === 'admin') {
986
+            throw new OCSException('Cannot create subadmins for admin group', 103);
987
+        }
988
+
989
+        $subAdminManager = $this->groupManager->getSubAdmin();
990
+
991
+        // We cannot be subadmin twice
992
+        if ($subAdminManager->isSubAdminOfGroup($user, $group)) {
993
+            return new DataResponse();
994
+        }
995
+        // Go
996
+        $subAdminManager->createSubAdmin($user, $group);
997
+        return new DataResponse();
998
+    }
999
+
1000
+    /**
1001
+     * Removes a subadmin from a group
1002
+     *
1003
+     * @PasswordConfirmationRequired
1004
+     *
1005
+     * @param string $userId
1006
+     * @param string $groupid
1007
+     * @return DataResponse
1008
+     * @throws OCSException
1009
+     */
1010
+    public function removeSubAdmin(string $userId, string $groupid): DataResponse {
1011
+        $group = $this->groupManager->get($groupid);
1012
+        $user = $this->userManager->get($userId);
1013
+        $subAdminManager = $this->groupManager->getSubAdmin();
1014
+
1015
+        // Check if the user exists
1016
+        if ($user === null) {
1017
+            throw new OCSException('User does not exist', 101);
1018
+        }
1019
+        // Check if the group exists
1020
+        if ($group === null) {
1021
+            throw new OCSException('Group does not exist', 101);
1022
+        }
1023
+        // Check if they are a subadmin of this said group
1024
+        if (!$subAdminManager->isSubAdminOfGroup($user, $group)) {
1025
+            throw new OCSException('User is not a subadmin of this group', 102);
1026
+        }
1027
+
1028
+        // Go
1029
+        $subAdminManager->deleteSubAdmin($user, $group);
1030
+        return new DataResponse();
1031
+    }
1032
+
1033
+    /**
1034
+     * Get the groups a user is a subadmin of
1035
+     *
1036
+     * @param string $userId
1037
+     * @return DataResponse
1038
+     * @throws OCSException
1039
+     */
1040
+    public function getUserSubAdminGroups(string $userId): DataResponse {
1041
+        $groups = $this->getUserSubAdminGroupsData($userId);
1042
+        return new DataResponse($groups);
1043
+    }
1044
+
1045
+    /**
1046
+     * @NoAdminRequired
1047
+     * @PasswordConfirmationRequired
1048
+     *
1049
+     * resend welcome message
1050
+     *
1051
+     * @param string $userId
1052
+     * @return DataResponse
1053
+     * @throws OCSException
1054
+     */
1055
+    public function resendWelcomeMessage(string $userId): DataResponse {
1056
+        $currentLoggedInUser = $this->userSession->getUser();
1057
+
1058
+        $targetUser = $this->userManager->get($userId);
1059
+        if ($targetUser === null) {
1060
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1061
+        }
1062
+
1063
+        // Check if admin / subadmin
1064
+        $subAdminManager = $this->groupManager->getSubAdmin();
1065
+        if (!$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
1066
+            && !$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
1067
+            // No rights
1068
+            throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
1069
+        }
1070
+
1071
+        $email = $targetUser->getEMailAddress();
1072
+        if ($email === '' || $email === null) {
1073
+            throw new OCSException('Email address not available', 101);
1074
+        }
1075
+
1076
+        try {
1077
+            $emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, false);
1078
+            $this->newUserMailHelper->sendMail($targetUser, $emailTemplate);
1079
+        } catch (\Exception $e) {
1080
+            $this->logger->error("Can't send new user mail to $email",
1081
+                [
1082
+                    'app' => 'settings',
1083
+                    'exception' => $e,
1084
+                ]
1085
+            );
1086
+            throw new OCSException('Sending email failed', 102);
1087
+        }
1088
+
1089
+        return new DataResponse();
1090
+    }
1091 1091
 }
Please login to merge, or discard this patch.