Passed
Push — master ( e31290...b1610e )
by Joas
13:57 queued 11s
created
apps/provisioning_api/appinfo/routes.php 1 patch
Indentation   +44 added lines, -44 removed lines patch added patch discarded remove patch
@@ -27,51 +27,51 @@
 block discarded – undo
27 27
  */
28 28
 
29 29
 return [
30
-	'ocs' => [
31
-		// Apps
32
-		['root' => '/cloud', 'name' => 'Apps#getApps', 'url' => '/apps', 'verb' => 'GET'],
33
-		['root' => '/cloud', 'name' => 'Apps#getAppInfo', 'url' => '/apps/{app}', 'verb' => 'GET'],
34
-		['root' => '/cloud', 'name' => 'Apps#enable', 'url' => '/apps/{app}', 'verb' => 'POST'],
35
-		['root' => '/cloud', 'name' => 'Apps#disable', 'url' => '/apps/{app}', 'verb' => 'DELETE'],
30
+    'ocs' => [
31
+        // Apps
32
+        ['root' => '/cloud', 'name' => 'Apps#getApps', 'url' => '/apps', 'verb' => 'GET'],
33
+        ['root' => '/cloud', 'name' => 'Apps#getAppInfo', 'url' => '/apps/{app}', 'verb' => 'GET'],
34
+        ['root' => '/cloud', 'name' => 'Apps#enable', 'url' => '/apps/{app}', 'verb' => 'POST'],
35
+        ['root' => '/cloud', 'name' => 'Apps#disable', 'url' => '/apps/{app}', 'verb' => 'DELETE'],
36 36
 
37
-		// Groups
38
-		['root' => '/cloud', 'name' => 'Groups#getGroups', 'url' => '/groups', 'verb' => 'GET'],
39
-		['root' => '/cloud', 'name' => 'Groups#getGroupsDetails', 'url' => '/groups/details', 'verb' => 'GET'],
40
-		['root' => '/cloud', 'name' => 'Groups#getGroupUsers', 'url' => '/groups/{groupId}/users', 'verb' => 'GET', 'requirements' => ['groupId' => '.+']],
41
-		['root' => '/cloud', 'name' => 'Groups#getGroupUsersDetails', 'url' => '/groups/{groupId}/users/details', 'verb' => 'GET', 'requirements' => ['groupId' => '.+']],
42
-		['root' => '/cloud', 'name' => 'Groups#getSubAdminsOfGroup', 'url' => '/groups/{groupId}/subadmins', 'verb' => 'GET', 'requirements' => ['groupId' => '.+']],
43
-		['root' => '/cloud', 'name' => 'Groups#addGroup', 'url' => '/groups', 'verb' => 'POST'],
44
-		['root' => '/cloud', 'name' => 'Groups#getGroup', 'url' => '/groups/{groupId}', 'verb' => 'GET', 'requirements' => ['groupId' => '.+']],
45
-		['root' => '/cloud', 'name' => 'Groups#updateGroup', 'url' => '/groups/{groupId}', 'verb' => 'PUT', 'requirements' => ['groupId' => '.+']],
46
-		['root' => '/cloud', 'name' => 'Groups#deleteGroup', 'url' => '/groups/{groupId}', 'verb' => 'DELETE', 'requirements' => ['groupId' => '.+']],
37
+        // Groups
38
+        ['root' => '/cloud', 'name' => 'Groups#getGroups', 'url' => '/groups', 'verb' => 'GET'],
39
+        ['root' => '/cloud', 'name' => 'Groups#getGroupsDetails', 'url' => '/groups/details', 'verb' => 'GET'],
40
+        ['root' => '/cloud', 'name' => 'Groups#getGroupUsers', 'url' => '/groups/{groupId}/users', 'verb' => 'GET', 'requirements' => ['groupId' => '.+']],
41
+        ['root' => '/cloud', 'name' => 'Groups#getGroupUsersDetails', 'url' => '/groups/{groupId}/users/details', 'verb' => 'GET', 'requirements' => ['groupId' => '.+']],
42
+        ['root' => '/cloud', 'name' => 'Groups#getSubAdminsOfGroup', 'url' => '/groups/{groupId}/subadmins', 'verb' => 'GET', 'requirements' => ['groupId' => '.+']],
43
+        ['root' => '/cloud', 'name' => 'Groups#addGroup', 'url' => '/groups', 'verb' => 'POST'],
44
+        ['root' => '/cloud', 'name' => 'Groups#getGroup', 'url' => '/groups/{groupId}', 'verb' => 'GET', 'requirements' => ['groupId' => '.+']],
45
+        ['root' => '/cloud', 'name' => 'Groups#updateGroup', 'url' => '/groups/{groupId}', 'verb' => 'PUT', 'requirements' => ['groupId' => '.+']],
46
+        ['root' => '/cloud', 'name' => 'Groups#deleteGroup', 'url' => '/groups/{groupId}', 'verb' => 'DELETE', 'requirements' => ['groupId' => '.+']],
47 47
 
48
-		// Users
49
-		['root' => '/cloud', 'name' => 'Users#getUsers', 'url' => '/users', 'verb' => 'GET'],
50
-		['root' => '/cloud', 'name' => 'Users#getUsersDetails', 'url' => '/users/details', 'verb' => 'GET'],
51
-		['root' => '/cloud', 'name' => 'Users#searchByPhoneNumbers', 'url' => '/users/search/by-phone', 'verb' => 'POST'],
52
-		['root' => '/cloud', 'name' => 'Users#addUser', 'url' => '/users', 'verb' => 'POST'],
53
-		['root' => '/cloud', 'name' => 'Users#getUser', 'url' => '/users/{userId}', 'verb' => 'GET'],
54
-		['root' => '/cloud', 'name' => 'Users#getCurrentUser', 'url' => '/user', 'verb' => 'GET'],
55
-		['root' => '/cloud', 'name' => 'Users#getEditableFields', 'url' => '/user/fields', 'verb' => 'GET'],
56
-		['root' => '/cloud', 'name' => 'Users#getEditableFieldsForUser', 'url' => '/user/fields/{userId}', 'verb' => 'GET'],
57
-		['root' => '/cloud', 'name' => 'Users#editUser', 'url' => '/users/{userId}', 'verb' => 'PUT'],
58
-		['root' => '/cloud', 'name' => 'Users#wipeUserDevices', 'url' => '/users/{userId}/wipe', 'verb' => 'POST'],
59
-		['root' => '/cloud', 'name' => 'Users#deleteUser', 'url' => '/users/{userId}', 'verb' => 'DELETE'],
60
-		['root' => '/cloud', 'name' => 'Users#enableUser', 'url' => '/users/{userId}/enable', 'verb' => 'PUT'],
61
-		['root' => '/cloud', 'name' => 'Users#disableUser', 'url' => '/users/{userId}/disable', 'verb' => 'PUT'],
62
-		['root' => '/cloud', 'name' => 'Users#getUsersGroups', 'url' => '/users/{userId}/groups', 'verb' => 'GET'],
63
-		['root' => '/cloud', 'name' => 'Users#addToGroup', 'url' => '/users/{userId}/groups', 'verb' => 'POST'],
64
-		['root' => '/cloud', 'name' => 'Users#removeFromGroup', 'url' => '/users/{userId}/groups', 'verb' => 'DELETE'],
65
-		['root' => '/cloud', 'name' => 'Users#getUserSubAdminGroups', 'url' => '/users/{userId}/subadmins', 'verb' => 'GET'],
66
-		['root' => '/cloud', 'name' => 'Users#addSubAdmin', 'url' => '/users/{userId}/subadmins', 'verb' => 'POST'],
67
-		['root' => '/cloud', 'name' => 'Users#removeSubAdmin', 'url' => '/users/{userId}/subadmins', 'verb' => 'DELETE'],
68
-		['root' => '/cloud', 'name' => 'Users#resendWelcomeMessage', 'url' => '/users/{userId}/welcome', 'verb' => 'POST'],
48
+        // Users
49
+        ['root' => '/cloud', 'name' => 'Users#getUsers', 'url' => '/users', 'verb' => 'GET'],
50
+        ['root' => '/cloud', 'name' => 'Users#getUsersDetails', 'url' => '/users/details', 'verb' => 'GET'],
51
+        ['root' => '/cloud', 'name' => 'Users#searchByPhoneNumbers', 'url' => '/users/search/by-phone', 'verb' => 'POST'],
52
+        ['root' => '/cloud', 'name' => 'Users#addUser', 'url' => '/users', 'verb' => 'POST'],
53
+        ['root' => '/cloud', 'name' => 'Users#getUser', 'url' => '/users/{userId}', 'verb' => 'GET'],
54
+        ['root' => '/cloud', 'name' => 'Users#getCurrentUser', 'url' => '/user', 'verb' => 'GET'],
55
+        ['root' => '/cloud', 'name' => 'Users#getEditableFields', 'url' => '/user/fields', 'verb' => 'GET'],
56
+        ['root' => '/cloud', 'name' => 'Users#getEditableFieldsForUser', 'url' => '/user/fields/{userId}', 'verb' => 'GET'],
57
+        ['root' => '/cloud', 'name' => 'Users#editUser', 'url' => '/users/{userId}', 'verb' => 'PUT'],
58
+        ['root' => '/cloud', 'name' => 'Users#wipeUserDevices', 'url' => '/users/{userId}/wipe', 'verb' => 'POST'],
59
+        ['root' => '/cloud', 'name' => 'Users#deleteUser', 'url' => '/users/{userId}', 'verb' => 'DELETE'],
60
+        ['root' => '/cloud', 'name' => 'Users#enableUser', 'url' => '/users/{userId}/enable', 'verb' => 'PUT'],
61
+        ['root' => '/cloud', 'name' => 'Users#disableUser', 'url' => '/users/{userId}/disable', 'verb' => 'PUT'],
62
+        ['root' => '/cloud', 'name' => 'Users#getUsersGroups', 'url' => '/users/{userId}/groups', 'verb' => 'GET'],
63
+        ['root' => '/cloud', 'name' => 'Users#addToGroup', 'url' => '/users/{userId}/groups', 'verb' => 'POST'],
64
+        ['root' => '/cloud', 'name' => 'Users#removeFromGroup', 'url' => '/users/{userId}/groups', 'verb' => 'DELETE'],
65
+        ['root' => '/cloud', 'name' => 'Users#getUserSubAdminGroups', 'url' => '/users/{userId}/subadmins', 'verb' => 'GET'],
66
+        ['root' => '/cloud', 'name' => 'Users#addSubAdmin', 'url' => '/users/{userId}/subadmins', 'verb' => 'POST'],
67
+        ['root' => '/cloud', 'name' => 'Users#removeSubAdmin', 'url' => '/users/{userId}/subadmins', 'verb' => 'DELETE'],
68
+        ['root' => '/cloud', 'name' => 'Users#resendWelcomeMessage', 'url' => '/users/{userId}/welcome', 'verb' => 'POST'],
69 69
 
70
-		// Config
71
-		['name' => 'AppConfig#getApps', 'url' => '/api/v1/config/apps', 'verb' => 'GET'],
72
-		['name' => 'AppConfig#getKeys', 'url' => '/api/v1/config/apps/{app}', 'verb' => 'GET'],
73
-		['name' => 'AppConfig#getValue', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'GET'],
74
-		['name' => 'AppConfig#setValue', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'POST'],
75
-		['name' => 'AppConfig#deleteKey', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'DELETE'],
76
-	],
70
+        // Config
71
+        ['name' => 'AppConfig#getApps', 'url' => '/api/v1/config/apps', 'verb' => 'GET'],
72
+        ['name' => 'AppConfig#getKeys', 'url' => '/api/v1/config/apps/{app}', 'verb' => 'GET'],
73
+        ['name' => 'AppConfig#getValue', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'GET'],
74
+        ['name' => 'AppConfig#setValue', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'POST'],
75
+        ['name' => 'AppConfig#deleteKey', 'url' => '/api/v1/config/apps/{app}/{key}', 'verb' => 'DELETE'],
76
+    ],
77 77
 ];
Please login to merge, or discard this patch.
apps/provisioning_api/lib/Controller/UsersController.php 1 patch
Indentation   +1106 added lines, -1106 removed lines patch added patch discarded remove patch
@@ -75,1110 +75,1110 @@
 block discarded – undo
75 75
 
76 76
 class UsersController extends AUserData {
77 77
 
78
-	/** @var IAppManager */
79
-	private $appManager;
80
-	/** @var IURLGenerator */
81
-	protected $urlGenerator;
82
-	/** @var LoggerInterface */
83
-	private $logger;
84
-	/** @var IFactory */
85
-	protected $l10nFactory;
86
-	/** @var NewUserMailHelper */
87
-	private $newUserMailHelper;
88
-	/** @var ISecureRandom */
89
-	private $secureRandom;
90
-	/** @var RemoteWipe */
91
-	private $remoteWipe;
92
-	/** @var KnownUserService */
93
-	private $knownUserService;
94
-	/** @var IEventDispatcher */
95
-	private $eventDispatcher;
96
-
97
-	public function __construct(string $appName,
98
-								IRequest $request,
99
-								IUserManager $userManager,
100
-								IConfig $config,
101
-								IAppManager $appManager,
102
-								IGroupManager $groupManager,
103
-								IUserSession $userSession,
104
-								IAccountManager $accountManager,
105
-								IURLGenerator $urlGenerator,
106
-								LoggerInterface $logger,
107
-								IFactory $l10nFactory,
108
-								NewUserMailHelper $newUserMailHelper,
109
-								ISecureRandom $secureRandom,
110
-								RemoteWipe $remoteWipe,
111
-								KnownUserService $knownUserService,
112
-								IEventDispatcher $eventDispatcher) {
113
-		parent::__construct($appName,
114
-							$request,
115
-							$userManager,
116
-							$config,
117
-							$groupManager,
118
-							$userSession,
119
-							$accountManager,
120
-							$l10nFactory);
121
-
122
-		$this->appManager = $appManager;
123
-		$this->urlGenerator = $urlGenerator;
124
-		$this->logger = $logger;
125
-		$this->l10nFactory = $l10nFactory;
126
-		$this->newUserMailHelper = $newUserMailHelper;
127
-		$this->secureRandom = $secureRandom;
128
-		$this->remoteWipe = $remoteWipe;
129
-		$this->knownUserService = $knownUserService;
130
-		$this->eventDispatcher = $eventDispatcher;
131
-	}
132
-
133
-	/**
134
-	 * @NoAdminRequired
135
-	 *
136
-	 * returns a list of users
137
-	 *
138
-	 * @param string $search
139
-	 * @param int $limit
140
-	 * @param int $offset
141
-	 * @return DataResponse
142
-	 */
143
-	public function getUsers(string $search = '', int $limit = null, int $offset = 0): DataResponse {
144
-		$user = $this->userSession->getUser();
145
-		$users = [];
146
-
147
-		// Admin? Or SubAdmin?
148
-		$uid = $user->getUID();
149
-		$subAdminManager = $this->groupManager->getSubAdmin();
150
-		if ($this->groupManager->isAdmin($uid)) {
151
-			$users = $this->userManager->search($search, $limit, $offset);
152
-		} elseif ($subAdminManager->isSubAdmin($user)) {
153
-			$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($user);
154
-			foreach ($subAdminOfGroups as $key => $group) {
155
-				$subAdminOfGroups[$key] = $group->getGID();
156
-			}
157
-
158
-			$users = [];
159
-			foreach ($subAdminOfGroups as $group) {
160
-				$users = array_merge($users, $this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
161
-			}
162
-		}
163
-
164
-		$users = array_keys($users);
165
-
166
-		return new DataResponse([
167
-			'users' => $users
168
-		]);
169
-	}
170
-
171
-	/**
172
-	 * @NoAdminRequired
173
-	 *
174
-	 * returns a list of users and their data
175
-	 */
176
-	public function getUsersDetails(string $search = '', int $limit = null, int $offset = 0): DataResponse {
177
-		$currentUser = $this->userSession->getUser();
178
-		$users = [];
179
-
180
-		// Admin? Or SubAdmin?
181
-		$uid = $currentUser->getUID();
182
-		$subAdminManager = $this->groupManager->getSubAdmin();
183
-		if ($this->groupManager->isAdmin($uid)) {
184
-			$users = $this->userManager->search($search, $limit, $offset);
185
-			$users = array_keys($users);
186
-		} elseif ($subAdminManager->isSubAdmin($currentUser)) {
187
-			$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
188
-			foreach ($subAdminOfGroups as $key => $group) {
189
-				$subAdminOfGroups[$key] = $group->getGID();
190
-			}
191
-
192
-			$users = [];
193
-			foreach ($subAdminOfGroups as $group) {
194
-				$users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
195
-			}
196
-			$users = array_merge(...$users);
197
-		}
198
-
199
-		$usersDetails = [];
200
-		foreach ($users as $userId) {
201
-			$userId = (string) $userId;
202
-			$userData = $this->getUserData($userId);
203
-			// Do not insert empty entry
204
-			if (!empty($userData)) {
205
-				$usersDetails[$userId] = $userData;
206
-			} else {
207
-				// Logged user does not have permissions to see this user
208
-				// only showing its id
209
-				$usersDetails[$userId] = ['id' => $userId];
210
-			}
211
-		}
212
-
213
-		return new DataResponse([
214
-			'users' => $usersDetails
215
-		]);
216
-	}
217
-
218
-
219
-	/**
220
-	 * @NoAdminRequired
221
-	 * @NoSubAdminRequired
222
-	 *
223
-	 * @param string $location
224
-	 * @param array $search
225
-	 * @return DataResponse
226
-	 */
227
-	public function searchByPhoneNumbers(string $location, array $search): DataResponse {
228
-		$phoneUtil = PhoneNumberUtil::getInstance();
229
-
230
-		if ($phoneUtil->getCountryCodeForRegion($location) === 0) {
231
-			// Not a valid region code
232
-			return new DataResponse([], Http::STATUS_BAD_REQUEST);
233
-		}
234
-
235
-		/** @var IUser $user */
236
-		$user = $this->userSession->getUser();
237
-		$knownTo = $user->getUID();
238
-		$defaultPhoneRegion = $this->config->getSystemValueString('default_phone_region');
239
-
240
-		$normalizedNumberToKey = [];
241
-		foreach ($search as $key => $phoneNumbers) {
242
-			foreach ($phoneNumbers as $phone) {
243
-				try {
244
-					$phoneNumber = $phoneUtil->parse($phone, $location);
245
-					if ($phoneNumber instanceof PhoneNumber && $phoneUtil->isValidNumber($phoneNumber)) {
246
-						$normalizedNumber = $phoneUtil->format($phoneNumber, PhoneNumberFormat::E164);
247
-						$normalizedNumberToKey[$normalizedNumber] = (string) $key;
248
-					}
249
-				} catch (NumberParseException $e) {
250
-				}
251
-
252
-				if ($defaultPhoneRegion !== '' && $defaultPhoneRegion !== $location && strpos($phone, '0') === 0) {
253
-					// If the number has a leading zero (no country code),
254
-					// we also check the default phone region of the instance,
255
-					// when it's different to the user's given region.
256
-					try {
257
-						$phoneNumber = $phoneUtil->parse($phone, $defaultPhoneRegion);
258
-						if ($phoneNumber instanceof PhoneNumber && $phoneUtil->isValidNumber($phoneNumber)) {
259
-							$normalizedNumber = $phoneUtil->format($phoneNumber, PhoneNumberFormat::E164);
260
-							$normalizedNumberToKey[$normalizedNumber] = (string) $key;
261
-						}
262
-					} catch (NumberParseException $e) {
263
-					}
264
-				}
265
-			}
266
-		}
267
-
268
-		$phoneNumbers = array_keys($normalizedNumberToKey);
269
-
270
-		if (empty($phoneNumbers)) {
271
-			return new DataResponse();
272
-		}
273
-
274
-		// Cleanup all previous entries and only allow new matches
275
-		$this->knownUserService->deleteKnownTo($knownTo);
276
-
277
-		$userMatches = $this->accountManager->searchUsers(IAccountManager::PROPERTY_PHONE, $phoneNumbers);
278
-
279
-		if (empty($userMatches)) {
280
-			return new DataResponse();
281
-		}
282
-
283
-		$cloudUrl = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/');
284
-		if (strpos($cloudUrl, 'http://') === 0) {
285
-			$cloudUrl = substr($cloudUrl, strlen('http://'));
286
-		} elseif (strpos($cloudUrl, 'https://') === 0) {
287
-			$cloudUrl = substr($cloudUrl, strlen('https://'));
288
-		}
289
-
290
-		$matches = [];
291
-		foreach ($userMatches as $phone => $userId) {
292
-			// Not using the ICloudIdManager as that would run a search for each contact to find the display name in the address book
293
-			$matches[$normalizedNumberToKey[$phone]] = $userId . '@' . $cloudUrl;
294
-			$this->knownUserService->storeIsKnownToUser($knownTo, $userId);
295
-		}
296
-
297
-		return new DataResponse($matches);
298
-	}
299
-
300
-	/**
301
-	 * @throws OCSException
302
-	 */
303
-	private function createNewUserId(): string {
304
-		$attempts = 0;
305
-		do {
306
-			$uidCandidate = $this->secureRandom->generate(10, ISecureRandom::CHAR_HUMAN_READABLE);
307
-			if (!$this->userManager->userExists($uidCandidate)) {
308
-				return $uidCandidate;
309
-			}
310
-			$attempts++;
311
-		} while ($attempts < 10);
312
-		throw new OCSException('Could not create non-existing user id', 111);
313
-	}
314
-
315
-	/**
316
-	 * @PasswordConfirmationRequired
317
-	 * @NoAdminRequired
318
-	 *
319
-	 * @param string $userid
320
-	 * @param string $password
321
-	 * @param string $displayName
322
-	 * @param string $email
323
-	 * @param array $groups
324
-	 * @param array $subadmin
325
-	 * @param string $quota
326
-	 * @param string $language
327
-	 * @return DataResponse
328
-	 * @throws OCSException
329
-	 */
330
-	public function addUser(string $userid,
331
-							string $password = '',
332
-							string $displayName = '',
333
-							string $email = '',
334
-							array $groups = [],
335
-							array $subadmin = [],
336
-							string $quota = '',
337
-							string $language = ''): DataResponse {
338
-		$user = $this->userSession->getUser();
339
-		$isAdmin = $this->groupManager->isAdmin($user->getUID());
340
-		$subAdminManager = $this->groupManager->getSubAdmin();
341
-
342
-		if (empty($userid) && $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes') {
343
-			$userid = $this->createNewUserId();
344
-		}
345
-
346
-		if ($this->userManager->userExists($userid)) {
347
-			$this->logger->error('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']);
348
-			throw new OCSException('User already exists', 102);
349
-		}
350
-
351
-		if ($groups !== []) {
352
-			foreach ($groups as $group) {
353
-				if (!$this->groupManager->groupExists($group)) {
354
-					throw new OCSException('group '.$group.' does not exist', 104);
355
-				}
356
-				if (!$isAdmin && !$subAdminManager->isSubAdminOfGroup($user, $this->groupManager->get($group))) {
357
-					throw new OCSException('insufficient privileges for group '. $group, 105);
358
-				}
359
-			}
360
-		} else {
361
-			if (!$isAdmin) {
362
-				throw new OCSException('no group specified (required for subadmins)', 106);
363
-			}
364
-		}
365
-
366
-		$subadminGroups = [];
367
-		if ($subadmin !== []) {
368
-			foreach ($subadmin as $groupid) {
369
-				$group = $this->groupManager->get($groupid);
370
-				// Check if group exists
371
-				if ($group === null) {
372
-					throw new OCSException('Subadmin group does not exist',  102);
373
-				}
374
-				// Check if trying to make subadmin of admin group
375
-				if ($group->getGID() === 'admin') {
376
-					throw new OCSException('Cannot create subadmins for admin group', 103);
377
-				}
378
-				// Check if has permission to promote subadmins
379
-				if (!$subAdminManager->isSubAdminOfGroup($user, $group) && !$isAdmin) {
380
-					throw new OCSForbiddenException('No permissions to promote subadmins');
381
-				}
382
-				$subadminGroups[] = $group;
383
-			}
384
-		}
385
-
386
-		$generatePasswordResetToken = false;
387
-		if ($password === '') {
388
-			if ($email === '') {
389
-				throw new OCSException('To send a password link to the user an email address is required.', 108);
390
-			}
391
-
392
-			$passwordEvent = new GenerateSecurePasswordEvent();
393
-			$this->eventDispatcher->dispatchTyped($passwordEvent);
394
-
395
-			$password = $passwordEvent->getPassword();
396
-			if ($password === null) {
397
-				// Fallback: ensure to pass password_policy in any case
398
-				$password = $this->secureRandom->generate(10)
399
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_UPPER)
400
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_LOWER)
401
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_DIGITS)
402
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_SYMBOLS);
403
-			}
404
-			$generatePasswordResetToken = true;
405
-		}
406
-
407
-		if ($email === '' && $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes') {
408
-			throw new OCSException('Required email address was not provided', 110);
409
-		}
410
-
411
-		try {
412
-			$newUser = $this->userManager->createUser($userid, $password);
413
-			$this->logger->info('Successful addUser call with userid: ' . $userid, ['app' => 'ocs_api']);
414
-
415
-			foreach ($groups as $group) {
416
-				$this->groupManager->get($group)->addUser($newUser);
417
-				$this->logger->info('Added userid ' . $userid . ' to group ' . $group, ['app' => 'ocs_api']);
418
-			}
419
-			foreach ($subadminGroups as $group) {
420
-				$subAdminManager->createSubAdmin($newUser, $group);
421
-			}
422
-
423
-			if ($displayName !== '') {
424
-				$this->editUser($userid, 'display', $displayName);
425
-			}
426
-
427
-			if ($quota !== '') {
428
-				$this->editUser($userid, 'quota', $quota);
429
-			}
430
-
431
-			if ($language !== '') {
432
-				$this->editUser($userid, 'language', $language);
433
-			}
434
-
435
-			// Send new user mail only if a mail is set
436
-			if ($email !== '') {
437
-				$newUser->setEMailAddress($email);
438
-				if ($this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes') {
439
-					try {
440
-						$emailTemplate = $this->newUserMailHelper->generateTemplate($newUser, $generatePasswordResetToken);
441
-						$this->newUserMailHelper->sendMail($newUser, $emailTemplate);
442
-					} catch (\Exception $e) {
443
-						// Mail could be failing hard or just be plain not configured
444
-						// Logging error as it is the hardest of the two
445
-						$this->logger->error("Unable to send the invitation mail to $email",
446
-							[
447
-								'app' => 'ocs_api',
448
-								'exception' => $e,
449
-							]
450
-						);
451
-					}
452
-				}
453
-			}
454
-
455
-			return new DataResponse(['id' => $userid]);
456
-		} catch (HintException $e) {
457
-			$this->logger->warning('Failed addUser attempt with hint exception.',
458
-				[
459
-					'app' => 'ocs_api',
460
-					'exception' => $e,
461
-				]
462
-			);
463
-			throw new OCSException($e->getHint(), 107);
464
-		} catch (OCSException $e) {
465
-			$this->logger->warning('Failed addUser attempt with ocs exeption.',
466
-				[
467
-					'app' => 'ocs_api',
468
-					'exception' => $e,
469
-				]
470
-			);
471
-			throw $e;
472
-		} catch (\InvalidArgumentException $e) {
473
-			$this->logger->error('Failed addUser attempt with invalid argument exeption.',
474
-				[
475
-					'app' => 'ocs_api',
476
-					'exception' => $e,
477
-				]
478
-			);
479
-			throw new OCSException($e->getMessage(), 101);
480
-		} catch (\Exception $e) {
481
-			$this->logger->error('Failed addUser attempt with exception.',
482
-				[
483
-					'app' => 'ocs_api',
484
-					'exception' => $e
485
-				]
486
-			);
487
-			throw new OCSException('Bad request', 101);
488
-		}
489
-	}
490
-
491
-	/**
492
-	 * @NoAdminRequired
493
-	 * @NoSubAdminRequired
494
-	 *
495
-	 * gets user info
496
-	 *
497
-	 * @param string $userId
498
-	 * @return DataResponse
499
-	 * @throws OCSException
500
-	 */
501
-	public function getUser(string $userId): DataResponse {
502
-		$includeScopes = false;
503
-		$currentUser = $this->userSession->getUser();
504
-		if ($currentUser && $currentUser->getUID() === $userId) {
505
-			$includeScopes = true;
506
-		}
507
-
508
-		$data = $this->getUserData($userId, $includeScopes);
509
-		// getUserData returns empty array if not enough permissions
510
-		if (empty($data)) {
511
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
512
-		}
513
-		return new DataResponse($data);
514
-	}
515
-
516
-	/**
517
-	 * @NoAdminRequired
518
-	 * @NoSubAdminRequired
519
-	 *
520
-	 * gets user info from the currently logged in user
521
-	 *
522
-	 * @return DataResponse
523
-	 * @throws OCSException
524
-	 */
525
-	public function getCurrentUser(): DataResponse {
526
-		$user = $this->userSession->getUser();
527
-		if ($user) {
528
-			$data = $this->getUserData($user->getUID(), true);
529
-			// rename "displayname" to "display-name" only for this call to keep
530
-			// the API stable.
531
-			$data['display-name'] = $data['displayname'];
532
-			unset($data['displayname']);
533
-			return new DataResponse($data);
534
-		}
535
-
536
-		throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
537
-	}
538
-
539
-	/**
540
-	 * @NoAdminRequired
541
-	 * @NoSubAdminRequired
542
-	 *
543
-	 * @return DataResponse
544
-	 * @throws OCSException
545
-	 */
546
-	public function getEditableFields(): DataResponse {
547
-		$currentLoggedInUser = $this->userSession->getUser();
548
-		if (!$currentLoggedInUser instanceof IUser) {
549
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
550
-		}
551
-
552
-		return $this->getEditableFieldsForUser($currentLoggedInUser->getUID());
553
-	}
554
-
555
-	/**
556
-	 * @NoAdminRequired
557
-	 * @NoSubAdminRequired
558
-	 *
559
-	 * @param string $userId
560
-	 * @return DataResponse
561
-	 * @throws OCSException
562
-	 */
563
-	public function getEditableFieldsForUser(string $userId): DataResponse {
564
-		$currentLoggedInUser = $this->userSession->getUser();
565
-		if (!$currentLoggedInUser instanceof IUser) {
566
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
567
-		}
568
-
569
-		$permittedFields = [];
570
-
571
-		if ($userId !== $currentLoggedInUser->getUID()) {
572
-			$targetUser = $this->userManager->get($userId);
573
-			if (!$targetUser instanceof IUser) {
574
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
575
-			}
576
-
577
-			$subAdminManager = $this->groupManager->getSubAdmin();
578
-			if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID())
579
-				&& !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
580
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
581
-			}
582
-		} else {
583
-			$targetUser = $currentLoggedInUser;
584
-		}
585
-
586
-		// Editing self (display, email)
587
-		if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
588
-			if ($targetUser->getBackend() instanceof ISetDisplayNameBackend
589
-				|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)) {
590
-				$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
591
-			}
592
-			$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
593
-		}
594
-
595
-		$permittedFields[] = IAccountManager::PROPERTY_PHONE;
596
-		$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
597
-		$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
598
-		$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
599
-
600
-		return new DataResponse($permittedFields);
601
-	}
602
-
603
-	/**
604
-	 * @NoAdminRequired
605
-	 * @NoSubAdminRequired
606
-	 * @PasswordConfirmationRequired
607
-	 *
608
-	 * edit users
609
-	 *
610
-	 * @param string $userId
611
-	 * @param string $key
612
-	 * @param string $value
613
-	 * @return DataResponse
614
-	 * @throws OCSException
615
-	 */
616
-	public function editUser(string $userId, string $key, string $value): DataResponse {
617
-		$currentLoggedInUser = $this->userSession->getUser();
618
-
619
-		$targetUser = $this->userManager->get($userId);
620
-		if ($targetUser === null) {
621
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
622
-		}
623
-
624
-		$permittedFields = [];
625
-		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
626
-			// Editing self (display, email)
627
-			if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
628
-				if ($targetUser->getBackend() instanceof ISetDisplayNameBackend
629
-					|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)) {
630
-					$permittedFields[] = 'display';
631
-					$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
632
-				}
633
-				$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
634
-			}
635
-
636
-			$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX;
637
-			$permittedFields[] = IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX;
638
-
639
-			$permittedFields[] = 'password';
640
-			if ($this->config->getSystemValue('force_language', false) === false ||
641
-				$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
642
-				$permittedFields[] = 'language';
643
-			}
644
-
645
-			if ($this->config->getSystemValue('force_locale', false) === false ||
646
-				$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
647
-				$permittedFields[] = 'locale';
648
-			}
649
-
650
-			$permittedFields[] = IAccountManager::PROPERTY_PHONE;
651
-			$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
652
-			$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
653
-			$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
654
-			$permittedFields[] = IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX;
655
-			$permittedFields[] = IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX;
656
-			$permittedFields[] = IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX;
657
-			$permittedFields[] = IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX;
658
-
659
-			$permittedFields[] = IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX;
660
-
661
-			// If admin they can edit their own quota
662
-			if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
663
-				$permittedFields[] = 'quota';
664
-			}
665
-		} else {
666
-			// Check if admin / subadmin
667
-			$subAdminManager = $this->groupManager->getSubAdmin();
668
-			if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())
669
-			|| $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
670
-				// They have permissions over the user
671
-				if ($targetUser->getBackend() instanceof ISetDisplayNameBackend
672
-					|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)) {
673
-					$permittedFields[] = 'display';
674
-					$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
675
-				}
676
-				$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
677
-				$permittedFields[] = 'password';
678
-				$permittedFields[] = 'language';
679
-				$permittedFields[] = 'locale';
680
-				$permittedFields[] = IAccountManager::PROPERTY_PHONE;
681
-				$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
682
-				$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
683
-				$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
684
-				$permittedFields[] = 'quota';
685
-			} else {
686
-				// No rights
687
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
688
-			}
689
-		}
690
-		// Check if permitted to edit this field
691
-		if (!in_array($key, $permittedFields)) {
692
-			throw new OCSException('', 103);
693
-		}
694
-		// Process the edit
695
-		switch ($key) {
696
-			case 'display':
697
-			case IAccountManager::PROPERTY_DISPLAYNAME:
698
-				$targetUser->setDisplayName($value);
699
-				break;
700
-			case 'quota':
701
-				$quota = $value;
702
-				if ($quota !== 'none' && $quota !== 'default') {
703
-					if (is_numeric($quota)) {
704
-						$quota = (float) $quota;
705
-					} else {
706
-						$quota = \OCP\Util::computerFileSize($quota);
707
-					}
708
-					if ($quota === false) {
709
-						throw new OCSException('Invalid quota value '.$value, 102);
710
-					}
711
-					if ($quota === -1) {
712
-						$quota = 'none';
713
-					} else {
714
-						$quota = \OCP\Util::humanFileSize($quota);
715
-					}
716
-				}
717
-				$targetUser->setQuota($quota);
718
-				break;
719
-			case 'password':
720
-				try {
721
-					if (!$targetUser->canChangePassword()) {
722
-						throw new OCSException('Setting the password is not supported by the users backend', 103);
723
-					}
724
-					$targetUser->setPassword($value);
725
-				} catch (HintException $e) { // password policy error
726
-					throw new OCSException($e->getMessage(), 103);
727
-				}
728
-				break;
729
-			case 'language':
730
-				$languagesCodes = $this->l10nFactory->findAvailableLanguages();
731
-				if (!in_array($value, $languagesCodes, true) && $value !== 'en') {
732
-					throw new OCSException('Invalid language', 102);
733
-				}
734
-				$this->config->setUserValue($targetUser->getUID(), 'core', 'lang', $value);
735
-				break;
736
-			case 'locale':
737
-				if (!$this->l10nFactory->localeExists($value)) {
738
-					throw new OCSException('Invalid locale', 102);
739
-				}
740
-				$this->config->setUserValue($targetUser->getUID(), 'core', 'locale', $value);
741
-				break;
742
-			case IAccountManager::PROPERTY_EMAIL:
743
-				if (filter_var($value, FILTER_VALIDATE_EMAIL) || $value === '') {
744
-					$targetUser->setEMailAddress($value);
745
-				} else {
746
-					throw new OCSException('', 102);
747
-				}
748
-				break;
749
-			case IAccountManager::PROPERTY_PHONE:
750
-			case IAccountManager::PROPERTY_ADDRESS:
751
-			case IAccountManager::PROPERTY_WEBSITE:
752
-			case IAccountManager::PROPERTY_TWITTER:
753
-				$userAccount = $this->accountManager->getAccount($targetUser);
754
-				$userProperty = $userAccount->getProperty($key);
755
-				if ($userProperty->getValue() !== $value) {
756
-					try {
757
-						$userProperty->setValue($value);
758
-						$this->accountManager->updateAccount($userAccount);
759
-
760
-						if ($userProperty->getName() === IAccountManager::PROPERTY_PHONE) {
761
-							$this->knownUserService->deleteByContactUserId($targetUser->getUID());
762
-						}
763
-					} catch (\InvalidArgumentException $e) {
764
-						throw new OCSException('Invalid ' . $e->getMessage(), 102);
765
-					}
766
-				}
767
-				break;
768
-			case IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX:
769
-			case IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX:
770
-			case IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX:
771
-			case IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX:
772
-			case IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX:
773
-			case IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX:
774
-			case IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX:
775
-				$propertyName = substr($key, 0, strlen($key) - strlen(self::SCOPE_SUFFIX));
776
-				$userAccount = $this->accountManager->getAccount($targetUser);
777
-				$userProperty = $userAccount->getProperty($propertyName);
778
-				if ($userProperty->getScope() !== $value) {
779
-					try {
780
-						$userProperty->setScope($value);
781
-						$this->accountManager->updateAccount($userAccount);
782
-					} catch (\InvalidArgumentException $e) {
783
-						throw new OCSException('Invalid ' . $e->getMessage(), 102);
784
-					}
785
-				}
786
-				break;
787
-			default:
788
-				throw new OCSException('', 103);
789
-		}
790
-		return new DataResponse();
791
-	}
792
-
793
-	/**
794
-	 * @PasswordConfirmationRequired
795
-	 * @NoAdminRequired
796
-	 *
797
-	 * @param string $userId
798
-	 *
799
-	 * @return DataResponse
800
-	 *
801
-	 * @throws OCSException
802
-	 */
803
-	public function wipeUserDevices(string $userId): DataResponse {
804
-		/** @var IUser $currentLoggedInUser */
805
-		$currentLoggedInUser = $this->userSession->getUser();
806
-
807
-		$targetUser = $this->userManager->get($userId);
808
-
809
-		if ($targetUser === null) {
810
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
811
-		}
812
-
813
-		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
814
-			throw new OCSException('', 101);
815
-		}
816
-
817
-		// If not permitted
818
-		$subAdminManager = $this->groupManager->getSubAdmin();
819
-		if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
820
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
821
-		}
822
-
823
-		$this->remoteWipe->markAllTokensForWipe($targetUser);
824
-
825
-		return new DataResponse();
826
-	}
827
-
828
-	/**
829
-	 * @PasswordConfirmationRequired
830
-	 * @NoAdminRequired
831
-	 *
832
-	 * @param string $userId
833
-	 * @return DataResponse
834
-	 * @throws OCSException
835
-	 */
836
-	public function deleteUser(string $userId): DataResponse {
837
-		$currentLoggedInUser = $this->userSession->getUser();
838
-
839
-		$targetUser = $this->userManager->get($userId);
840
-
841
-		if ($targetUser === null) {
842
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
843
-		}
844
-
845
-		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
846
-			throw new OCSException('', 101);
847
-		}
848
-
849
-		// If not permitted
850
-		$subAdminManager = $this->groupManager->getSubAdmin();
851
-		if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
852
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
853
-		}
854
-
855
-		// Go ahead with the delete
856
-		if ($targetUser->delete()) {
857
-			return new DataResponse();
858
-		} else {
859
-			throw new OCSException('', 101);
860
-		}
861
-	}
862
-
863
-	/**
864
-	 * @PasswordConfirmationRequired
865
-	 * @NoAdminRequired
866
-	 *
867
-	 * @param string $userId
868
-	 * @return DataResponse
869
-	 * @throws OCSException
870
-	 * @throws OCSForbiddenException
871
-	 */
872
-	public function disableUser(string $userId): DataResponse {
873
-		return $this->setEnabled($userId, false);
874
-	}
875
-
876
-	/**
877
-	 * @PasswordConfirmationRequired
878
-	 * @NoAdminRequired
879
-	 *
880
-	 * @param string $userId
881
-	 * @return DataResponse
882
-	 * @throws OCSException
883
-	 * @throws OCSForbiddenException
884
-	 */
885
-	public function enableUser(string $userId): DataResponse {
886
-		return $this->setEnabled($userId, true);
887
-	}
888
-
889
-	/**
890
-	 * @param string $userId
891
-	 * @param bool $value
892
-	 * @return DataResponse
893
-	 * @throws OCSException
894
-	 */
895
-	private function setEnabled(string $userId, bool $value): DataResponse {
896
-		$currentLoggedInUser = $this->userSession->getUser();
897
-
898
-		$targetUser = $this->userManager->get($userId);
899
-		if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
900
-			throw new OCSException('', 101);
901
-		}
902
-
903
-		// If not permitted
904
-		$subAdminManager = $this->groupManager->getSubAdmin();
905
-		if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
906
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
907
-		}
908
-
909
-		// enable/disable the user now
910
-		$targetUser->setEnabled($value);
911
-		return new DataResponse();
912
-	}
913
-
914
-	/**
915
-	 * @NoAdminRequired
916
-	 * @NoSubAdminRequired
917
-	 *
918
-	 * @param string $userId
919
-	 * @return DataResponse
920
-	 * @throws OCSException
921
-	 */
922
-	public function getUsersGroups(string $userId): DataResponse {
923
-		$loggedInUser = $this->userSession->getUser();
924
-
925
-		$targetUser = $this->userManager->get($userId);
926
-		if ($targetUser === null) {
927
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
928
-		}
929
-
930
-		if ($targetUser->getUID() === $loggedInUser->getUID() || $this->groupManager->isAdmin($loggedInUser->getUID())) {
931
-			// Self lookup or admin lookup
932
-			return new DataResponse([
933
-				'groups' => $this->groupManager->getUserGroupIds($targetUser)
934
-			]);
935
-		} else {
936
-			$subAdminManager = $this->groupManager->getSubAdmin();
937
-
938
-			// Looking up someone else
939
-			if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
940
-				// Return the group that the method caller is subadmin of for the user in question
941
-				/** @var IGroup[] $getSubAdminsGroups */
942
-				$getSubAdminsGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
943
-				foreach ($getSubAdminsGroups as $key => $group) {
944
-					$getSubAdminsGroups[$key] = $group->getGID();
945
-				}
946
-				$groups = array_intersect(
947
-					$getSubAdminsGroups,
948
-					$this->groupManager->getUserGroupIds($targetUser)
949
-				);
950
-				return new DataResponse(['groups' => $groups]);
951
-			} else {
952
-				// Not permitted
953
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
954
-			}
955
-		}
956
-	}
957
-
958
-	/**
959
-	 * @PasswordConfirmationRequired
960
-	 * @NoAdminRequired
961
-	 *
962
-	 * @param string $userId
963
-	 * @param string $groupid
964
-	 * @return DataResponse
965
-	 * @throws OCSException
966
-	 */
967
-	public function addToGroup(string $userId, string $groupid = ''): DataResponse {
968
-		if ($groupid === '') {
969
-			throw new OCSException('', 101);
970
-		}
971
-
972
-		$group = $this->groupManager->get($groupid);
973
-		$targetUser = $this->userManager->get($userId);
974
-		if ($group === null) {
975
-			throw new OCSException('', 102);
976
-		}
977
-		if ($targetUser === null) {
978
-			throw new OCSException('', 103);
979
-		}
980
-
981
-		// If they're not an admin, check they are a subadmin of the group in question
982
-		$loggedInUser = $this->userSession->getUser();
983
-		$subAdminManager = $this->groupManager->getSubAdmin();
984
-		if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
985
-			throw new OCSException('', 104);
986
-		}
987
-
988
-		// Add user to group
989
-		$group->addUser($targetUser);
990
-		return new DataResponse();
991
-	}
992
-
993
-	/**
994
-	 * @PasswordConfirmationRequired
995
-	 * @NoAdminRequired
996
-	 *
997
-	 * @param string $userId
998
-	 * @param string $groupid
999
-	 * @return DataResponse
1000
-	 * @throws OCSException
1001
-	 */
1002
-	public function removeFromGroup(string $userId, string $groupid): DataResponse {
1003
-		$loggedInUser = $this->userSession->getUser();
1004
-
1005
-		if ($groupid === null || trim($groupid) === '') {
1006
-			throw new OCSException('', 101);
1007
-		}
1008
-
1009
-		$group = $this->groupManager->get($groupid);
1010
-		if ($group === null) {
1011
-			throw new OCSException('', 102);
1012
-		}
1013
-
1014
-		$targetUser = $this->userManager->get($userId);
1015
-		if ($targetUser === null) {
1016
-			throw new OCSException('', 103);
1017
-		}
1018
-
1019
-		// If they're not an admin, check they are a subadmin of the group in question
1020
-		$subAdminManager = $this->groupManager->getSubAdmin();
1021
-		if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
1022
-			throw new OCSException('', 104);
1023
-		}
1024
-
1025
-		// Check they aren't removing themselves from 'admin' or their 'subadmin; group
1026
-		if ($targetUser->getUID() === $loggedInUser->getUID()) {
1027
-			if ($this->groupManager->isAdmin($loggedInUser->getUID())) {
1028
-				if ($group->getGID() === 'admin') {
1029
-					throw new OCSException('Cannot remove yourself from the admin group', 105);
1030
-				}
1031
-			} else {
1032
-				// Not an admin, so the user must be a subadmin of this group, but that is not allowed.
1033
-				throw new OCSException('Cannot remove yourself from this group as you are a SubAdmin', 105);
1034
-			}
1035
-		} elseif (!$this->groupManager->isAdmin($loggedInUser->getUID())) {
1036
-			/** @var IGroup[] $subAdminGroups */
1037
-			$subAdminGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
1038
-			$subAdminGroups = array_map(function (IGroup $subAdminGroup) {
1039
-				return $subAdminGroup->getGID();
1040
-			}, $subAdminGroups);
1041
-			$userGroups = $this->groupManager->getUserGroupIds($targetUser);
1042
-			$userSubAdminGroups = array_intersect($subAdminGroups, $userGroups);
1043
-
1044
-			if (count($userSubAdminGroups) <= 1) {
1045
-				// Subadmin must not be able to remove a user from all their subadmin groups.
1046
-				throw new OCSException('Not viable to remove user from the last group you are SubAdmin of', 105);
1047
-			}
1048
-		}
1049
-
1050
-		// Remove user from group
1051
-		$group->removeUser($targetUser);
1052
-		return new DataResponse();
1053
-	}
1054
-
1055
-	/**
1056
-	 * Creates a subadmin
1057
-	 *
1058
-	 * @PasswordConfirmationRequired
1059
-	 *
1060
-	 * @param string $userId
1061
-	 * @param string $groupid
1062
-	 * @return DataResponse
1063
-	 * @throws OCSException
1064
-	 */
1065
-	public function addSubAdmin(string $userId, string $groupid): DataResponse {
1066
-		$group = $this->groupManager->get($groupid);
1067
-		$user = $this->userManager->get($userId);
1068
-
1069
-		// Check if the user exists
1070
-		if ($user === null) {
1071
-			throw new OCSException('User does not exist', 101);
1072
-		}
1073
-		// Check if group exists
1074
-		if ($group === null) {
1075
-			throw new OCSException('Group does not exist',  102);
1076
-		}
1077
-		// Check if trying to make subadmin of admin group
1078
-		if ($group->getGID() === 'admin') {
1079
-			throw new OCSException('Cannot create subadmins for admin group', 103);
1080
-		}
1081
-
1082
-		$subAdminManager = $this->groupManager->getSubAdmin();
1083
-
1084
-		// We cannot be subadmin twice
1085
-		if ($subAdminManager->isSubAdminOfGroup($user, $group)) {
1086
-			return new DataResponse();
1087
-		}
1088
-		// Go
1089
-		$subAdminManager->createSubAdmin($user, $group);
1090
-		return new DataResponse();
1091
-	}
1092
-
1093
-	/**
1094
-	 * Removes a subadmin from a group
1095
-	 *
1096
-	 * @PasswordConfirmationRequired
1097
-	 *
1098
-	 * @param string $userId
1099
-	 * @param string $groupid
1100
-	 * @return DataResponse
1101
-	 * @throws OCSException
1102
-	 */
1103
-	public function removeSubAdmin(string $userId, string $groupid): DataResponse {
1104
-		$group = $this->groupManager->get($groupid);
1105
-		$user = $this->userManager->get($userId);
1106
-		$subAdminManager = $this->groupManager->getSubAdmin();
1107
-
1108
-		// Check if the user exists
1109
-		if ($user === null) {
1110
-			throw new OCSException('User does not exist', 101);
1111
-		}
1112
-		// Check if the group exists
1113
-		if ($group === null) {
1114
-			throw new OCSException('Group does not exist', 101);
1115
-		}
1116
-		// Check if they are a subadmin of this said group
1117
-		if (!$subAdminManager->isSubAdminOfGroup($user, $group)) {
1118
-			throw new OCSException('User is not a subadmin of this group', 102);
1119
-		}
1120
-
1121
-		// Go
1122
-		$subAdminManager->deleteSubAdmin($user, $group);
1123
-		return new DataResponse();
1124
-	}
1125
-
1126
-	/**
1127
-	 * Get the groups a user is a subadmin of
1128
-	 *
1129
-	 * @param string $userId
1130
-	 * @return DataResponse
1131
-	 * @throws OCSException
1132
-	 */
1133
-	public function getUserSubAdminGroups(string $userId): DataResponse {
1134
-		$groups = $this->getUserSubAdminGroupsData($userId);
1135
-		return new DataResponse($groups);
1136
-	}
1137
-
1138
-	/**
1139
-	 * @NoAdminRequired
1140
-	 * @PasswordConfirmationRequired
1141
-	 *
1142
-	 * resend welcome message
1143
-	 *
1144
-	 * @param string $userId
1145
-	 * @return DataResponse
1146
-	 * @throws OCSException
1147
-	 */
1148
-	public function resendWelcomeMessage(string $userId): DataResponse {
1149
-		$currentLoggedInUser = $this->userSession->getUser();
1150
-
1151
-		$targetUser = $this->userManager->get($userId);
1152
-		if ($targetUser === null) {
1153
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1154
-		}
1155
-
1156
-		// Check if admin / subadmin
1157
-		$subAdminManager = $this->groupManager->getSubAdmin();
1158
-		if (!$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
1159
-			&& !$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
1160
-			// No rights
1161
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1162
-		}
1163
-
1164
-		$email = $targetUser->getEMailAddress();
1165
-		if ($email === '' || $email === null) {
1166
-			throw new OCSException('Email address not available', 101);
1167
-		}
1168
-
1169
-		try {
1170
-			$emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, false);
1171
-			$this->newUserMailHelper->sendMail($targetUser, $emailTemplate);
1172
-		} catch (\Exception $e) {
1173
-			$this->logger->error("Can't send new user mail to $email",
1174
-				[
1175
-					'app' => 'settings',
1176
-					'exception' => $e,
1177
-				]
1178
-			);
1179
-			throw new OCSException('Sending email failed', 102);
1180
-		}
1181
-
1182
-		return new DataResponse();
1183
-	}
78
+    /** @var IAppManager */
79
+    private $appManager;
80
+    /** @var IURLGenerator */
81
+    protected $urlGenerator;
82
+    /** @var LoggerInterface */
83
+    private $logger;
84
+    /** @var IFactory */
85
+    protected $l10nFactory;
86
+    /** @var NewUserMailHelper */
87
+    private $newUserMailHelper;
88
+    /** @var ISecureRandom */
89
+    private $secureRandom;
90
+    /** @var RemoteWipe */
91
+    private $remoteWipe;
92
+    /** @var KnownUserService */
93
+    private $knownUserService;
94
+    /** @var IEventDispatcher */
95
+    private $eventDispatcher;
96
+
97
+    public function __construct(string $appName,
98
+                                IRequest $request,
99
+                                IUserManager $userManager,
100
+                                IConfig $config,
101
+                                IAppManager $appManager,
102
+                                IGroupManager $groupManager,
103
+                                IUserSession $userSession,
104
+                                IAccountManager $accountManager,
105
+                                IURLGenerator $urlGenerator,
106
+                                LoggerInterface $logger,
107
+                                IFactory $l10nFactory,
108
+                                NewUserMailHelper $newUserMailHelper,
109
+                                ISecureRandom $secureRandom,
110
+                                RemoteWipe $remoteWipe,
111
+                                KnownUserService $knownUserService,
112
+                                IEventDispatcher $eventDispatcher) {
113
+        parent::__construct($appName,
114
+                            $request,
115
+                            $userManager,
116
+                            $config,
117
+                            $groupManager,
118
+                            $userSession,
119
+                            $accountManager,
120
+                            $l10nFactory);
121
+
122
+        $this->appManager = $appManager;
123
+        $this->urlGenerator = $urlGenerator;
124
+        $this->logger = $logger;
125
+        $this->l10nFactory = $l10nFactory;
126
+        $this->newUserMailHelper = $newUserMailHelper;
127
+        $this->secureRandom = $secureRandom;
128
+        $this->remoteWipe = $remoteWipe;
129
+        $this->knownUserService = $knownUserService;
130
+        $this->eventDispatcher = $eventDispatcher;
131
+    }
132
+
133
+    /**
134
+     * @NoAdminRequired
135
+     *
136
+     * returns a list of users
137
+     *
138
+     * @param string $search
139
+     * @param int $limit
140
+     * @param int $offset
141
+     * @return DataResponse
142
+     */
143
+    public function getUsers(string $search = '', int $limit = null, int $offset = 0): DataResponse {
144
+        $user = $this->userSession->getUser();
145
+        $users = [];
146
+
147
+        // Admin? Or SubAdmin?
148
+        $uid = $user->getUID();
149
+        $subAdminManager = $this->groupManager->getSubAdmin();
150
+        if ($this->groupManager->isAdmin($uid)) {
151
+            $users = $this->userManager->search($search, $limit, $offset);
152
+        } elseif ($subAdminManager->isSubAdmin($user)) {
153
+            $subAdminOfGroups = $subAdminManager->getSubAdminsGroups($user);
154
+            foreach ($subAdminOfGroups as $key => $group) {
155
+                $subAdminOfGroups[$key] = $group->getGID();
156
+            }
157
+
158
+            $users = [];
159
+            foreach ($subAdminOfGroups as $group) {
160
+                $users = array_merge($users, $this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
161
+            }
162
+        }
163
+
164
+        $users = array_keys($users);
165
+
166
+        return new DataResponse([
167
+            'users' => $users
168
+        ]);
169
+    }
170
+
171
+    /**
172
+     * @NoAdminRequired
173
+     *
174
+     * returns a list of users and their data
175
+     */
176
+    public function getUsersDetails(string $search = '', int $limit = null, int $offset = 0): DataResponse {
177
+        $currentUser = $this->userSession->getUser();
178
+        $users = [];
179
+
180
+        // Admin? Or SubAdmin?
181
+        $uid = $currentUser->getUID();
182
+        $subAdminManager = $this->groupManager->getSubAdmin();
183
+        if ($this->groupManager->isAdmin($uid)) {
184
+            $users = $this->userManager->search($search, $limit, $offset);
185
+            $users = array_keys($users);
186
+        } elseif ($subAdminManager->isSubAdmin($currentUser)) {
187
+            $subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
188
+            foreach ($subAdminOfGroups as $key => $group) {
189
+                $subAdminOfGroups[$key] = $group->getGID();
190
+            }
191
+
192
+            $users = [];
193
+            foreach ($subAdminOfGroups as $group) {
194
+                $users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
195
+            }
196
+            $users = array_merge(...$users);
197
+        }
198
+
199
+        $usersDetails = [];
200
+        foreach ($users as $userId) {
201
+            $userId = (string) $userId;
202
+            $userData = $this->getUserData($userId);
203
+            // Do not insert empty entry
204
+            if (!empty($userData)) {
205
+                $usersDetails[$userId] = $userData;
206
+            } else {
207
+                // Logged user does not have permissions to see this user
208
+                // only showing its id
209
+                $usersDetails[$userId] = ['id' => $userId];
210
+            }
211
+        }
212
+
213
+        return new DataResponse([
214
+            'users' => $usersDetails
215
+        ]);
216
+    }
217
+
218
+
219
+    /**
220
+     * @NoAdminRequired
221
+     * @NoSubAdminRequired
222
+     *
223
+     * @param string $location
224
+     * @param array $search
225
+     * @return DataResponse
226
+     */
227
+    public function searchByPhoneNumbers(string $location, array $search): DataResponse {
228
+        $phoneUtil = PhoneNumberUtil::getInstance();
229
+
230
+        if ($phoneUtil->getCountryCodeForRegion($location) === 0) {
231
+            // Not a valid region code
232
+            return new DataResponse([], Http::STATUS_BAD_REQUEST);
233
+        }
234
+
235
+        /** @var IUser $user */
236
+        $user = $this->userSession->getUser();
237
+        $knownTo = $user->getUID();
238
+        $defaultPhoneRegion = $this->config->getSystemValueString('default_phone_region');
239
+
240
+        $normalizedNumberToKey = [];
241
+        foreach ($search as $key => $phoneNumbers) {
242
+            foreach ($phoneNumbers as $phone) {
243
+                try {
244
+                    $phoneNumber = $phoneUtil->parse($phone, $location);
245
+                    if ($phoneNumber instanceof PhoneNumber && $phoneUtil->isValidNumber($phoneNumber)) {
246
+                        $normalizedNumber = $phoneUtil->format($phoneNumber, PhoneNumberFormat::E164);
247
+                        $normalizedNumberToKey[$normalizedNumber] = (string) $key;
248
+                    }
249
+                } catch (NumberParseException $e) {
250
+                }
251
+
252
+                if ($defaultPhoneRegion !== '' && $defaultPhoneRegion !== $location && strpos($phone, '0') === 0) {
253
+                    // If the number has a leading zero (no country code),
254
+                    // we also check the default phone region of the instance,
255
+                    // when it's different to the user's given region.
256
+                    try {
257
+                        $phoneNumber = $phoneUtil->parse($phone, $defaultPhoneRegion);
258
+                        if ($phoneNumber instanceof PhoneNumber && $phoneUtil->isValidNumber($phoneNumber)) {
259
+                            $normalizedNumber = $phoneUtil->format($phoneNumber, PhoneNumberFormat::E164);
260
+                            $normalizedNumberToKey[$normalizedNumber] = (string) $key;
261
+                        }
262
+                    } catch (NumberParseException $e) {
263
+                    }
264
+                }
265
+            }
266
+        }
267
+
268
+        $phoneNumbers = array_keys($normalizedNumberToKey);
269
+
270
+        if (empty($phoneNumbers)) {
271
+            return new DataResponse();
272
+        }
273
+
274
+        // Cleanup all previous entries and only allow new matches
275
+        $this->knownUserService->deleteKnownTo($knownTo);
276
+
277
+        $userMatches = $this->accountManager->searchUsers(IAccountManager::PROPERTY_PHONE, $phoneNumbers);
278
+
279
+        if (empty($userMatches)) {
280
+            return new DataResponse();
281
+        }
282
+
283
+        $cloudUrl = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/');
284
+        if (strpos($cloudUrl, 'http://') === 0) {
285
+            $cloudUrl = substr($cloudUrl, strlen('http://'));
286
+        } elseif (strpos($cloudUrl, 'https://') === 0) {
287
+            $cloudUrl = substr($cloudUrl, strlen('https://'));
288
+        }
289
+
290
+        $matches = [];
291
+        foreach ($userMatches as $phone => $userId) {
292
+            // Not using the ICloudIdManager as that would run a search for each contact to find the display name in the address book
293
+            $matches[$normalizedNumberToKey[$phone]] = $userId . '@' . $cloudUrl;
294
+            $this->knownUserService->storeIsKnownToUser($knownTo, $userId);
295
+        }
296
+
297
+        return new DataResponse($matches);
298
+    }
299
+
300
+    /**
301
+     * @throws OCSException
302
+     */
303
+    private function createNewUserId(): string {
304
+        $attempts = 0;
305
+        do {
306
+            $uidCandidate = $this->secureRandom->generate(10, ISecureRandom::CHAR_HUMAN_READABLE);
307
+            if (!$this->userManager->userExists($uidCandidate)) {
308
+                return $uidCandidate;
309
+            }
310
+            $attempts++;
311
+        } while ($attempts < 10);
312
+        throw new OCSException('Could not create non-existing user id', 111);
313
+    }
314
+
315
+    /**
316
+     * @PasswordConfirmationRequired
317
+     * @NoAdminRequired
318
+     *
319
+     * @param string $userid
320
+     * @param string $password
321
+     * @param string $displayName
322
+     * @param string $email
323
+     * @param array $groups
324
+     * @param array $subadmin
325
+     * @param string $quota
326
+     * @param string $language
327
+     * @return DataResponse
328
+     * @throws OCSException
329
+     */
330
+    public function addUser(string $userid,
331
+                            string $password = '',
332
+                            string $displayName = '',
333
+                            string $email = '',
334
+                            array $groups = [],
335
+                            array $subadmin = [],
336
+                            string $quota = '',
337
+                            string $language = ''): DataResponse {
338
+        $user = $this->userSession->getUser();
339
+        $isAdmin = $this->groupManager->isAdmin($user->getUID());
340
+        $subAdminManager = $this->groupManager->getSubAdmin();
341
+
342
+        if (empty($userid) && $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes') {
343
+            $userid = $this->createNewUserId();
344
+        }
345
+
346
+        if ($this->userManager->userExists($userid)) {
347
+            $this->logger->error('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']);
348
+            throw new OCSException('User already exists', 102);
349
+        }
350
+
351
+        if ($groups !== []) {
352
+            foreach ($groups as $group) {
353
+                if (!$this->groupManager->groupExists($group)) {
354
+                    throw new OCSException('group '.$group.' does not exist', 104);
355
+                }
356
+                if (!$isAdmin && !$subAdminManager->isSubAdminOfGroup($user, $this->groupManager->get($group))) {
357
+                    throw new OCSException('insufficient privileges for group '. $group, 105);
358
+                }
359
+            }
360
+        } else {
361
+            if (!$isAdmin) {
362
+                throw new OCSException('no group specified (required for subadmins)', 106);
363
+            }
364
+        }
365
+
366
+        $subadminGroups = [];
367
+        if ($subadmin !== []) {
368
+            foreach ($subadmin as $groupid) {
369
+                $group = $this->groupManager->get($groupid);
370
+                // Check if group exists
371
+                if ($group === null) {
372
+                    throw new OCSException('Subadmin group does not exist',  102);
373
+                }
374
+                // Check if trying to make subadmin of admin group
375
+                if ($group->getGID() === 'admin') {
376
+                    throw new OCSException('Cannot create subadmins for admin group', 103);
377
+                }
378
+                // Check if has permission to promote subadmins
379
+                if (!$subAdminManager->isSubAdminOfGroup($user, $group) && !$isAdmin) {
380
+                    throw new OCSForbiddenException('No permissions to promote subadmins');
381
+                }
382
+                $subadminGroups[] = $group;
383
+            }
384
+        }
385
+
386
+        $generatePasswordResetToken = false;
387
+        if ($password === '') {
388
+            if ($email === '') {
389
+                throw new OCSException('To send a password link to the user an email address is required.', 108);
390
+            }
391
+
392
+            $passwordEvent = new GenerateSecurePasswordEvent();
393
+            $this->eventDispatcher->dispatchTyped($passwordEvent);
394
+
395
+            $password = $passwordEvent->getPassword();
396
+            if ($password === null) {
397
+                // Fallback: ensure to pass password_policy in any case
398
+                $password = $this->secureRandom->generate(10)
399
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_UPPER)
400
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_LOWER)
401
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_DIGITS)
402
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_SYMBOLS);
403
+            }
404
+            $generatePasswordResetToken = true;
405
+        }
406
+
407
+        if ($email === '' && $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes') {
408
+            throw new OCSException('Required email address was not provided', 110);
409
+        }
410
+
411
+        try {
412
+            $newUser = $this->userManager->createUser($userid, $password);
413
+            $this->logger->info('Successful addUser call with userid: ' . $userid, ['app' => 'ocs_api']);
414
+
415
+            foreach ($groups as $group) {
416
+                $this->groupManager->get($group)->addUser($newUser);
417
+                $this->logger->info('Added userid ' . $userid . ' to group ' . $group, ['app' => 'ocs_api']);
418
+            }
419
+            foreach ($subadminGroups as $group) {
420
+                $subAdminManager->createSubAdmin($newUser, $group);
421
+            }
422
+
423
+            if ($displayName !== '') {
424
+                $this->editUser($userid, 'display', $displayName);
425
+            }
426
+
427
+            if ($quota !== '') {
428
+                $this->editUser($userid, 'quota', $quota);
429
+            }
430
+
431
+            if ($language !== '') {
432
+                $this->editUser($userid, 'language', $language);
433
+            }
434
+
435
+            // Send new user mail only if a mail is set
436
+            if ($email !== '') {
437
+                $newUser->setEMailAddress($email);
438
+                if ($this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes') {
439
+                    try {
440
+                        $emailTemplate = $this->newUserMailHelper->generateTemplate($newUser, $generatePasswordResetToken);
441
+                        $this->newUserMailHelper->sendMail($newUser, $emailTemplate);
442
+                    } catch (\Exception $e) {
443
+                        // Mail could be failing hard or just be plain not configured
444
+                        // Logging error as it is the hardest of the two
445
+                        $this->logger->error("Unable to send the invitation mail to $email",
446
+                            [
447
+                                'app' => 'ocs_api',
448
+                                'exception' => $e,
449
+                            ]
450
+                        );
451
+                    }
452
+                }
453
+            }
454
+
455
+            return new DataResponse(['id' => $userid]);
456
+        } catch (HintException $e) {
457
+            $this->logger->warning('Failed addUser attempt with hint exception.',
458
+                [
459
+                    'app' => 'ocs_api',
460
+                    'exception' => $e,
461
+                ]
462
+            );
463
+            throw new OCSException($e->getHint(), 107);
464
+        } catch (OCSException $e) {
465
+            $this->logger->warning('Failed addUser attempt with ocs exeption.',
466
+                [
467
+                    'app' => 'ocs_api',
468
+                    'exception' => $e,
469
+                ]
470
+            );
471
+            throw $e;
472
+        } catch (\InvalidArgumentException $e) {
473
+            $this->logger->error('Failed addUser attempt with invalid argument exeption.',
474
+                [
475
+                    'app' => 'ocs_api',
476
+                    'exception' => $e,
477
+                ]
478
+            );
479
+            throw new OCSException($e->getMessage(), 101);
480
+        } catch (\Exception $e) {
481
+            $this->logger->error('Failed addUser attempt with exception.',
482
+                [
483
+                    'app' => 'ocs_api',
484
+                    'exception' => $e
485
+                ]
486
+            );
487
+            throw new OCSException('Bad request', 101);
488
+        }
489
+    }
490
+
491
+    /**
492
+     * @NoAdminRequired
493
+     * @NoSubAdminRequired
494
+     *
495
+     * gets user info
496
+     *
497
+     * @param string $userId
498
+     * @return DataResponse
499
+     * @throws OCSException
500
+     */
501
+    public function getUser(string $userId): DataResponse {
502
+        $includeScopes = false;
503
+        $currentUser = $this->userSession->getUser();
504
+        if ($currentUser && $currentUser->getUID() === $userId) {
505
+            $includeScopes = true;
506
+        }
507
+
508
+        $data = $this->getUserData($userId, $includeScopes);
509
+        // getUserData returns empty array if not enough permissions
510
+        if (empty($data)) {
511
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
512
+        }
513
+        return new DataResponse($data);
514
+    }
515
+
516
+    /**
517
+     * @NoAdminRequired
518
+     * @NoSubAdminRequired
519
+     *
520
+     * gets user info from the currently logged in user
521
+     *
522
+     * @return DataResponse
523
+     * @throws OCSException
524
+     */
525
+    public function getCurrentUser(): DataResponse {
526
+        $user = $this->userSession->getUser();
527
+        if ($user) {
528
+            $data = $this->getUserData($user->getUID(), true);
529
+            // rename "displayname" to "display-name" only for this call to keep
530
+            // the API stable.
531
+            $data['display-name'] = $data['displayname'];
532
+            unset($data['displayname']);
533
+            return new DataResponse($data);
534
+        }
535
+
536
+        throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
537
+    }
538
+
539
+    /**
540
+     * @NoAdminRequired
541
+     * @NoSubAdminRequired
542
+     *
543
+     * @return DataResponse
544
+     * @throws OCSException
545
+     */
546
+    public function getEditableFields(): DataResponse {
547
+        $currentLoggedInUser = $this->userSession->getUser();
548
+        if (!$currentLoggedInUser instanceof IUser) {
549
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
550
+        }
551
+
552
+        return $this->getEditableFieldsForUser($currentLoggedInUser->getUID());
553
+    }
554
+
555
+    /**
556
+     * @NoAdminRequired
557
+     * @NoSubAdminRequired
558
+     *
559
+     * @param string $userId
560
+     * @return DataResponse
561
+     * @throws OCSException
562
+     */
563
+    public function getEditableFieldsForUser(string $userId): DataResponse {
564
+        $currentLoggedInUser = $this->userSession->getUser();
565
+        if (!$currentLoggedInUser instanceof IUser) {
566
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
567
+        }
568
+
569
+        $permittedFields = [];
570
+
571
+        if ($userId !== $currentLoggedInUser->getUID()) {
572
+            $targetUser = $this->userManager->get($userId);
573
+            if (!$targetUser instanceof IUser) {
574
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
575
+            }
576
+
577
+            $subAdminManager = $this->groupManager->getSubAdmin();
578
+            if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID())
579
+                && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
580
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
581
+            }
582
+        } else {
583
+            $targetUser = $currentLoggedInUser;
584
+        }
585
+
586
+        // Editing self (display, email)
587
+        if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
588
+            if ($targetUser->getBackend() instanceof ISetDisplayNameBackend
589
+                || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)) {
590
+                $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
591
+            }
592
+            $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
593
+        }
594
+
595
+        $permittedFields[] = IAccountManager::PROPERTY_PHONE;
596
+        $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
597
+        $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
598
+        $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
599
+
600
+        return new DataResponse($permittedFields);
601
+    }
602
+
603
+    /**
604
+     * @NoAdminRequired
605
+     * @NoSubAdminRequired
606
+     * @PasswordConfirmationRequired
607
+     *
608
+     * edit users
609
+     *
610
+     * @param string $userId
611
+     * @param string $key
612
+     * @param string $value
613
+     * @return DataResponse
614
+     * @throws OCSException
615
+     */
616
+    public function editUser(string $userId, string $key, string $value): DataResponse {
617
+        $currentLoggedInUser = $this->userSession->getUser();
618
+
619
+        $targetUser = $this->userManager->get($userId);
620
+        if ($targetUser === null) {
621
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
622
+        }
623
+
624
+        $permittedFields = [];
625
+        if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
626
+            // Editing self (display, email)
627
+            if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
628
+                if ($targetUser->getBackend() instanceof ISetDisplayNameBackend
629
+                    || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)) {
630
+                    $permittedFields[] = 'display';
631
+                    $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
632
+                }
633
+                $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
634
+            }
635
+
636
+            $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX;
637
+            $permittedFields[] = IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX;
638
+
639
+            $permittedFields[] = 'password';
640
+            if ($this->config->getSystemValue('force_language', false) === false ||
641
+                $this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
642
+                $permittedFields[] = 'language';
643
+            }
644
+
645
+            if ($this->config->getSystemValue('force_locale', false) === false ||
646
+                $this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
647
+                $permittedFields[] = 'locale';
648
+            }
649
+
650
+            $permittedFields[] = IAccountManager::PROPERTY_PHONE;
651
+            $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
652
+            $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
653
+            $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
654
+            $permittedFields[] = IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX;
655
+            $permittedFields[] = IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX;
656
+            $permittedFields[] = IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX;
657
+            $permittedFields[] = IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX;
658
+
659
+            $permittedFields[] = IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX;
660
+
661
+            // If admin they can edit their own quota
662
+            if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
663
+                $permittedFields[] = 'quota';
664
+            }
665
+        } else {
666
+            // Check if admin / subadmin
667
+            $subAdminManager = $this->groupManager->getSubAdmin();
668
+            if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())
669
+            || $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
670
+                // They have permissions over the user
671
+                if ($targetUser->getBackend() instanceof ISetDisplayNameBackend
672
+                    || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)) {
673
+                    $permittedFields[] = 'display';
674
+                    $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
675
+                }
676
+                $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
677
+                $permittedFields[] = 'password';
678
+                $permittedFields[] = 'language';
679
+                $permittedFields[] = 'locale';
680
+                $permittedFields[] = IAccountManager::PROPERTY_PHONE;
681
+                $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
682
+                $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
683
+                $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
684
+                $permittedFields[] = 'quota';
685
+            } else {
686
+                // No rights
687
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
688
+            }
689
+        }
690
+        // Check if permitted to edit this field
691
+        if (!in_array($key, $permittedFields)) {
692
+            throw new OCSException('', 103);
693
+        }
694
+        // Process the edit
695
+        switch ($key) {
696
+            case 'display':
697
+            case IAccountManager::PROPERTY_DISPLAYNAME:
698
+                $targetUser->setDisplayName($value);
699
+                break;
700
+            case 'quota':
701
+                $quota = $value;
702
+                if ($quota !== 'none' && $quota !== 'default') {
703
+                    if (is_numeric($quota)) {
704
+                        $quota = (float) $quota;
705
+                    } else {
706
+                        $quota = \OCP\Util::computerFileSize($quota);
707
+                    }
708
+                    if ($quota === false) {
709
+                        throw new OCSException('Invalid quota value '.$value, 102);
710
+                    }
711
+                    if ($quota === -1) {
712
+                        $quota = 'none';
713
+                    } else {
714
+                        $quota = \OCP\Util::humanFileSize($quota);
715
+                    }
716
+                }
717
+                $targetUser->setQuota($quota);
718
+                break;
719
+            case 'password':
720
+                try {
721
+                    if (!$targetUser->canChangePassword()) {
722
+                        throw new OCSException('Setting the password is not supported by the users backend', 103);
723
+                    }
724
+                    $targetUser->setPassword($value);
725
+                } catch (HintException $e) { // password policy error
726
+                    throw new OCSException($e->getMessage(), 103);
727
+                }
728
+                break;
729
+            case 'language':
730
+                $languagesCodes = $this->l10nFactory->findAvailableLanguages();
731
+                if (!in_array($value, $languagesCodes, true) && $value !== 'en') {
732
+                    throw new OCSException('Invalid language', 102);
733
+                }
734
+                $this->config->setUserValue($targetUser->getUID(), 'core', 'lang', $value);
735
+                break;
736
+            case 'locale':
737
+                if (!$this->l10nFactory->localeExists($value)) {
738
+                    throw new OCSException('Invalid locale', 102);
739
+                }
740
+                $this->config->setUserValue($targetUser->getUID(), 'core', 'locale', $value);
741
+                break;
742
+            case IAccountManager::PROPERTY_EMAIL:
743
+                if (filter_var($value, FILTER_VALIDATE_EMAIL) || $value === '') {
744
+                    $targetUser->setEMailAddress($value);
745
+                } else {
746
+                    throw new OCSException('', 102);
747
+                }
748
+                break;
749
+            case IAccountManager::PROPERTY_PHONE:
750
+            case IAccountManager::PROPERTY_ADDRESS:
751
+            case IAccountManager::PROPERTY_WEBSITE:
752
+            case IAccountManager::PROPERTY_TWITTER:
753
+                $userAccount = $this->accountManager->getAccount($targetUser);
754
+                $userProperty = $userAccount->getProperty($key);
755
+                if ($userProperty->getValue() !== $value) {
756
+                    try {
757
+                        $userProperty->setValue($value);
758
+                        $this->accountManager->updateAccount($userAccount);
759
+
760
+                        if ($userProperty->getName() === IAccountManager::PROPERTY_PHONE) {
761
+                            $this->knownUserService->deleteByContactUserId($targetUser->getUID());
762
+                        }
763
+                    } catch (\InvalidArgumentException $e) {
764
+                        throw new OCSException('Invalid ' . $e->getMessage(), 102);
765
+                    }
766
+                }
767
+                break;
768
+            case IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX:
769
+            case IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX:
770
+            case IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX:
771
+            case IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX:
772
+            case IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX:
773
+            case IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX:
774
+            case IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX:
775
+                $propertyName = substr($key, 0, strlen($key) - strlen(self::SCOPE_SUFFIX));
776
+                $userAccount = $this->accountManager->getAccount($targetUser);
777
+                $userProperty = $userAccount->getProperty($propertyName);
778
+                if ($userProperty->getScope() !== $value) {
779
+                    try {
780
+                        $userProperty->setScope($value);
781
+                        $this->accountManager->updateAccount($userAccount);
782
+                    } catch (\InvalidArgumentException $e) {
783
+                        throw new OCSException('Invalid ' . $e->getMessage(), 102);
784
+                    }
785
+                }
786
+                break;
787
+            default:
788
+                throw new OCSException('', 103);
789
+        }
790
+        return new DataResponse();
791
+    }
792
+
793
+    /**
794
+     * @PasswordConfirmationRequired
795
+     * @NoAdminRequired
796
+     *
797
+     * @param string $userId
798
+     *
799
+     * @return DataResponse
800
+     *
801
+     * @throws OCSException
802
+     */
803
+    public function wipeUserDevices(string $userId): DataResponse {
804
+        /** @var IUser $currentLoggedInUser */
805
+        $currentLoggedInUser = $this->userSession->getUser();
806
+
807
+        $targetUser = $this->userManager->get($userId);
808
+
809
+        if ($targetUser === null) {
810
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
811
+        }
812
+
813
+        if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
814
+            throw new OCSException('', 101);
815
+        }
816
+
817
+        // If not permitted
818
+        $subAdminManager = $this->groupManager->getSubAdmin();
819
+        if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
820
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
821
+        }
822
+
823
+        $this->remoteWipe->markAllTokensForWipe($targetUser);
824
+
825
+        return new DataResponse();
826
+    }
827
+
828
+    /**
829
+     * @PasswordConfirmationRequired
830
+     * @NoAdminRequired
831
+     *
832
+     * @param string $userId
833
+     * @return DataResponse
834
+     * @throws OCSException
835
+     */
836
+    public function deleteUser(string $userId): DataResponse {
837
+        $currentLoggedInUser = $this->userSession->getUser();
838
+
839
+        $targetUser = $this->userManager->get($userId);
840
+
841
+        if ($targetUser === null) {
842
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
843
+        }
844
+
845
+        if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
846
+            throw new OCSException('', 101);
847
+        }
848
+
849
+        // If not permitted
850
+        $subAdminManager = $this->groupManager->getSubAdmin();
851
+        if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
852
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
853
+        }
854
+
855
+        // Go ahead with the delete
856
+        if ($targetUser->delete()) {
857
+            return new DataResponse();
858
+        } else {
859
+            throw new OCSException('', 101);
860
+        }
861
+    }
862
+
863
+    /**
864
+     * @PasswordConfirmationRequired
865
+     * @NoAdminRequired
866
+     *
867
+     * @param string $userId
868
+     * @return DataResponse
869
+     * @throws OCSException
870
+     * @throws OCSForbiddenException
871
+     */
872
+    public function disableUser(string $userId): DataResponse {
873
+        return $this->setEnabled($userId, false);
874
+    }
875
+
876
+    /**
877
+     * @PasswordConfirmationRequired
878
+     * @NoAdminRequired
879
+     *
880
+     * @param string $userId
881
+     * @return DataResponse
882
+     * @throws OCSException
883
+     * @throws OCSForbiddenException
884
+     */
885
+    public function enableUser(string $userId): DataResponse {
886
+        return $this->setEnabled($userId, true);
887
+    }
888
+
889
+    /**
890
+     * @param string $userId
891
+     * @param bool $value
892
+     * @return DataResponse
893
+     * @throws OCSException
894
+     */
895
+    private function setEnabled(string $userId, bool $value): DataResponse {
896
+        $currentLoggedInUser = $this->userSession->getUser();
897
+
898
+        $targetUser = $this->userManager->get($userId);
899
+        if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
900
+            throw new OCSException('', 101);
901
+        }
902
+
903
+        // If not permitted
904
+        $subAdminManager = $this->groupManager->getSubAdmin();
905
+        if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
906
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
907
+        }
908
+
909
+        // enable/disable the user now
910
+        $targetUser->setEnabled($value);
911
+        return new DataResponse();
912
+    }
913
+
914
+    /**
915
+     * @NoAdminRequired
916
+     * @NoSubAdminRequired
917
+     *
918
+     * @param string $userId
919
+     * @return DataResponse
920
+     * @throws OCSException
921
+     */
922
+    public function getUsersGroups(string $userId): DataResponse {
923
+        $loggedInUser = $this->userSession->getUser();
924
+
925
+        $targetUser = $this->userManager->get($userId);
926
+        if ($targetUser === null) {
927
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
928
+        }
929
+
930
+        if ($targetUser->getUID() === $loggedInUser->getUID() || $this->groupManager->isAdmin($loggedInUser->getUID())) {
931
+            // Self lookup or admin lookup
932
+            return new DataResponse([
933
+                'groups' => $this->groupManager->getUserGroupIds($targetUser)
934
+            ]);
935
+        } else {
936
+            $subAdminManager = $this->groupManager->getSubAdmin();
937
+
938
+            // Looking up someone else
939
+            if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
940
+                // Return the group that the method caller is subadmin of for the user in question
941
+                /** @var IGroup[] $getSubAdminsGroups */
942
+                $getSubAdminsGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
943
+                foreach ($getSubAdminsGroups as $key => $group) {
944
+                    $getSubAdminsGroups[$key] = $group->getGID();
945
+                }
946
+                $groups = array_intersect(
947
+                    $getSubAdminsGroups,
948
+                    $this->groupManager->getUserGroupIds($targetUser)
949
+                );
950
+                return new DataResponse(['groups' => $groups]);
951
+            } else {
952
+                // Not permitted
953
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
954
+            }
955
+        }
956
+    }
957
+
958
+    /**
959
+     * @PasswordConfirmationRequired
960
+     * @NoAdminRequired
961
+     *
962
+     * @param string $userId
963
+     * @param string $groupid
964
+     * @return DataResponse
965
+     * @throws OCSException
966
+     */
967
+    public function addToGroup(string $userId, string $groupid = ''): DataResponse {
968
+        if ($groupid === '') {
969
+            throw new OCSException('', 101);
970
+        }
971
+
972
+        $group = $this->groupManager->get($groupid);
973
+        $targetUser = $this->userManager->get($userId);
974
+        if ($group === null) {
975
+            throw new OCSException('', 102);
976
+        }
977
+        if ($targetUser === null) {
978
+            throw new OCSException('', 103);
979
+        }
980
+
981
+        // If they're not an admin, check they are a subadmin of the group in question
982
+        $loggedInUser = $this->userSession->getUser();
983
+        $subAdminManager = $this->groupManager->getSubAdmin();
984
+        if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
985
+            throw new OCSException('', 104);
986
+        }
987
+
988
+        // Add user to group
989
+        $group->addUser($targetUser);
990
+        return new DataResponse();
991
+    }
992
+
993
+    /**
994
+     * @PasswordConfirmationRequired
995
+     * @NoAdminRequired
996
+     *
997
+     * @param string $userId
998
+     * @param string $groupid
999
+     * @return DataResponse
1000
+     * @throws OCSException
1001
+     */
1002
+    public function removeFromGroup(string $userId, string $groupid): DataResponse {
1003
+        $loggedInUser = $this->userSession->getUser();
1004
+
1005
+        if ($groupid === null || trim($groupid) === '') {
1006
+            throw new OCSException('', 101);
1007
+        }
1008
+
1009
+        $group = $this->groupManager->get($groupid);
1010
+        if ($group === null) {
1011
+            throw new OCSException('', 102);
1012
+        }
1013
+
1014
+        $targetUser = $this->userManager->get($userId);
1015
+        if ($targetUser === null) {
1016
+            throw new OCSException('', 103);
1017
+        }
1018
+
1019
+        // If they're not an admin, check they are a subadmin of the group in question
1020
+        $subAdminManager = $this->groupManager->getSubAdmin();
1021
+        if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
1022
+            throw new OCSException('', 104);
1023
+        }
1024
+
1025
+        // Check they aren't removing themselves from 'admin' or their 'subadmin; group
1026
+        if ($targetUser->getUID() === $loggedInUser->getUID()) {
1027
+            if ($this->groupManager->isAdmin($loggedInUser->getUID())) {
1028
+                if ($group->getGID() === 'admin') {
1029
+                    throw new OCSException('Cannot remove yourself from the admin group', 105);
1030
+                }
1031
+            } else {
1032
+                // Not an admin, so the user must be a subadmin of this group, but that is not allowed.
1033
+                throw new OCSException('Cannot remove yourself from this group as you are a SubAdmin', 105);
1034
+            }
1035
+        } elseif (!$this->groupManager->isAdmin($loggedInUser->getUID())) {
1036
+            /** @var IGroup[] $subAdminGroups */
1037
+            $subAdminGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
1038
+            $subAdminGroups = array_map(function (IGroup $subAdminGroup) {
1039
+                return $subAdminGroup->getGID();
1040
+            }, $subAdminGroups);
1041
+            $userGroups = $this->groupManager->getUserGroupIds($targetUser);
1042
+            $userSubAdminGroups = array_intersect($subAdminGroups, $userGroups);
1043
+
1044
+            if (count($userSubAdminGroups) <= 1) {
1045
+                // Subadmin must not be able to remove a user from all their subadmin groups.
1046
+                throw new OCSException('Not viable to remove user from the last group you are SubAdmin of', 105);
1047
+            }
1048
+        }
1049
+
1050
+        // Remove user from group
1051
+        $group->removeUser($targetUser);
1052
+        return new DataResponse();
1053
+    }
1054
+
1055
+    /**
1056
+     * Creates a subadmin
1057
+     *
1058
+     * @PasswordConfirmationRequired
1059
+     *
1060
+     * @param string $userId
1061
+     * @param string $groupid
1062
+     * @return DataResponse
1063
+     * @throws OCSException
1064
+     */
1065
+    public function addSubAdmin(string $userId, string $groupid): DataResponse {
1066
+        $group = $this->groupManager->get($groupid);
1067
+        $user = $this->userManager->get($userId);
1068
+
1069
+        // Check if the user exists
1070
+        if ($user === null) {
1071
+            throw new OCSException('User does not exist', 101);
1072
+        }
1073
+        // Check if group exists
1074
+        if ($group === null) {
1075
+            throw new OCSException('Group does not exist',  102);
1076
+        }
1077
+        // Check if trying to make subadmin of admin group
1078
+        if ($group->getGID() === 'admin') {
1079
+            throw new OCSException('Cannot create subadmins for admin group', 103);
1080
+        }
1081
+
1082
+        $subAdminManager = $this->groupManager->getSubAdmin();
1083
+
1084
+        // We cannot be subadmin twice
1085
+        if ($subAdminManager->isSubAdminOfGroup($user, $group)) {
1086
+            return new DataResponse();
1087
+        }
1088
+        // Go
1089
+        $subAdminManager->createSubAdmin($user, $group);
1090
+        return new DataResponse();
1091
+    }
1092
+
1093
+    /**
1094
+     * Removes a subadmin from a group
1095
+     *
1096
+     * @PasswordConfirmationRequired
1097
+     *
1098
+     * @param string $userId
1099
+     * @param string $groupid
1100
+     * @return DataResponse
1101
+     * @throws OCSException
1102
+     */
1103
+    public function removeSubAdmin(string $userId, string $groupid): DataResponse {
1104
+        $group = $this->groupManager->get($groupid);
1105
+        $user = $this->userManager->get($userId);
1106
+        $subAdminManager = $this->groupManager->getSubAdmin();
1107
+
1108
+        // Check if the user exists
1109
+        if ($user === null) {
1110
+            throw new OCSException('User does not exist', 101);
1111
+        }
1112
+        // Check if the group exists
1113
+        if ($group === null) {
1114
+            throw new OCSException('Group does not exist', 101);
1115
+        }
1116
+        // Check if they are a subadmin of this said group
1117
+        if (!$subAdminManager->isSubAdminOfGroup($user, $group)) {
1118
+            throw new OCSException('User is not a subadmin of this group', 102);
1119
+        }
1120
+
1121
+        // Go
1122
+        $subAdminManager->deleteSubAdmin($user, $group);
1123
+        return new DataResponse();
1124
+    }
1125
+
1126
+    /**
1127
+     * Get the groups a user is a subadmin of
1128
+     *
1129
+     * @param string $userId
1130
+     * @return DataResponse
1131
+     * @throws OCSException
1132
+     */
1133
+    public function getUserSubAdminGroups(string $userId): DataResponse {
1134
+        $groups = $this->getUserSubAdminGroupsData($userId);
1135
+        return new DataResponse($groups);
1136
+    }
1137
+
1138
+    /**
1139
+     * @NoAdminRequired
1140
+     * @PasswordConfirmationRequired
1141
+     *
1142
+     * resend welcome message
1143
+     *
1144
+     * @param string $userId
1145
+     * @return DataResponse
1146
+     * @throws OCSException
1147
+     */
1148
+    public function resendWelcomeMessage(string $userId): DataResponse {
1149
+        $currentLoggedInUser = $this->userSession->getUser();
1150
+
1151
+        $targetUser = $this->userManager->get($userId);
1152
+        if ($targetUser === null) {
1153
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1154
+        }
1155
+
1156
+        // Check if admin / subadmin
1157
+        $subAdminManager = $this->groupManager->getSubAdmin();
1158
+        if (!$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
1159
+            && !$this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
1160
+            // No rights
1161
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1162
+        }
1163
+
1164
+        $email = $targetUser->getEMailAddress();
1165
+        if ($email === '' || $email === null) {
1166
+            throw new OCSException('Email address not available', 101);
1167
+        }
1168
+
1169
+        try {
1170
+            $emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, false);
1171
+            $this->newUserMailHelper->sendMail($targetUser, $emailTemplate);
1172
+        } catch (\Exception $e) {
1173
+            $this->logger->error("Can't send new user mail to $email",
1174
+                [
1175
+                    'app' => 'settings',
1176
+                    'exception' => $e,
1177
+                ]
1178
+            );
1179
+            throw new OCSException('Sending email failed', 102);
1180
+        }
1181
+
1182
+        return new DataResponse();
1183
+    }
1184 1184
 }
Please login to merge, or discard this patch.