Completed
Push — master ( efa9ac...0478db )
by Christoph
14:32 queued 05:45
created

UsersController::stats()   B

Complexity

Conditions 6
Paths 3

Size

Total Lines 29
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 16
nc 3
nop 0
dl 0
loc 29
rs 8.439
c 0
b 0
f 0
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\User\User;
37
use OCP\App\IAppManager;
38
use OCP\AppFramework\Controller;
39
use OCP\AppFramework\Http\DataResponse;
40
use OCP\AppFramework\Http\TemplateResponse;
41
use OCP\IConfig;
42
use OCP\IGroupManager;
43
use OCP\IL10N;
44
use OCP\ILogger;
45
use OCP\IRequest;
46
use OCP\IURLGenerator;
47
use OCP\IUser;
48
use OCP\IUserManager;
49
use OCP\IUserSession;
50
use OCP\Mail\IMailer;
51
use OCP\IAvatarManager;
52
use Punic\Exception;
53
54
/**
55
 * @package OC\Settings\Controller
56
 */
57
class UsersController extends Controller {
58
	/** @var IL10N */
59
	private $l10n;
60
	/** @var IUserSession */
61
	private $userSession;
62
	/** @var bool */
63
	private $isAdmin;
64
	/** @var IUserManager */
65
	private $userManager;
66
	/** @var IGroupManager */
67
	private $groupManager;
68
	/** @var IConfig */
69
	private $config;
70
	/** @var ILogger */
71
	private $log;
72
	/** @var \OC_Defaults */
73
	private $defaults;
74
	/** @var IMailer */
75
	private $mailer;
76
	/** @var string */
77
	private $fromMailAddress;
78
	/** @var IURLGenerator */
79
	private $urlGenerator;
80
	/** @var bool contains the state of the encryption app */
81
	private $isEncryptionAppEnabled;
82
	/** @var bool contains the state of the admin recovery setting */
83
	private $isRestoreEnabled = false;
84
	/** @var IAvatarManager */
85
	private $avatarManager;
86
	/** @var AccountManager */
87
	private $accountManager;
88
89
	/**
90
	 * @param string $appName
91
	 * @param IRequest $request
92
	 * @param IUserManager $userManager
93
	 * @param IGroupManager $groupManager
94
	 * @param IUserSession $userSession
95
	 * @param IConfig $config
96
	 * @param bool $isAdmin
97
	 * @param IL10N $l10n
98
	 * @param ILogger $log
99
	 * @param \OC_Defaults $defaults
100
	 * @param IMailer $mailer
101
	 * @param string $fromMailAddress
102
	 * @param IURLGenerator $urlGenerator
103
	 * @param IAppManager $appManager
104
	 * @param IAvatarManager $avatarManager
105
	 * @param AccountManager $accountManager
106
	 */
107
	public function __construct($appName,
108
								IRequest $request,
109
								IUserManager $userManager,
110
								IGroupManager $groupManager,
111
								IUserSession $userSession,
112
								IConfig $config,
113
								$isAdmin,
114
								IL10N $l10n,
115
								ILogger $log,
116
								\OC_Defaults $defaults,
117
								IMailer $mailer,
118
								$fromMailAddress,
119
								IURLGenerator $urlGenerator,
120
								IAppManager $appManager,
121
								IAvatarManager $avatarManager,
122
								AccountManager $accountManager
123
) {
124
		parent::__construct($appName, $request);
125
		$this->userManager = $userManager;
126
		$this->groupManager = $groupManager;
127
		$this->userSession = $userSession;
128
		$this->config = $config;
129
		$this->isAdmin = $isAdmin;
130
		$this->l10n = $l10n;
131
		$this->log = $log;
132
		$this->defaults = $defaults;
133
		$this->mailer = $mailer;
134
		$this->fromMailAddress = $fromMailAddress;
135
		$this->urlGenerator = $urlGenerator;
136
		$this->avatarManager = $avatarManager;
137
		$this->accountManager = $accountManager;
138
139
		// check for encryption state - TODO see formatUserForIndex
140
		$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
141
		if($this->isEncryptionAppEnabled) {
142
			// putting this directly in empty is possible in PHP 5.5+
143
			$result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
144
			$this->isRestoreEnabled = !empty($result);
145
		}
146
	}
147
148
	/**
149
	 * @param IUser $user
150
	 * @param array $userGroups
151
	 * @return array
152
	 */
153
	private function formatUserForIndex(IUser $user, array $userGroups = null) {
154
155
		// TODO: eliminate this encryption specific code below and somehow
156
		// hook in additional user info from other apps
157
158
		// recovery isn't possible if admin or user has it disabled and encryption
159
		// is enabled - so we eliminate the else paths in the conditional tree
160
		// below
161
		$restorePossible = false;
162
163
		if ($this->isEncryptionAppEnabled) {
164
			if ($this->isRestoreEnabled) {
165
				// check for the users recovery setting
166
				$recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
167
				// method call inside empty is possible with PHP 5.5+
168
				$recoveryModeEnabled = !empty($recoveryMode);
169
				if ($recoveryModeEnabled) {
170
					// user also has recovery mode enabled
171
					$restorePossible = true;
172
				}
173
			}
174
		} else {
175
			// recovery is possible if encryption is disabled (plain files are
176
			// available)
177
			$restorePossible = true;
178
		}
179
180
		$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
181
		foreach($subAdminGroups as $key => $subAdminGroup) {
182
			$subAdminGroups[$key] = $subAdminGroup->getGID();
183
		}
184
185
		$displayName = $user->getEMailAddress();
186
		if (is_null($displayName)) {
187
			$displayName = '';
188
		}
189
190
		$avatarAvailable = false;
191
		if ($this->config->getSystemValue('enable_avatars', true) === true) {
192
			try {
193
				$avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
194
			} catch (\Exception $e) {
195
				//No avatar yet
196
			}
197
		}
198
199
		return [
200
			'name' => $user->getUID(),
201
			'displayname' => $user->getDisplayName(),
202
			'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
203
			'subadmin' => $subAdminGroups,
204
			'quota' => $user->getQuota(),
205
			'storageLocation' => $user->getHome(),
206
			'lastLogin' => $user->getLastLogin() * 1000,
207
			'backend' => $user->getBackendClassName(),
208
			'email' => $displayName,
209
			'isRestoreDisabled' => !$restorePossible,
210
			'isAvatarAvailable' => $avatarAvailable,
211
		];
212
	}
213
214
	/**
215
	 * @param array $userIDs Array with schema [$uid => $displayName]
216
	 * @return IUser[]
217
	 */
218
	private function getUsersForUID(array $userIDs) {
219
		$users = [];
220
		foreach ($userIDs as $uid => $displayName) {
221
			$users[$uid] = $this->userManager->get($uid);
222
		}
223
		return $users;
224
	}
225
226
	/**
227
	 * @NoAdminRequired
228
	 *
229
	 * @param int $offset
230
	 * @param int $limit
231
	 * @param string $gid GID to filter for
232
	 * @param string $pattern Pattern to search for in the username
233
	 * @param string $backend Backend to filter for (class-name)
234
	 * @return DataResponse
235
	 *
236
	 * TODO: Tidy up and write unit tests - code is mainly static method calls
237
	 */
238
	public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
239
		// FIXME: The JS sends the group '_everyone' instead of no GID for the "all users" group.
240
		if($gid === '_everyone') {
241
			$gid = '';
242
		}
243
244
		// Remove backends
245
		if(!empty($backend)) {
246
			$activeBackends = $this->userManager->getBackends();
247
			$this->userManager->clearBackends();
248
			foreach($activeBackends as $singleActiveBackend) {
249
				if($backend === get_class($singleActiveBackend)) {
250
					$this->userManager->registerBackend($singleActiveBackend);
251
					break;
252
				}
253
			}
254
		}
255
256
		$users = [];
257
		if ($this->isAdmin) {
258
259
			if($gid !== '') {
260
				$batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
261
			} else {
262
				$batch = $this->userManager->search($pattern, $limit, $offset);
263
			}
264
265
			foreach ($batch as $user) {
266
				$users[] = $this->formatUserForIndex($user);
267
			}
268
269
		} else {
270
			$subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
271
			// New class returns IGroup[] so convert back
272
			$gids = [];
273
			foreach ($subAdminOfGroups as $group) {
274
				$gids[] = $group->getGID();
275
			}
276
			$subAdminOfGroups = $gids;
277
278
			// Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
279
			if($gid !== '' && !in_array($gid, $subAdminOfGroups)) {
280
				$gid = '';
281
			}
282
283
			// Batch all groups the user is subadmin of when a group is specified
284
			$batch = [];
285
			if($gid === '') {
286
				foreach($subAdminOfGroups as $group) {
287
					$groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
288
289
					foreach($groupUsers as $uid => $displayName) {
290
						$batch[$uid] = $displayName;
291
					}
292
				}
293
			} else {
294
				$batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
295
			}
296
			$batch = $this->getUsersForUID($batch);
297
298
			foreach ($batch as $user) {
299
				// Only add the groups, this user is a subadmin of
300
				$userGroups = array_values(array_intersect(
301
					$this->groupManager->getUserGroupIds($user),
302
					$subAdminOfGroups
303
				));
304
				$users[] = $this->formatUserForIndex($user, $userGroups);
305
			}
306
		}
307
308
		return new DataResponse($users);
309
	}
310
311
	/**
312
	 * @NoAdminRequired
313
	 * @PasswordConfirmationRequired
314
	 *
315
	 * @param string $username
316
	 * @param string $password
317
	 * @param array $groups
318
	 * @param string $email
319
	 * @return DataResponse
320
	 */
321
	public function create($username, $password, array $groups=array(), $email='') {
322
		if($email !== '' && !$this->mailer->validateMailAddress($email)) {
323
			return new DataResponse(
324
				array(
325
					'message' => (string)$this->l10n->t('Invalid mail address')
326
				),
327
				Http::STATUS_UNPROCESSABLE_ENTITY
328
			);
329
		}
330
331
		$currentUser = $this->userSession->getUser();
332
333
		if (!$this->isAdmin) {
334
			if (!empty($groups)) {
335
				foreach ($groups as $key => $group) {
336
					$groupObject = $this->groupManager->get($group);
337
					if($groupObject === null) {
338
						unset($groups[$key]);
339
						continue;
340
					}
341
342
					if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
343
						unset($groups[$key]);
344
					}
345
				}
346
			}
347
348
			if (empty($groups)) {
349
				$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($currentUser);
350
				// New class returns IGroup[] so convert back
351
				$gids = [];
352
				foreach ($groups as $group) {
353
					$gids[] = $group->getGID();
354
				}
355
				$groups = $gids;
356
			}
357
		}
358
359
		if ($this->userManager->userExists($username)) {
360
			return new DataResponse(
361
				array(
362
					'message' => (string)$this->l10n->t('A user with that name already exists.')
363
				),
364
				Http::STATUS_CONFLICT
365
			);
366
		}
367
368
		try {
369
			$user = $this->userManager->createUser($username, $password);
370
		} catch (\Exception $exception) {
371
			$message = $exception->getMessage();
372
			if (!$message) {
373
				$message = $this->l10n->t('Unable to create user.');
374
			}
375
			return new DataResponse(
376
				array(
377
					'message' => (string) $message,
378
				),
379
				Http::STATUS_FORBIDDEN
380
			);
381
		}
382
383
		if($user instanceof User) {
384
			if($groups !== null) {
385
				foreach($groups as $groupName) {
386
					$group = $this->groupManager->get($groupName);
387
388
					if(empty($group)) {
389
						$group = $this->groupManager->createGroup($groupName);
390
					}
391
					$group->addUser($user);
392
				}
393
			}
394
			/**
395
			 * Send new user mail only if a mail is set
396
			 */
397
			if($email !== '') {
398
				$user->setEMailAddress($email);
399
400
				// data for the mail template
401
				$mailData = array(
402
					'username' => $username,
403
					'url' => $this->urlGenerator->getAbsoluteURL('/')
404
				);
405
406
				$mail = new TemplateResponse('settings', 'email.new_user', $mailData, 'blank');
407
				$mailContent = $mail->render();
408
409
				$mail = new TemplateResponse('settings', 'email.new_user_plain_text', $mailData, 'blank');
410
				$plainTextMailContent = $mail->render();
411
412
				$subject = $this->l10n->t('Your %s account was created', [$this->defaults->getName()]);
413
414
				try {
415
					$message = $this->mailer->createMessage();
416
					$message->setTo([$email => $username]);
417
					$message->setSubject($subject);
418
					$message->setHtmlBody($mailContent);
0 ignored issues
show
Bug introduced by
It seems like $mailContent defined by $mail->render() on line 407 can also be of type boolean; however, OC\Mail\Message::setHtmlBody() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
419
					$message->setPlainBody($plainTextMailContent);
0 ignored issues
show
Bug introduced by
It seems like $plainTextMailContent defined by $mail->render() on line 410 can also be of type boolean; however, OC\Mail\Message::setPlainBody() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
420
					$message->setFrom([$this->fromMailAddress => $this->defaults->getName()]);
421
					$this->mailer->send($message);
422
				} catch(\Exception $e) {
423
					$this->log->error("Can't send new user mail to $email: " . $e->getMessage(), array('app' => 'settings'));
424
				}
425
			}
426
			// fetch users groups
427
			$userGroups = $this->groupManager->getUserGroupIds($user);
428
429
			return new DataResponse(
430
				$this->formatUserForIndex($user, $userGroups),
431
				Http::STATUS_CREATED
432
			);
433
		}
434
435
		return new DataResponse(
436
			array(
437
				'message' => (string)$this->l10n->t('Unable to create user.')
438
			),
439
			Http::STATUS_FORBIDDEN
440
		);
441
442
	}
443
444
	/**
445
	 * @NoAdminRequired
446
	 * @PasswordConfirmationRequired
447
	 *
448
	 * @param string $id
449
	 * @return DataResponse
450
	 */
451
	public function destroy($id) {
452
		$userId = $this->userSession->getUser()->getUID();
453
		$user = $this->userManager->get($id);
454
455
		if($userId === $id) {
456
			return new DataResponse(
457
				array(
458
					'status' => 'error',
459
					'data' => array(
460
						'message' => (string)$this->l10n->t('Unable to delete user.')
461
					)
462
				),
463
				Http::STATUS_FORBIDDEN
464
			);
465
		}
466
467 View Code Duplication
		if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
468
			return new DataResponse(
469
				array(
470
					'status' => 'error',
471
					'data' => array(
472
						'message' => (string)$this->l10n->t('Authentication error')
473
					)
474
				),
475
				Http::STATUS_FORBIDDEN
476
			);
477
		}
478
479
		if($user) {
480
			if($user->delete()) {
481
				return new DataResponse(
482
					array(
483
						'status' => 'success',
484
						'data' => array(
485
							'username' => $id
486
						)
487
					),
488
					Http::STATUS_NO_CONTENT
489
				);
490
			}
491
		}
492
493
		return new DataResponse(
494
			array(
495
				'status' => 'error',
496
				'data' => array(
497
					'message' => (string)$this->l10n->t('Unable to delete user.')
498
				)
499
			),
500
			Http::STATUS_FORBIDDEN
501
		);
502
	}
503
504
	/**
505
	 * @NoAdminRequired
506
	 * @NoSubadminRequired
507
	 * @PasswordConfirmationRequired
508
	 *
509
	 * @param string $avatarScope
510
	 * @param string $displayname
511
	 * @param string $displaynameScope
512
	 * @param string $phone
513
	 * @param string $phoneScope
514
	 * @param string $email
515
	 * @param string $emailScope
516
	 * @param string $website
517
	 * @param string $websiteScope
518
	 * @param string $address
519
	 * @param string $addressScope
520
	 * @param string $twitter
521
	 * @param string $twitterScope
522
	 * @return DataResponse
523
	 */
524
	public function setUserSettings($avatarScope,
525
									$displayname,
526
									$displaynameScope,
527
									$phone,
528
									$phoneScope,
529
									$email,
530
									$emailScope,
531
									$website,
532
									$websiteScope,
533
									$address,
534
									$addressScope,
535
									$twitter,
536
									$twitterScope
537
	) {
538
539
		if(!empty($email) && !$this->mailer->validateMailAddress($email)) {
540
			return new DataResponse(
541
				array(
542
					'status' => 'error',
543
					'data' => array(
544
						'message' => (string)$this->l10n->t('Invalid mail address')
545
					)
546
				),
547
				Http::STATUS_UNPROCESSABLE_ENTITY
548
			);
549
		}
550
551
		$data = [
552
			AccountManager::PROPERTY_AVATAR =>  ['scope' => $avatarScope],
553
			AccountManager::PROPERTY_DISPLAYNAME => ['value' => $displayname, 'scope' => $displaynameScope],
554
			AccountManager::PROPERTY_EMAIL=> ['value' => $email, 'scope' => $emailScope],
555
			AccountManager::PROPERTY_WEBSITE => ['value' => $website, 'scope' => $websiteScope],
556
			AccountManager::PROPERTY_ADDRESS => ['value' => $address, 'scope' => $addressScope],
557
			AccountManager::PROPERTY_PHONE => ['value' => $phone, 'scope' => $phoneScope],
558
			AccountManager::PROPERTY_TWITTER => ['value' => $twitter, 'scope' => $twitterScope]
559
		];
560
561
		$user = $this->userSession->getUser();
562
563
		try {
564
			$this->saveUserSettings($user, $data);
0 ignored issues
show
Bug introduced by
It seems like $user defined by $this->userSession->getUser() on line 561 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...
565
			return new DataResponse(
566
				array(
567
					'status' => 'success',
568
					'data' => array(
569
						'userId' => $user->getUID(),
570
						'avatarScope' => $avatarScope,
571
						'displayname' => $displayname,
572
						'displaynameScope' => $displaynameScope,
573
						'email' => $email,
574
						'emailScope' => $emailScope,
575
						'website' => $website,
576
						'websiteScope' => $websiteScope,
577
						'address' => $address,
578
						'addressScope' => $addressScope,
579
						'message' => (string)$this->l10n->t('Settings saved')
580
					)
581
				),
582
				Http::STATUS_OK
583
			);
584
		} catch (ForbiddenException $e) {
585
			return new DataResponse([
586
				'status' => 'error',
587
				'data' => [
588
					'message' => $e->getMessage()
589
				],
590
			]);
591
		}
592
593
	}
594
595
596
	/**
597
	 * update account manager with new user data
598
	 *
599
	 * @param IUser $user
600
	 * @param array $data
601
	 * @throws ForbiddenException
602
	 */
603
	protected function saveUserSettings(IUser $user, $data) {
604
605
		// keep the user back-end up-to-date with the latest display name and email
606
		// address
607
		$oldDisplayName = $user->getDisplayName();
608
		$oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
609 View Code Duplication
		if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
610
			&& $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
611
		) {
612
			$result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
613
			if ($result === false) {
614
				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
615
			}
616
		}
617
618
		$oldEmailAddress = $user->getEMailAddress();
619
		$oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
620 View Code Duplication
		if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
621
			&& $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
622
		) {
623
			// this is the only permission a backend provides and is also used
624
			// for the permission of setting a email address
625
			if (!$user->canChangeDisplayName()) {
626
				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
627
			}
628
			$user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
629
		}
630
631
		$this->accountManager->updateUser($user, $data);
632
	}
633
634
	/**
635
	 * Count all unique users visible for the current admin/subadmin.
636
	 *
637
	 * @NoAdminRequired
638
	 *
639
	 * @return DataResponse
640
	 */
641
	public function stats() {
642
		$userCount = 0;
643
		if ($this->isAdmin) {
644
			$countByBackend = $this->userManager->countUsers();
645
646
			if (!empty($countByBackend)) {
647
				foreach ($countByBackend as $count) {
648
					$userCount += $count;
649
				}
650
			}
651
		} else {
652
			$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
653
654
			$uniqueUsers = [];
655
			foreach ($groups as $group) {
656
				foreach($group->getUsers() as $uid => $displayName) {
657
					$uniqueUsers[$uid] = true;
658
				}
659
			}
660
661
			$userCount = count($uniqueUsers);
662
		}
663
664
		return new DataResponse(
665
			[
666
				'totalUsers' => $userCount
667
			]
668
		);
669
	}
670
671
672
	/**
673
	 * Set the displayName of a user
674
	 *
675
	 * @NoAdminRequired
676
	 * @NoSubadminRequired
677
	 * @PasswordConfirmationRequired
678
	 * @todo merge into saveUserSettings
679
	 *
680
	 * @param string $username
681
	 * @param string $displayName
682
	 * @return DataResponse
683
	 */
684
	public function setDisplayName($username, $displayName) {
685
		$currentUser = $this->userSession->getUser();
686
		$user = $this->userManager->get($username);
687
688
		if ($user === null ||
689
			!$user->canChangeDisplayName() ||
690
			(
691
				!$this->groupManager->isAdmin($currentUser->getUID()) &&
692
				!$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
693
				$currentUser->getUID() !== $username
694
695
			)
696
		) {
697
			return new DataResponse([
698
				'status' => 'error',
699
				'data' => [
700
					'message' => $this->l10n->t('Authentication error'),
701
				],
702
			]);
703
		}
704
705
		$userData = $this->accountManager->getUser($user);
706
		$userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
707
708
709
		try {
710
			$this->saveUserSettings($user, $userData);
711
			return new DataResponse([
712
				'status' => 'success',
713
				'data' => [
714
					'message' => $this->l10n->t('Your full name has been changed.'),
715
					'username' => $username,
716
					'displayName' => $displayName,
717
				],
718
			]);
719
		} catch (ForbiddenException $e) {
720
			return new DataResponse([
721
				'status' => 'error',
722
				'data' => [
723
					'message' => $e->getMessage(),
724
					'displayName' => $user->getDisplayName(),
725
				],
726
			]);
727
		}
728
	}
729
730
	/**
731
	 * Set the mail address of a user
732
	 *
733
	 * @NoAdminRequired
734
	 * @NoSubadminRequired
735
	 * @PasswordConfirmationRequired
736
	 *
737
	 * @param string $id
738
	 * @param string $mailAddress
739
	 * @return DataResponse
740
	 */
741
	public function setEMailAddress($id, $mailAddress) {
742
		$user = $this->userManager->get($id);
743 View Code Duplication
		if (!$this->isAdmin
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
744
			&& !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
745
		) {
746
			return new DataResponse(
747
				array(
748
					'status' => 'error',
749
					'data' => array(
750
						'message' => (string)$this->l10n->t('Forbidden')
751
					)
752
				),
753
				Http::STATUS_FORBIDDEN
754
			);
755
		}
756
757
		if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
758
			return new DataResponse(
759
				array(
760
					'status' => 'error',
761
					'data' => array(
762
						'message' => (string)$this->l10n->t('Invalid mail address')
763
					)
764
				),
765
				Http::STATUS_UNPROCESSABLE_ENTITY
766
			);
767
		}
768
769
		if (!$user) {
770
			return new DataResponse(
771
				array(
772
					'status' => 'error',
773
					'data' => array(
774
						'message' => (string)$this->l10n->t('Invalid user')
775
					)
776
				),
777
				Http::STATUS_UNPROCESSABLE_ENTITY
778
			);
779
		}
780
		// this is the only permission a backend provides and is also used
781
		// for the permission of setting a email address
782
		if (!$user->canChangeDisplayName()) {
783
			return new DataResponse(
784
				array(
785
					'status' => 'error',
786
					'data' => array(
787
						'message' => (string)$this->l10n->t('Unable to change mail address')
788
					)
789
				),
790
				Http::STATUS_FORBIDDEN
791
			);
792
		}
793
794
		$userData = $this->accountManager->getUser($user);
795
		$userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
796
797
		try {
798
			$this->saveUserSettings($user, $userData);
799
			return new DataResponse(
800
				array(
801
					'status' => 'success',
802
					'data' => array(
803
						'username' => $id,
804
						'mailAddress' => $mailAddress,
805
						'message' => (string)$this->l10n->t('Email saved')
806
					)
807
				),
808
				Http::STATUS_OK
809
			);
810
		} catch (ForbiddenException $e) {
811
			return new DataResponse([
812
				'status' => 'error',
813
				'data' => [
814
					'message' => $e->getMessage()
815
				],
816
			]);
817
		}
818
	}
819
820
}
821