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