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

UsersController::getUserSubAdminGroups()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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