Completed
Push — master ( 811f7b...15314b )
by Morris
54:22 queued 31:53
created

UsersController::index()   C

Complexity

Conditions 24
Paths 56

Size

Total Lines 74
Code Lines 43

Duplication

Lines 10
Ratio 13.51 %

Importance

Changes 0
Metric Value
cc 24
eloc 43
nc 56
nop 5
dl 10
loc 74
rs 5.284
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Arthur Schiwon <[email protected]>
6
 * @author Clark Tomlinson <[email protected]>
7
 * @author Joas Schilling <[email protected]>
8
 * @author Lukas Reschke <[email protected]>
9
 * @author Morris Jobke <[email protected]>
10
 * @author Robin Appelman <[email protected]>
11
 * @author Roeland Jago Douma <[email protected]>
12
 * @author Thomas Müller <[email protected]>
13
 * @author Vincent Petry <[email protected]>
14
 *
15
 * @license AGPL-3.0
16
 *
17
 * This code is free software: you can redistribute it and/or modify
18
 * it under the terms of the GNU Affero General Public License, version 3,
19
 * as published by the Free Software Foundation.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License, version 3,
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
28
 *
29
 */
30
31
namespace OC\Settings\Controller;
32
33
use OC\Accounts\AccountManager;
34
use OC\AppFramework\Http;
35
use OC\ForbiddenException;
36
use OC\Settings\Mailer\NewUserMailHelper;
37
use OC\Security\IdentityProof\Manager;
38
use OCP\App\IAppManager;
39
use OCP\AppFramework\Controller;
40
use OCP\AppFramework\Http\DataResponse;
41
use OCP\AppFramework\Utility\ITimeFactory;
42
use OCP\BackgroundJob\IJobList;
43
use OCP\IConfig;
44
use OCP\IGroupManager;
45
use OCP\IL10N;
46
use OCP\ILogger;
47
use OCP\IRequest;
48
use OCP\IURLGenerator;
49
use OCP\IUser;
50
use OCP\IUserManager;
51
use OCP\IUserSession;
52
use OCP\Mail\IMailer;
53
use OCP\IAvatarManager;
54
use OCP\Security\ICrypto;
55
use OCP\Security\ISecureRandom;
56
57
/**
58
 * @package OC\Settings\Controller
59
 */
60
class UsersController extends Controller {
61
	/** @var IL10N */
62
	private $l10n;
63
	/** @var IUserSession */
64
	private $userSession;
65
	/** @var bool */
66
	private $isAdmin;
67
	/** @var IUserManager */
68
	private $userManager;
69
	/** @var IGroupManager */
70
	private $groupManager;
71
	/** @var IConfig */
72
	private $config;
73
	/** @var ILogger */
74
	private $log;
75
	/** @var IMailer */
76
	private $mailer;
77
	/** @var bool contains the state of the encryption app */
78
	private $isEncryptionAppEnabled;
79
	/** @var bool contains the state of the admin recovery setting */
80
	private $isRestoreEnabled = false;
81
	/** @var IAppManager */
82
	private $appManager;
83
	/** @var IAvatarManager */
84
	private $avatarManager;
85
	/** @var AccountManager */
86
	private $accountManager;
87
	/** @var ISecureRandom */
88
	private $secureRandom;
89
	/** @var NewUserMailHelper */
90
	private $newUserMailHelper;
91
	/** @var ITimeFactory */
92
	private $timeFactory;
93
	/** @var ICrypto */
94
	private $crypto;
95
	/** @var Manager */
96
	private $keyManager;
97
	/** @var IJobList */
98
	private $jobList;
99
100
	/**
101
	 * @param string $appName
102
	 * @param IRequest $request
103
	 * @param IUserManager $userManager
104
	 * @param IGroupManager $groupManager
105
	 * @param IUserSession $userSession
106
	 * @param IConfig $config
107
	 * @param bool $isAdmin
108
	 * @param IL10N $l10n
109
	 * @param ILogger $log
110
	 * @param IMailer $mailer
111
	 * @param IURLGenerator $urlGenerator
112
	 * @param IAppManager $appManager
113
	 * @param IAvatarManager $avatarManager
114
	 * @param AccountManager $accountManager
115
	 * @param ISecureRandom $secureRandom
116
	 * @param NewUserMailHelper $newUserMailHelper
117
	 * @param ITimeFactory $timeFactory
118
	 * @param ICrypto $crypto
119
	 * @param Manager $keyManager
120
	 * @param IJobList $jobList
121
	 */
122
	public function __construct($appName,
123
								IRequest $request,
124
								IUserManager $userManager,
125
								IGroupManager $groupManager,
126
								IUserSession $userSession,
127
								IConfig $config,
128
								$isAdmin,
129
								IL10N $l10n,
130
								ILogger $log,
131
								IMailer $mailer,
132
								IURLGenerator $urlGenerator,
0 ignored issues
show
Unused Code introduced by
The parameter $urlGenerator is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
133
								IAppManager $appManager,
134
								IAvatarManager $avatarManager,
135
								AccountManager $accountManager,
136
								ISecureRandom $secureRandom,
137
								NewUserMailHelper $newUserMailHelper,
138
								ITimeFactory $timeFactory,
139
								ICrypto $crypto,
140
								Manager $keyManager,
141
								IJobList $jobList) {
142
		parent::__construct($appName, $request);
143
		$this->userManager = $userManager;
144
		$this->groupManager = $groupManager;
145
		$this->userSession = $userSession;
146
		$this->config = $config;
147
		$this->isAdmin = $isAdmin;
148
		$this->l10n = $l10n;
149
		$this->log = $log;
150
		$this->mailer = $mailer;
151
		$this->appManager = $appManager;
152
		$this->avatarManager = $avatarManager;
153
		$this->accountManager = $accountManager;
154
		$this->secureRandom = $secureRandom;
155
		$this->newUserMailHelper = $newUserMailHelper;
156
		$this->timeFactory = $timeFactory;
157
		$this->crypto = $crypto;
158
		$this->keyManager = $keyManager;
159
		$this->jobList = $jobList;
160
161
		// check for encryption state - TODO see formatUserForIndex
162
		$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
163
		if($this->isEncryptionAppEnabled) {
164
			// putting this directly in empty is possible in PHP 5.5+
165
			$result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
166
			$this->isRestoreEnabled = !empty($result);
167
		}
168
	}
169
170
	/**
171
	 * @param IUser $user
172
	 * @param array $userGroups
173
	 * @return array
174
	 */
175
	private function formatUserForIndex(IUser $user, array $userGroups = null) {
176
177
		// TODO: eliminate this encryption specific code below and somehow
178
		// hook in additional user info from other apps
179
180
		// recovery isn't possible if admin or user has it disabled and encryption
181
		// is enabled - so we eliminate the else paths in the conditional tree
182
		// below
183
		$restorePossible = false;
184
185
		if ($this->isEncryptionAppEnabled) {
186
			if ($this->isRestoreEnabled) {
187
				// check for the users recovery setting
188
				$recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
189
				// method call inside empty is possible with PHP 5.5+
190
				$recoveryModeEnabled = !empty($recoveryMode);
191
				if ($recoveryModeEnabled) {
192
					// user also has recovery mode enabled
193
					$restorePossible = true;
194
				}
195
			}
196
		} else {
197
			// recovery is possible if encryption is disabled (plain files are
198
			// available)
199
			$restorePossible = true;
200
		}
201
202
		$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
203
		foreach($subAdminGroups as $key => $subAdminGroup) {
204
			$subAdminGroups[$key] = $subAdminGroup->getGID();
205
		}
206
207
		$displayName = $user->getEMailAddress();
208
		if (is_null($displayName)) {
209
			$displayName = '';
210
		}
211
212
		$avatarAvailable = false;
213
		try {
214
			$avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
215
		} catch (\Exception $e) {
216
			//No avatar yet
217
		}
218
219
		return [
220
			'name' => $user->getUID(),
221
			'displayname' => $user->getDisplayName(),
222
			'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
223
			'subadmin' => $subAdminGroups,
224
			'quota' => $user->getQuota(),
225
			'storageLocation' => $user->getHome(),
226
			'lastLogin' => $user->getLastLogin() * 1000,
227
			'backend' => $user->getBackendClassName(),
228
			'email' => $displayName,
229
			'isRestoreDisabled' => !$restorePossible,
230
			'isAvatarAvailable' => $avatarAvailable,
231
			'isEnabled' => $user->isEnabled(),
232
		];
233
	}
234
235
	/**
236
	 * @param array $userIDs Array with schema [$uid => $displayName]
237
	 * @return IUser[]
238
	 */
239
	private function getUsersForUID(array $userIDs) {
240
		$users = [];
241
		foreach ($userIDs as $uid => $displayName) {
242
			$users[$uid] = $this->userManager->get($uid);
243
		}
244
		return $users;
245
	}
246
247
	/**
248
	 * @NoAdminRequired
249
	 *
250
	 * @param int $offset
251
	 * @param int $limit
252
	 * @param string $gid GID to filter for
253
	 * @param string $pattern Pattern to search for in the username
254
	 * @param string $backend Backend to filter for (class-name)
255
	 * @return DataResponse
256
	 *
257
	 * TODO: Tidy up and write unit tests - code is mainly static method calls
258
	 */
259
	public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
260
		// Remove backends
261
		if(!empty($backend)) {
262
			$activeBackends = $this->userManager->getBackends();
263
			$this->userManager->clearBackends();
264
			foreach($activeBackends as $singleActiveBackend) {
265
				if($backend === get_class($singleActiveBackend)) {
266
					$this->userManager->registerBackend($singleActiveBackend);
267
					break;
268
				}
269
			}
270
		}
271
272
		$users = [];
273
		if ($this->isAdmin) {
274
			if($gid !== '' && $gid !== '_disabledUsers') {
275
				$batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
276
			} else {
277
				$batch = $this->userManager->search($pattern, $limit, $offset);
278
			}
279
280
			foreach ($batch as $user) {
281 View Code Duplication
				if( ($gid !== '_disabledUsers' && $user->isEnabled()) ||
282
					($gid === '_disabledUsers' && !$user->isEnabled())
283
				) {
284
					$users[] = $this->formatUserForIndex($user);
285
				}
286
			}
287
288
		} else {
289
			$subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
290
			// New class returns IGroup[] so convert back
291
			$gids = [];
292
			foreach ($subAdminOfGroups as $group) {
293
				$gids[] = $group->getGID();
294
			}
295
			$subAdminOfGroups = $gids;
296
297
			// Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
298
			if($gid !== '' && $gid !== '_disabledUsers' && !in_array($gid, $subAdminOfGroups)) {
299
				$gid = '';
300
			}
301
302
			// Batch all groups the user is subadmin of when a group is specified
303
			$batch = [];
304
			if($gid === '') {
305
				foreach($subAdminOfGroups as $group) {
306
					$groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
307
308
					foreach($groupUsers as $uid => $displayName) {
309
						$batch[$uid] = $displayName;
310
					}
311
				}
312
			} else {
313
				$batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
314
			}
315
			$batch = $this->getUsersForUID($batch);
316
317
			foreach ($batch as $user) {
318
				// Only add the groups, this user is a subadmin of
319
				$userGroups = array_values(array_intersect(
320
					$this->groupManager->getUserGroupIds($user),
321
					$subAdminOfGroups
322
				));
323 View Code Duplication
				if( ($gid !== '_disabledUsers' && $user->isEnabled()) ||
324
					($gid === '_disabledUsers' && !$user->isEnabled())
325
				) {
326
					$users[] = $this->formatUserForIndex($user, $userGroups);
327
				}
328
			}
329
		}
330
331
		return new DataResponse($users);
332
	}
333
334
	/**
335
	 * @NoAdminRequired
336
	 * @PasswordConfirmationRequired
337
	 *
338
	 * @param string $username
339
	 * @param string $password
340
	 * @param array $groups
341
	 * @param string $email
342
	 * @return DataResponse
343
	 */
344
	public function create($username, $password, array $groups=[], $email='') {
345
		if($email !== '' && !$this->mailer->validateMailAddress($email)) {
346
			return new DataResponse(
347
				[
348
					'message' => (string)$this->l10n->t('Invalid mail address')
349
				],
350
				Http::STATUS_UNPROCESSABLE_ENTITY
351
			);
352
		}
353
354
		$currentUser = $this->userSession->getUser();
355
356
		if (!$this->isAdmin) {
357
			if (!empty($groups)) {
358
				foreach ($groups as $key => $group) {
359
					$groupObject = $this->groupManager->get($group);
360
					if($groupObject === null) {
361
						unset($groups[$key]);
362
						continue;
363
					}
364
365
					if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
366
						unset($groups[$key]);
367
					}
368
				}
369
			}
370
371
			if (empty($groups)) {
372
				return new DataResponse(
373
					[
374
						'message' => $this->l10n->t('No valid group selected'),
375
					],
376
					Http::STATUS_FORBIDDEN
377
				);
378
			}
379
		}
380
381
		if ($this->userManager->userExists($username)) {
382
			return new DataResponse(
383
				[
384
					'message' => (string)$this->l10n->t('A user with that name already exists.')
385
				],
386
				Http::STATUS_CONFLICT
387
			);
388
		}
389
390
		$generatePasswordResetToken = false;
391
		if ($password === '') {
392
			if ($email === '') {
393
				return new DataResponse(
394
					[
395
						'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
396
					],
397
					Http::STATUS_UNPROCESSABLE_ENTITY
398
				);
399
			}
400
401
			$password = $this->secureRandom->generate(32);
402
			$generatePasswordResetToken = true;
403
		}
404
405
		try {
406
			$user = $this->userManager->createUser($username, $password);
407
		} catch (\Exception $exception) {
408
			$message = $exception->getMessage();
409
			if (!$message) {
410
				$message = $this->l10n->t('Unable to create user.');
411
			}
412
			return new DataResponse(
413
				[
414
					'message' => (string) $message,
415
				],
416
				Http::STATUS_FORBIDDEN
417
			);
418
		}
419
420
		if($user instanceof IUser) {
421
			if($groups !== null) {
422
				foreach($groups as $groupName) {
423
					$group = $this->groupManager->get($groupName);
424
425
					if(empty($group)) {
426
						$group = $this->groupManager->createGroup($groupName);
427
					}
428
					$group->addUser($user);
429
				}
430
			}
431
			/**
432
			 * Send new user mail only if a mail is set
433
			 */
434
			if($email !== '') {
435
				$user->setEMailAddress($email);
436
				try {
437
					$emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
438
					$this->newUserMailHelper->sendMail($user, $emailTemplate);
439
				} catch(\Exception $e) {
440
					$this->log->error("Can't send new user mail to $email: " . $e->getMessage(), ['app' => 'settings']);
441
				}
442
			}
443
			// fetch users groups
444
			$userGroups = $this->groupManager->getUserGroupIds($user);
445
446
			return new DataResponse(
447
				$this->formatUserForIndex($user, $userGroups),
448
				Http::STATUS_CREATED
449
			);
450
		}
451
452
		return new DataResponse(
453
			[
454
				'message' => (string) $this->l10n->t('Unable to create user.')
455
			],
456
			Http::STATUS_FORBIDDEN
457
		);
458
459
	}
460
461
	/**
462
	 * @NoAdminRequired
463
	 * @PasswordConfirmationRequired
464
	 *
465
	 * @param string $id
466
	 * @return DataResponse
467
	 */
468
	public function destroy($id) {
469
		$userId = $this->userSession->getUser()->getUID();
470
		$user = $this->userManager->get($id);
471
472
		if($userId === $id) {
473
			return new DataResponse(
474
				[
475
					'status' => 'error',
476
					'data' => [
477
						'message' => (string) $this->l10n->t('Unable to delete user.')
478
					]
479
				],
480
				Http::STATUS_FORBIDDEN
481
			);
482
		}
483
484 View Code Duplication
		if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
485
			return new DataResponse(
486
				[
487
					'status' => 'error',
488
					'data' => [
489
						'message' => (string)$this->l10n->t('Authentication error')
490
					]
491
				],
492
				Http::STATUS_FORBIDDEN
493
			);
494
		}
495
496
		if($user) {
497
			if($user->delete()) {
498
				return new DataResponse(
499
					[
500
						'status' => 'success',
501
						'data' => [
502
							'username' => $id
503
						]
504
					],
505
					Http::STATUS_NO_CONTENT
506
				);
507
			}
508
		}
509
510
		return new DataResponse(
511
			[
512
				'status' => 'error',
513
				'data' => [
514
					'message' => (string)$this->l10n->t('Unable to delete user.')
515
				]
516
			],
517
			Http::STATUS_FORBIDDEN
518
		);
519
	}
520
521
	/**
522
	 * @NoAdminRequired
523
	 *
524
	 * @param string $id
525
	 * @param int $enabled
526
	 * @return DataResponse
527
	 */
528
	public function setEnabled($id, $enabled) {
529
		$enabled = (bool)$enabled;
530
		if($enabled) {
531
			$errorMsgGeneral = (string) $this->l10n->t('Error while enabling user.');
532
		} else {
533
			$errorMsgGeneral = (string) $this->l10n->t('Error while disabling user.');
534
		}
535
536
		$userId = $this->userSession->getUser()->getUID();
537
		$user = $this->userManager->get($id);
538
539 View Code Duplication
		if ($userId === $id) {
540
			return new DataResponse(
541
				[
542
					'status' => 'error',
543
					'data' => [
544
						'message' => $errorMsgGeneral
545
					]
546
				], Http::STATUS_FORBIDDEN
547
			);
548
		}
549
550
		if($user) {
551 View Code Duplication
			if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
552
				return new DataResponse(
553
					[
554
						'status' => 'error',
555
						'data' => [
556
							'message' => (string) $this->l10n->t('Authentication error')
557
						]
558
					],
559
					Http::STATUS_FORBIDDEN
560
				);
561
			}
562
563
			$user->setEnabled($enabled);
564
			return new DataResponse(
565
				[
566
					'status' => 'success',
567
					'data' => [
568
						'username' => $id,
569
						'enabled' => $enabled
570
					]
571
				]
572
			);
573 View Code Duplication
		} else {
574
			return new DataResponse(
575
				[
576
					'status' => 'error',
577
					'data' => [
578
						'message' => $errorMsgGeneral
579
					]
580
				],
581
				Http::STATUS_FORBIDDEN
582
			);
583
		}
584
585
	}
586
587
	/**
588
	 * Set the mail address of a user
589
	 *
590
	 * @NoAdminRequired
591
	 * @NoSubadminRequired
592
	 * @PasswordConfirmationRequired
593
	 *
594
	 * @param string $account
595
	 * @param bool $onlyVerificationCode only return verification code without updating the data
596
	 * @return DataResponse
597
	 */
598
	public function getVerificationCode($account, $onlyVerificationCode) {
599
600
		$user = $this->userSession->getUser();
601
602
		if ($user === null) {
603
			return new DataResponse([], Http::STATUS_BAD_REQUEST);
604
		}
605
606
		$accountData = $this->accountManager->getUser($user);
607
		$cloudId = $user->getCloudId();
608
		$message = "Use my Federated Cloud ID to share with me: " . $cloudId;
609
		$signature = $this->signMessage($user, $message);
610
611
		$code = $message . ' ' . $signature;
612
		$codeMd5 = $message . ' ' . md5($signature);
613
614
		switch ($account) {
615 View Code Duplication
			case 'verify-twitter':
616
				$accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
617
				$msg = $this->l10n->t('In order to verify your Twitter account, post the following tweet on Twitter (please make sure to post it without any line breaks):');
618
				$code = $codeMd5;
619
				$type = AccountManager::PROPERTY_TWITTER;
620
				$data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
621
				$accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
622
				break;
623 View Code Duplication
			case 'verify-website':
624
				$accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
625
				$msg = $this->l10n->t('In order to verify your Website, store the following content in your web-root at \'.well-known/CloudIdVerificationCode.txt\' (please make sure that the complete text is in one line):');
626
				$type = AccountManager::PROPERTY_WEBSITE;
627
				$data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
628
				$accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
629
				break;
630
			default:
631
				return new DataResponse([], Http::STATUS_BAD_REQUEST);
632
		}
633
634
		if ($onlyVerificationCode === false) {
635
			$this->accountManager->updateUser($user, $accountData);
636
637
			$this->jobList->add('OC\Settings\BackgroundJobs\VerifyUserData',
638
				[
639
					'verificationCode' => $code,
640
					'data' => $data,
641
					'type' => $type,
642
					'uid' => $user->getUID(),
643
					'try' => 0,
644
					'lastRun' => $this->getCurrentTime()
645
				]
646
			);
647
		}
648
649
		return new DataResponse(['msg' => $msg, 'code' => $code]);
650
	}
651
652
	/**
653
	 * get current timestamp
654
	 *
655
	 * @return int
656
	 */
657
	protected function getCurrentTime() {
658
		return time();
659
	}
660
661
	/**
662
	 * sign message with users private key
663
	 *
664
	 * @param IUser $user
665
	 * @param string $message
666
	 *
667
	 * @return string base64 encoded signature
668
	 */
669
	protected function signMessage(IUser $user, $message) {
670
		$privateKey = $this->keyManager->getKey($user)->getPrivate();
671
		openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
672
		$signatureBase64 = base64_encode($signature);
673
674
		return $signatureBase64;
675
	}
676
677
	/**
678
	 * @NoAdminRequired
679
	 * @NoSubadminRequired
680
	 * @PasswordConfirmationRequired
681
	 *
682
	 * @param string $avatarScope
683
	 * @param string $displayname
684
	 * @param string $displaynameScope
685
	 * @param string $phone
686
	 * @param string $phoneScope
687
	 * @param string $email
688
	 * @param string $emailScope
689
	 * @param string $website
690
	 * @param string $websiteScope
691
	 * @param string $address
692
	 * @param string $addressScope
693
	 * @param string $twitter
694
	 * @param string $twitterScope
695
	 * @return DataResponse
696
	 */
697
	public function setUserSettings($avatarScope,
698
									$displayname,
699
									$displaynameScope,
700
									$phone,
701
									$phoneScope,
702
									$email,
703
									$emailScope,
704
									$website,
705
									$websiteScope,
706
									$address,
707
									$addressScope,
708
									$twitter,
709
									$twitterScope
710
	) {
711
712
		if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
713
			return new DataResponse(
714
				[
715
					'status' => 'error',
716
					'data' => [
717
						'message' => (string) $this->l10n->t('Invalid mail address')
718
					]
719
				],
720
				Http::STATUS_UNPROCESSABLE_ENTITY
721
			);
722
		}
723
724
		$user = $this->userSession->getUser();
725
726
		$data = $this->accountManager->getUser($user);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 724 can be null; however, OC\Accounts\AccountManager::getUser() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
727
728
		$data[AccountManager::PROPERTY_AVATAR] =  ['scope' => $avatarScope];
729
		if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
730
			$data[AccountManager::PROPERTY_DISPLAYNAME] = ['value' => $displayname, 'scope' => $displaynameScope];
731
			$data[AccountManager::PROPERTY_EMAIL] = ['value' => $email, 'scope' => $emailScope];
732
		}
733
734
		if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
735
			$federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application();
736
			$shareProvider = $federatedFileSharing->getFederatedShareProvider();
737
			if ($shareProvider->isLookupServerUploadEnabled()) {
738
				$data[AccountManager::PROPERTY_WEBSITE] = ['value' => $website, 'scope' => $websiteScope];
739
				$data[AccountManager::PROPERTY_ADDRESS] = ['value' => $address, 'scope' => $addressScope];
740
				$data[AccountManager::PROPERTY_PHONE] = ['value' => $phone, 'scope' => $phoneScope];
741
				$data[AccountManager::PROPERTY_TWITTER] = ['value' => $twitter, 'scope' => $twitterScope];
742
			}
743
		}
744
745
		try {
746
			$this->saveUserSettings($user, $data);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 724 can be null; however, OC\Settings\Controller\U...ler::saveUserSettings() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
747
			return new DataResponse(
748
				[
749
					'status' => 'success',
750
					'data' => [
751
						'userId' => $user->getUID(),
752
						'avatarScope' => $data[AccountManager::PROPERTY_AVATAR]['scope'],
753
						'displayname' => $data[AccountManager::PROPERTY_DISPLAYNAME]['value'],
754
						'displaynameScope' => $data[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
755
						'email' => $data[AccountManager::PROPERTY_EMAIL]['value'],
756
						'emailScope' => $data[AccountManager::PROPERTY_EMAIL]['scope'],
757
						'website' => $data[AccountManager::PROPERTY_WEBSITE]['value'],
758
						'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
759
						'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
760
						'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
761
						'message' => (string) $this->l10n->t('Settings saved')
762
					]
763
				],
764
				Http::STATUS_OK
765
			);
766
		} catch (ForbiddenException $e) {
767
			return new DataResponse([
768
				'status' => 'error',
769
				'data' => [
770
					'message' => $e->getMessage()
771
				],
772
			]);
773
		}
774
775
	}
776
777
778
	/**
779
	 * update account manager with new user data
780
	 *
781
	 * @param IUser $user
782
	 * @param array $data
783
	 * @throws ForbiddenException
784
	 */
785
	protected function saveUserSettings(IUser $user, $data) {
786
787
		// keep the user back-end up-to-date with the latest display name and email
788
		// address
789
		$oldDisplayName = $user->getDisplayName();
790
		$oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
791 View Code Duplication
		if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
792
			&& $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
793
		) {
794
			$result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
795
			if ($result === false) {
796
				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
797
			}
798
		}
799
800
		$oldEmailAddress = $user->getEMailAddress();
801
		$oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
802 View Code Duplication
		if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
803
			&& $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
804
		) {
805
			// this is the only permission a backend provides and is also used
806
			// for the permission of setting a email address
807
			if (!$user->canChangeDisplayName()) {
808
				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
809
			}
810
			$user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
811
		}
812
813
		$this->accountManager->updateUser($user, $data);
814
	}
815
816
	/**
817
	 * Count all unique users visible for the current admin/subadmin.
818
	 *
819
	 * @NoAdminRequired
820
	 *
821
	 * @return DataResponse
822
	 */
823
	public function stats() {
824
		$userCount = 0;
825
		if ($this->isAdmin) {
826
			$countByBackend = $this->userManager->countUsers();
827
828
			if (!empty($countByBackend)) {
829
				foreach ($countByBackend as $count) {
830
					$userCount += $count;
831
				}
832
			}
833
		} else {
834
			$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
835
836
			$uniqueUsers = [];
837
			foreach ($groups as $group) {
838
				foreach($group->getUsers() as $uid => $displayName) {
839
					$uniqueUsers[$uid] = true;
840
				}
841
			}
842
843
			$userCount = count($uniqueUsers);
844
		}
845
846
		return new DataResponse(
847
			[
848
				'totalUsers' => $userCount
849
			]
850
		);
851
	}
852
853
854
	/**
855
	 * Set the displayName of a user
856
	 *
857
	 * @NoAdminRequired
858
	 * @NoSubadminRequired
859
	 * @PasswordConfirmationRequired
860
	 * @todo merge into saveUserSettings
861
	 *
862
	 * @param string $username
863
	 * @param string $displayName
864
	 * @return DataResponse
865
	 */
866
	public function setDisplayName($username, $displayName) {
867
		$currentUser = $this->userSession->getUser();
868
		$user = $this->userManager->get($username);
869
870
		if ($user === null ||
871
			!$user->canChangeDisplayName() ||
872
			(
873
				!$this->groupManager->isAdmin($currentUser->getUID()) &&
874
				!$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
875
				$currentUser->getUID() !== $username
876
877
			)
878
		) {
879
			return new DataResponse([
880
				'status' => 'error',
881
				'data' => [
882
					'message' => $this->l10n->t('Authentication error'),
883
				],
884
			]);
885
		}
886
887
		$userData = $this->accountManager->getUser($user);
888
		$userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
889
890
891
		try {
892
			$this->saveUserSettings($user, $userData);
893
			return new DataResponse([
894
				'status' => 'success',
895
				'data' => [
896
					'message' => $this->l10n->t('Your full name has been changed.'),
897
					'username' => $username,
898
					'displayName' => $displayName,
899
				],
900
			]);
901
		} catch (ForbiddenException $e) {
902
			return new DataResponse([
903
				'status' => 'error',
904
				'data' => [
905
					'message' => $e->getMessage(),
906
					'displayName' => $user->getDisplayName(),
907
				],
908
			]);
909
		}
910
	}
911
912
	/**
913
	 * Set the mail address of a user
914
	 *
915
	 * @NoAdminRequired
916
	 * @NoSubadminRequired
917
	 * @PasswordConfirmationRequired
918
	 *
919
	 * @param string $id
920
	 * @param string $mailAddress
921
	 * @return DataResponse
922
	 */
923
	public function setEMailAddress($id, $mailAddress) {
924
		$user = $this->userManager->get($id);
925
		if (!$this->isAdmin
926
			&& !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
927
		) {
928
			return new DataResponse(
929
				[
930
					'status' => 'error',
931
					'data' => [
932
						'message' => (string) $this->l10n->t('Forbidden')
933
					]
934
				],
935
				Http::STATUS_FORBIDDEN
936
			);
937
		}
938
939
		if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
940
			return new DataResponse(
941
				[
942
					'status' => 'error',
943
					'data' => [
944
						'message' => (string) $this->l10n->t('Invalid mail address')
945
					]
946
				],
947
				Http::STATUS_UNPROCESSABLE_ENTITY
948
			);
949
		}
950
951
		if (!$user) {
952
			return new DataResponse(
953
				[
954
					'status' => 'error',
955
					'data' => [
956
						'message' => (string) $this->l10n->t('Invalid user')
957
					]
958
				],
959
				Http::STATUS_UNPROCESSABLE_ENTITY
960
			);
961
		}
962
		// this is the only permission a backend provides and is also used
963
		// for the permission of setting a email address
964
		if (!$user->canChangeDisplayName()) {
965
			return new DataResponse(
966
				[
967
					'status' => 'error',
968
					'data' => [
969
						'message' => (string) $this->l10n->t('Unable to change mail address')
970
					]
971
				],
972
				Http::STATUS_FORBIDDEN
973
			);
974
		}
975
976
		$userData = $this->accountManager->getUser($user);
977
		$userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
978
979
		try {
980
			$this->saveUserSettings($user, $userData);
981
			return new DataResponse(
982
				[
983
					'status' => 'success',
984
					'data' => [
985
						'username' => $id,
986
						'mailAddress' => $mailAddress,
987
						'message' => (string) $this->l10n->t('Email saved')
988
					]
989
				],
990
				Http::STATUS_OK
991
			);
992
		} catch (ForbiddenException $e) {
993
			return new DataResponse([
994
				'status' => 'error',
995
				'data' => [
996
					'message' => $e->getMessage()
997
				],
998
			]);
999
		}
1000
	}
1001
1002
}
1003