Completed
Pull Request — master (#4244)
by Morris
12:45
created
settings/templates/email.new_user.php 1 patch
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -13,7 +13,7 @@  discard block
 block discarded – undo
13 13
 		<tr style="padding:0;text-align:left;vertical-align:top">
14 14
 			<td class="center" align="center" valign="top" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
15 15
 				<center data-parsed="" style="min-width:580px;width:100%">
16
-					<table align="center" class="wrapper header float-center" style="Margin:0 auto;background:#8a8a8a;background-color:<?php p($theme->getColorPrimary());?>;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%">
16
+					<table align="center" class="wrapper header float-center" style="Margin:0 auto;background:#8a8a8a;background-color:<?php p($theme->getColorPrimary()); ?>;border-collapse:collapse;border-spacing:0;float:none;margin:0 auto;padding:0;text-align:center;vertical-align:top;width:100%">
17 17
 						<tr style="padding:0;text-align:left;vertical-align:top">
18 18
 							<td class="wrapper-inner" style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:20px;text-align:left;vertical-align:top;word-wrap:break-word">
19 19
 								<table align="center" class="container" style="Margin:0 auto;background:0 0;border-collapse:collapse;border-spacing:0;margin:0 auto;padding:0;text-align:inherit;vertical-align:top;width:580px">
@@ -47,7 +47,7 @@  discard block
 block discarded – undo
47 47
 						<tbody>
48 48
 						<tr style="padding:0;text-align:left;vertical-align:top">
49 49
 							<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
50
-								<h1 class="text-center" style="Margin:0;Margin-bottom:10px;color:inherit;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:24px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;text-align:center;word-wrap:normal"><?php p($l->t('Welcome aboard %s', [$_['displayname']]));?></h1>
50
+								<h1 class="text-center" style="Margin:0;Margin-bottom:10px;color:inherit;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:24px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;text-align:center;word-wrap:normal"><?php p($l->t('Welcome aboard %s', [$_['displayname']])); ?></h1>
51 51
 							</td>
52 52
 						</tr>
53 53
 						</tbody>
@@ -80,7 +80,7 @@  discard block
 block discarded – undo
80 80
 														<table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%">
81 81
 															<tr style="padding:0;text-align:left;vertical-align:top">
82 82
 																<th style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left">
83
-																	<p class="text-left" style="Margin:0;Margin-bottom:10px;color:#777;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;text-align:left"><?php p($l->t('You have now an Nextcloud account, you can add, protect, and share your data.'));?></p>
83
+																	<p class="text-left" style="Margin:0;Margin-bottom:10px;color:#777;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;text-align:left"><?php p($l->t('You have now an Nextcloud account, you can add, protect, and share your data.')); ?></p>
84 84
 																</th>
85 85
 																<th class="expander" style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0!important;text-align:left;visibility:hidden;width:0"></th>
86 86
 															</tr>
@@ -96,7 +96,7 @@  discard block
 block discarded – undo
96 96
 														<table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%">
97 97
 															<tr style="padding:0;text-align:left;vertical-align:top">
98 98
 																<th style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;text-align:left">
99
-																	<p class="text-left" style="Margin:0;Margin-bottom:10px;color:#777;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;text-align:left"><?php p($l->t('Your username is: %s', [$_['username']]));?></p>
99
+																	<p class="text-left" style="Margin:0;Margin-bottom:10px;color:#777;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;margin-bottom:10px;padding:0;text-align:left"><?php p($l->t('Your username is: %s', [$_['username']])); ?></p>
100 100
 																</th>
101 101
 																<th class="expander" style="Margin:0;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0!important;text-align:left;visibility:hidden;width:0"></th>
102 102
 															</tr>
@@ -125,8 +125,8 @@  discard block
 block discarded – undo
125 125
 																				<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;border-collapse:collapse!important;color:#0a0a0a;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
126 126
 																					<table style="border-collapse:collapse;border-spacing:0;padding:0;text-align:left;vertical-align:top;width:100%">
127 127
 																						<tr style="padding:0;text-align:left;vertical-align:top">
128
-																							<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;background:<?php p($theme->getColorPrimary());?>;border:0 solid <?php p($theme->getColorPrimary());?>;border-collapse:collapse!important;color:#fefefe;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
129
-																								<a href="<?php p($_['url']);?>" style="Margin:0;border:0 solid <?php p($theme->getColorPrimary());?>;border-radius:2px;color:#fefefe;display:inline-block;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:regular;line-height:1.3;margin:0;padding:10px 25px 10px 25px;text-align:left;text-decoration:none"><?php if($_['generated_password']) { p($l->t('Set your password')); } else { p($l->t('Go to %s', [$theme->getName()])); } ?></a>
128
+																							<td style="-moz-hyphens:auto;-webkit-hyphens:auto;Margin:0;background:<?php p($theme->getColorPrimary()); ?>;border:0 solid <?php p($theme->getColorPrimary()); ?>;border-collapse:collapse!important;color:#fefefe;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:400;hyphens:auto;line-height:1.3;margin:0;padding:0;text-align:left;vertical-align:top;word-wrap:break-word">
129
+																								<a href="<?php p($_['url']); ?>" style="Margin:0;border:0 solid <?php p($theme->getColorPrimary()); ?>;border-radius:2px;color:#fefefe;display:inline-block;font-family:Lucida Grande,Geneva,Verdana,sans-serif;font-size:16px;font-weight:regular;line-height:1.3;margin:0;padding:10px 25px 10px 25px;text-align:left;text-decoration:none"><?php if ($_['generated_password']) { p($l->t('Set your password')); } else { p($l->t('Go to %s', [$theme->getName()])); } ?></a>
130 130
 																							</td>
131 131
 																						</tr>
132 132
 																					</table>
Please login to merge, or discard this patch.
settings/templates/email.new_user_plain_text.php 1 patch
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -1,13 +1,13 @@
 block discarded – undo
1
-<?php p($l->t('Welcome aboard %s', [$_['displayname']]));?>
1
+<?php p($l->t('Welcome aboard %s', [$_['displayname']])); ?>
2 2
 
3
-<?php p($l->t('You have now an Nextcloud account, you can add, protect, and share your data.'));?>
3
+<?php p($l->t('You have now an Nextcloud account, you can add, protect, and share your data.')); ?>
4 4
 
5
-<?php if($_['generated_password']) { p($l->t('Set your password')); } else { p($l->t('Go to %s', [$theme->getName()])); } ?>: <?php p($_['url']); ?>
5
+<?php if ($_['generated_password']) { p($l->t('Set your password')); } else { p($l->t('Go to %s', [$theme->getName()])); } ?>: <?php p($_['url']); ?>
6 6
 
7
-<?php p($l->t('Install Client') . ': ' . $_['url_client_install']); ?>
7
+<?php p($l->t('Install Client').': '.$_['url_client_install']); ?>
8 8
 
9 9
 	--
10
-<?php p($theme->getName() . ' - ' . $theme->getSlogan()); ?>
10
+<?php p($theme->getName().' - '.$theme->getSlogan()); ?>
11 11
 <?php p($l->t('This is an automatically generated email, please do not reply.')); ?>
12 12
 
13 13
 
Please login to merge, or discard this patch.
settings/Controller/UsersController.php 1 patch
Indentation   +810 added lines, -810 removed lines patch added patch discarded remove patch
@@ -57,815 +57,815 @@
 block discarded – undo
57 57
  * @package OC\Settings\Controller
58 58
  */
59 59
 class UsersController extends Controller {
60
-	/** @var IL10N */
61
-	private $l10n;
62
-	/** @var IUserSession */
63
-	private $userSession;
64
-	/** @var bool */
65
-	private $isAdmin;
66
-	/** @var IUserManager */
67
-	private $userManager;
68
-	/** @var IGroupManager */
69
-	private $groupManager;
70
-	/** @var IConfig */
71
-	private $config;
72
-	/** @var ILogger */
73
-	private $log;
74
-	/** @var \OC_Defaults */
75
-	private $defaults;
76
-	/** @var IMailer */
77
-	private $mailer;
78
-	/** @var string */
79
-	private $fromMailAddress;
80
-	/** @var IURLGenerator */
81
-	private $urlGenerator;
82
-	/** @var bool contains the state of the encryption app */
83
-	private $isEncryptionAppEnabled;
84
-	/** @var bool contains the state of the admin recovery setting */
85
-	private $isRestoreEnabled = false;
86
-	/** @var IAvatarManager */
87
-	private $avatarManager;
88
-	/** @var AccountManager */
89
-	private $accountManager;
90
-	/** @var ISecureRandom */
91
-	private $secureRandom;
92
-	/** @var ITimeFactory */
93
-	private $timeFactory;
94
-	/** @var ICrypto */
95
-	private $crypto;
96
-
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 \OC_Defaults $defaults
109
-	 * @param IMailer $mailer
110
-	 * @param string $fromMailAddress
111
-	 * @param IURLGenerator $urlGenerator
112
-	 * @param IAppManager $appManager
113
-	 * @param IAvatarManager $avatarManager
114
-	 * @param AccountManager $accountManager
115
-	 * @param ISecureRandom $secureRandom
116
-	 * @param ITimeFactory $timeFactory
117
-	 * @param ICrypto $crypto
118
-	 */
119
-	public function __construct($appName,
120
-								IRequest $request,
121
-								IUserManager $userManager,
122
-								IGroupManager $groupManager,
123
-								IUserSession $userSession,
124
-								IConfig $config,
125
-								$isAdmin,
126
-								IL10N $l10n,
127
-								ILogger $log,
128
-								\OC_Defaults $defaults,
129
-								IMailer $mailer,
130
-								$fromMailAddress,
131
-								IURLGenerator $urlGenerator,
132
-								IAppManager $appManager,
133
-								IAvatarManager $avatarManager,
134
-								AccountManager $accountManager,
135
-								ISecureRandom $secureRandom,
136
-								ITimeFactory $timeFactory,
137
-								ICrypto $crypto) {
138
-		parent::__construct($appName, $request);
139
-		$this->userManager = $userManager;
140
-		$this->groupManager = $groupManager;
141
-		$this->userSession = $userSession;
142
-		$this->config = $config;
143
-		$this->isAdmin = $isAdmin;
144
-		$this->l10n = $l10n;
145
-		$this->log = $log;
146
-		$this->defaults = $defaults;
147
-		$this->mailer = $mailer;
148
-		$this->fromMailAddress = $fromMailAddress;
149
-		$this->urlGenerator = $urlGenerator;
150
-		$this->avatarManager = $avatarManager;
151
-		$this->accountManager = $accountManager;
152
-		$this->secureRandom = $secureRandom;
153
-		$this->timeFactory = $timeFactory;
154
-		$this->crypto = $crypto;
155
-
156
-		// check for encryption state - TODO see formatUserForIndex
157
-		$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
158
-		if($this->isEncryptionAppEnabled) {
159
-			// putting this directly in empty is possible in PHP 5.5+
160
-			$result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
161
-			$this->isRestoreEnabled = !empty($result);
162
-		}
163
-	}
164
-
165
-	/**
166
-	 * @param IUser $user
167
-	 * @param array $userGroups
168
-	 * @return array
169
-	 */
170
-	private function formatUserForIndex(IUser $user, array $userGroups = null) {
171
-
172
-		// TODO: eliminate this encryption specific code below and somehow
173
-		// hook in additional user info from other apps
174
-
175
-		// recovery isn't possible if admin or user has it disabled and encryption
176
-		// is enabled - so we eliminate the else paths in the conditional tree
177
-		// below
178
-		$restorePossible = false;
179
-
180
-		if ($this->isEncryptionAppEnabled) {
181
-			if ($this->isRestoreEnabled) {
182
-				// check for the users recovery setting
183
-				$recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
184
-				// method call inside empty is possible with PHP 5.5+
185
-				$recoveryModeEnabled = !empty($recoveryMode);
186
-				if ($recoveryModeEnabled) {
187
-					// user also has recovery mode enabled
188
-					$restorePossible = true;
189
-				}
190
-			}
191
-		} else {
192
-			// recovery is possible if encryption is disabled (plain files are
193
-			// available)
194
-			$restorePossible = true;
195
-		}
196
-
197
-		$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
198
-		foreach($subAdminGroups as $key => $subAdminGroup) {
199
-			$subAdminGroups[$key] = $subAdminGroup->getGID();
200
-		}
201
-
202
-		$displayName = $user->getEMailAddress();
203
-		if (is_null($displayName)) {
204
-			$displayName = '';
205
-		}
206
-
207
-		$avatarAvailable = false;
208
-		try {
209
-			$avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
210
-		} catch (\Exception $e) {
211
-			//No avatar yet
212
-		}
213
-
214
-		return [
215
-			'name' => $user->getUID(),
216
-			'displayname' => $user->getDisplayName(),
217
-			'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
218
-			'subadmin' => $subAdminGroups,
219
-			'quota' => $user->getQuota(),
220
-			'storageLocation' => $user->getHome(),
221
-			'lastLogin' => $user->getLastLogin() * 1000,
222
-			'backend' => $user->getBackendClassName(),
223
-			'email' => $displayName,
224
-			'isRestoreDisabled' => !$restorePossible,
225
-			'isAvatarAvailable' => $avatarAvailable,
226
-		];
227
-	}
228
-
229
-	/**
230
-	 * @param array $userIDs Array with schema [$uid => $displayName]
231
-	 * @return IUser[]
232
-	 */
233
-	private function getUsersForUID(array $userIDs) {
234
-		$users = [];
235
-		foreach ($userIDs as $uid => $displayName) {
236
-			$users[$uid] = $this->userManager->get($uid);
237
-		}
238
-		return $users;
239
-	}
240
-
241
-	/**
242
-	 * @NoAdminRequired
243
-	 *
244
-	 * @param int $offset
245
-	 * @param int $limit
246
-	 * @param string $gid GID to filter for
247
-	 * @param string $pattern Pattern to search for in the username
248
-	 * @param string $backend Backend to filter for (class-name)
249
-	 * @return DataResponse
250
-	 *
251
-	 * TODO: Tidy up and write unit tests - code is mainly static method calls
252
-	 */
253
-	public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
254
-		// FIXME: The JS sends the group '_everyone' instead of no GID for the "all users" group.
255
-		if($gid === '_everyone') {
256
-			$gid = '';
257
-		}
258
-
259
-		// Remove backends
260
-		if(!empty($backend)) {
261
-			$activeBackends = $this->userManager->getBackends();
262
-			$this->userManager->clearBackends();
263
-			foreach($activeBackends as $singleActiveBackend) {
264
-				if($backend === get_class($singleActiveBackend)) {
265
-					$this->userManager->registerBackend($singleActiveBackend);
266
-					break;
267
-				}
268
-			}
269
-		}
270
-
271
-		$users = [];
272
-		if ($this->isAdmin) {
273
-
274
-			if($gid !== '') {
275
-				$batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
276
-			} else {
277
-				$batch = $this->userManager->search($pattern, $limit, $offset);
278
-			}
279
-
280
-			foreach ($batch as $user) {
281
-				$users[] = $this->formatUserForIndex($user);
282
-			}
283
-
284
-		} else {
285
-			$subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
286
-			// New class returns IGroup[] so convert back
287
-			$gids = [];
288
-			foreach ($subAdminOfGroups as $group) {
289
-				$gids[] = $group->getGID();
290
-			}
291
-			$subAdminOfGroups = $gids;
292
-
293
-			// Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
294
-			if($gid !== '' && !in_array($gid, $subAdminOfGroups)) {
295
-				$gid = '';
296
-			}
297
-
298
-			// Batch all groups the user is subadmin of when a group is specified
299
-			$batch = [];
300
-			if($gid === '') {
301
-				foreach($subAdminOfGroups as $group) {
302
-					$groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
303
-
304
-					foreach($groupUsers as $uid => $displayName) {
305
-						$batch[$uid] = $displayName;
306
-					}
307
-				}
308
-			} else {
309
-				$batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
310
-			}
311
-			$batch = $this->getUsersForUID($batch);
312
-
313
-			foreach ($batch as $user) {
314
-				// Only add the groups, this user is a subadmin of
315
-				$userGroups = array_values(array_intersect(
316
-					$this->groupManager->getUserGroupIds($user),
317
-					$subAdminOfGroups
318
-				));
319
-				$users[] = $this->formatUserForIndex($user, $userGroups);
320
-			}
321
-		}
322
-
323
-		return new DataResponse($users);
324
-	}
325
-
326
-	/**
327
-	 * @NoAdminRequired
328
-	 * @PasswordConfirmationRequired
329
-	 *
330
-	 * @param string $username
331
-	 * @param string $password
332
-	 * @param array $groups
333
-	 * @param string $email
334
-	 * @return DataResponse
335
-	 */
336
-	public function create($username, $password, array $groups=array(), $email='') {
337
-		if($email !== '' && !$this->mailer->validateMailAddress($email)) {
338
-			return new DataResponse(
339
-				array(
340
-					'message' => (string)$this->l10n->t('Invalid mail address')
341
-				),
342
-				Http::STATUS_UNPROCESSABLE_ENTITY
343
-			);
344
-		}
345
-
346
-		$currentUser = $this->userSession->getUser();
347
-
348
-		if (!$this->isAdmin) {
349
-			if (!empty($groups)) {
350
-				foreach ($groups as $key => $group) {
351
-					$groupObject = $this->groupManager->get($group);
352
-					if($groupObject === null) {
353
-						unset($groups[$key]);
354
-						continue;
355
-					}
356
-
357
-					if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
358
-						unset($groups[$key]);
359
-					}
360
-				}
361
-			}
362
-
363
-			if (empty($groups)) {
364
-				return new DataResponse(
365
-					array(
366
-						'message' => $this->l10n->t('No valid group selected'),
367
-					),
368
-					Http::STATUS_FORBIDDEN
369
-				);
370
-			}
371
-		}
372
-
373
-		if ($this->userManager->userExists($username)) {
374
-			return new DataResponse(
375
-				array(
376
-					'message' => (string)$this->l10n->t('A user with that name already exists.')
377
-				),
378
-				Http::STATUS_CONFLICT
379
-			);
380
-		}
381
-
382
-		$generatedPassword = false;
383
-		if ($password === '') {
384
-			if ($email === '') {
385
-				return new DataResponse(
386
-					array(
387
-						'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
388
-					),
389
-					Http::STATUS_UNPROCESSABLE_ENTITY
390
-				);
391
-			}
392
-
393
-			$password = $this->secureRandom->generate(32);
394
-			$generatedPassword = true;
395
-		}
396
-
397
-		try {
398
-			$user = $this->userManager->createUser($username, $password);
399
-		} catch (\Exception $exception) {
400
-			$message = $exception->getMessage();
401
-			if (!$message) {
402
-				$message = $this->l10n->t('Unable to create user.');
403
-			}
404
-			return new DataResponse(
405
-				array(
406
-					'message' => (string) $message,
407
-				),
408
-				Http::STATUS_FORBIDDEN
409
-			);
410
-		}
411
-
412
-		if($user instanceof IUser) {
413
-			if($groups !== null) {
414
-				foreach($groups as $groupName) {
415
-					$group = $this->groupManager->get($groupName);
416
-
417
-					if(empty($group)) {
418
-						$group = $this->groupManager->createGroup($groupName);
419
-					}
420
-					$group->addUser($user);
421
-				}
422
-			}
423
-			/**
424
-			 * Send new user mail only if a mail is set
425
-			 */
426
-			if($email !== '') {
427
-				$user->setEMailAddress($email);
428
-
429
-				if ($generatedPassword) {
430
-					$token = $this->secureRandom->generate(
431
-						21,
432
-						ISecureRandom::CHAR_DIGITS .
433
-						ISecureRandom::CHAR_LOWER .
434
-						ISecureRandom::CHAR_UPPER
435
-					);
436
-					$tokenValue = $this->timeFactory->getTime() . ':' . $token;
437
-					$mailAddress = !is_null($user->getEMailAddress()) ? $user->getEMailAddress() : '';
438
-					$encryptedValue = $this->crypto->encrypt($tokenValue, $mailAddress . $this->config->getSystemValue('secret'));
439
-					$this->config->setUserValue($username, 'core', 'lostpassword', $encryptedValue);
440
-
441
-					$link = $this->urlGenerator->linkToRouteAbsolute('core.lost.resetform', ['userId' => $username, 'token' => $token]);
442
-				} else {
443
-					$link = $this->urlGenerator->getAbsoluteURL('/');
444
-				}
445
-
446
-				$displayname = $user->getDisplayName();
447
-
448
-				// data for the mail template
449
-				$mailData = array(
450
-					'username' => $username,
451
-					'url' => $link,
452
-					'generated_password' => $generatedPassword,
453
-					'url_client_install' => 'https://nextcloud.com/install/#install-clients',
454
-					'displayname' => ($username !== $displayname) ? $displayname : '',
455
-				);
456
-
457
-				$mail = new TemplateResponse('settings', 'email.new_user', $mailData, 'blank');
458
-				$mailContent = $mail->render();
459
-
460
-				$mail = new TemplateResponse('settings', 'email.new_user_plain_text', $mailData, 'blank');
461
-				$plainTextMailContent = $mail->render();
462
-
463
-				$subject = $this->l10n->t('Your %s account was created', [$this->defaults->getName()]);
464
-
465
-				try {
466
-					$message = $this->mailer->createMessage();
467
-					$message->setTo([$email => $username]);
468
-					$message->setSubject($subject);
469
-					$message->setHtmlBody($mailContent);
470
-					$message->setPlainBody($plainTextMailContent);
471
-					$message->setFrom([$this->fromMailAddress => $this->defaults->getName()]);
472
-					$this->mailer->send($message);
473
-				} catch(\Exception $e) {
474
-					$this->log->error("Can't send new user mail to $email: " . $e->getMessage(), array('app' => 'settings'));
475
-				}
476
-			}
477
-			// fetch users groups
478
-			$userGroups = $this->groupManager->getUserGroupIds($user);
479
-
480
-			return new DataResponse(
481
-				$this->formatUserForIndex($user, $userGroups),
482
-				Http::STATUS_CREATED
483
-			);
484
-		}
485
-
486
-		return new DataResponse(
487
-			array(
488
-				'message' => (string)$this->l10n->t('Unable to create user.')
489
-			),
490
-			Http::STATUS_FORBIDDEN
491
-		);
492
-
493
-	}
494
-
495
-	/**
496
-	 * @NoAdminRequired
497
-	 * @PasswordConfirmationRequired
498
-	 *
499
-	 * @param string $id
500
-	 * @return DataResponse
501
-	 */
502
-	public function destroy($id) {
503
-		$userId = $this->userSession->getUser()->getUID();
504
-		$user = $this->userManager->get($id);
505
-
506
-		if($userId === $id) {
507
-			return new DataResponse(
508
-				array(
509
-					'status' => 'error',
510
-					'data' => array(
511
-						'message' => (string)$this->l10n->t('Unable to delete user.')
512
-					)
513
-				),
514
-				Http::STATUS_FORBIDDEN
515
-			);
516
-		}
517
-
518
-		if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
519
-			return new DataResponse(
520
-				array(
521
-					'status' => 'error',
522
-					'data' => array(
523
-						'message' => (string)$this->l10n->t('Authentication error')
524
-					)
525
-				),
526
-				Http::STATUS_FORBIDDEN
527
-			);
528
-		}
529
-
530
-		if($user) {
531
-			if($user->delete()) {
532
-				return new DataResponse(
533
-					array(
534
-						'status' => 'success',
535
-						'data' => array(
536
-							'username' => $id
537
-						)
538
-					),
539
-					Http::STATUS_NO_CONTENT
540
-				);
541
-			}
542
-		}
543
-
544
-		return new DataResponse(
545
-			array(
546
-				'status' => 'error',
547
-				'data' => array(
548
-					'message' => (string)$this->l10n->t('Unable to delete user.')
549
-				)
550
-			),
551
-			Http::STATUS_FORBIDDEN
552
-		);
553
-	}
554
-
555
-	/**
556
-	 * @NoAdminRequired
557
-	 * @NoSubadminRequired
558
-	 * @PasswordConfirmationRequired
559
-	 *
560
-	 * @param string $avatarScope
561
-	 * @param string $displayname
562
-	 * @param string $displaynameScope
563
-	 * @param string $phone
564
-	 * @param string $phoneScope
565
-	 * @param string $email
566
-	 * @param string $emailScope
567
-	 * @param string $website
568
-	 * @param string $websiteScope
569
-	 * @param string $address
570
-	 * @param string $addressScope
571
-	 * @param string $twitter
572
-	 * @param string $twitterScope
573
-	 * @return DataResponse
574
-	 */
575
-	public function setUserSettings($avatarScope,
576
-									$displayname,
577
-									$displaynameScope,
578
-									$phone,
579
-									$phoneScope,
580
-									$email,
581
-									$emailScope,
582
-									$website,
583
-									$websiteScope,
584
-									$address,
585
-									$addressScope,
586
-									$twitter,
587
-									$twitterScope
588
-	) {
589
-
590
-		if(!empty($email) && !$this->mailer->validateMailAddress($email)) {
591
-			return new DataResponse(
592
-				array(
593
-					'status' => 'error',
594
-					'data' => array(
595
-						'message' => (string)$this->l10n->t('Invalid mail address')
596
-					)
597
-				),
598
-				Http::STATUS_UNPROCESSABLE_ENTITY
599
-			);
600
-		}
601
-
602
-		$data = [
603
-			AccountManager::PROPERTY_AVATAR =>  ['scope' => $avatarScope],
604
-			AccountManager::PROPERTY_DISPLAYNAME => ['value' => $displayname, 'scope' => $displaynameScope],
605
-			AccountManager::PROPERTY_EMAIL=> ['value' => $email, 'scope' => $emailScope],
606
-			AccountManager::PROPERTY_WEBSITE => ['value' => $website, 'scope' => $websiteScope],
607
-			AccountManager::PROPERTY_ADDRESS => ['value' => $address, 'scope' => $addressScope],
608
-			AccountManager::PROPERTY_PHONE => ['value' => $phone, 'scope' => $phoneScope],
609
-			AccountManager::PROPERTY_TWITTER => ['value' => $twitter, 'scope' => $twitterScope]
610
-		];
611
-
612
-		$user = $this->userSession->getUser();
613
-
614
-		try {
615
-			$this->saveUserSettings($user, $data);
616
-			return new DataResponse(
617
-				array(
618
-					'status' => 'success',
619
-					'data' => array(
620
-						'userId' => $user->getUID(),
621
-						'avatarScope' => $avatarScope,
622
-						'displayname' => $displayname,
623
-						'displaynameScope' => $displaynameScope,
624
-						'email' => $email,
625
-						'emailScope' => $emailScope,
626
-						'website' => $website,
627
-						'websiteScope' => $websiteScope,
628
-						'address' => $address,
629
-						'addressScope' => $addressScope,
630
-						'message' => (string)$this->l10n->t('Settings saved')
631
-					)
632
-				),
633
-				Http::STATUS_OK
634
-			);
635
-		} catch (ForbiddenException $e) {
636
-			return new DataResponse([
637
-				'status' => 'error',
638
-				'data' => [
639
-					'message' => $e->getMessage()
640
-				],
641
-			]);
642
-		}
643
-
644
-	}
645
-
646
-
647
-	/**
648
-	 * update account manager with new user data
649
-	 *
650
-	 * @param IUser $user
651
-	 * @param array $data
652
-	 * @throws ForbiddenException
653
-	 */
654
-	protected function saveUserSettings(IUser $user, $data) {
655
-
656
-		// keep the user back-end up-to-date with the latest display name and email
657
-		// address
658
-		$oldDisplayName = $user->getDisplayName();
659
-		$oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
660
-		if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
661
-			&& $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
662
-		) {
663
-			$result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
664
-			if ($result === false) {
665
-				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
666
-			}
667
-		}
668
-
669
-		$oldEmailAddress = $user->getEMailAddress();
670
-		$oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
671
-		if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
672
-			&& $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
673
-		) {
674
-			// this is the only permission a backend provides and is also used
675
-			// for the permission of setting a email address
676
-			if (!$user->canChangeDisplayName()) {
677
-				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
678
-			}
679
-			$user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
680
-		}
681
-
682
-		$this->accountManager->updateUser($user, $data);
683
-	}
684
-
685
-	/**
686
-	 * Count all unique users visible for the current admin/subadmin.
687
-	 *
688
-	 * @NoAdminRequired
689
-	 *
690
-	 * @return DataResponse
691
-	 */
692
-	public function stats() {
693
-		$userCount = 0;
694
-		if ($this->isAdmin) {
695
-			$countByBackend = $this->userManager->countUsers();
696
-
697
-			if (!empty($countByBackend)) {
698
-				foreach ($countByBackend as $count) {
699
-					$userCount += $count;
700
-				}
701
-			}
702
-		} else {
703
-			$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
704
-
705
-			$uniqueUsers = [];
706
-			foreach ($groups as $group) {
707
-				foreach($group->getUsers() as $uid => $displayName) {
708
-					$uniqueUsers[$uid] = true;
709
-				}
710
-			}
711
-
712
-			$userCount = count($uniqueUsers);
713
-		}
714
-
715
-		return new DataResponse(
716
-			[
717
-				'totalUsers' => $userCount
718
-			]
719
-		);
720
-	}
721
-
722
-
723
-	/**
724
-	 * Set the displayName of a user
725
-	 *
726
-	 * @NoAdminRequired
727
-	 * @NoSubadminRequired
728
-	 * @PasswordConfirmationRequired
729
-	 * @todo merge into saveUserSettings
730
-	 *
731
-	 * @param string $username
732
-	 * @param string $displayName
733
-	 * @return DataResponse
734
-	 */
735
-	public function setDisplayName($username, $displayName) {
736
-		$currentUser = $this->userSession->getUser();
737
-		$user = $this->userManager->get($username);
738
-
739
-		if ($user === null ||
740
-			!$user->canChangeDisplayName() ||
741
-			(
742
-				!$this->groupManager->isAdmin($currentUser->getUID()) &&
743
-				!$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
744
-				$currentUser->getUID() !== $username
745
-
746
-			)
747
-		) {
748
-			return new DataResponse([
749
-				'status' => 'error',
750
-				'data' => [
751
-					'message' => $this->l10n->t('Authentication error'),
752
-				],
753
-			]);
754
-		}
755
-
756
-		$userData = $this->accountManager->getUser($user);
757
-		$userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
758
-
759
-
760
-		try {
761
-			$this->saveUserSettings($user, $userData);
762
-			return new DataResponse([
763
-				'status' => 'success',
764
-				'data' => [
765
-					'message' => $this->l10n->t('Your full name has been changed.'),
766
-					'username' => $username,
767
-					'displayName' => $displayName,
768
-				],
769
-			]);
770
-		} catch (ForbiddenException $e) {
771
-			return new DataResponse([
772
-				'status' => 'error',
773
-				'data' => [
774
-					'message' => $e->getMessage(),
775
-					'displayName' => $user->getDisplayName(),
776
-				],
777
-			]);
778
-		}
779
-	}
780
-
781
-	/**
782
-	 * Set the mail address of a user
783
-	 *
784
-	 * @NoAdminRequired
785
-	 * @NoSubadminRequired
786
-	 * @PasswordConfirmationRequired
787
-	 *
788
-	 * @param string $id
789
-	 * @param string $mailAddress
790
-	 * @return DataResponse
791
-	 */
792
-	public function setEMailAddress($id, $mailAddress) {
793
-		$user = $this->userManager->get($id);
794
-		if (!$this->isAdmin
795
-			&& !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
796
-		) {
797
-			return new DataResponse(
798
-				array(
799
-					'status' => 'error',
800
-					'data' => array(
801
-						'message' => (string)$this->l10n->t('Forbidden')
802
-					)
803
-				),
804
-				Http::STATUS_FORBIDDEN
805
-			);
806
-		}
807
-
808
-		if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
809
-			return new DataResponse(
810
-				array(
811
-					'status' => 'error',
812
-					'data' => array(
813
-						'message' => (string)$this->l10n->t('Invalid mail address')
814
-					)
815
-				),
816
-				Http::STATUS_UNPROCESSABLE_ENTITY
817
-			);
818
-		}
819
-
820
-		if (!$user) {
821
-			return new DataResponse(
822
-				array(
823
-					'status' => 'error',
824
-					'data' => array(
825
-						'message' => (string)$this->l10n->t('Invalid user')
826
-					)
827
-				),
828
-				Http::STATUS_UNPROCESSABLE_ENTITY
829
-			);
830
-		}
831
-		// this is the only permission a backend provides and is also used
832
-		// for the permission of setting a email address
833
-		if (!$user->canChangeDisplayName()) {
834
-			return new DataResponse(
835
-				array(
836
-					'status' => 'error',
837
-					'data' => array(
838
-						'message' => (string)$this->l10n->t('Unable to change mail address')
839
-					)
840
-				),
841
-				Http::STATUS_FORBIDDEN
842
-			);
843
-		}
844
-
845
-		$userData = $this->accountManager->getUser($user);
846
-		$userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
847
-
848
-		try {
849
-			$this->saveUserSettings($user, $userData);
850
-			return new DataResponse(
851
-				array(
852
-					'status' => 'success',
853
-					'data' => array(
854
-						'username' => $id,
855
-						'mailAddress' => $mailAddress,
856
-						'message' => (string)$this->l10n->t('Email saved')
857
-					)
858
-				),
859
-				Http::STATUS_OK
860
-			);
861
-		} catch (ForbiddenException $e) {
862
-			return new DataResponse([
863
-				'status' => 'error',
864
-				'data' => [
865
-					'message' => $e->getMessage()
866
-				],
867
-			]);
868
-		}
869
-	}
60
+    /** @var IL10N */
61
+    private $l10n;
62
+    /** @var IUserSession */
63
+    private $userSession;
64
+    /** @var bool */
65
+    private $isAdmin;
66
+    /** @var IUserManager */
67
+    private $userManager;
68
+    /** @var IGroupManager */
69
+    private $groupManager;
70
+    /** @var IConfig */
71
+    private $config;
72
+    /** @var ILogger */
73
+    private $log;
74
+    /** @var \OC_Defaults */
75
+    private $defaults;
76
+    /** @var IMailer */
77
+    private $mailer;
78
+    /** @var string */
79
+    private $fromMailAddress;
80
+    /** @var IURLGenerator */
81
+    private $urlGenerator;
82
+    /** @var bool contains the state of the encryption app */
83
+    private $isEncryptionAppEnabled;
84
+    /** @var bool contains the state of the admin recovery setting */
85
+    private $isRestoreEnabled = false;
86
+    /** @var IAvatarManager */
87
+    private $avatarManager;
88
+    /** @var AccountManager */
89
+    private $accountManager;
90
+    /** @var ISecureRandom */
91
+    private $secureRandom;
92
+    /** @var ITimeFactory */
93
+    private $timeFactory;
94
+    /** @var ICrypto */
95
+    private $crypto;
96
+
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 \OC_Defaults $defaults
109
+     * @param IMailer $mailer
110
+     * @param string $fromMailAddress
111
+     * @param IURLGenerator $urlGenerator
112
+     * @param IAppManager $appManager
113
+     * @param IAvatarManager $avatarManager
114
+     * @param AccountManager $accountManager
115
+     * @param ISecureRandom $secureRandom
116
+     * @param ITimeFactory $timeFactory
117
+     * @param ICrypto $crypto
118
+     */
119
+    public function __construct($appName,
120
+                                IRequest $request,
121
+                                IUserManager $userManager,
122
+                                IGroupManager $groupManager,
123
+                                IUserSession $userSession,
124
+                                IConfig $config,
125
+                                $isAdmin,
126
+                                IL10N $l10n,
127
+                                ILogger $log,
128
+                                \OC_Defaults $defaults,
129
+                                IMailer $mailer,
130
+                                $fromMailAddress,
131
+                                IURLGenerator $urlGenerator,
132
+                                IAppManager $appManager,
133
+                                IAvatarManager $avatarManager,
134
+                                AccountManager $accountManager,
135
+                                ISecureRandom $secureRandom,
136
+                                ITimeFactory $timeFactory,
137
+                                ICrypto $crypto) {
138
+        parent::__construct($appName, $request);
139
+        $this->userManager = $userManager;
140
+        $this->groupManager = $groupManager;
141
+        $this->userSession = $userSession;
142
+        $this->config = $config;
143
+        $this->isAdmin = $isAdmin;
144
+        $this->l10n = $l10n;
145
+        $this->log = $log;
146
+        $this->defaults = $defaults;
147
+        $this->mailer = $mailer;
148
+        $this->fromMailAddress = $fromMailAddress;
149
+        $this->urlGenerator = $urlGenerator;
150
+        $this->avatarManager = $avatarManager;
151
+        $this->accountManager = $accountManager;
152
+        $this->secureRandom = $secureRandom;
153
+        $this->timeFactory = $timeFactory;
154
+        $this->crypto = $crypto;
155
+
156
+        // check for encryption state - TODO see formatUserForIndex
157
+        $this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
158
+        if($this->isEncryptionAppEnabled) {
159
+            // putting this directly in empty is possible in PHP 5.5+
160
+            $result = $config->getAppValue('encryption', 'recoveryAdminEnabled', 0);
161
+            $this->isRestoreEnabled = !empty($result);
162
+        }
163
+    }
164
+
165
+    /**
166
+     * @param IUser $user
167
+     * @param array $userGroups
168
+     * @return array
169
+     */
170
+    private function formatUserForIndex(IUser $user, array $userGroups = null) {
171
+
172
+        // TODO: eliminate this encryption specific code below and somehow
173
+        // hook in additional user info from other apps
174
+
175
+        // recovery isn't possible if admin or user has it disabled and encryption
176
+        // is enabled - so we eliminate the else paths in the conditional tree
177
+        // below
178
+        $restorePossible = false;
179
+
180
+        if ($this->isEncryptionAppEnabled) {
181
+            if ($this->isRestoreEnabled) {
182
+                // check for the users recovery setting
183
+                $recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
184
+                // method call inside empty is possible with PHP 5.5+
185
+                $recoveryModeEnabled = !empty($recoveryMode);
186
+                if ($recoveryModeEnabled) {
187
+                    // user also has recovery mode enabled
188
+                    $restorePossible = true;
189
+                }
190
+            }
191
+        } else {
192
+            // recovery is possible if encryption is disabled (plain files are
193
+            // available)
194
+            $restorePossible = true;
195
+        }
196
+
197
+        $subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
198
+        foreach($subAdminGroups as $key => $subAdminGroup) {
199
+            $subAdminGroups[$key] = $subAdminGroup->getGID();
200
+        }
201
+
202
+        $displayName = $user->getEMailAddress();
203
+        if (is_null($displayName)) {
204
+            $displayName = '';
205
+        }
206
+
207
+        $avatarAvailable = false;
208
+        try {
209
+            $avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
210
+        } catch (\Exception $e) {
211
+            //No avatar yet
212
+        }
213
+
214
+        return [
215
+            'name' => $user->getUID(),
216
+            'displayname' => $user->getDisplayName(),
217
+            'groups' => (empty($userGroups)) ? $this->groupManager->getUserGroupIds($user) : $userGroups,
218
+            'subadmin' => $subAdminGroups,
219
+            'quota' => $user->getQuota(),
220
+            'storageLocation' => $user->getHome(),
221
+            'lastLogin' => $user->getLastLogin() * 1000,
222
+            'backend' => $user->getBackendClassName(),
223
+            'email' => $displayName,
224
+            'isRestoreDisabled' => !$restorePossible,
225
+            'isAvatarAvailable' => $avatarAvailable,
226
+        ];
227
+    }
228
+
229
+    /**
230
+     * @param array $userIDs Array with schema [$uid => $displayName]
231
+     * @return IUser[]
232
+     */
233
+    private function getUsersForUID(array $userIDs) {
234
+        $users = [];
235
+        foreach ($userIDs as $uid => $displayName) {
236
+            $users[$uid] = $this->userManager->get($uid);
237
+        }
238
+        return $users;
239
+    }
240
+
241
+    /**
242
+     * @NoAdminRequired
243
+     *
244
+     * @param int $offset
245
+     * @param int $limit
246
+     * @param string $gid GID to filter for
247
+     * @param string $pattern Pattern to search for in the username
248
+     * @param string $backend Backend to filter for (class-name)
249
+     * @return DataResponse
250
+     *
251
+     * TODO: Tidy up and write unit tests - code is mainly static method calls
252
+     */
253
+    public function index($offset = 0, $limit = 10, $gid = '', $pattern = '', $backend = '') {
254
+        // FIXME: The JS sends the group '_everyone' instead of no GID for the "all users" group.
255
+        if($gid === '_everyone') {
256
+            $gid = '';
257
+        }
258
+
259
+        // Remove backends
260
+        if(!empty($backend)) {
261
+            $activeBackends = $this->userManager->getBackends();
262
+            $this->userManager->clearBackends();
263
+            foreach($activeBackends as $singleActiveBackend) {
264
+                if($backend === get_class($singleActiveBackend)) {
265
+                    $this->userManager->registerBackend($singleActiveBackend);
266
+                    break;
267
+                }
268
+            }
269
+        }
270
+
271
+        $users = [];
272
+        if ($this->isAdmin) {
273
+
274
+            if($gid !== '') {
275
+                $batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
276
+            } else {
277
+                $batch = $this->userManager->search($pattern, $limit, $offset);
278
+            }
279
+
280
+            foreach ($batch as $user) {
281
+                $users[] = $this->formatUserForIndex($user);
282
+            }
283
+
284
+        } else {
285
+            $subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
286
+            // New class returns IGroup[] so convert back
287
+            $gids = [];
288
+            foreach ($subAdminOfGroups as $group) {
289
+                $gids[] = $group->getGID();
290
+            }
291
+            $subAdminOfGroups = $gids;
292
+
293
+            // Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
294
+            if($gid !== '' && !in_array($gid, $subAdminOfGroups)) {
295
+                $gid = '';
296
+            }
297
+
298
+            // Batch all groups the user is subadmin of when a group is specified
299
+            $batch = [];
300
+            if($gid === '') {
301
+                foreach($subAdminOfGroups as $group) {
302
+                    $groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
303
+
304
+                    foreach($groupUsers as $uid => $displayName) {
305
+                        $batch[$uid] = $displayName;
306
+                    }
307
+                }
308
+            } else {
309
+                $batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
310
+            }
311
+            $batch = $this->getUsersForUID($batch);
312
+
313
+            foreach ($batch as $user) {
314
+                // Only add the groups, this user is a subadmin of
315
+                $userGroups = array_values(array_intersect(
316
+                    $this->groupManager->getUserGroupIds($user),
317
+                    $subAdminOfGroups
318
+                ));
319
+                $users[] = $this->formatUserForIndex($user, $userGroups);
320
+            }
321
+        }
322
+
323
+        return new DataResponse($users);
324
+    }
325
+
326
+    /**
327
+     * @NoAdminRequired
328
+     * @PasswordConfirmationRequired
329
+     *
330
+     * @param string $username
331
+     * @param string $password
332
+     * @param array $groups
333
+     * @param string $email
334
+     * @return DataResponse
335
+     */
336
+    public function create($username, $password, array $groups=array(), $email='') {
337
+        if($email !== '' && !$this->mailer->validateMailAddress($email)) {
338
+            return new DataResponse(
339
+                array(
340
+                    'message' => (string)$this->l10n->t('Invalid mail address')
341
+                ),
342
+                Http::STATUS_UNPROCESSABLE_ENTITY
343
+            );
344
+        }
345
+
346
+        $currentUser = $this->userSession->getUser();
347
+
348
+        if (!$this->isAdmin) {
349
+            if (!empty($groups)) {
350
+                foreach ($groups as $key => $group) {
351
+                    $groupObject = $this->groupManager->get($group);
352
+                    if($groupObject === null) {
353
+                        unset($groups[$key]);
354
+                        continue;
355
+                    }
356
+
357
+                    if (!$this->groupManager->getSubAdmin()->isSubAdminofGroup($currentUser, $groupObject)) {
358
+                        unset($groups[$key]);
359
+                    }
360
+                }
361
+            }
362
+
363
+            if (empty($groups)) {
364
+                return new DataResponse(
365
+                    array(
366
+                        'message' => $this->l10n->t('No valid group selected'),
367
+                    ),
368
+                    Http::STATUS_FORBIDDEN
369
+                );
370
+            }
371
+        }
372
+
373
+        if ($this->userManager->userExists($username)) {
374
+            return new DataResponse(
375
+                array(
376
+                    'message' => (string)$this->l10n->t('A user with that name already exists.')
377
+                ),
378
+                Http::STATUS_CONFLICT
379
+            );
380
+        }
381
+
382
+        $generatedPassword = false;
383
+        if ($password === '') {
384
+            if ($email === '') {
385
+                return new DataResponse(
386
+                    array(
387
+                        'message' => (string)$this->l10n->t('To send a password link to the user an email address is required.')
388
+                    ),
389
+                    Http::STATUS_UNPROCESSABLE_ENTITY
390
+                );
391
+            }
392
+
393
+            $password = $this->secureRandom->generate(32);
394
+            $generatedPassword = true;
395
+        }
396
+
397
+        try {
398
+            $user = $this->userManager->createUser($username, $password);
399
+        } catch (\Exception $exception) {
400
+            $message = $exception->getMessage();
401
+            if (!$message) {
402
+                $message = $this->l10n->t('Unable to create user.');
403
+            }
404
+            return new DataResponse(
405
+                array(
406
+                    'message' => (string) $message,
407
+                ),
408
+                Http::STATUS_FORBIDDEN
409
+            );
410
+        }
411
+
412
+        if($user instanceof IUser) {
413
+            if($groups !== null) {
414
+                foreach($groups as $groupName) {
415
+                    $group = $this->groupManager->get($groupName);
416
+
417
+                    if(empty($group)) {
418
+                        $group = $this->groupManager->createGroup($groupName);
419
+                    }
420
+                    $group->addUser($user);
421
+                }
422
+            }
423
+            /**
424
+             * Send new user mail only if a mail is set
425
+             */
426
+            if($email !== '') {
427
+                $user->setEMailAddress($email);
428
+
429
+                if ($generatedPassword) {
430
+                    $token = $this->secureRandom->generate(
431
+                        21,
432
+                        ISecureRandom::CHAR_DIGITS .
433
+                        ISecureRandom::CHAR_LOWER .
434
+                        ISecureRandom::CHAR_UPPER
435
+                    );
436
+                    $tokenValue = $this->timeFactory->getTime() . ':' . $token;
437
+                    $mailAddress = !is_null($user->getEMailAddress()) ? $user->getEMailAddress() : '';
438
+                    $encryptedValue = $this->crypto->encrypt($tokenValue, $mailAddress . $this->config->getSystemValue('secret'));
439
+                    $this->config->setUserValue($username, 'core', 'lostpassword', $encryptedValue);
440
+
441
+                    $link = $this->urlGenerator->linkToRouteAbsolute('core.lost.resetform', ['userId' => $username, 'token' => $token]);
442
+                } else {
443
+                    $link = $this->urlGenerator->getAbsoluteURL('/');
444
+                }
445
+
446
+                $displayname = $user->getDisplayName();
447
+
448
+                // data for the mail template
449
+                $mailData = array(
450
+                    'username' => $username,
451
+                    'url' => $link,
452
+                    'generated_password' => $generatedPassword,
453
+                    'url_client_install' => 'https://nextcloud.com/install/#install-clients',
454
+                    'displayname' => ($username !== $displayname) ? $displayname : '',
455
+                );
456
+
457
+                $mail = new TemplateResponse('settings', 'email.new_user', $mailData, 'blank');
458
+                $mailContent = $mail->render();
459
+
460
+                $mail = new TemplateResponse('settings', 'email.new_user_plain_text', $mailData, 'blank');
461
+                $plainTextMailContent = $mail->render();
462
+
463
+                $subject = $this->l10n->t('Your %s account was created', [$this->defaults->getName()]);
464
+
465
+                try {
466
+                    $message = $this->mailer->createMessage();
467
+                    $message->setTo([$email => $username]);
468
+                    $message->setSubject($subject);
469
+                    $message->setHtmlBody($mailContent);
470
+                    $message->setPlainBody($plainTextMailContent);
471
+                    $message->setFrom([$this->fromMailAddress => $this->defaults->getName()]);
472
+                    $this->mailer->send($message);
473
+                } catch(\Exception $e) {
474
+                    $this->log->error("Can't send new user mail to $email: " . $e->getMessage(), array('app' => 'settings'));
475
+                }
476
+            }
477
+            // fetch users groups
478
+            $userGroups = $this->groupManager->getUserGroupIds($user);
479
+
480
+            return new DataResponse(
481
+                $this->formatUserForIndex($user, $userGroups),
482
+                Http::STATUS_CREATED
483
+            );
484
+        }
485
+
486
+        return new DataResponse(
487
+            array(
488
+                'message' => (string)$this->l10n->t('Unable to create user.')
489
+            ),
490
+            Http::STATUS_FORBIDDEN
491
+        );
492
+
493
+    }
494
+
495
+    /**
496
+     * @NoAdminRequired
497
+     * @PasswordConfirmationRequired
498
+     *
499
+     * @param string $id
500
+     * @return DataResponse
501
+     */
502
+    public function destroy($id) {
503
+        $userId = $this->userSession->getUser()->getUID();
504
+        $user = $this->userManager->get($id);
505
+
506
+        if($userId === $id) {
507
+            return new DataResponse(
508
+                array(
509
+                    'status' => 'error',
510
+                    'data' => array(
511
+                        'message' => (string)$this->l10n->t('Unable to delete user.')
512
+                    )
513
+                ),
514
+                Http::STATUS_FORBIDDEN
515
+            );
516
+        }
517
+
518
+        if(!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
519
+            return new DataResponse(
520
+                array(
521
+                    'status' => 'error',
522
+                    'data' => array(
523
+                        'message' => (string)$this->l10n->t('Authentication error')
524
+                    )
525
+                ),
526
+                Http::STATUS_FORBIDDEN
527
+            );
528
+        }
529
+
530
+        if($user) {
531
+            if($user->delete()) {
532
+                return new DataResponse(
533
+                    array(
534
+                        'status' => 'success',
535
+                        'data' => array(
536
+                            'username' => $id
537
+                        )
538
+                    ),
539
+                    Http::STATUS_NO_CONTENT
540
+                );
541
+            }
542
+        }
543
+
544
+        return new DataResponse(
545
+            array(
546
+                'status' => 'error',
547
+                'data' => array(
548
+                    'message' => (string)$this->l10n->t('Unable to delete user.')
549
+                )
550
+            ),
551
+            Http::STATUS_FORBIDDEN
552
+        );
553
+    }
554
+
555
+    /**
556
+     * @NoAdminRequired
557
+     * @NoSubadminRequired
558
+     * @PasswordConfirmationRequired
559
+     *
560
+     * @param string $avatarScope
561
+     * @param string $displayname
562
+     * @param string $displaynameScope
563
+     * @param string $phone
564
+     * @param string $phoneScope
565
+     * @param string $email
566
+     * @param string $emailScope
567
+     * @param string $website
568
+     * @param string $websiteScope
569
+     * @param string $address
570
+     * @param string $addressScope
571
+     * @param string $twitter
572
+     * @param string $twitterScope
573
+     * @return DataResponse
574
+     */
575
+    public function setUserSettings($avatarScope,
576
+                                    $displayname,
577
+                                    $displaynameScope,
578
+                                    $phone,
579
+                                    $phoneScope,
580
+                                    $email,
581
+                                    $emailScope,
582
+                                    $website,
583
+                                    $websiteScope,
584
+                                    $address,
585
+                                    $addressScope,
586
+                                    $twitter,
587
+                                    $twitterScope
588
+    ) {
589
+
590
+        if(!empty($email) && !$this->mailer->validateMailAddress($email)) {
591
+            return new DataResponse(
592
+                array(
593
+                    'status' => 'error',
594
+                    'data' => array(
595
+                        'message' => (string)$this->l10n->t('Invalid mail address')
596
+                    )
597
+                ),
598
+                Http::STATUS_UNPROCESSABLE_ENTITY
599
+            );
600
+        }
601
+
602
+        $data = [
603
+            AccountManager::PROPERTY_AVATAR =>  ['scope' => $avatarScope],
604
+            AccountManager::PROPERTY_DISPLAYNAME => ['value' => $displayname, 'scope' => $displaynameScope],
605
+            AccountManager::PROPERTY_EMAIL=> ['value' => $email, 'scope' => $emailScope],
606
+            AccountManager::PROPERTY_WEBSITE => ['value' => $website, 'scope' => $websiteScope],
607
+            AccountManager::PROPERTY_ADDRESS => ['value' => $address, 'scope' => $addressScope],
608
+            AccountManager::PROPERTY_PHONE => ['value' => $phone, 'scope' => $phoneScope],
609
+            AccountManager::PROPERTY_TWITTER => ['value' => $twitter, 'scope' => $twitterScope]
610
+        ];
611
+
612
+        $user = $this->userSession->getUser();
613
+
614
+        try {
615
+            $this->saveUserSettings($user, $data);
616
+            return new DataResponse(
617
+                array(
618
+                    'status' => 'success',
619
+                    'data' => array(
620
+                        'userId' => $user->getUID(),
621
+                        'avatarScope' => $avatarScope,
622
+                        'displayname' => $displayname,
623
+                        'displaynameScope' => $displaynameScope,
624
+                        'email' => $email,
625
+                        'emailScope' => $emailScope,
626
+                        'website' => $website,
627
+                        'websiteScope' => $websiteScope,
628
+                        'address' => $address,
629
+                        'addressScope' => $addressScope,
630
+                        'message' => (string)$this->l10n->t('Settings saved')
631
+                    )
632
+                ),
633
+                Http::STATUS_OK
634
+            );
635
+        } catch (ForbiddenException $e) {
636
+            return new DataResponse([
637
+                'status' => 'error',
638
+                'data' => [
639
+                    'message' => $e->getMessage()
640
+                ],
641
+            ]);
642
+        }
643
+
644
+    }
645
+
646
+
647
+    /**
648
+     * update account manager with new user data
649
+     *
650
+     * @param IUser $user
651
+     * @param array $data
652
+     * @throws ForbiddenException
653
+     */
654
+    protected function saveUserSettings(IUser $user, $data) {
655
+
656
+        // keep the user back-end up-to-date with the latest display name and email
657
+        // address
658
+        $oldDisplayName = $user->getDisplayName();
659
+        $oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
660
+        if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
661
+            && $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
662
+        ) {
663
+            $result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
664
+            if ($result === false) {
665
+                throw new ForbiddenException($this->l10n->t('Unable to change full name'));
666
+            }
667
+        }
668
+
669
+        $oldEmailAddress = $user->getEMailAddress();
670
+        $oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
671
+        if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
672
+            && $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
673
+        ) {
674
+            // this is the only permission a backend provides and is also used
675
+            // for the permission of setting a email address
676
+            if (!$user->canChangeDisplayName()) {
677
+                throw new ForbiddenException($this->l10n->t('Unable to change email address'));
678
+            }
679
+            $user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
680
+        }
681
+
682
+        $this->accountManager->updateUser($user, $data);
683
+    }
684
+
685
+    /**
686
+     * Count all unique users visible for the current admin/subadmin.
687
+     *
688
+     * @NoAdminRequired
689
+     *
690
+     * @return DataResponse
691
+     */
692
+    public function stats() {
693
+        $userCount = 0;
694
+        if ($this->isAdmin) {
695
+            $countByBackend = $this->userManager->countUsers();
696
+
697
+            if (!empty($countByBackend)) {
698
+                foreach ($countByBackend as $count) {
699
+                    $userCount += $count;
700
+                }
701
+            }
702
+        } else {
703
+            $groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
704
+
705
+            $uniqueUsers = [];
706
+            foreach ($groups as $group) {
707
+                foreach($group->getUsers() as $uid => $displayName) {
708
+                    $uniqueUsers[$uid] = true;
709
+                }
710
+            }
711
+
712
+            $userCount = count($uniqueUsers);
713
+        }
714
+
715
+        return new DataResponse(
716
+            [
717
+                'totalUsers' => $userCount
718
+            ]
719
+        );
720
+    }
721
+
722
+
723
+    /**
724
+     * Set the displayName of a user
725
+     *
726
+     * @NoAdminRequired
727
+     * @NoSubadminRequired
728
+     * @PasswordConfirmationRequired
729
+     * @todo merge into saveUserSettings
730
+     *
731
+     * @param string $username
732
+     * @param string $displayName
733
+     * @return DataResponse
734
+     */
735
+    public function setDisplayName($username, $displayName) {
736
+        $currentUser = $this->userSession->getUser();
737
+        $user = $this->userManager->get($username);
738
+
739
+        if ($user === null ||
740
+            !$user->canChangeDisplayName() ||
741
+            (
742
+                !$this->groupManager->isAdmin($currentUser->getUID()) &&
743
+                !$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
744
+                $currentUser->getUID() !== $username
745
+
746
+            )
747
+        ) {
748
+            return new DataResponse([
749
+                'status' => 'error',
750
+                'data' => [
751
+                    'message' => $this->l10n->t('Authentication error'),
752
+                ],
753
+            ]);
754
+        }
755
+
756
+        $userData = $this->accountManager->getUser($user);
757
+        $userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
758
+
759
+
760
+        try {
761
+            $this->saveUserSettings($user, $userData);
762
+            return new DataResponse([
763
+                'status' => 'success',
764
+                'data' => [
765
+                    'message' => $this->l10n->t('Your full name has been changed.'),
766
+                    'username' => $username,
767
+                    'displayName' => $displayName,
768
+                ],
769
+            ]);
770
+        } catch (ForbiddenException $e) {
771
+            return new DataResponse([
772
+                'status' => 'error',
773
+                'data' => [
774
+                    'message' => $e->getMessage(),
775
+                    'displayName' => $user->getDisplayName(),
776
+                ],
777
+            ]);
778
+        }
779
+    }
780
+
781
+    /**
782
+     * Set the mail address of a user
783
+     *
784
+     * @NoAdminRequired
785
+     * @NoSubadminRequired
786
+     * @PasswordConfirmationRequired
787
+     *
788
+     * @param string $id
789
+     * @param string $mailAddress
790
+     * @return DataResponse
791
+     */
792
+    public function setEMailAddress($id, $mailAddress) {
793
+        $user = $this->userManager->get($id);
794
+        if (!$this->isAdmin
795
+            && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
796
+        ) {
797
+            return new DataResponse(
798
+                array(
799
+                    'status' => 'error',
800
+                    'data' => array(
801
+                        'message' => (string)$this->l10n->t('Forbidden')
802
+                    )
803
+                ),
804
+                Http::STATUS_FORBIDDEN
805
+            );
806
+        }
807
+
808
+        if($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
809
+            return new DataResponse(
810
+                array(
811
+                    'status' => 'error',
812
+                    'data' => array(
813
+                        'message' => (string)$this->l10n->t('Invalid mail address')
814
+                    )
815
+                ),
816
+                Http::STATUS_UNPROCESSABLE_ENTITY
817
+            );
818
+        }
819
+
820
+        if (!$user) {
821
+            return new DataResponse(
822
+                array(
823
+                    'status' => 'error',
824
+                    'data' => array(
825
+                        'message' => (string)$this->l10n->t('Invalid user')
826
+                    )
827
+                ),
828
+                Http::STATUS_UNPROCESSABLE_ENTITY
829
+            );
830
+        }
831
+        // this is the only permission a backend provides and is also used
832
+        // for the permission of setting a email address
833
+        if (!$user->canChangeDisplayName()) {
834
+            return new DataResponse(
835
+                array(
836
+                    'status' => 'error',
837
+                    'data' => array(
838
+                        'message' => (string)$this->l10n->t('Unable to change mail address')
839
+                    )
840
+                ),
841
+                Http::STATUS_FORBIDDEN
842
+            );
843
+        }
844
+
845
+        $userData = $this->accountManager->getUser($user);
846
+        $userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
847
+
848
+        try {
849
+            $this->saveUserSettings($user, $userData);
850
+            return new DataResponse(
851
+                array(
852
+                    'status' => 'success',
853
+                    'data' => array(
854
+                        'username' => $id,
855
+                        'mailAddress' => $mailAddress,
856
+                        'message' => (string)$this->l10n->t('Email saved')
857
+                    )
858
+                ),
859
+                Http::STATUS_OK
860
+            );
861
+        } catch (ForbiddenException $e) {
862
+            return new DataResponse([
863
+                'status' => 'error',
864
+                'data' => [
865
+                    'message' => $e->getMessage()
866
+                ],
867
+            ]);
868
+        }
869
+    }
870 870
 
871 871
 }
Please login to merge, or discard this patch.