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