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