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