Passed
Push — master ( 22de68...e9bf19 )
by Roeland
10:44 queued 10s
created

UsersController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 29
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 14
nc 1
nop 14
dl 0
loc 29
rs 9.7998
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\Authentication\Token\RemoteWipe;
38
use OC\HintException;
39
use OC\Settings\Mailer\NewUserMailHelper;
40
use OCA\Provisioning_API\FederatedFileSharingFactory;
41
use OCP\App\IAppManager;
42
use OCP\AppFramework\Http\DataResponse;
43
use OCP\AppFramework\OCS\OCSException;
44
use OCP\AppFramework\OCS\OCSForbiddenException;
45
use OCP\IConfig;
46
use OCP\IGroup;
47
use OCP\IGroupManager;
48
use OCP\ILogger;
49
use OCP\IRequest;
50
use OCP\IUser;
51
use OCP\IUserManager;
52
use OCP\IUserSession;
53
use OCP\L10N\IFactory;
54
use OCP\Security\ISecureRandom;
55
56
class UsersController extends AUserData {
57
58
	/** @var IAppManager */
59
	private $appManager;
60
	/** @var ILogger */
61
	private $logger;
62
	/** @var IFactory */
63
	private $l10nFactory;
64
	/** @var NewUserMailHelper */
65
	private $newUserMailHelper;
66
	/** @var FederatedFileSharingFactory */
67
	private $federatedFileSharingFactory;
68
	/** @var ISecureRandom */
69
	private $secureRandom;
70
	/** @var RemoteWipe */
71
	private $remoteWipe;
72
73
	/**
74
	 * @param string $appName
75
	 * @param IRequest $request
76
	 * @param IUserManager $userManager
77
	 * @param IConfig $config
78
	 * @param IAppManager $appManager
79
	 * @param IGroupManager $groupManager
80
	 * @param IUserSession $userSession
81
	 * @param AccountManager $accountManager
82
	 * @param ILogger $logger
83
	 * @param IFactory $l10nFactory
84
	 * @param NewUserMailHelper $newUserMailHelper
85
	 * @param FederatedFileSharingFactory $federatedFileSharingFactory
86
	 * @param ISecureRandom $secureRandom
87
	 */
88
	public function __construct(string $appName,
89
								IRequest $request,
90
								IUserManager $userManager,
91
								IConfig $config,
92
								IAppManager $appManager,
93
								IGroupManager $groupManager,
94
								IUserSession $userSession,
95
								AccountManager $accountManager,
96
								ILogger $logger,
97
								IFactory $l10nFactory,
98
								NewUserMailHelper $newUserMailHelper,
99
								FederatedFileSharingFactory $federatedFileSharingFactory,
100
								ISecureRandom $secureRandom,
101
							    RemoteWipe $remoteWipe) {
102
		parent::__construct($appName,
103
							$request,
104
							$userManager,
105
							$config,
106
							$groupManager,
107
							$userSession,
108
							$accountManager);
109
110
		$this->appManager = $appManager;
111
		$this->logger = $logger;
112
		$this->l10nFactory = $l10nFactory;
113
		$this->newUserMailHelper = $newUserMailHelper;
114
		$this->federatedFileSharingFactory = $federatedFileSharingFactory;
115
		$this->secureRandom = $secureRandom;
116
		$this->remoteWipe = $remoteWipe;
117
	}
118
119
	/**
120
	 * @NoAdminRequired
121
	 *
122
	 * returns a list of users
123
	 *
124
	 * @param string $search
125
	 * @param int $limit
126
	 * @param int $offset
127
	 * @return DataResponse
128
	 */
129
	public function getUsers(string $search = '', $limit = null, $offset = 0): DataResponse {
130
		$user = $this->userSession->getUser();
131
		$users = [];
132
133
		// Admin? Or SubAdmin?
134
		$uid = $user->getUID();
135
		$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

135
		/** @scrutinizer ignore-call */ 
136
  $subAdminManager = $this->groupManager->getSubAdmin();
Loading history...
136
		if ($this->groupManager->isAdmin($uid)){
137
			$users = $this->userManager->search($search, $limit, $offset);
138
		} else if ($subAdminManager->isSubAdmin($user)) {
139
			$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($user);
140
			foreach ($subAdminOfGroups as $key => $group) {
141
				$subAdminOfGroups[$key] = $group->getGID();
142
			}
143
144
			$users = [];
145
			foreach ($subAdminOfGroups as $group) {
146
				$users = array_merge($users, $this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
147
			}
148
		}
149
150
		$users = array_keys($users);
151
152
		return new DataResponse([
153
			'users' => $users
154
		]);
155
	}
156
157
	/**
158
	 * @NoAdminRequired
159
	 *
160
	 * returns a list of users and their data
161
	 */
162
	public function getUsersDetails(string $search = '', $limit = null, $offset = 0): DataResponse {
163
		$currentUser = $this->userSession->getUser();
164
		$users = [];
165
166
		// Admin? Or SubAdmin?
167
		$uid = $currentUser->getUID();
168
		$subAdminManager = $this->groupManager->getSubAdmin();
169
		if ($this->groupManager->isAdmin($uid)){
170
			$users = $this->userManager->search($search, $limit, $offset);
171
			$users = array_keys($users);
172
		} else if ($subAdminManager->isSubAdmin($currentUser)) {
173
			$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
174
			foreach ($subAdminOfGroups as $key => $group) {
175
				$subAdminOfGroups[$key] = $group->getGID();
176
			}
177
178
			$users = [];
179
			foreach ($subAdminOfGroups as $group) {
180
				$users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
181
			}
182
			$users = array_merge(...$users);
183
		}
184
185
		$usersDetails = [];
186
		foreach ($users as $userId) {
187
			$userId = (string) $userId;
188
			$userData = $this->getUserData($userId);
189
			// Do not insert empty entry
190
			if (!empty($userData)) {
191
				$usersDetails[$userId] = $userData;
192
			} else {
193
				// Logged user does not have permissions to see this user
194
				// only showing its id
195
				$usersDetails[$userId] = ['id' => $userId];
196
			}
197
		}
198
199
		return new DataResponse([
200
			'users' => $usersDetails
201
		]);
202
	}
203
204
	/**
205
	 * @throws OCSException
206
	 */
207
	private function createNewUserId(): string {
208
		$attempts = 0;
209
		do {
210
			$uidCandidate = $this->secureRandom->generate(10, ISecureRandom::CHAR_HUMAN_READABLE);
211
			if (!$this->userManager->userExists($uidCandidate)) {
212
				return $uidCandidate;
213
			}
214
			$attempts++;
215
		} while ($attempts < 10);
216
		throw new OCSException('Could not create non-existing user id', 111);
217
	}
218
219
	/**
220
	 * @PasswordConfirmationRequired
221
	 * @NoAdminRequired
222
	 *
223
	 * @param string $userid
224
	 * @param string $password
225
	 * @param string $displayName
226
	 * @param string $email
227
	 * @param array $groups
228
	 * @param array $subadmin
229
	 * @param string $quota
230
	 * @param string $language
231
	 * @return DataResponse
232
	 * @throws OCSException
233
	 */
234
	public function addUser(string $userid,
235
							string $password = '',
236
							string $displayName = '',
237
							string $email = '',
238
							array $groups = [],
239
							array $subadmin = [],
240
							string $quota = '',
241
							string $language = ''): DataResponse {
242
		$user = $this->userSession->getUser();
243
		$isAdmin = $this->groupManager->isAdmin($user->getUID());
244
		$subAdminManager = $this->groupManager->getSubAdmin();
245
246
		if(empty($userid) && $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes') {
247
			$userid = $this->createNewUserId();
248
		}
249
250
		if ($this->userManager->userExists($userid)) {
251
			$this->logger->error('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']);
252
			throw new OCSException('User already exists', 102);
253
		}
254
255
		if ($groups !== []) {
256
			foreach ($groups as $group) {
257
				if (!$this->groupManager->groupExists($group)) {
258
					throw new OCSException('group '.$group.' does not exist', 104);
259
				}
260
				if (!$isAdmin && !$subAdminManager->isSubAdminOfGroup($user, $this->groupManager->get($group))) {
261
					throw new OCSException('insufficient privileges for group '. $group, 105);
262
				}
263
			}
264
		} else {
265
			if (!$isAdmin) {
266
				throw new OCSException('no group specified (required for subadmins)', 106);
267
			}
268
		}
269
270
		$subadminGroups = [];
271
		if ($subadmin !== []) {
272
			foreach ($subadmin as $groupid) {
273
				$group = $this->groupManager->get($groupid);
274
				// Check if group exists
275
				if ($group === null) {
276
					throw new OCSException('Subadmin group does not exist',  102);
277
				}
278
				// Check if trying to make subadmin of admin group
279
				if ($group->getGID() === 'admin') {
280
					throw new OCSException('Cannot create subadmins for admin group', 103);
281
				}
282
				// Check if has permission to promote subadmins
283
				if (!$subAdminManager->isSubAdminOfGroup($user, $group) && !$isAdmin) {
284
					throw new OCSForbiddenException('No permissions to promote subadmins');
285
				}
286
				$subadminGroups[] = $group;
287
			}
288
		}
289
290
		$generatePasswordResetToken = false;
291
		if ($password === '') {
292
			if ($email === '') {
293
				throw new OCSException('To send a password link to the user an email address is required.', 108);
294
			}
295
296
			$password = $this->secureRandom->generate(10);
297
			// Make sure we pass the password_policy
298
			$password .= $this->secureRandom->generate(2, '$!.,;:-~+*[]{}()');
299
			$generatePasswordResetToken = true;
300
		}
301
302
		if ($email === '' && $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes') {
303
			throw new OCSException('Required email address was not provided', 110);
304
		}
305
306
		try {
307
			$newUser = $this->userManager->createUser($userid, $password);
308
			$this->logger->info('Successful addUser call with userid: ' . $userid, ['app' => 'ocs_api']);
309
310
			foreach ($groups as $group) {
311
				$this->groupManager->get($group)->addUser($newUser);
312
				$this->logger->info('Added userid ' . $userid . ' to group ' . $group, ['app' => 'ocs_api']);
313
			}
314
			foreach ($subadminGroups as $group) {
315
				$subAdminManager->createSubAdmin($newUser, $group);
316
			}
317
318
			if ($displayName !== '') {
319
				$this->editUser($userid, 'display', $displayName);
320
			}
321
322
			if ($quota !== '') {
323
				$this->editUser($userid, 'quota', $quota);
324
			}
325
326
			if ($language !== '') {
327
				$this->editUser($userid, 'language', $language);
328
			}
329
330
			// Send new user mail only if a mail is set
331
			if ($email !== '') {
332
				$newUser->setEMailAddress($email);
333
				try {
334
					$emailTemplate = $this->newUserMailHelper->generateTemplate($newUser, $generatePasswordResetToken);
335
					$this->newUserMailHelper->sendMail($newUser, $emailTemplate);
336
				} catch (\Exception $e) {
337
					// Mail could be failing hard or just be plain not configured
338
					// Logging error as it is the hardest of the two
339
					$this->logger->logException($e, [
340
						'message' => "Unable to send the invitation mail to $email",
341
						'level' => ILogger::ERROR,
342
						'app' => 'ocs_api',
343
					]);
344
				}
345
			}
346
347
			return new DataResponse(['id' => $userid]);
348
349
		} catch (HintException $e) {
350
			$this->logger->logException($e, [
351
				'message' => 'Failed addUser attempt with hint exception.',
352
				'level' => ILogger::WARN,
353
				'app' => 'ocs_api',
354
			]);
355
			throw new OCSException($e->getHint(), 107);
356
		} catch (OCSException $e) {
357
			$this->logger->logException($e, [
358
				'message' => 'Failed addUser attempt with ocs exeption.',
359
				'level' => ILogger::ERROR,
360
				'app' => 'ocs_api',
361
			]);
362
			throw $e;
363
		} catch (\Exception $e) {
364
			$this->logger->logException($e, [
365
				'message' => 'Failed addUser attempt with exception.',
366
				'level' => ILogger::ERROR,
367
				'app' => 'ocs_api',
368
			]);
369
			throw new OCSException('Bad request', 101);
370
		}
371
	}
372
373
	/**
374
	 * @NoAdminRequired
375
	 * @NoSubAdminRequired
376
	 *
377
	 * gets user info
378
	 *
379
	 * @param string $userId
380
	 * @return DataResponse
381
	 * @throws OCSException
382
	 */
383
	public function getUser(string $userId): DataResponse {
384
		$data = $this->getUserData($userId);
385
		// getUserData returns empty array if not enough permissions
386
		if (empty($data)) {
387
			throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
388
		}
389
		return new DataResponse($data);
390
	}
391
392
	/**
393
	 * @NoAdminRequired
394
	 * @NoSubAdminRequired
395
	 *
396
	 * gets user info from the currently logged in user
397
	 *
398
	 * @return DataResponse
399
	 * @throws OCSException
400
	 */
401
	public function getCurrentUser(): DataResponse {
402
		$user = $this->userSession->getUser();
403
		if ($user) {
404
			$data =  $this->getUserData($user->getUID());
405
			// rename "displayname" to "display-name" only for this call to keep
406
			// the API stable.
407
			$data['display-name'] = $data['displayname'];
408
			unset($data['displayname']);
409
			return new DataResponse($data);
410
411
		}
412
413
		throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
414
	}
415
416
	/**
417
	 * @NoAdminRequired
418
	 * @NoSubAdminRequired
419
	 */
420
	public function getEditableFields(): DataResponse {
421
		$permittedFields = [];
422
423
		// Editing self (display, email)
424
		if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
425
			$permittedFields[] = AccountManager::PROPERTY_DISPLAYNAME;
426
			$permittedFields[] = AccountManager::PROPERTY_EMAIL;
427
		}
428
429
		if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
430
			$federatedFileSharing = $this->federatedFileSharingFactory->get();
431
			$shareProvider = $federatedFileSharing->getFederatedShareProvider();
432
			if ($shareProvider->isLookupServerUploadEnabled()) {
433
				$permittedFields[] = AccountManager::PROPERTY_PHONE;
434
				$permittedFields[] = AccountManager::PROPERTY_ADDRESS;
435
				$permittedFields[] = AccountManager::PROPERTY_WEBSITE;
436
				$permittedFields[] = AccountManager::PROPERTY_TWITTER;
437
			}
438
		}
439
440
		return new DataResponse($permittedFields);
441
	}
442
443
	/**
444
	 * @NoAdminRequired
445
	 * @NoSubAdminRequired
446
	 * @PasswordConfirmationRequired
447
	 *
448
	 * edit users
449
	 *
450
	 * @param string $userId
451
	 * @param string $key
452
	 * @param string $value
453
	 * @return DataResponse
454
	 * @throws OCSException
455
	 */
456
	public function editUser(string $userId, string $key, string $value): DataResponse {
457
		$currentLoggedInUser = $this->userSession->getUser();
458
459
		$targetUser = $this->userManager->get($userId);
460
		if ($targetUser === null) {
461
			throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
462
		}
463
464
		$permittedFields = [];
465
		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
466
			// Editing self (display, email)
467
			if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
468
				$permittedFields[] = 'display';
469
				$permittedFields[] = AccountManager::PROPERTY_DISPLAYNAME;
470
				$permittedFields[] = AccountManager::PROPERTY_EMAIL;
471
			}
472
473
			$permittedFields[] = 'password';
474
			if ($this->config->getSystemValue('force_language', false) === false ||
475
				$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
476
				$permittedFields[] = 'language';
477
			}
478
479
			if ($this->config->getSystemValue('force_locale', false) === false ||
480
				$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
481
				$permittedFields[] = 'locale';
482
			}
483
484
			if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
485
				$federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application();
486
				$shareProvider = $federatedFileSharing->getFederatedShareProvider();
487
				if ($shareProvider->isLookupServerUploadEnabled()) {
488
					$permittedFields[] = AccountManager::PROPERTY_PHONE;
489
					$permittedFields[] = AccountManager::PROPERTY_ADDRESS;
490
					$permittedFields[] = AccountManager::PROPERTY_WEBSITE;
491
					$permittedFields[] = AccountManager::PROPERTY_TWITTER;
492
				}
493
			}
494
495
			// If admin they can edit their own quota
496
			if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
497
				$permittedFields[] = 'quota';
498
			}
499
		} else {
500
			// Check if admin / subadmin
501
			$subAdminManager = $this->groupManager->getSubAdmin();
502
			if ($subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
503
			|| $this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
504
				// They have permissions over the user
505
				$permittedFields[] = 'display';
506
				$permittedFields[] = AccountManager::PROPERTY_DISPLAYNAME;
507
				$permittedFields[] = AccountManager::PROPERTY_EMAIL;
508
				$permittedFields[] = 'password';
509
				$permittedFields[] = 'language';
510
				$permittedFields[] = 'locale';
511
				$permittedFields[] = AccountManager::PROPERTY_PHONE;
512
				$permittedFields[] = AccountManager::PROPERTY_ADDRESS;
513
				$permittedFields[] = AccountManager::PROPERTY_WEBSITE;
514
				$permittedFields[] = AccountManager::PROPERTY_TWITTER;
515
				$permittedFields[] = 'quota';
516
			} else {
517
				// No rights
518
				throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
519
			}
520
		}
521
		// Check if permitted to edit this field
522
		if (!in_array($key, $permittedFields)) {
523
			throw new OCSException('', \OCP\API::RESPOND_UNAUTHORISED);
524
		}
525
		// Process the edit
526
		switch($key) {
527
			case 'display':
528
			case AccountManager::PROPERTY_DISPLAYNAME:
529
				$targetUser->setDisplayName($value);
530
				break;
531
			case 'quota':
532
				$quota = $value;
533
				if ($quota !== 'none' && $quota !== 'default') {
534
					if (is_numeric($quota)) {
535
						$quota = (float) $quota;
536
					} else {
537
						$quota = \OCP\Util::computerFileSize($quota);
538
					}
539
					if ($quota === false) {
0 ignored issues
show
introduced by
The condition $quota === false is always false.
Loading history...
540
						throw new OCSException('Invalid quota value '.$value, 103);
541
					}
542
					if ($quota === -1) {
0 ignored issues
show
introduced by
The condition $quota === -1 is always false.
Loading history...
543
						$quota = 'none';
544
					} else {
545
						$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

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