Completed
Pull Request — master (#3869)
by Morris
11:40
created

UsersController::setUserSettings()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 70
Code Lines 52

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 52
nc 4
nop 13
dl 0
loc 70
rs 8.7445
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

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:

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
/**
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
		];
229
	}
230
231
	/**
232
	 * @param array $userIDs Array with schema [$uid => $displayName]
233
	 * @return IUser[]
234
	 */
235
	private function getUsersForUID(array $userIDs) {
236
		$users = [];
237
		foreach ($userIDs as $uid => $displayName) {
238
			$users[$uid] = $this->userManager->get($uid);
239
		}
240
		return $users;
241
	}
242
243
	/**
244
	 * @NoAdminRequired
245
	 *
246
	 * @param int $offset
247
	 * @param int $limit
248
	 * @param string $gid GID to filter for
249
	 * @param string $pattern Pattern to search for in the username
250
	 * @param string $backend Backend to filter for (class-name)
251
	 * @return DataResponse
252
	 *
253
	 * TODO: Tidy up and write unit tests - code is mainly static method calls
254
	 */
255
	public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
256
		// FIXME: The JS sends the group '_everyone' instead of no GID for the "all users" group.
257
		if($gid === '_everyone') {
258
			$gid = '';
259
		}
260
261
		// Remove backends
262
		if(!empty($backend)) {
263
			$activeBackends = $this->userManager->getBackends();
264
			$this->userManager->clearBackends();
265
			foreach($activeBackends as $singleActiveBackend) {
266
				if($backend === get_class($singleActiveBackend)) {
267
					$this->userManager->registerBackend($singleActiveBackend);
268
					break;
269
				}
270
			}
271
		}
272
273
		$users = [];
274
		if ($this->isAdmin) {
275
276
			if($gid !== '') {
277
				$batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
278
			} else {
279
				$batch = $this->userManager->search($pattern, $limit, $offset);
280
			}
281
282
			foreach ($batch as $user) {
283
				$users[] = $this->formatUserForIndex($user);
284
			}
285
286
		} else {
287
			$subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
288
			// New class returns IGroup[] so convert back
289
			$gids = [];
290
			foreach ($subAdminOfGroups as $group) {
291
				$gids[] = $group->getGID();
292
			}
293
			$subAdminOfGroups = $gids;
294
295
			// Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
296
			if($gid !== '' && !in_array($gid, $subAdminOfGroups)) {
297
				$gid = '';
298
			}
299
300
			// Batch all groups the user is subadmin of when a group is specified
301
			$batch = [];
302
			if($gid === '') {
303
				foreach($subAdminOfGroups as $group) {
304
					$groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
305
306
					foreach($groupUsers as $uid => $displayName) {
307
						$batch[$uid] = $displayName;
308
					}
309
				}
310
			} else {
311
				$batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
312
			}
313
			$batch = $this->getUsersForUID($batch);
314
315
			foreach ($batch as $user) {
316
				// Only add the groups, this user is a subadmin of
317
				$userGroups = array_values(array_intersect(
318
					$this->groupManager->getUserGroupIds($user),
319
					$subAdminOfGroups
320
				));
321
				$users[] = $this->formatUserForIndex($user, $userGroups);
322
			}
323
		}
324
325
		return new DataResponse($users);
326
	}
327
328
	/**
329
	 * @NoAdminRequired
330
	 * @PasswordConfirmationRequired
331
	 *
332
	 * @param string $username
333
	 * @param string $password
334
	 * @param array $groups
335
	 * @param string $email
336
	 * @return DataResponse
337
	 */
338
	public function create($username, $password, array $groups=array(), $email='') {
339
		if($email !== '' && !$this->mailer->validateMailAddress($email)) {
340
			return new DataResponse(
341
				array(
342
					'message' => (string)$this->l10n->t('Invalid mail address')
343
				),
344
				Http::STATUS_UNPROCESSABLE_ENTITY
345
			);
346
		}
347
348
		$currentUser = $this->userSession->getUser();
349
350
		if (!$this->isAdmin) {
351
			if (!empty($groups)) {
352
				foreach ($groups as $key => $group) {
353
					$groupObject = $this->groupManager->get($group);
354
					if($groupObject === null) {
355
						unset($groups[$key]);
356
						continue;
357
					}
358
359
					if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
360
						unset($groups[$key]);
361
					}
362
				}
363
			}
364
365
			if (empty($groups)) {
366
				return new DataResponse(
367
					array(
368
						'message' => $this->l10n->t('No valid group selected'),
369
					),
370
					Http::STATUS_FORBIDDEN
371
				);
372
			}
373
		}
374
375
		if ($this->userManager->userExists($username)) {
376
			return new DataResponse(
377
				array(
378
					'message' => (string)$this->l10n->t('A user with that name already exists.')
379
				),
380
				Http::STATUS_CONFLICT
381
			);
382
		}
383
384
		$generatePasswordResetToken = false;
385
		if ($password === '') {
386
			if ($email === '') {
387
				return new DataResponse(
388
					array(
389
						'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
390
					),
391
					Http::STATUS_UNPROCESSABLE_ENTITY
392
				);
393
			}
394
395
			$password = $this->secureRandom->generate(32);
396
			$generatePasswordResetToken = true;
397
		}
398
399
		try {
400
			$user = $this->userManager->createUser($username, $password);
401
		} catch (\Exception $exception) {
402
			$message = $exception->getMessage();
403
			if (!$message) {
404
				$message = $this->l10n->t('Unable to create user.');
405
			}
406
			return new DataResponse(
407
				array(
408
					'message' => (string) $message,
409
				),
410
				Http::STATUS_FORBIDDEN
411
			);
412
		}
413
414
		if($user instanceof IUser) {
415
			if($groups !== null) {
416
				foreach($groups as $groupName) {
417
					$group = $this->groupManager->get($groupName);
418
419
					if(empty($group)) {
420
						$group = $this->groupManager->createGroup($groupName);
421
					}
422
					$group->addUser($user);
423
				}
424
			}
425
			/**
426
			 * Send new user mail only if a mail is set
427
			 */
428
			if($email !== '') {
429
				$user->setEMailAddress($email);
430
				try {
431
					$emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
432
					$this->newUserMailHelper->sendMail($user, $emailTemplate);
433
				} catch(\Exception $e) {
434
					$this->log->error("Can't send new user mail to $email: " . $e->getMessage(), array('app' => 'settings'));
435
				}
436
			}
437
			// fetch users groups
438
			$userGroups = $this->groupManager->getUserGroupIds($user);
439
440
			return new DataResponse(
441
				$this->formatUserForIndex($user, $userGroups),
442
				Http::STATUS_CREATED
443
			);
444
		}
445
446
		return new DataResponse(
447
			array(
448
				'message' => (string)$this->l10n->t('Unable to create user.')
449
			),
450
			Http::STATUS_FORBIDDEN
451
		);
452
453
	}
454
455
	/**
456
	 * @NoAdminRequired
457
	 * @PasswordConfirmationRequired
458
	 *
459
	 * @param string $id
460
	 * @return DataResponse
461
	 */
462
	public function destroy($id) {
463
		$userId = $this->userSession->getUser()->getUID();
464
		$user = $this->userManager->get($id);
465
466
		if($userId === $id) {
467
			return new DataResponse(
468
				array(
469
					'status' => 'error',
470
					'data' => array(
471
						'message' => (string)$this->l10n->t('Unable to delete user.')
472
					)
473
				),
474
				Http::STATUS_FORBIDDEN
475
			);
476
		}
477
478 View Code Duplication
		if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
479
			return new DataResponse(
480
				array(
481
					'status' => 'error',
482
					'data' => array(
483
						'message' => (string)$this->l10n->t('Authentication error')
484
					)
485
				),
486
				Http::STATUS_FORBIDDEN
487
			);
488
		}
489
490
		if($user) {
491
			if($user->delete()) {
492
				return new DataResponse(
493
					array(
494
						'status' => 'success',
495
						'data' => array(
496
							'username' => $id
497
						)
498
					),
499
					Http::STATUS_NO_CONTENT
500
				);
501
			}
502
		}
503
504
		return new DataResponse(
505
			array(
506
				'status' => 'error',
507
				'data' => array(
508
					'message' => (string)$this->l10n->t('Unable to delete user.')
509
				)
510
			),
511
			Http::STATUS_FORBIDDEN
512
		);
513
	}
514
515
	/**
516
	 * @NoAdminRequired
517
	 * @NoSubadminRequired
518
	 * @PasswordConfirmationRequired
519
	 *
520
	 * @param string $account
521
	 * @param bool $onlyVerificationCode only return verification code without updating the data
522
	 * @return DataResponse
523
	 */
524
	public function getVerificationCode($account, $onlyVerificationCode) {
525
526
		$user = $this->userSession->getUser();
527
528
		if ($user === null) {
529
			return new DataResponse([], Http::STATUS_BAD_REQUEST);
530
		}
531
532
		$accountData = $this->accountManager->getUser($user);
533
		$cloudId = $user->getCloudId();
534
		$message = "Use my Federated Cloud ID to share with me: " . $cloudId;
535
		$signature = $this->signMessage($user, $message);
536
537
		$code = $message . ' ' . $signature;
538
		$codeMd5 = $message . ' ' . md5($signature);
539
540
		switch ($account) {
541 View Code Duplication
			case 'verify-twitter':
542
				$accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
543
				$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):');
544
				$code = $codeMd5;
545
				$type = AccountManager::PROPERTY_TWITTER;
546
				$data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
547
				$accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
548
				break;
549 View Code Duplication
			case 'verify-website':
550
				$accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
551
				$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):');
552
				$type = AccountManager::PROPERTY_WEBSITE;
553
				$data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
554
				$accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
555
				break;
556
			default:
557
				return new DataResponse([], Http::STATUS_BAD_REQUEST);
558
		}
559
560
		if ($onlyVerificationCode === false) {
561
			$this->accountManager->updateUser($user, $accountData);
562
563
			$this->jobList->add('OC\Settings\BackgroundJobs\VerifyUserData',
564
				[
565
					'verificationCode' => $code,
566
					'data' => $data,
567
					'type' => $type,
568
					'uid' => $user->getUID(),
569
					'try' => 0,
570
					'lastRun' => $this->getCurrentTime()
571
				]
572
			);
573
		}
574
575
		return new DataResponse(['msg' => $msg, 'code' => $code]);
576
	}
577
578
	/**
579
	 * get current timestamp
580
	 *
581
	 * @return int
582
	 */
583
	protected function getCurrentTime() {
584
		return time();
585
	}
586
587
	/**
588
	 * sign message with users private key
589
	 *
590
	 * @param IUser $user
591
	 * @param string $message
592
	 *
593
	 * @return string base64 encoded signature
594
	 */
595
	protected function signMessage(IUser $user, $message) {
596
		$privateKey = $this->keyManager->getKey($user)->getPrivate();
597
		openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
598
		$signatureBase64 = base64_encode($signature);
599
600
		return $signatureBase64;
601
	}
602
603
	/**
604
	 * @NoAdminRequired
605
	 * @NoSubadminRequired
606
	 * @PasswordConfirmationRequired
607
	 *
608
	 * @param string $avatarScope
609
	 * @param string $displayname
610
	 * @param string $displaynameScope
611
	 * @param string $phone
612
	 * @param string $phoneScope
613
	 * @param string $email
614
	 * @param string $emailScope
615
	 * @param string $website
616
	 * @param string $websiteScope
617
	 * @param string $address
618
	 * @param string $addressScope
619
	 * @param string $twitter
620
	 * @param string $twitterScope
621
	 * @return DataResponse
622
	 */
623
	public function setUserSettings($avatarScope,
624
									$displayname,
625
									$displaynameScope,
626
									$phone,
627
									$phoneScope,
628
									$email,
629
									$emailScope,
630
									$website,
631
									$websiteScope,
632
									$address,
633
									$addressScope,
634
									$twitter,
635
									$twitterScope
636
	) {
637
638
		if(!empty($email) && !$this->mailer->validateMailAddress($email)) {
639
			return new DataResponse(
640
				array(
641
					'status' => 'error',
642
					'data' => array(
643
						'message' => (string)$this->l10n->t('Invalid mail address')
644
					)
645
				),
646
				Http::STATUS_UNPROCESSABLE_ENTITY
647
			);
648
		}
649
650
		$data = [
651
			AccountManager::PROPERTY_AVATAR =>  ['scope' => $avatarScope],
652
			AccountManager::PROPERTY_DISPLAYNAME => ['value' => $displayname, 'scope' => $displaynameScope],
653
			AccountManager::PROPERTY_EMAIL=> ['value' => $email, 'scope' => $emailScope],
654
			AccountManager::PROPERTY_WEBSITE => ['value' => $website, 'scope' => $websiteScope],
655
			AccountManager::PROPERTY_ADDRESS => ['value' => $address, 'scope' => $addressScope],
656
			AccountManager::PROPERTY_PHONE => ['value' => $phone, 'scope' => $phoneScope],
657
			AccountManager::PROPERTY_TWITTER => ['value' => $twitter, 'scope' => $twitterScope]
658
		];
659
660
		$user = $this->userSession->getUser();
661
662
		try {
663
			$this->saveUserSettings($user, $data);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 660 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...
664
			return new DataResponse(
665
				array(
666
					'status' => 'success',
667
					'data' => array(
668
						'userId' => $user->getUID(),
669
						'avatarScope' => $avatarScope,
670
						'displayname' => $displayname,
671
						'displaynameScope' => $displaynameScope,
672
						'email' => $email,
673
						'emailScope' => $emailScope,
674
						'website' => $website,
675
						'websiteScope' => $websiteScope,
676
						'address' => $address,
677
						'addressScope' => $addressScope,
678
						'message' => (string)$this->l10n->t('Settings saved')
679
					)
680
				),
681
				Http::STATUS_OK
682
			);
683
		} catch (ForbiddenException $e) {
684
			return new DataResponse([
685
				'status' => 'error',
686
				'data' => [
687
					'message' => $e->getMessage()
688
				],
689
			]);
690
		}
691
692
	}
693
694
695
	/**
696
	 * update account manager with new user data
697
	 *
698
	 * @param IUser $user
699
	 * @param array $data
700
	 * @throws ForbiddenException
701
	 */
702
	protected function saveUserSettings(IUser $user, $data) {
703
704
		// keep the user back-end up-to-date with the latest display name and email
705
		// address
706
		$oldDisplayName = $user->getDisplayName();
707
		$oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
708 View Code Duplication
		if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
709
			&& $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
710
		) {
711
			$result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
712
			if ($result === false) {
713
				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
714
			}
715
		}
716
717
		$oldEmailAddress = $user->getEMailAddress();
718
		$oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
719 View Code Duplication
		if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
720
			&& $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
721
		) {
722
			// this is the only permission a backend provides and is also used
723
			// for the permission of setting a email address
724
			if (!$user->canChangeDisplayName()) {
725
				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
726
			}
727
			$user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
728
		}
729
730
		$this->accountManager->updateUser($user, $data);
731
	}
732
733
	/**
734
	 * Count all unique users visible for the current admin/subadmin.
735
	 *
736
	 * @NoAdminRequired
737
	 *
738
	 * @return DataResponse
739
	 */
740
	public function stats() {
741
		$userCount = 0;
742
		if ($this->isAdmin) {
743
			$countByBackend = $this->userManager->countUsers();
744
745
			if (!empty($countByBackend)) {
746
				foreach ($countByBackend as $count) {
747
					$userCount += $count;
748
				}
749
			}
750
		} else {
751
			$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
752
753
			$uniqueUsers = [];
754
			foreach ($groups as $group) {
755
				foreach($group->getUsers() as $uid => $displayName) {
756
					$uniqueUsers[$uid] = true;
757
				}
758
			}
759
760
			$userCount = count($uniqueUsers);
761
		}
762
763
		return new DataResponse(
764
			[
765
				'totalUsers' => $userCount
766
			]
767
		);
768
	}
769
770
771
	/**
772
	 * Set the displayName of a user
773
	 *
774
	 * @NoAdminRequired
775
	 * @NoSubadminRequired
776
	 * @PasswordConfirmationRequired
777
	 * @todo merge into saveUserSettings
778
	 *
779
	 * @param string $username
780
	 * @param string $displayName
781
	 * @return DataResponse
782
	 */
783
	public function setDisplayName($username, $displayName) {
784
		$currentUser = $this->userSession->getUser();
785
		$user = $this->userManager->get($username);
786
787
		if ($user === null ||
788
			!$user->canChangeDisplayName() ||
789
			(
790
				!$this->groupManager->isAdmin($currentUser->getUID()) &&
791
				!$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
792
				$currentUser->getUID() !== $username
793
794
			)
795
		) {
796
			return new DataResponse([
797
				'status' => 'error',
798
				'data' => [
799
					'message' => $this->l10n->t('Authentication error'),
800
				],
801
			]);
802
		}
803
804
		$userData = $this->accountManager->getUser($user);
805
		$userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
806
807
808
		try {
809
			$this->saveUserSettings($user, $userData);
810
			return new DataResponse([
811
				'status' => 'success',
812
				'data' => [
813
					'message' => $this->l10n->t('Your full name has been changed.'),
814
					'username' => $username,
815
					'displayName' => $displayName,
816
				],
817
			]);
818
		} catch (ForbiddenException $e) {
819
			return new DataResponse([
820
				'status' => 'error',
821
				'data' => [
822
					'message' => $e->getMessage(),
823
					'displayName' => $user->getDisplayName(),
824
				],
825
			]);
826
		}
827
	}
828
829
	/**
830
	 * Set the mail address of a user
831
	 *
832
	 * @NoAdminRequired
833
	 * @NoSubadminRequired
834
	 * @PasswordConfirmationRequired
835
	 *
836
	 * @param string $id
837
	 * @param string $mailAddress
838
	 * @return DataResponse
839
	 */
840
	public function setEMailAddress($id, $mailAddress) {
841
		$user = $this->userManager->get($id);
842 View Code Duplication
		if (!$this->isAdmin
843
			&& !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
844
		) {
845
			return new DataResponse(
846
				array(
847
					'status' => 'error',
848
					'data' => array(
849
						'message' => (string)$this->l10n->t('Forbidden')
850
					)
851
				),
852
				Http::STATUS_FORBIDDEN
853
			);
854
		}
855
856
		if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
857
			return new DataResponse(
858
				array(
859
					'status' => 'error',
860
					'data' => array(
861
						'message' => (string)$this->l10n->t('Invalid mail address')
862
					)
863
				),
864
				Http::STATUS_UNPROCESSABLE_ENTITY
865
			);
866
		}
867
868
		if (!$user) {
869
			return new DataResponse(
870
				array(
871
					'status' => 'error',
872
					'data' => array(
873
						'message' => (string)$this->l10n->t('Invalid user')
874
					)
875
				),
876
				Http::STATUS_UNPROCESSABLE_ENTITY
877
			);
878
		}
879
		// this is the only permission a backend provides and is also used
880
		// for the permission of setting a email address
881
		if (!$user->canChangeDisplayName()) {
882
			return new DataResponse(
883
				array(
884
					'status' => 'error',
885
					'data' => array(
886
						'message' => (string)$this->l10n->t('Unable to change mail address')
887
					)
888
				),
889
				Http::STATUS_FORBIDDEN
890
			);
891
		}
892
893
		$userData = $this->accountManager->getUser($user);
894
		$userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
895
896
		try {
897
			$this->saveUserSettings($user, $userData);
898
			return new DataResponse(
899
				array(
900
					'status' => 'success',
901
					'data' => array(
902
						'username' => $id,
903
						'mailAddress' => $mailAddress,
904
						'message' => (string)$this->l10n->t('Email saved')
905
					)
906
				),
907
				Http::STATUS_OK
908
			);
909
		} catch (ForbiddenException $e) {
910
			return new DataResponse([
911
				'status' => 'error',
912
				'data' => [
913
					'message' => $e->getMessage()
914
				],
915
			]);
916
		}
917
	}
918
919
}
920