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