Passed
Push — master ( 087343...c1eff7 )
by Blizzz
13:03 queued 10s
created

UsersController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 27
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 13
nc 1
nop 13
dl 0
loc 27
rs 9.8333
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
declare(strict_types=1);
3
/**
4
 * @copyright Copyright (c) 2016, ownCloud, Inc.
5
 *
6
 * @author Arthur Schiwon <[email protected]>
7
 * @author Bjoern Schiessle <[email protected]>
8
 * @author Joas Schilling <[email protected]>
9
 * @author Lukas Reschke <[email protected]>
10
 * @author michag86 <[email protected]>
11
 * @author Morris Jobke <[email protected]>
12
 * @author Roeland Jago Douma <[email protected]>
13
 * @author Thomas Müller <[email protected]>
14
 * @author Tom Needham <[email protected]>
15
 * @author John Molakvoæ <[email protected]>
16
 * @author Thomas Citharel <[email protected]>
17
 *
18
 * @license AGPL-3.0
19
 *
20
 * This code is free software: you can redistribute it and/or modify
21
 * it under the terms of the GNU Affero General Public License, version 3,
22
 * as published by the Free Software Foundation.
23
 *
24
 * This program is distributed in the hope that it will be useful,
25
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27
 * GNU Affero General Public License for more details.
28
 *
29
 * You should have received a copy of the GNU Affero General Public License, version 3,
30
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
31
 *
32
 */
33
34
namespace OCA\Provisioning_API\Controller;
35
36
use OC\Accounts\AccountManager;
37
use OC\HintException;
38
use OC\Settings\Mailer\NewUserMailHelper;
39
use OCA\Provisioning_API\FederatedFileSharingFactory;
40
use OCP\App\IAppManager;
41
use OCP\AppFramework\Http\DataResponse;
42
use OCP\AppFramework\OCS\OCSException;
43
use OCP\AppFramework\OCS\OCSForbiddenException;
44
use OCP\IConfig;
45
use OCP\IGroup;
46
use OCP\IGroupManager;
47
use OCP\ILogger;
48
use OCP\IRequest;
49
use OCP\IUserManager;
50
use OCP\IUserSession;
51
use OCP\L10N\IFactory;
52
use OCP\Security\ISecureRandom;
53
54
class UsersController extends AUserData {
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();
0 ignored issues
show
Bug introduced by
The method getSubAdmin() does not exist on OCP\IGroupManager. Since it exists in all sub-types, consider adding an abstract or default implementation to OCP\IGroupManager. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

129
		/** @scrutinizer ignore-call */ 
130
  $subAdminManager = $this->groupManager->getSubAdmin();
Loading history...
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
					$this->logger->logException($e, [
332
						'message' => "Can't send new user mail to $email",
333
						'level' => ILogger::ERROR,
334
						'app' => 'ocs_api',
335
					]);
336
					throw new OCSException('Unable to send the invitation mail', 109);
337
				}
338
			}
339
340
			return new DataResponse(['UserID' => $userid]);
341
342
		} catch (HintException $e ) {
343
			$this->logger->logException($e, [
344
				'message' => 'Failed addUser attempt with hint exception.',
345
				'level' => ILogger::WARN,
346
				'app' => 'ocs_api',
347
			]);
348
			throw new OCSException($e->getHint(), 107);
349
		} catch (\Exception $e) {
350
			$this->logger->logException($e, [
351
				'message' => 'Failed addUser attempt with exception.',
352
				'level' => ILogger::ERROR,
353
				'app' => 'ocs_api',
354
			]);
355
			throw new OCSException('Bad request', 101);
356
		}
357
	}
358
359
	/**
360
	 * @NoAdminRequired
361
	 * @NoSubAdminRequired
362
	 *
363
	 * gets user info
364
	 *
365
	 * @param string $userId
366
	 * @return DataResponse
367
	 * @throws OCSException
368
	 */
369
	public function getUser(string $userId): DataResponse {
370
		$data = $this->getUserData($userId);
371
		// getUserData returns empty array if not enough permissions
372
		if (empty($data)) {
373
			throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
374
		}
375
		return new DataResponse($data);
376
	}
377
378
	/**
379
	 * @NoAdminRequired
380
	 * @NoSubAdminRequired
381
	 *
382
	 * gets user info from the currently logged in user
383
	 *
384
	 * @return DataResponse
385
	 * @throws OCSException
386
	 */
387
	public function getCurrentUser(): DataResponse {
388
		$user = $this->userSession->getUser();
389
		if ($user) {
390
			$data =  $this->getUserData($user->getUID());
391
			// rename "displayname" to "display-name" only for this call to keep
392
			// the API stable.
393
			$data['display-name'] = $data['displayname'];
394
			unset($data['displayname']);
395
			return new DataResponse($data);
396
397
		}
398
399
		throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
400
	}
401
402
	/**
403
	 * @NoAdminRequired
404
	 * @NoSubAdminRequired
405
	 */
406
	public function getEditableFields(): DataResponse {
407
		$permittedFields = [];
408
409
		// Editing self (display, email)
410
		if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
411
			$permittedFields[] = AccountManager::PROPERTY_DISPLAYNAME;
412
			$permittedFields[] = AccountManager::PROPERTY_EMAIL;
413
		}
414
415
		if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
416
			$federatedFileSharing = $this->federatedFileSharingFactory->get();
417
			$shareProvider = $federatedFileSharing->getFederatedShareProvider();
418
			if ($shareProvider->isLookupServerUploadEnabled()) {
419
				$permittedFields[] = AccountManager::PROPERTY_PHONE;
420
				$permittedFields[] = AccountManager::PROPERTY_ADDRESS;
421
				$permittedFields[] = AccountManager::PROPERTY_WEBSITE;
422
				$permittedFields[] = AccountManager::PROPERTY_TWITTER;
423
			}
424
		}
425
426
		return new DataResponse($permittedFields);
427
	}
428
429
	/**
430
	 * @NoAdminRequired
431
	 * @NoSubAdminRequired
432
	 * @PasswordConfirmationRequired
433
	 *
434
	 * edit users
435
	 *
436
	 * @param string $userId
437
	 * @param string $key
438
	 * @param string $value
439
	 * @return DataResponse
440
	 * @throws OCSException
441
	 */
442
	public function editUser(string $userId, string $key, string $value): DataResponse {
443
		$currentLoggedInUser = $this->userSession->getUser();
444
445
		$targetUser = $this->userManager->get($userId);
446
		if ($targetUser === null) {
447
			throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
448
		}
449
450
		$permittedFields = [];
451
		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
452
			// Editing self (display, email)
453
			if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
454
				$permittedFields[] = 'display';
455
				$permittedFields[] = AccountManager::PROPERTY_DISPLAYNAME;
456
				$permittedFields[] = AccountManager::PROPERTY_EMAIL;
457
			}
458
459
			$permittedFields[] = 'password';
460
			if ($this->config->getSystemValue('force_language', false) === false ||
461
				$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
462
				$permittedFields[] = 'language';
463
			}
464
465
			if ($this->config->getSystemValue('force_locale', false) === false ||
466
				$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
467
				$permittedFields[] = 'locale';
468
			}
469
470
			if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
471
				$federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application();
472
				$shareProvider = $federatedFileSharing->getFederatedShareProvider();
473
				if ($shareProvider->isLookupServerUploadEnabled()) {
474
					$permittedFields[] = AccountManager::PROPERTY_PHONE;
475
					$permittedFields[] = AccountManager::PROPERTY_ADDRESS;
476
					$permittedFields[] = AccountManager::PROPERTY_WEBSITE;
477
					$permittedFields[] = AccountManager::PROPERTY_TWITTER;
478
				}
479
			}
480
481
			// If admin they can edit their own quota
482
			if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
483
				$permittedFields[] = 'quota';
484
			}
485
		} else {
486
			// Check if admin / subadmin
487
			$subAdminManager = $this->groupManager->getSubAdmin();
488
			if ($subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
489
			|| $this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
490
				// They have permissions over the user
491
				$permittedFields[] = 'display';
492
				$permittedFields[] = AccountManager::PROPERTY_DISPLAYNAME;
493
				$permittedFields[] = AccountManager::PROPERTY_EMAIL;
494
				$permittedFields[] = 'password';
495
				$permittedFields[] = 'language';
496
				$permittedFields[] = 'locale';
497
				$permittedFields[] = AccountManager::PROPERTY_PHONE;
498
				$permittedFields[] = AccountManager::PROPERTY_ADDRESS;
499
				$permittedFields[] = AccountManager::PROPERTY_WEBSITE;
500
				$permittedFields[] = AccountManager::PROPERTY_TWITTER;
501
				$permittedFields[] = 'quota';
502
			} else {
503
				// No rights
504
				throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
505
			}
506
		}
507
		// Check if permitted to edit this field
508
		if (!in_array($key, $permittedFields)) {
509
			throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
510
		}
511
		// Process the edit
512
		switch($key) {
513
			case 'display':
514
			case AccountManager::PROPERTY_DISPLAYNAME:
515
				$targetUser->setDisplayName($value);
516
				break;
517
			case 'quota':
518
				$quota = $value;
519
				if ($quota !== 'none' && $quota !== 'default') {
520
					if (is_numeric($quota)) {
521
						$quota = (float) $quota;
522
					} else {
523
						$quota = \OCP\Util::computerFileSize($quota);
524
					}
525
					if ($quota === false) {
0 ignored issues
show
introduced by
The condition $quota === false is always false.
Loading history...
526
						throw new OCSException('Invalid quota value '.$value, 103);
527
					}
528
					if ($quota === -1) {
0 ignored issues
show
introduced by
The condition $quota === -1 is always false.
Loading history...
529
						$quota = 'none';
530
					} else {
531
						$quota = \OCP\Util::humanFileSize($quota);
0 ignored issues
show
Bug introduced by
$quota of type double is incompatible with the type integer expected by parameter $bytes of OCP\Util::humanFileSize(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

531
						$quota = \OCP\Util::humanFileSize(/** @scrutinizer ignore-type */ $quota);
Loading history...
532
					}
533
				}
534
				$targetUser->setQuota($quota);
535
				break;
536
			case 'password':
537
				try {
538
					if (!$targetUser->canChangePassword()) {
539
						throw new OCSException('Setting the password is not supported by the users backend', 103);
540
					}
541
					$targetUser->setPassword($value);
542
				} catch (HintException $e) { // password policy error
543
					throw new OCSException($e->getMessage(), 103);
544
				}
545
				break;
546
			case 'language':
547
				$languagesCodes = $this->l10nFactory->findAvailableLanguages();
548
				if (!in_array($value, $languagesCodes, true) && $value !== 'en') {
549
					throw new OCSException('Invalid language', 102);
550
				}
551
				$this->config->setUserValue($targetUser->getUID(), 'core', 'lang', $value);
552
				break;
553
			case 'locale':
554
				if (!$this->l10nFactory->localeExists($value)) {
555
					throw new OCSException('Invalid locale', 102);
556
				}
557
				$this->config->setUserValue($targetUser->getUID(), 'core', 'locale', $value);
558
				break;
559
			case AccountManager::PROPERTY_EMAIL:
560
				if (filter_var($value, FILTER_VALIDATE_EMAIL) || $value === '') {
561
					$targetUser->setEMailAddress($value);
562
				} else {
563
					throw new OCSException('', 102);
564
				}
565
				break;
566
			case AccountManager::PROPERTY_PHONE:
567
			case AccountManager::PROPERTY_ADDRESS:
568
			case AccountManager::PROPERTY_WEBSITE:
569
			case AccountManager::PROPERTY_TWITTER:
570
				$userAccount = $this->accountManager->getUser($targetUser);
571
				if ($userAccount[$key]['value'] !== $value) {
572
					$userAccount[$key]['value'] = $value;
573
					$this->accountManager->updateUser($targetUser, $userAccount);
574
				}
575
				break;
576
			default:
577
				throw new OCSException('', 103);
578
		}
579
		return new DataResponse();
580
	}
581
582
	/**
583
	 * @PasswordConfirmationRequired
584
	 * @NoAdminRequired
585
	 *
586
	 * @param string $userId
587
	 * @return DataResponse
588
	 * @throws OCSException
589
	 */
590
	public function deleteUser(string $userId): DataResponse {
591
		$currentLoggedInUser = $this->userSession->getUser();
592
593
		$targetUser = $this->userManager->get($userId);
594
595
		if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
596
			throw new OCSException('', 101);
597
		}
598
599
		// If not permitted
600
		$subAdminManager = $this->groupManager->getSubAdmin();
601
		if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
602
			throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
603
		}
604
605
		// Go ahead with the delete
606
		if ($targetUser->delete()) {
607
			return new DataResponse();
608
		} else {
609
			throw new OCSException('', 101);
610
		}
611
	}
612
613
	/**
614
	 * @PasswordConfirmationRequired
615
	 * @NoAdminRequired
616
	 *
617
	 * @param string $userId
618
	 * @return DataResponse
619
	 * @throws OCSException
620
	 * @throws OCSForbiddenException
621
	 */
622
	public function disableUser(string $userId): DataResponse {
623
		return $this->setEnabled($userId, false);
624
	}
625
626
	/**
627
	 * @PasswordConfirmationRequired
628
	 * @NoAdminRequired
629
	 *
630
	 * @param string $userId
631
	 * @return DataResponse
632
	 * @throws OCSException
633
	 * @throws OCSForbiddenException
634
	 */
635
	public function enableUser(string $userId): DataResponse {
636
		return $this->setEnabled($userId, true);
637
	}
638
639
	/**
640
	 * @param string $userId
641
	 * @param bool $value
642
	 * @return DataResponse
643
	 * @throws OCSException
644
	 */
645
	private function setEnabled(string $userId, bool $value): DataResponse {
646
		$currentLoggedInUser = $this->userSession->getUser();
647
648
		$targetUser = $this->userManager->get($userId);
649
		if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
650
			throw new OCSException('', 101);
651
		}
652
653
		// If not permitted
654
		$subAdminManager = $this->groupManager->getSubAdmin();
655
		if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
656
			throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
657
		}
658
659
		// enable/disable the user now
660
		$targetUser->setEnabled($value);
661
		return new DataResponse();
662
	}
663
664
	/**
665
	 * @NoAdminRequired
666
	 * @NoSubAdminRequired
667
	 *
668
	 * @param string $userId
669
	 * @return DataResponse
670
	 * @throws OCSException
671
	 */
672
	public function getUsersGroups(string $userId): DataResponse {
673
		$loggedInUser = $this->userSession->getUser();
674
675
		$targetUser = $this->userManager->get($userId);
676
		if ($targetUser === null) {
677
			throw new OCSException('', \OCP\API::RESPOND_NOT_FOUND);
678
		}
679
680
		if ($targetUser->getUID() === $loggedInUser->getUID() || $this->groupManager->isAdmin($loggedInUser->getUID())) {
681
			// Self lookup or admin lookup
682
			return new DataResponse([
683
				'groups' => $this->groupManager->getUserGroupIds($targetUser)
684
			]);
685
		} else {
686
			$subAdminManager = $this->groupManager->getSubAdmin();
687
688
			// Looking up someone else
689
			if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
690
				// Return the group that the method caller is subadmin of for the user in question
691
				/** @var IGroup[] $getSubAdminsGroups */
692
				$getSubAdminsGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
693
				foreach ($getSubAdminsGroups as $key => $group) {
694
					$getSubAdminsGroups[$key] = $group->getGID();
695
				}
696
				$groups = array_intersect(
697
					$getSubAdminsGroups,
698
					$this->groupManager->getUserGroupIds($targetUser)
699
				);
700
				return new DataResponse(['groups' => $groups]);
701
			} else {
702
				// Not permitted
703
				throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
704
			}
705
		}
706
707
	}
708
709
	/**
710
	 * @PasswordConfirmationRequired
711
	 * @NoAdminRequired
712
	 *
713
	 * @param string $userId
714
	 * @param string $groupid
715
	 * @return DataResponse
716
	 * @throws OCSException
717
	 */
718
	public function addToGroup(string $userId, string $groupid = ''): DataResponse {
719
		if ($groupid === '') {
720
			throw new OCSException('', 101);
721
		}
722
723
		$group = $this->groupManager->get($groupid);
724
		$targetUser = $this->userManager->get($userId);
725
		if ($group === null) {
726
			throw new OCSException('', 102);
727
		}
728
		if ($targetUser === null) {
729
			throw new OCSException('', 103);
730
		}
731
732
		// If they're not an admin, check they are a subadmin of the group in question
733
		$loggedInUser = $this->userSession->getUser();
734
		$subAdminManager = $this->groupManager->getSubAdmin();
735
		if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
736
			throw new OCSException('', 104);
737
		}
738
739
		// Add user to group
740
		$group->addUser($targetUser);
741
		return new DataResponse();
742
	}
743
744
	/**
745
	 * @PasswordConfirmationRequired
746
	 * @NoAdminRequired
747
	 *
748
	 * @param string $userId
749
	 * @param string $groupid
750
	 * @return DataResponse
751
	 * @throws OCSException
752
	 */
753
	public function removeFromGroup(string $userId, string $groupid): DataResponse {
754
		$loggedInUser = $this->userSession->getUser();
755
756
		if ($groupid === null || trim($groupid) === '') {
757
			throw new OCSException('', 101);
758
		}
759
760
		$group = $this->groupManager->get($groupid);
761
		if ($group === null) {
762
			throw new OCSException('', 102);
763
		}
764
765
		$targetUser = $this->userManager->get($userId);
766
		if ($targetUser === null) {
767
			throw new OCSException('', 103);
768
		}
769
770
		// If they're not an admin, check they are a subadmin of the group in question
771
		$subAdminManager = $this->groupManager->getSubAdmin();
772
		if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
773
			throw new OCSException('', 104);
774
		}
775
776
		// Check they aren't removing themselves from 'admin' or their 'subadmin; group
777
		if ($targetUser->getUID() === $loggedInUser->getUID()) {
778
			if ($this->groupManager->isAdmin($loggedInUser->getUID())) {
779
				if ($group->getGID() === 'admin') {
780
					throw new OCSException('Cannot remove yourself from the admin group', 105);
781
				}
782
			} else {
783
				// Not an admin, so the user must be a subadmin of this group, but that is not allowed.
784
				throw new OCSException('Cannot remove yourself from this group as you are a SubAdmin', 105);
785
			}
786
787
		} else if (!$this->groupManager->isAdmin($loggedInUser->getUID())) {
788
			/** @var IGroup[] $subAdminGroups */
789
			$subAdminGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
790
			$subAdminGroups = array_map(function (IGroup $subAdminGroup) {
791
				return $subAdminGroup->getGID();
792
			}, $subAdminGroups);
793
			$userGroups = $this->groupManager->getUserGroupIds($targetUser);
794
			$userSubAdminGroups = array_intersect($subAdminGroups, $userGroups);
795
796
			if (count($userSubAdminGroups) <= 1) {
797
				// Subadmin must not be able to remove a user from all their subadmin groups.
798
				throw new OCSException('Not viable to remove user from the last group you are SubAdmin of', 105);
799
			}
800
		}
801
802
		// Remove user from group
803
		$group->removeUser($targetUser);
804
		return new DataResponse();
805
	}
806
807
	/**
808
	 * Creates a subadmin
809
	 *
810
	 * @PasswordConfirmationRequired
811
	 *
812
	 * @param string $userId
813
	 * @param string $groupid
814
	 * @return DataResponse
815
	 * @throws OCSException
816
	 */
817
	public function addSubAdmin(string $userId, string $groupid): DataResponse {
818
		$group = $this->groupManager->get($groupid);
819
		$user = $this->userManager->get($userId);
820
821
		// Check if the user exists
822
		if ($user === null) {
823
			throw new OCSException('User does not exist', 101);
824
		}
825
		// Check if group exists
826
		if ($group === null) {
827
			throw new OCSException('Group does not exist',  102);
828
		}
829
		// Check if trying to make subadmin of admin group
830
		if ($group->getGID() === 'admin') {
831
			throw new OCSException('Cannot create subadmins for admin group', 103);
832
		}
833
834
		$subAdminManager = $this->groupManager->getSubAdmin();
835
836
		// We cannot be subadmin twice
837
		if ($subAdminManager->isSubAdminOfGroup($user, $group)) {
838
			return new DataResponse();
839
		}
840
		// Go
841
		$subAdminManager->createSubAdmin($user, $group);
842
		return new DataResponse();
843
	}
844
845
	/**
846
	 * Removes a subadmin from a group
847
	 *
848
	 * @PasswordConfirmationRequired
849
	 *
850
	 * @param string $userId
851
	 * @param string $groupid
852
	 * @return DataResponse
853
	 * @throws OCSException
854
	 */
855
	public function removeSubAdmin(string $userId, string $groupid): DataResponse {
856
		$group = $this->groupManager->get($groupid);
857
		$user = $this->userManager->get($userId);
858
		$subAdminManager = $this->groupManager->getSubAdmin();
859
860
		// Check if the user exists
861
		if ($user === null) {
862
			throw new OCSException('User does not exist', 101);
863
		}
864
		// Check if the group exists
865
		if ($group === null) {
866
			throw new OCSException('Group does not exist', 101);
867
		}
868
		// Check if they are a subadmin of this said group
869
		if (!$subAdminManager->isSubAdminOfGroup($user, $group)) {
870
			throw new OCSException('User is not a subadmin of this group', 102);
871
		}
872
873
		// Go
874
		$subAdminManager->deleteSubAdmin($user, $group);
875
		return new DataResponse();
876
	}
877
878
	/**
879
	 * Get the groups a user is a subadmin of
880
	 *
881
	 * @param string $userId
882
	 * @return DataResponse
883
	 * @throws OCSException
884
	 */
885
	public function getUserSubAdminGroups(string $userId): DataResponse {
886
		$groups = $this->getUserSubAdminGroupsData($userId);
887
		return new DataResponse($groups);
888
	}
889
890
	/**
891
	 * @NoAdminRequired
892
	 * @PasswordConfirmationRequired
893
	 *
894
	 * resend welcome message
895
	 *
896
	 * @param string $userId
897
	 * @return DataResponse
898
	 * @throws OCSException
899
	 */
900
	public function resendWelcomeMessage(string $userId): DataResponse {
901
		$currentLoggedInUser = $this->userSession->getUser();
902
903
		$targetUser = $this->userManager->get($userId);
904
		if ($targetUser === null) {
905
			throw new OCSException('', \OCP\API::RESPOND_NOT_FOUND);
906
		}
907
908
		// Check if admin / subadmin
909
		$subAdminManager = $this->groupManager->getSubAdmin();
910
		if (!$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
911
			&& !$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
912
			// No rights
913
			throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
914
		}
915
916
		$email = $targetUser->getEMailAddress();
917
		if ($email === '' || $email === null) {
918
			throw new OCSException('Email address not available', 101);
919
		}
920
921
		try {
922
			$emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, false);
923
			$this->newUserMailHelper->sendMail($targetUser, $emailTemplate);
924
		} catch(\Exception $e) {
925
			$this->logger->logException($e, [
926
				'message' => "Can't send new user mail to $email",
927
				'level' => ILogger::ERROR,
928
				'app' => 'settings',
929
			]);
930
			throw new OCSException('Sending email failed', 102);
931
		}
932
933
		return new DataResponse();
934
	}
935
}
936