Completed
Push — master ( 130780...854dfe )
by Morris
26s
created

UsersController::create()   D

Complexity

Conditions 20
Paths 75

Size

Total Lines 116
Code Lines 61

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 20
eloc 61
nc 75
nop 4
dl 0
loc 116
rs 4.7294
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 IAvatarManager */
82
	private $avatarManager;
83
	/** @var AccountManager */
84
	private $accountManager;
85
	/** @var ISecureRandom */
86
	private $secureRandom;
87
	/** @var NewUserMailHelper */
88
	private $newUserMailHelper;
89
	/** @var ITimeFactory */
90
	private $timeFactory;
91
	/** @var ICrypto */
92
	private $crypto;
93
	/** @var Manager */
94
	private $keyManager;
95
	/** @var IJobList */
96
	private $jobList;
97
98
	/**
99
	 * @param string $appName
100
	 * @param IRequest $request
101
	 * @param IUserManager $userManager
102
	 * @param IGroupManager $groupManager
103
	 * @param IUserSession $userSession
104
	 * @param IConfig $config
105
	 * @param bool $isAdmin
106
	 * @param IL10N $l10n
107
	 * @param ILogger $log
108
	 * @param IMailer $mailer
109
	 * @param IURLGenerator $urlGenerator
110
	 * @param IAppManager $appManager
111
	 * @param IAvatarManager $avatarManager
112
	 * @param AccountManager $accountManager
113
	 * @param ISecureRandom $secureRandom
114
	 * @param NewUserMailHelper $newUserMailHelper
115
	 * @param ITimeFactory $timeFactory
116
	 * @param ICrypto $crypto
117
	 * @param Manager $keyManager
118
	 * @param IJobList $jobList
119
	 */
120
	public function __construct($appName,
121
								IRequest $request,
122
								IUserManager $userManager,
123
								IGroupManager $groupManager,
124
								IUserSession $userSession,
125
								IConfig $config,
126
								$isAdmin,
127
								IL10N $l10n,
128
								ILogger $log,
129
								IMailer $mailer,
130
								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...
131
								IAppManager $appManager,
132
								IAvatarManager $avatarManager,
133
								AccountManager $accountManager,
134
								ISecureRandom $secureRandom,
135
								NewUserMailHelper $newUserMailHelper,
136
								ITimeFactory $timeFactory,
137
								ICrypto $crypto,
138
								Manager $keyManager,
139
								IJobList $jobList) {
140
		parent::__construct($appName, $request);
141
		$this->userManager = $userManager;
142
		$this->groupManager = $groupManager;
143
		$this->userSession = $userSession;
144
		$this->config = $config;
145
		$this->isAdmin = $isAdmin;
146
		$this->l10n = $l10n;
147
		$this->log = $log;
148
		$this->mailer = $mailer;
149
		$this->avatarManager = $avatarManager;
150
		$this->accountManager = $accountManager;
151
		$this->secureRandom = $secureRandom;
152
		$this->newUserMailHelper = $newUserMailHelper;
153
		$this->timeFactory = $timeFactory;
154
		$this->crypto = $crypto;
155
		$this->keyManager = $keyManager;
156
		$this->jobList = $jobList;
157
158
		// check for encryption state - TODO see formatUserForIndex
159
		$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
160
		if($this->isEncryptionAppEnabled) {
161
			// putting this directly in empty is possible in PHP 5.5+
162
			$result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
163
			$this->isRestoreEnabled = !empty($result);
164
		}
165
	}
166
167
	/**
168
	 * @param IUser $user
169
	 * @param array $userGroups
170
	 * @return array
171
	 */
172
	private function formatUserForIndex(IUser $user, array $userGroups = null) {
173
174
		// TODO: eliminate this encryption specific code below and somehow
175
		// hook in additional user info from other apps
176
177
		// recovery isn't possible if admin or user has it disabled and encryption
178
		// is enabled - so we eliminate the else paths in the conditional tree
179
		// below
180
		$restorePossible = false;
181
182
		if ($this->isEncryptionAppEnabled) {
183
			if ($this->isRestoreEnabled) {
184
				// check for the users recovery setting
185
				$recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
186
				// method call inside empty is possible with PHP 5.5+
187
				$recoveryModeEnabled = !empty($recoveryMode);
188
				if ($recoveryModeEnabled) {
189
					// user also has recovery mode enabled
190
					$restorePossible = true;
191
				}
192
			}
193
		} else {
194
			// recovery is possible if encryption is disabled (plain files are
195
			// available)
196
			$restorePossible = true;
197
		}
198
199
		$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
200
		foreach($subAdminGroups as $key => $subAdminGroup) {
201
			$subAdminGroups[$key] = $subAdminGroup->getGID();
202
		}
203
204
		$displayName = $user->getEMailAddress();
205
		if (is_null($displayName)) {
206
			$displayName = '';
207
		}
208
209
		$avatarAvailable = false;
210
		try {
211
			$avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
212
		} catch (\Exception $e) {
213
			//No avatar yet
214
		}
215
216
		return [
217
			'name' => $user->getUID(),
218
			'displayname' => $user->getDisplayName(),
219
			'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
220
			'subadmin' => $subAdminGroups,
221
			'quota' => $user->getQuota(),
222
			'storageLocation' => $user->getHome(),
223
			'lastLogin' => $user->getLastLogin() * 1000,
224
			'backend' => $user->getBackendClassName(),
225
			'email' => $displayName,
226
			'isRestoreDisabled' => !$restorePossible,
227
			'isAvatarAvailable' => $avatarAvailable,
228
			'isEnabled' => $user->isEnabled(),
229
		];
230
	}
231
232
	/**
233
	 * @param array $userIDs Array with schema [$uid => $displayName]
234
	 * @return IUser[]
235
	 */
236
	private function getUsersForUID(array $userIDs) {
237
		$users = [];
238
		foreach ($userIDs as $uid => $displayName) {
239
			$users[$uid] = $this->userManager->get($uid);
240
		}
241
		return $users;
242
	}
243
244
	/**
245
	 * @NoAdminRequired
246
	 *
247
	 * @param int $offset
248
	 * @param int $limit
249
	 * @param string $gid GID to filter for
250
	 * @param string $pattern Pattern to search for in the username
251
	 * @param string $backend Backend to filter for (class-name)
252
	 * @return DataResponse
253
	 *
254
	 * TODO: Tidy up and write unit tests - code is mainly static method calls
255
	 */
256
	public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
257
		// Remove backends
258
		if(!empty($backend)) {
259
			$activeBackends = $this->userManager->getBackends();
260
			$this->userManager->clearBackends();
261
			foreach($activeBackends as $singleActiveBackend) {
262
				if($backend === get_class($singleActiveBackend)) {
263
					$this->userManager->registerBackend($singleActiveBackend);
264
					break;
265
				}
266
			}
267
		}
268
269
		$users = [];
270
		if ($this->isAdmin) {
271
			if($gid !== '' && $gid !== '_disabledUsers') {
272
				$batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
273
			} else {
274
				$batch = $this->userManager->search($pattern, $limit, $offset);
275
			}
276
277
			foreach ($batch as $user) {
278 View Code Duplication
				if( ($gid !== '_disabledUsers' && $user->isEnabled()) ||
279
					($gid === '_disabledUsers' && !$user->isEnabled())
280
				) {
281
					$users[] = $this->formatUserForIndex($user);
282
				}
283
			}
284
285
		} else {
286
			$subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
287
			// New class returns IGroup[] so convert back
288
			$gids = [];
289
			foreach ($subAdminOfGroups as $group) {
290
				$gids[] = $group->getGID();
291
			}
292
			$subAdminOfGroups = $gids;
293
294
			// Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
295
			if($gid !== '' && $gid !== '_disabledUsers' && !in_array($gid, $subAdminOfGroups)) {
296
				$gid = '';
297
			}
298
299
			// Batch all groups the user is subadmin of when a group is specified
300
			$batch = [];
301
			if($gid === '') {
302
				foreach($subAdminOfGroups as $group) {
303
					$groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
304
305
					foreach($groupUsers as $uid => $displayName) {
306
						$batch[$uid] = $displayName;
307
					}
308
				}
309
			} else {
310
				$batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
311
			}
312
			$batch = $this->getUsersForUID($batch);
313
314
			foreach ($batch as $user) {
315
				// Only add the groups, this user is a subadmin of
316
				$userGroups = array_values(array_intersect(
317
					$this->groupManager->getUserGroupIds($user),
318
					$subAdminOfGroups
319
				));
320 View Code Duplication
				if( ($gid !== '_disabledUsers' && $user->isEnabled()) ||
321
					($gid === '_disabledUsers' && !$user->isEnabled())
322
				) {
323
					$users[] = $this->formatUserForIndex($user, $userGroups);
324
				}
325
			}
326
		}
327
328
		return new DataResponse($users);
329
	}
330
331
	/**
332
	 * @NoAdminRequired
333
	 * @PasswordConfirmationRequired
334
	 *
335
	 * @param string $username
336
	 * @param string $password
337
	 * @param array $groups
338
	 * @param string $email
339
	 * @return DataResponse
340
	 */
341
	public function create($username, $password, array $groups=[], $email='') {
342
		if($email !== '' && !$this->mailer->validateMailAddress($email)) {
343
			return new DataResponse(
344
				[
345
					'message' => (string)$this->l10n->t('Invalid mail address')
346
				],
347
				Http::STATUS_UNPROCESSABLE_ENTITY
348
			);
349
		}
350
351
		$currentUser = $this->userSession->getUser();
352
353
		if (!$this->isAdmin) {
354
			if (!empty($groups)) {
355
				foreach ($groups as $key => $group) {
356
					$groupObject = $this->groupManager->get($group);
357
					if($groupObject === null) {
358
						unset($groups[$key]);
359
						continue;
360
					}
361
362
					if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
363
						unset($groups[$key]);
364
					}
365
				}
366
			}
367
368
			if (empty($groups)) {
369
				return new DataResponse(
370
					[
371
						'message' => $this->l10n->t('No valid group selected'),
372
					],
373
					Http::STATUS_FORBIDDEN
374
				);
375
			}
376
		}
377
378
		if ($this->userManager->userExists($username)) {
379
			return new DataResponse(
380
				[
381
					'message' => (string)$this->l10n->t('A user with that name already exists.')
382
				],
383
				Http::STATUS_CONFLICT
384
			);
385
		}
386
387
		$generatePasswordResetToken = false;
388
		if ($password === '') {
389
			if ($email === '') {
390
				return new DataResponse(
391
					[
392
						'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
393
					],
394
					Http::STATUS_UNPROCESSABLE_ENTITY
395
				);
396
			}
397
398
			$password = $this->secureRandom->generate(32);
399
			$generatePasswordResetToken = true;
400
		}
401
402
		try {
403
			$user = $this->userManager->createUser($username, $password);
404
		} catch (\Exception $exception) {
405
			$message = $exception->getMessage();
406
			if (!$message) {
407
				$message = $this->l10n->t('Unable to create user.');
408
			}
409
			return new DataResponse(
410
				[
411
					'message' => (string) $message,
412
				],
413
				Http::STATUS_FORBIDDEN
414
			);
415
		}
416
417
		if($user instanceof IUser) {
418
			if($groups !== null) {
419
				foreach($groups as $groupName) {
420
					$group = $this->groupManager->get($groupName);
421
422
					if(empty($group)) {
423
						$group = $this->groupManager->createGroup($groupName);
424
					}
425
					$group->addUser($user);
426
				}
427
			}
428
			/**
429
			 * Send new user mail only if a mail is set
430
			 */
431
			if($email !== '') {
432
				$user->setEMailAddress($email);
433
				try {
434
					$emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
435
					$this->newUserMailHelper->sendMail($user, $emailTemplate);
436
				} catch(\Exception $e) {
437
					$this->log->error("Can't send new user mail to $email: " . $e->getMessage(), ['app' => 'settings']);
438
				}
439
			}
440
			// fetch users groups
441
			$userGroups = $this->groupManager->getUserGroupIds($user);
442
443
			return new DataResponse(
444
				$this->formatUserForIndex($user, $userGroups),
445
				Http::STATUS_CREATED
446
			);
447
		}
448
449
		return new DataResponse(
450
			[
451
				'message' => (string) $this->l10n->t('Unable to create user.')
452
			],
453
			Http::STATUS_FORBIDDEN
454
		);
455
456
	}
457
458
	/**
459
	 * @NoAdminRequired
460
	 * @PasswordConfirmationRequired
461
	 *
462
	 * @param string $id
463
	 * @return DataResponse
464
	 */
465
	public function destroy($id) {
466
		$userId = $this->userSession->getUser()->getUID();
467
		$user = $this->userManager->get($id);
468
469
		if($userId === $id) {
470
			return new DataResponse(
471
				[
472
					'status' => 'error',
473
					'data' => [
474
						'message' => (string) $this->l10n->t('Unable to delete user.')
475
					]
476
				],
477
				Http::STATUS_FORBIDDEN
478
			);
479
		}
480
481 View Code Duplication
		if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
482
			return new DataResponse(
483
				[
484
					'status' => 'error',
485
					'data' => [
486
						'message' => (string)$this->l10n->t('Authentication error')
487
					]
488
				],
489
				Http::STATUS_FORBIDDEN
490
			);
491
		}
492
493
		if($user) {
494
			if($user->delete()) {
495
				return new DataResponse(
496
					[
497
						'status' => 'success',
498
						'data' => [
499
							'username' => $id
500
						]
501
					],
502
					Http::STATUS_NO_CONTENT
503
				);
504
			}
505
		}
506
507
		return new DataResponse(
508
			[
509
				'status' => 'error',
510
				'data' => [
511
					'message' => (string)$this->l10n->t('Unable to delete user.')
512
				]
513
			],
514
			Http::STATUS_FORBIDDEN
515
		);
516
	}
517
518
	/**
519
	 * @NoAdminRequired
520
	 *
521
	 * @param string $id
522
	 * @param int $enabled
523
	 * @return DataResponse
524
	 */
525
	public function setEnabled($id, $enabled) {
526
		$enabled = (bool)$enabled;
527
		if($enabled) {
528
			$errorMsgGeneral = (string) $this->l10n->t('Error while enabling user.');
529
		} else {
530
			$errorMsgGeneral = (string) $this->l10n->t('Error while disabling user.');
531
		}
532
533
		$userId = $this->userSession->getUser()->getUID();
534
		$user = $this->userManager->get($id);
535
536 View Code Duplication
		if ($userId === $id) {
537
			return new DataResponse(
538
				[
539
					'status' => 'error',
540
					'data' => [
541
						'message' => $errorMsgGeneral
542
					]
543
				], Http::STATUS_FORBIDDEN
544
			);
545
		}
546
547
		if($user) {
548 View Code Duplication
			if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
549
				return new DataResponse(
550
					[
551
						'status' => 'error',
552
						'data' => [
553
							'message' => (string) $this->l10n->t('Authentication error')
554
						]
555
					],
556
					Http::STATUS_FORBIDDEN
557
				);
558
			}
559
560
			$user->setEnabled($enabled);
561
			return new DataResponse(
562
				[
563
					'status' => 'success',
564
					'data' => [
565
						'username' => $id,
566
						'enabled' => $enabled
567
					]
568
				]
569
			);
570 View Code Duplication
		} else {
571
			return new DataResponse(
572
				[
573
					'status' => 'error',
574
					'data' => [
575
						'message' => $errorMsgGeneral
576
					]
577
				],
578
				Http::STATUS_FORBIDDEN
579
			);
580
		}
581
582
	}
583
584
	/**
585
	 * Set the mail address of a user
586
	 *
587
	 * @NoAdminRequired
588
	 * @NoSubadminRequired
589
	 * @PasswordConfirmationRequired
590
	 *
591
	 * @param string $account
592
	 * @param bool $onlyVerificationCode only return verification code without updating the data
593
	 * @return DataResponse
594
	 */
595
	public function getVerificationCode($account, $onlyVerificationCode) {
596
597
		$user = $this->userSession->getUser();
598
599
		if ($user === null) {
600
			return new DataResponse([], Http::STATUS_BAD_REQUEST);
601
		}
602
603
		$accountData = $this->accountManager->getUser($user);
604
		$cloudId = $user->getCloudId();
605
		$message = "Use my Federated Cloud ID to share with me: " . $cloudId;
606
		$signature = $this->signMessage($user, $message);
607
608
		$code = $message . ' ' . $signature;
609
		$codeMd5 = $message . ' ' . md5($signature);
610
611
		switch ($account) {
612 View Code Duplication
			case 'verify-twitter':
613
				$accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
614
				$msg = $this->l10n->t('In order to verify your Twitter account post following tweet on Twitter (please make sure to post it without any line breaks):');
615
				$code = $codeMd5;
616
				$type = AccountManager::PROPERTY_TWITTER;
617
				$data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
618
				$accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
619
				break;
620 View Code Duplication
			case 'verify-website':
621
				$accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
622
				$msg = $this->l10n->t('In order to verify your Website store following content in your web-root at \'.well-known/CloudIdVerificationCode.txt\' (please make sure that the complete text is in one line):');
623
				$type = AccountManager::PROPERTY_WEBSITE;
624
				$data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
625
				$accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
626
				break;
627
			default:
628
				return new DataResponse([], Http::STATUS_BAD_REQUEST);
629
		}
630
631
		if ($onlyVerificationCode === false) {
632
			$this->accountManager->updateUser($user, $accountData);
633
634
			$this->jobList->add('OC\Settings\BackgroundJobs\VerifyUserData',
635
				[
636
					'verificationCode' => $code,
637
					'data' => $data,
638
					'type' => $type,
639
					'uid' => $user->getUID(),
640
					'try' => 0,
641
					'lastRun' => $this->getCurrentTime()
642
				]
643
			);
644
		}
645
646
		return new DataResponse(['msg' => $msg, 'code' => $code]);
647
	}
648
649
	/**
650
	 * get current timestamp
651
	 *
652
	 * @return int
653
	 */
654
	protected function getCurrentTime() {
655
		return time();
656
	}
657
658
	/**
659
	 * sign message with users private key
660
	 *
661
	 * @param IUser $user
662
	 * @param string $message
663
	 *
664
	 * @return string base64 encoded signature
665
	 */
666
	protected function signMessage(IUser $user, $message) {
667
		$privateKey = $this->keyManager->getKey($user)->getPrivate();
668
		openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
669
		$signatureBase64 = base64_encode($signature);
670
671
		return $signatureBase64;
672
	}
673
674
	/**
675
	 * @NoAdminRequired
676
	 * @NoSubadminRequired
677
	 * @PasswordConfirmationRequired
678
	 *
679
	 * @param string $avatarScope
680
	 * @param string $displayname
681
	 * @param string $displaynameScope
682
	 * @param string $phone
683
	 * @param string $phoneScope
684
	 * @param string $email
685
	 * @param string $emailScope
686
	 * @param string $website
687
	 * @param string $websiteScope
688
	 * @param string $address
689
	 * @param string $addressScope
690
	 * @param string $twitter
691
	 * @param string $twitterScope
692
	 * @return DataResponse
693
	 */
694
	public function setUserSettings($avatarScope,
695
									$displayname,
696
									$displaynameScope,
697
									$phone,
698
									$phoneScope,
699
									$email,
700
									$emailScope,
701
									$website,
702
									$websiteScope,
703
									$address,
704
									$addressScope,
705
									$twitter,
706
									$twitterScope
707
	) {
708
709
		if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
710
			return new DataResponse(
711
				[
712
					'status' => 'error',
713
					'data' => [
714
						'message' => (string) $this->l10n->t('Invalid mail address')
715
					]
716
				],
717
				Http::STATUS_UNPROCESSABLE_ENTITY
718
			);
719
		}
720
721
		$data = [
722
			AccountManager::PROPERTY_AVATAR =>  ['scope' => $avatarScope],
723
			AccountManager::PROPERTY_DISPLAYNAME => ['value' => $displayname, 'scope' => $displaynameScope],
724
			AccountManager::PROPERTY_EMAIL=> ['value' => $email, 'scope' => $emailScope],
725
			AccountManager::PROPERTY_WEBSITE => ['value' => $website, 'scope' => $websiteScope],
726
			AccountManager::PROPERTY_ADDRESS => ['value' => $address, 'scope' => $addressScope],
727
			AccountManager::PROPERTY_PHONE => ['value' => $phone, 'scope' => $phoneScope],
728
			AccountManager::PROPERTY_TWITTER => ['value' => $twitter, 'scope' => $twitterScope]
729
		];
730
731
		$user = $this->userSession->getUser();
732
733
		try {
734
			$this->saveUserSettings($user, $data);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 731 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...
735
			return new DataResponse(
736
				[
737
					'status' => 'success',
738
					'data' => [
739
						'userId' => $user->getUID(),
740
						'avatarScope' => $avatarScope,
741
						'displayname' => $displayname,
742
						'displaynameScope' => $displaynameScope,
743
						'email' => $email,
744
						'emailScope' => $emailScope,
745
						'website' => $website,
746
						'websiteScope' => $websiteScope,
747
						'address' => $address,
748
						'addressScope' => $addressScope,
749
						'message' => (string) $this->l10n->t('Settings saved')
750
					]
751
				],
752
				Http::STATUS_OK
753
			);
754
		} catch (ForbiddenException $e) {
755
			return new DataResponse([
756
				'status' => 'error',
757
				'data' => [
758
					'message' => $e->getMessage()
759
				],
760
			]);
761
		}
762
763
	}
764
765
766
	/**
767
	 * update account manager with new user data
768
	 *
769
	 * @param IUser $user
770
	 * @param array $data
771
	 * @throws ForbiddenException
772
	 */
773
	protected function saveUserSettings(IUser $user, $data) {
774
775
		// keep the user back-end up-to-date with the latest display name and email
776
		// address
777
		$oldDisplayName = $user->getDisplayName();
778
		$oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
779 View Code Duplication
		if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
780
			&& $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
781
		) {
782
			$result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
783
			if ($result === false) {
784
				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
785
			}
786
		}
787
788
		$oldEmailAddress = $user->getEMailAddress();
789
		$oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
790 View Code Duplication
		if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
791
			&& $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
792
		) {
793
			// this is the only permission a backend provides and is also used
794
			// for the permission of setting a email address
795
			if (!$user->canChangeDisplayName()) {
796
				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
797
			}
798
			$user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
799
		}
800
801
		$this->accountManager->updateUser($user, $data);
802
	}
803
804
	/**
805
	 * Count all unique users visible for the current admin/subadmin.
806
	 *
807
	 * @NoAdminRequired
808
	 *
809
	 * @return DataResponse
810
	 */
811
	public function stats() {
812
		$userCount = 0;
813
		if ($this->isAdmin) {
814
			$countByBackend = $this->userManager->countUsers();
815
816
			if (!empty($countByBackend)) {
817
				foreach ($countByBackend as $count) {
818
					$userCount += $count;
819
				}
820
			}
821
		} else {
822
			$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
823
824
			$uniqueUsers = [];
825
			foreach ($groups as $group) {
826
				foreach($group->getUsers() as $uid => $displayName) {
827
					$uniqueUsers[$uid] = true;
828
				}
829
			}
830
831
			$userCount = count($uniqueUsers);
832
		}
833
834
		return new DataResponse(
835
			[
836
				'totalUsers' => $userCount
837
			]
838
		);
839
	}
840
841
842
	/**
843
	 * Set the displayName of a user
844
	 *
845
	 * @NoAdminRequired
846
	 * @NoSubadminRequired
847
	 * @PasswordConfirmationRequired
848
	 * @todo merge into saveUserSettings
849
	 *
850
	 * @param string $username
851
	 * @param string $displayName
852
	 * @return DataResponse
853
	 */
854
	public function setDisplayName($username, $displayName) {
855
		$currentUser = $this->userSession->getUser();
856
		$user = $this->userManager->get($username);
857
858
		if ($user === null ||
859
			!$user->canChangeDisplayName() ||
860
			(
861
				!$this->groupManager->isAdmin($currentUser->getUID()) &&
862
				!$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
863
				$currentUser->getUID() !== $username
864
865
			)
866
		) {
867
			return new DataResponse([
868
				'status' => 'error',
869
				'data' => [
870
					'message' => $this->l10n->t('Authentication error'),
871
				],
872
			]);
873
		}
874
875
		$userData = $this->accountManager->getUser($user);
876
		$userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
877
878
879
		try {
880
			$this->saveUserSettings($user, $userData);
881
			return new DataResponse([
882
				'status' => 'success',
883
				'data' => [
884
					'message' => $this->l10n->t('Your full name has been changed.'),
885
					'username' => $username,
886
					'displayName' => $displayName,
887
				],
888
			]);
889
		} catch (ForbiddenException $e) {
890
			return new DataResponse([
891
				'status' => 'error',
892
				'data' => [
893
					'message' => $e->getMessage(),
894
					'displayName' => $user->getDisplayName(),
895
				],
896
			]);
897
		}
898
	}
899
900
	/**
901
	 * Set the mail address of a user
902
	 *
903
	 * @NoAdminRequired
904
	 * @NoSubadminRequired
905
	 * @PasswordConfirmationRequired
906
	 *
907
	 * @param string $id
908
	 * @param string $mailAddress
909
	 * @return DataResponse
910
	 */
911
	public function setEMailAddress($id, $mailAddress) {
912
		$user = $this->userManager->get($id);
913
		if (!$this->isAdmin
914
			&& !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
915
		) {
916
			return new DataResponse(
917
				[
918
					'status' => 'error',
919
					'data' => [
920
						'message' => (string) $this->l10n->t('Forbidden')
921
					]
922
				],
923
				Http::STATUS_FORBIDDEN
924
			);
925
		}
926
927
		if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
928
			return new DataResponse(
929
				[
930
					'status' => 'error',
931
					'data' => [
932
						'message' => (string) $this->l10n->t('Invalid mail address')
933
					]
934
				],
935
				Http::STATUS_UNPROCESSABLE_ENTITY
936
			);
937
		}
938
939
		if (!$user) {
940
			return new DataResponse(
941
				[
942
					'status' => 'error',
943
					'data' => [
944
						'message' => (string) $this->l10n->t('Invalid user')
945
					]
946
				],
947
				Http::STATUS_UNPROCESSABLE_ENTITY
948
			);
949
		}
950
		// this is the only permission a backend provides and is also used
951
		// for the permission of setting a email address
952
		if (!$user->canChangeDisplayName()) {
953
			return new DataResponse(
954
				[
955
					'status' => 'error',
956
					'data' => [
957
						'message' => (string) $this->l10n->t('Unable to change mail address')
958
					]
959
				],
960
				Http::STATUS_FORBIDDEN
961
			);
962
		}
963
964
		$userData = $this->accountManager->getUser($user);
965
		$userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
966
967
		try {
968
			$this->saveUserSettings($user, $userData);
969
			return new DataResponse(
970
				[
971
					'status' => 'success',
972
					'data' => [
973
						'username' => $id,
974
						'mailAddress' => $mailAddress,
975
						'message' => (string) $this->l10n->t('Email saved')
976
					]
977
				],
978
				Http::STATUS_OK
979
			);
980
		} catch (ForbiddenException $e) {
981
			return new DataResponse([
982
				'status' => 'error',
983
				'data' => [
984
					'message' => $e->getMessage()
985
				],
986
			]);
987
		}
988
	}
989
990
}
991