Completed
Push — master ( 5fe858...fff964 )
by John
40:08 queued 01:21
created
apps/settings/lib/Settings/Personal/PersonalInfo.php 1 patch
Indentation   +283 added lines, -283 removed lines patch added patch discarded remove patch
@@ -32,287 +32,287 @@
 block discarded – undo
32 32
 
33 33
 class PersonalInfo implements ISettings {
34 34
 
35
-	/** @var ProfileManager */
36
-	private $profileManager;
37
-
38
-	public function __construct(
39
-		private IConfig $config,
40
-		private IUserManager $userManager,
41
-		private IGroupManager $groupManager,
42
-		private IAccountManager $accountManager,
43
-		ProfileManager $profileManager,
44
-		private IAppManager $appManager,
45
-		private IFactory $l10nFactory,
46
-		private IL10N $l,
47
-		private IInitialState $initialStateService,
48
-		private IManager $manager,
49
-	) {
50
-		$this->profileManager = $profileManager;
51
-	}
52
-
53
-	public function getForm(): TemplateResponse {
54
-		$federationEnabled = $this->appManager->isEnabledForUser('federation');
55
-		$federatedFileSharingEnabled = $this->appManager->isEnabledForUser('federatedfilesharing');
56
-		$lookupServerUploadEnabled = false;
57
-		if ($federatedFileSharingEnabled) {
58
-			/** @var FederatedShareProvider $shareProvider */
59
-			$shareProvider = Server::get(FederatedShareProvider::class);
60
-			$lookupServerUploadEnabled = $shareProvider->isLookupServerUploadEnabled();
61
-		}
62
-
63
-		$uid = \OC_User::getUser();
64
-		$user = $this->userManager->get($uid);
65
-		$account = $this->accountManager->getAccount($user);
66
-
67
-		// make sure FS is setup before querying storage related stuff...
68
-		\OC_Util::setupFS($user->getUID());
69
-
70
-		$storageInfo = \OC_Helper::getStorageInfo('/');
71
-		if ($storageInfo['quota'] === FileInfo::SPACE_UNLIMITED) {
72
-			$totalSpace = $this->l->t('Unlimited');
73
-		} else {
74
-			$totalSpace = \OC_Helper::humanFileSize($storageInfo['total']);
75
-		}
76
-
77
-		$messageParameters = $this->getMessageParameters($account);
78
-
79
-		$parameters = [
80
-			'lookupServerUploadEnabled' => $lookupServerUploadEnabled,
81
-			'isFairUseOfFreePushService' => $this->isFairUseOfFreePushService(),
82
-			'profileEnabledGlobally' => $this->profileManager->isProfileEnabled(),
83
-		] + $messageParameters;
84
-
85
-		$personalInfoParameters = [
86
-			'userId' => $uid,
87
-			'avatar' => $this->getProperty($account, IAccountManager::PROPERTY_AVATAR),
88
-			'groups' => $this->getGroups($user),
89
-			'quota' => $storageInfo['quota'],
90
-			'totalSpace' => $totalSpace,
91
-			'usage' => \OC_Helper::humanFileSize($storageInfo['used']),
92
-			'usageRelative' => round($storageInfo['relative']),
93
-			'displayName' => $this->getProperty($account, IAccountManager::PROPERTY_DISPLAYNAME),
94
-			'emailMap' => $this->getEmailMap($account),
95
-			'phone' => $this->getProperty($account, IAccountManager::PROPERTY_PHONE),
96
-			'defaultPhoneRegion' => $this->config->getSystemValueString('default_phone_region'),
97
-			'location' => $this->getProperty($account, IAccountManager::PROPERTY_ADDRESS),
98
-			'website' => $this->getProperty($account, IAccountManager::PROPERTY_WEBSITE),
99
-			'twitter' => $this->getProperty($account, IAccountManager::PROPERTY_TWITTER),
100
-			'fediverse' => $this->getProperty($account, IAccountManager::PROPERTY_FEDIVERSE),
101
-			'languageMap' => $this->getLanguageMap($user),
102
-			'localeMap' => $this->getLocaleMap($user),
103
-			'profileEnabledGlobally' => $this->profileManager->isProfileEnabled(),
104
-			'profileEnabled' => $this->profileManager->isProfileEnabled($user),
105
-			'organisation' => $this->getProperty($account, IAccountManager::PROPERTY_ORGANISATION),
106
-			'role' => $this->getProperty($account, IAccountManager::PROPERTY_ROLE),
107
-			'headline' => $this->getProperty($account, IAccountManager::PROPERTY_HEADLINE),
108
-			'biography' => $this->getProperty($account, IAccountManager::PROPERTY_BIOGRAPHY),
109
-			'birthdate' => $this->getProperty($account, IAccountManager::PROPERTY_BIRTHDATE),
110
-			'firstDayOfWeek' => $this->config->getUserValue($uid, 'core', AUserDataOCSController::USER_FIELD_FIRST_DAY_OF_WEEK),
111
-			'pronouns' => $this->getProperty($account, IAccountManager::PROPERTY_PRONOUNS),
112
-		];
113
-
114
-		$accountParameters = [
115
-			'avatarChangeSupported' => $user->canChangeAvatar(),
116
-			'displayNameChangeSupported' => $user->canChangeDisplayName(),
117
-			'emailChangeSupported' => $user->canChangeEmail(),
118
-			'federationEnabled' => $federationEnabled,
119
-			'lookupServerUploadEnabled' => $lookupServerUploadEnabled,
120
-		];
121
-
122
-		$profileParameters = [
123
-			'profileConfig' => $this->profileManager->getProfileConfigWithMetadata($user, $user),
124
-		];
125
-
126
-		$this->initialStateService->provideInitialState('profileEnabledGlobally', $this->profileManager->isProfileEnabled());
127
-		$this->initialStateService->provideInitialState('personalInfoParameters', $personalInfoParameters);
128
-		$this->initialStateService->provideInitialState('accountParameters', $accountParameters);
129
-		$this->initialStateService->provideInitialState('profileParameters', $profileParameters);
130
-
131
-		return new TemplateResponse('settings', 'settings/personal/personal.info', $parameters, '');
132
-	}
133
-
134
-	/**
135
-	 * Check if is fair use of free push service
136
-	 * @return boolean
137
-	 */
138
-	private function isFairUseOfFreePushService(): bool {
139
-		return $this->manager->isFairUseOfFreePushService();
140
-	}
141
-
142
-	/**
143
-	 * returns the property data in an
144
-	 * associative array
145
-	 */
146
-	private function getProperty(IAccount $account, string $property): array {
147
-		$property = [
148
-			'name' => $account->getProperty($property)->getName(),
149
-			'value' => $account->getProperty($property)->getValue(),
150
-			'scope' => $account->getProperty($property)->getScope(),
151
-			'verified' => $account->getProperty($property)->getVerified(),
152
-		];
153
-
154
-		return $property;
155
-	}
156
-
157
-	/**
158
-	 * returns the section ID string, e.g. 'sharing'
159
-	 * @since 9.1
160
-	 */
161
-	public function getSection(): string {
162
-		return 'personal-info';
163
-	}
164
-
165
-	/**
166
-	 * @return int whether the form should be rather on the top or bottom of
167
-	 *             the admin section. The forms are arranged in ascending order of the
168
-	 *             priority values. It is required to return a value between 0 and 100.
169
-	 *
170
-	 * E.g.: 70
171
-	 * @since 9.1
172
-	 */
173
-	public function getPriority(): int {
174
-		return 10;
175
-	}
176
-
177
-	/**
178
-	 * returns a sorted list of the user's group GIDs
179
-	 */
180
-	private function getGroups(IUser $user): array {
181
-		$groups = array_map(
182
-			static function (IGroup $group) {
183
-				return $group->getDisplayName();
184
-			},
185
-			$this->groupManager->getUserGroups($user)
186
-		);
187
-		sort($groups);
188
-
189
-		return $groups;
190
-	}
191
-
192
-	/**
193
-	 * returns the primary email and additional emails in an
194
-	 * associative array
195
-	 */
196
-	private function getEmailMap(IAccount $account): array {
197
-		$systemEmail = [
198
-			'name' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getName(),
199
-			'value' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getValue(),
200
-			'scope' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope(),
201
-			'verified' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getVerified(),
202
-		];
203
-
204
-		$additionalEmails = array_map(
205
-			function (IAccountProperty $property) {
206
-				return [
207
-					'name' => $property->getName(),
208
-					'value' => $property->getValue(),
209
-					'scope' => $property->getScope(),
210
-					'verified' => $property->getVerified(),
211
-					'locallyVerified' => $property->getLocallyVerified(),
212
-				];
213
-			},
214
-			$account->getPropertyCollection(IAccountManager::COLLECTION_EMAIL)->getProperties(),
215
-		);
216
-
217
-		$emailMap = [
218
-			'primaryEmail' => $systemEmail,
219
-			'additionalEmails' => $additionalEmails,
220
-			'notificationEmail' => (string)$account->getUser()->getPrimaryEMailAddress(),
221
-		];
222
-
223
-		return $emailMap;
224
-	}
225
-
226
-	/**
227
-	 * returns the user's active language, common languages, and other languages in an
228
-	 * associative array
229
-	 */
230
-	private function getLanguageMap(IUser $user): array {
231
-		$forceLanguage = $this->config->getSystemValue('force_language', false);
232
-		if ($forceLanguage !== false) {
233
-			return [];
234
-		}
235
-
236
-		$uid = $user->getUID();
237
-
238
-		$userConfLang = $this->config->getUserValue($uid, 'core', 'lang', $this->l10nFactory->findLanguage());
239
-		$languages = $this->l10nFactory->getLanguages();
240
-
241
-		// associate the user language with the proper array
242
-		$userLangIndex = array_search($userConfLang, array_column($languages['commonLanguages'], 'code'));
243
-		$userLang = $languages['commonLanguages'][$userLangIndex];
244
-		// search in the other languages
245
-		if ($userLangIndex === false) {
246
-			$userLangIndex = array_search($userConfLang, array_column($languages['otherLanguages'], 'code'));
247
-			$userLang = $languages['otherLanguages'][$userLangIndex];
248
-		}
249
-		// if user language is not available but set somehow: show the actual code as name
250
-		if (!is_array($userLang)) {
251
-			$userLang = [
252
-				'code' => $userConfLang,
253
-				'name' => $userConfLang,
254
-			];
255
-		}
256
-
257
-		return array_merge(
258
-			['activeLanguage' => $userLang],
259
-			$languages
260
-		);
261
-	}
262
-
263
-	private function getLocaleMap(IUser $user): array {
264
-		$forceLanguage = $this->config->getSystemValue('force_locale', false);
265
-		if ($forceLanguage !== false) {
266
-			return [];
267
-		}
268
-
269
-		$uid = $user->getUID();
270
-		$userLang = $this->config->getUserValue($uid, 'core', 'lang', $this->l10nFactory->findLanguage());
271
-		$userLocaleString = $this->config->getUserValue($uid, 'core', 'locale', $this->l10nFactory->findLocale($userLang));
272
-		$localeCodes = $this->l10nFactory->findAvailableLocales();
273
-		$userLocale = array_filter($localeCodes, fn ($value) => $userLocaleString === $value['code']);
274
-
275
-		if (!empty($userLocale)) {
276
-			$userLocale = reset($userLocale);
277
-		}
278
-
279
-		$localesForLanguage = array_values(array_filter($localeCodes, fn ($localeCode) => str_starts_with($localeCode['code'], $userLang)));
280
-		$otherLocales = array_values(array_filter($localeCodes, fn ($localeCode) => !str_starts_with($localeCode['code'], $userLang)));
281
-
282
-		if (!$userLocale) {
283
-			$userLocale = [
284
-				'code' => 'en',
285
-				'name' => 'English'
286
-			];
287
-		}
288
-
289
-		return [
290
-			'activeLocaleLang' => $userLocaleString,
291
-			'activeLocale' => $userLocale,
292
-			'localesForLanguage' => $localesForLanguage,
293
-			'otherLocales' => $otherLocales,
294
-		];
295
-	}
296
-
297
-	/**
298
-	 * returns the message parameters
299
-	 */
300
-	private function getMessageParameters(IAccount $account): array {
301
-		$needVerifyMessage = [IAccountManager::PROPERTY_EMAIL, IAccountManager::PROPERTY_WEBSITE, IAccountManager::PROPERTY_TWITTER];
302
-		$messageParameters = [];
303
-		foreach ($needVerifyMessage as $property) {
304
-			switch ($account->getProperty($property)->getVerified()) {
305
-				case IAccountManager::VERIFIED:
306
-					$message = $this->l->t('Verifying');
307
-					break;
308
-				case IAccountManager::VERIFICATION_IN_PROGRESS:
309
-					$message = $this->l->t('Verifying …');
310
-					break;
311
-				default:
312
-					$message = $this->l->t('Verify');
313
-			}
314
-			$messageParameters[$property . 'Message'] = $message;
315
-		}
316
-		return $messageParameters;
317
-	}
35
+    /** @var ProfileManager */
36
+    private $profileManager;
37
+
38
+    public function __construct(
39
+        private IConfig $config,
40
+        private IUserManager $userManager,
41
+        private IGroupManager $groupManager,
42
+        private IAccountManager $accountManager,
43
+        ProfileManager $profileManager,
44
+        private IAppManager $appManager,
45
+        private IFactory $l10nFactory,
46
+        private IL10N $l,
47
+        private IInitialState $initialStateService,
48
+        private IManager $manager,
49
+    ) {
50
+        $this->profileManager = $profileManager;
51
+    }
52
+
53
+    public function getForm(): TemplateResponse {
54
+        $federationEnabled = $this->appManager->isEnabledForUser('federation');
55
+        $federatedFileSharingEnabled = $this->appManager->isEnabledForUser('federatedfilesharing');
56
+        $lookupServerUploadEnabled = false;
57
+        if ($federatedFileSharingEnabled) {
58
+            /** @var FederatedShareProvider $shareProvider */
59
+            $shareProvider = Server::get(FederatedShareProvider::class);
60
+            $lookupServerUploadEnabled = $shareProvider->isLookupServerUploadEnabled();
61
+        }
62
+
63
+        $uid = \OC_User::getUser();
64
+        $user = $this->userManager->get($uid);
65
+        $account = $this->accountManager->getAccount($user);
66
+
67
+        // make sure FS is setup before querying storage related stuff...
68
+        \OC_Util::setupFS($user->getUID());
69
+
70
+        $storageInfo = \OC_Helper::getStorageInfo('/');
71
+        if ($storageInfo['quota'] === FileInfo::SPACE_UNLIMITED) {
72
+            $totalSpace = $this->l->t('Unlimited');
73
+        } else {
74
+            $totalSpace = \OC_Helper::humanFileSize($storageInfo['total']);
75
+        }
76
+
77
+        $messageParameters = $this->getMessageParameters($account);
78
+
79
+        $parameters = [
80
+            'lookupServerUploadEnabled' => $lookupServerUploadEnabled,
81
+            'isFairUseOfFreePushService' => $this->isFairUseOfFreePushService(),
82
+            'profileEnabledGlobally' => $this->profileManager->isProfileEnabled(),
83
+        ] + $messageParameters;
84
+
85
+        $personalInfoParameters = [
86
+            'userId' => $uid,
87
+            'avatar' => $this->getProperty($account, IAccountManager::PROPERTY_AVATAR),
88
+            'groups' => $this->getGroups($user),
89
+            'quota' => $storageInfo['quota'],
90
+            'totalSpace' => $totalSpace,
91
+            'usage' => \OC_Helper::humanFileSize($storageInfo['used']),
92
+            'usageRelative' => round($storageInfo['relative']),
93
+            'displayName' => $this->getProperty($account, IAccountManager::PROPERTY_DISPLAYNAME),
94
+            'emailMap' => $this->getEmailMap($account),
95
+            'phone' => $this->getProperty($account, IAccountManager::PROPERTY_PHONE),
96
+            'defaultPhoneRegion' => $this->config->getSystemValueString('default_phone_region'),
97
+            'location' => $this->getProperty($account, IAccountManager::PROPERTY_ADDRESS),
98
+            'website' => $this->getProperty($account, IAccountManager::PROPERTY_WEBSITE),
99
+            'twitter' => $this->getProperty($account, IAccountManager::PROPERTY_TWITTER),
100
+            'fediverse' => $this->getProperty($account, IAccountManager::PROPERTY_FEDIVERSE),
101
+            'languageMap' => $this->getLanguageMap($user),
102
+            'localeMap' => $this->getLocaleMap($user),
103
+            'profileEnabledGlobally' => $this->profileManager->isProfileEnabled(),
104
+            'profileEnabled' => $this->profileManager->isProfileEnabled($user),
105
+            'organisation' => $this->getProperty($account, IAccountManager::PROPERTY_ORGANISATION),
106
+            'role' => $this->getProperty($account, IAccountManager::PROPERTY_ROLE),
107
+            'headline' => $this->getProperty($account, IAccountManager::PROPERTY_HEADLINE),
108
+            'biography' => $this->getProperty($account, IAccountManager::PROPERTY_BIOGRAPHY),
109
+            'birthdate' => $this->getProperty($account, IAccountManager::PROPERTY_BIRTHDATE),
110
+            'firstDayOfWeek' => $this->config->getUserValue($uid, 'core', AUserDataOCSController::USER_FIELD_FIRST_DAY_OF_WEEK),
111
+            'pronouns' => $this->getProperty($account, IAccountManager::PROPERTY_PRONOUNS),
112
+        ];
113
+
114
+        $accountParameters = [
115
+            'avatarChangeSupported' => $user->canChangeAvatar(),
116
+            'displayNameChangeSupported' => $user->canChangeDisplayName(),
117
+            'emailChangeSupported' => $user->canChangeEmail(),
118
+            'federationEnabled' => $federationEnabled,
119
+            'lookupServerUploadEnabled' => $lookupServerUploadEnabled,
120
+        ];
121
+
122
+        $profileParameters = [
123
+            'profileConfig' => $this->profileManager->getProfileConfigWithMetadata($user, $user),
124
+        ];
125
+
126
+        $this->initialStateService->provideInitialState('profileEnabledGlobally', $this->profileManager->isProfileEnabled());
127
+        $this->initialStateService->provideInitialState('personalInfoParameters', $personalInfoParameters);
128
+        $this->initialStateService->provideInitialState('accountParameters', $accountParameters);
129
+        $this->initialStateService->provideInitialState('profileParameters', $profileParameters);
130
+
131
+        return new TemplateResponse('settings', 'settings/personal/personal.info', $parameters, '');
132
+    }
133
+
134
+    /**
135
+     * Check if is fair use of free push service
136
+     * @return boolean
137
+     */
138
+    private function isFairUseOfFreePushService(): bool {
139
+        return $this->manager->isFairUseOfFreePushService();
140
+    }
141
+
142
+    /**
143
+     * returns the property data in an
144
+     * associative array
145
+     */
146
+    private function getProperty(IAccount $account, string $property): array {
147
+        $property = [
148
+            'name' => $account->getProperty($property)->getName(),
149
+            'value' => $account->getProperty($property)->getValue(),
150
+            'scope' => $account->getProperty($property)->getScope(),
151
+            'verified' => $account->getProperty($property)->getVerified(),
152
+        ];
153
+
154
+        return $property;
155
+    }
156
+
157
+    /**
158
+     * returns the section ID string, e.g. 'sharing'
159
+     * @since 9.1
160
+     */
161
+    public function getSection(): string {
162
+        return 'personal-info';
163
+    }
164
+
165
+    /**
166
+     * @return int whether the form should be rather on the top or bottom of
167
+     *             the admin section. The forms are arranged in ascending order of the
168
+     *             priority values. It is required to return a value between 0 and 100.
169
+     *
170
+     * E.g.: 70
171
+     * @since 9.1
172
+     */
173
+    public function getPriority(): int {
174
+        return 10;
175
+    }
176
+
177
+    /**
178
+     * returns a sorted list of the user's group GIDs
179
+     */
180
+    private function getGroups(IUser $user): array {
181
+        $groups = array_map(
182
+            static function (IGroup $group) {
183
+                return $group->getDisplayName();
184
+            },
185
+            $this->groupManager->getUserGroups($user)
186
+        );
187
+        sort($groups);
188
+
189
+        return $groups;
190
+    }
191
+
192
+    /**
193
+     * returns the primary email and additional emails in an
194
+     * associative array
195
+     */
196
+    private function getEmailMap(IAccount $account): array {
197
+        $systemEmail = [
198
+            'name' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getName(),
199
+            'value' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getValue(),
200
+            'scope' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope(),
201
+            'verified' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getVerified(),
202
+        ];
203
+
204
+        $additionalEmails = array_map(
205
+            function (IAccountProperty $property) {
206
+                return [
207
+                    'name' => $property->getName(),
208
+                    'value' => $property->getValue(),
209
+                    'scope' => $property->getScope(),
210
+                    'verified' => $property->getVerified(),
211
+                    'locallyVerified' => $property->getLocallyVerified(),
212
+                ];
213
+            },
214
+            $account->getPropertyCollection(IAccountManager::COLLECTION_EMAIL)->getProperties(),
215
+        );
216
+
217
+        $emailMap = [
218
+            'primaryEmail' => $systemEmail,
219
+            'additionalEmails' => $additionalEmails,
220
+            'notificationEmail' => (string)$account->getUser()->getPrimaryEMailAddress(),
221
+        ];
222
+
223
+        return $emailMap;
224
+    }
225
+
226
+    /**
227
+     * returns the user's active language, common languages, and other languages in an
228
+     * associative array
229
+     */
230
+    private function getLanguageMap(IUser $user): array {
231
+        $forceLanguage = $this->config->getSystemValue('force_language', false);
232
+        if ($forceLanguage !== false) {
233
+            return [];
234
+        }
235
+
236
+        $uid = $user->getUID();
237
+
238
+        $userConfLang = $this->config->getUserValue($uid, 'core', 'lang', $this->l10nFactory->findLanguage());
239
+        $languages = $this->l10nFactory->getLanguages();
240
+
241
+        // associate the user language with the proper array
242
+        $userLangIndex = array_search($userConfLang, array_column($languages['commonLanguages'], 'code'));
243
+        $userLang = $languages['commonLanguages'][$userLangIndex];
244
+        // search in the other languages
245
+        if ($userLangIndex === false) {
246
+            $userLangIndex = array_search($userConfLang, array_column($languages['otherLanguages'], 'code'));
247
+            $userLang = $languages['otherLanguages'][$userLangIndex];
248
+        }
249
+        // if user language is not available but set somehow: show the actual code as name
250
+        if (!is_array($userLang)) {
251
+            $userLang = [
252
+                'code' => $userConfLang,
253
+                'name' => $userConfLang,
254
+            ];
255
+        }
256
+
257
+        return array_merge(
258
+            ['activeLanguage' => $userLang],
259
+            $languages
260
+        );
261
+    }
262
+
263
+    private function getLocaleMap(IUser $user): array {
264
+        $forceLanguage = $this->config->getSystemValue('force_locale', false);
265
+        if ($forceLanguage !== false) {
266
+            return [];
267
+        }
268
+
269
+        $uid = $user->getUID();
270
+        $userLang = $this->config->getUserValue($uid, 'core', 'lang', $this->l10nFactory->findLanguage());
271
+        $userLocaleString = $this->config->getUserValue($uid, 'core', 'locale', $this->l10nFactory->findLocale($userLang));
272
+        $localeCodes = $this->l10nFactory->findAvailableLocales();
273
+        $userLocale = array_filter($localeCodes, fn ($value) => $userLocaleString === $value['code']);
274
+
275
+        if (!empty($userLocale)) {
276
+            $userLocale = reset($userLocale);
277
+        }
278
+
279
+        $localesForLanguage = array_values(array_filter($localeCodes, fn ($localeCode) => str_starts_with($localeCode['code'], $userLang)));
280
+        $otherLocales = array_values(array_filter($localeCodes, fn ($localeCode) => !str_starts_with($localeCode['code'], $userLang)));
281
+
282
+        if (!$userLocale) {
283
+            $userLocale = [
284
+                'code' => 'en',
285
+                'name' => 'English'
286
+            ];
287
+        }
288
+
289
+        return [
290
+            'activeLocaleLang' => $userLocaleString,
291
+            'activeLocale' => $userLocale,
292
+            'localesForLanguage' => $localesForLanguage,
293
+            'otherLocales' => $otherLocales,
294
+        ];
295
+    }
296
+
297
+    /**
298
+     * returns the message parameters
299
+     */
300
+    private function getMessageParameters(IAccount $account): array {
301
+        $needVerifyMessage = [IAccountManager::PROPERTY_EMAIL, IAccountManager::PROPERTY_WEBSITE, IAccountManager::PROPERTY_TWITTER];
302
+        $messageParameters = [];
303
+        foreach ($needVerifyMessage as $property) {
304
+            switch ($account->getProperty($property)->getVerified()) {
305
+                case IAccountManager::VERIFIED:
306
+                    $message = $this->l->t('Verifying');
307
+                    break;
308
+                case IAccountManager::VERIFICATION_IN_PROGRESS:
309
+                    $message = $this->l->t('Verifying …');
310
+                    break;
311
+                default:
312
+                    $message = $this->l->t('Verify');
313
+            }
314
+            $messageParameters[$property . 'Message'] = $message;
315
+        }
316
+        return $messageParameters;
317
+    }
318 318
 }
Please login to merge, or discard this patch.
apps/provisioning_api/tests/Controller/UsersControllerTest.php 1 patch
Indentation   +4386 added lines, -4386 removed lines patch added patch discarded remove patch
@@ -46,4391 +46,4391 @@
 block discarded – undo
46 46
 use Test\TestCase;
47 47
 
48 48
 class UsersControllerTest extends TestCase {
49
-	/** @var IUserManager|MockObject */
50
-	protected $userManager;
51
-	/** @var IConfig|MockObject */
52
-	protected $config;
53
-	/** @var Manager|MockObject */
54
-	protected $groupManager;
55
-	/** @var IUserSession|MockObject */
56
-	protected $userSession;
57
-	/** @var LoggerInterface|MockObject */
58
-	protected $logger;
59
-	/** @var UsersController|MockObject */
60
-	protected $api;
61
-	/** @var IAccountManager|MockObject */
62
-	protected $accountManager;
63
-	/** @var ISubAdmin|MockObject */
64
-	protected $subAdminManager;
65
-	/** @var IURLGenerator|MockObject */
66
-	protected $urlGenerator;
67
-	/** @var IRequest|MockObject */
68
-	protected $request;
69
-	/** @var IFactory|MockObject */
70
-	private $l10nFactory;
71
-	/** @var NewUserMailHelper|MockObject */
72
-	private $newUserMailHelper;
73
-	/** @var ISecureRandom|MockObject */
74
-	private $secureRandom;
75
-	/** @var RemoteWipe|MockObject */
76
-	private $remoteWipe;
77
-	/** @var KnownUserService|MockObject */
78
-	private $knownUserService;
79
-	/** @var IEventDispatcher|MockObject */
80
-	private $eventDispatcher;
81
-	private IRootFolder $rootFolder;
82
-	/** @var IPhoneNumberUtil */
83
-	private $phoneNumberUtil;
84
-
85
-	protected function setUp(): void {
86
-		parent::setUp();
87
-
88
-		$this->userManager = $this->createMock(IUserManager::class);
89
-		$this->config = $this->createMock(IConfig::class);
90
-		$this->groupManager = $this->createMock(Manager::class);
91
-		$this->userSession = $this->createMock(IUserSession::class);
92
-		$this->logger = $this->createMock(LoggerInterface::class);
93
-		$this->request = $this->createMock(IRequest::class);
94
-		$this->accountManager = $this->createMock(IAccountManager::class);
95
-		$this->subAdminManager = $this->createMock(ISubAdmin::class);
96
-		$this->urlGenerator = $this->createMock(IURLGenerator::class);
97
-		$this->l10nFactory = $this->createMock(IFactory::class);
98
-		$this->newUserMailHelper = $this->createMock(NewUserMailHelper::class);
99
-		$this->secureRandom = $this->createMock(ISecureRandom::class);
100
-		$this->remoteWipe = $this->createMock(RemoteWipe::class);
101
-		$this->knownUserService = $this->createMock(KnownUserService::class);
102
-		$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
103
-		$this->phoneNumberUtil = new PhoneNumberUtil();
104
-		$this->rootFolder = $this->createMock(IRootFolder::class);
105
-
106
-		$l10n = $this->createMock(IL10N::class);
107
-		$l10n->method('t')->willReturnCallback(fn (string $txt, array $replacement = []) => sprintf($txt, ...$replacement));
108
-		$this->l10nFactory->method('get')->with('provisioning_api')->willReturn($l10n);
109
-
110
-		$this->api = $this->getMockBuilder(UsersController::class)
111
-			->setConstructorArgs([
112
-				'provisioning_api',
113
-				$this->request,
114
-				$this->userManager,
115
-				$this->config,
116
-				$this->groupManager,
117
-				$this->userSession,
118
-				$this->accountManager,
119
-				$this->subAdminManager,
120
-				$this->l10nFactory,
121
-				$this->rootFolder,
122
-				$this->urlGenerator,
123
-				$this->logger,
124
-				$this->newUserMailHelper,
125
-				$this->secureRandom,
126
-				$this->remoteWipe,
127
-				$this->knownUserService,
128
-				$this->eventDispatcher,
129
-				$this->phoneNumberUtil,
130
-			])
131
-			->onlyMethods(['fillStorageInfo'])
132
-			->getMock();
133
-	}
134
-
135
-	public function testGetUsersAsAdmin(): void {
136
-		$loggedInUser = $this->getMockBuilder(IUser::class)
137
-			->disableOriginalConstructor()
138
-			->getMock();
139
-		$loggedInUser
140
-			->expects($this->once())
141
-			->method('getUID')
142
-			->willReturn('admin');
143
-		$this->userSession
144
-			->expects($this->once())
145
-			->method('getUser')
146
-			->willReturn($loggedInUser);
147
-		$this->groupManager
148
-			->expects($this->once())
149
-			->method('isAdmin')
150
-			->willReturn(true);
151
-		$this->userManager
152
-			->expects($this->once())
153
-			->method('search')
154
-			->with('MyCustomSearch')
155
-			->willReturn(['Admin' => [], 'Foo' => [], 'Bar' => []]);
156
-
157
-		$expected = [
158
-			'users' => [
159
-				'Admin',
160
-				'Foo',
161
-				'Bar',
162
-			],
163
-		];
164
-		$this->assertEquals($expected, $this->api->getUsers('MyCustomSearch')->getData());
165
-	}
166
-
167
-	public function testGetUsersAsSubAdmin(): void {
168
-		$loggedInUser = $this->getMockBuilder(IUser::class)
169
-			->disableOriginalConstructor()
170
-			->getMock();
171
-		$loggedInUser
172
-			->expects($this->once())
173
-			->method('getUID')
174
-			->willReturn('subadmin');
175
-		$this->userSession
176
-			->expects($this->once())
177
-			->method('getUser')
178
-			->willReturn($loggedInUser);
179
-		$this->groupManager
180
-			->expects($this->once())
181
-			->method('isAdmin')
182
-			->willReturn(false);
183
-		$firstGroup = $this->getMockBuilder('OCP\IGroup')
184
-			->disableOriginalConstructor()
185
-			->getMock();
186
-		$firstGroup
187
-			->expects($this->once())
188
-			->method('getGID')
189
-			->willReturn('FirstGroup');
190
-		$secondGroup = $this->getMockBuilder('OCP\IGroup')
191
-			->disableOriginalConstructor()
192
-			->getMock();
193
-		$secondGroup
194
-			->expects($this->once())
195
-			->method('getGID')
196
-			->willReturn('SecondGroup');
197
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
198
-			->disableOriginalConstructor()->getMock();
199
-		$subAdminManager
200
-			->expects($this->once())
201
-			->method('isSubAdmin')
202
-			->with($loggedInUser)
203
-			->willReturn(true);
204
-		$subAdminManager
205
-			->expects($this->once())
206
-			->method('getSubAdminsGroups')
207
-			->with($loggedInUser)
208
-			->willReturn([$firstGroup, $secondGroup]);
209
-		$this->groupManager
210
-			->expects($this->once())
211
-			->method('getSubAdmin')
212
-			->willReturn($subAdminManager);
213
-		$this->groupManager
214
-			->expects($this->any())
215
-			->method('displayNamesInGroup')
216
-			->will($this->onConsecutiveCalls(['AnotherUserInTheFirstGroup' => []], ['UserInTheSecondGroup' => []]));
217
-
218
-		$expected = [
219
-			'users' => [
220
-				'AnotherUserInTheFirstGroup',
221
-				'UserInTheSecondGroup',
222
-			],
223
-		];
224
-		$this->assertEquals($expected, $this->api->getUsers('MyCustomSearch')->getData());
225
-	}
226
-
227
-	private function createUserMock(string $uid, bool $enabled): MockObject&IUser {
228
-		$mockUser = $this->getMockBuilder(IUser::class)
229
-			->disableOriginalConstructor()
230
-			->getMock();
231
-		$mockUser
232
-			->method('getUID')
233
-			->willReturn($uid);
234
-		$mockUser
235
-			->method('isEnabled')
236
-			->willReturn($enabled);
237
-		return $mockUser;
238
-	}
239
-
240
-	public function testGetDisabledUsersAsAdmin(): void {
241
-		$loggedInUser = $this->getMockBuilder(IUser::class)
242
-			->disableOriginalConstructor()
243
-			->getMock();
244
-		$loggedInUser
245
-			->expects($this->once())
246
-			->method('getUID')
247
-			->willReturn('admin');
248
-		$this->userSession
249
-			->expects($this->atLeastOnce())
250
-			->method('getUser')
251
-			->willReturn($loggedInUser);
252
-		$this->groupManager
253
-			->expects($this->once())
254
-			->method('isAdmin')
255
-			->willReturn(true);
256
-		$this->userManager
257
-			->expects($this->once())
258
-			->method('getDisabledUsers')
259
-			->with(3, 0, 'MyCustomSearch')
260
-			->willReturn([
261
-				$this->createUserMock('admin', false),
262
-				$this->createUserMock('foo', false),
263
-				$this->createUserMock('bar', false),
264
-			]);
265
-
266
-		$expected = [
267
-			'users' => [
268
-				'admin' => ['id' => 'admin'],
269
-				'foo' => ['id' => 'foo'],
270
-				'bar' => ['id' => 'bar'],
271
-			],
272
-		];
273
-		$this->assertEquals($expected, $this->api->getDisabledUsersDetails('MyCustomSearch', 3)->getData());
274
-	}
275
-
276
-	public function testGetDisabledUsersAsSubAdmin(): void {
277
-		$loggedInUser = $this->getMockBuilder(IUser::class)
278
-			->disableOriginalConstructor()
279
-			->getMock();
280
-		$loggedInUser
281
-			->expects($this->once())
282
-			->method('getUID')
283
-			->willReturn('subadmin');
284
-		$this->userSession
285
-			->expects($this->atLeastOnce())
286
-			->method('getUser')
287
-			->willReturn($loggedInUser);
288
-		$this->groupManager
289
-			->expects($this->once())
290
-			->method('isAdmin')
291
-			->willReturn(false);
292
-		$firstGroup = $this->getMockBuilder('OCP\IGroup')
293
-			->disableOriginalConstructor()
294
-			->getMock();
295
-		$secondGroup = $this->getMockBuilder('OCP\IGroup')
296
-			->disableOriginalConstructor()
297
-			->getMock();
298
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
299
-			->disableOriginalConstructor()->getMock();
300
-		$subAdminManager
301
-			->expects($this->once())
302
-			->method('isSubAdmin')
303
-			->with($loggedInUser)
304
-			->willReturn(true);
305
-		$subAdminManager
306
-			->expects($this->once())
307
-			->method('getSubAdminsGroups')
308
-			->with($loggedInUser)
309
-			->willReturn([$firstGroup, $secondGroup]);
310
-		$this->groupManager
311
-			->expects($this->once())
312
-			->method('getSubAdmin')
313
-			->willReturn($subAdminManager);
314
-		$this->groupManager
315
-			->expects($this->never())
316
-			->method('displayNamesInGroup');
317
-
318
-		$firstGroup
319
-			->expects($this->once())
320
-			->method('searchUsers')
321
-			->with('MyCustomSearch')
322
-			->willReturn([
323
-				$this->createUserMock('user1', false),
324
-				$this->createUserMock('bob', true),
325
-				$this->createUserMock('user2', false),
326
-				$this->createUserMock('alice', true),
327
-			]);
328
-
329
-		$secondGroup
330
-			->expects($this->once())
331
-			->method('searchUsers')
332
-			->with('MyCustomSearch')
333
-			->willReturn([
334
-				$this->createUserMock('user2', false),
335
-				$this->createUserMock('joe', true),
336
-				$this->createUserMock('user3', false),
337
-				$this->createUserMock('jim', true),
338
-				$this->createUserMock('john', true),
339
-			]);
340
-
341
-
342
-		$expected = [
343
-			'users' => [
344
-				'user1' => ['id' => 'user1'],
345
-				'user2' => ['id' => 'user2'],
346
-				'user3' => ['id' => 'user3'],
347
-			],
348
-		];
349
-		$this->assertEquals($expected, $this->api->getDisabledUsersDetails('MyCustomSearch', 3)->getData());
350
-	}
351
-
352
-
353
-	public function testAddUserAlreadyExisting(): void {
354
-		$this->expectException(OCSException::class);
355
-		$this->expectExceptionCode(102);
356
-
357
-		$this->userManager
358
-			->expects($this->once())
359
-			->method('userExists')
360
-			->with('AlreadyExistingUser')
361
-			->willReturn(true);
362
-		$this->logger
363
-			->expects($this->once())
364
-			->method('error')
365
-			->with('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']);
366
-		$loggedInUser = $this->getMockBuilder(IUser::class)
367
-			->disableOriginalConstructor()
368
-			->getMock();
369
-		$loggedInUser
370
-			->expects($this->exactly(2))
371
-			->method('getUID')
372
-			->willReturn('adminUser');
373
-		$this->userSession
374
-			->expects($this->once())
375
-			->method('getUser')
376
-			->willReturn($loggedInUser);
377
-		$this->groupManager
378
-			->expects($this->once())
379
-			->method('isAdmin')
380
-			->with('adminUser')
381
-			->willReturn(true);
382
-
383
-		$this->api->addUser('AlreadyExistingUser', 'password', '', '', []);
384
-	}
385
-
386
-
387
-	public function testAddUserNonExistingGroup(): void {
388
-		$this->expectException(OCSException::class);
389
-		$this->expectExceptionMessage('Group NonExistingGroup does not exist');
390
-		$this->expectExceptionCode(104);
391
-
392
-		$this->userManager
393
-			->expects($this->once())
394
-			->method('userExists')
395
-			->with('NewUser')
396
-			->willReturn(false);
397
-		$loggedInUser = $this->getMockBuilder(IUser::class)
398
-			->disableOriginalConstructor()
399
-			->getMock();
400
-		$loggedInUser
401
-			->expects($this->exactly(2))
402
-			->method('getUID')
403
-			->willReturn('adminUser');
404
-		$this->userSession
405
-			->expects($this->once())
406
-			->method('getUser')
407
-			->willReturn($loggedInUser);
408
-		$this->groupManager
409
-			->expects($this->once())
410
-			->method('isAdmin')
411
-			->with('adminUser')
412
-			->willReturn(true);
413
-		$this->groupManager
414
-			->expects($this->once())
415
-			->method('groupExists')
416
-			->with('NonExistingGroup')
417
-			->willReturn(false);
418
-
419
-		$this->api->addUser('NewUser', 'pass', '', '', ['NonExistingGroup']);
420
-	}
421
-
422
-
423
-	public function testAddUserExistingGroupNonExistingGroup(): void {
424
-		$this->expectException(OCSException::class);
425
-		$this->expectExceptionMessage('Group NonExistingGroup does not exist');
426
-		$this->expectExceptionCode(104);
427
-
428
-		$this->userManager
429
-			->expects($this->once())
430
-			->method('userExists')
431
-			->with('NewUser')
432
-			->willReturn(false);
433
-		$loggedInUser = $this->getMockBuilder(IUser::class)
434
-			->disableOriginalConstructor()
435
-			->getMock();
436
-		$loggedInUser
437
-			->expects($this->exactly(2))
438
-			->method('getUID')
439
-			->willReturn('adminUser');
440
-		$this->userSession
441
-			->expects($this->once())
442
-			->method('getUser')
443
-			->willReturn($loggedInUser);
444
-		$this->groupManager
445
-			->expects($this->once())
446
-			->method('isAdmin')
447
-			->with('adminUser')
448
-			->willReturn(true);
449
-		$this->groupManager
450
-			->expects($this->exactly(2))
451
-			->method('groupExists')
452
-			->withConsecutive(
453
-				['ExistingGroup'],
454
-				['NonExistingGroup']
455
-			)
456
-			->willReturnMap([
457
-				['ExistingGroup', true],
458
-				['NonExistingGroup', false]
459
-			]);
460
-
461
-		$this->api->addUser('NewUser', 'pass', '', '', ['ExistingGroup', 'NonExistingGroup']);
462
-	}
463
-
464
-	public function testAddUserSuccessful(): void {
465
-		$this->userManager
466
-			->expects($this->once())
467
-			->method('userExists')
468
-			->with('NewUser')
469
-			->willReturn(false);
470
-		$this->userManager
471
-			->expects($this->once())
472
-			->method('createUser')
473
-			->with('NewUser', 'PasswordOfTheNewUser');
474
-		$this->logger
475
-			->expects($this->once())
476
-			->method('info')
477
-			->with('Successful addUser call with userid: NewUser', ['app' => 'ocs_api']);
478
-		$loggedInUser = $this->getMockBuilder(IUser::class)
479
-			->disableOriginalConstructor()
480
-			->getMock();
481
-		$loggedInUser
482
-			->expects($this->exactly(2))
483
-			->method('getUID')
484
-			->willReturn('adminUser');
485
-		$this->userSession
486
-			->expects($this->once())
487
-			->method('getUser')
488
-			->willReturn($loggedInUser);
489
-		$this->groupManager
490
-			->expects($this->once())
491
-			->method('isAdmin')
492
-			->with('adminUser')
493
-			->willReturn(true);
494
-
495
-		$this->assertTrue(key_exists(
496
-			'id',
497
-			$this->api->addUser('NewUser', 'PasswordOfTheNewUser')->getData()
498
-		));
499
-	}
500
-
501
-	public function testAddUserSuccessfulWithDisplayName(): void {
502
-		/**
503
-		 * @var UserController
504
-		 */
505
-		$api = $this->getMockBuilder(UsersController::class)
506
-			->setConstructorArgs([
507
-				'provisioning_api',
508
-				$this->request,
509
-				$this->userManager,
510
-				$this->config,
511
-				$this->groupManager,
512
-				$this->userSession,
513
-				$this->accountManager,
514
-				$this->subAdminManager,
515
-				$this->l10nFactory,
516
-				$this->rootFolder,
517
-				$this->urlGenerator,
518
-				$this->logger,
519
-				$this->newUserMailHelper,
520
-				$this->secureRandom,
521
-				$this->remoteWipe,
522
-				$this->knownUserService,
523
-				$this->eventDispatcher,
524
-				$this->phoneNumberUtil,
525
-			])
526
-			->onlyMethods(['editUser'])
527
-			->getMock();
528
-
529
-		$this->userManager
530
-			->expects($this->once())
531
-			->method('userExists')
532
-			->with('NewUser')
533
-			->willReturn(false);
534
-		$this->userManager
535
-			->expects($this->once())
536
-			->method('createUser')
537
-			->with('NewUser', 'PasswordOfTheNewUser');
538
-		$this->logger
539
-			->expects($this->once())
540
-			->method('info')
541
-			->with('Successful addUser call with userid: NewUser', ['app' => 'ocs_api']);
542
-		$loggedInUser = $this->getMockBuilder(IUser::class)
543
-			->disableOriginalConstructor()
544
-			->getMock();
545
-		$loggedInUser
546
-			->expects($this->any())
547
-			->method('getUID')
548
-			->willReturn('adminUser');
549
-		$this->userSession
550
-			->expects($this->any())
551
-			->method('getUser')
552
-			->willReturn($loggedInUser);
553
-		$this->groupManager
554
-			->expects($this->once())
555
-			->method('isAdmin')
556
-			->with('adminUser')
557
-			->willReturn(true);
558
-		$api
559
-			->expects($this->once())
560
-			->method('editUser')
561
-			->with('NewUser', 'display', 'DisplayNameOfTheNewUser');
562
-
563
-		$this->assertTrue(key_exists(
564
-			'id',
565
-			$api->addUser('NewUser', 'PasswordOfTheNewUser', 'DisplayNameOfTheNewUser')->getData()
566
-		));
567
-	}
568
-
569
-	public function testAddUserSuccessfulGenerateUserID(): void {
570
-		$this->config
571
-			->expects($this->any())
572
-			->method('getAppValue')
573
-			->willReturnCallback(function ($appid, $key, $default) {
574
-				if ($key === 'newUser.generateUserID') {
575
-					return 'yes';
576
-				}
577
-				return null;
578
-			});
579
-		$this->userManager
580
-			->expects($this->any())
581
-			->method('userExists')
582
-			->with($this->anything())
583
-			->willReturn(false);
584
-		$this->userManager
585
-			->expects($this->once())
586
-			->method('createUser')
587
-			->with($this->anything(), 'PasswordOfTheNewUser');
588
-		$this->logger
589
-			->expects($this->once())
590
-			->method('info')
591
-			->with($this->stringStartsWith('Successful addUser call with userid: '), ['app' => 'ocs_api']);
592
-		$loggedInUser = $this->getMockBuilder(IUser::class)
593
-			->disableOriginalConstructor()
594
-			->getMock();
595
-		$loggedInUser
596
-			->expects($this->exactly(2))
597
-			->method('getUID')
598
-			->willReturn('adminUser');
599
-		$this->userSession
600
-			->expects($this->once())
601
-			->method('getUser')
602
-			->willReturn($loggedInUser);
603
-		$this->groupManager
604
-			->expects($this->once())
605
-			->method('isAdmin')
606
-			->with('adminUser')
607
-			->willReturn(true);
608
-		$this->secureRandom->expects($this->any())
609
-			->method('generate')
610
-			->with(10)
611
-			->willReturnCallback(function () {
612
-				return (string)rand(100000000, 999999999);
613
-			});
614
-
615
-		$this->assertTrue(key_exists(
616
-			'id',
617
-			$this->api->addUser('', 'PasswordOfTheNewUser')->getData()
618
-		));
619
-	}
620
-
621
-	public function testAddUserSuccessfulGeneratePassword(): void {
622
-		$this->userManager
623
-			->expects($this->once())
624
-			->method('userExists')
625
-			->with('NewUser')
626
-			->willReturn(false);
627
-		$newUser = $this->createMock(IUser::class);
628
-		$newUser->expects($this->once())
629
-			->method('setEMailAddress');
630
-		$this->userManager
631
-			->expects($this->once())
632
-			->method('createUser')
633
-			->willReturn($newUser);
634
-		$this->logger
635
-			->expects($this->once())
636
-			->method('info')
637
-			->with('Successful addUser call with userid: NewUser', ['app' => 'ocs_api']);
638
-		$loggedInUser = $this->getMockBuilder(IUser::class)
639
-			->disableOriginalConstructor()
640
-			->getMock();
641
-		$loggedInUser
642
-			->expects($this->exactly(2))
643
-			->method('getUID')
644
-			->willReturn('adminUser');
645
-		$this->userSession
646
-			->expects($this->once())
647
-			->method('getUser')
648
-			->willReturn($loggedInUser);
649
-		$this->groupManager
650
-			->expects($this->once())
651
-			->method('isAdmin')
652
-			->with('adminUser')
653
-			->willReturn(true);
654
-		$this->eventDispatcher
655
-			->expects($this->once())
656
-			->method('dispatchTyped')
657
-			->with(new GenerateSecurePasswordEvent());
658
-
659
-		$this->assertTrue(key_exists(
660
-			'id',
661
-			$this->api->addUser('NewUser', '', '', 'foo@bar')->getData()
662
-		));
663
-	}
664
-
665
-
666
-	public function testAddUserFailedToGenerateUserID(): void {
667
-		$this->expectException(OCSException::class);
668
-		$this->expectExceptionMessage('Could not create non-existing user ID');
669
-		$this->expectExceptionCode(111);
670
-
671
-		$this->config
672
-			->expects($this->any())
673
-			->method('getAppValue')
674
-			->willReturnCallback(function ($appid, $key, $default) {
675
-				if ($key === 'newUser.generateUserID') {
676
-					return 'yes';
677
-				}
678
-				return null;
679
-			});
680
-		$this->userManager
681
-			->expects($this->any())
682
-			->method('userExists')
683
-			->with($this->anything())
684
-			->willReturn(true);
685
-		$this->userManager
686
-			->expects($this->never())
687
-			->method('createUser');
688
-		$loggedInUser = $this->getMockBuilder(IUser::class)
689
-			->disableOriginalConstructor()
690
-			->getMock();
691
-		$loggedInUser
692
-			->expects($this->exactly(2))
693
-			->method('getUID')
694
-			->willReturn('adminUser');
695
-		$this->userSession
696
-			->expects($this->once())
697
-			->method('getUser')
698
-			->willReturn($loggedInUser);
699
-		$this->groupManager
700
-			->expects($this->once())
701
-			->method('isAdmin')
702
-			->with('adminUser')
703
-			->willReturn(true);
704
-
705
-		$this->api->addUser('', 'PasswordOfTheNewUser')->getData();
706
-	}
707
-
708
-
709
-	public function testAddUserEmailRequired(): void {
710
-		$this->expectException(OCSException::class);
711
-		$this->expectExceptionMessage('Required email address was not provided');
712
-		$this->expectExceptionCode(110);
713
-
714
-		$this->config
715
-			->expects($this->any())
716
-			->method('getAppValue')
717
-			->willReturnCallback(function ($appid, $key, $default) {
718
-				if ($key === 'newUser.requireEmail') {
719
-					return 'yes';
720
-				}
721
-				return null;
722
-			});
723
-		$this->userManager
724
-			->expects($this->once())
725
-			->method('userExists')
726
-			->with('NewUser')
727
-			->willReturn(false);
728
-		$this->userManager
729
-			->expects($this->never())
730
-			->method('createUser');
731
-		$loggedInUser = $this->getMockBuilder(IUser::class)
732
-			->disableOriginalConstructor()
733
-			->getMock();
734
-		$loggedInUser
735
-			->expects($this->exactly(2))
736
-			->method('getUID')
737
-			->willReturn('adminUser');
738
-		$this->userSession
739
-			->expects($this->once())
740
-			->method('getUser')
741
-			->willReturn($loggedInUser);
742
-		$this->groupManager
743
-			->expects($this->once())
744
-			->method('isAdmin')
745
-			->with('adminUser')
746
-			->willReturn(true);
747
-
748
-		$this->assertTrue(key_exists(
749
-			'id',
750
-			$this->api->addUser('NewUser', 'PasswordOfTheNewUser')->getData()
751
-		));
752
-	}
753
-
754
-	public function testAddUserExistingGroup(): void {
755
-		$this->userManager
756
-			->expects($this->once())
757
-			->method('userExists')
758
-			->with('NewUser')
759
-			->willReturn(false);
760
-		$loggedInUser = $this->getMockBuilder(IUser::class)
761
-			->disableOriginalConstructor()
762
-			->getMock();
763
-		$loggedInUser
764
-			->expects($this->exactly(2))
765
-			->method('getUID')
766
-			->willReturn('adminUser');
767
-		$this->userSession
768
-			->expects($this->once())
769
-			->method('getUser')
770
-			->willReturn($loggedInUser);
771
-		$this->groupManager
772
-			->expects($this->once())
773
-			->method('isAdmin')
774
-			->with('adminUser')
775
-			->willReturn(true);
776
-		$this->groupManager
777
-			->expects($this->once())
778
-			->method('groupExists')
779
-			->with('ExistingGroup')
780
-			->willReturn(true);
781
-		$user = $this->getMockBuilder(IUser::class)
782
-			->disableOriginalConstructor()
783
-			->getMock();
784
-		$this->userManager
785
-			->expects($this->once())
786
-			->method('createUser')
787
-			->with('NewUser', 'PasswordOfTheNewUser')
788
-			->willReturn($user);
789
-		$group = $this->getMockBuilder('OCP\IGroup')
790
-			->disableOriginalConstructor()
791
-			->getMock();
792
-		$group
793
-			->expects($this->once())
794
-			->method('addUser')
795
-			->with($user);
796
-		$this->groupManager
797
-			->expects($this->once())
798
-			->method('get')
799
-			->with('ExistingGroup')
800
-			->willReturn($group);
801
-		$this->logger
802
-			->expects($this->exactly(2))
803
-			->method('info')
804
-			->withConsecutive(
805
-				['Successful addUser call with userid: NewUser', ['app' => 'ocs_api']],
806
-				['Added userid NewUser to group ExistingGroup', ['app' => 'ocs_api']]
807
-			);
808
-
809
-		$this->assertTrue(key_exists(
810
-			'id',
811
-			$this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup'])->getData()
812
-		));
813
-	}
814
-
815
-
816
-	public function testAddUserUnsuccessful(): void {
817
-		$this->expectException(OCSException::class);
818
-		$this->expectExceptionMessage('Bad request');
819
-		$this->expectExceptionCode(101);
820
-
821
-		$exception = new Exception('User backend not found.');
822
-		$this->userManager
823
-			->expects($this->once())
824
-			->method('userExists')
825
-			->with('NewUser')
826
-			->willReturn(false);
827
-		$this->userManager
828
-			->expects($this->once())
829
-			->method('createUser')
830
-			->with('NewUser', 'PasswordOfTheNewUser')
831
-			->will($this->throwException($exception));
832
-		$this->logger
833
-			->expects($this->once())
834
-			->method('error')
835
-			->with(
836
-				'Failed addUser attempt with exception.',
837
-				[
838
-					'app' => 'ocs_api',
839
-					'exception' => $exception
840
-				]
841
-			);
842
-		$loggedInUser = $this->getMockBuilder(IUser::class)
843
-			->disableOriginalConstructor()
844
-			->getMock();
845
-		$loggedInUser
846
-			->expects($this->exactly(2))
847
-			->method('getUID')
848
-			->willReturn('adminUser');
849
-		$this->userSession
850
-			->expects($this->once())
851
-			->method('getUser')
852
-			->willReturn($loggedInUser);
853
-		$this->groupManager
854
-			->expects($this->once())
855
-			->method('isAdmin')
856
-			->with('adminUser')
857
-			->willReturn(true);
858
-
859
-		$this->api->addUser('NewUser', 'PasswordOfTheNewUser');
860
-	}
861
-
862
-
863
-	public function testAddUserAsSubAdminNoGroup(): void {
864
-		$this->expectException(OCSException::class);
865
-		$this->expectExceptionMessage('No group specified (required for sub-admins)');
866
-		$this->expectExceptionCode(106);
867
-
868
-		$loggedInUser = $this->getMockBuilder(IUser::class)
869
-			->disableOriginalConstructor()
870
-			->getMock();
871
-		$loggedInUser
872
-			->expects($this->exactly(2))
873
-			->method('getUID')
874
-			->willReturn('regularUser');
875
-		$this->userSession
876
-			->expects($this->once())
877
-			->method('getUser')
878
-			->willReturn($loggedInUser);
879
-		$this->groupManager
880
-			->expects($this->once())
881
-			->method('isAdmin')
882
-			->with('regularUser')
883
-			->willReturn(false);
884
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
885
-			->disableOriginalConstructor()->getMock();
886
-		$this->groupManager
887
-			->expects($this->once())
888
-			->method('getSubAdmin')
889
-			->with()
890
-			->willReturn($subAdminManager);
891
-
892
-		$this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', []);
893
-	}
894
-
895
-
896
-	public function testAddUserAsSubAdminValidGroupNotSubAdmin(): void {
897
-		$this->expectException(OCSException::class);
898
-		$this->expectExceptionMessage('Insufficient privileges for group ExistingGroup');
899
-		$this->expectExceptionCode(105);
900
-
901
-		$loggedInUser = $this->getMockBuilder(IUser::class)
902
-			->disableOriginalConstructor()
903
-			->getMock();
904
-		$loggedInUser
905
-			->expects($this->exactly(2))
906
-			->method('getUID')
907
-			->willReturn('regularUser');
908
-		$this->userSession
909
-			->expects($this->once())
910
-			->method('getUser')
911
-			->willReturn($loggedInUser);
912
-		$this->groupManager
913
-			->expects($this->once())
914
-			->method('isAdmin')
915
-			->with('regularUser')
916
-			->willReturn(false);
917
-		$existingGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
918
-		$this->groupManager
919
-			->expects($this->once())
920
-			->method('get')
921
-			->with('ExistingGroup')
922
-			->willReturn($existingGroup);
923
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
924
-			->disableOriginalConstructor()->getMock();
925
-		$subAdminManager
926
-			->expects($this->once())
927
-			->method('isSubAdminOfGroup')
928
-			->with($loggedInUser, $existingGroup)
929
-			->willReturn(false);
930
-		$this->groupManager
931
-			->expects($this->once())
932
-			->method('getSubAdmin')
933
-			->with()
934
-			->willReturn($subAdminManager);
935
-		$this->groupManager
936
-			->expects($this->once())
937
-			->method('groupExists')
938
-			->with('ExistingGroup')
939
-			->willReturn(true);
940
-
941
-		$this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup'])->getData();
942
-	}
943
-
944
-	public function testAddUserAsSubAdminExistingGroups(): void {
945
-		$this->userManager
946
-			->expects($this->once())
947
-			->method('userExists')
948
-			->with('NewUser')
949
-			->willReturn(false);
950
-		$loggedInUser = $this->getMockBuilder(IUser::class)
951
-			->disableOriginalConstructor()
952
-			->getMock();
953
-		$loggedInUser
954
-			->expects($this->exactly(2))
955
-			->method('getUID')
956
-			->willReturn('subAdminUser');
957
-		$this->userSession
958
-			->expects($this->once())
959
-			->method('getUser')
960
-			->willReturn($loggedInUser);
961
-		$this->groupManager
962
-			->expects($this->once())
963
-			->method('isAdmin')
964
-			->with('subAdminUser')
965
-			->willReturn(false);
966
-		$this->groupManager
967
-			->expects($this->exactly(2))
968
-			->method('groupExists')
969
-			->withConsecutive(
970
-				['ExistingGroup1'],
971
-				['ExistingGroup2']
972
-			)
973
-			->willReturn(true);
974
-		$user = $this->getMockBuilder(IUser::class)
975
-			->disableOriginalConstructor()
976
-			->getMock();
977
-		$this->userManager
978
-			->expects($this->once())
979
-			->method('createUser')
980
-			->with('NewUser', 'PasswordOfTheNewUser')
981
-			->willReturn($user);
982
-		$existingGroup1 = $this->getMockBuilder('OCP\IGroup')
983
-			->disableOriginalConstructor()
984
-			->getMock();
985
-		$existingGroup2 = $this->getMockBuilder('OCP\IGroup')
986
-			->disableOriginalConstructor()
987
-			->getMock();
988
-		$existingGroup1
989
-			->expects($this->once())
990
-			->method('addUser')
991
-			->with($user);
992
-		$existingGroup2
993
-			->expects($this->once())
994
-			->method('addUser')
995
-			->with($user);
996
-		$this->groupManager
997
-			->expects($this->exactly(4))
998
-			->method('get')
999
-			->withConsecutive(
1000
-				['ExistingGroup1'],
1001
-				['ExistingGroup2'],
1002
-				['ExistingGroup1'],
1003
-				['ExistingGroup2']
1004
-			)
1005
-			->willReturnMap([
1006
-				['ExistingGroup1', $existingGroup1],
1007
-				['ExistingGroup2', $existingGroup2]
1008
-			]);
1009
-		$this->logger
1010
-			->expects($this->exactly(3))
1011
-			->method('info')
1012
-			->withConsecutive(
1013
-				['Successful addUser call with userid: NewUser', ['app' => 'ocs_api']],
1014
-				['Added userid NewUser to group ExistingGroup1', ['app' => 'ocs_api']],
1015
-				['Added userid NewUser to group ExistingGroup2', ['app' => 'ocs_api']]
1016
-			);
1017
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
1018
-			->disableOriginalConstructor()->getMock();
1019
-		$this->groupManager
1020
-			->expects($this->once())
1021
-			->method('getSubAdmin')
1022
-			->willReturn($subAdminManager);
1023
-		$subAdminManager
1024
-			->expects($this->exactly(2))
1025
-			->method('isSubAdminOfGroup')
1026
-			->withConsecutive(
1027
-				[$loggedInUser, $existingGroup1],
1028
-				[$loggedInUser, $existingGroup2]
1029
-			)
1030
-			->willReturn(true);
1031
-
1032
-		$this->assertTrue(key_exists(
1033
-			'id',
1034
-			$this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup1', 'ExistingGroup2'])->getData()
1035
-		));
1036
-	}
1037
-
1038
-
1039
-	public function testGetUserTargetDoesNotExist(): void {
1040
-		$this->expectException(OCSException::class);
1041
-		$this->expectExceptionMessage('User does not exist');
1042
-		$this->expectExceptionCode(404);
1043
-
1044
-		$loggedInUser = $this->getMockBuilder(IUser::class)
1045
-			->disableOriginalConstructor()
1046
-			->getMock();
1047
-		$this->userSession
1048
-			->method('getUser')
1049
-			->willReturn($loggedInUser);
1050
-		$this->userManager
1051
-			->expects($this->once())
1052
-			->method('get')
1053
-			->with('UserToGet')
1054
-			->willReturn(null);
1055
-
1056
-		$this->api->getUser('UserToGet');
1057
-	}
1058
-
1059
-	public function testGetUserDataAsAdmin(): void {
1060
-		$group0 = $this->createMock(IGroup::class);
1061
-		$group1 = $this->createMock(IGroup::class);
1062
-		$group2 = $this->createMock(IGroup::class);
1063
-		$group3 = $this->createMock(IGroup::class);
1064
-		$loggedInUser = $this->getMockBuilder(IUser::class)
1065
-			->disableOriginalConstructor()
1066
-			->getMock();
1067
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
1068
-			->disableOriginalConstructor()
1069
-			->getMock();
1070
-		$loggedInUser
1071
-			->method('getUID')
1072
-			->willReturn('admin');
1073
-		$targetUser = $this->getMockBuilder(IUser::class)
1074
-			->disableOriginalConstructor()
1075
-			->getMock();
1076
-		$targetUser->expects($this->once())
1077
-			->method('getSystemEMailAddress')
1078
-			->willReturn('[email protected]');
1079
-		$this->userSession
1080
-			->method('getUser')
1081
-			->willReturn($loggedInUser);
1082
-		$this->userManager
1083
-			->method('get')
1084
-			->with('UID')
1085
-			->willReturn($targetUser);
1086
-		$this->groupManager
1087
-			->method('isAdmin')
1088
-			->with('admin')
1089
-			->willReturn(true);
1090
-		$this->groupManager
1091
-			->expects($this->any())
1092
-			->method('getUserGroups')
1093
-			->willReturn([$group0, $group1, $group2]);
1094
-		$this->groupManager
1095
-			->expects($this->once())
1096
-			->method('getSubAdmin')
1097
-			->willReturn($subAdminManager);
1098
-		$subAdminManager
1099
-			->expects($this->once())
1100
-			->method('getSubAdminsGroups')
1101
-			->willReturn([$group3]);
1102
-		$group0->expects($this->once())
1103
-			->method('getGID')
1104
-			->willReturn('group0');
1105
-		$group1->expects($this->once())
1106
-			->method('getGID')
1107
-			->willReturn('group1');
1108
-		$group2->expects($this->once())
1109
-			->method('getGID')
1110
-			->willReturn('group2');
1111
-		$group3->expects($this->once())
1112
-			->method('getGID')
1113
-			->willReturn('group3');
1114
-
1115
-		$this->mockAccount($targetUser, [
1116
-			IAccountManager::PROPERTY_ADDRESS => ['value' => 'address'],
1117
-			IAccountManager::PROPERTY_PHONE => ['value' => 'phone'],
1118
-			IAccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
1119
-			IAccountManager::PROPERTY_FEDIVERSE => ['value' => 'fediverse'],
1120
-			IAccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
1121
-			IAccountManager::PROPERTY_ORGANISATION => ['value' => 'organisation'],
1122
-			IAccountManager::PROPERTY_ROLE => ['value' => 'role'],
1123
-			IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
1124
-			IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
1125
-			IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
1126
-			IAccountManager::PROPERTY_PRONOUNS => ['value' => 'they/them'],
1127
-		]);
1128
-		$this->config
1129
-			->method('getUserValue')
1130
-			->willReturnMap([
1131
-				['UID', 'core', 'enabled', 'true', 'true'],
1132
-			]);
1133
-		$this->api
1134
-			->expects($this->once())
1135
-			->method('fillStorageInfo')
1136
-			->with($targetUser)
1137
-			->willReturn(['DummyValue']);
1138
-
1139
-		$backend = $this->createMock(UserInterface::class);
1140
-		$backend->expects($this->any())
1141
-			->method('implementsActions')
1142
-			->willReturn(true);
1143
-
1144
-		$targetUser
1145
-			->expects($this->once())
1146
-			->method('getDisplayName')
1147
-			->willReturn('Demo User');
1148
-		$targetUser
1149
-			->expects($this->once())
1150
-			->method('getHome')
1151
-			->willReturn('/var/www/newtcloud/data/UID');
1152
-		$targetUser
1153
-			->expects($this->exactly(2))
1154
-			->method('getLastLogin')
1155
-			->willReturn(1521191471);
1156
-		$targetUser
1157
-			->expects($this->once())
1158
-			->method('getFirstLogin')
1159
-			->willReturn(1511191471);
1160
-		$targetUser
1161
-			->expects($this->once())
1162
-			->method('getBackendClassName')
1163
-			->willReturn('Database');
1164
-		$targetUser
1165
-			->expects($this->once())
1166
-			->method('getBackend')
1167
-			->willReturn($backend);
1168
-		$targetUser
1169
-			->method('getUID')
1170
-			->willReturn('UID');
1171
-
1172
-		$this->l10nFactory
1173
-			->expects($this->once())
1174
-			->method('getUserLanguage')
1175
-			->with($targetUser)
1176
-			->willReturn('de');
1177
-
1178
-		$expected = [
1179
-			'id' => 'UID',
1180
-			'enabled' => true,
1181
-			'storageLocation' => '/var/www/newtcloud/data/UID',
1182
-			'firstLoginTimestamp' => 1511191471,
1183
-			'lastLoginTimestamp' => 1521191471,
1184
-			'lastLogin' => 1521191471000,
1185
-			'backend' => 'Database',
1186
-			'subadmin' => ['group3'],
1187
-			'quota' => ['DummyValue'],
1188
-			'email' => '[email protected]',
1189
-			'displayname' => 'Demo User',
1190
-			'display-name' => 'Demo User',
1191
-			'phone' => 'phone',
1192
-			'address' => 'address',
1193
-			'website' => 'website',
1194
-			'twitter' => 'twitter',
1195
-			'fediverse' => 'fediverse',
1196
-			'groups' => ['group0', 'group1', 'group2'],
1197
-			'language' => 'de',
1198
-			'locale' => null,
1199
-			'backendCapabilities' => [
1200
-				'setDisplayName' => true,
1201
-				'setPassword' => true,
1202
-			],
1203
-			'additional_mail' => [],
1204
-			'organisation' => 'organisation',
1205
-			'role' => 'role',
1206
-			'headline' => 'headline',
1207
-			'biography' => 'biography',
1208
-			'profile_enabled' => '1',
1209
-			'notify_email' => null,
1210
-			'manager' => '',
1211
-			'pronouns' => 'they/them',
1212
-		];
1213
-		$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
1214
-	}
1215
-
1216
-	public function testGetUserDataAsSubAdminAndUserIsAccessible(): void {
1217
-		$loggedInUser = $this->getMockBuilder(IUser::class)
1218
-			->disableOriginalConstructor()
1219
-			->getMock();
1220
-		$loggedInUser
1221
-			->method('getUID')
1222
-			->willReturn('subadmin');
1223
-		$targetUser = $this->getMockBuilder(IUser::class)
1224
-			->disableOriginalConstructor()
1225
-			->getMock();
1226
-		$targetUser
1227
-			->expects($this->once())
1228
-			->method('getSystemEMailAddress')
1229
-			->willReturn('[email protected]');
1230
-		$this->userSession
1231
-			->method('getUser')
1232
-			->willReturn($loggedInUser);
1233
-		$this->userManager
1234
-			->method('get')
1235
-			->with('UID')
1236
-			->willReturn($targetUser);
1237
-		$this->groupManager
1238
-			->method('isAdmin')
1239
-			->with('subadmin')
1240
-			->willReturn(false);
1241
-		$this->groupManager
1242
-			->expects($this->any())
1243
-			->method('getUserGroups')
1244
-			->willReturn([]);
1245
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
1246
-			->disableOriginalConstructor()
1247
-			->getMock();
1248
-		$subAdminManager
1249
-			->expects($this->once())
1250
-			->method('isUserAccessible')
1251
-			->with($loggedInUser, $targetUser)
1252
-			->willReturn(true);
1253
-		$subAdminManager
1254
-			->expects($this->once())
1255
-			->method('getSubAdminsGroups')
1256
-			->willReturn([]);
1257
-		$this->groupManager
1258
-			->expects($this->exactly(2))
1259
-			->method('getSubAdmin')
1260
-			->willReturn($subAdminManager);
1261
-		$this->config
1262
-			->method('getUserValue')
1263
-			->willReturnMap([
1264
-				['UID', 'core', 'enabled', 'true', 'true'],
1265
-			]);
1266
-		$this->api
1267
-			->expects($this->once())
1268
-			->method('fillStorageInfo')
1269
-			->with($targetUser)
1270
-			->willReturn(['DummyValue']);
1271
-
1272
-		$backend = $this->createMock(UserInterface::class);
1273
-		$backend->expects($this->any())
1274
-			->method('implementsActions')
1275
-			->willReturn(true);
1276
-
1277
-		$targetUser
1278
-			->expects($this->once())
1279
-			->method('getDisplayName')
1280
-			->willReturn('Demo User');
1281
-		$targetUser
1282
-			->expects($this->never())
1283
-			->method('getHome');
1284
-		$targetUser
1285
-			->expects($this->exactly(2))
1286
-			->method('getLastLogin')
1287
-			->willReturn(1521191471);
1288
-		$targetUser
1289
-			->expects($this->once())
1290
-			->method('getFirstLogin')
1291
-			->willReturn(1511191471);
1292
-		$targetUser
1293
-			->expects($this->once())
1294
-			->method('getBackendClassName')
1295
-			->willReturn('Database');
1296
-		$targetUser
1297
-			->expects($this->once())
1298
-			->method('getBackend')
1299
-			->willReturn($backend);
1300
-		$targetUser
1301
-			->method('getUID')
1302
-			->willReturn('UID');
1303
-
1304
-		$this->mockAccount($targetUser, [
1305
-			IAccountManager::PROPERTY_ADDRESS => ['value' => 'address'],
1306
-			IAccountManager::PROPERTY_PHONE => ['value' => 'phone'],
1307
-			IAccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
1308
-			IAccountManager::PROPERTY_FEDIVERSE => ['value' => 'fediverse'],
1309
-			IAccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
1310
-			IAccountManager::PROPERTY_ORGANISATION => ['value' => 'organisation'],
1311
-			IAccountManager::PROPERTY_ROLE => ['value' => 'role'],
1312
-			IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
1313
-			IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
1314
-			IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
1315
-			IAccountManager::PROPERTY_PRONOUNS => ['value' => 'they/them'],
1316
-		]);
1317
-
1318
-		$this->l10nFactory
1319
-			->expects($this->once())
1320
-			->method('getUserLanguage')
1321
-			->with($targetUser)
1322
-			->willReturn('da');
1323
-
1324
-		$expected = [
1325
-			'id' => 'UID',
1326
-			'enabled' => true,
1327
-			'firstLoginTimestamp' => 1511191471,
1328
-			'lastLoginTimestamp' => 1521191471,
1329
-			'lastLogin' => 1521191471000,
1330
-			'backend' => 'Database',
1331
-			'subadmin' => [],
1332
-			'quota' => ['DummyValue'],
1333
-			'email' => '[email protected]',
1334
-			'displayname' => 'Demo User',
1335
-			'display-name' => 'Demo User',
1336
-			'phone' => 'phone',
1337
-			'address' => 'address',
1338
-			'website' => 'website',
1339
-			'twitter' => 'twitter',
1340
-			'fediverse' => 'fediverse',
1341
-			'groups' => [],
1342
-			'language' => 'da',
1343
-			'locale' => null,
1344
-			'backendCapabilities' => [
1345
-				'setDisplayName' => true,
1346
-				'setPassword' => true,
1347
-			],
1348
-			'additional_mail' => [],
1349
-			'organisation' => 'organisation',
1350
-			'role' => 'role',
1351
-			'headline' => 'headline',
1352
-			'biography' => 'biography',
1353
-			'profile_enabled' => '1',
1354
-			'notify_email' => null,
1355
-			'manager' => '',
1356
-			'pronouns' => 'they/them',
1357
-		];
1358
-		$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
1359
-	}
1360
-
1361
-
1362
-
1363
-	public function testGetUserDataAsSubAdminAndUserIsNotAccessible(): void {
1364
-		$this->expectException(OCSException::class);
1365
-		$this->expectExceptionCode(998);
1366
-
1367
-		$loggedInUser = $this->getMockBuilder(IUser::class)
1368
-			->disableOriginalConstructor()
1369
-			->getMock();
1370
-		$loggedInUser
1371
-			->expects($this->exactly(4))
1372
-			->method('getUID')
1373
-			->willReturn('subadmin');
1374
-		$targetUser = $this->getMockBuilder(IUser::class)
1375
-			->disableOriginalConstructor()
1376
-			->getMock();
1377
-		$this->userSession
1378
-			->method('getUser')
1379
-			->willReturn($loggedInUser);
1380
-		$this->userManager
1381
-			->expects($this->once())
1382
-			->method('get')
1383
-			->with('UserToGet')
1384
-			->willReturn($targetUser);
1385
-		$this->groupManager
1386
-			->expects($this->once())
1387
-			->method('isAdmin')
1388
-			->with('subadmin')
1389
-			->willReturn(false);
1390
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
1391
-			->disableOriginalConstructor()
1392
-			->getMock();
1393
-		$subAdminManager
1394
-			->expects($this->once())
1395
-			->method('isUserAccessible')
1396
-			->with($loggedInUser, $targetUser)
1397
-			->willReturn(false);
1398
-		$this->groupManager
1399
-			->expects($this->once())
1400
-			->method('getSubAdmin')
1401
-			->willReturn($subAdminManager);
1402
-
1403
-		$this->invokePrivate($this->api, 'getUser', ['UserToGet']);
1404
-	}
1405
-
1406
-	public function testGetUserDataAsSubAdminSelfLookup(): void {
1407
-		$loggedInUser = $this->getMockBuilder(IUser::class)
1408
-			->disableOriginalConstructor()
1409
-			->getMock();
1410
-		$loggedInUser
1411
-			->method('getUID')
1412
-			->willReturn('UID');
1413
-		$targetUser = $this->getMockBuilder(IUser::class)
1414
-			->disableOriginalConstructor()
1415
-			->getMock();
1416
-		$this->userSession
1417
-			->method('getUser')
1418
-			->willReturn($loggedInUser);
1419
-		$this->userManager
1420
-			->method('get')
1421
-			->with('UID')
1422
-			->willReturn($targetUser);
1423
-		$this->groupManager
1424
-			->method('isAdmin')
1425
-			->with('UID')
1426
-			->willReturn(false);
1427
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
1428
-			->disableOriginalConstructor()
1429
-			->getMock();
1430
-		$subAdminManager
1431
-			->expects($this->once())
1432
-			->method('isUserAccessible')
1433
-			->with($loggedInUser, $targetUser)
1434
-			->willReturn(false);
1435
-		$subAdminManager
1436
-			->expects($this->once())
1437
-			->method('getSubAdminsGroups')
1438
-			->willReturn([]);
1439
-		$this->groupManager
1440
-			->expects($this->exactly(2))
1441
-			->method('getSubAdmin')
1442
-			->willReturn($subAdminManager);
1443
-		$this->groupManager
1444
-			->expects($this->any())
1445
-			->method('getUserGroups')
1446
-			->willReturn([]);
1447
-		$this->api
1448
-			->expects($this->once())
1449
-			->method('fillStorageInfo')
1450
-			->with($targetUser)
1451
-			->willReturn(['DummyValue']);
1452
-
1453
-		$backend = $this->createMock(UserInterface::class);
1454
-		$backend->expects($this->atLeastOnce())
1455
-			->method('implementsActions')
1456
-			->willReturn(false);
1457
-
1458
-		$targetUser
1459
-			->expects($this->once())
1460
-			->method('getDisplayName')
1461
-			->willReturn('Subadmin User');
1462
-		$targetUser
1463
-			->expects($this->once())
1464
-			->method('getSystemEMailAddress')
1465
-			->willReturn('[email protected]');
1466
-		$targetUser
1467
-			->method('getUID')
1468
-			->willReturn('UID');
1469
-		$targetUser
1470
-			->expects($this->never())
1471
-			->method('getHome');
1472
-		$targetUser
1473
-			->expects($this->exactly(2))
1474
-			->method('getLastLogin')
1475
-			->willReturn(1521191471);
1476
-		$targetUser
1477
-			->expects($this->once())
1478
-			->method('getFirstLogin')
1479
-			->willReturn(1511191471);
1480
-		$targetUser
1481
-			->expects($this->once())
1482
-			->method('getBackendClassName')
1483
-			->willReturn('Database');
1484
-		$targetUser
1485
-			->expects($this->once())
1486
-			->method('getBackend')
1487
-			->willReturn($backend);
1488
-		$this->mockAccount($targetUser, [
1489
-			IAccountManager::PROPERTY_ADDRESS => ['value' => 'address'],
1490
-			IAccountManager::PROPERTY_PHONE => ['value' => 'phone'],
1491
-			IAccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
1492
-			IAccountManager::PROPERTY_FEDIVERSE => ['value' => 'fediverse'],
1493
-			IAccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
1494
-			IAccountManager::PROPERTY_ORGANISATION => ['value' => 'organisation'],
1495
-			IAccountManager::PROPERTY_ROLE => ['value' => 'role'],
1496
-			IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
1497
-			IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
1498
-			IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
1499
-			IAccountManager::PROPERTY_PRONOUNS => ['value' => 'they/them'],
1500
-		]);
1501
-
1502
-		$this->l10nFactory
1503
-			->expects($this->once())
1504
-			->method('getUserLanguage')
1505
-			->with($targetUser)
1506
-			->willReturn('ru');
1507
-
1508
-		$expected = [
1509
-			'id' => 'UID',
1510
-			'firstLoginTimestamp' => 1511191471,
1511
-			'lastLoginTimestamp' => 1521191471,
1512
-			'lastLogin' => 1521191471000,
1513
-			'backend' => 'Database',
1514
-			'subadmin' => [],
1515
-			'quota' => ['DummyValue'],
1516
-			'email' => '[email protected]',
1517
-			'displayname' => 'Subadmin User',
1518
-			'display-name' => 'Subadmin User',
1519
-			'phone' => 'phone',
1520
-			'address' => 'address',
1521
-			'website' => 'website',
1522
-			'twitter' => 'twitter',
1523
-			'fediverse' => 'fediverse',
1524
-			'groups' => [],
1525
-			'language' => 'ru',
1526
-			'locale' => null,
1527
-			'backendCapabilities' => [
1528
-				'setDisplayName' => false,
1529
-				'setPassword' => false,
1530
-			],
1531
-			'additional_mail' => [],
1532
-			'organisation' => 'organisation',
1533
-			'role' => 'role',
1534
-			'headline' => 'headline',
1535
-			'biography' => 'biography',
1536
-			'profile_enabled' => '1',
1537
-			'notify_email' => null,
1538
-			'manager' => '',
1539
-			'pronouns' => 'they/them',
1540
-		];
1541
-		$this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
1542
-	}
1543
-
1544
-	public function dataSearchByPhoneNumbers(): array {
1545
-		return [
1546
-			'Invalid country' => ['Not a country code', ['12345' => ['NaN']], 400, null, null, []],
1547
-			'No number to search' => ['DE', ['12345' => ['NaN']], 200, null, null, []],
1548
-			'Valid number but no match' => ['DE', ['12345' => ['0711 / 25 24 28-90']], 200, ['+4971125242890'], [], []],
1549
-			'Invalid number' => ['FR', ['12345' => ['0711 / 25 24 28-90']], 200, null, null, []],
1550
-			'Invalid and valid number' => ['DE', ['12345' => ['NaN', '0711 / 25 24 28-90']], 200, ['+4971125242890'], [], []],
1551
-			'Valid and invalid number' => ['DE', ['12345' => ['0711 / 25 24 28-90', 'NaN']], 200, ['+4971125242890'], [], []],
1552
-			'Valid number and a match' => ['DE', ['12345' => ['0711 / 25 24 28-90']], 200, ['+4971125242890'], ['+4971125242890' => 'admin'], ['12345' => 'admin@localhost']],
1553
-			'Same number twice, later hits' => ['DE', ['12345' => ['0711 / 25 24 28-90'], '23456' => ['0711 / 25 24 28-90']], 200, ['+4971125242890'], ['+4971125242890' => 'admin'], ['23456' => 'admin@localhost']],
1554
-		];
1555
-	}
1556
-
1557
-	/**
1558
-	 * @dataProvider dataSearchByPhoneNumbers
1559
-	 * @param string $location
1560
-	 * @param array $search
1561
-	 * @param int $status
1562
-	 * @param array $expected
1563
-	 */
1564
-	public function testSearchByPhoneNumbers(string $location, array $search, int $status, ?array $searchUsers, ?array $userMatches, array $expected): void {
1565
-		$knownTo = 'knownTo';
1566
-		$user = $this->createMock(IUser::class);
1567
-		$user->method('getUID')
1568
-			->willReturn($knownTo);
1569
-		$this->userSession->method('getUser')
1570
-			->willReturn($user);
1571
-
1572
-		if ($searchUsers === null) {
1573
-			$this->accountManager->expects($this->never())
1574
-				->method('searchUsers');
1575
-		} else {
1576
-			$this->accountManager->expects($this->once())
1577
-				->method('searchUsers')
1578
-				->with(IAccountManager::PROPERTY_PHONE, $searchUsers)
1579
-				->willReturn($userMatches);
1580
-
1581
-			$this->knownUserService->expects($this->once())
1582
-				->method('deleteKnownTo')
1583
-				->with($knownTo);
1584
-
1585
-			$this->knownUserService->expects($this->exactly(count($expected)))
1586
-				->method('storeIsKnownToUser')
1587
-				->with($knownTo, $this->anything());
1588
-		}
1589
-
1590
-		$this->urlGenerator->method('getAbsoluteURL')
1591
-			->with('/')
1592
-			->willReturn('https://localhost/');
1593
-
1594
-		$response = $this->api->searchByPhoneNumbers($location, $search);
1595
-
1596
-		self::assertEquals($status, $response->getStatus());
1597
-		self::assertEquals($expected, $response->getData());
1598
-	}
1599
-
1600
-	public function testEditUserRegularUserSelfEditChangeDisplayName(): void {
1601
-		$loggedInUser = $this->getMockBuilder(IUser::class)
1602
-			->disableOriginalConstructor()
1603
-			->getMock();
1604
-		$loggedInUser
1605
-			->expects($this->any())
1606
-			->method('getUID')
1607
-			->willReturn('UID');
1608
-		$targetUser = $this->getMockBuilder(IUser::class)
1609
-			->disableOriginalConstructor()
1610
-			->getMock();
1611
-		$this->userSession
1612
-			->expects($this->once())
1613
-			->method('getUser')
1614
-			->willReturn($loggedInUser);
1615
-		$this->userManager
1616
-			->expects($this->once())
1617
-			->method('get')
1618
-			->with('UserToEdit')
1619
-			->willReturn($targetUser);
1620
-		$targetUser
1621
-			->expects($this->once())
1622
-			->method('getBackend')
1623
-			->willReturn($this->createMock(ISetDisplayNameBackend::class));
1624
-		$targetUser
1625
-			->expects($this->once())
1626
-			->method('setDisplayName')
1627
-			->with('NewDisplayName')
1628
-			->willReturn(true);
1629
-		$targetUser
1630
-			->expects($this->any())
1631
-			->method('getUID')
1632
-			->willReturn('UID');
1633
-
1634
-		$this->assertEquals([], $this->api->editUser('UserToEdit', 'display', 'NewDisplayName')->getData());
1635
-	}
1636
-
1637
-	public function testEditUserRegularUserSelfEditChangeEmailValid(): void {
1638
-		$loggedInUser = $this->getMockBuilder(IUser::class)
1639
-			->disableOriginalConstructor()
1640
-			->getMock();
1641
-		$loggedInUser
1642
-			->expects($this->any())
1643
-			->method('getUID')
1644
-			->willReturn('UID');
1645
-		$targetUser = $this->getMockBuilder(IUser::class)
1646
-			->disableOriginalConstructor()
1647
-			->getMock();
1648
-		$this->userSession
1649
-			->expects($this->once())
1650
-			->method('getUser')
1651
-			->willReturn($loggedInUser);
1652
-		$this->userManager
1653
-			->expects($this->once())
1654
-			->method('get')
1655
-			->with('UserToEdit')
1656
-			->willReturn($targetUser);
1657
-		$targetUser
1658
-			->expects($this->once())
1659
-			->method('setEMailAddress')
1660
-			->with('[email protected]');
1661
-		$targetUser
1662
-			->expects($this->any())
1663
-			->method('getUID')
1664
-			->willReturn('UID');
1665
-
1666
-		$backend = $this->createMock(UserInterface::class);
1667
-		$targetUser
1668
-			->expects($this->any())
1669
-			->method('getBackend')
1670
-			->willReturn($backend);
1671
-
1672
-		$this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => $default);
1673
-
1674
-		$this->assertEquals([], $this->api->editUser('UserToEdit', 'email', '[email protected]')->getData());
1675
-	}
1676
-
1677
-	public function testEditUserRegularUserSelfEditAddAdditionalEmailValid(): void {
1678
-		$loggedInUser = $this->getMockBuilder(IUser::class)
1679
-			->disableOriginalConstructor()
1680
-			->getMock();
1681
-		$loggedInUser
1682
-			->expects($this->any())
1683
-			->method('getUID')
1684
-			->willReturn('UID');
1685
-		$targetUser = $this->getMockBuilder(IUser::class)
1686
-			->disableOriginalConstructor()
1687
-			->getMock();
1688
-		$this->userSession
1689
-			->expects($this->once())
1690
-			->method('getUser')
1691
-			->willReturn($loggedInUser);
1692
-		$this->userManager
1693
-			->expects($this->once())
1694
-			->method('get')
1695
-			->with('UserToEdit')
1696
-			->willReturn($targetUser);
1697
-		$targetUser
1698
-			->expects($this->any())
1699
-			->method('getUID')
1700
-			->willReturn('UID');
1701
-
1702
-		$backend = $this->createMock(UserInterface::class);
1703
-		$targetUser
1704
-			->expects($this->any())
1705
-			->method('getBackend')
1706
-			->willReturn($backend);
1707
-
1708
-		$userAccount = $this->createMock(IAccount::class);
1709
-
1710
-		$this->accountManager
1711
-			->expects($this->once())
1712
-			->method('getAccount')
1713
-			->with($targetUser)
1714
-			->willReturn($userAccount);
1715
-		$this->accountManager
1716
-			->expects($this->once())
1717
-			->method('updateAccount')
1718
-			->with($userAccount);
1719
-
1720
-		$this->assertEquals([], $this->api->editUser('UserToEdit', 'additional_mail', '[email protected]')->getData());
1721
-	}
1722
-
1723
-	public function testEditUserRegularUserSelfEditAddAdditionalEmailMainAddress(): void {
1724
-		$loggedInUser = $this->getMockBuilder(IUser::class)
1725
-			->disableOriginalConstructor()
1726
-			->getMock();
1727
-		$loggedInUser
1728
-			->expects($this->any())
1729
-			->method('getUID')
1730
-			->willReturn('UID');
1731
-		$targetUser = $this->getMockBuilder(IUser::class)
1732
-			->disableOriginalConstructor()
1733
-			->getMock();
1734
-		$this->userSession
1735
-			->expects($this->once())
1736
-			->method('getUser')
1737
-			->willReturn($loggedInUser);
1738
-		$this->userManager
1739
-			->expects($this->once())
1740
-			->method('get')
1741
-			->with('UserToEdit')
1742
-			->willReturn($targetUser);
1743
-		$targetUser
1744
-			->expects($this->any())
1745
-			->method('getUID')
1746
-			->willReturn('UID');
1747
-
1748
-		$backend = $this->createMock(UserInterface::class);
1749
-		$targetUser
1750
-			->expects($this->any())
1751
-			->method('getBackend')
1752
-			->willReturn($backend);
1753
-		$targetUser
1754
-			->expects($this->any())
1755
-			->method('getSystemEMailAddress')
1756
-			->willReturn('[email protected]');
1757
-
1758
-		$userAccount = $this->createMock(IAccount::class);
1759
-
1760
-		$this->accountManager
1761
-			->expects($this->never())
1762
-			->method('getAccount')
1763
-			->with($targetUser)
1764
-			->willReturn($userAccount);
1765
-		$this->accountManager
1766
-			->expects($this->never())
1767
-			->method('updateAccount')
1768
-			->with($userAccount);
1769
-
1770
-		$this->expectException(OCSException::class);
1771
-		$this->expectExceptionCode(101);
1772
-		$this->api->editUser('UserToEdit', 'additional_mail', '[email protected]')->getData();
1773
-	}
1774
-
1775
-	public function testEditUserRegularUserSelfEditAddAdditionalEmailDuplicate(): void {
1776
-		$loggedInUser = $this->getMockBuilder(IUser::class)
1777
-			->disableOriginalConstructor()
1778
-			->getMock();
1779
-		$loggedInUser
1780
-			->expects($this->any())
1781
-			->method('getUID')
1782
-			->willReturn('UID');
1783
-		$targetUser = $this->getMockBuilder(IUser::class)
1784
-			->disableOriginalConstructor()
1785
-			->getMock();
1786
-		$this->userSession
1787
-			->expects($this->once())
1788
-			->method('getUser')
1789
-			->willReturn($loggedInUser);
1790
-		$this->userManager
1791
-			->expects($this->once())
1792
-			->method('get')
1793
-			->with('UserToEdit')
1794
-			->willReturn($targetUser);
1795
-		$targetUser
1796
-			->expects($this->any())
1797
-			->method('getUID')
1798
-			->willReturn('UID');
1799
-
1800
-		$backend = $this->createMock(UserInterface::class);
1801
-		$targetUser
1802
-			->expects($this->any())
1803
-			->method('getBackend')
1804
-			->willReturn($backend);
1805
-
1806
-		$property = $this->createMock(IAccountProperty::class);
1807
-		$property->method('getValue')
1808
-			->willReturn('[email protected]');
1809
-		$collection = $this->createMock(IAccountPropertyCollection::class);
1810
-		$collection->method('getPropertyByValue')
1811
-			->with('[email protected]')
1812
-			->willReturn($property);
1813
-
1814
-		$userAccount = $this->createMock(IAccount::class);
1815
-		$userAccount->method('getPropertyCollection')
1816
-			->with(IAccountManager::COLLECTION_EMAIL)
1817
-			->willReturn($collection);
1818
-
1819
-		$this->accountManager
1820
-			->expects($this->once())
1821
-			->method('getAccount')
1822
-			->with($targetUser)
1823
-			->willReturn($userAccount);
1824
-		$this->accountManager
1825
-			->expects($this->never())
1826
-			->method('updateAccount')
1827
-			->with($userAccount);
1828
-
1829
-		$this->expectException(OCSException::class);
1830
-		$this->expectExceptionCode(101);
1831
-		$this->api->editUser('UserToEdit', 'additional_mail', '[email protected]')->getData();
1832
-	}
1833
-
1834
-	public function testEditUserRegularUserSelfEditChangeEmailInvalid(): void {
1835
-		$this->expectException(OCSException::class);
1836
-		$this->expectExceptionCode(101);
1837
-
1838
-		$loggedInUser = $this->getMockBuilder(IUser::class)
1839
-			->disableOriginalConstructor()
1840
-			->getMock();
1841
-		$loggedInUser
1842
-			->expects($this->any())
1843
-			->method('getUID')
1844
-			->willReturn('UID');
1845
-		$targetUser = $this->getMockBuilder(IUser::class)
1846
-			->disableOriginalConstructor()
1847
-			->getMock();
1848
-		$this->userSession
1849
-			->expects($this->once())
1850
-			->method('getUser')
1851
-			->willReturn($loggedInUser);
1852
-		$this->userManager
1853
-			->expects($this->once())
1854
-			->method('get')
1855
-			->with('UserToEdit')
1856
-			->willReturn($targetUser);
1857
-		$targetUser
1858
-			->expects($this->any())
1859
-			->method('getUID')
1860
-			->willReturn('UID');
1861
-
1862
-		$backend = $this->createMock(UserInterface::class);
1863
-		$targetUser
1864
-			->expects($this->any())
1865
-			->method('getBackend')
1866
-			->willReturn($backend);
1867
-
1868
-		$this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => $default);
1869
-
1870
-		$this->api->editUser('UserToEdit', 'email', 'demo.org');
1871
-	}
1872
-
1873
-	public function selfEditChangePropertyProvider() {
1874
-		return [
1875
-			[IAccountManager::PROPERTY_TWITTER, '@oldtwitter', '@newtwitter'],
1876
-			[IAccountManager::PROPERTY_FEDIVERSE, '@[email protected]', '@[email protected]'],
1877
-			[IAccountManager::PROPERTY_PHONE, '1234', '12345'],
1878
-			[IAccountManager::PROPERTY_ADDRESS, 'Something street 2', 'Another street 3'],
1879
-			[IAccountManager::PROPERTY_WEBSITE, 'https://examplesite1', 'https://examplesite2'],
1880
-			[IAccountManager::PROPERTY_ORGANISATION, 'Organisation A', 'Organisation B'],
1881
-			[IAccountManager::PROPERTY_ROLE, 'Human', 'Alien'],
1882
-			[IAccountManager::PROPERTY_HEADLINE, 'Hi', 'Hello'],
1883
-			[IAccountManager::PROPERTY_BIOGRAPHY, 'A biography', 'Another biography'],
1884
-			[IAccountManager::PROPERTY_PROFILE_ENABLED, '1', '0'],
1885
-			[IAccountManager::PROPERTY_PRONOUNS, 'they/them', 'he/him'],
1886
-		];
1887
-	}
1888
-
1889
-	/**
1890
-	 * @dataProvider selfEditChangePropertyProvider
1891
-	 */
1892
-	public function testEditUserRegularUserSelfEditChangeProperty($propertyName, $oldValue, $newValue): void {
1893
-		$loggedInUser = $this->getMockBuilder(IUser::class)
1894
-			->disableOriginalConstructor()
1895
-			->getMock();
1896
-		$loggedInUser
1897
-			->expects($this->any())
1898
-			->method('getUID')
1899
-			->willReturn('UID');
1900
-		$this->userSession
1901
-			->expects($this->once())
1902
-			->method('getUser')
1903
-			->willReturn($loggedInUser);
1904
-		$this->userManager
1905
-			->expects($this->once())
1906
-			->method('get')
1907
-			->with('UserToEdit')
1908
-			->willReturn($loggedInUser);
1909
-
1910
-		$backend = $this->createMock(UserInterface::class);
1911
-		$loggedInUser
1912
-			->expects($this->any())
1913
-			->method('getBackend')
1914
-			->willReturn($backend);
1915
-
1916
-		$propertyMock = $this->createMock(IAccountProperty::class);
1917
-		$propertyMock->expects($this->any())
1918
-			->method('getName')
1919
-			->willReturn($propertyName);
1920
-		$propertyMock->expects($this->any())
1921
-			->method('getValue')
1922
-			->willReturn($oldValue);
1923
-		$propertyMock->expects($this->once())
1924
-			->method('setValue')
1925
-			->with($newValue)
1926
-			->willReturnSelf();
1927
-		$propertyMock->expects($this->any())
1928
-			->method('getScope')
1929
-			->willReturn(IAccountManager::SCOPE_LOCAL);
1930
-
1931
-		$accountMock = $this->createMock(IAccount::class);
1932
-		$accountMock->expects($this->any())
1933
-			->method('getProperty')
1934
-			->with($propertyName)
1935
-			->willReturn($propertyMock);
1936
-
1937
-		$this->accountManager->expects($this->atLeastOnce())
1938
-			->method('getAccount')
1939
-			->with($loggedInUser)
1940
-			->willReturn($accountMock);
1941
-		$this->accountManager->expects($this->once())
1942
-			->method('updateAccount')
1943
-			->with($accountMock);
1944
-
1945
-		$this->assertEquals([], $this->api->editUser('UserToEdit', $propertyName, $newValue)->getData());
1946
-	}
1947
-
1948
-	public function selfEditChangePropertyScopeProvider() {
1949
-		return [
1950
-			[IAccountManager::PROPERTY_AVATAR, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1951
-			[IAccountManager::PROPERTY_DISPLAYNAME, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1952
-			[IAccountManager::PROPERTY_EMAIL, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1953
-			[IAccountManager::PROPERTY_TWITTER, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1954
-			[IAccountManager::PROPERTY_FEDIVERSE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1955
-			[IAccountManager::PROPERTY_PHONE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1956
-			[IAccountManager::PROPERTY_ADDRESS, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1957
-			[IAccountManager::PROPERTY_WEBSITE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1958
-			[IAccountManager::PROPERTY_ORGANISATION, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1959
-			[IAccountManager::PROPERTY_ROLE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1960
-			[IAccountManager::PROPERTY_HEADLINE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1961
-			[IAccountManager::PROPERTY_BIOGRAPHY, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1962
-			[IAccountManager::PROPERTY_PROFILE_ENABLED, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1963
-			[IAccountManager::PROPERTY_PRONOUNS, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1964
-		];
1965
-	}
1966
-
1967
-	/**
1968
-	 * @dataProvider selfEditChangePropertyProvider
1969
-	 */
1970
-	public function testEditUserRegularUserSelfEditChangePropertyScope($propertyName, $oldScope, $newScope): void {
1971
-		$loggedInUser = $this->getMockBuilder(IUser::class)
1972
-			->disableOriginalConstructor()
1973
-			->getMock();
1974
-		$loggedInUser
1975
-			->expects($this->any())
1976
-			->method('getUID')
1977
-			->willReturn('UID');
1978
-		$this->userSession
1979
-			->expects($this->once())
1980
-			->method('getUser')
1981
-			->willReturn($loggedInUser);
1982
-		$this->userManager
1983
-			->expects($this->once())
1984
-			->method('get')
1985
-			->with('UserToEdit')
1986
-			->willReturn($loggedInUser);
1987
-
1988
-		$backend = $this->createMock(UserInterface::class);
1989
-		$loggedInUser
1990
-			->expects($this->any())
1991
-			->method('getBackend')
1992
-			->willReturn($backend);
1993
-
1994
-		$propertyMock = $this->createMock(IAccountProperty::class);
1995
-		$propertyMock->expects($this->any())
1996
-			->method('getName')
1997
-			->willReturn($propertyName);
1998
-		$propertyMock->expects($this->any())
1999
-			->method('getValue')
2000
-			->willReturn('somevalue');
2001
-		$propertyMock->expects($this->any())
2002
-			->method('getScope')
2003
-			->willReturn($oldScope);
2004
-		$propertyMock->expects($this->atLeastOnce())
2005
-			->method('setScope')
2006
-			->with($newScope)
2007
-			->willReturnSelf();
2008
-
2009
-		$accountMock = $this->createMock(IAccount::class);
2010
-		$accountMock->expects($this->any())
2011
-			->method('getProperty')
2012
-			->with($propertyName)
2013
-			->willReturn($propertyMock);
2014
-
2015
-		$this->accountManager->expects($this->atLeastOnce())
2016
-			->method('getAccount')
2017
-			->with($loggedInUser)
2018
-			->willReturn($accountMock);
2019
-		$this->accountManager->expects($this->once())
2020
-			->method('updateAccount')
2021
-			->with($accountMock);
2022
-
2023
-		$this->assertEquals([], $this->api->editUser('UserToEdit', $propertyName . 'Scope', $newScope)->getData());
2024
-	}
2025
-
2026
-	public function testEditUserRegularUserSelfEditChangePassword(): void {
2027
-		$loggedInUser = $this->getMockBuilder(IUser::class)
2028
-			->disableOriginalConstructor()
2029
-			->getMock();
2030
-		$loggedInUser
2031
-			->expects($this->any())
2032
-			->method('getUID')
2033
-			->willReturn('UID');
2034
-		$targetUser = $this->getMockBuilder(IUser::class)
2035
-			->disableOriginalConstructor()
2036
-			->getMock();
2037
-		$this->userSession
2038
-			->expects($this->once())
2039
-			->method('getUser')
2040
-			->willReturn($loggedInUser);
2041
-		$this->userManager
2042
-			->expects($this->once())
2043
-			->method('get')
2044
-			->with('UserToEdit')
2045
-			->willReturn($targetUser);
2046
-		$targetUser
2047
-			->expects($this->once())
2048
-			->method('canChangePassword')
2049
-			->willReturn(true);
2050
-		$targetUser
2051
-			->expects($this->once())
2052
-			->method('setPassword')
2053
-			->with('NewPassword');
2054
-		$targetUser
2055
-			->expects($this->any())
2056
-			->method('getUID')
2057
-			->willReturn('UID');
2058
-
2059
-		$backend = $this->createMock(UserInterface::class);
2060
-		$targetUser
2061
-			->expects($this->any())
2062
-			->method('getBackend')
2063
-			->willReturn($backend);
2064
-
2065
-		$this->assertEquals([], $this->api->editUser('UserToEdit', 'password', 'NewPassword')->getData());
2066
-	}
2067
-
2068
-
2069
-
2070
-	public function testEditUserRegularUserSelfEditChangeQuota(): void {
2071
-		$this->expectException(OCSException::class);
2072
-		$this->expectExceptionCode(113);
2073
-
2074
-		$loggedInUser = $this->getMockBuilder(IUser::class)
2075
-			->disableOriginalConstructor()
2076
-			->getMock();
2077
-		$loggedInUser
2078
-			->expects($this->any())
2079
-			->method('getUID')
2080
-			->willReturn('UID');
2081
-		$targetUser = $this->getMockBuilder(IUser::class)
2082
-			->disableOriginalConstructor()
2083
-			->getMock();
2084
-		$this->userSession
2085
-			->expects($this->once())
2086
-			->method('getUser')
2087
-			->willReturn($loggedInUser);
2088
-		$this->userManager
2089
-			->expects($this->once())
2090
-			->method('get')
2091
-			->with('UserToEdit')
2092
-			->willReturn($targetUser);
2093
-		$targetUser
2094
-			->expects($this->any())
2095
-			->method('getUID')
2096
-			->willReturn('UID');
2097
-
2098
-		$backend = $this->createMock(UserInterface::class);
2099
-		$targetUser
2100
-			->expects($this->any())
2101
-			->method('getBackend')
2102
-			->willReturn($backend);
2103
-
2104
-		$this->api->editUser('UserToEdit', 'quota', 'NewQuota');
2105
-	}
2106
-
2107
-	public function testEditUserAdminUserSelfEditChangeValidQuota(): void {
2108
-		$this->config
2109
-			->expects($this->once())
2110
-			->method('getAppValue')
2111
-			->willReturnCallback(function ($appid, $key, $default) {
2112
-				if ($key === 'max_quota') {
2113
-					return '-1';
2114
-				}
2115
-				return null;
2116
-			});
2117
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2118
-		$loggedInUser
2119
-			->expects($this->any())
2120
-			->method('getUID')
2121
-			->willReturn('UID');
2122
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2123
-		$targetUser->expects($this->once())
2124
-			->method('setQuota')
2125
-			->with('2.9 MB');
2126
-		$this->userSession
2127
-			->expects($this->once())
2128
-			->method('getUser')
2129
-			->willReturn($loggedInUser);
2130
-		$this->userManager
2131
-			->expects($this->once())
2132
-			->method('get')
2133
-			->with('UserToEdit')
2134
-			->willReturn($targetUser);
2135
-		$this->groupManager
2136
-			->expects($this->exactly(3))
2137
-			->method('isAdmin')
2138
-			->with('UID')
2139
-			->willReturn(true);
2140
-		$targetUser
2141
-			->expects($this->any())
2142
-			->method('getUID')
2143
-			->willReturn('UID');
2144
-
2145
-		$backend = $this->createMock(UserInterface::class);
2146
-		$targetUser
2147
-			->expects($this->any())
2148
-			->method('getBackend')
2149
-			->willReturn($backend);
2150
-
2151
-		$this->assertEquals([], $this->api->editUser('UserToEdit', 'quota', '3042824')->getData());
2152
-	}
2153
-
2154
-
2155
-
2156
-	public function testEditUserAdminUserSelfEditChangeInvalidQuota(): void {
2157
-		$this->expectException(OCSException::class);
2158
-		$this->expectExceptionMessage('Invalid quota value: ABC');
2159
-		$this->expectExceptionCode(101);
2160
-
2161
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2162
-		$loggedInUser
2163
-			->expects($this->any())
2164
-			->method('getUID')
2165
-			->willReturn('UID');
2166
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2167
-		$this->userSession
2168
-			->expects($this->once())
2169
-			->method('getUser')
2170
-			->willReturn($loggedInUser);
2171
-		$this->userManager
2172
-			->expects($this->once())
2173
-			->method('get')
2174
-			->with('UserToEdit')
2175
-			->willReturn($targetUser);
2176
-		$this->groupManager
2177
-			->expects($this->exactly(3))
2178
-			->method('isAdmin')
2179
-			->with('UID')
2180
-			->willReturn(true);
2181
-		$targetUser
2182
-			->expects($this->any())
2183
-			->method('getUID')
2184
-			->willReturn('UID');
2185
-
2186
-		$backend = $this->createMock(UserInterface::class);
2187
-		$targetUser
2188
-			->expects($this->any())
2189
-			->method('getBackend')
2190
-			->willReturn($backend);
2191
-
2192
-		$this->api->editUser('UserToEdit', 'quota', 'ABC');
2193
-	}
2194
-
2195
-	public function testEditUserAdminUserEditChangeValidQuota(): void {
2196
-		$this->config
2197
-			->expects($this->once())
2198
-			->method('getAppValue')
2199
-			->willReturnCallback(function ($appid, $key, $default) {
2200
-				if ($key === 'max_quota') {
2201
-					return '-1';
2202
-				}
2203
-				return null;
2204
-			});
2205
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2206
-		$loggedInUser
2207
-			->expects($this->any())
2208
-			->method('getUID')
2209
-			->willReturn('admin');
2210
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2211
-		$targetUser->expects($this->once())
2212
-			->method('setQuota')
2213
-			->with('2.9 MB');
2214
-		$this->userSession
2215
-			->expects($this->once())
2216
-			->method('getUser')
2217
-			->willReturn($loggedInUser);
2218
-		$this->userManager
2219
-			->expects($this->once())
2220
-			->method('get')
2221
-			->with('UserToEdit')
2222
-			->willReturn($targetUser);
2223
-		$this->groupManager
2224
-			->expects($this->once())
2225
-			->method('isAdmin')
2226
-			->with('admin')
2227
-			->willReturn(true);
2228
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2229
-			->disableOriginalConstructor()
2230
-			->getMock();
2231
-		$this->groupManager
2232
-			->expects($this->once())
2233
-			->method('getSubAdmin')
2234
-			->willReturn($subAdminManager);
2235
-		$targetUser
2236
-			->expects($this->any())
2237
-			->method('getUID')
2238
-			->willReturn('UID');
2239
-
2240
-		$backend = $this->createMock(UserInterface::class);
2241
-		$targetUser
2242
-			->expects($this->any())
2243
-			->method('getBackend')
2244
-			->willReturn($backend);
2245
-
2246
-		$this->assertEquals([], $this->api->editUser('UserToEdit', 'quota', '3042824')->getData());
2247
-	}
2248
-
2249
-	public function testEditUserSelfEditChangeLanguage(): void {
2250
-		$this->l10nFactory->expects($this->once())
2251
-			->method('findAvailableLanguages')
2252
-			->willReturn(['en', 'de', 'sv']);
2253
-		$this->config->expects($this->any())
2254
-			->method('getSystemValue')
2255
-			->willReturnMap([
2256
-				['allow_user_to_change_display_name', true, true],
2257
-				['force_language', false, false],
2258
-			]);
2259
-
2260
-		$loggedInUser = $this->createMock(IUser::class);
2261
-		$loggedInUser
2262
-			->expects($this->any())
2263
-			->method('getUID')
2264
-			->willReturn('UserToEdit');
2265
-		$targetUser = $this->createMock(IUser::class);
2266
-		$this->config->expects($this->once())
2267
-			->method('setUserValue')
2268
-			->with('UserToEdit', 'core', 'lang', 'de');
2269
-		$this->userSession
2270
-			->expects($this->once())
2271
-			->method('getUser')
2272
-			->willReturn($loggedInUser);
2273
-		$this->userManager
2274
-			->expects($this->once())
2275
-			->method('get')
2276
-			->with('UserToEdit')
2277
-			->willReturn($targetUser);
2278
-		$this->groupManager
2279
-			->expects($this->atLeastOnce())
2280
-			->method('isAdmin')
2281
-			->with('UserToEdit')
2282
-			->willReturn(false);
2283
-		$targetUser
2284
-			->expects($this->any())
2285
-			->method('getUID')
2286
-			->willReturn('UserToEdit');
2287
-
2288
-		$backend = $this->createMock(UserInterface::class);
2289
-		$targetUser
2290
-			->expects($this->any())
2291
-			->method('getBackend')
2292
-			->willReturn($backend);
2293
-
2294
-		$this->assertEquals([], $this->api->editUser('UserToEdit', 'language', 'de')->getData());
2295
-	}
2296
-
2297
-	public function dataEditUserSelfEditChangeLanguageButForced() {
2298
-		return [
2299
-			['de'],
2300
-			[true],
2301
-		];
2302
-	}
2303
-
2304
-	/**
2305
-	 * @dataProvider dataEditUserSelfEditChangeLanguageButForced
2306
-	 */
2307
-	public function testEditUserSelfEditChangeLanguageButForced($forced): void {
2308
-		$this->expectException(OCSException::class);
2309
-
2310
-		$this->config->expects($this->any())
2311
-			->method('getSystemValue')
2312
-			->willReturnMap([
2313
-				['allow_user_to_change_display_name', true, true],
2314
-				['force_language', false, $forced],
2315
-			]);
2316
-
2317
-		$loggedInUser = $this->createMock(IUser::class);
2318
-		$loggedInUser
2319
-			->expects($this->any())
2320
-			->method('getUID')
2321
-			->willReturn('UserToEdit');
2322
-		$targetUser = $this->createMock(IUser::class);
2323
-		$this->config->expects($this->never())
2324
-			->method('setUserValue');
2325
-		$this->userSession
2326
-			->expects($this->once())
2327
-			->method('getUser')
2328
-			->willReturn($loggedInUser);
2329
-		$this->userManager
2330
-			->expects($this->once())
2331
-			->method('get')
2332
-			->with('UserToEdit')
2333
-			->willReturn($targetUser);
2334
-		$this->groupManager
2335
-			->expects($this->atLeastOnce())
2336
-			->method('isAdmin')
2337
-			->with('UserToEdit')
2338
-			->willReturn(false);
2339
-		$targetUser
2340
-			->expects($this->any())
2341
-			->method('getUID')
2342
-			->willReturn('UserToEdit');
2343
-
2344
-		$backend = $this->createMock(UserInterface::class);
2345
-		$targetUser
2346
-			->expects($this->any())
2347
-			->method('getBackend')
2348
-			->willReturn($backend);
2349
-
2350
-		$this->assertEquals([], $this->api->editUser('UserToEdit', 'language', 'de')->getData());
2351
-	}
2352
-
2353
-	public function testEditUserAdminEditChangeLanguage(): void {
2354
-		$this->l10nFactory->expects($this->once())
2355
-			->method('findAvailableLanguages')
2356
-			->willReturn(['en', 'de', 'sv']);
2357
-
2358
-		$loggedInUser = $this->createMock(IUser::class);
2359
-		$loggedInUser
2360
-			->expects($this->any())
2361
-			->method('getUID')
2362
-			->willReturn('admin');
2363
-		$targetUser = $this->createMock(IUser::class);
2364
-		$this->config->expects($this->once())
2365
-			->method('setUserValue')
2366
-			->with('UserToEdit', 'core', 'lang', 'de');
2367
-		$this->userSession
2368
-			->expects($this->once())
2369
-			->method('getUser')
2370
-			->willReturn($loggedInUser);
2371
-		$this->userManager
2372
-			->expects($this->once())
2373
-			->method('get')
2374
-			->with('UserToEdit')
2375
-			->willReturn($targetUser);
2376
-		$this->groupManager
2377
-			->expects($this->once())
2378
-			->method('isAdmin')
2379
-			->with('admin')
2380
-			->willReturn(true);
2381
-		$subAdminManager = $this->createMock(SubAdmin::class);
2382
-		$this->groupManager
2383
-			->expects($this->once())
2384
-			->method('getSubAdmin')
2385
-			->willReturn($subAdminManager);
2386
-		$targetUser
2387
-			->expects($this->any())
2388
-			->method('getUID')
2389
-			->willReturn('UserToEdit');
2390
-
2391
-		$backend = $this->createMock(UserInterface::class);
2392
-		$targetUser
2393
-			->expects($this->any())
2394
-			->method('getBackend')
2395
-			->willReturn($backend);
2396
-
2397
-		$this->assertEquals([], $this->api->editUser('UserToEdit', 'language', 'de')->getData());
2398
-	}
2399
-
2400
-	/**
2401
-	 * @dataProvider dataEditUserSelfEditChangeLanguageButForced
2402
-	 */
2403
-	public function testEditUserAdminEditChangeLanguageInvalidLanguage(): void {
2404
-		$this->expectException(OCSException::class);
2405
-
2406
-
2407
-		$this->l10nFactory->expects($this->once())
2408
-			->method('findAvailableLanguages')
2409
-			->willReturn(['en', 'de', 'sv']);
2410
-
2411
-		$loggedInUser = $this->createMock(IUser::class);
2412
-		$loggedInUser
2413
-			->expects($this->any())
2414
-			->method('getUID')
2415
-			->willReturn('admin');
2416
-		$targetUser = $this->createMock(IUser::class);
2417
-		$this->config->expects($this->never())
2418
-			->method('setUserValue');
2419
-		$this->userSession
2420
-			->expects($this->once())
2421
-			->method('getUser')
2422
-			->willReturn($loggedInUser);
2423
-		$this->userManager
2424
-			->expects($this->once())
2425
-			->method('get')
2426
-			->with('UserToEdit')
2427
-			->willReturn($targetUser);
2428
-		$this->groupManager
2429
-			->expects($this->once())
2430
-			->method('isAdmin')
2431
-			->with('admin')
2432
-			->willReturn(true);
2433
-		$subAdminManager = $this->createMock(SubAdmin::class);
2434
-		$this->groupManager
2435
-			->expects($this->once())
2436
-			->method('getSubAdmin')
2437
-			->willReturn($subAdminManager);
2438
-		$targetUser
2439
-			->expects($this->any())
2440
-			->method('getUID')
2441
-			->willReturn('UserToEdit');
2442
-
2443
-		$backend = $this->createMock(UserInterface::class);
2444
-		$targetUser
2445
-			->expects($this->any())
2446
-			->method('getBackend')
2447
-			->willReturn($backend);
2448
-
2449
-		$this->assertEquals([], $this->api->editUser('UserToEdit', 'language', 'ru')->getData());
2450
-	}
2451
-
2452
-	public function testEditUserSubadminUserAccessible(): void {
2453
-		$this->config
2454
-			->expects($this->once())
2455
-			->method('getAppValue')
2456
-			->willReturnCallback(function ($appid, $key, $default) {
2457
-				if ($key === 'max_quota') {
2458
-					return '-1';
2459
-				}
2460
-				return null;
2461
-			});
2462
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2463
-		$loggedInUser
2464
-			->expects($this->any())
2465
-			->method('getUID')
2466
-			->willReturn('subadmin');
2467
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2468
-		$targetUser->expects($this->once())
2469
-			->method('setQuota')
2470
-			->with('2.9 MB');
2471
-		$this->userSession
2472
-			->expects($this->once())
2473
-			->method('getUser')
2474
-			->willReturn($loggedInUser);
2475
-		$this->userManager
2476
-			->expects($this->once())
2477
-			->method('get')
2478
-			->with('UserToEdit')
2479
-			->willReturn($targetUser);
2480
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2481
-			->disableOriginalConstructor()
2482
-			->getMock();
2483
-		$subAdminManager
2484
-			->expects($this->once())
2485
-			->method('isUserAccessible')
2486
-			->with($loggedInUser, $targetUser)
2487
-			->willReturn(true);
2488
-		$this->groupManager
2489
-			->expects($this->once())
2490
-			->method('getSubAdmin')
2491
-			->willReturn($subAdminManager);
2492
-		$targetUser
2493
-			->expects($this->any())
2494
-			->method('getUID')
2495
-			->willReturn('UID');
2496
-
2497
-		$backend = $this->createMock(UserInterface::class);
2498
-		$targetUser
2499
-			->expects($this->any())
2500
-			->method('getBackend')
2501
-			->willReturn($backend);
2502
-
2503
-		$this->assertEquals([], $this->api->editUser('UserToEdit', 'quota', '3042824')->getData());
2504
-	}
2505
-
2506
-
2507
-	public function testEditUserSubadminUserInaccessible(): void {
2508
-		$this->expectException(OCSException::class);
2509
-		$this->expectExceptionCode(998);
2510
-
2511
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2512
-		$loggedInUser
2513
-			->expects($this->any())
2514
-			->method('getUID')
2515
-			->willReturn('subadmin');
2516
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2517
-		$this->userSession
2518
-			->expects($this->once())
2519
-			->method('getUser')
2520
-			->willReturn($loggedInUser);
2521
-		$this->userManager
2522
-			->expects($this->once())
2523
-			->method('get')
2524
-			->with('UserToEdit')
2525
-			->willReturn($targetUser);
2526
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2527
-			->disableOriginalConstructor()
2528
-			->getMock();
2529
-		$subAdminManager
2530
-			->expects($this->once())
2531
-			->method('isUserAccessible')
2532
-			->with($loggedInUser, $targetUser)
2533
-			->willReturn(false);
2534
-		$this->groupManager
2535
-			->expects($this->once())
2536
-			->method('getSubAdmin')
2537
-			->willReturn($subAdminManager);
2538
-		$targetUser
2539
-			->expects($this->any())
2540
-			->method('getUID')
2541
-			->willReturn('UID');
2542
-
2543
-		$this->api->editUser('UserToEdit', 'quota', 'value');
2544
-	}
2545
-
2546
-
2547
-	public function testDeleteUserNotExistingUser(): void {
2548
-		$this->expectException(OCSException::class);
2549
-		$this->expectExceptionCode(998);
2550
-
2551
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2552
-		$loggedInUser
2553
-			->expects($this->any())
2554
-			->method('getUID')
2555
-			->willReturn('UserToEdit');
2556
-		$this->userSession
2557
-			->expects($this->once())
2558
-			->method('getUser')
2559
-			->willReturn($loggedInUser);
2560
-		$this->userManager
2561
-			->expects($this->once())
2562
-			->method('get')
2563
-			->with('UserToDelete')
2564
-			->willReturn(null);
2565
-
2566
-		$this->api->deleteUser('UserToDelete');
2567
-	}
2568
-
2569
-
2570
-	public function testDeleteUserSelf(): void {
2571
-		$this->expectException(OCSException::class);
2572
-		$this->expectExceptionCode(101);
2573
-
2574
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2575
-		$loggedInUser
2576
-			->expects($this->any())
2577
-			->method('getUID')
2578
-			->willReturn('UID');
2579
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2580
-		$targetUser
2581
-			->expects($this->once())
2582
-			->method('getUID')
2583
-			->willReturn('UID');
2584
-		$this->userSession
2585
-			->expects($this->once())
2586
-			->method('getUser')
2587
-			->willReturn($loggedInUser);
2588
-		$this->userManager
2589
-			->expects($this->once())
2590
-			->method('get')
2591
-			->with('UserToDelete')
2592
-			->willReturn($targetUser);
2593
-
2594
-		$this->api->deleteUser('UserToDelete');
2595
-	}
2596
-
2597
-	public function testDeleteSuccessfulUserAsAdmin(): void {
2598
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2599
-		$loggedInUser
2600
-			->expects($this->any())
2601
-			->method('getUID')
2602
-			->willReturn('admin');
2603
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2604
-		$targetUser
2605
-			->expects($this->once())
2606
-			->method('getUID')
2607
-			->willReturn('UID');
2608
-		$this->userSession
2609
-			->expects($this->once())
2610
-			->method('getUser')
2611
-			->willReturn($loggedInUser);
2612
-		$this->userManager
2613
-			->expects($this->once())
2614
-			->method('get')
2615
-			->with('UserToDelete')
2616
-			->willReturn($targetUser);
2617
-		$this->groupManager
2618
-			->expects($this->once())
2619
-			->method('isAdmin')
2620
-			->with('admin')
2621
-			->willReturn(true);
2622
-		$targetUser
2623
-			->expects($this->once())
2624
-			->method('delete')
2625
-			->willReturn(true);
2626
-
2627
-		$this->assertEquals([], $this->api->deleteUser('UserToDelete')->getData());
2628
-	}
2629
-
2630
-
2631
-	public function testDeleteUnsuccessfulUserAsAdmin(): void {
2632
-		$this->expectException(OCSException::class);
2633
-		$this->expectExceptionCode(101);
2634
-
2635
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2636
-		$loggedInUser
2637
-			->expects($this->any())
2638
-			->method('getUID')
2639
-			->willReturn('admin');
2640
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2641
-		$targetUser
2642
-			->expects($this->once())
2643
-			->method('getUID')
2644
-			->willReturn('UID');
2645
-		$this->userSession
2646
-			->expects($this->once())
2647
-			->method('getUser')
2648
-			->willReturn($loggedInUser);
2649
-		$this->userManager
2650
-			->expects($this->once())
2651
-			->method('get')
2652
-			->with('UserToDelete')
2653
-			->willReturn($targetUser);
2654
-		$this->groupManager
2655
-			->expects($this->once())
2656
-			->method('isAdmin')
2657
-			->with('admin')
2658
-			->willReturn(true);
2659
-		$targetUser
2660
-			->expects($this->once())
2661
-			->method('delete')
2662
-			->willReturn(false);
2663
-
2664
-		$this->api->deleteUser('UserToDelete');
2665
-	}
2666
-
2667
-	public function testDeleteSuccessfulUserAsSubadmin(): void {
2668
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2669
-		$loggedInUser
2670
-			->expects($this->any())
2671
-			->method('getUID')
2672
-			->willReturn('subadmin');
2673
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2674
-		$targetUser
2675
-			->expects($this->once())
2676
-			->method('getUID')
2677
-			->willReturn('UID');
2678
-		$this->userSession
2679
-			->expects($this->once())
2680
-			->method('getUser')
2681
-			->willReturn($loggedInUser);
2682
-		$this->userManager
2683
-			->expects($this->once())
2684
-			->method('get')
2685
-			->with('UserToDelete')
2686
-			->willReturn($targetUser);
2687
-		$this->groupManager
2688
-			->expects($this->once())
2689
-			->method('isAdmin')
2690
-			->with('subadmin')
2691
-			->willReturn(false);
2692
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2693
-			->disableOriginalConstructor()->getMock();
2694
-		$subAdminManager
2695
-			->expects($this->once())
2696
-			->method('isUserAccessible')
2697
-			->with($loggedInUser, $targetUser)
2698
-			->willReturn(true);
2699
-		$this->groupManager
2700
-			->expects($this->once())
2701
-			->method('getSubAdmin')
2702
-			->willReturn($subAdminManager);
2703
-		$targetUser
2704
-			->expects($this->once())
2705
-			->method('delete')
2706
-			->willReturn(true);
2707
-
2708
-		$this->assertEquals([], $this->api->deleteUser('UserToDelete')->getData());
2709
-	}
2710
-
2711
-
2712
-	public function testDeleteUnsuccessfulUserAsSubadmin(): void {
2713
-		$this->expectException(OCSException::class);
2714
-		$this->expectExceptionCode(101);
2715
-
2716
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2717
-		$loggedInUser
2718
-			->expects($this->any())
2719
-			->method('getUID')
2720
-			->willReturn('subadmin');
2721
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2722
-		$targetUser
2723
-			->expects($this->once())
2724
-			->method('getUID')
2725
-			->willReturn('UID');
2726
-		$this->userSession
2727
-			->expects($this->once())
2728
-			->method('getUser')
2729
-			->willReturn($loggedInUser);
2730
-		$this->userManager
2731
-			->expects($this->once())
2732
-			->method('get')
2733
-			->with('UserToDelete')
2734
-			->willReturn($targetUser);
2735
-		$this->groupManager
2736
-			->expects($this->once())
2737
-			->method('isAdmin')
2738
-			->with('subadmin')
2739
-			->willReturn(false);
2740
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2741
-			->disableOriginalConstructor()->getMock();
2742
-		$subAdminManager
2743
-			->expects($this->once())
2744
-			->method('isUserAccessible')
2745
-			->with($loggedInUser, $targetUser)
2746
-			->willReturn(true);
2747
-		$this->groupManager
2748
-			->expects($this->once())
2749
-			->method('getSubAdmin')
2750
-			->willReturn($subAdminManager);
2751
-		$targetUser
2752
-			->expects($this->once())
2753
-			->method('delete')
2754
-			->willReturn(false);
2755
-
2756
-		$this->api->deleteUser('UserToDelete');
2757
-	}
2758
-
2759
-
2760
-	public function testDeleteUserAsSubAdminAndUserIsNotAccessible(): void {
2761
-		$this->expectException(OCSException::class);
2762
-		$this->expectExceptionCode(998);
2763
-
2764
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2765
-		$loggedInUser
2766
-			->expects($this->any())
2767
-			->method('getUID')
2768
-			->willReturn('subadmin');
2769
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2770
-		$targetUser
2771
-			->expects($this->once())
2772
-			->method('getUID')
2773
-			->willReturn('UID');
2774
-		$this->userSession
2775
-			->expects($this->once())
2776
-			->method('getUser')
2777
-			->willReturn($loggedInUser);
2778
-		$this->userManager
2779
-			->expects($this->once())
2780
-			->method('get')
2781
-			->with('UserToDelete')
2782
-			->willReturn($targetUser);
2783
-		$this->groupManager
2784
-			->expects($this->once())
2785
-			->method('isAdmin')
2786
-			->with('subadmin')
2787
-			->willReturn(false);
2788
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2789
-			->disableOriginalConstructor()->getMock();
2790
-		$subAdminManager
2791
-			->expects($this->once())
2792
-			->method('isUserAccessible')
2793
-			->with($loggedInUser, $targetUser)
2794
-			->willReturn(false);
2795
-		$this->groupManager
2796
-			->expects($this->once())
2797
-			->method('getSubAdmin')
2798
-			->willReturn($subAdminManager);
2799
-
2800
-		$this->api->deleteUser('UserToDelete');
2801
-	}
2802
-
2803
-
2804
-	public function testGetUsersGroupsTargetUserNotExisting(): void {
2805
-		$this->expectException(OCSException::class);
2806
-		$this->expectExceptionCode(998);
2807
-
2808
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2809
-		$this->userSession
2810
-			->expects($this->once())
2811
-			->method('getUser')
2812
-			->willReturn($loggedInUser);
2813
-
2814
-		$this->api->getUsersGroups('UserToLookup');
2815
-	}
2816
-
2817
-	public function testGetUsersGroupsSelfTargetted(): void {
2818
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2819
-		$loggedInUser
2820
-			->expects($this->exactly(3))
2821
-			->method('getUID')
2822
-			->willReturn('UserToLookup');
2823
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2824
-		$targetUser
2825
-			->expects($this->once())
2826
-			->method('getUID')
2827
-			->willReturn('UserToLookup');
2828
-		$this->userSession
2829
-			->expects($this->once())
2830
-			->method('getUser')
2831
-			->willReturn($loggedInUser);
2832
-		$this->userManager
2833
-			->expects($this->once())
2834
-			->method('get')
2835
-			->with('UserToLookup')
2836
-			->willReturn($targetUser);
2837
-		$this->groupManager
2838
-			->expects($this->once())
2839
-			->method('getUserGroupIds')
2840
-			->with($targetUser)
2841
-			->willReturn(['DummyValue']);
2842
-
2843
-		$this->assertEquals(['groups' => ['DummyValue']], $this->api->getUsersGroups('UserToLookup')->getData());
2844
-	}
2845
-
2846
-	public function testGetUsersGroupsForAdminUser(): void {
2847
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2848
-		$loggedInUser
2849
-			->expects($this->exactly(3))
2850
-			->method('getUID')
2851
-			->willReturn('admin');
2852
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2853
-		$targetUser
2854
-			->expects($this->once())
2855
-			->method('getUID')
2856
-			->willReturn('UserToLookup');
2857
-		$this->userSession
2858
-			->expects($this->once())
2859
-			->method('getUser')
2860
-			->willReturn($loggedInUser);
2861
-		$this->userManager
2862
-			->expects($this->once())
2863
-			->method('get')
2864
-			->with('UserToLookup')
2865
-			->willReturn($targetUser);
2866
-		$this->groupManager
2867
-			->expects($this->once())
2868
-			->method('getUserGroupIds')
2869
-			->with($targetUser)
2870
-			->willReturn(['DummyValue']);
2871
-		$this->groupManager
2872
-			->expects($this->once())
2873
-			->method('isAdmin')
2874
-			->with('admin')
2875
-			->willReturn(true);
2876
-
2877
-		$this->assertEquals(['groups' => ['DummyValue']], $this->api->getUsersGroups('UserToLookup')->getData());
2878
-	}
2879
-
2880
-	public function testGetUsersGroupsForSubAdminUserAndUserIsAccessible(): void {
2881
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2882
-		$loggedInUser
2883
-			->expects($this->exactly(3))
2884
-			->method('getUID')
2885
-			->willReturn('subadmin');
2886
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2887
-		$targetUser
2888
-			->expects($this->once())
2889
-			->method('getUID')
2890
-			->willReturn('UserToLookup');
2891
-		$this->userSession
2892
-			->expects($this->once())
2893
-			->method('getUser')
2894
-			->willReturn($loggedInUser);
2895
-		$this->userManager
2896
-			->expects($this->once())
2897
-			->method('get')
2898
-			->with('UserToLookup')
2899
-			->willReturn($targetUser);
2900
-		$this->groupManager
2901
-			->expects($this->once())
2902
-			->method('isAdmin')
2903
-			->with('subadmin')
2904
-			->willReturn(false);
2905
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2906
-			->disableOriginalConstructor()->getMock();
2907
-		$subAdminManager
2908
-			->expects($this->once())
2909
-			->method('isUserAccessible')
2910
-			->with($loggedInUser, $targetUser)
2911
-			->willReturn(true);
2912
-		$this->groupManager
2913
-			->expects($this->once())
2914
-			->method('getSubAdmin')
2915
-			->willReturn($subAdminManager);
2916
-		$group1 = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
2917
-		$group1
2918
-			->expects($this->any())
2919
-			->method('getGID')
2920
-			->willReturn('Group1');
2921
-		$group2 = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
2922
-		$group2
2923
-			->expects($this->any())
2924
-			->method('getGID')
2925
-			->willReturn('Group2');
2926
-		$subAdminManager
2927
-			->expects($this->once())
2928
-			->method('getSubAdminsGroups')
2929
-			->with($loggedInUser)
2930
-			->willReturn([$group1, $group2]);
2931
-		$this->groupManager
2932
-			->expects($this->any())
2933
-			->method('getUserGroupIds')
2934
-			->with($targetUser)
2935
-			->willReturn(['Group1']);
2936
-
2937
-		$this->assertEquals(['groups' => ['Group1']], $this->api->getUsersGroups('UserToLookup')->getData());
2938
-	}
2939
-
2940
-
2941
-	public function testGetUsersGroupsForSubAdminUserAndUserIsInaccessible(): void {
2942
-		$this->expectException(OCSException::class);
2943
-		$this->expectExceptionCode(998);
2944
-
2945
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2946
-		$loggedInUser
2947
-			->expects($this->exactly(3))
2948
-			->method('getUID')
2949
-			->willReturn('subadmin');
2950
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2951
-		$targetUser
2952
-			->expects($this->once())
2953
-			->method('getUID')
2954
-			->willReturn('UserToLookup');
2955
-		$this->userSession
2956
-			->expects($this->once())
2957
-			->method('getUser')
2958
-			->willReturn($loggedInUser);
2959
-		$this->userManager
2960
-			->expects($this->once())
2961
-			->method('get')
2962
-			->with('UserToLookup')
2963
-			->willReturn($targetUser);
2964
-		$this->groupManager
2965
-			->expects($this->once())
2966
-			->method('isAdmin')
2967
-			->with('subadmin')
2968
-			->willReturn(false);
2969
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2970
-			->disableOriginalConstructor()->getMock();
2971
-		$subAdminManager
2972
-			->expects($this->once())
2973
-			->method('isUserAccessible')
2974
-			->with($loggedInUser, $targetUser)
2975
-			->willReturn(false);
2976
-		$this->groupManager
2977
-			->expects($this->once())
2978
-			->method('getSubAdmin')
2979
-			->willReturn($subAdminManager);
2980
-		$this->groupManager
2981
-			->expects($this->any())
2982
-			->method('getUserGroupIds')
2983
-			->with($targetUser)
2984
-			->willReturn(['Group1']);
2985
-
2986
-		$this->api->getUsersGroups('UserToLookup');
2987
-	}
2988
-
2989
-
2990
-	public function testAddToGroupWithTargetGroupNotExisting(): void {
2991
-		$this->expectException(OCSException::class);
2992
-		$this->expectExceptionCode(102);
2993
-
2994
-		$this->groupManager->expects($this->once())
2995
-			->method('get')
2996
-			->with('GroupToAddTo')
2997
-			->willReturn(null);
2998
-
2999
-		$this->api->addToGroup('TargetUser', 'GroupToAddTo');
3000
-	}
3001
-
3002
-
3003
-	public function testAddToGroupWithNoGroupSpecified(): void {
3004
-		$this->expectException(OCSException::class);
3005
-		$this->expectExceptionCode(101);
3006
-
3007
-		$this->api->addToGroup('TargetUser');
3008
-	}
3009
-
3010
-
3011
-	public function testAddToGroupWithTargetUserNotExisting(): void {
3012
-		$this->expectException(OCSException::class);
3013
-		$this->expectExceptionCode(103);
3014
-
3015
-		$targetGroup = $this->createMock(IGroup::class);
3016
-		$this->groupManager->expects($this->once())
3017
-			->method('get')
3018
-			->with('GroupToAddTo')
3019
-			->willReturn($targetGroup);
3020
-
3021
-		$this->api->addToGroup('TargetUser', 'GroupToAddTo');
3022
-	}
3023
-
3024
-
3025
-	public function testAddToGroupNoSubadmin(): void {
3026
-		$this->expectException(OCSException::class);
3027
-		$this->expectExceptionCode(104);
3028
-
3029
-		$targetUser = $this->createMock(IUser::class);
3030
-		$loggedInUser = $this->createMock(IUser::class);
3031
-		$loggedInUser->expects($this->exactly(2))
3032
-			->method('getUID')
3033
-			->willReturn('subadmin');
3034
-
3035
-		$targetGroup = $this->createMock(IGroup::class);
3036
-		$targetGroup->expects($this->never())
3037
-			->method('addUser')
3038
-			->with($targetUser);
3039
-
3040
-		$this->groupManager->expects($this->once())
3041
-			->method('get')
3042
-			->with('GroupToAddTo')
3043
-			->willReturn($targetGroup);
3044
-
3045
-
3046
-		$subAdminManager = $this->createMock(SubAdmin::class);
3047
-		$subAdminManager->expects($this->once())
3048
-			->method('isSubAdminOfGroup')
3049
-			->with($loggedInUser, $targetGroup)
3050
-			->willReturn(false);
3051
-
3052
-		$this->groupManager->expects($this->once())
3053
-			->method('getSubAdmin')
3054
-			->willReturn($subAdminManager);
3055
-		$this->groupManager->expects($this->once())
3056
-			->method('isAdmin')
3057
-			->with('subadmin')
3058
-			->willReturn(false);
3059
-
3060
-		$this->userManager->expects($this->once())
3061
-			->method('get')
3062
-			->with('TargetUser')
3063
-			->willReturn($targetUser);
3064
-
3065
-		$this->userSession->expects($this->once())
3066
-			->method('getUser')
3067
-			->willReturn($loggedInUser);
3068
-
3069
-		$this->api->addToGroup('TargetUser', 'GroupToAddTo');
3070
-	}
3071
-
3072
-	public function testAddToGroupSuccessAsSubadmin(): void {
3073
-		$targetUser = $this->createMock(IUser::class);
3074
-		$loggedInUser = $this->createMock(IUser::class);
3075
-		$loggedInUser->expects($this->exactly(2))
3076
-			->method('getUID')
3077
-			->willReturn('subadmin');
3078
-
3079
-		$targetGroup = $this->createMock(IGroup::class);
3080
-		$targetGroup->expects($this->once())
3081
-			->method('addUser')
3082
-			->with($targetUser);
3083
-
3084
-		$this->groupManager->expects($this->once())
3085
-			->method('get')
3086
-			->with('GroupToAddTo')
3087
-			->willReturn($targetGroup);
49
+    /** @var IUserManager|MockObject */
50
+    protected $userManager;
51
+    /** @var IConfig|MockObject */
52
+    protected $config;
53
+    /** @var Manager|MockObject */
54
+    protected $groupManager;
55
+    /** @var IUserSession|MockObject */
56
+    protected $userSession;
57
+    /** @var LoggerInterface|MockObject */
58
+    protected $logger;
59
+    /** @var UsersController|MockObject */
60
+    protected $api;
61
+    /** @var IAccountManager|MockObject */
62
+    protected $accountManager;
63
+    /** @var ISubAdmin|MockObject */
64
+    protected $subAdminManager;
65
+    /** @var IURLGenerator|MockObject */
66
+    protected $urlGenerator;
67
+    /** @var IRequest|MockObject */
68
+    protected $request;
69
+    /** @var IFactory|MockObject */
70
+    private $l10nFactory;
71
+    /** @var NewUserMailHelper|MockObject */
72
+    private $newUserMailHelper;
73
+    /** @var ISecureRandom|MockObject */
74
+    private $secureRandom;
75
+    /** @var RemoteWipe|MockObject */
76
+    private $remoteWipe;
77
+    /** @var KnownUserService|MockObject */
78
+    private $knownUserService;
79
+    /** @var IEventDispatcher|MockObject */
80
+    private $eventDispatcher;
81
+    private IRootFolder $rootFolder;
82
+    /** @var IPhoneNumberUtil */
83
+    private $phoneNumberUtil;
84
+
85
+    protected function setUp(): void {
86
+        parent::setUp();
87
+
88
+        $this->userManager = $this->createMock(IUserManager::class);
89
+        $this->config = $this->createMock(IConfig::class);
90
+        $this->groupManager = $this->createMock(Manager::class);
91
+        $this->userSession = $this->createMock(IUserSession::class);
92
+        $this->logger = $this->createMock(LoggerInterface::class);
93
+        $this->request = $this->createMock(IRequest::class);
94
+        $this->accountManager = $this->createMock(IAccountManager::class);
95
+        $this->subAdminManager = $this->createMock(ISubAdmin::class);
96
+        $this->urlGenerator = $this->createMock(IURLGenerator::class);
97
+        $this->l10nFactory = $this->createMock(IFactory::class);
98
+        $this->newUserMailHelper = $this->createMock(NewUserMailHelper::class);
99
+        $this->secureRandom = $this->createMock(ISecureRandom::class);
100
+        $this->remoteWipe = $this->createMock(RemoteWipe::class);
101
+        $this->knownUserService = $this->createMock(KnownUserService::class);
102
+        $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
103
+        $this->phoneNumberUtil = new PhoneNumberUtil();
104
+        $this->rootFolder = $this->createMock(IRootFolder::class);
105
+
106
+        $l10n = $this->createMock(IL10N::class);
107
+        $l10n->method('t')->willReturnCallback(fn (string $txt, array $replacement = []) => sprintf($txt, ...$replacement));
108
+        $this->l10nFactory->method('get')->with('provisioning_api')->willReturn($l10n);
109
+
110
+        $this->api = $this->getMockBuilder(UsersController::class)
111
+            ->setConstructorArgs([
112
+                'provisioning_api',
113
+                $this->request,
114
+                $this->userManager,
115
+                $this->config,
116
+                $this->groupManager,
117
+                $this->userSession,
118
+                $this->accountManager,
119
+                $this->subAdminManager,
120
+                $this->l10nFactory,
121
+                $this->rootFolder,
122
+                $this->urlGenerator,
123
+                $this->logger,
124
+                $this->newUserMailHelper,
125
+                $this->secureRandom,
126
+                $this->remoteWipe,
127
+                $this->knownUserService,
128
+                $this->eventDispatcher,
129
+                $this->phoneNumberUtil,
130
+            ])
131
+            ->onlyMethods(['fillStorageInfo'])
132
+            ->getMock();
133
+    }
134
+
135
+    public function testGetUsersAsAdmin(): void {
136
+        $loggedInUser = $this->getMockBuilder(IUser::class)
137
+            ->disableOriginalConstructor()
138
+            ->getMock();
139
+        $loggedInUser
140
+            ->expects($this->once())
141
+            ->method('getUID')
142
+            ->willReturn('admin');
143
+        $this->userSession
144
+            ->expects($this->once())
145
+            ->method('getUser')
146
+            ->willReturn($loggedInUser);
147
+        $this->groupManager
148
+            ->expects($this->once())
149
+            ->method('isAdmin')
150
+            ->willReturn(true);
151
+        $this->userManager
152
+            ->expects($this->once())
153
+            ->method('search')
154
+            ->with('MyCustomSearch')
155
+            ->willReturn(['Admin' => [], 'Foo' => [], 'Bar' => []]);
156
+
157
+        $expected = [
158
+            'users' => [
159
+                'Admin',
160
+                'Foo',
161
+                'Bar',
162
+            ],
163
+        ];
164
+        $this->assertEquals($expected, $this->api->getUsers('MyCustomSearch')->getData());
165
+    }
166
+
167
+    public function testGetUsersAsSubAdmin(): void {
168
+        $loggedInUser = $this->getMockBuilder(IUser::class)
169
+            ->disableOriginalConstructor()
170
+            ->getMock();
171
+        $loggedInUser
172
+            ->expects($this->once())
173
+            ->method('getUID')
174
+            ->willReturn('subadmin');
175
+        $this->userSession
176
+            ->expects($this->once())
177
+            ->method('getUser')
178
+            ->willReturn($loggedInUser);
179
+        $this->groupManager
180
+            ->expects($this->once())
181
+            ->method('isAdmin')
182
+            ->willReturn(false);
183
+        $firstGroup = $this->getMockBuilder('OCP\IGroup')
184
+            ->disableOriginalConstructor()
185
+            ->getMock();
186
+        $firstGroup
187
+            ->expects($this->once())
188
+            ->method('getGID')
189
+            ->willReturn('FirstGroup');
190
+        $secondGroup = $this->getMockBuilder('OCP\IGroup')
191
+            ->disableOriginalConstructor()
192
+            ->getMock();
193
+        $secondGroup
194
+            ->expects($this->once())
195
+            ->method('getGID')
196
+            ->willReturn('SecondGroup');
197
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
198
+            ->disableOriginalConstructor()->getMock();
199
+        $subAdminManager
200
+            ->expects($this->once())
201
+            ->method('isSubAdmin')
202
+            ->with($loggedInUser)
203
+            ->willReturn(true);
204
+        $subAdminManager
205
+            ->expects($this->once())
206
+            ->method('getSubAdminsGroups')
207
+            ->with($loggedInUser)
208
+            ->willReturn([$firstGroup, $secondGroup]);
209
+        $this->groupManager
210
+            ->expects($this->once())
211
+            ->method('getSubAdmin')
212
+            ->willReturn($subAdminManager);
213
+        $this->groupManager
214
+            ->expects($this->any())
215
+            ->method('displayNamesInGroup')
216
+            ->will($this->onConsecutiveCalls(['AnotherUserInTheFirstGroup' => []], ['UserInTheSecondGroup' => []]));
217
+
218
+        $expected = [
219
+            'users' => [
220
+                'AnotherUserInTheFirstGroup',
221
+                'UserInTheSecondGroup',
222
+            ],
223
+        ];
224
+        $this->assertEquals($expected, $this->api->getUsers('MyCustomSearch')->getData());
225
+    }
226
+
227
+    private function createUserMock(string $uid, bool $enabled): MockObject&IUser {
228
+        $mockUser = $this->getMockBuilder(IUser::class)
229
+            ->disableOriginalConstructor()
230
+            ->getMock();
231
+        $mockUser
232
+            ->method('getUID')
233
+            ->willReturn($uid);
234
+        $mockUser
235
+            ->method('isEnabled')
236
+            ->willReturn($enabled);
237
+        return $mockUser;
238
+    }
239
+
240
+    public function testGetDisabledUsersAsAdmin(): void {
241
+        $loggedInUser = $this->getMockBuilder(IUser::class)
242
+            ->disableOriginalConstructor()
243
+            ->getMock();
244
+        $loggedInUser
245
+            ->expects($this->once())
246
+            ->method('getUID')
247
+            ->willReturn('admin');
248
+        $this->userSession
249
+            ->expects($this->atLeastOnce())
250
+            ->method('getUser')
251
+            ->willReturn($loggedInUser);
252
+        $this->groupManager
253
+            ->expects($this->once())
254
+            ->method('isAdmin')
255
+            ->willReturn(true);
256
+        $this->userManager
257
+            ->expects($this->once())
258
+            ->method('getDisabledUsers')
259
+            ->with(3, 0, 'MyCustomSearch')
260
+            ->willReturn([
261
+                $this->createUserMock('admin', false),
262
+                $this->createUserMock('foo', false),
263
+                $this->createUserMock('bar', false),
264
+            ]);
265
+
266
+        $expected = [
267
+            'users' => [
268
+                'admin' => ['id' => 'admin'],
269
+                'foo' => ['id' => 'foo'],
270
+                'bar' => ['id' => 'bar'],
271
+            ],
272
+        ];
273
+        $this->assertEquals($expected, $this->api->getDisabledUsersDetails('MyCustomSearch', 3)->getData());
274
+    }
275
+
276
+    public function testGetDisabledUsersAsSubAdmin(): void {
277
+        $loggedInUser = $this->getMockBuilder(IUser::class)
278
+            ->disableOriginalConstructor()
279
+            ->getMock();
280
+        $loggedInUser
281
+            ->expects($this->once())
282
+            ->method('getUID')
283
+            ->willReturn('subadmin');
284
+        $this->userSession
285
+            ->expects($this->atLeastOnce())
286
+            ->method('getUser')
287
+            ->willReturn($loggedInUser);
288
+        $this->groupManager
289
+            ->expects($this->once())
290
+            ->method('isAdmin')
291
+            ->willReturn(false);
292
+        $firstGroup = $this->getMockBuilder('OCP\IGroup')
293
+            ->disableOriginalConstructor()
294
+            ->getMock();
295
+        $secondGroup = $this->getMockBuilder('OCP\IGroup')
296
+            ->disableOriginalConstructor()
297
+            ->getMock();
298
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
299
+            ->disableOriginalConstructor()->getMock();
300
+        $subAdminManager
301
+            ->expects($this->once())
302
+            ->method('isSubAdmin')
303
+            ->with($loggedInUser)
304
+            ->willReturn(true);
305
+        $subAdminManager
306
+            ->expects($this->once())
307
+            ->method('getSubAdminsGroups')
308
+            ->with($loggedInUser)
309
+            ->willReturn([$firstGroup, $secondGroup]);
310
+        $this->groupManager
311
+            ->expects($this->once())
312
+            ->method('getSubAdmin')
313
+            ->willReturn($subAdminManager);
314
+        $this->groupManager
315
+            ->expects($this->never())
316
+            ->method('displayNamesInGroup');
317
+
318
+        $firstGroup
319
+            ->expects($this->once())
320
+            ->method('searchUsers')
321
+            ->with('MyCustomSearch')
322
+            ->willReturn([
323
+                $this->createUserMock('user1', false),
324
+                $this->createUserMock('bob', true),
325
+                $this->createUserMock('user2', false),
326
+                $this->createUserMock('alice', true),
327
+            ]);
328
+
329
+        $secondGroup
330
+            ->expects($this->once())
331
+            ->method('searchUsers')
332
+            ->with('MyCustomSearch')
333
+            ->willReturn([
334
+                $this->createUserMock('user2', false),
335
+                $this->createUserMock('joe', true),
336
+                $this->createUserMock('user3', false),
337
+                $this->createUserMock('jim', true),
338
+                $this->createUserMock('john', true),
339
+            ]);
340
+
341
+
342
+        $expected = [
343
+            'users' => [
344
+                'user1' => ['id' => 'user1'],
345
+                'user2' => ['id' => 'user2'],
346
+                'user3' => ['id' => 'user3'],
347
+            ],
348
+        ];
349
+        $this->assertEquals($expected, $this->api->getDisabledUsersDetails('MyCustomSearch', 3)->getData());
350
+    }
351
+
352
+
353
+    public function testAddUserAlreadyExisting(): void {
354
+        $this->expectException(OCSException::class);
355
+        $this->expectExceptionCode(102);
356
+
357
+        $this->userManager
358
+            ->expects($this->once())
359
+            ->method('userExists')
360
+            ->with('AlreadyExistingUser')
361
+            ->willReturn(true);
362
+        $this->logger
363
+            ->expects($this->once())
364
+            ->method('error')
365
+            ->with('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']);
366
+        $loggedInUser = $this->getMockBuilder(IUser::class)
367
+            ->disableOriginalConstructor()
368
+            ->getMock();
369
+        $loggedInUser
370
+            ->expects($this->exactly(2))
371
+            ->method('getUID')
372
+            ->willReturn('adminUser');
373
+        $this->userSession
374
+            ->expects($this->once())
375
+            ->method('getUser')
376
+            ->willReturn($loggedInUser);
377
+        $this->groupManager
378
+            ->expects($this->once())
379
+            ->method('isAdmin')
380
+            ->with('adminUser')
381
+            ->willReturn(true);
382
+
383
+        $this->api->addUser('AlreadyExistingUser', 'password', '', '', []);
384
+    }
385
+
386
+
387
+    public function testAddUserNonExistingGroup(): void {
388
+        $this->expectException(OCSException::class);
389
+        $this->expectExceptionMessage('Group NonExistingGroup does not exist');
390
+        $this->expectExceptionCode(104);
391
+
392
+        $this->userManager
393
+            ->expects($this->once())
394
+            ->method('userExists')
395
+            ->with('NewUser')
396
+            ->willReturn(false);
397
+        $loggedInUser = $this->getMockBuilder(IUser::class)
398
+            ->disableOriginalConstructor()
399
+            ->getMock();
400
+        $loggedInUser
401
+            ->expects($this->exactly(2))
402
+            ->method('getUID')
403
+            ->willReturn('adminUser');
404
+        $this->userSession
405
+            ->expects($this->once())
406
+            ->method('getUser')
407
+            ->willReturn($loggedInUser);
408
+        $this->groupManager
409
+            ->expects($this->once())
410
+            ->method('isAdmin')
411
+            ->with('adminUser')
412
+            ->willReturn(true);
413
+        $this->groupManager
414
+            ->expects($this->once())
415
+            ->method('groupExists')
416
+            ->with('NonExistingGroup')
417
+            ->willReturn(false);
418
+
419
+        $this->api->addUser('NewUser', 'pass', '', '', ['NonExistingGroup']);
420
+    }
421
+
422
+
423
+    public function testAddUserExistingGroupNonExistingGroup(): void {
424
+        $this->expectException(OCSException::class);
425
+        $this->expectExceptionMessage('Group NonExistingGroup does not exist');
426
+        $this->expectExceptionCode(104);
427
+
428
+        $this->userManager
429
+            ->expects($this->once())
430
+            ->method('userExists')
431
+            ->with('NewUser')
432
+            ->willReturn(false);
433
+        $loggedInUser = $this->getMockBuilder(IUser::class)
434
+            ->disableOriginalConstructor()
435
+            ->getMock();
436
+        $loggedInUser
437
+            ->expects($this->exactly(2))
438
+            ->method('getUID')
439
+            ->willReturn('adminUser');
440
+        $this->userSession
441
+            ->expects($this->once())
442
+            ->method('getUser')
443
+            ->willReturn($loggedInUser);
444
+        $this->groupManager
445
+            ->expects($this->once())
446
+            ->method('isAdmin')
447
+            ->with('adminUser')
448
+            ->willReturn(true);
449
+        $this->groupManager
450
+            ->expects($this->exactly(2))
451
+            ->method('groupExists')
452
+            ->withConsecutive(
453
+                ['ExistingGroup'],
454
+                ['NonExistingGroup']
455
+            )
456
+            ->willReturnMap([
457
+                ['ExistingGroup', true],
458
+                ['NonExistingGroup', false]
459
+            ]);
460
+
461
+        $this->api->addUser('NewUser', 'pass', '', '', ['ExistingGroup', 'NonExistingGroup']);
462
+    }
463
+
464
+    public function testAddUserSuccessful(): void {
465
+        $this->userManager
466
+            ->expects($this->once())
467
+            ->method('userExists')
468
+            ->with('NewUser')
469
+            ->willReturn(false);
470
+        $this->userManager
471
+            ->expects($this->once())
472
+            ->method('createUser')
473
+            ->with('NewUser', 'PasswordOfTheNewUser');
474
+        $this->logger
475
+            ->expects($this->once())
476
+            ->method('info')
477
+            ->with('Successful addUser call with userid: NewUser', ['app' => 'ocs_api']);
478
+        $loggedInUser = $this->getMockBuilder(IUser::class)
479
+            ->disableOriginalConstructor()
480
+            ->getMock();
481
+        $loggedInUser
482
+            ->expects($this->exactly(2))
483
+            ->method('getUID')
484
+            ->willReturn('adminUser');
485
+        $this->userSession
486
+            ->expects($this->once())
487
+            ->method('getUser')
488
+            ->willReturn($loggedInUser);
489
+        $this->groupManager
490
+            ->expects($this->once())
491
+            ->method('isAdmin')
492
+            ->with('adminUser')
493
+            ->willReturn(true);
494
+
495
+        $this->assertTrue(key_exists(
496
+            'id',
497
+            $this->api->addUser('NewUser', 'PasswordOfTheNewUser')->getData()
498
+        ));
499
+    }
500
+
501
+    public function testAddUserSuccessfulWithDisplayName(): void {
502
+        /**
503
+         * @var UserController
504
+         */
505
+        $api = $this->getMockBuilder(UsersController::class)
506
+            ->setConstructorArgs([
507
+                'provisioning_api',
508
+                $this->request,
509
+                $this->userManager,
510
+                $this->config,
511
+                $this->groupManager,
512
+                $this->userSession,
513
+                $this->accountManager,
514
+                $this->subAdminManager,
515
+                $this->l10nFactory,
516
+                $this->rootFolder,
517
+                $this->urlGenerator,
518
+                $this->logger,
519
+                $this->newUserMailHelper,
520
+                $this->secureRandom,
521
+                $this->remoteWipe,
522
+                $this->knownUserService,
523
+                $this->eventDispatcher,
524
+                $this->phoneNumberUtil,
525
+            ])
526
+            ->onlyMethods(['editUser'])
527
+            ->getMock();
528
+
529
+        $this->userManager
530
+            ->expects($this->once())
531
+            ->method('userExists')
532
+            ->with('NewUser')
533
+            ->willReturn(false);
534
+        $this->userManager
535
+            ->expects($this->once())
536
+            ->method('createUser')
537
+            ->with('NewUser', 'PasswordOfTheNewUser');
538
+        $this->logger
539
+            ->expects($this->once())
540
+            ->method('info')
541
+            ->with('Successful addUser call with userid: NewUser', ['app' => 'ocs_api']);
542
+        $loggedInUser = $this->getMockBuilder(IUser::class)
543
+            ->disableOriginalConstructor()
544
+            ->getMock();
545
+        $loggedInUser
546
+            ->expects($this->any())
547
+            ->method('getUID')
548
+            ->willReturn('adminUser');
549
+        $this->userSession
550
+            ->expects($this->any())
551
+            ->method('getUser')
552
+            ->willReturn($loggedInUser);
553
+        $this->groupManager
554
+            ->expects($this->once())
555
+            ->method('isAdmin')
556
+            ->with('adminUser')
557
+            ->willReturn(true);
558
+        $api
559
+            ->expects($this->once())
560
+            ->method('editUser')
561
+            ->with('NewUser', 'display', 'DisplayNameOfTheNewUser');
562
+
563
+        $this->assertTrue(key_exists(
564
+            'id',
565
+            $api->addUser('NewUser', 'PasswordOfTheNewUser', 'DisplayNameOfTheNewUser')->getData()
566
+        ));
567
+    }
568
+
569
+    public function testAddUserSuccessfulGenerateUserID(): void {
570
+        $this->config
571
+            ->expects($this->any())
572
+            ->method('getAppValue')
573
+            ->willReturnCallback(function ($appid, $key, $default) {
574
+                if ($key === 'newUser.generateUserID') {
575
+                    return 'yes';
576
+                }
577
+                return null;
578
+            });
579
+        $this->userManager
580
+            ->expects($this->any())
581
+            ->method('userExists')
582
+            ->with($this->anything())
583
+            ->willReturn(false);
584
+        $this->userManager
585
+            ->expects($this->once())
586
+            ->method('createUser')
587
+            ->with($this->anything(), 'PasswordOfTheNewUser');
588
+        $this->logger
589
+            ->expects($this->once())
590
+            ->method('info')
591
+            ->with($this->stringStartsWith('Successful addUser call with userid: '), ['app' => 'ocs_api']);
592
+        $loggedInUser = $this->getMockBuilder(IUser::class)
593
+            ->disableOriginalConstructor()
594
+            ->getMock();
595
+        $loggedInUser
596
+            ->expects($this->exactly(2))
597
+            ->method('getUID')
598
+            ->willReturn('adminUser');
599
+        $this->userSession
600
+            ->expects($this->once())
601
+            ->method('getUser')
602
+            ->willReturn($loggedInUser);
603
+        $this->groupManager
604
+            ->expects($this->once())
605
+            ->method('isAdmin')
606
+            ->with('adminUser')
607
+            ->willReturn(true);
608
+        $this->secureRandom->expects($this->any())
609
+            ->method('generate')
610
+            ->with(10)
611
+            ->willReturnCallback(function () {
612
+                return (string)rand(100000000, 999999999);
613
+            });
614
+
615
+        $this->assertTrue(key_exists(
616
+            'id',
617
+            $this->api->addUser('', 'PasswordOfTheNewUser')->getData()
618
+        ));
619
+    }
620
+
621
+    public function testAddUserSuccessfulGeneratePassword(): void {
622
+        $this->userManager
623
+            ->expects($this->once())
624
+            ->method('userExists')
625
+            ->with('NewUser')
626
+            ->willReturn(false);
627
+        $newUser = $this->createMock(IUser::class);
628
+        $newUser->expects($this->once())
629
+            ->method('setEMailAddress');
630
+        $this->userManager
631
+            ->expects($this->once())
632
+            ->method('createUser')
633
+            ->willReturn($newUser);
634
+        $this->logger
635
+            ->expects($this->once())
636
+            ->method('info')
637
+            ->with('Successful addUser call with userid: NewUser', ['app' => 'ocs_api']);
638
+        $loggedInUser = $this->getMockBuilder(IUser::class)
639
+            ->disableOriginalConstructor()
640
+            ->getMock();
641
+        $loggedInUser
642
+            ->expects($this->exactly(2))
643
+            ->method('getUID')
644
+            ->willReturn('adminUser');
645
+        $this->userSession
646
+            ->expects($this->once())
647
+            ->method('getUser')
648
+            ->willReturn($loggedInUser);
649
+        $this->groupManager
650
+            ->expects($this->once())
651
+            ->method('isAdmin')
652
+            ->with('adminUser')
653
+            ->willReturn(true);
654
+        $this->eventDispatcher
655
+            ->expects($this->once())
656
+            ->method('dispatchTyped')
657
+            ->with(new GenerateSecurePasswordEvent());
658
+
659
+        $this->assertTrue(key_exists(
660
+            'id',
661
+            $this->api->addUser('NewUser', '', '', 'foo@bar')->getData()
662
+        ));
663
+    }
664
+
665
+
666
+    public function testAddUserFailedToGenerateUserID(): void {
667
+        $this->expectException(OCSException::class);
668
+        $this->expectExceptionMessage('Could not create non-existing user ID');
669
+        $this->expectExceptionCode(111);
670
+
671
+        $this->config
672
+            ->expects($this->any())
673
+            ->method('getAppValue')
674
+            ->willReturnCallback(function ($appid, $key, $default) {
675
+                if ($key === 'newUser.generateUserID') {
676
+                    return 'yes';
677
+                }
678
+                return null;
679
+            });
680
+        $this->userManager
681
+            ->expects($this->any())
682
+            ->method('userExists')
683
+            ->with($this->anything())
684
+            ->willReturn(true);
685
+        $this->userManager
686
+            ->expects($this->never())
687
+            ->method('createUser');
688
+        $loggedInUser = $this->getMockBuilder(IUser::class)
689
+            ->disableOriginalConstructor()
690
+            ->getMock();
691
+        $loggedInUser
692
+            ->expects($this->exactly(2))
693
+            ->method('getUID')
694
+            ->willReturn('adminUser');
695
+        $this->userSession
696
+            ->expects($this->once())
697
+            ->method('getUser')
698
+            ->willReturn($loggedInUser);
699
+        $this->groupManager
700
+            ->expects($this->once())
701
+            ->method('isAdmin')
702
+            ->with('adminUser')
703
+            ->willReturn(true);
704
+
705
+        $this->api->addUser('', 'PasswordOfTheNewUser')->getData();
706
+    }
707
+
708
+
709
+    public function testAddUserEmailRequired(): void {
710
+        $this->expectException(OCSException::class);
711
+        $this->expectExceptionMessage('Required email address was not provided');
712
+        $this->expectExceptionCode(110);
713
+
714
+        $this->config
715
+            ->expects($this->any())
716
+            ->method('getAppValue')
717
+            ->willReturnCallback(function ($appid, $key, $default) {
718
+                if ($key === 'newUser.requireEmail') {
719
+                    return 'yes';
720
+                }
721
+                return null;
722
+            });
723
+        $this->userManager
724
+            ->expects($this->once())
725
+            ->method('userExists')
726
+            ->with('NewUser')
727
+            ->willReturn(false);
728
+        $this->userManager
729
+            ->expects($this->never())
730
+            ->method('createUser');
731
+        $loggedInUser = $this->getMockBuilder(IUser::class)
732
+            ->disableOriginalConstructor()
733
+            ->getMock();
734
+        $loggedInUser
735
+            ->expects($this->exactly(2))
736
+            ->method('getUID')
737
+            ->willReturn('adminUser');
738
+        $this->userSession
739
+            ->expects($this->once())
740
+            ->method('getUser')
741
+            ->willReturn($loggedInUser);
742
+        $this->groupManager
743
+            ->expects($this->once())
744
+            ->method('isAdmin')
745
+            ->with('adminUser')
746
+            ->willReturn(true);
747
+
748
+        $this->assertTrue(key_exists(
749
+            'id',
750
+            $this->api->addUser('NewUser', 'PasswordOfTheNewUser')->getData()
751
+        ));
752
+    }
753
+
754
+    public function testAddUserExistingGroup(): void {
755
+        $this->userManager
756
+            ->expects($this->once())
757
+            ->method('userExists')
758
+            ->with('NewUser')
759
+            ->willReturn(false);
760
+        $loggedInUser = $this->getMockBuilder(IUser::class)
761
+            ->disableOriginalConstructor()
762
+            ->getMock();
763
+        $loggedInUser
764
+            ->expects($this->exactly(2))
765
+            ->method('getUID')
766
+            ->willReturn('adminUser');
767
+        $this->userSession
768
+            ->expects($this->once())
769
+            ->method('getUser')
770
+            ->willReturn($loggedInUser);
771
+        $this->groupManager
772
+            ->expects($this->once())
773
+            ->method('isAdmin')
774
+            ->with('adminUser')
775
+            ->willReturn(true);
776
+        $this->groupManager
777
+            ->expects($this->once())
778
+            ->method('groupExists')
779
+            ->with('ExistingGroup')
780
+            ->willReturn(true);
781
+        $user = $this->getMockBuilder(IUser::class)
782
+            ->disableOriginalConstructor()
783
+            ->getMock();
784
+        $this->userManager
785
+            ->expects($this->once())
786
+            ->method('createUser')
787
+            ->with('NewUser', 'PasswordOfTheNewUser')
788
+            ->willReturn($user);
789
+        $group = $this->getMockBuilder('OCP\IGroup')
790
+            ->disableOriginalConstructor()
791
+            ->getMock();
792
+        $group
793
+            ->expects($this->once())
794
+            ->method('addUser')
795
+            ->with($user);
796
+        $this->groupManager
797
+            ->expects($this->once())
798
+            ->method('get')
799
+            ->with('ExistingGroup')
800
+            ->willReturn($group);
801
+        $this->logger
802
+            ->expects($this->exactly(2))
803
+            ->method('info')
804
+            ->withConsecutive(
805
+                ['Successful addUser call with userid: NewUser', ['app' => 'ocs_api']],
806
+                ['Added userid NewUser to group ExistingGroup', ['app' => 'ocs_api']]
807
+            );
808
+
809
+        $this->assertTrue(key_exists(
810
+            'id',
811
+            $this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup'])->getData()
812
+        ));
813
+    }
814
+
815
+
816
+    public function testAddUserUnsuccessful(): void {
817
+        $this->expectException(OCSException::class);
818
+        $this->expectExceptionMessage('Bad request');
819
+        $this->expectExceptionCode(101);
820
+
821
+        $exception = new Exception('User backend not found.');
822
+        $this->userManager
823
+            ->expects($this->once())
824
+            ->method('userExists')
825
+            ->with('NewUser')
826
+            ->willReturn(false);
827
+        $this->userManager
828
+            ->expects($this->once())
829
+            ->method('createUser')
830
+            ->with('NewUser', 'PasswordOfTheNewUser')
831
+            ->will($this->throwException($exception));
832
+        $this->logger
833
+            ->expects($this->once())
834
+            ->method('error')
835
+            ->with(
836
+                'Failed addUser attempt with exception.',
837
+                [
838
+                    'app' => 'ocs_api',
839
+                    'exception' => $exception
840
+                ]
841
+            );
842
+        $loggedInUser = $this->getMockBuilder(IUser::class)
843
+            ->disableOriginalConstructor()
844
+            ->getMock();
845
+        $loggedInUser
846
+            ->expects($this->exactly(2))
847
+            ->method('getUID')
848
+            ->willReturn('adminUser');
849
+        $this->userSession
850
+            ->expects($this->once())
851
+            ->method('getUser')
852
+            ->willReturn($loggedInUser);
853
+        $this->groupManager
854
+            ->expects($this->once())
855
+            ->method('isAdmin')
856
+            ->with('adminUser')
857
+            ->willReturn(true);
858
+
859
+        $this->api->addUser('NewUser', 'PasswordOfTheNewUser');
860
+    }
861
+
862
+
863
+    public function testAddUserAsSubAdminNoGroup(): void {
864
+        $this->expectException(OCSException::class);
865
+        $this->expectExceptionMessage('No group specified (required for sub-admins)');
866
+        $this->expectExceptionCode(106);
867
+
868
+        $loggedInUser = $this->getMockBuilder(IUser::class)
869
+            ->disableOriginalConstructor()
870
+            ->getMock();
871
+        $loggedInUser
872
+            ->expects($this->exactly(2))
873
+            ->method('getUID')
874
+            ->willReturn('regularUser');
875
+        $this->userSession
876
+            ->expects($this->once())
877
+            ->method('getUser')
878
+            ->willReturn($loggedInUser);
879
+        $this->groupManager
880
+            ->expects($this->once())
881
+            ->method('isAdmin')
882
+            ->with('regularUser')
883
+            ->willReturn(false);
884
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
885
+            ->disableOriginalConstructor()->getMock();
886
+        $this->groupManager
887
+            ->expects($this->once())
888
+            ->method('getSubAdmin')
889
+            ->with()
890
+            ->willReturn($subAdminManager);
891
+
892
+        $this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', []);
893
+    }
894
+
895
+
896
+    public function testAddUserAsSubAdminValidGroupNotSubAdmin(): void {
897
+        $this->expectException(OCSException::class);
898
+        $this->expectExceptionMessage('Insufficient privileges for group ExistingGroup');
899
+        $this->expectExceptionCode(105);
900
+
901
+        $loggedInUser = $this->getMockBuilder(IUser::class)
902
+            ->disableOriginalConstructor()
903
+            ->getMock();
904
+        $loggedInUser
905
+            ->expects($this->exactly(2))
906
+            ->method('getUID')
907
+            ->willReturn('regularUser');
908
+        $this->userSession
909
+            ->expects($this->once())
910
+            ->method('getUser')
911
+            ->willReturn($loggedInUser);
912
+        $this->groupManager
913
+            ->expects($this->once())
914
+            ->method('isAdmin')
915
+            ->with('regularUser')
916
+            ->willReturn(false);
917
+        $existingGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
918
+        $this->groupManager
919
+            ->expects($this->once())
920
+            ->method('get')
921
+            ->with('ExistingGroup')
922
+            ->willReturn($existingGroup);
923
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
924
+            ->disableOriginalConstructor()->getMock();
925
+        $subAdminManager
926
+            ->expects($this->once())
927
+            ->method('isSubAdminOfGroup')
928
+            ->with($loggedInUser, $existingGroup)
929
+            ->willReturn(false);
930
+        $this->groupManager
931
+            ->expects($this->once())
932
+            ->method('getSubAdmin')
933
+            ->with()
934
+            ->willReturn($subAdminManager);
935
+        $this->groupManager
936
+            ->expects($this->once())
937
+            ->method('groupExists')
938
+            ->with('ExistingGroup')
939
+            ->willReturn(true);
940
+
941
+        $this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup'])->getData();
942
+    }
943
+
944
+    public function testAddUserAsSubAdminExistingGroups(): void {
945
+        $this->userManager
946
+            ->expects($this->once())
947
+            ->method('userExists')
948
+            ->with('NewUser')
949
+            ->willReturn(false);
950
+        $loggedInUser = $this->getMockBuilder(IUser::class)
951
+            ->disableOriginalConstructor()
952
+            ->getMock();
953
+        $loggedInUser
954
+            ->expects($this->exactly(2))
955
+            ->method('getUID')
956
+            ->willReturn('subAdminUser');
957
+        $this->userSession
958
+            ->expects($this->once())
959
+            ->method('getUser')
960
+            ->willReturn($loggedInUser);
961
+        $this->groupManager
962
+            ->expects($this->once())
963
+            ->method('isAdmin')
964
+            ->with('subAdminUser')
965
+            ->willReturn(false);
966
+        $this->groupManager
967
+            ->expects($this->exactly(2))
968
+            ->method('groupExists')
969
+            ->withConsecutive(
970
+                ['ExistingGroup1'],
971
+                ['ExistingGroup2']
972
+            )
973
+            ->willReturn(true);
974
+        $user = $this->getMockBuilder(IUser::class)
975
+            ->disableOriginalConstructor()
976
+            ->getMock();
977
+        $this->userManager
978
+            ->expects($this->once())
979
+            ->method('createUser')
980
+            ->with('NewUser', 'PasswordOfTheNewUser')
981
+            ->willReturn($user);
982
+        $existingGroup1 = $this->getMockBuilder('OCP\IGroup')
983
+            ->disableOriginalConstructor()
984
+            ->getMock();
985
+        $existingGroup2 = $this->getMockBuilder('OCP\IGroup')
986
+            ->disableOriginalConstructor()
987
+            ->getMock();
988
+        $existingGroup1
989
+            ->expects($this->once())
990
+            ->method('addUser')
991
+            ->with($user);
992
+        $existingGroup2
993
+            ->expects($this->once())
994
+            ->method('addUser')
995
+            ->with($user);
996
+        $this->groupManager
997
+            ->expects($this->exactly(4))
998
+            ->method('get')
999
+            ->withConsecutive(
1000
+                ['ExistingGroup1'],
1001
+                ['ExistingGroup2'],
1002
+                ['ExistingGroup1'],
1003
+                ['ExistingGroup2']
1004
+            )
1005
+            ->willReturnMap([
1006
+                ['ExistingGroup1', $existingGroup1],
1007
+                ['ExistingGroup2', $existingGroup2]
1008
+            ]);
1009
+        $this->logger
1010
+            ->expects($this->exactly(3))
1011
+            ->method('info')
1012
+            ->withConsecutive(
1013
+                ['Successful addUser call with userid: NewUser', ['app' => 'ocs_api']],
1014
+                ['Added userid NewUser to group ExistingGroup1', ['app' => 'ocs_api']],
1015
+                ['Added userid NewUser to group ExistingGroup2', ['app' => 'ocs_api']]
1016
+            );
1017
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
1018
+            ->disableOriginalConstructor()->getMock();
1019
+        $this->groupManager
1020
+            ->expects($this->once())
1021
+            ->method('getSubAdmin')
1022
+            ->willReturn($subAdminManager);
1023
+        $subAdminManager
1024
+            ->expects($this->exactly(2))
1025
+            ->method('isSubAdminOfGroup')
1026
+            ->withConsecutive(
1027
+                [$loggedInUser, $existingGroup1],
1028
+                [$loggedInUser, $existingGroup2]
1029
+            )
1030
+            ->willReturn(true);
1031
+
1032
+        $this->assertTrue(key_exists(
1033
+            'id',
1034
+            $this->api->addUser('NewUser', 'PasswordOfTheNewUser', '', '', ['ExistingGroup1', 'ExistingGroup2'])->getData()
1035
+        ));
1036
+    }
1037
+
1038
+
1039
+    public function testGetUserTargetDoesNotExist(): void {
1040
+        $this->expectException(OCSException::class);
1041
+        $this->expectExceptionMessage('User does not exist');
1042
+        $this->expectExceptionCode(404);
1043
+
1044
+        $loggedInUser = $this->getMockBuilder(IUser::class)
1045
+            ->disableOriginalConstructor()
1046
+            ->getMock();
1047
+        $this->userSession
1048
+            ->method('getUser')
1049
+            ->willReturn($loggedInUser);
1050
+        $this->userManager
1051
+            ->expects($this->once())
1052
+            ->method('get')
1053
+            ->with('UserToGet')
1054
+            ->willReturn(null);
1055
+
1056
+        $this->api->getUser('UserToGet');
1057
+    }
1058
+
1059
+    public function testGetUserDataAsAdmin(): void {
1060
+        $group0 = $this->createMock(IGroup::class);
1061
+        $group1 = $this->createMock(IGroup::class);
1062
+        $group2 = $this->createMock(IGroup::class);
1063
+        $group3 = $this->createMock(IGroup::class);
1064
+        $loggedInUser = $this->getMockBuilder(IUser::class)
1065
+            ->disableOriginalConstructor()
1066
+            ->getMock();
1067
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
1068
+            ->disableOriginalConstructor()
1069
+            ->getMock();
1070
+        $loggedInUser
1071
+            ->method('getUID')
1072
+            ->willReturn('admin');
1073
+        $targetUser = $this->getMockBuilder(IUser::class)
1074
+            ->disableOriginalConstructor()
1075
+            ->getMock();
1076
+        $targetUser->expects($this->once())
1077
+            ->method('getSystemEMailAddress')
1078
+            ->willReturn('[email protected]');
1079
+        $this->userSession
1080
+            ->method('getUser')
1081
+            ->willReturn($loggedInUser);
1082
+        $this->userManager
1083
+            ->method('get')
1084
+            ->with('UID')
1085
+            ->willReturn($targetUser);
1086
+        $this->groupManager
1087
+            ->method('isAdmin')
1088
+            ->with('admin')
1089
+            ->willReturn(true);
1090
+        $this->groupManager
1091
+            ->expects($this->any())
1092
+            ->method('getUserGroups')
1093
+            ->willReturn([$group0, $group1, $group2]);
1094
+        $this->groupManager
1095
+            ->expects($this->once())
1096
+            ->method('getSubAdmin')
1097
+            ->willReturn($subAdminManager);
1098
+        $subAdminManager
1099
+            ->expects($this->once())
1100
+            ->method('getSubAdminsGroups')
1101
+            ->willReturn([$group3]);
1102
+        $group0->expects($this->once())
1103
+            ->method('getGID')
1104
+            ->willReturn('group0');
1105
+        $group1->expects($this->once())
1106
+            ->method('getGID')
1107
+            ->willReturn('group1');
1108
+        $group2->expects($this->once())
1109
+            ->method('getGID')
1110
+            ->willReturn('group2');
1111
+        $group3->expects($this->once())
1112
+            ->method('getGID')
1113
+            ->willReturn('group3');
1114
+
1115
+        $this->mockAccount($targetUser, [
1116
+            IAccountManager::PROPERTY_ADDRESS => ['value' => 'address'],
1117
+            IAccountManager::PROPERTY_PHONE => ['value' => 'phone'],
1118
+            IAccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
1119
+            IAccountManager::PROPERTY_FEDIVERSE => ['value' => 'fediverse'],
1120
+            IAccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
1121
+            IAccountManager::PROPERTY_ORGANISATION => ['value' => 'organisation'],
1122
+            IAccountManager::PROPERTY_ROLE => ['value' => 'role'],
1123
+            IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
1124
+            IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
1125
+            IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
1126
+            IAccountManager::PROPERTY_PRONOUNS => ['value' => 'they/them'],
1127
+        ]);
1128
+        $this->config
1129
+            ->method('getUserValue')
1130
+            ->willReturnMap([
1131
+                ['UID', 'core', 'enabled', 'true', 'true'],
1132
+            ]);
1133
+        $this->api
1134
+            ->expects($this->once())
1135
+            ->method('fillStorageInfo')
1136
+            ->with($targetUser)
1137
+            ->willReturn(['DummyValue']);
1138
+
1139
+        $backend = $this->createMock(UserInterface::class);
1140
+        $backend->expects($this->any())
1141
+            ->method('implementsActions')
1142
+            ->willReturn(true);
1143
+
1144
+        $targetUser
1145
+            ->expects($this->once())
1146
+            ->method('getDisplayName')
1147
+            ->willReturn('Demo User');
1148
+        $targetUser
1149
+            ->expects($this->once())
1150
+            ->method('getHome')
1151
+            ->willReturn('/var/www/newtcloud/data/UID');
1152
+        $targetUser
1153
+            ->expects($this->exactly(2))
1154
+            ->method('getLastLogin')
1155
+            ->willReturn(1521191471);
1156
+        $targetUser
1157
+            ->expects($this->once())
1158
+            ->method('getFirstLogin')
1159
+            ->willReturn(1511191471);
1160
+        $targetUser
1161
+            ->expects($this->once())
1162
+            ->method('getBackendClassName')
1163
+            ->willReturn('Database');
1164
+        $targetUser
1165
+            ->expects($this->once())
1166
+            ->method('getBackend')
1167
+            ->willReturn($backend);
1168
+        $targetUser
1169
+            ->method('getUID')
1170
+            ->willReturn('UID');
1171
+
1172
+        $this->l10nFactory
1173
+            ->expects($this->once())
1174
+            ->method('getUserLanguage')
1175
+            ->with($targetUser)
1176
+            ->willReturn('de');
1177
+
1178
+        $expected = [
1179
+            'id' => 'UID',
1180
+            'enabled' => true,
1181
+            'storageLocation' => '/var/www/newtcloud/data/UID',
1182
+            'firstLoginTimestamp' => 1511191471,
1183
+            'lastLoginTimestamp' => 1521191471,
1184
+            'lastLogin' => 1521191471000,
1185
+            'backend' => 'Database',
1186
+            'subadmin' => ['group3'],
1187
+            'quota' => ['DummyValue'],
1188
+            'email' => '[email protected]',
1189
+            'displayname' => 'Demo User',
1190
+            'display-name' => 'Demo User',
1191
+            'phone' => 'phone',
1192
+            'address' => 'address',
1193
+            'website' => 'website',
1194
+            'twitter' => 'twitter',
1195
+            'fediverse' => 'fediverse',
1196
+            'groups' => ['group0', 'group1', 'group2'],
1197
+            'language' => 'de',
1198
+            'locale' => null,
1199
+            'backendCapabilities' => [
1200
+                'setDisplayName' => true,
1201
+                'setPassword' => true,
1202
+            ],
1203
+            'additional_mail' => [],
1204
+            'organisation' => 'organisation',
1205
+            'role' => 'role',
1206
+            'headline' => 'headline',
1207
+            'biography' => 'biography',
1208
+            'profile_enabled' => '1',
1209
+            'notify_email' => null,
1210
+            'manager' => '',
1211
+            'pronouns' => 'they/them',
1212
+        ];
1213
+        $this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
1214
+    }
1215
+
1216
+    public function testGetUserDataAsSubAdminAndUserIsAccessible(): void {
1217
+        $loggedInUser = $this->getMockBuilder(IUser::class)
1218
+            ->disableOriginalConstructor()
1219
+            ->getMock();
1220
+        $loggedInUser
1221
+            ->method('getUID')
1222
+            ->willReturn('subadmin');
1223
+        $targetUser = $this->getMockBuilder(IUser::class)
1224
+            ->disableOriginalConstructor()
1225
+            ->getMock();
1226
+        $targetUser
1227
+            ->expects($this->once())
1228
+            ->method('getSystemEMailAddress')
1229
+            ->willReturn('[email protected]');
1230
+        $this->userSession
1231
+            ->method('getUser')
1232
+            ->willReturn($loggedInUser);
1233
+        $this->userManager
1234
+            ->method('get')
1235
+            ->with('UID')
1236
+            ->willReturn($targetUser);
1237
+        $this->groupManager
1238
+            ->method('isAdmin')
1239
+            ->with('subadmin')
1240
+            ->willReturn(false);
1241
+        $this->groupManager
1242
+            ->expects($this->any())
1243
+            ->method('getUserGroups')
1244
+            ->willReturn([]);
1245
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
1246
+            ->disableOriginalConstructor()
1247
+            ->getMock();
1248
+        $subAdminManager
1249
+            ->expects($this->once())
1250
+            ->method('isUserAccessible')
1251
+            ->with($loggedInUser, $targetUser)
1252
+            ->willReturn(true);
1253
+        $subAdminManager
1254
+            ->expects($this->once())
1255
+            ->method('getSubAdminsGroups')
1256
+            ->willReturn([]);
1257
+        $this->groupManager
1258
+            ->expects($this->exactly(2))
1259
+            ->method('getSubAdmin')
1260
+            ->willReturn($subAdminManager);
1261
+        $this->config
1262
+            ->method('getUserValue')
1263
+            ->willReturnMap([
1264
+                ['UID', 'core', 'enabled', 'true', 'true'],
1265
+            ]);
1266
+        $this->api
1267
+            ->expects($this->once())
1268
+            ->method('fillStorageInfo')
1269
+            ->with($targetUser)
1270
+            ->willReturn(['DummyValue']);
1271
+
1272
+        $backend = $this->createMock(UserInterface::class);
1273
+        $backend->expects($this->any())
1274
+            ->method('implementsActions')
1275
+            ->willReturn(true);
1276
+
1277
+        $targetUser
1278
+            ->expects($this->once())
1279
+            ->method('getDisplayName')
1280
+            ->willReturn('Demo User');
1281
+        $targetUser
1282
+            ->expects($this->never())
1283
+            ->method('getHome');
1284
+        $targetUser
1285
+            ->expects($this->exactly(2))
1286
+            ->method('getLastLogin')
1287
+            ->willReturn(1521191471);
1288
+        $targetUser
1289
+            ->expects($this->once())
1290
+            ->method('getFirstLogin')
1291
+            ->willReturn(1511191471);
1292
+        $targetUser
1293
+            ->expects($this->once())
1294
+            ->method('getBackendClassName')
1295
+            ->willReturn('Database');
1296
+        $targetUser
1297
+            ->expects($this->once())
1298
+            ->method('getBackend')
1299
+            ->willReturn($backend);
1300
+        $targetUser
1301
+            ->method('getUID')
1302
+            ->willReturn('UID');
1303
+
1304
+        $this->mockAccount($targetUser, [
1305
+            IAccountManager::PROPERTY_ADDRESS => ['value' => 'address'],
1306
+            IAccountManager::PROPERTY_PHONE => ['value' => 'phone'],
1307
+            IAccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
1308
+            IAccountManager::PROPERTY_FEDIVERSE => ['value' => 'fediverse'],
1309
+            IAccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
1310
+            IAccountManager::PROPERTY_ORGANISATION => ['value' => 'organisation'],
1311
+            IAccountManager::PROPERTY_ROLE => ['value' => 'role'],
1312
+            IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
1313
+            IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
1314
+            IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
1315
+            IAccountManager::PROPERTY_PRONOUNS => ['value' => 'they/them'],
1316
+        ]);
1317
+
1318
+        $this->l10nFactory
1319
+            ->expects($this->once())
1320
+            ->method('getUserLanguage')
1321
+            ->with($targetUser)
1322
+            ->willReturn('da');
1323
+
1324
+        $expected = [
1325
+            'id' => 'UID',
1326
+            'enabled' => true,
1327
+            'firstLoginTimestamp' => 1511191471,
1328
+            'lastLoginTimestamp' => 1521191471,
1329
+            'lastLogin' => 1521191471000,
1330
+            'backend' => 'Database',
1331
+            'subadmin' => [],
1332
+            'quota' => ['DummyValue'],
1333
+            'email' => '[email protected]',
1334
+            'displayname' => 'Demo User',
1335
+            'display-name' => 'Demo User',
1336
+            'phone' => 'phone',
1337
+            'address' => 'address',
1338
+            'website' => 'website',
1339
+            'twitter' => 'twitter',
1340
+            'fediverse' => 'fediverse',
1341
+            'groups' => [],
1342
+            'language' => 'da',
1343
+            'locale' => null,
1344
+            'backendCapabilities' => [
1345
+                'setDisplayName' => true,
1346
+                'setPassword' => true,
1347
+            ],
1348
+            'additional_mail' => [],
1349
+            'organisation' => 'organisation',
1350
+            'role' => 'role',
1351
+            'headline' => 'headline',
1352
+            'biography' => 'biography',
1353
+            'profile_enabled' => '1',
1354
+            'notify_email' => null,
1355
+            'manager' => '',
1356
+            'pronouns' => 'they/them',
1357
+        ];
1358
+        $this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
1359
+    }
1360
+
1361
+
1362
+
1363
+    public function testGetUserDataAsSubAdminAndUserIsNotAccessible(): void {
1364
+        $this->expectException(OCSException::class);
1365
+        $this->expectExceptionCode(998);
1366
+
1367
+        $loggedInUser = $this->getMockBuilder(IUser::class)
1368
+            ->disableOriginalConstructor()
1369
+            ->getMock();
1370
+        $loggedInUser
1371
+            ->expects($this->exactly(4))
1372
+            ->method('getUID')
1373
+            ->willReturn('subadmin');
1374
+        $targetUser = $this->getMockBuilder(IUser::class)
1375
+            ->disableOriginalConstructor()
1376
+            ->getMock();
1377
+        $this->userSession
1378
+            ->method('getUser')
1379
+            ->willReturn($loggedInUser);
1380
+        $this->userManager
1381
+            ->expects($this->once())
1382
+            ->method('get')
1383
+            ->with('UserToGet')
1384
+            ->willReturn($targetUser);
1385
+        $this->groupManager
1386
+            ->expects($this->once())
1387
+            ->method('isAdmin')
1388
+            ->with('subadmin')
1389
+            ->willReturn(false);
1390
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
1391
+            ->disableOriginalConstructor()
1392
+            ->getMock();
1393
+        $subAdminManager
1394
+            ->expects($this->once())
1395
+            ->method('isUserAccessible')
1396
+            ->with($loggedInUser, $targetUser)
1397
+            ->willReturn(false);
1398
+        $this->groupManager
1399
+            ->expects($this->once())
1400
+            ->method('getSubAdmin')
1401
+            ->willReturn($subAdminManager);
1402
+
1403
+        $this->invokePrivate($this->api, 'getUser', ['UserToGet']);
1404
+    }
1405
+
1406
+    public function testGetUserDataAsSubAdminSelfLookup(): void {
1407
+        $loggedInUser = $this->getMockBuilder(IUser::class)
1408
+            ->disableOriginalConstructor()
1409
+            ->getMock();
1410
+        $loggedInUser
1411
+            ->method('getUID')
1412
+            ->willReturn('UID');
1413
+        $targetUser = $this->getMockBuilder(IUser::class)
1414
+            ->disableOriginalConstructor()
1415
+            ->getMock();
1416
+        $this->userSession
1417
+            ->method('getUser')
1418
+            ->willReturn($loggedInUser);
1419
+        $this->userManager
1420
+            ->method('get')
1421
+            ->with('UID')
1422
+            ->willReturn($targetUser);
1423
+        $this->groupManager
1424
+            ->method('isAdmin')
1425
+            ->with('UID')
1426
+            ->willReturn(false);
1427
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
1428
+            ->disableOriginalConstructor()
1429
+            ->getMock();
1430
+        $subAdminManager
1431
+            ->expects($this->once())
1432
+            ->method('isUserAccessible')
1433
+            ->with($loggedInUser, $targetUser)
1434
+            ->willReturn(false);
1435
+        $subAdminManager
1436
+            ->expects($this->once())
1437
+            ->method('getSubAdminsGroups')
1438
+            ->willReturn([]);
1439
+        $this->groupManager
1440
+            ->expects($this->exactly(2))
1441
+            ->method('getSubAdmin')
1442
+            ->willReturn($subAdminManager);
1443
+        $this->groupManager
1444
+            ->expects($this->any())
1445
+            ->method('getUserGroups')
1446
+            ->willReturn([]);
1447
+        $this->api
1448
+            ->expects($this->once())
1449
+            ->method('fillStorageInfo')
1450
+            ->with($targetUser)
1451
+            ->willReturn(['DummyValue']);
1452
+
1453
+        $backend = $this->createMock(UserInterface::class);
1454
+        $backend->expects($this->atLeastOnce())
1455
+            ->method('implementsActions')
1456
+            ->willReturn(false);
1457
+
1458
+        $targetUser
1459
+            ->expects($this->once())
1460
+            ->method('getDisplayName')
1461
+            ->willReturn('Subadmin User');
1462
+        $targetUser
1463
+            ->expects($this->once())
1464
+            ->method('getSystemEMailAddress')
1465
+            ->willReturn('[email protected]');
1466
+        $targetUser
1467
+            ->method('getUID')
1468
+            ->willReturn('UID');
1469
+        $targetUser
1470
+            ->expects($this->never())
1471
+            ->method('getHome');
1472
+        $targetUser
1473
+            ->expects($this->exactly(2))
1474
+            ->method('getLastLogin')
1475
+            ->willReturn(1521191471);
1476
+        $targetUser
1477
+            ->expects($this->once())
1478
+            ->method('getFirstLogin')
1479
+            ->willReturn(1511191471);
1480
+        $targetUser
1481
+            ->expects($this->once())
1482
+            ->method('getBackendClassName')
1483
+            ->willReturn('Database');
1484
+        $targetUser
1485
+            ->expects($this->once())
1486
+            ->method('getBackend')
1487
+            ->willReturn($backend);
1488
+        $this->mockAccount($targetUser, [
1489
+            IAccountManager::PROPERTY_ADDRESS => ['value' => 'address'],
1490
+            IAccountManager::PROPERTY_PHONE => ['value' => 'phone'],
1491
+            IAccountManager::PROPERTY_TWITTER => ['value' => 'twitter'],
1492
+            IAccountManager::PROPERTY_FEDIVERSE => ['value' => 'fediverse'],
1493
+            IAccountManager::PROPERTY_WEBSITE => ['value' => 'website'],
1494
+            IAccountManager::PROPERTY_ORGANISATION => ['value' => 'organisation'],
1495
+            IAccountManager::PROPERTY_ROLE => ['value' => 'role'],
1496
+            IAccountManager::PROPERTY_HEADLINE => ['value' => 'headline'],
1497
+            IAccountManager::PROPERTY_BIOGRAPHY => ['value' => 'biography'],
1498
+            IAccountManager::PROPERTY_PROFILE_ENABLED => ['value' => '1'],
1499
+            IAccountManager::PROPERTY_PRONOUNS => ['value' => 'they/them'],
1500
+        ]);
1501
+
1502
+        $this->l10nFactory
1503
+            ->expects($this->once())
1504
+            ->method('getUserLanguage')
1505
+            ->with($targetUser)
1506
+            ->willReturn('ru');
1507
+
1508
+        $expected = [
1509
+            'id' => 'UID',
1510
+            'firstLoginTimestamp' => 1511191471,
1511
+            'lastLoginTimestamp' => 1521191471,
1512
+            'lastLogin' => 1521191471000,
1513
+            'backend' => 'Database',
1514
+            'subadmin' => [],
1515
+            'quota' => ['DummyValue'],
1516
+            'email' => '[email protected]',
1517
+            'displayname' => 'Subadmin User',
1518
+            'display-name' => 'Subadmin User',
1519
+            'phone' => 'phone',
1520
+            'address' => 'address',
1521
+            'website' => 'website',
1522
+            'twitter' => 'twitter',
1523
+            'fediverse' => 'fediverse',
1524
+            'groups' => [],
1525
+            'language' => 'ru',
1526
+            'locale' => null,
1527
+            'backendCapabilities' => [
1528
+                'setDisplayName' => false,
1529
+                'setPassword' => false,
1530
+            ],
1531
+            'additional_mail' => [],
1532
+            'organisation' => 'organisation',
1533
+            'role' => 'role',
1534
+            'headline' => 'headline',
1535
+            'biography' => 'biography',
1536
+            'profile_enabled' => '1',
1537
+            'notify_email' => null,
1538
+            'manager' => '',
1539
+            'pronouns' => 'they/them',
1540
+        ];
1541
+        $this->assertEquals($expected, $this->invokePrivate($this->api, 'getUserData', ['UID']));
1542
+    }
1543
+
1544
+    public function dataSearchByPhoneNumbers(): array {
1545
+        return [
1546
+            'Invalid country' => ['Not a country code', ['12345' => ['NaN']], 400, null, null, []],
1547
+            'No number to search' => ['DE', ['12345' => ['NaN']], 200, null, null, []],
1548
+            'Valid number but no match' => ['DE', ['12345' => ['0711 / 25 24 28-90']], 200, ['+4971125242890'], [], []],
1549
+            'Invalid number' => ['FR', ['12345' => ['0711 / 25 24 28-90']], 200, null, null, []],
1550
+            'Invalid and valid number' => ['DE', ['12345' => ['NaN', '0711 / 25 24 28-90']], 200, ['+4971125242890'], [], []],
1551
+            'Valid and invalid number' => ['DE', ['12345' => ['0711 / 25 24 28-90', 'NaN']], 200, ['+4971125242890'], [], []],
1552
+            'Valid number and a match' => ['DE', ['12345' => ['0711 / 25 24 28-90']], 200, ['+4971125242890'], ['+4971125242890' => 'admin'], ['12345' => 'admin@localhost']],
1553
+            'Same number twice, later hits' => ['DE', ['12345' => ['0711 / 25 24 28-90'], '23456' => ['0711 / 25 24 28-90']], 200, ['+4971125242890'], ['+4971125242890' => 'admin'], ['23456' => 'admin@localhost']],
1554
+        ];
1555
+    }
1556
+
1557
+    /**
1558
+     * @dataProvider dataSearchByPhoneNumbers
1559
+     * @param string $location
1560
+     * @param array $search
1561
+     * @param int $status
1562
+     * @param array $expected
1563
+     */
1564
+    public function testSearchByPhoneNumbers(string $location, array $search, int $status, ?array $searchUsers, ?array $userMatches, array $expected): void {
1565
+        $knownTo = 'knownTo';
1566
+        $user = $this->createMock(IUser::class);
1567
+        $user->method('getUID')
1568
+            ->willReturn($knownTo);
1569
+        $this->userSession->method('getUser')
1570
+            ->willReturn($user);
1571
+
1572
+        if ($searchUsers === null) {
1573
+            $this->accountManager->expects($this->never())
1574
+                ->method('searchUsers');
1575
+        } else {
1576
+            $this->accountManager->expects($this->once())
1577
+                ->method('searchUsers')
1578
+                ->with(IAccountManager::PROPERTY_PHONE, $searchUsers)
1579
+                ->willReturn($userMatches);
1580
+
1581
+            $this->knownUserService->expects($this->once())
1582
+                ->method('deleteKnownTo')
1583
+                ->with($knownTo);
1584
+
1585
+            $this->knownUserService->expects($this->exactly(count($expected)))
1586
+                ->method('storeIsKnownToUser')
1587
+                ->with($knownTo, $this->anything());
1588
+        }
1589
+
1590
+        $this->urlGenerator->method('getAbsoluteURL')
1591
+            ->with('/')
1592
+            ->willReturn('https://localhost/');
1593
+
1594
+        $response = $this->api->searchByPhoneNumbers($location, $search);
1595
+
1596
+        self::assertEquals($status, $response->getStatus());
1597
+        self::assertEquals($expected, $response->getData());
1598
+    }
1599
+
1600
+    public function testEditUserRegularUserSelfEditChangeDisplayName(): void {
1601
+        $loggedInUser = $this->getMockBuilder(IUser::class)
1602
+            ->disableOriginalConstructor()
1603
+            ->getMock();
1604
+        $loggedInUser
1605
+            ->expects($this->any())
1606
+            ->method('getUID')
1607
+            ->willReturn('UID');
1608
+        $targetUser = $this->getMockBuilder(IUser::class)
1609
+            ->disableOriginalConstructor()
1610
+            ->getMock();
1611
+        $this->userSession
1612
+            ->expects($this->once())
1613
+            ->method('getUser')
1614
+            ->willReturn($loggedInUser);
1615
+        $this->userManager
1616
+            ->expects($this->once())
1617
+            ->method('get')
1618
+            ->with('UserToEdit')
1619
+            ->willReturn($targetUser);
1620
+        $targetUser
1621
+            ->expects($this->once())
1622
+            ->method('getBackend')
1623
+            ->willReturn($this->createMock(ISetDisplayNameBackend::class));
1624
+        $targetUser
1625
+            ->expects($this->once())
1626
+            ->method('setDisplayName')
1627
+            ->with('NewDisplayName')
1628
+            ->willReturn(true);
1629
+        $targetUser
1630
+            ->expects($this->any())
1631
+            ->method('getUID')
1632
+            ->willReturn('UID');
1633
+
1634
+        $this->assertEquals([], $this->api->editUser('UserToEdit', 'display', 'NewDisplayName')->getData());
1635
+    }
1636
+
1637
+    public function testEditUserRegularUserSelfEditChangeEmailValid(): void {
1638
+        $loggedInUser = $this->getMockBuilder(IUser::class)
1639
+            ->disableOriginalConstructor()
1640
+            ->getMock();
1641
+        $loggedInUser
1642
+            ->expects($this->any())
1643
+            ->method('getUID')
1644
+            ->willReturn('UID');
1645
+        $targetUser = $this->getMockBuilder(IUser::class)
1646
+            ->disableOriginalConstructor()
1647
+            ->getMock();
1648
+        $this->userSession
1649
+            ->expects($this->once())
1650
+            ->method('getUser')
1651
+            ->willReturn($loggedInUser);
1652
+        $this->userManager
1653
+            ->expects($this->once())
1654
+            ->method('get')
1655
+            ->with('UserToEdit')
1656
+            ->willReturn($targetUser);
1657
+        $targetUser
1658
+            ->expects($this->once())
1659
+            ->method('setEMailAddress')
1660
+            ->with('[email protected]');
1661
+        $targetUser
1662
+            ->expects($this->any())
1663
+            ->method('getUID')
1664
+            ->willReturn('UID');
1665
+
1666
+        $backend = $this->createMock(UserInterface::class);
1667
+        $targetUser
1668
+            ->expects($this->any())
1669
+            ->method('getBackend')
1670
+            ->willReturn($backend);
1671
+
1672
+        $this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => $default);
1673
+
1674
+        $this->assertEquals([], $this->api->editUser('UserToEdit', 'email', '[email protected]')->getData());
1675
+    }
1676
+
1677
+    public function testEditUserRegularUserSelfEditAddAdditionalEmailValid(): void {
1678
+        $loggedInUser = $this->getMockBuilder(IUser::class)
1679
+            ->disableOriginalConstructor()
1680
+            ->getMock();
1681
+        $loggedInUser
1682
+            ->expects($this->any())
1683
+            ->method('getUID')
1684
+            ->willReturn('UID');
1685
+        $targetUser = $this->getMockBuilder(IUser::class)
1686
+            ->disableOriginalConstructor()
1687
+            ->getMock();
1688
+        $this->userSession
1689
+            ->expects($this->once())
1690
+            ->method('getUser')
1691
+            ->willReturn($loggedInUser);
1692
+        $this->userManager
1693
+            ->expects($this->once())
1694
+            ->method('get')
1695
+            ->with('UserToEdit')
1696
+            ->willReturn($targetUser);
1697
+        $targetUser
1698
+            ->expects($this->any())
1699
+            ->method('getUID')
1700
+            ->willReturn('UID');
1701
+
1702
+        $backend = $this->createMock(UserInterface::class);
1703
+        $targetUser
1704
+            ->expects($this->any())
1705
+            ->method('getBackend')
1706
+            ->willReturn($backend);
1707
+
1708
+        $userAccount = $this->createMock(IAccount::class);
1709
+
1710
+        $this->accountManager
1711
+            ->expects($this->once())
1712
+            ->method('getAccount')
1713
+            ->with($targetUser)
1714
+            ->willReturn($userAccount);
1715
+        $this->accountManager
1716
+            ->expects($this->once())
1717
+            ->method('updateAccount')
1718
+            ->with($userAccount);
1719
+
1720
+        $this->assertEquals([], $this->api->editUser('UserToEdit', 'additional_mail', '[email protected]')->getData());
1721
+    }
1722
+
1723
+    public function testEditUserRegularUserSelfEditAddAdditionalEmailMainAddress(): void {
1724
+        $loggedInUser = $this->getMockBuilder(IUser::class)
1725
+            ->disableOriginalConstructor()
1726
+            ->getMock();
1727
+        $loggedInUser
1728
+            ->expects($this->any())
1729
+            ->method('getUID')
1730
+            ->willReturn('UID');
1731
+        $targetUser = $this->getMockBuilder(IUser::class)
1732
+            ->disableOriginalConstructor()
1733
+            ->getMock();
1734
+        $this->userSession
1735
+            ->expects($this->once())
1736
+            ->method('getUser')
1737
+            ->willReturn($loggedInUser);
1738
+        $this->userManager
1739
+            ->expects($this->once())
1740
+            ->method('get')
1741
+            ->with('UserToEdit')
1742
+            ->willReturn($targetUser);
1743
+        $targetUser
1744
+            ->expects($this->any())
1745
+            ->method('getUID')
1746
+            ->willReturn('UID');
1747
+
1748
+        $backend = $this->createMock(UserInterface::class);
1749
+        $targetUser
1750
+            ->expects($this->any())
1751
+            ->method('getBackend')
1752
+            ->willReturn($backend);
1753
+        $targetUser
1754
+            ->expects($this->any())
1755
+            ->method('getSystemEMailAddress')
1756
+            ->willReturn('[email protected]');
1757
+
1758
+        $userAccount = $this->createMock(IAccount::class);
1759
+
1760
+        $this->accountManager
1761
+            ->expects($this->never())
1762
+            ->method('getAccount')
1763
+            ->with($targetUser)
1764
+            ->willReturn($userAccount);
1765
+        $this->accountManager
1766
+            ->expects($this->never())
1767
+            ->method('updateAccount')
1768
+            ->with($userAccount);
1769
+
1770
+        $this->expectException(OCSException::class);
1771
+        $this->expectExceptionCode(101);
1772
+        $this->api->editUser('UserToEdit', 'additional_mail', '[email protected]')->getData();
1773
+    }
1774
+
1775
+    public function testEditUserRegularUserSelfEditAddAdditionalEmailDuplicate(): void {
1776
+        $loggedInUser = $this->getMockBuilder(IUser::class)
1777
+            ->disableOriginalConstructor()
1778
+            ->getMock();
1779
+        $loggedInUser
1780
+            ->expects($this->any())
1781
+            ->method('getUID')
1782
+            ->willReturn('UID');
1783
+        $targetUser = $this->getMockBuilder(IUser::class)
1784
+            ->disableOriginalConstructor()
1785
+            ->getMock();
1786
+        $this->userSession
1787
+            ->expects($this->once())
1788
+            ->method('getUser')
1789
+            ->willReturn($loggedInUser);
1790
+        $this->userManager
1791
+            ->expects($this->once())
1792
+            ->method('get')
1793
+            ->with('UserToEdit')
1794
+            ->willReturn($targetUser);
1795
+        $targetUser
1796
+            ->expects($this->any())
1797
+            ->method('getUID')
1798
+            ->willReturn('UID');
1799
+
1800
+        $backend = $this->createMock(UserInterface::class);
1801
+        $targetUser
1802
+            ->expects($this->any())
1803
+            ->method('getBackend')
1804
+            ->willReturn($backend);
1805
+
1806
+        $property = $this->createMock(IAccountProperty::class);
1807
+        $property->method('getValue')
1808
+            ->willReturn('[email protected]');
1809
+        $collection = $this->createMock(IAccountPropertyCollection::class);
1810
+        $collection->method('getPropertyByValue')
1811
+            ->with('[email protected]')
1812
+            ->willReturn($property);
1813
+
1814
+        $userAccount = $this->createMock(IAccount::class);
1815
+        $userAccount->method('getPropertyCollection')
1816
+            ->with(IAccountManager::COLLECTION_EMAIL)
1817
+            ->willReturn($collection);
1818
+
1819
+        $this->accountManager
1820
+            ->expects($this->once())
1821
+            ->method('getAccount')
1822
+            ->with($targetUser)
1823
+            ->willReturn($userAccount);
1824
+        $this->accountManager
1825
+            ->expects($this->never())
1826
+            ->method('updateAccount')
1827
+            ->with($userAccount);
1828
+
1829
+        $this->expectException(OCSException::class);
1830
+        $this->expectExceptionCode(101);
1831
+        $this->api->editUser('UserToEdit', 'additional_mail', '[email protected]')->getData();
1832
+    }
1833
+
1834
+    public function testEditUserRegularUserSelfEditChangeEmailInvalid(): void {
1835
+        $this->expectException(OCSException::class);
1836
+        $this->expectExceptionCode(101);
1837
+
1838
+        $loggedInUser = $this->getMockBuilder(IUser::class)
1839
+            ->disableOriginalConstructor()
1840
+            ->getMock();
1841
+        $loggedInUser
1842
+            ->expects($this->any())
1843
+            ->method('getUID')
1844
+            ->willReturn('UID');
1845
+        $targetUser = $this->getMockBuilder(IUser::class)
1846
+            ->disableOriginalConstructor()
1847
+            ->getMock();
1848
+        $this->userSession
1849
+            ->expects($this->once())
1850
+            ->method('getUser')
1851
+            ->willReturn($loggedInUser);
1852
+        $this->userManager
1853
+            ->expects($this->once())
1854
+            ->method('get')
1855
+            ->with('UserToEdit')
1856
+            ->willReturn($targetUser);
1857
+        $targetUser
1858
+            ->expects($this->any())
1859
+            ->method('getUID')
1860
+            ->willReturn('UID');
1861
+
1862
+        $backend = $this->createMock(UserInterface::class);
1863
+        $targetUser
1864
+            ->expects($this->any())
1865
+            ->method('getBackend')
1866
+            ->willReturn($backend);
1867
+
1868
+        $this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => $default);
1869
+
1870
+        $this->api->editUser('UserToEdit', 'email', 'demo.org');
1871
+    }
1872
+
1873
+    public function selfEditChangePropertyProvider() {
1874
+        return [
1875
+            [IAccountManager::PROPERTY_TWITTER, '@oldtwitter', '@newtwitter'],
1876
+            [IAccountManager::PROPERTY_FEDIVERSE, '@[email protected]', '@[email protected]'],
1877
+            [IAccountManager::PROPERTY_PHONE, '1234', '12345'],
1878
+            [IAccountManager::PROPERTY_ADDRESS, 'Something street 2', 'Another street 3'],
1879
+            [IAccountManager::PROPERTY_WEBSITE, 'https://examplesite1', 'https://examplesite2'],
1880
+            [IAccountManager::PROPERTY_ORGANISATION, 'Organisation A', 'Organisation B'],
1881
+            [IAccountManager::PROPERTY_ROLE, 'Human', 'Alien'],
1882
+            [IAccountManager::PROPERTY_HEADLINE, 'Hi', 'Hello'],
1883
+            [IAccountManager::PROPERTY_BIOGRAPHY, 'A biography', 'Another biography'],
1884
+            [IAccountManager::PROPERTY_PROFILE_ENABLED, '1', '0'],
1885
+            [IAccountManager::PROPERTY_PRONOUNS, 'they/them', 'he/him'],
1886
+        ];
1887
+    }
1888
+
1889
+    /**
1890
+     * @dataProvider selfEditChangePropertyProvider
1891
+     */
1892
+    public function testEditUserRegularUserSelfEditChangeProperty($propertyName, $oldValue, $newValue): void {
1893
+        $loggedInUser = $this->getMockBuilder(IUser::class)
1894
+            ->disableOriginalConstructor()
1895
+            ->getMock();
1896
+        $loggedInUser
1897
+            ->expects($this->any())
1898
+            ->method('getUID')
1899
+            ->willReturn('UID');
1900
+        $this->userSession
1901
+            ->expects($this->once())
1902
+            ->method('getUser')
1903
+            ->willReturn($loggedInUser);
1904
+        $this->userManager
1905
+            ->expects($this->once())
1906
+            ->method('get')
1907
+            ->with('UserToEdit')
1908
+            ->willReturn($loggedInUser);
1909
+
1910
+        $backend = $this->createMock(UserInterface::class);
1911
+        $loggedInUser
1912
+            ->expects($this->any())
1913
+            ->method('getBackend')
1914
+            ->willReturn($backend);
1915
+
1916
+        $propertyMock = $this->createMock(IAccountProperty::class);
1917
+        $propertyMock->expects($this->any())
1918
+            ->method('getName')
1919
+            ->willReturn($propertyName);
1920
+        $propertyMock->expects($this->any())
1921
+            ->method('getValue')
1922
+            ->willReturn($oldValue);
1923
+        $propertyMock->expects($this->once())
1924
+            ->method('setValue')
1925
+            ->with($newValue)
1926
+            ->willReturnSelf();
1927
+        $propertyMock->expects($this->any())
1928
+            ->method('getScope')
1929
+            ->willReturn(IAccountManager::SCOPE_LOCAL);
1930
+
1931
+        $accountMock = $this->createMock(IAccount::class);
1932
+        $accountMock->expects($this->any())
1933
+            ->method('getProperty')
1934
+            ->with($propertyName)
1935
+            ->willReturn($propertyMock);
1936
+
1937
+        $this->accountManager->expects($this->atLeastOnce())
1938
+            ->method('getAccount')
1939
+            ->with($loggedInUser)
1940
+            ->willReturn($accountMock);
1941
+        $this->accountManager->expects($this->once())
1942
+            ->method('updateAccount')
1943
+            ->with($accountMock);
1944
+
1945
+        $this->assertEquals([], $this->api->editUser('UserToEdit', $propertyName, $newValue)->getData());
1946
+    }
1947
+
1948
+    public function selfEditChangePropertyScopeProvider() {
1949
+        return [
1950
+            [IAccountManager::PROPERTY_AVATAR, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1951
+            [IAccountManager::PROPERTY_DISPLAYNAME, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1952
+            [IAccountManager::PROPERTY_EMAIL, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1953
+            [IAccountManager::PROPERTY_TWITTER, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1954
+            [IAccountManager::PROPERTY_FEDIVERSE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1955
+            [IAccountManager::PROPERTY_PHONE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1956
+            [IAccountManager::PROPERTY_ADDRESS, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1957
+            [IAccountManager::PROPERTY_WEBSITE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1958
+            [IAccountManager::PROPERTY_ORGANISATION, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1959
+            [IAccountManager::PROPERTY_ROLE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1960
+            [IAccountManager::PROPERTY_HEADLINE, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1961
+            [IAccountManager::PROPERTY_BIOGRAPHY, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1962
+            [IAccountManager::PROPERTY_PROFILE_ENABLED, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1963
+            [IAccountManager::PROPERTY_PRONOUNS, IAccountManager::SCOPE_LOCAL, IAccountManager::SCOPE_FEDERATED],
1964
+        ];
1965
+    }
1966
+
1967
+    /**
1968
+     * @dataProvider selfEditChangePropertyProvider
1969
+     */
1970
+    public function testEditUserRegularUserSelfEditChangePropertyScope($propertyName, $oldScope, $newScope): void {
1971
+        $loggedInUser = $this->getMockBuilder(IUser::class)
1972
+            ->disableOriginalConstructor()
1973
+            ->getMock();
1974
+        $loggedInUser
1975
+            ->expects($this->any())
1976
+            ->method('getUID')
1977
+            ->willReturn('UID');
1978
+        $this->userSession
1979
+            ->expects($this->once())
1980
+            ->method('getUser')
1981
+            ->willReturn($loggedInUser);
1982
+        $this->userManager
1983
+            ->expects($this->once())
1984
+            ->method('get')
1985
+            ->with('UserToEdit')
1986
+            ->willReturn($loggedInUser);
1987
+
1988
+        $backend = $this->createMock(UserInterface::class);
1989
+        $loggedInUser
1990
+            ->expects($this->any())
1991
+            ->method('getBackend')
1992
+            ->willReturn($backend);
1993
+
1994
+        $propertyMock = $this->createMock(IAccountProperty::class);
1995
+        $propertyMock->expects($this->any())
1996
+            ->method('getName')
1997
+            ->willReturn($propertyName);
1998
+        $propertyMock->expects($this->any())
1999
+            ->method('getValue')
2000
+            ->willReturn('somevalue');
2001
+        $propertyMock->expects($this->any())
2002
+            ->method('getScope')
2003
+            ->willReturn($oldScope);
2004
+        $propertyMock->expects($this->atLeastOnce())
2005
+            ->method('setScope')
2006
+            ->with($newScope)
2007
+            ->willReturnSelf();
2008
+
2009
+        $accountMock = $this->createMock(IAccount::class);
2010
+        $accountMock->expects($this->any())
2011
+            ->method('getProperty')
2012
+            ->with($propertyName)
2013
+            ->willReturn($propertyMock);
2014
+
2015
+        $this->accountManager->expects($this->atLeastOnce())
2016
+            ->method('getAccount')
2017
+            ->with($loggedInUser)
2018
+            ->willReturn($accountMock);
2019
+        $this->accountManager->expects($this->once())
2020
+            ->method('updateAccount')
2021
+            ->with($accountMock);
2022
+
2023
+        $this->assertEquals([], $this->api->editUser('UserToEdit', $propertyName . 'Scope', $newScope)->getData());
2024
+    }
2025
+
2026
+    public function testEditUserRegularUserSelfEditChangePassword(): void {
2027
+        $loggedInUser = $this->getMockBuilder(IUser::class)
2028
+            ->disableOriginalConstructor()
2029
+            ->getMock();
2030
+        $loggedInUser
2031
+            ->expects($this->any())
2032
+            ->method('getUID')
2033
+            ->willReturn('UID');
2034
+        $targetUser = $this->getMockBuilder(IUser::class)
2035
+            ->disableOriginalConstructor()
2036
+            ->getMock();
2037
+        $this->userSession
2038
+            ->expects($this->once())
2039
+            ->method('getUser')
2040
+            ->willReturn($loggedInUser);
2041
+        $this->userManager
2042
+            ->expects($this->once())
2043
+            ->method('get')
2044
+            ->with('UserToEdit')
2045
+            ->willReturn($targetUser);
2046
+        $targetUser
2047
+            ->expects($this->once())
2048
+            ->method('canChangePassword')
2049
+            ->willReturn(true);
2050
+        $targetUser
2051
+            ->expects($this->once())
2052
+            ->method('setPassword')
2053
+            ->with('NewPassword');
2054
+        $targetUser
2055
+            ->expects($this->any())
2056
+            ->method('getUID')
2057
+            ->willReturn('UID');
2058
+
2059
+        $backend = $this->createMock(UserInterface::class);
2060
+        $targetUser
2061
+            ->expects($this->any())
2062
+            ->method('getBackend')
2063
+            ->willReturn($backend);
2064
+
2065
+        $this->assertEquals([], $this->api->editUser('UserToEdit', 'password', 'NewPassword')->getData());
2066
+    }
2067
+
2068
+
2069
+
2070
+    public function testEditUserRegularUserSelfEditChangeQuota(): void {
2071
+        $this->expectException(OCSException::class);
2072
+        $this->expectExceptionCode(113);
2073
+
2074
+        $loggedInUser = $this->getMockBuilder(IUser::class)
2075
+            ->disableOriginalConstructor()
2076
+            ->getMock();
2077
+        $loggedInUser
2078
+            ->expects($this->any())
2079
+            ->method('getUID')
2080
+            ->willReturn('UID');
2081
+        $targetUser = $this->getMockBuilder(IUser::class)
2082
+            ->disableOriginalConstructor()
2083
+            ->getMock();
2084
+        $this->userSession
2085
+            ->expects($this->once())
2086
+            ->method('getUser')
2087
+            ->willReturn($loggedInUser);
2088
+        $this->userManager
2089
+            ->expects($this->once())
2090
+            ->method('get')
2091
+            ->with('UserToEdit')
2092
+            ->willReturn($targetUser);
2093
+        $targetUser
2094
+            ->expects($this->any())
2095
+            ->method('getUID')
2096
+            ->willReturn('UID');
2097
+
2098
+        $backend = $this->createMock(UserInterface::class);
2099
+        $targetUser
2100
+            ->expects($this->any())
2101
+            ->method('getBackend')
2102
+            ->willReturn($backend);
2103
+
2104
+        $this->api->editUser('UserToEdit', 'quota', 'NewQuota');
2105
+    }
2106
+
2107
+    public function testEditUserAdminUserSelfEditChangeValidQuota(): void {
2108
+        $this->config
2109
+            ->expects($this->once())
2110
+            ->method('getAppValue')
2111
+            ->willReturnCallback(function ($appid, $key, $default) {
2112
+                if ($key === 'max_quota') {
2113
+                    return '-1';
2114
+                }
2115
+                return null;
2116
+            });
2117
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2118
+        $loggedInUser
2119
+            ->expects($this->any())
2120
+            ->method('getUID')
2121
+            ->willReturn('UID');
2122
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2123
+        $targetUser->expects($this->once())
2124
+            ->method('setQuota')
2125
+            ->with('2.9 MB');
2126
+        $this->userSession
2127
+            ->expects($this->once())
2128
+            ->method('getUser')
2129
+            ->willReturn($loggedInUser);
2130
+        $this->userManager
2131
+            ->expects($this->once())
2132
+            ->method('get')
2133
+            ->with('UserToEdit')
2134
+            ->willReturn($targetUser);
2135
+        $this->groupManager
2136
+            ->expects($this->exactly(3))
2137
+            ->method('isAdmin')
2138
+            ->with('UID')
2139
+            ->willReturn(true);
2140
+        $targetUser
2141
+            ->expects($this->any())
2142
+            ->method('getUID')
2143
+            ->willReturn('UID');
2144
+
2145
+        $backend = $this->createMock(UserInterface::class);
2146
+        $targetUser
2147
+            ->expects($this->any())
2148
+            ->method('getBackend')
2149
+            ->willReturn($backend);
2150
+
2151
+        $this->assertEquals([], $this->api->editUser('UserToEdit', 'quota', '3042824')->getData());
2152
+    }
2153
+
2154
+
2155
+
2156
+    public function testEditUserAdminUserSelfEditChangeInvalidQuota(): void {
2157
+        $this->expectException(OCSException::class);
2158
+        $this->expectExceptionMessage('Invalid quota value: ABC');
2159
+        $this->expectExceptionCode(101);
2160
+
2161
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2162
+        $loggedInUser
2163
+            ->expects($this->any())
2164
+            ->method('getUID')
2165
+            ->willReturn('UID');
2166
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2167
+        $this->userSession
2168
+            ->expects($this->once())
2169
+            ->method('getUser')
2170
+            ->willReturn($loggedInUser);
2171
+        $this->userManager
2172
+            ->expects($this->once())
2173
+            ->method('get')
2174
+            ->with('UserToEdit')
2175
+            ->willReturn($targetUser);
2176
+        $this->groupManager
2177
+            ->expects($this->exactly(3))
2178
+            ->method('isAdmin')
2179
+            ->with('UID')
2180
+            ->willReturn(true);
2181
+        $targetUser
2182
+            ->expects($this->any())
2183
+            ->method('getUID')
2184
+            ->willReturn('UID');
2185
+
2186
+        $backend = $this->createMock(UserInterface::class);
2187
+        $targetUser
2188
+            ->expects($this->any())
2189
+            ->method('getBackend')
2190
+            ->willReturn($backend);
2191
+
2192
+        $this->api->editUser('UserToEdit', 'quota', 'ABC');
2193
+    }
2194
+
2195
+    public function testEditUserAdminUserEditChangeValidQuota(): void {
2196
+        $this->config
2197
+            ->expects($this->once())
2198
+            ->method('getAppValue')
2199
+            ->willReturnCallback(function ($appid, $key, $default) {
2200
+                if ($key === 'max_quota') {
2201
+                    return '-1';
2202
+                }
2203
+                return null;
2204
+            });
2205
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2206
+        $loggedInUser
2207
+            ->expects($this->any())
2208
+            ->method('getUID')
2209
+            ->willReturn('admin');
2210
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2211
+        $targetUser->expects($this->once())
2212
+            ->method('setQuota')
2213
+            ->with('2.9 MB');
2214
+        $this->userSession
2215
+            ->expects($this->once())
2216
+            ->method('getUser')
2217
+            ->willReturn($loggedInUser);
2218
+        $this->userManager
2219
+            ->expects($this->once())
2220
+            ->method('get')
2221
+            ->with('UserToEdit')
2222
+            ->willReturn($targetUser);
2223
+        $this->groupManager
2224
+            ->expects($this->once())
2225
+            ->method('isAdmin')
2226
+            ->with('admin')
2227
+            ->willReturn(true);
2228
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2229
+            ->disableOriginalConstructor()
2230
+            ->getMock();
2231
+        $this->groupManager
2232
+            ->expects($this->once())
2233
+            ->method('getSubAdmin')
2234
+            ->willReturn($subAdminManager);
2235
+        $targetUser
2236
+            ->expects($this->any())
2237
+            ->method('getUID')
2238
+            ->willReturn('UID');
2239
+
2240
+        $backend = $this->createMock(UserInterface::class);
2241
+        $targetUser
2242
+            ->expects($this->any())
2243
+            ->method('getBackend')
2244
+            ->willReturn($backend);
2245
+
2246
+        $this->assertEquals([], $this->api->editUser('UserToEdit', 'quota', '3042824')->getData());
2247
+    }
2248
+
2249
+    public function testEditUserSelfEditChangeLanguage(): void {
2250
+        $this->l10nFactory->expects($this->once())
2251
+            ->method('findAvailableLanguages')
2252
+            ->willReturn(['en', 'de', 'sv']);
2253
+        $this->config->expects($this->any())
2254
+            ->method('getSystemValue')
2255
+            ->willReturnMap([
2256
+                ['allow_user_to_change_display_name', true, true],
2257
+                ['force_language', false, false],
2258
+            ]);
2259
+
2260
+        $loggedInUser = $this->createMock(IUser::class);
2261
+        $loggedInUser
2262
+            ->expects($this->any())
2263
+            ->method('getUID')
2264
+            ->willReturn('UserToEdit');
2265
+        $targetUser = $this->createMock(IUser::class);
2266
+        $this->config->expects($this->once())
2267
+            ->method('setUserValue')
2268
+            ->with('UserToEdit', 'core', 'lang', 'de');
2269
+        $this->userSession
2270
+            ->expects($this->once())
2271
+            ->method('getUser')
2272
+            ->willReturn($loggedInUser);
2273
+        $this->userManager
2274
+            ->expects($this->once())
2275
+            ->method('get')
2276
+            ->with('UserToEdit')
2277
+            ->willReturn($targetUser);
2278
+        $this->groupManager
2279
+            ->expects($this->atLeastOnce())
2280
+            ->method('isAdmin')
2281
+            ->with('UserToEdit')
2282
+            ->willReturn(false);
2283
+        $targetUser
2284
+            ->expects($this->any())
2285
+            ->method('getUID')
2286
+            ->willReturn('UserToEdit');
2287
+
2288
+        $backend = $this->createMock(UserInterface::class);
2289
+        $targetUser
2290
+            ->expects($this->any())
2291
+            ->method('getBackend')
2292
+            ->willReturn($backend);
2293
+
2294
+        $this->assertEquals([], $this->api->editUser('UserToEdit', 'language', 'de')->getData());
2295
+    }
2296
+
2297
+    public function dataEditUserSelfEditChangeLanguageButForced() {
2298
+        return [
2299
+            ['de'],
2300
+            [true],
2301
+        ];
2302
+    }
2303
+
2304
+    /**
2305
+     * @dataProvider dataEditUserSelfEditChangeLanguageButForced
2306
+     */
2307
+    public function testEditUserSelfEditChangeLanguageButForced($forced): void {
2308
+        $this->expectException(OCSException::class);
2309
+
2310
+        $this->config->expects($this->any())
2311
+            ->method('getSystemValue')
2312
+            ->willReturnMap([
2313
+                ['allow_user_to_change_display_name', true, true],
2314
+                ['force_language', false, $forced],
2315
+            ]);
2316
+
2317
+        $loggedInUser = $this->createMock(IUser::class);
2318
+        $loggedInUser
2319
+            ->expects($this->any())
2320
+            ->method('getUID')
2321
+            ->willReturn('UserToEdit');
2322
+        $targetUser = $this->createMock(IUser::class);
2323
+        $this->config->expects($this->never())
2324
+            ->method('setUserValue');
2325
+        $this->userSession
2326
+            ->expects($this->once())
2327
+            ->method('getUser')
2328
+            ->willReturn($loggedInUser);
2329
+        $this->userManager
2330
+            ->expects($this->once())
2331
+            ->method('get')
2332
+            ->with('UserToEdit')
2333
+            ->willReturn($targetUser);
2334
+        $this->groupManager
2335
+            ->expects($this->atLeastOnce())
2336
+            ->method('isAdmin')
2337
+            ->with('UserToEdit')
2338
+            ->willReturn(false);
2339
+        $targetUser
2340
+            ->expects($this->any())
2341
+            ->method('getUID')
2342
+            ->willReturn('UserToEdit');
2343
+
2344
+        $backend = $this->createMock(UserInterface::class);
2345
+        $targetUser
2346
+            ->expects($this->any())
2347
+            ->method('getBackend')
2348
+            ->willReturn($backend);
2349
+
2350
+        $this->assertEquals([], $this->api->editUser('UserToEdit', 'language', 'de')->getData());
2351
+    }
2352
+
2353
+    public function testEditUserAdminEditChangeLanguage(): void {
2354
+        $this->l10nFactory->expects($this->once())
2355
+            ->method('findAvailableLanguages')
2356
+            ->willReturn(['en', 'de', 'sv']);
2357
+
2358
+        $loggedInUser = $this->createMock(IUser::class);
2359
+        $loggedInUser
2360
+            ->expects($this->any())
2361
+            ->method('getUID')
2362
+            ->willReturn('admin');
2363
+        $targetUser = $this->createMock(IUser::class);
2364
+        $this->config->expects($this->once())
2365
+            ->method('setUserValue')
2366
+            ->with('UserToEdit', 'core', 'lang', 'de');
2367
+        $this->userSession
2368
+            ->expects($this->once())
2369
+            ->method('getUser')
2370
+            ->willReturn($loggedInUser);
2371
+        $this->userManager
2372
+            ->expects($this->once())
2373
+            ->method('get')
2374
+            ->with('UserToEdit')
2375
+            ->willReturn($targetUser);
2376
+        $this->groupManager
2377
+            ->expects($this->once())
2378
+            ->method('isAdmin')
2379
+            ->with('admin')
2380
+            ->willReturn(true);
2381
+        $subAdminManager = $this->createMock(SubAdmin::class);
2382
+        $this->groupManager
2383
+            ->expects($this->once())
2384
+            ->method('getSubAdmin')
2385
+            ->willReturn($subAdminManager);
2386
+        $targetUser
2387
+            ->expects($this->any())
2388
+            ->method('getUID')
2389
+            ->willReturn('UserToEdit');
2390
+
2391
+        $backend = $this->createMock(UserInterface::class);
2392
+        $targetUser
2393
+            ->expects($this->any())
2394
+            ->method('getBackend')
2395
+            ->willReturn($backend);
2396
+
2397
+        $this->assertEquals([], $this->api->editUser('UserToEdit', 'language', 'de')->getData());
2398
+    }
2399
+
2400
+    /**
2401
+     * @dataProvider dataEditUserSelfEditChangeLanguageButForced
2402
+     */
2403
+    public function testEditUserAdminEditChangeLanguageInvalidLanguage(): void {
2404
+        $this->expectException(OCSException::class);
2405
+
2406
+
2407
+        $this->l10nFactory->expects($this->once())
2408
+            ->method('findAvailableLanguages')
2409
+            ->willReturn(['en', 'de', 'sv']);
2410
+
2411
+        $loggedInUser = $this->createMock(IUser::class);
2412
+        $loggedInUser
2413
+            ->expects($this->any())
2414
+            ->method('getUID')
2415
+            ->willReturn('admin');
2416
+        $targetUser = $this->createMock(IUser::class);
2417
+        $this->config->expects($this->never())
2418
+            ->method('setUserValue');
2419
+        $this->userSession
2420
+            ->expects($this->once())
2421
+            ->method('getUser')
2422
+            ->willReturn($loggedInUser);
2423
+        $this->userManager
2424
+            ->expects($this->once())
2425
+            ->method('get')
2426
+            ->with('UserToEdit')
2427
+            ->willReturn($targetUser);
2428
+        $this->groupManager
2429
+            ->expects($this->once())
2430
+            ->method('isAdmin')
2431
+            ->with('admin')
2432
+            ->willReturn(true);
2433
+        $subAdminManager = $this->createMock(SubAdmin::class);
2434
+        $this->groupManager
2435
+            ->expects($this->once())
2436
+            ->method('getSubAdmin')
2437
+            ->willReturn($subAdminManager);
2438
+        $targetUser
2439
+            ->expects($this->any())
2440
+            ->method('getUID')
2441
+            ->willReturn('UserToEdit');
2442
+
2443
+        $backend = $this->createMock(UserInterface::class);
2444
+        $targetUser
2445
+            ->expects($this->any())
2446
+            ->method('getBackend')
2447
+            ->willReturn($backend);
2448
+
2449
+        $this->assertEquals([], $this->api->editUser('UserToEdit', 'language', 'ru')->getData());
2450
+    }
2451
+
2452
+    public function testEditUserSubadminUserAccessible(): void {
2453
+        $this->config
2454
+            ->expects($this->once())
2455
+            ->method('getAppValue')
2456
+            ->willReturnCallback(function ($appid, $key, $default) {
2457
+                if ($key === 'max_quota') {
2458
+                    return '-1';
2459
+                }
2460
+                return null;
2461
+            });
2462
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2463
+        $loggedInUser
2464
+            ->expects($this->any())
2465
+            ->method('getUID')
2466
+            ->willReturn('subadmin');
2467
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2468
+        $targetUser->expects($this->once())
2469
+            ->method('setQuota')
2470
+            ->with('2.9 MB');
2471
+        $this->userSession
2472
+            ->expects($this->once())
2473
+            ->method('getUser')
2474
+            ->willReturn($loggedInUser);
2475
+        $this->userManager
2476
+            ->expects($this->once())
2477
+            ->method('get')
2478
+            ->with('UserToEdit')
2479
+            ->willReturn($targetUser);
2480
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2481
+            ->disableOriginalConstructor()
2482
+            ->getMock();
2483
+        $subAdminManager
2484
+            ->expects($this->once())
2485
+            ->method('isUserAccessible')
2486
+            ->with($loggedInUser, $targetUser)
2487
+            ->willReturn(true);
2488
+        $this->groupManager
2489
+            ->expects($this->once())
2490
+            ->method('getSubAdmin')
2491
+            ->willReturn($subAdminManager);
2492
+        $targetUser
2493
+            ->expects($this->any())
2494
+            ->method('getUID')
2495
+            ->willReturn('UID');
2496
+
2497
+        $backend = $this->createMock(UserInterface::class);
2498
+        $targetUser
2499
+            ->expects($this->any())
2500
+            ->method('getBackend')
2501
+            ->willReturn($backend);
2502
+
2503
+        $this->assertEquals([], $this->api->editUser('UserToEdit', 'quota', '3042824')->getData());
2504
+    }
2505
+
2506
+
2507
+    public function testEditUserSubadminUserInaccessible(): void {
2508
+        $this->expectException(OCSException::class);
2509
+        $this->expectExceptionCode(998);
2510
+
2511
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2512
+        $loggedInUser
2513
+            ->expects($this->any())
2514
+            ->method('getUID')
2515
+            ->willReturn('subadmin');
2516
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2517
+        $this->userSession
2518
+            ->expects($this->once())
2519
+            ->method('getUser')
2520
+            ->willReturn($loggedInUser);
2521
+        $this->userManager
2522
+            ->expects($this->once())
2523
+            ->method('get')
2524
+            ->with('UserToEdit')
2525
+            ->willReturn($targetUser);
2526
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2527
+            ->disableOriginalConstructor()
2528
+            ->getMock();
2529
+        $subAdminManager
2530
+            ->expects($this->once())
2531
+            ->method('isUserAccessible')
2532
+            ->with($loggedInUser, $targetUser)
2533
+            ->willReturn(false);
2534
+        $this->groupManager
2535
+            ->expects($this->once())
2536
+            ->method('getSubAdmin')
2537
+            ->willReturn($subAdminManager);
2538
+        $targetUser
2539
+            ->expects($this->any())
2540
+            ->method('getUID')
2541
+            ->willReturn('UID');
2542
+
2543
+        $this->api->editUser('UserToEdit', 'quota', 'value');
2544
+    }
2545
+
2546
+
2547
+    public function testDeleteUserNotExistingUser(): void {
2548
+        $this->expectException(OCSException::class);
2549
+        $this->expectExceptionCode(998);
2550
+
2551
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2552
+        $loggedInUser
2553
+            ->expects($this->any())
2554
+            ->method('getUID')
2555
+            ->willReturn('UserToEdit');
2556
+        $this->userSession
2557
+            ->expects($this->once())
2558
+            ->method('getUser')
2559
+            ->willReturn($loggedInUser);
2560
+        $this->userManager
2561
+            ->expects($this->once())
2562
+            ->method('get')
2563
+            ->with('UserToDelete')
2564
+            ->willReturn(null);
2565
+
2566
+        $this->api->deleteUser('UserToDelete');
2567
+    }
2568
+
2569
+
2570
+    public function testDeleteUserSelf(): void {
2571
+        $this->expectException(OCSException::class);
2572
+        $this->expectExceptionCode(101);
2573
+
2574
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2575
+        $loggedInUser
2576
+            ->expects($this->any())
2577
+            ->method('getUID')
2578
+            ->willReturn('UID');
2579
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2580
+        $targetUser
2581
+            ->expects($this->once())
2582
+            ->method('getUID')
2583
+            ->willReturn('UID');
2584
+        $this->userSession
2585
+            ->expects($this->once())
2586
+            ->method('getUser')
2587
+            ->willReturn($loggedInUser);
2588
+        $this->userManager
2589
+            ->expects($this->once())
2590
+            ->method('get')
2591
+            ->with('UserToDelete')
2592
+            ->willReturn($targetUser);
2593
+
2594
+        $this->api->deleteUser('UserToDelete');
2595
+    }
2596
+
2597
+    public function testDeleteSuccessfulUserAsAdmin(): void {
2598
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2599
+        $loggedInUser
2600
+            ->expects($this->any())
2601
+            ->method('getUID')
2602
+            ->willReturn('admin');
2603
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2604
+        $targetUser
2605
+            ->expects($this->once())
2606
+            ->method('getUID')
2607
+            ->willReturn('UID');
2608
+        $this->userSession
2609
+            ->expects($this->once())
2610
+            ->method('getUser')
2611
+            ->willReturn($loggedInUser);
2612
+        $this->userManager
2613
+            ->expects($this->once())
2614
+            ->method('get')
2615
+            ->with('UserToDelete')
2616
+            ->willReturn($targetUser);
2617
+        $this->groupManager
2618
+            ->expects($this->once())
2619
+            ->method('isAdmin')
2620
+            ->with('admin')
2621
+            ->willReturn(true);
2622
+        $targetUser
2623
+            ->expects($this->once())
2624
+            ->method('delete')
2625
+            ->willReturn(true);
2626
+
2627
+        $this->assertEquals([], $this->api->deleteUser('UserToDelete')->getData());
2628
+    }
2629
+
2630
+
2631
+    public function testDeleteUnsuccessfulUserAsAdmin(): void {
2632
+        $this->expectException(OCSException::class);
2633
+        $this->expectExceptionCode(101);
2634
+
2635
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2636
+        $loggedInUser
2637
+            ->expects($this->any())
2638
+            ->method('getUID')
2639
+            ->willReturn('admin');
2640
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2641
+        $targetUser
2642
+            ->expects($this->once())
2643
+            ->method('getUID')
2644
+            ->willReturn('UID');
2645
+        $this->userSession
2646
+            ->expects($this->once())
2647
+            ->method('getUser')
2648
+            ->willReturn($loggedInUser);
2649
+        $this->userManager
2650
+            ->expects($this->once())
2651
+            ->method('get')
2652
+            ->with('UserToDelete')
2653
+            ->willReturn($targetUser);
2654
+        $this->groupManager
2655
+            ->expects($this->once())
2656
+            ->method('isAdmin')
2657
+            ->with('admin')
2658
+            ->willReturn(true);
2659
+        $targetUser
2660
+            ->expects($this->once())
2661
+            ->method('delete')
2662
+            ->willReturn(false);
2663
+
2664
+        $this->api->deleteUser('UserToDelete');
2665
+    }
2666
+
2667
+    public function testDeleteSuccessfulUserAsSubadmin(): void {
2668
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2669
+        $loggedInUser
2670
+            ->expects($this->any())
2671
+            ->method('getUID')
2672
+            ->willReturn('subadmin');
2673
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2674
+        $targetUser
2675
+            ->expects($this->once())
2676
+            ->method('getUID')
2677
+            ->willReturn('UID');
2678
+        $this->userSession
2679
+            ->expects($this->once())
2680
+            ->method('getUser')
2681
+            ->willReturn($loggedInUser);
2682
+        $this->userManager
2683
+            ->expects($this->once())
2684
+            ->method('get')
2685
+            ->with('UserToDelete')
2686
+            ->willReturn($targetUser);
2687
+        $this->groupManager
2688
+            ->expects($this->once())
2689
+            ->method('isAdmin')
2690
+            ->with('subadmin')
2691
+            ->willReturn(false);
2692
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2693
+            ->disableOriginalConstructor()->getMock();
2694
+        $subAdminManager
2695
+            ->expects($this->once())
2696
+            ->method('isUserAccessible')
2697
+            ->with($loggedInUser, $targetUser)
2698
+            ->willReturn(true);
2699
+        $this->groupManager
2700
+            ->expects($this->once())
2701
+            ->method('getSubAdmin')
2702
+            ->willReturn($subAdminManager);
2703
+        $targetUser
2704
+            ->expects($this->once())
2705
+            ->method('delete')
2706
+            ->willReturn(true);
2707
+
2708
+        $this->assertEquals([], $this->api->deleteUser('UserToDelete')->getData());
2709
+    }
2710
+
2711
+
2712
+    public function testDeleteUnsuccessfulUserAsSubadmin(): void {
2713
+        $this->expectException(OCSException::class);
2714
+        $this->expectExceptionCode(101);
2715
+
2716
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2717
+        $loggedInUser
2718
+            ->expects($this->any())
2719
+            ->method('getUID')
2720
+            ->willReturn('subadmin');
2721
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2722
+        $targetUser
2723
+            ->expects($this->once())
2724
+            ->method('getUID')
2725
+            ->willReturn('UID');
2726
+        $this->userSession
2727
+            ->expects($this->once())
2728
+            ->method('getUser')
2729
+            ->willReturn($loggedInUser);
2730
+        $this->userManager
2731
+            ->expects($this->once())
2732
+            ->method('get')
2733
+            ->with('UserToDelete')
2734
+            ->willReturn($targetUser);
2735
+        $this->groupManager
2736
+            ->expects($this->once())
2737
+            ->method('isAdmin')
2738
+            ->with('subadmin')
2739
+            ->willReturn(false);
2740
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2741
+            ->disableOriginalConstructor()->getMock();
2742
+        $subAdminManager
2743
+            ->expects($this->once())
2744
+            ->method('isUserAccessible')
2745
+            ->with($loggedInUser, $targetUser)
2746
+            ->willReturn(true);
2747
+        $this->groupManager
2748
+            ->expects($this->once())
2749
+            ->method('getSubAdmin')
2750
+            ->willReturn($subAdminManager);
2751
+        $targetUser
2752
+            ->expects($this->once())
2753
+            ->method('delete')
2754
+            ->willReturn(false);
2755
+
2756
+        $this->api->deleteUser('UserToDelete');
2757
+    }
2758
+
2759
+
2760
+    public function testDeleteUserAsSubAdminAndUserIsNotAccessible(): void {
2761
+        $this->expectException(OCSException::class);
2762
+        $this->expectExceptionCode(998);
2763
+
2764
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2765
+        $loggedInUser
2766
+            ->expects($this->any())
2767
+            ->method('getUID')
2768
+            ->willReturn('subadmin');
2769
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2770
+        $targetUser
2771
+            ->expects($this->once())
2772
+            ->method('getUID')
2773
+            ->willReturn('UID');
2774
+        $this->userSession
2775
+            ->expects($this->once())
2776
+            ->method('getUser')
2777
+            ->willReturn($loggedInUser);
2778
+        $this->userManager
2779
+            ->expects($this->once())
2780
+            ->method('get')
2781
+            ->with('UserToDelete')
2782
+            ->willReturn($targetUser);
2783
+        $this->groupManager
2784
+            ->expects($this->once())
2785
+            ->method('isAdmin')
2786
+            ->with('subadmin')
2787
+            ->willReturn(false);
2788
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2789
+            ->disableOriginalConstructor()->getMock();
2790
+        $subAdminManager
2791
+            ->expects($this->once())
2792
+            ->method('isUserAccessible')
2793
+            ->with($loggedInUser, $targetUser)
2794
+            ->willReturn(false);
2795
+        $this->groupManager
2796
+            ->expects($this->once())
2797
+            ->method('getSubAdmin')
2798
+            ->willReturn($subAdminManager);
2799
+
2800
+        $this->api->deleteUser('UserToDelete');
2801
+    }
2802
+
2803
+
2804
+    public function testGetUsersGroupsTargetUserNotExisting(): void {
2805
+        $this->expectException(OCSException::class);
2806
+        $this->expectExceptionCode(998);
2807
+
2808
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2809
+        $this->userSession
2810
+            ->expects($this->once())
2811
+            ->method('getUser')
2812
+            ->willReturn($loggedInUser);
2813
+
2814
+        $this->api->getUsersGroups('UserToLookup');
2815
+    }
2816
+
2817
+    public function testGetUsersGroupsSelfTargetted(): void {
2818
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2819
+        $loggedInUser
2820
+            ->expects($this->exactly(3))
2821
+            ->method('getUID')
2822
+            ->willReturn('UserToLookup');
2823
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2824
+        $targetUser
2825
+            ->expects($this->once())
2826
+            ->method('getUID')
2827
+            ->willReturn('UserToLookup');
2828
+        $this->userSession
2829
+            ->expects($this->once())
2830
+            ->method('getUser')
2831
+            ->willReturn($loggedInUser);
2832
+        $this->userManager
2833
+            ->expects($this->once())
2834
+            ->method('get')
2835
+            ->with('UserToLookup')
2836
+            ->willReturn($targetUser);
2837
+        $this->groupManager
2838
+            ->expects($this->once())
2839
+            ->method('getUserGroupIds')
2840
+            ->with($targetUser)
2841
+            ->willReturn(['DummyValue']);
2842
+
2843
+        $this->assertEquals(['groups' => ['DummyValue']], $this->api->getUsersGroups('UserToLookup')->getData());
2844
+    }
2845
+
2846
+    public function testGetUsersGroupsForAdminUser(): void {
2847
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2848
+        $loggedInUser
2849
+            ->expects($this->exactly(3))
2850
+            ->method('getUID')
2851
+            ->willReturn('admin');
2852
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2853
+        $targetUser
2854
+            ->expects($this->once())
2855
+            ->method('getUID')
2856
+            ->willReturn('UserToLookup');
2857
+        $this->userSession
2858
+            ->expects($this->once())
2859
+            ->method('getUser')
2860
+            ->willReturn($loggedInUser);
2861
+        $this->userManager
2862
+            ->expects($this->once())
2863
+            ->method('get')
2864
+            ->with('UserToLookup')
2865
+            ->willReturn($targetUser);
2866
+        $this->groupManager
2867
+            ->expects($this->once())
2868
+            ->method('getUserGroupIds')
2869
+            ->with($targetUser)
2870
+            ->willReturn(['DummyValue']);
2871
+        $this->groupManager
2872
+            ->expects($this->once())
2873
+            ->method('isAdmin')
2874
+            ->with('admin')
2875
+            ->willReturn(true);
2876
+
2877
+        $this->assertEquals(['groups' => ['DummyValue']], $this->api->getUsersGroups('UserToLookup')->getData());
2878
+    }
2879
+
2880
+    public function testGetUsersGroupsForSubAdminUserAndUserIsAccessible(): void {
2881
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2882
+        $loggedInUser
2883
+            ->expects($this->exactly(3))
2884
+            ->method('getUID')
2885
+            ->willReturn('subadmin');
2886
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2887
+        $targetUser
2888
+            ->expects($this->once())
2889
+            ->method('getUID')
2890
+            ->willReturn('UserToLookup');
2891
+        $this->userSession
2892
+            ->expects($this->once())
2893
+            ->method('getUser')
2894
+            ->willReturn($loggedInUser);
2895
+        $this->userManager
2896
+            ->expects($this->once())
2897
+            ->method('get')
2898
+            ->with('UserToLookup')
2899
+            ->willReturn($targetUser);
2900
+        $this->groupManager
2901
+            ->expects($this->once())
2902
+            ->method('isAdmin')
2903
+            ->with('subadmin')
2904
+            ->willReturn(false);
2905
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2906
+            ->disableOriginalConstructor()->getMock();
2907
+        $subAdminManager
2908
+            ->expects($this->once())
2909
+            ->method('isUserAccessible')
2910
+            ->with($loggedInUser, $targetUser)
2911
+            ->willReturn(true);
2912
+        $this->groupManager
2913
+            ->expects($this->once())
2914
+            ->method('getSubAdmin')
2915
+            ->willReturn($subAdminManager);
2916
+        $group1 = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
2917
+        $group1
2918
+            ->expects($this->any())
2919
+            ->method('getGID')
2920
+            ->willReturn('Group1');
2921
+        $group2 = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
2922
+        $group2
2923
+            ->expects($this->any())
2924
+            ->method('getGID')
2925
+            ->willReturn('Group2');
2926
+        $subAdminManager
2927
+            ->expects($this->once())
2928
+            ->method('getSubAdminsGroups')
2929
+            ->with($loggedInUser)
2930
+            ->willReturn([$group1, $group2]);
2931
+        $this->groupManager
2932
+            ->expects($this->any())
2933
+            ->method('getUserGroupIds')
2934
+            ->with($targetUser)
2935
+            ->willReturn(['Group1']);
2936
+
2937
+        $this->assertEquals(['groups' => ['Group1']], $this->api->getUsersGroups('UserToLookup')->getData());
2938
+    }
2939
+
2940
+
2941
+    public function testGetUsersGroupsForSubAdminUserAndUserIsInaccessible(): void {
2942
+        $this->expectException(OCSException::class);
2943
+        $this->expectExceptionCode(998);
2944
+
2945
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2946
+        $loggedInUser
2947
+            ->expects($this->exactly(3))
2948
+            ->method('getUID')
2949
+            ->willReturn('subadmin');
2950
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
2951
+        $targetUser
2952
+            ->expects($this->once())
2953
+            ->method('getUID')
2954
+            ->willReturn('UserToLookup');
2955
+        $this->userSession
2956
+            ->expects($this->once())
2957
+            ->method('getUser')
2958
+            ->willReturn($loggedInUser);
2959
+        $this->userManager
2960
+            ->expects($this->once())
2961
+            ->method('get')
2962
+            ->with('UserToLookup')
2963
+            ->willReturn($targetUser);
2964
+        $this->groupManager
2965
+            ->expects($this->once())
2966
+            ->method('isAdmin')
2967
+            ->with('subadmin')
2968
+            ->willReturn(false);
2969
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
2970
+            ->disableOriginalConstructor()->getMock();
2971
+        $subAdminManager
2972
+            ->expects($this->once())
2973
+            ->method('isUserAccessible')
2974
+            ->with($loggedInUser, $targetUser)
2975
+            ->willReturn(false);
2976
+        $this->groupManager
2977
+            ->expects($this->once())
2978
+            ->method('getSubAdmin')
2979
+            ->willReturn($subAdminManager);
2980
+        $this->groupManager
2981
+            ->expects($this->any())
2982
+            ->method('getUserGroupIds')
2983
+            ->with($targetUser)
2984
+            ->willReturn(['Group1']);
2985
+
2986
+        $this->api->getUsersGroups('UserToLookup');
2987
+    }
2988
+
2989
+
2990
+    public function testAddToGroupWithTargetGroupNotExisting(): void {
2991
+        $this->expectException(OCSException::class);
2992
+        $this->expectExceptionCode(102);
2993
+
2994
+        $this->groupManager->expects($this->once())
2995
+            ->method('get')
2996
+            ->with('GroupToAddTo')
2997
+            ->willReturn(null);
2998
+
2999
+        $this->api->addToGroup('TargetUser', 'GroupToAddTo');
3000
+    }
3001
+
3002
+
3003
+    public function testAddToGroupWithNoGroupSpecified(): void {
3004
+        $this->expectException(OCSException::class);
3005
+        $this->expectExceptionCode(101);
3006
+
3007
+        $this->api->addToGroup('TargetUser');
3008
+    }
3009
+
3010
+
3011
+    public function testAddToGroupWithTargetUserNotExisting(): void {
3012
+        $this->expectException(OCSException::class);
3013
+        $this->expectExceptionCode(103);
3014
+
3015
+        $targetGroup = $this->createMock(IGroup::class);
3016
+        $this->groupManager->expects($this->once())
3017
+            ->method('get')
3018
+            ->with('GroupToAddTo')
3019
+            ->willReturn($targetGroup);
3020
+
3021
+        $this->api->addToGroup('TargetUser', 'GroupToAddTo');
3022
+    }
3023
+
3024
+
3025
+    public function testAddToGroupNoSubadmin(): void {
3026
+        $this->expectException(OCSException::class);
3027
+        $this->expectExceptionCode(104);
3028
+
3029
+        $targetUser = $this->createMock(IUser::class);
3030
+        $loggedInUser = $this->createMock(IUser::class);
3031
+        $loggedInUser->expects($this->exactly(2))
3032
+            ->method('getUID')
3033
+            ->willReturn('subadmin');
3034
+
3035
+        $targetGroup = $this->createMock(IGroup::class);
3036
+        $targetGroup->expects($this->never())
3037
+            ->method('addUser')
3038
+            ->with($targetUser);
3039
+
3040
+        $this->groupManager->expects($this->once())
3041
+            ->method('get')
3042
+            ->with('GroupToAddTo')
3043
+            ->willReturn($targetGroup);
3044
+
3045
+
3046
+        $subAdminManager = $this->createMock(SubAdmin::class);
3047
+        $subAdminManager->expects($this->once())
3048
+            ->method('isSubAdminOfGroup')
3049
+            ->with($loggedInUser, $targetGroup)
3050
+            ->willReturn(false);
3051
+
3052
+        $this->groupManager->expects($this->once())
3053
+            ->method('getSubAdmin')
3054
+            ->willReturn($subAdminManager);
3055
+        $this->groupManager->expects($this->once())
3056
+            ->method('isAdmin')
3057
+            ->with('subadmin')
3058
+            ->willReturn(false);
3059
+
3060
+        $this->userManager->expects($this->once())
3061
+            ->method('get')
3062
+            ->with('TargetUser')
3063
+            ->willReturn($targetUser);
3064
+
3065
+        $this->userSession->expects($this->once())
3066
+            ->method('getUser')
3067
+            ->willReturn($loggedInUser);
3068
+
3069
+        $this->api->addToGroup('TargetUser', 'GroupToAddTo');
3070
+    }
3071
+
3072
+    public function testAddToGroupSuccessAsSubadmin(): void {
3073
+        $targetUser = $this->createMock(IUser::class);
3074
+        $loggedInUser = $this->createMock(IUser::class);
3075
+        $loggedInUser->expects($this->exactly(2))
3076
+            ->method('getUID')
3077
+            ->willReturn('subadmin');
3078
+
3079
+        $targetGroup = $this->createMock(IGroup::class);
3080
+        $targetGroup->expects($this->once())
3081
+            ->method('addUser')
3082
+            ->with($targetUser);
3083
+
3084
+        $this->groupManager->expects($this->once())
3085
+            ->method('get')
3086
+            ->with('GroupToAddTo')
3087
+            ->willReturn($targetGroup);
3088 3088
 
3089
-
3090
-		$subAdminManager = $this->createMock(SubAdmin::class);
3091
-		$subAdminManager->expects($this->once())
3092
-			->method('isSubAdminOfGroup')
3093
-			->with($loggedInUser, $targetGroup)
3094
-			->willReturn(true);
3095
-
3096
-		$this->groupManager->expects($this->once())
3097
-			->method('getSubAdmin')
3098
-			->willReturn($subAdminManager);
3099
-		$this->groupManager->expects($this->once())
3100
-			->method('isAdmin')
3101
-			->with('subadmin')
3102
-			->willReturn(false);
3103
-
3104
-		$this->userManager->expects($this->once())
3105
-			->method('get')
3106
-			->with('TargetUser')
3107
-			->willReturn($targetUser);
3108
-
3109
-		$this->userSession->expects($this->once())
3110
-			->method('getUser')
3111
-			->willReturn($loggedInUser);
3112
-
3113
-		$this->assertEquals(new DataResponse(), $this->api->addToGroup('TargetUser', 'GroupToAddTo'));
3114
-	}
3115
-
3116
-	public function testAddToGroupSuccessAsAdmin(): void {
3117
-		$targetUser = $this->createMock(IUser::class);
3118
-		$loggedInUser = $this->createMock(IUser::class);
3119
-		$loggedInUser->expects($this->exactly(2))
3120
-			->method('getUID')
3121
-			->willReturn('admin');
3122
-
3123
-		$targetGroup = $this->createMock(IGroup::class);
3124
-		$targetGroup->expects($this->once())
3125
-			->method('addUser')
3126
-			->with($targetUser);
3127
-
3128
-		$this->groupManager->expects($this->once())
3129
-			->method('get')
3130
-			->with('GroupToAddTo')
3131
-			->willReturn($targetGroup);
3132
-
3133
-
3134
-		$subAdminManager = $this->createMock(SubAdmin::class);
3135
-		$subAdminManager->expects($this->never())
3136
-			->method('isSubAdminOfGroup');
3137
-
3138
-		$this->groupManager->expects($this->once())
3139
-			->method('getSubAdmin')
3140
-			->willReturn($subAdminManager);
3141
-		$this->groupManager->expects($this->once())
3142
-			->method('isAdmin')
3143
-			->with('admin')
3144
-			->willReturn(true);
3145
-
3146
-		$this->userManager->expects($this->once())
3147
-			->method('get')
3148
-			->with('TargetUser')
3149
-			->willReturn($targetUser);
3150
-
3151
-		$this->userSession->expects($this->once())
3152
-			->method('getUser')
3153
-			->willReturn($loggedInUser);
3154
-
3155
-		$this->assertEquals(new DataResponse(), $this->api->addToGroup('TargetUser', 'GroupToAddTo'));
3156
-	}
3157
-
3158
-
3159
-	public function testRemoveFromGroupWithNoTargetGroup(): void {
3160
-		$this->expectException(OCSException::class);
3161
-		$this->expectExceptionCode(101);
3162
-
3163
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3164
-		$this->userSession
3165
-			->expects($this->once())
3166
-			->method('getUser')
3167
-			->willReturn($loggedInUser);
3168
-
3169
-		$this->api->removeFromGroup('TargetUser', '');
3170
-	}
3171
-
3172
-
3173
-	public function testRemoveFromGroupWithEmptyTargetGroup(): void {
3174
-		$this->expectException(OCSException::class);
3175
-		$this->expectExceptionCode(101);
3176
-
3177
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3178
-		$this->userSession
3179
-			->expects($this->once())
3180
-			->method('getUser')
3181
-			->willReturn($loggedInUser);
3182
-
3183
-		$this->api->removeFromGroup('TargetUser', '');
3184
-	}
3185
-
3186
-
3187
-	public function testRemoveFromGroupWithNotExistingTargetGroup(): void {
3188
-		$this->expectException(OCSException::class);
3189
-		$this->expectExceptionCode(102);
3190
-
3191
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3192
-		$this->userSession
3193
-			->expects($this->once())
3194
-			->method('getUser')
3195
-			->willReturn($loggedInUser);
3196
-		$this->groupManager
3197
-			->expects($this->once())
3198
-			->method('get')
3199
-			->with('TargetGroup')
3200
-			->willReturn(null);
3201
-
3202
-		$this->api->removeFromGroup('TargetUser', 'TargetGroup');
3203
-	}
3204
-
3205
-
3206
-	public function testRemoveFromGroupWithNotExistingTargetUser(): void {
3207
-		$this->expectException(OCSException::class);
3208
-		$this->expectExceptionCode(103);
3209
-
3210
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3211
-		$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3212
-		$this->userSession
3213
-			->expects($this->once())
3214
-			->method('getUser')
3215
-			->willReturn($loggedInUser);
3216
-		$this->groupManager
3217
-			->expects($this->once())
3218
-			->method('get')
3219
-			->with('TargetGroup')
3220
-			->willReturn($targetGroup);
3221
-		$this->userManager
3222
-			->expects($this->once())
3223
-			->method('get')
3224
-			->with('TargetUser')
3225
-			->willReturn(null);
3226
-
3227
-		$this->api->removeFromGroup('TargetUser', 'TargetGroup');
3228
-	}
3229
-
3230
-
3231
-	public function testRemoveFromGroupWithoutPermission(): void {
3232
-		$this->expectException(OCSException::class);
3233
-		$this->expectExceptionCode(104);
3234
-
3235
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3236
-		$loggedInUser
3237
-			->expects($this->exactly(2))
3238
-			->method('getUID')
3239
-			->willReturn('unauthorizedUser');
3240
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3241
-		$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3242
-		$this->userSession
3243
-			->expects($this->once())
3244
-			->method('getUser')
3245
-			->willReturn($loggedInUser);
3246
-		$this->groupManager
3247
-			->expects($this->once())
3248
-			->method('get')
3249
-			->with('TargetGroup')
3250
-			->willReturn($targetGroup);
3251
-		$this->userManager
3252
-			->expects($this->once())
3253
-			->method('get')
3254
-			->with('TargetUser')
3255
-			->willReturn($targetUser);
3256
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3257
-			->disableOriginalConstructor()->getMock();
3258
-		$this->groupManager
3259
-			->expects($this->once())
3260
-			->method('getSubAdmin')
3261
-			->willReturn($subAdminManager);
3262
-		$this->groupManager
3263
-			->expects($this->once())
3264
-			->method('isAdmin')
3265
-			->with('unauthorizedUser')
3266
-			->willReturn(false);
3267
-
3268
-		$this->api->removeFromGroup('TargetUser', 'TargetGroup');
3269
-	}
3270
-
3271
-
3272
-	public function testRemoveFromGroupAsAdminFromAdmin(): void {
3273
-		$this->expectException(OCSException::class);
3274
-		$this->expectExceptionMessage('Cannot remove yourself from the admin group');
3275
-		$this->expectExceptionCode(105);
3276
-
3277
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3278
-		$loggedInUser
3279
-			->expects($this->any())
3280
-			->method('getUID')
3281
-			->willReturn('admin');
3282
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3283
-		$targetUser
3284
-			->expects($this->once())
3285
-			->method('getUID')
3286
-			->willReturn('admin');
3287
-		$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3288
-		$targetGroup
3289
-			->expects($this->once())
3290
-			->method('getGID')
3291
-			->willReturn('admin');
3292
-		$this->userSession
3293
-			->expects($this->once())
3294
-			->method('getUser')
3295
-			->willReturn($loggedInUser);
3296
-		$this->groupManager
3297
-			->expects($this->once())
3298
-			->method('get')
3299
-			->with('admin')
3300
-			->willReturn($targetGroup);
3301
-		$this->userManager
3302
-			->expects($this->once())
3303
-			->method('get')
3304
-			->with('Admin')
3305
-			->willReturn($targetUser);
3306
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3307
-			->disableOriginalConstructor()->getMock();
3308
-		$this->groupManager
3309
-			->expects($this->once())
3310
-			->method('getSubAdmin')
3311
-			->willReturn($subAdminManager);
3312
-		$this->groupManager
3313
-			->expects($this->any())
3314
-			->method('isAdmin')
3315
-			->with('admin')
3316
-			->willReturn(true);
3317
-
3318
-		$this->api->removeFromGroup('Admin', 'admin');
3319
-	}
3320
-
3321
-
3322
-	public function testRemoveFromGroupAsSubAdminFromSubAdmin(): void {
3323
-		$this->expectException(OCSException::class);
3324
-		$this->expectExceptionMessage('Cannot remove yourself from this group as you are a sub-admin');
3325
-		$this->expectExceptionCode(105);
3326
-
3327
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3328
-		$loggedInUser
3329
-			->expects($this->any())
3330
-			->method('getUID')
3331
-			->willReturn('subadmin');
3332
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3333
-		$targetUser
3334
-			->expects($this->once())
3335
-			->method('getUID')
3336
-			->willReturn('subadmin');
3337
-		$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3338
-		$targetGroup
3339
-			->expects($this->any())
3340
-			->method('getGID')
3341
-			->willReturn('subadmin');
3342
-		$this->userSession
3343
-			->expects($this->once())
3344
-			->method('getUser')
3345
-			->willReturn($loggedInUser);
3346
-		$this->groupManager
3347
-			->expects($this->once())
3348
-			->method('get')
3349
-			->with('subadmin')
3350
-			->willReturn($targetGroup);
3351
-		$this->userManager
3352
-			->expects($this->once())
3353
-			->method('get')
3354
-			->with('SubAdmin')
3355
-			->willReturn($targetUser);
3356
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3357
-			->disableOriginalConstructor()->getMock();
3358
-		$subAdminManager
3359
-			->expects($this->once())
3360
-			->method('isSubAdminOfGroup')
3361
-			->with($loggedInUser, $targetGroup)
3362
-			->willReturn(true);
3363
-		$this->groupManager
3364
-			->expects($this->once())
3365
-			->method('getSubAdmin')
3366
-			->willReturn($subAdminManager);
3367
-		$this->groupManager
3368
-			->expects($this->any())
3369
-			->method('isAdmin')
3370
-			->with('subadmin')
3371
-			->willReturn(false);
3372
-
3373
-		$this->api->removeFromGroup('SubAdmin', 'subadmin');
3374
-	}
3375
-
3376
-
3377
-	public function testRemoveFromGroupAsSubAdminFromLastSubAdminGroup(): void {
3378
-		$this->expectException(OCSException::class);
3379
-		$this->expectExceptionMessage('Not viable to remove user from the last group you are sub-admin of');
3380
-		$this->expectExceptionCode(105);
3381
-
3382
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3383
-		$loggedInUser
3384
-			->expects($this->any())
3385
-			->method('getUID')
3386
-			->willReturn('subadmin');
3387
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3388
-		$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3389
-		$targetGroup
3390
-			->expects($this->any())
3391
-			->method('getGID')
3392
-			->willReturn('subadmin');
3393
-		$this->userSession
3394
-			->expects($this->once())
3395
-			->method('getUser')
3396
-			->willReturn($loggedInUser);
3397
-		$this->groupManager
3398
-			->expects($this->once())
3399
-			->method('get')
3400
-			->with('subadmin')
3401
-			->willReturn($targetGroup);
3402
-		$this->userManager
3403
-			->expects($this->once())
3404
-			->method('get')
3405
-			->with('AnotherUser')
3406
-			->willReturn($targetUser);
3407
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3408
-			->disableOriginalConstructor()->getMock();
3409
-		$subAdminManager
3410
-			->expects($this->once())
3411
-			->method('isSubAdminOfGroup')
3412
-			->with($loggedInUser, $targetGroup)
3413
-			->willReturn(true);
3414
-		$this->groupManager
3415
-			->expects($this->once())
3416
-			->method('getSubAdmin')
3417
-			->willReturn($subAdminManager);
3418
-		$subAdminManager
3419
-			->expects($this->once())
3420
-			->method('getSubAdminsGroups')
3421
-			->with($loggedInUser)
3422
-			->willReturn([$targetGroup]);
3423
-
3424
-		$this->groupManager
3425
-			->expects($this->any())
3426
-			->method('isAdmin')
3427
-			->with('subadmin')
3428
-			->willReturn(false);
3429
-		$this->groupManager
3430
-			->expects($this->once())
3431
-			->method('getUserGroupIds')
3432
-			->with($targetUser)
3433
-			->willReturn(['subadmin', 'other group']);
3434
-
3435
-		$this->api->removeFromGroup('AnotherUser', 'subadmin');
3436
-	}
3437
-
3438
-	public function testRemoveFromGroupSuccessful(): void {
3439
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3440
-		$loggedInUser
3441
-			->expects($this->any())
3442
-			->method('getUID')
3443
-			->willReturn('admin');
3444
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3445
-		$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3446
-		$this->userSession
3447
-			->expects($this->once())
3448
-			->method('getUser')
3449
-			->willReturn($loggedInUser);
3450
-		$this->groupManager
3451
-			->expects($this->once())
3452
-			->method('get')
3453
-			->with('admin')
3454
-			->willReturn($targetGroup);
3455
-		$this->userManager
3456
-			->expects($this->once())
3457
-			->method('get')
3458
-			->with('AnotherUser')
3459
-			->willReturn($targetUser);
3460
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3461
-			->disableOriginalConstructor()->getMock();
3462
-		$this->groupManager
3463
-			->expects($this->once())
3464
-			->method('getSubAdmin')
3465
-			->willReturn($subAdminManager);
3466
-		$this->groupManager
3467
-			->expects($this->any())
3468
-			->method('isAdmin')
3469
-			->with('admin')
3470
-			->willReturn(true);
3471
-		$targetGroup
3472
-			->expects($this->once())
3473
-			->method('removeUser')
3474
-			->with($targetUser);
3475
-
3476
-		$this->assertEquals([], $this->api->removeFromGroup('AnotherUser', 'admin')->getData());
3477
-	}
3478
-
3479
-
3480
-	public function testAddSubAdminWithNotExistingTargetUser(): void {
3481
-		$this->expectException(OCSException::class);
3482
-		$this->expectExceptionMessage('User does not exist');
3483
-		$this->expectExceptionCode(101);
3484
-
3485
-		$this->userManager
3486
-			->expects($this->once())
3487
-			->method('get')
3488
-			->with('NotExistingUser')
3489
-			->willReturn(null);
3490
-
3491
-		$this->api->addSubAdmin('NotExistingUser', '');
3492
-	}
3493
-
3494
-
3495
-	public function testAddSubAdminWithNotExistingTargetGroup(): void {
3496
-		$this->expectException(OCSException::class);
3497
-		$this->expectExceptionMessage('Group does not exist');
3498
-		$this->expectExceptionCode(102);
3499
-
3500
-
3501
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3502
-		$this->userManager
3503
-			->expects($this->once())
3504
-			->method('get')
3505
-			->with('ExistingUser')
3506
-			->willReturn($targetUser);
3507
-		$this->groupManager
3508
-			->expects($this->once())
3509
-			->method('get')
3510
-			->with('NotExistingGroup')
3511
-			->willReturn(null);
3512
-
3513
-		$this->api->addSubAdmin('ExistingUser', 'NotExistingGroup');
3514
-	}
3515
-
3516
-
3517
-	public function testAddSubAdminToAdminGroup(): void {
3518
-		$this->expectException(OCSException::class);
3519
-		$this->expectExceptionMessage('Cannot create sub-admins for admin group');
3520
-		$this->expectExceptionCode(103);
3521
-
3522
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3523
-		$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3524
-		$targetGroup
3525
-			->expects($this->once())
3526
-			->method('getGID')
3527
-			->willReturn('admin');
3528
-		$this->userManager
3529
-			->expects($this->once())
3530
-			->method('get')
3531
-			->with('ExistingUser')
3532
-			->willReturn($targetUser);
3533
-		$this->groupManager
3534
-			->expects($this->once())
3535
-			->method('get')
3536
-			->with('ADmiN')
3537
-			->willReturn($targetGroup);
3538
-
3539
-		$this->api->addSubAdmin('ExistingUser', 'ADmiN');
3540
-	}
3541
-
3542
-	public function testAddSubAdminTwice(): void {
3543
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3544
-		$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3545
-		$this->userManager
3546
-			->expects($this->once())
3547
-			->method('get')
3548
-			->with('ExistingUser')
3549
-			->willReturn($targetUser);
3550
-		$this->groupManager
3551
-			->expects($this->once())
3552
-			->method('get')
3553
-			->with('TargetGroup')
3554
-			->willReturn($targetGroup);
3555
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3556
-			->disableOriginalConstructor()->getMock();
3557
-		$subAdminManager
3558
-			->expects($this->once())
3559
-			->method('isSubAdminOfGroup')
3560
-			->with($targetUser, $targetGroup)
3561
-			->willReturn(true);
3562
-		$this->groupManager
3563
-			->expects($this->once())
3564
-			->method('getSubAdmin')
3565
-			->willReturn($subAdminManager);
3566
-
3567
-		$this->assertEquals([], $this->api->addSubAdmin('ExistingUser', 'TargetGroup')->getData());
3568
-	}
3569
-
3570
-	public function testAddSubAdminSuccessful(): void {
3571
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3572
-		$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3573
-		$this->userManager
3574
-			->expects($this->once())
3575
-			->method('get')
3576
-			->with('ExistingUser')
3577
-			->willReturn($targetUser);
3578
-		$this->groupManager
3579
-			->expects($this->once())
3580
-			->method('get')
3581
-			->with('TargetGroup')
3582
-			->willReturn($targetGroup);
3583
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3584
-			->disableOriginalConstructor()->getMock();
3585
-		$subAdminManager
3586
-			->expects($this->once())
3587
-			->method('isSubAdminOfGroup')
3588
-			->with($targetUser, $targetGroup)
3589
-			->willReturn(false);
3590
-		$subAdminManager
3591
-			->expects($this->once())
3592
-			->method('createSubAdmin')
3593
-			->with($targetUser, $targetGroup);
3594
-		$this->groupManager
3595
-			->expects($this->once())
3596
-			->method('getSubAdmin')
3597
-			->willReturn($subAdminManager);
3598
-
3599
-		$this->assertEquals([], $this->api->addSubAdmin('ExistingUser', 'TargetGroup')->getData());
3600
-	}
3601
-
3602
-
3603
-	public function testRemoveSubAdminNotExistingTargetUser(): void {
3604
-		$this->expectException(OCSException::class);
3605
-		$this->expectExceptionMessage('User does not exist');
3606
-		$this->expectExceptionCode(101);
3607
-
3608
-		$this->userManager
3609
-			->expects($this->once())
3610
-			->method('get')
3611
-			->with('NotExistingUser')
3612
-			->willReturn(null);
3613
-
3614
-		$this->api->removeSubAdmin('NotExistingUser', 'GroupToDeleteFrom');
3615
-	}
3616
-
3617
-
3618
-	public function testRemoveSubAdminNotExistingTargetGroup(): void {
3619
-		$this->expectException(OCSException::class);
3620
-		$this->expectExceptionMessage('Group does not exist');
3621
-		$this->expectExceptionCode(101);
3622
-
3623
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3624
-		$this->userManager
3625
-			->expects($this->once())
3626
-			->method('get')
3627
-			->with('ExistingUser')
3628
-			->willReturn($targetUser);
3629
-		$this->groupManager
3630
-			->expects($this->once())
3631
-			->method('get')
3632
-			->with('GroupToDeleteFrom')
3633
-			->willReturn(null);
3634
-
3635
-		$this->api->removeSubAdmin('ExistingUser', 'GroupToDeleteFrom');
3636
-	}
3637
-
3638
-
3639
-
3640
-	public function testRemoveSubAdminFromNotASubadmin(): void {
3641
-		$this->expectException(OCSException::class);
3642
-		$this->expectExceptionMessage('User is not a sub-admin of this group');
3643
-		$this->expectExceptionCode(102);
3644
-
3645
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3646
-		$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3647
-		$this->userManager
3648
-			->expects($this->once())
3649
-			->method('get')
3650
-			->with('ExistingUser')
3651
-			->willReturn($targetUser);
3652
-		$this->groupManager
3653
-			->expects($this->once())
3654
-			->method('get')
3655
-			->with('GroupToDeleteFrom')
3656
-			->willReturn($targetGroup);
3657
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3658
-			->disableOriginalConstructor()->getMock();
3659
-		$subAdminManager
3660
-			->expects($this->once())
3661
-			->method('isSubAdminOfGroup')
3662
-			->with($targetUser, $targetGroup)
3663
-			->willReturn(false);
3664
-		$this->groupManager
3665
-			->expects($this->once())
3666
-			->method('getSubAdmin')
3667
-			->willReturn($subAdminManager);
3668
-
3669
-		$this->api->removeSubAdmin('ExistingUser', 'GroupToDeleteFrom');
3670
-	}
3671
-
3672
-	public function testRemoveSubAdminSuccessful(): void {
3673
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3674
-		$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3675
-		$this->userManager
3676
-			->expects($this->once())
3677
-			->method('get')
3678
-			->with('ExistingUser')
3679
-			->willReturn($targetUser);
3680
-		$this->groupManager
3681
-			->expects($this->once())
3682
-			->method('get')
3683
-			->with('GroupToDeleteFrom')
3684
-			->willReturn($targetGroup);
3685
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3686
-			->disableOriginalConstructor()->getMock();
3687
-		$subAdminManager
3688
-			->expects($this->once())
3689
-			->method('isSubAdminOfGroup')
3690
-			->with($targetUser, $targetGroup)
3691
-			->willReturn(true);
3692
-		$subAdminManager
3693
-			->expects($this->once())
3694
-			->method('deleteSubAdmin')
3695
-			->with($targetUser, $targetGroup);
3696
-		$this->groupManager
3697
-			->expects($this->once())
3698
-			->method('getSubAdmin')
3699
-			->willReturn($subAdminManager);
3700
-
3701
-		$this->assertEquals([], $this->api->removeSubAdmin('ExistingUser', 'GroupToDeleteFrom')->getData());
3702
-	}
3703
-
3704
-
3705
-	public function testGetUserSubAdminGroupsNotExistingTargetUser(): void {
3706
-		$this->expectException(OCSException::class);
3707
-		$this->expectExceptionMessage('User does not exist');
3708
-		$this->expectExceptionCode(404);
3709
-
3710
-		$this->userManager
3711
-			->expects($this->once())
3712
-			->method('get')
3713
-			->with('RequestedUser')
3714
-			->willReturn(null);
3715
-
3716
-		$this->api->getUserSubAdminGroups('RequestedUser');
3717
-	}
3718
-
3719
-	public function testGetUserSubAdminGroupsWithGroups(): void {
3720
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3721
-		$targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3722
-		$targetGroup
3723
-			->expects($this->once())
3724
-			->method('getGID')
3725
-			->willReturn('TargetGroup');
3726
-		$this->userManager
3727
-			->expects($this->once())
3728
-			->method('get')
3729
-			->with('RequestedUser')
3730
-			->willReturn($targetUser);
3731
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3732
-			->disableOriginalConstructor()->getMock();
3733
-		$subAdminManager
3734
-			->expects($this->once())
3735
-			->method('getSubAdminsGroups')
3736
-			->with($targetUser)
3737
-			->willReturn([$targetGroup]);
3738
-		$this->groupManager
3739
-			->expects($this->once())
3740
-			->method('getSubAdmin')
3741
-			->willReturn($subAdminManager);
3742
-
3743
-		$this->assertEquals(['TargetGroup'], $this->api->getUserSubAdminGroups('RequestedUser')->getData());
3744
-	}
3745
-
3746
-	public function testEnableUser(): void {
3747
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3748
-		$targetUser->expects($this->once())
3749
-			->method('setEnabled')
3750
-			->with(true);
3751
-		$this->userManager
3752
-			->expects($this->once())
3753
-			->method('get')
3754
-			->with('RequestedUser')
3755
-			->willReturn($targetUser);
3756
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3757
-		$loggedInUser
3758
-			->expects($this->exactly(3))
3759
-			->method('getUID')
3760
-			->willReturn('admin');
3761
-		$this->userSession
3762
-			->expects($this->once())
3763
-			->method('getUser')
3764
-			->willReturn($loggedInUser);
3765
-		$this->groupManager
3766
-			->expects($this->once())
3767
-			->method('isAdmin')
3768
-			->willReturn(true);
3769
-
3770
-		$this->assertEquals([], $this->api->enableUser('RequestedUser')->getData());
3771
-	}
3772
-
3773
-	public function testDisableUser(): void {
3774
-		$targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3775
-		$targetUser->expects($this->once())
3776
-			->method('setEnabled')
3777
-			->with(false);
3778
-		$this->userManager
3779
-			->expects($this->once())
3780
-			->method('get')
3781
-			->with('RequestedUser')
3782
-			->willReturn($targetUser);
3783
-		$loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3784
-		$loggedInUser
3785
-			->expects($this->exactly(3))
3786
-			->method('getUID')
3787
-			->willReturn('admin');
3788
-		$this->userSession
3789
-			->expects($this->once())
3790
-			->method('getUser')
3791
-			->willReturn($loggedInUser);
3792
-		$this->groupManager
3793
-			->expects($this->once())
3794
-			->method('isAdmin')
3795
-			->willReturn(true);
3796
-
3797
-		$this->assertEquals([], $this->api->disableUser('RequestedUser')->getData());
3798
-	}
3799
-
3800
-	public function testGetCurrentUserLoggedIn(): void {
3801
-		$user = $this->createMock(IUser::class);
3802
-		$user->expects($this->once())->method('getUID')->willReturn('UID');
3803
-
3804
-		$this->userSession->expects($this->once())->method('getUser')
3805
-			->willReturn($user);
3806
-
3807
-		/** @var UsersController | MockObject $api */
3808
-		$api = $this->getMockBuilder(UsersController::class)
3809
-			->setConstructorArgs([
3810
-				'provisioning_api',
3811
-				$this->request,
3812
-				$this->userManager,
3813
-				$this->config,
3814
-				$this->groupManager,
3815
-				$this->userSession,
3816
-				$this->accountManager,
3817
-				$this->subAdminManager,
3818
-				$this->l10nFactory,
3819
-				$this->rootFolder,
3820
-				$this->urlGenerator,
3821
-				$this->logger,
3822
-				$this->newUserMailHelper,
3823
-				$this->secureRandom,
3824
-				$this->remoteWipe,
3825
-				$this->knownUserService,
3826
-				$this->eventDispatcher,
3827
-				$this->phoneNumberUtil,
3828
-			])
3829
-			->onlyMethods(['getUserData'])
3830
-			->getMock();
3831
-
3832
-		$api->expects($this->once())->method('getUserData')->with('UID', true)
3833
-			->willReturn(
3834
-				[
3835
-					'id' => 'UID',
3836
-					'enabled' => 'true',
3837
-					'quota' => ['DummyValue'],
3838
-					'email' => '[email protected]',
3839
-					'displayname' => 'Demo User',
3840
-					'display-name' => 'Demo User',
3841
-					'phone' => 'phone',
3842
-					'address' => 'address',
3843
-					'website' => 'website',
3844
-					'twitter' => 'twitter',
3845
-					'fediverse' => 'fediverse',
3846
-					'organisation' => 'organisation',
3847
-					'role' => 'role',
3848
-					'headline' => 'headline',
3849
-					'biography' => 'biography',
3850
-					'profile_enabled' => '1',
3851
-					'pronouns' => 'they/them',
3852
-				]
3853
-			);
3854
-
3855
-		$expected = [
3856
-			'id' => 'UID',
3857
-			'enabled' => 'true',
3858
-			'quota' => ['DummyValue'],
3859
-			'email' => '[email protected]',
3860
-			'displayname' => 'Demo User',
3861
-			'display-name' => 'Demo User',
3862
-			'phone' => 'phone',
3863
-			'address' => 'address',
3864
-			'website' => 'website',
3865
-			'twitter' => 'twitter',
3866
-			'fediverse' => 'fediverse',
3867
-			'organisation' => 'organisation',
3868
-			'role' => 'role',
3869
-			'headline' => 'headline',
3870
-			'biography' => 'biography',
3871
-			'profile_enabled' => '1',
3872
-			'pronouns' => 'they/them',
3873
-		];
3874
-
3875
-		$this->assertSame($expected, $api->getCurrentUser()->getData());
3876
-	}
3877
-
3878
-
3879
-	public function testGetCurrentUserNotLoggedIn(): void {
3880
-		$this->expectException(OCSException::class);
3881
-
3882
-
3883
-		$this->userSession->expects($this->once())->method('getUser')
3884
-			->willReturn(null);
3885
-
3886
-		$this->api->getCurrentUser();
3887
-	}
3888
-
3889
-	public function testGetUser(): void {
3890
-		$loggedInUser = $this->createMock(IUser::class);
3891
-		$loggedInUser
3892
-			->method('getUID')
3893
-			->willReturn('currentuser');
3894
-		$this->userSession
3895
-			->method('getUser')
3896
-			->willReturn($loggedInUser);
3897
-
3898
-		/** @var UsersController | MockObject $api */
3899
-		$api = $this->getMockBuilder(UsersController::class)
3900
-			->setConstructorArgs([
3901
-				'provisioning_api',
3902
-				$this->request,
3903
-				$this->userManager,
3904
-				$this->config,
3905
-				$this->groupManager,
3906
-				$this->userSession,
3907
-				$this->accountManager,
3908
-				$this->subAdminManager,
3909
-				$this->l10nFactory,
3910
-				$this->rootFolder,
3911
-				$this->urlGenerator,
3912
-				$this->logger,
3913
-				$this->newUserMailHelper,
3914
-				$this->secureRandom,
3915
-				$this->remoteWipe,
3916
-				$this->knownUserService,
3917
-				$this->eventDispatcher,
3918
-				$this->phoneNumberUtil,
3919
-			])
3920
-			->onlyMethods(['getUserData'])
3921
-			->getMock();
3922
-
3923
-		$expected = [
3924
-			'id' => 'UID',
3925
-			'enabled' => 'true',
3926
-			'quota' => ['DummyValue'],
3927
-			'email' => '[email protected]',
3928
-			'phone' => 'phone',
3929
-			'address' => 'address',
3930
-			'website' => 'website',
3931
-			'twitter' => 'twitter',
3932
-			'fediverse' => 'fediverse',
3933
-			'displayname' => 'Demo User',
3934
-			'display-name' => 'Demo User',
3935
-			'organisation' => 'organisation',
3936
-			'role' => 'role',
3937
-			'headline' => 'headline',
3938
-			'biography' => 'biography',
3939
-			'profile_enabled' => '1',
3940
-			'pronouns' => 'they/them',
3941
-		];
3942
-
3943
-		$api->expects($this->exactly(2))
3944
-			->method('getUserData')
3945
-			->withConsecutive(
3946
-				['uid', false],
3947
-				['currentuser', true],
3948
-			)
3949
-			->willReturn($expected);
3950
-
3951
-		$this->assertSame($expected, $api->getUser('uid')->getData());
3952
-
3953
-		$this->assertSame($expected, $api->getUser('currentuser')->getData());
3954
-	}
3955
-
3956
-
3957
-	public function testResendWelcomeMessageWithNotExistingTargetUser(): void {
3958
-		$this->expectException(OCSException::class);
3959
-		$this->expectExceptionCode(998);
3960
-
3961
-		$this->userManager
3962
-			->expects($this->once())
3963
-			->method('get')
3964
-			->with('NotExistingUser')
3965
-			->willReturn(null);
3966
-
3967
-		$this->api->resendWelcomeMessage('NotExistingUser');
3968
-	}
3969
-
3970
-
3971
-	public function testResendWelcomeMessageAsSubAdminAndUserIsNotAccessible(): void {
3972
-		$this->expectException(OCSException::class);
3973
-		$this->expectExceptionCode(998);
3974
-
3975
-		$loggedInUser = $this->getMockBuilder(IUser::class)
3976
-			->disableOriginalConstructor()
3977
-			->getMock();
3978
-		$loggedInUser
3979
-			->expects($this->exactly(2))
3980
-			->method('getUID')
3981
-			->willReturn('subadmin');
3982
-		$targetUser = $this->getMockBuilder(IUser::class)
3983
-			->disableOriginalConstructor()
3984
-			->getMock();
3985
-		$this->userSession
3986
-			->expects($this->once())
3987
-			->method('getUser')
3988
-			->willReturn($loggedInUser);
3989
-		$this->userManager
3990
-			->expects($this->once())
3991
-			->method('get')
3992
-			->with('UserToGet')
3993
-			->willReturn($targetUser);
3994
-		$this->groupManager
3995
-			->expects($this->once())
3996
-			->method('isAdmin')
3997
-			->with('subadmin')
3998
-			->willReturn(false);
3999
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
4000
-			->disableOriginalConstructor()
4001
-			->getMock();
4002
-		$subAdminManager
4003
-			->expects($this->once())
4004
-			->method('isUserAccessible')
4005
-			->with($loggedInUser, $targetUser)
4006
-			->willReturn(false);
4007
-		$this->groupManager
4008
-			->expects($this->once())
4009
-			->method('getSubAdmin')
4010
-			->willReturn($subAdminManager);
4011
-
4012
-		$this->api->resendWelcomeMessage('UserToGet');
4013
-	}
4014
-
4015
-
4016
-	public function testResendWelcomeMessageNoEmail(): void {
4017
-		$this->expectException(OCSException::class);
4018
-		$this->expectExceptionMessage('Email address not available');
4019
-		$this->expectExceptionCode(101);
4020
-
4021
-		$loggedInUser = $this->getMockBuilder(IUser::class)
4022
-			->disableOriginalConstructor()
4023
-			->getMock();
4024
-		$targetUser = $this->getMockBuilder(IUser::class)
4025
-			->disableOriginalConstructor()
4026
-			->getMock();
4027
-		$this->userSession
4028
-			->expects($this->once())
4029
-			->method('getUser')
4030
-			->willReturn($loggedInUser);
4031
-		$this->userManager
4032
-			->expects($this->once())
4033
-			->method('get')
4034
-			->with('UserToGet')
4035
-			->willReturn($targetUser);
4036
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
4037
-			->disableOriginalConstructor()
4038
-			->getMock();
4039
-		$subAdminManager
4040
-			->expects($this->once())
4041
-			->method('isUserAccessible')
4042
-			->with($loggedInUser, $targetUser)
4043
-			->willReturn(true);
4044
-		$this->groupManager
4045
-			->expects($this->once())
4046
-			->method('getSubAdmin')
4047
-			->willReturn($subAdminManager);
4048
-		$loggedInUser
4049
-			->expects($this->exactly(2))
4050
-			->method('getUID')
4051
-			->willReturn('logged-user-id');
4052
-		$targetUser
4053
-			->expects($this->once())
4054
-			->method('getEmailAddress')
4055
-			->willReturn('');
4056
-
4057
-		$this->api->resendWelcomeMessage('UserToGet');
4058
-	}
4059
-
4060
-
4061
-	public function testResendWelcomeMessageNullEmail(): void {
4062
-		$this->expectException(OCSException::class);
4063
-		$this->expectExceptionMessage('Email address not available');
4064
-		$this->expectExceptionCode(101);
4065
-
4066
-		$loggedInUser = $this->getMockBuilder(IUser::class)
4067
-			->disableOriginalConstructor()
4068
-			->getMock();
4069
-		$targetUser = $this->getMockBuilder(IUser::class)
4070
-			->disableOriginalConstructor()
4071
-			->getMock();
4072
-		$this->userSession
4073
-			->expects($this->once())
4074
-			->method('getUser')
4075
-			->willReturn($loggedInUser);
4076
-		$this->userManager
4077
-			->expects($this->once())
4078
-			->method('get')
4079
-			->with('UserToGet')
4080
-			->willReturn($targetUser);
4081
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
4082
-			->disableOriginalConstructor()
4083
-			->getMock();
4084
-		$subAdminManager
4085
-			->expects($this->once())
4086
-			->method('isUserAccessible')
4087
-			->with($loggedInUser, $targetUser)
4088
-			->willReturn(true);
4089
-		$this->groupManager
4090
-			->expects($this->once())
4091
-			->method('getSubAdmin')
4092
-			->willReturn($subAdminManager);
4093
-		$loggedInUser
4094
-			->expects($this->exactly(2))
4095
-			->method('getUID')
4096
-			->willReturn('logged-user-id');
4097
-		$targetUser
4098
-			->expects($this->once())
4099
-			->method('getEmailAddress')
4100
-			->willReturn(null);
4101
-
4102
-		$this->api->resendWelcomeMessage('UserToGet');
4103
-	}
4104
-
4105
-	public function testResendWelcomeMessageSuccess(): void {
4106
-		$loggedInUser = $this->getMockBuilder(IUser::class)
4107
-			->disableOriginalConstructor()
4108
-			->getMock();
4109
-		$targetUser = $this->getMockBuilder(IUser::class)
4110
-			->disableOriginalConstructor()
4111
-			->getMock();
4112
-		$loggedInUser
4113
-			->method('getUID')
4114
-			->willReturn('logged-user-id');
4115
-		$targetUser
4116
-			->method('getUID')
4117
-			->willReturn('user-id');
4118
-		$this->userSession
4119
-			->expects($this->once())
4120
-			->method('getUser')
4121
-			->willReturn($loggedInUser);
4122
-		$this->userManager
4123
-			->expects($this->once())
4124
-			->method('get')
4125
-			->with('UserToGet')
4126
-			->willReturn($targetUser);
4127
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
4128
-			->disableOriginalConstructor()
4129
-			->getMock();
4130
-		$subAdminManager
4131
-			->expects($this->once())
4132
-			->method('isUserAccessible')
4133
-			->with($loggedInUser, $targetUser)
4134
-			->willReturn(true);
4135
-		$this->groupManager
4136
-			->expects($this->once())
4137
-			->method('getSubAdmin')
4138
-			->willReturn($subAdminManager);
4139
-		$targetUser
4140
-			->expects($this->once())
4141
-			->method('getEmailAddress')
4142
-			->willReturn('[email protected]');
4143
-		$emailTemplate = $this->createMock(IEMailTemplate::class);
4144
-		$this->newUserMailHelper
4145
-			->expects($this->once())
4146
-			->method('generateTemplate')
4147
-			->willReturn($emailTemplate);
4148
-		$this->newUserMailHelper
4149
-			->expects($this->once())
4150
-			->method('sendMail')
4151
-			->with($targetUser, $emailTemplate);
4152
-
4153
-		$this->api->resendWelcomeMessage('UserToGet');
4154
-	}
4155
-
4156
-	public function testResendWelcomeMessageSuccessWithFallbackLanguage(): void {
4157
-		$loggedInUser = $this->getMockBuilder(IUser::class)
4158
-			->disableOriginalConstructor()
4159
-			->getMock();
4160
-		$targetUser = $this->getMockBuilder(IUser::class)
4161
-			->disableOriginalConstructor()
4162
-			->getMock();
4163
-		$loggedInUser
4164
-			->method('getUID')
4165
-			->willReturn('logged-user-id');
4166
-		$targetUser
4167
-			->method('getUID')
4168
-			->willReturn('user-id');
4169
-		$this->userSession
4170
-			->expects($this->once())
4171
-			->method('getUser')
4172
-			->willReturn($loggedInUser);
4173
-		$this->userManager
4174
-			->expects($this->once())
4175
-			->method('get')
4176
-			->with('UserToGet')
4177
-			->willReturn($targetUser);
4178
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
4179
-			->disableOriginalConstructor()
4180
-			->getMock();
4181
-		$subAdminManager
4182
-			->expects($this->once())
4183
-			->method('isUserAccessible')
4184
-			->with($loggedInUser, $targetUser)
4185
-			->willReturn(true);
4186
-		$this->groupManager
4187
-			->expects($this->once())
4188
-			->method('getSubAdmin')
4189
-			->willReturn($subAdminManager);
4190
-		$targetUser
4191
-			->expects($this->once())
4192
-			->method('getEmailAddress')
4193
-			->willReturn('[email protected]');
4194
-		$emailTemplate = $this->createMock(IEMailTemplate::class);
4195
-		$this->newUserMailHelper
4196
-			->expects($this->once())
4197
-			->method('generateTemplate')
4198
-			->willReturn($emailTemplate);
4199
-		$this->newUserMailHelper
4200
-			->expects($this->once())
4201
-			->method('sendMail')
4202
-			->with($targetUser, $emailTemplate);
4203
-
4204
-		$this->api->resendWelcomeMessage('UserToGet');
4205
-	}
4206
-
4207
-
4208
-	public function testResendWelcomeMessageFailed(): void {
4209
-		$this->expectException(OCSException::class);
4210
-		$this->expectExceptionMessage('Sending email failed');
4211
-		$this->expectExceptionCode(102);
4212
-
4213
-		$loggedInUser = $this->getMockBuilder(IUser::class)
4214
-			->disableOriginalConstructor()
4215
-			->getMock();
4216
-		$targetUser = $this->getMockBuilder(IUser::class)
4217
-			->disableOriginalConstructor()
4218
-			->getMock();
4219
-		$loggedInUser
4220
-			->expects($this->exactly(2))
4221
-			->method('getUID')
4222
-			->willReturn('logged-user-id');
4223
-		$targetUser
4224
-			->method('getUID')
4225
-			->willReturn('user-id');
4226
-		$this->userSession
4227
-			->expects($this->once())
4228
-			->method('getUser')
4229
-			->willReturn($loggedInUser);
4230
-		$this->userManager
4231
-			->expects($this->once())
4232
-			->method('get')
4233
-			->with('UserToGet')
4234
-			->willReturn($targetUser);
4235
-		$subAdminManager = $this->getMockBuilder('OC\SubAdmin')
4236
-			->disableOriginalConstructor()
4237
-			->getMock();
4238
-		$subAdminManager
4239
-			->expects($this->once())
4240
-			->method('isUserAccessible')
4241
-			->with($loggedInUser, $targetUser)
4242
-			->willReturn(true);
4243
-		$this->groupManager
4244
-			->expects($this->once())
4245
-			->method('getSubAdmin')
4246
-			->willReturn($subAdminManager);
4247
-		$targetUser
4248
-			->expects($this->once())
4249
-			->method('getEmailAddress')
4250
-			->willReturn('[email protected]');
4251
-		$emailTemplate = $this->createMock(IEMailTemplate::class);
4252
-		$this->newUserMailHelper
4253
-			->expects($this->once())
4254
-			->method('generateTemplate')
4255
-			->willReturn($emailTemplate);
4256
-		$this->newUserMailHelper
4257
-			->expects($this->once())
4258
-			->method('sendMail')
4259
-			->with($targetUser, $emailTemplate)
4260
-			->willThrowException(new \Exception());
4261
-
4262
-		$this->api->resendWelcomeMessage('UserToGet');
4263
-	}
4264
-
4265
-
4266
-	public function dataGetEditableFields() {
4267
-		return [
4268
-			[false, true, ISetDisplayNameBackend::class, [
4269
-				IAccountManager::PROPERTY_EMAIL,
4270
-				IAccountManager::COLLECTION_EMAIL,
4271
-				IAccountManager::PROPERTY_PHONE,
4272
-				IAccountManager::PROPERTY_ADDRESS,
4273
-				IAccountManager::PROPERTY_WEBSITE,
4274
-				IAccountManager::PROPERTY_TWITTER,
4275
-				IAccountManager::PROPERTY_FEDIVERSE,
4276
-				IAccountManager::PROPERTY_ORGANISATION,
4277
-				IAccountManager::PROPERTY_ROLE,
4278
-				IAccountManager::PROPERTY_HEADLINE,
4279
-				IAccountManager::PROPERTY_BIOGRAPHY,
4280
-				IAccountManager::PROPERTY_PROFILE_ENABLED,
4281
-				IAccountManager::PROPERTY_PRONOUNS,
4282
-			]],
4283
-			[true, false, ISetDisplayNameBackend::class, [
4284
-				IAccountManager::PROPERTY_DISPLAYNAME,
4285
-				IAccountManager::COLLECTION_EMAIL,
4286
-				IAccountManager::PROPERTY_PHONE,
4287
-				IAccountManager::PROPERTY_ADDRESS,
4288
-				IAccountManager::PROPERTY_WEBSITE,
4289
-				IAccountManager::PROPERTY_TWITTER,
4290
-				IAccountManager::PROPERTY_FEDIVERSE,
4291
-				IAccountManager::PROPERTY_ORGANISATION,
4292
-				IAccountManager::PROPERTY_ROLE,
4293
-				IAccountManager::PROPERTY_HEADLINE,
4294
-				IAccountManager::PROPERTY_BIOGRAPHY,
4295
-				IAccountManager::PROPERTY_PROFILE_ENABLED,
4296
-				IAccountManager::PROPERTY_PRONOUNS,
4297
-			]],
4298
-			[true, true, ISetDisplayNameBackend::class, [
4299
-				IAccountManager::PROPERTY_DISPLAYNAME,
4300
-				IAccountManager::PROPERTY_EMAIL,
4301
-				IAccountManager::COLLECTION_EMAIL,
4302
-				IAccountManager::PROPERTY_PHONE,
4303
-				IAccountManager::PROPERTY_ADDRESS,
4304
-				IAccountManager::PROPERTY_WEBSITE,
4305
-				IAccountManager::PROPERTY_TWITTER,
4306
-				IAccountManager::PROPERTY_FEDIVERSE,
4307
-				IAccountManager::PROPERTY_ORGANISATION,
4308
-				IAccountManager::PROPERTY_ROLE,
4309
-				IAccountManager::PROPERTY_HEADLINE,
4310
-				IAccountManager::PROPERTY_BIOGRAPHY,
4311
-				IAccountManager::PROPERTY_PROFILE_ENABLED,
4312
-				IAccountManager::PROPERTY_PRONOUNS,
4313
-			]],
4314
-			[false, false, ISetDisplayNameBackend::class, [
4315
-				IAccountManager::COLLECTION_EMAIL,
4316
-				IAccountManager::PROPERTY_PHONE,
4317
-				IAccountManager::PROPERTY_ADDRESS,
4318
-				IAccountManager::PROPERTY_WEBSITE,
4319
-				IAccountManager::PROPERTY_TWITTER,
4320
-				IAccountManager::PROPERTY_FEDIVERSE,
4321
-				IAccountManager::PROPERTY_ORGANISATION,
4322
-				IAccountManager::PROPERTY_ROLE,
4323
-				IAccountManager::PROPERTY_HEADLINE,
4324
-				IAccountManager::PROPERTY_BIOGRAPHY,
4325
-				IAccountManager::PROPERTY_PROFILE_ENABLED,
4326
-				IAccountManager::PROPERTY_PRONOUNS,
4327
-			]],
4328
-			[false, true, UserInterface::class, [
4329
-				IAccountManager::PROPERTY_EMAIL,
4330
-				IAccountManager::COLLECTION_EMAIL,
4331
-				IAccountManager::PROPERTY_PHONE,
4332
-				IAccountManager::PROPERTY_ADDRESS,
4333
-				IAccountManager::PROPERTY_WEBSITE,
4334
-				IAccountManager::PROPERTY_TWITTER,
4335
-				IAccountManager::PROPERTY_FEDIVERSE,
4336
-				IAccountManager::PROPERTY_ORGANISATION,
4337
-				IAccountManager::PROPERTY_ROLE,
4338
-				IAccountManager::PROPERTY_HEADLINE,
4339
-				IAccountManager::PROPERTY_BIOGRAPHY,
4340
-				IAccountManager::PROPERTY_PROFILE_ENABLED,
4341
-				IAccountManager::PROPERTY_PRONOUNS,
4342
-			]],
4343
-			[true, false, UserInterface::class, [
4344
-				IAccountManager::COLLECTION_EMAIL,
4345
-				IAccountManager::PROPERTY_PHONE,
4346
-				IAccountManager::PROPERTY_ADDRESS,
4347
-				IAccountManager::PROPERTY_WEBSITE,
4348
-				IAccountManager::PROPERTY_TWITTER,
4349
-				IAccountManager::PROPERTY_FEDIVERSE,
4350
-				IAccountManager::PROPERTY_ORGANISATION,
4351
-				IAccountManager::PROPERTY_ROLE,
4352
-				IAccountManager::PROPERTY_HEADLINE,
4353
-				IAccountManager::PROPERTY_BIOGRAPHY,
4354
-				IAccountManager::PROPERTY_PROFILE_ENABLED,
4355
-				IAccountManager::PROPERTY_PRONOUNS,
4356
-			]],
4357
-			[true, true, UserInterface::class, [
4358
-				IAccountManager::PROPERTY_EMAIL,
4359
-				IAccountManager::COLLECTION_EMAIL,
4360
-				IAccountManager::PROPERTY_PHONE,
4361
-				IAccountManager::PROPERTY_ADDRESS,
4362
-				IAccountManager::PROPERTY_WEBSITE,
4363
-				IAccountManager::PROPERTY_TWITTER,
4364
-				IAccountManager::PROPERTY_FEDIVERSE,
4365
-				IAccountManager::PROPERTY_ORGANISATION,
4366
-				IAccountManager::PROPERTY_ROLE,
4367
-				IAccountManager::PROPERTY_HEADLINE,
4368
-				IAccountManager::PROPERTY_BIOGRAPHY,
4369
-				IAccountManager::PROPERTY_PROFILE_ENABLED,
4370
-				IAccountManager::PROPERTY_PRONOUNS,
4371
-			]],
4372
-			[false, false, UserInterface::class, [
4373
-				IAccountManager::COLLECTION_EMAIL,
4374
-				IAccountManager::PROPERTY_PHONE,
4375
-				IAccountManager::PROPERTY_ADDRESS,
4376
-				IAccountManager::PROPERTY_WEBSITE,
4377
-				IAccountManager::PROPERTY_TWITTER,
4378
-				IAccountManager::PROPERTY_FEDIVERSE,
4379
-				IAccountManager::PROPERTY_ORGANISATION,
4380
-				IAccountManager::PROPERTY_ROLE,
4381
-				IAccountManager::PROPERTY_HEADLINE,
4382
-				IAccountManager::PROPERTY_BIOGRAPHY,
4383
-				IAccountManager::PROPERTY_PROFILE_ENABLED,
4384
-				IAccountManager::PROPERTY_PRONOUNS,
4385
-			]],
4386
-		];
4387
-	}
4388
-
4389
-	/**
4390
-	 * @dataProvider dataGetEditableFields
4391
-	 *
4392
-	 * @param bool $allowedToChangeDisplayName
4393
-	 * @param string $userBackend
4394
-	 * @param array $expected
4395
-	 */
4396
-	public function testGetEditableFields(bool $allowedToChangeDisplayName, bool $allowedToChangeEmail, string $userBackend, array $expected): void {
4397
-		$this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => match ($key) {
4398
-			'allow_user_to_change_display_name' => $allowedToChangeDisplayName,
4399
-			'allow_user_to_change_email' => $allowedToChangeEmail,
4400
-			default => throw new RuntimeException('Unexpected system config key: ' . $key),
4401
-		});
4402
-
4403
-		$user = $this->createMock(IUser::class);
4404
-		$this->userSession->method('getUser')
4405
-			->willReturn($user);
4406
-
4407
-		$backend = $this->createMock($userBackend);
4408
-
4409
-		$user->method('getUID')
4410
-			->willReturn('userId');
4411
-		$user->method('getBackend')
4412
-			->willReturn($backend);
4413
-
4414
-		$expectedResp = new DataResponse($expected);
4415
-		$this->assertEquals($expectedResp, $this->api->getEditableFields('userId'));
4416
-	}
4417
-
4418
-	private function mockAccount($targetUser, $accountProperties) {
4419
-		$mockedProperties = [];
4420
-
4421
-		foreach ($accountProperties as $propertyName => $data) {
4422
-			$mockedProperty = $this->createMock(IAccountProperty::class);
4423
-			$mockedProperty->method('getValue')->willReturn($data['value'] ?? '');
4424
-			$mockedProperty->method('getScope')->willReturn($data['scope'] ?? '');
4425
-			$mockedProperties[] = [$propertyName, $mockedProperty];
4426
-		}
4427
-
4428
-		$account = $this->createMock(IAccount::class);
4429
-		$account->method('getProperty')
4430
-			->will($this->returnValueMap($mockedProperties));
4431
-
4432
-		$this->accountManager->expects($this->any())->method('getAccount')
4433
-			->with($targetUser)
4434
-			->willReturn($account);
4435
-	}
3089
+
3090
+        $subAdminManager = $this->createMock(SubAdmin::class);
3091
+        $subAdminManager->expects($this->once())
3092
+            ->method('isSubAdminOfGroup')
3093
+            ->with($loggedInUser, $targetGroup)
3094
+            ->willReturn(true);
3095
+
3096
+        $this->groupManager->expects($this->once())
3097
+            ->method('getSubAdmin')
3098
+            ->willReturn($subAdminManager);
3099
+        $this->groupManager->expects($this->once())
3100
+            ->method('isAdmin')
3101
+            ->with('subadmin')
3102
+            ->willReturn(false);
3103
+
3104
+        $this->userManager->expects($this->once())
3105
+            ->method('get')
3106
+            ->with('TargetUser')
3107
+            ->willReturn($targetUser);
3108
+
3109
+        $this->userSession->expects($this->once())
3110
+            ->method('getUser')
3111
+            ->willReturn($loggedInUser);
3112
+
3113
+        $this->assertEquals(new DataResponse(), $this->api->addToGroup('TargetUser', 'GroupToAddTo'));
3114
+    }
3115
+
3116
+    public function testAddToGroupSuccessAsAdmin(): void {
3117
+        $targetUser = $this->createMock(IUser::class);
3118
+        $loggedInUser = $this->createMock(IUser::class);
3119
+        $loggedInUser->expects($this->exactly(2))
3120
+            ->method('getUID')
3121
+            ->willReturn('admin');
3122
+
3123
+        $targetGroup = $this->createMock(IGroup::class);
3124
+        $targetGroup->expects($this->once())
3125
+            ->method('addUser')
3126
+            ->with($targetUser);
3127
+
3128
+        $this->groupManager->expects($this->once())
3129
+            ->method('get')
3130
+            ->with('GroupToAddTo')
3131
+            ->willReturn($targetGroup);
3132
+
3133
+
3134
+        $subAdminManager = $this->createMock(SubAdmin::class);
3135
+        $subAdminManager->expects($this->never())
3136
+            ->method('isSubAdminOfGroup');
3137
+
3138
+        $this->groupManager->expects($this->once())
3139
+            ->method('getSubAdmin')
3140
+            ->willReturn($subAdminManager);
3141
+        $this->groupManager->expects($this->once())
3142
+            ->method('isAdmin')
3143
+            ->with('admin')
3144
+            ->willReturn(true);
3145
+
3146
+        $this->userManager->expects($this->once())
3147
+            ->method('get')
3148
+            ->with('TargetUser')
3149
+            ->willReturn($targetUser);
3150
+
3151
+        $this->userSession->expects($this->once())
3152
+            ->method('getUser')
3153
+            ->willReturn($loggedInUser);
3154
+
3155
+        $this->assertEquals(new DataResponse(), $this->api->addToGroup('TargetUser', 'GroupToAddTo'));
3156
+    }
3157
+
3158
+
3159
+    public function testRemoveFromGroupWithNoTargetGroup(): void {
3160
+        $this->expectException(OCSException::class);
3161
+        $this->expectExceptionCode(101);
3162
+
3163
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3164
+        $this->userSession
3165
+            ->expects($this->once())
3166
+            ->method('getUser')
3167
+            ->willReturn($loggedInUser);
3168
+
3169
+        $this->api->removeFromGroup('TargetUser', '');
3170
+    }
3171
+
3172
+
3173
+    public function testRemoveFromGroupWithEmptyTargetGroup(): void {
3174
+        $this->expectException(OCSException::class);
3175
+        $this->expectExceptionCode(101);
3176
+
3177
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3178
+        $this->userSession
3179
+            ->expects($this->once())
3180
+            ->method('getUser')
3181
+            ->willReturn($loggedInUser);
3182
+
3183
+        $this->api->removeFromGroup('TargetUser', '');
3184
+    }
3185
+
3186
+
3187
+    public function testRemoveFromGroupWithNotExistingTargetGroup(): void {
3188
+        $this->expectException(OCSException::class);
3189
+        $this->expectExceptionCode(102);
3190
+
3191
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3192
+        $this->userSession
3193
+            ->expects($this->once())
3194
+            ->method('getUser')
3195
+            ->willReturn($loggedInUser);
3196
+        $this->groupManager
3197
+            ->expects($this->once())
3198
+            ->method('get')
3199
+            ->with('TargetGroup')
3200
+            ->willReturn(null);
3201
+
3202
+        $this->api->removeFromGroup('TargetUser', 'TargetGroup');
3203
+    }
3204
+
3205
+
3206
+    public function testRemoveFromGroupWithNotExistingTargetUser(): void {
3207
+        $this->expectException(OCSException::class);
3208
+        $this->expectExceptionCode(103);
3209
+
3210
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3211
+        $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3212
+        $this->userSession
3213
+            ->expects($this->once())
3214
+            ->method('getUser')
3215
+            ->willReturn($loggedInUser);
3216
+        $this->groupManager
3217
+            ->expects($this->once())
3218
+            ->method('get')
3219
+            ->with('TargetGroup')
3220
+            ->willReturn($targetGroup);
3221
+        $this->userManager
3222
+            ->expects($this->once())
3223
+            ->method('get')
3224
+            ->with('TargetUser')
3225
+            ->willReturn(null);
3226
+
3227
+        $this->api->removeFromGroup('TargetUser', 'TargetGroup');
3228
+    }
3229
+
3230
+
3231
+    public function testRemoveFromGroupWithoutPermission(): void {
3232
+        $this->expectException(OCSException::class);
3233
+        $this->expectExceptionCode(104);
3234
+
3235
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3236
+        $loggedInUser
3237
+            ->expects($this->exactly(2))
3238
+            ->method('getUID')
3239
+            ->willReturn('unauthorizedUser');
3240
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3241
+        $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3242
+        $this->userSession
3243
+            ->expects($this->once())
3244
+            ->method('getUser')
3245
+            ->willReturn($loggedInUser);
3246
+        $this->groupManager
3247
+            ->expects($this->once())
3248
+            ->method('get')
3249
+            ->with('TargetGroup')
3250
+            ->willReturn($targetGroup);
3251
+        $this->userManager
3252
+            ->expects($this->once())
3253
+            ->method('get')
3254
+            ->with('TargetUser')
3255
+            ->willReturn($targetUser);
3256
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3257
+            ->disableOriginalConstructor()->getMock();
3258
+        $this->groupManager
3259
+            ->expects($this->once())
3260
+            ->method('getSubAdmin')
3261
+            ->willReturn($subAdminManager);
3262
+        $this->groupManager
3263
+            ->expects($this->once())
3264
+            ->method('isAdmin')
3265
+            ->with('unauthorizedUser')
3266
+            ->willReturn(false);
3267
+
3268
+        $this->api->removeFromGroup('TargetUser', 'TargetGroup');
3269
+    }
3270
+
3271
+
3272
+    public function testRemoveFromGroupAsAdminFromAdmin(): void {
3273
+        $this->expectException(OCSException::class);
3274
+        $this->expectExceptionMessage('Cannot remove yourself from the admin group');
3275
+        $this->expectExceptionCode(105);
3276
+
3277
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3278
+        $loggedInUser
3279
+            ->expects($this->any())
3280
+            ->method('getUID')
3281
+            ->willReturn('admin');
3282
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3283
+        $targetUser
3284
+            ->expects($this->once())
3285
+            ->method('getUID')
3286
+            ->willReturn('admin');
3287
+        $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3288
+        $targetGroup
3289
+            ->expects($this->once())
3290
+            ->method('getGID')
3291
+            ->willReturn('admin');
3292
+        $this->userSession
3293
+            ->expects($this->once())
3294
+            ->method('getUser')
3295
+            ->willReturn($loggedInUser);
3296
+        $this->groupManager
3297
+            ->expects($this->once())
3298
+            ->method('get')
3299
+            ->with('admin')
3300
+            ->willReturn($targetGroup);
3301
+        $this->userManager
3302
+            ->expects($this->once())
3303
+            ->method('get')
3304
+            ->with('Admin')
3305
+            ->willReturn($targetUser);
3306
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3307
+            ->disableOriginalConstructor()->getMock();
3308
+        $this->groupManager
3309
+            ->expects($this->once())
3310
+            ->method('getSubAdmin')
3311
+            ->willReturn($subAdminManager);
3312
+        $this->groupManager
3313
+            ->expects($this->any())
3314
+            ->method('isAdmin')
3315
+            ->with('admin')
3316
+            ->willReturn(true);
3317
+
3318
+        $this->api->removeFromGroup('Admin', 'admin');
3319
+    }
3320
+
3321
+
3322
+    public function testRemoveFromGroupAsSubAdminFromSubAdmin(): void {
3323
+        $this->expectException(OCSException::class);
3324
+        $this->expectExceptionMessage('Cannot remove yourself from this group as you are a sub-admin');
3325
+        $this->expectExceptionCode(105);
3326
+
3327
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3328
+        $loggedInUser
3329
+            ->expects($this->any())
3330
+            ->method('getUID')
3331
+            ->willReturn('subadmin');
3332
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3333
+        $targetUser
3334
+            ->expects($this->once())
3335
+            ->method('getUID')
3336
+            ->willReturn('subadmin');
3337
+        $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3338
+        $targetGroup
3339
+            ->expects($this->any())
3340
+            ->method('getGID')
3341
+            ->willReturn('subadmin');
3342
+        $this->userSession
3343
+            ->expects($this->once())
3344
+            ->method('getUser')
3345
+            ->willReturn($loggedInUser);
3346
+        $this->groupManager
3347
+            ->expects($this->once())
3348
+            ->method('get')
3349
+            ->with('subadmin')
3350
+            ->willReturn($targetGroup);
3351
+        $this->userManager
3352
+            ->expects($this->once())
3353
+            ->method('get')
3354
+            ->with('SubAdmin')
3355
+            ->willReturn($targetUser);
3356
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3357
+            ->disableOriginalConstructor()->getMock();
3358
+        $subAdminManager
3359
+            ->expects($this->once())
3360
+            ->method('isSubAdminOfGroup')
3361
+            ->with($loggedInUser, $targetGroup)
3362
+            ->willReturn(true);
3363
+        $this->groupManager
3364
+            ->expects($this->once())
3365
+            ->method('getSubAdmin')
3366
+            ->willReturn($subAdminManager);
3367
+        $this->groupManager
3368
+            ->expects($this->any())
3369
+            ->method('isAdmin')
3370
+            ->with('subadmin')
3371
+            ->willReturn(false);
3372
+
3373
+        $this->api->removeFromGroup('SubAdmin', 'subadmin');
3374
+    }
3375
+
3376
+
3377
+    public function testRemoveFromGroupAsSubAdminFromLastSubAdminGroup(): void {
3378
+        $this->expectException(OCSException::class);
3379
+        $this->expectExceptionMessage('Not viable to remove user from the last group you are sub-admin of');
3380
+        $this->expectExceptionCode(105);
3381
+
3382
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3383
+        $loggedInUser
3384
+            ->expects($this->any())
3385
+            ->method('getUID')
3386
+            ->willReturn('subadmin');
3387
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3388
+        $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3389
+        $targetGroup
3390
+            ->expects($this->any())
3391
+            ->method('getGID')
3392
+            ->willReturn('subadmin');
3393
+        $this->userSession
3394
+            ->expects($this->once())
3395
+            ->method('getUser')
3396
+            ->willReturn($loggedInUser);
3397
+        $this->groupManager
3398
+            ->expects($this->once())
3399
+            ->method('get')
3400
+            ->with('subadmin')
3401
+            ->willReturn($targetGroup);
3402
+        $this->userManager
3403
+            ->expects($this->once())
3404
+            ->method('get')
3405
+            ->with('AnotherUser')
3406
+            ->willReturn($targetUser);
3407
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3408
+            ->disableOriginalConstructor()->getMock();
3409
+        $subAdminManager
3410
+            ->expects($this->once())
3411
+            ->method('isSubAdminOfGroup')
3412
+            ->with($loggedInUser, $targetGroup)
3413
+            ->willReturn(true);
3414
+        $this->groupManager
3415
+            ->expects($this->once())
3416
+            ->method('getSubAdmin')
3417
+            ->willReturn($subAdminManager);
3418
+        $subAdminManager
3419
+            ->expects($this->once())
3420
+            ->method('getSubAdminsGroups')
3421
+            ->with($loggedInUser)
3422
+            ->willReturn([$targetGroup]);
3423
+
3424
+        $this->groupManager
3425
+            ->expects($this->any())
3426
+            ->method('isAdmin')
3427
+            ->with('subadmin')
3428
+            ->willReturn(false);
3429
+        $this->groupManager
3430
+            ->expects($this->once())
3431
+            ->method('getUserGroupIds')
3432
+            ->with($targetUser)
3433
+            ->willReturn(['subadmin', 'other group']);
3434
+
3435
+        $this->api->removeFromGroup('AnotherUser', 'subadmin');
3436
+    }
3437
+
3438
+    public function testRemoveFromGroupSuccessful(): void {
3439
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3440
+        $loggedInUser
3441
+            ->expects($this->any())
3442
+            ->method('getUID')
3443
+            ->willReturn('admin');
3444
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3445
+        $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3446
+        $this->userSession
3447
+            ->expects($this->once())
3448
+            ->method('getUser')
3449
+            ->willReturn($loggedInUser);
3450
+        $this->groupManager
3451
+            ->expects($this->once())
3452
+            ->method('get')
3453
+            ->with('admin')
3454
+            ->willReturn($targetGroup);
3455
+        $this->userManager
3456
+            ->expects($this->once())
3457
+            ->method('get')
3458
+            ->with('AnotherUser')
3459
+            ->willReturn($targetUser);
3460
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3461
+            ->disableOriginalConstructor()->getMock();
3462
+        $this->groupManager
3463
+            ->expects($this->once())
3464
+            ->method('getSubAdmin')
3465
+            ->willReturn($subAdminManager);
3466
+        $this->groupManager
3467
+            ->expects($this->any())
3468
+            ->method('isAdmin')
3469
+            ->with('admin')
3470
+            ->willReturn(true);
3471
+        $targetGroup
3472
+            ->expects($this->once())
3473
+            ->method('removeUser')
3474
+            ->with($targetUser);
3475
+
3476
+        $this->assertEquals([], $this->api->removeFromGroup('AnotherUser', 'admin')->getData());
3477
+    }
3478
+
3479
+
3480
+    public function testAddSubAdminWithNotExistingTargetUser(): void {
3481
+        $this->expectException(OCSException::class);
3482
+        $this->expectExceptionMessage('User does not exist');
3483
+        $this->expectExceptionCode(101);
3484
+
3485
+        $this->userManager
3486
+            ->expects($this->once())
3487
+            ->method('get')
3488
+            ->with('NotExistingUser')
3489
+            ->willReturn(null);
3490
+
3491
+        $this->api->addSubAdmin('NotExistingUser', '');
3492
+    }
3493
+
3494
+
3495
+    public function testAddSubAdminWithNotExistingTargetGroup(): void {
3496
+        $this->expectException(OCSException::class);
3497
+        $this->expectExceptionMessage('Group does not exist');
3498
+        $this->expectExceptionCode(102);
3499
+
3500
+
3501
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3502
+        $this->userManager
3503
+            ->expects($this->once())
3504
+            ->method('get')
3505
+            ->with('ExistingUser')
3506
+            ->willReturn($targetUser);
3507
+        $this->groupManager
3508
+            ->expects($this->once())
3509
+            ->method('get')
3510
+            ->with('NotExistingGroup')
3511
+            ->willReturn(null);
3512
+
3513
+        $this->api->addSubAdmin('ExistingUser', 'NotExistingGroup');
3514
+    }
3515
+
3516
+
3517
+    public function testAddSubAdminToAdminGroup(): void {
3518
+        $this->expectException(OCSException::class);
3519
+        $this->expectExceptionMessage('Cannot create sub-admins for admin group');
3520
+        $this->expectExceptionCode(103);
3521
+
3522
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3523
+        $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3524
+        $targetGroup
3525
+            ->expects($this->once())
3526
+            ->method('getGID')
3527
+            ->willReturn('admin');
3528
+        $this->userManager
3529
+            ->expects($this->once())
3530
+            ->method('get')
3531
+            ->with('ExistingUser')
3532
+            ->willReturn($targetUser);
3533
+        $this->groupManager
3534
+            ->expects($this->once())
3535
+            ->method('get')
3536
+            ->with('ADmiN')
3537
+            ->willReturn($targetGroup);
3538
+
3539
+        $this->api->addSubAdmin('ExistingUser', 'ADmiN');
3540
+    }
3541
+
3542
+    public function testAddSubAdminTwice(): void {
3543
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3544
+        $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3545
+        $this->userManager
3546
+            ->expects($this->once())
3547
+            ->method('get')
3548
+            ->with('ExistingUser')
3549
+            ->willReturn($targetUser);
3550
+        $this->groupManager
3551
+            ->expects($this->once())
3552
+            ->method('get')
3553
+            ->with('TargetGroup')
3554
+            ->willReturn($targetGroup);
3555
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3556
+            ->disableOriginalConstructor()->getMock();
3557
+        $subAdminManager
3558
+            ->expects($this->once())
3559
+            ->method('isSubAdminOfGroup')
3560
+            ->with($targetUser, $targetGroup)
3561
+            ->willReturn(true);
3562
+        $this->groupManager
3563
+            ->expects($this->once())
3564
+            ->method('getSubAdmin')
3565
+            ->willReturn($subAdminManager);
3566
+
3567
+        $this->assertEquals([], $this->api->addSubAdmin('ExistingUser', 'TargetGroup')->getData());
3568
+    }
3569
+
3570
+    public function testAddSubAdminSuccessful(): void {
3571
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3572
+        $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3573
+        $this->userManager
3574
+            ->expects($this->once())
3575
+            ->method('get')
3576
+            ->with('ExistingUser')
3577
+            ->willReturn($targetUser);
3578
+        $this->groupManager
3579
+            ->expects($this->once())
3580
+            ->method('get')
3581
+            ->with('TargetGroup')
3582
+            ->willReturn($targetGroup);
3583
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3584
+            ->disableOriginalConstructor()->getMock();
3585
+        $subAdminManager
3586
+            ->expects($this->once())
3587
+            ->method('isSubAdminOfGroup')
3588
+            ->with($targetUser, $targetGroup)
3589
+            ->willReturn(false);
3590
+        $subAdminManager
3591
+            ->expects($this->once())
3592
+            ->method('createSubAdmin')
3593
+            ->with($targetUser, $targetGroup);
3594
+        $this->groupManager
3595
+            ->expects($this->once())
3596
+            ->method('getSubAdmin')
3597
+            ->willReturn($subAdminManager);
3598
+
3599
+        $this->assertEquals([], $this->api->addSubAdmin('ExistingUser', 'TargetGroup')->getData());
3600
+    }
3601
+
3602
+
3603
+    public function testRemoveSubAdminNotExistingTargetUser(): void {
3604
+        $this->expectException(OCSException::class);
3605
+        $this->expectExceptionMessage('User does not exist');
3606
+        $this->expectExceptionCode(101);
3607
+
3608
+        $this->userManager
3609
+            ->expects($this->once())
3610
+            ->method('get')
3611
+            ->with('NotExistingUser')
3612
+            ->willReturn(null);
3613
+
3614
+        $this->api->removeSubAdmin('NotExistingUser', 'GroupToDeleteFrom');
3615
+    }
3616
+
3617
+
3618
+    public function testRemoveSubAdminNotExistingTargetGroup(): void {
3619
+        $this->expectException(OCSException::class);
3620
+        $this->expectExceptionMessage('Group does not exist');
3621
+        $this->expectExceptionCode(101);
3622
+
3623
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3624
+        $this->userManager
3625
+            ->expects($this->once())
3626
+            ->method('get')
3627
+            ->with('ExistingUser')
3628
+            ->willReturn($targetUser);
3629
+        $this->groupManager
3630
+            ->expects($this->once())
3631
+            ->method('get')
3632
+            ->with('GroupToDeleteFrom')
3633
+            ->willReturn(null);
3634
+
3635
+        $this->api->removeSubAdmin('ExistingUser', 'GroupToDeleteFrom');
3636
+    }
3637
+
3638
+
3639
+
3640
+    public function testRemoveSubAdminFromNotASubadmin(): void {
3641
+        $this->expectException(OCSException::class);
3642
+        $this->expectExceptionMessage('User is not a sub-admin of this group');
3643
+        $this->expectExceptionCode(102);
3644
+
3645
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3646
+        $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3647
+        $this->userManager
3648
+            ->expects($this->once())
3649
+            ->method('get')
3650
+            ->with('ExistingUser')
3651
+            ->willReturn($targetUser);
3652
+        $this->groupManager
3653
+            ->expects($this->once())
3654
+            ->method('get')
3655
+            ->with('GroupToDeleteFrom')
3656
+            ->willReturn($targetGroup);
3657
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3658
+            ->disableOriginalConstructor()->getMock();
3659
+        $subAdminManager
3660
+            ->expects($this->once())
3661
+            ->method('isSubAdminOfGroup')
3662
+            ->with($targetUser, $targetGroup)
3663
+            ->willReturn(false);
3664
+        $this->groupManager
3665
+            ->expects($this->once())
3666
+            ->method('getSubAdmin')
3667
+            ->willReturn($subAdminManager);
3668
+
3669
+        $this->api->removeSubAdmin('ExistingUser', 'GroupToDeleteFrom');
3670
+    }
3671
+
3672
+    public function testRemoveSubAdminSuccessful(): void {
3673
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3674
+        $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3675
+        $this->userManager
3676
+            ->expects($this->once())
3677
+            ->method('get')
3678
+            ->with('ExistingUser')
3679
+            ->willReturn($targetUser);
3680
+        $this->groupManager
3681
+            ->expects($this->once())
3682
+            ->method('get')
3683
+            ->with('GroupToDeleteFrom')
3684
+            ->willReturn($targetGroup);
3685
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3686
+            ->disableOriginalConstructor()->getMock();
3687
+        $subAdminManager
3688
+            ->expects($this->once())
3689
+            ->method('isSubAdminOfGroup')
3690
+            ->with($targetUser, $targetGroup)
3691
+            ->willReturn(true);
3692
+        $subAdminManager
3693
+            ->expects($this->once())
3694
+            ->method('deleteSubAdmin')
3695
+            ->with($targetUser, $targetGroup);
3696
+        $this->groupManager
3697
+            ->expects($this->once())
3698
+            ->method('getSubAdmin')
3699
+            ->willReturn($subAdminManager);
3700
+
3701
+        $this->assertEquals([], $this->api->removeSubAdmin('ExistingUser', 'GroupToDeleteFrom')->getData());
3702
+    }
3703
+
3704
+
3705
+    public function testGetUserSubAdminGroupsNotExistingTargetUser(): void {
3706
+        $this->expectException(OCSException::class);
3707
+        $this->expectExceptionMessage('User does not exist');
3708
+        $this->expectExceptionCode(404);
3709
+
3710
+        $this->userManager
3711
+            ->expects($this->once())
3712
+            ->method('get')
3713
+            ->with('RequestedUser')
3714
+            ->willReturn(null);
3715
+
3716
+        $this->api->getUserSubAdminGroups('RequestedUser');
3717
+    }
3718
+
3719
+    public function testGetUserSubAdminGroupsWithGroups(): void {
3720
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3721
+        $targetGroup = $this->getMockBuilder('\OCP\IGroup')->disableOriginalConstructor()->getMock();
3722
+        $targetGroup
3723
+            ->expects($this->once())
3724
+            ->method('getGID')
3725
+            ->willReturn('TargetGroup');
3726
+        $this->userManager
3727
+            ->expects($this->once())
3728
+            ->method('get')
3729
+            ->with('RequestedUser')
3730
+            ->willReturn($targetUser);
3731
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
3732
+            ->disableOriginalConstructor()->getMock();
3733
+        $subAdminManager
3734
+            ->expects($this->once())
3735
+            ->method('getSubAdminsGroups')
3736
+            ->with($targetUser)
3737
+            ->willReturn([$targetGroup]);
3738
+        $this->groupManager
3739
+            ->expects($this->once())
3740
+            ->method('getSubAdmin')
3741
+            ->willReturn($subAdminManager);
3742
+
3743
+        $this->assertEquals(['TargetGroup'], $this->api->getUserSubAdminGroups('RequestedUser')->getData());
3744
+    }
3745
+
3746
+    public function testEnableUser(): void {
3747
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3748
+        $targetUser->expects($this->once())
3749
+            ->method('setEnabled')
3750
+            ->with(true);
3751
+        $this->userManager
3752
+            ->expects($this->once())
3753
+            ->method('get')
3754
+            ->with('RequestedUser')
3755
+            ->willReturn($targetUser);
3756
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3757
+        $loggedInUser
3758
+            ->expects($this->exactly(3))
3759
+            ->method('getUID')
3760
+            ->willReturn('admin');
3761
+        $this->userSession
3762
+            ->expects($this->once())
3763
+            ->method('getUser')
3764
+            ->willReturn($loggedInUser);
3765
+        $this->groupManager
3766
+            ->expects($this->once())
3767
+            ->method('isAdmin')
3768
+            ->willReturn(true);
3769
+
3770
+        $this->assertEquals([], $this->api->enableUser('RequestedUser')->getData());
3771
+    }
3772
+
3773
+    public function testDisableUser(): void {
3774
+        $targetUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3775
+        $targetUser->expects($this->once())
3776
+            ->method('setEnabled')
3777
+            ->with(false);
3778
+        $this->userManager
3779
+            ->expects($this->once())
3780
+            ->method('get')
3781
+            ->with('RequestedUser')
3782
+            ->willReturn($targetUser);
3783
+        $loggedInUser = $this->getMockBuilder(IUser::class)->disableOriginalConstructor()->getMock();
3784
+        $loggedInUser
3785
+            ->expects($this->exactly(3))
3786
+            ->method('getUID')
3787
+            ->willReturn('admin');
3788
+        $this->userSession
3789
+            ->expects($this->once())
3790
+            ->method('getUser')
3791
+            ->willReturn($loggedInUser);
3792
+        $this->groupManager
3793
+            ->expects($this->once())
3794
+            ->method('isAdmin')
3795
+            ->willReturn(true);
3796
+
3797
+        $this->assertEquals([], $this->api->disableUser('RequestedUser')->getData());
3798
+    }
3799
+
3800
+    public function testGetCurrentUserLoggedIn(): void {
3801
+        $user = $this->createMock(IUser::class);
3802
+        $user->expects($this->once())->method('getUID')->willReturn('UID');
3803
+
3804
+        $this->userSession->expects($this->once())->method('getUser')
3805
+            ->willReturn($user);
3806
+
3807
+        /** @var UsersController | MockObject $api */
3808
+        $api = $this->getMockBuilder(UsersController::class)
3809
+            ->setConstructorArgs([
3810
+                'provisioning_api',
3811
+                $this->request,
3812
+                $this->userManager,
3813
+                $this->config,
3814
+                $this->groupManager,
3815
+                $this->userSession,
3816
+                $this->accountManager,
3817
+                $this->subAdminManager,
3818
+                $this->l10nFactory,
3819
+                $this->rootFolder,
3820
+                $this->urlGenerator,
3821
+                $this->logger,
3822
+                $this->newUserMailHelper,
3823
+                $this->secureRandom,
3824
+                $this->remoteWipe,
3825
+                $this->knownUserService,
3826
+                $this->eventDispatcher,
3827
+                $this->phoneNumberUtil,
3828
+            ])
3829
+            ->onlyMethods(['getUserData'])
3830
+            ->getMock();
3831
+
3832
+        $api->expects($this->once())->method('getUserData')->with('UID', true)
3833
+            ->willReturn(
3834
+                [
3835
+                    'id' => 'UID',
3836
+                    'enabled' => 'true',
3837
+                    'quota' => ['DummyValue'],
3838
+                    'email' => '[email protected]',
3839
+                    'displayname' => 'Demo User',
3840
+                    'display-name' => 'Demo User',
3841
+                    'phone' => 'phone',
3842
+                    'address' => 'address',
3843
+                    'website' => 'website',
3844
+                    'twitter' => 'twitter',
3845
+                    'fediverse' => 'fediverse',
3846
+                    'organisation' => 'organisation',
3847
+                    'role' => 'role',
3848
+                    'headline' => 'headline',
3849
+                    'biography' => 'biography',
3850
+                    'profile_enabled' => '1',
3851
+                    'pronouns' => 'they/them',
3852
+                ]
3853
+            );
3854
+
3855
+        $expected = [
3856
+            'id' => 'UID',
3857
+            'enabled' => 'true',
3858
+            'quota' => ['DummyValue'],
3859
+            'email' => '[email protected]',
3860
+            'displayname' => 'Demo User',
3861
+            'display-name' => 'Demo User',
3862
+            'phone' => 'phone',
3863
+            'address' => 'address',
3864
+            'website' => 'website',
3865
+            'twitter' => 'twitter',
3866
+            'fediverse' => 'fediverse',
3867
+            'organisation' => 'organisation',
3868
+            'role' => 'role',
3869
+            'headline' => 'headline',
3870
+            'biography' => 'biography',
3871
+            'profile_enabled' => '1',
3872
+            'pronouns' => 'they/them',
3873
+        ];
3874
+
3875
+        $this->assertSame($expected, $api->getCurrentUser()->getData());
3876
+    }
3877
+
3878
+
3879
+    public function testGetCurrentUserNotLoggedIn(): void {
3880
+        $this->expectException(OCSException::class);
3881
+
3882
+
3883
+        $this->userSession->expects($this->once())->method('getUser')
3884
+            ->willReturn(null);
3885
+
3886
+        $this->api->getCurrentUser();
3887
+    }
3888
+
3889
+    public function testGetUser(): void {
3890
+        $loggedInUser = $this->createMock(IUser::class);
3891
+        $loggedInUser
3892
+            ->method('getUID')
3893
+            ->willReturn('currentuser');
3894
+        $this->userSession
3895
+            ->method('getUser')
3896
+            ->willReturn($loggedInUser);
3897
+
3898
+        /** @var UsersController | MockObject $api */
3899
+        $api = $this->getMockBuilder(UsersController::class)
3900
+            ->setConstructorArgs([
3901
+                'provisioning_api',
3902
+                $this->request,
3903
+                $this->userManager,
3904
+                $this->config,
3905
+                $this->groupManager,
3906
+                $this->userSession,
3907
+                $this->accountManager,
3908
+                $this->subAdminManager,
3909
+                $this->l10nFactory,
3910
+                $this->rootFolder,
3911
+                $this->urlGenerator,
3912
+                $this->logger,
3913
+                $this->newUserMailHelper,
3914
+                $this->secureRandom,
3915
+                $this->remoteWipe,
3916
+                $this->knownUserService,
3917
+                $this->eventDispatcher,
3918
+                $this->phoneNumberUtil,
3919
+            ])
3920
+            ->onlyMethods(['getUserData'])
3921
+            ->getMock();
3922
+
3923
+        $expected = [
3924
+            'id' => 'UID',
3925
+            'enabled' => 'true',
3926
+            'quota' => ['DummyValue'],
3927
+            'email' => '[email protected]',
3928
+            'phone' => 'phone',
3929
+            'address' => 'address',
3930
+            'website' => 'website',
3931
+            'twitter' => 'twitter',
3932
+            'fediverse' => 'fediverse',
3933
+            'displayname' => 'Demo User',
3934
+            'display-name' => 'Demo User',
3935
+            'organisation' => 'organisation',
3936
+            'role' => 'role',
3937
+            'headline' => 'headline',
3938
+            'biography' => 'biography',
3939
+            'profile_enabled' => '1',
3940
+            'pronouns' => 'they/them',
3941
+        ];
3942
+
3943
+        $api->expects($this->exactly(2))
3944
+            ->method('getUserData')
3945
+            ->withConsecutive(
3946
+                ['uid', false],
3947
+                ['currentuser', true],
3948
+            )
3949
+            ->willReturn($expected);
3950
+
3951
+        $this->assertSame($expected, $api->getUser('uid')->getData());
3952
+
3953
+        $this->assertSame($expected, $api->getUser('currentuser')->getData());
3954
+    }
3955
+
3956
+
3957
+    public function testResendWelcomeMessageWithNotExistingTargetUser(): void {
3958
+        $this->expectException(OCSException::class);
3959
+        $this->expectExceptionCode(998);
3960
+
3961
+        $this->userManager
3962
+            ->expects($this->once())
3963
+            ->method('get')
3964
+            ->with('NotExistingUser')
3965
+            ->willReturn(null);
3966
+
3967
+        $this->api->resendWelcomeMessage('NotExistingUser');
3968
+    }
3969
+
3970
+
3971
+    public function testResendWelcomeMessageAsSubAdminAndUserIsNotAccessible(): void {
3972
+        $this->expectException(OCSException::class);
3973
+        $this->expectExceptionCode(998);
3974
+
3975
+        $loggedInUser = $this->getMockBuilder(IUser::class)
3976
+            ->disableOriginalConstructor()
3977
+            ->getMock();
3978
+        $loggedInUser
3979
+            ->expects($this->exactly(2))
3980
+            ->method('getUID')
3981
+            ->willReturn('subadmin');
3982
+        $targetUser = $this->getMockBuilder(IUser::class)
3983
+            ->disableOriginalConstructor()
3984
+            ->getMock();
3985
+        $this->userSession
3986
+            ->expects($this->once())
3987
+            ->method('getUser')
3988
+            ->willReturn($loggedInUser);
3989
+        $this->userManager
3990
+            ->expects($this->once())
3991
+            ->method('get')
3992
+            ->with('UserToGet')
3993
+            ->willReturn($targetUser);
3994
+        $this->groupManager
3995
+            ->expects($this->once())
3996
+            ->method('isAdmin')
3997
+            ->with('subadmin')
3998
+            ->willReturn(false);
3999
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
4000
+            ->disableOriginalConstructor()
4001
+            ->getMock();
4002
+        $subAdminManager
4003
+            ->expects($this->once())
4004
+            ->method('isUserAccessible')
4005
+            ->with($loggedInUser, $targetUser)
4006
+            ->willReturn(false);
4007
+        $this->groupManager
4008
+            ->expects($this->once())
4009
+            ->method('getSubAdmin')
4010
+            ->willReturn($subAdminManager);
4011
+
4012
+        $this->api->resendWelcomeMessage('UserToGet');
4013
+    }
4014
+
4015
+
4016
+    public function testResendWelcomeMessageNoEmail(): void {
4017
+        $this->expectException(OCSException::class);
4018
+        $this->expectExceptionMessage('Email address not available');
4019
+        $this->expectExceptionCode(101);
4020
+
4021
+        $loggedInUser = $this->getMockBuilder(IUser::class)
4022
+            ->disableOriginalConstructor()
4023
+            ->getMock();
4024
+        $targetUser = $this->getMockBuilder(IUser::class)
4025
+            ->disableOriginalConstructor()
4026
+            ->getMock();
4027
+        $this->userSession
4028
+            ->expects($this->once())
4029
+            ->method('getUser')
4030
+            ->willReturn($loggedInUser);
4031
+        $this->userManager
4032
+            ->expects($this->once())
4033
+            ->method('get')
4034
+            ->with('UserToGet')
4035
+            ->willReturn($targetUser);
4036
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
4037
+            ->disableOriginalConstructor()
4038
+            ->getMock();
4039
+        $subAdminManager
4040
+            ->expects($this->once())
4041
+            ->method('isUserAccessible')
4042
+            ->with($loggedInUser, $targetUser)
4043
+            ->willReturn(true);
4044
+        $this->groupManager
4045
+            ->expects($this->once())
4046
+            ->method('getSubAdmin')
4047
+            ->willReturn($subAdminManager);
4048
+        $loggedInUser
4049
+            ->expects($this->exactly(2))
4050
+            ->method('getUID')
4051
+            ->willReturn('logged-user-id');
4052
+        $targetUser
4053
+            ->expects($this->once())
4054
+            ->method('getEmailAddress')
4055
+            ->willReturn('');
4056
+
4057
+        $this->api->resendWelcomeMessage('UserToGet');
4058
+    }
4059
+
4060
+
4061
+    public function testResendWelcomeMessageNullEmail(): void {
4062
+        $this->expectException(OCSException::class);
4063
+        $this->expectExceptionMessage('Email address not available');
4064
+        $this->expectExceptionCode(101);
4065
+
4066
+        $loggedInUser = $this->getMockBuilder(IUser::class)
4067
+            ->disableOriginalConstructor()
4068
+            ->getMock();
4069
+        $targetUser = $this->getMockBuilder(IUser::class)
4070
+            ->disableOriginalConstructor()
4071
+            ->getMock();
4072
+        $this->userSession
4073
+            ->expects($this->once())
4074
+            ->method('getUser')
4075
+            ->willReturn($loggedInUser);
4076
+        $this->userManager
4077
+            ->expects($this->once())
4078
+            ->method('get')
4079
+            ->with('UserToGet')
4080
+            ->willReturn($targetUser);
4081
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
4082
+            ->disableOriginalConstructor()
4083
+            ->getMock();
4084
+        $subAdminManager
4085
+            ->expects($this->once())
4086
+            ->method('isUserAccessible')
4087
+            ->with($loggedInUser, $targetUser)
4088
+            ->willReturn(true);
4089
+        $this->groupManager
4090
+            ->expects($this->once())
4091
+            ->method('getSubAdmin')
4092
+            ->willReturn($subAdminManager);
4093
+        $loggedInUser
4094
+            ->expects($this->exactly(2))
4095
+            ->method('getUID')
4096
+            ->willReturn('logged-user-id');
4097
+        $targetUser
4098
+            ->expects($this->once())
4099
+            ->method('getEmailAddress')
4100
+            ->willReturn(null);
4101
+
4102
+        $this->api->resendWelcomeMessage('UserToGet');
4103
+    }
4104
+
4105
+    public function testResendWelcomeMessageSuccess(): void {
4106
+        $loggedInUser = $this->getMockBuilder(IUser::class)
4107
+            ->disableOriginalConstructor()
4108
+            ->getMock();
4109
+        $targetUser = $this->getMockBuilder(IUser::class)
4110
+            ->disableOriginalConstructor()
4111
+            ->getMock();
4112
+        $loggedInUser
4113
+            ->method('getUID')
4114
+            ->willReturn('logged-user-id');
4115
+        $targetUser
4116
+            ->method('getUID')
4117
+            ->willReturn('user-id');
4118
+        $this->userSession
4119
+            ->expects($this->once())
4120
+            ->method('getUser')
4121
+            ->willReturn($loggedInUser);
4122
+        $this->userManager
4123
+            ->expects($this->once())
4124
+            ->method('get')
4125
+            ->with('UserToGet')
4126
+            ->willReturn($targetUser);
4127
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
4128
+            ->disableOriginalConstructor()
4129
+            ->getMock();
4130
+        $subAdminManager
4131
+            ->expects($this->once())
4132
+            ->method('isUserAccessible')
4133
+            ->with($loggedInUser, $targetUser)
4134
+            ->willReturn(true);
4135
+        $this->groupManager
4136
+            ->expects($this->once())
4137
+            ->method('getSubAdmin')
4138
+            ->willReturn($subAdminManager);
4139
+        $targetUser
4140
+            ->expects($this->once())
4141
+            ->method('getEmailAddress')
4142
+            ->willReturn('[email protected]');
4143
+        $emailTemplate = $this->createMock(IEMailTemplate::class);
4144
+        $this->newUserMailHelper
4145
+            ->expects($this->once())
4146
+            ->method('generateTemplate')
4147
+            ->willReturn($emailTemplate);
4148
+        $this->newUserMailHelper
4149
+            ->expects($this->once())
4150
+            ->method('sendMail')
4151
+            ->with($targetUser, $emailTemplate);
4152
+
4153
+        $this->api->resendWelcomeMessage('UserToGet');
4154
+    }
4155
+
4156
+    public function testResendWelcomeMessageSuccessWithFallbackLanguage(): void {
4157
+        $loggedInUser = $this->getMockBuilder(IUser::class)
4158
+            ->disableOriginalConstructor()
4159
+            ->getMock();
4160
+        $targetUser = $this->getMockBuilder(IUser::class)
4161
+            ->disableOriginalConstructor()
4162
+            ->getMock();
4163
+        $loggedInUser
4164
+            ->method('getUID')
4165
+            ->willReturn('logged-user-id');
4166
+        $targetUser
4167
+            ->method('getUID')
4168
+            ->willReturn('user-id');
4169
+        $this->userSession
4170
+            ->expects($this->once())
4171
+            ->method('getUser')
4172
+            ->willReturn($loggedInUser);
4173
+        $this->userManager
4174
+            ->expects($this->once())
4175
+            ->method('get')
4176
+            ->with('UserToGet')
4177
+            ->willReturn($targetUser);
4178
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
4179
+            ->disableOriginalConstructor()
4180
+            ->getMock();
4181
+        $subAdminManager
4182
+            ->expects($this->once())
4183
+            ->method('isUserAccessible')
4184
+            ->with($loggedInUser, $targetUser)
4185
+            ->willReturn(true);
4186
+        $this->groupManager
4187
+            ->expects($this->once())
4188
+            ->method('getSubAdmin')
4189
+            ->willReturn($subAdminManager);
4190
+        $targetUser
4191
+            ->expects($this->once())
4192
+            ->method('getEmailAddress')
4193
+            ->willReturn('[email protected]');
4194
+        $emailTemplate = $this->createMock(IEMailTemplate::class);
4195
+        $this->newUserMailHelper
4196
+            ->expects($this->once())
4197
+            ->method('generateTemplate')
4198
+            ->willReturn($emailTemplate);
4199
+        $this->newUserMailHelper
4200
+            ->expects($this->once())
4201
+            ->method('sendMail')
4202
+            ->with($targetUser, $emailTemplate);
4203
+
4204
+        $this->api->resendWelcomeMessage('UserToGet');
4205
+    }
4206
+
4207
+
4208
+    public function testResendWelcomeMessageFailed(): void {
4209
+        $this->expectException(OCSException::class);
4210
+        $this->expectExceptionMessage('Sending email failed');
4211
+        $this->expectExceptionCode(102);
4212
+
4213
+        $loggedInUser = $this->getMockBuilder(IUser::class)
4214
+            ->disableOriginalConstructor()
4215
+            ->getMock();
4216
+        $targetUser = $this->getMockBuilder(IUser::class)
4217
+            ->disableOriginalConstructor()
4218
+            ->getMock();
4219
+        $loggedInUser
4220
+            ->expects($this->exactly(2))
4221
+            ->method('getUID')
4222
+            ->willReturn('logged-user-id');
4223
+        $targetUser
4224
+            ->method('getUID')
4225
+            ->willReturn('user-id');
4226
+        $this->userSession
4227
+            ->expects($this->once())
4228
+            ->method('getUser')
4229
+            ->willReturn($loggedInUser);
4230
+        $this->userManager
4231
+            ->expects($this->once())
4232
+            ->method('get')
4233
+            ->with('UserToGet')
4234
+            ->willReturn($targetUser);
4235
+        $subAdminManager = $this->getMockBuilder('OC\SubAdmin')
4236
+            ->disableOriginalConstructor()
4237
+            ->getMock();
4238
+        $subAdminManager
4239
+            ->expects($this->once())
4240
+            ->method('isUserAccessible')
4241
+            ->with($loggedInUser, $targetUser)
4242
+            ->willReturn(true);
4243
+        $this->groupManager
4244
+            ->expects($this->once())
4245
+            ->method('getSubAdmin')
4246
+            ->willReturn($subAdminManager);
4247
+        $targetUser
4248
+            ->expects($this->once())
4249
+            ->method('getEmailAddress')
4250
+            ->willReturn('[email protected]');
4251
+        $emailTemplate = $this->createMock(IEMailTemplate::class);
4252
+        $this->newUserMailHelper
4253
+            ->expects($this->once())
4254
+            ->method('generateTemplate')
4255
+            ->willReturn($emailTemplate);
4256
+        $this->newUserMailHelper
4257
+            ->expects($this->once())
4258
+            ->method('sendMail')
4259
+            ->with($targetUser, $emailTemplate)
4260
+            ->willThrowException(new \Exception());
4261
+
4262
+        $this->api->resendWelcomeMessage('UserToGet');
4263
+    }
4264
+
4265
+
4266
+    public function dataGetEditableFields() {
4267
+        return [
4268
+            [false, true, ISetDisplayNameBackend::class, [
4269
+                IAccountManager::PROPERTY_EMAIL,
4270
+                IAccountManager::COLLECTION_EMAIL,
4271
+                IAccountManager::PROPERTY_PHONE,
4272
+                IAccountManager::PROPERTY_ADDRESS,
4273
+                IAccountManager::PROPERTY_WEBSITE,
4274
+                IAccountManager::PROPERTY_TWITTER,
4275
+                IAccountManager::PROPERTY_FEDIVERSE,
4276
+                IAccountManager::PROPERTY_ORGANISATION,
4277
+                IAccountManager::PROPERTY_ROLE,
4278
+                IAccountManager::PROPERTY_HEADLINE,
4279
+                IAccountManager::PROPERTY_BIOGRAPHY,
4280
+                IAccountManager::PROPERTY_PROFILE_ENABLED,
4281
+                IAccountManager::PROPERTY_PRONOUNS,
4282
+            ]],
4283
+            [true, false, ISetDisplayNameBackend::class, [
4284
+                IAccountManager::PROPERTY_DISPLAYNAME,
4285
+                IAccountManager::COLLECTION_EMAIL,
4286
+                IAccountManager::PROPERTY_PHONE,
4287
+                IAccountManager::PROPERTY_ADDRESS,
4288
+                IAccountManager::PROPERTY_WEBSITE,
4289
+                IAccountManager::PROPERTY_TWITTER,
4290
+                IAccountManager::PROPERTY_FEDIVERSE,
4291
+                IAccountManager::PROPERTY_ORGANISATION,
4292
+                IAccountManager::PROPERTY_ROLE,
4293
+                IAccountManager::PROPERTY_HEADLINE,
4294
+                IAccountManager::PROPERTY_BIOGRAPHY,
4295
+                IAccountManager::PROPERTY_PROFILE_ENABLED,
4296
+                IAccountManager::PROPERTY_PRONOUNS,
4297
+            ]],
4298
+            [true, true, ISetDisplayNameBackend::class, [
4299
+                IAccountManager::PROPERTY_DISPLAYNAME,
4300
+                IAccountManager::PROPERTY_EMAIL,
4301
+                IAccountManager::COLLECTION_EMAIL,
4302
+                IAccountManager::PROPERTY_PHONE,
4303
+                IAccountManager::PROPERTY_ADDRESS,
4304
+                IAccountManager::PROPERTY_WEBSITE,
4305
+                IAccountManager::PROPERTY_TWITTER,
4306
+                IAccountManager::PROPERTY_FEDIVERSE,
4307
+                IAccountManager::PROPERTY_ORGANISATION,
4308
+                IAccountManager::PROPERTY_ROLE,
4309
+                IAccountManager::PROPERTY_HEADLINE,
4310
+                IAccountManager::PROPERTY_BIOGRAPHY,
4311
+                IAccountManager::PROPERTY_PROFILE_ENABLED,
4312
+                IAccountManager::PROPERTY_PRONOUNS,
4313
+            ]],
4314
+            [false, false, ISetDisplayNameBackend::class, [
4315
+                IAccountManager::COLLECTION_EMAIL,
4316
+                IAccountManager::PROPERTY_PHONE,
4317
+                IAccountManager::PROPERTY_ADDRESS,
4318
+                IAccountManager::PROPERTY_WEBSITE,
4319
+                IAccountManager::PROPERTY_TWITTER,
4320
+                IAccountManager::PROPERTY_FEDIVERSE,
4321
+                IAccountManager::PROPERTY_ORGANISATION,
4322
+                IAccountManager::PROPERTY_ROLE,
4323
+                IAccountManager::PROPERTY_HEADLINE,
4324
+                IAccountManager::PROPERTY_BIOGRAPHY,
4325
+                IAccountManager::PROPERTY_PROFILE_ENABLED,
4326
+                IAccountManager::PROPERTY_PRONOUNS,
4327
+            ]],
4328
+            [false, true, UserInterface::class, [
4329
+                IAccountManager::PROPERTY_EMAIL,
4330
+                IAccountManager::COLLECTION_EMAIL,
4331
+                IAccountManager::PROPERTY_PHONE,
4332
+                IAccountManager::PROPERTY_ADDRESS,
4333
+                IAccountManager::PROPERTY_WEBSITE,
4334
+                IAccountManager::PROPERTY_TWITTER,
4335
+                IAccountManager::PROPERTY_FEDIVERSE,
4336
+                IAccountManager::PROPERTY_ORGANISATION,
4337
+                IAccountManager::PROPERTY_ROLE,
4338
+                IAccountManager::PROPERTY_HEADLINE,
4339
+                IAccountManager::PROPERTY_BIOGRAPHY,
4340
+                IAccountManager::PROPERTY_PROFILE_ENABLED,
4341
+                IAccountManager::PROPERTY_PRONOUNS,
4342
+            ]],
4343
+            [true, false, UserInterface::class, [
4344
+                IAccountManager::COLLECTION_EMAIL,
4345
+                IAccountManager::PROPERTY_PHONE,
4346
+                IAccountManager::PROPERTY_ADDRESS,
4347
+                IAccountManager::PROPERTY_WEBSITE,
4348
+                IAccountManager::PROPERTY_TWITTER,
4349
+                IAccountManager::PROPERTY_FEDIVERSE,
4350
+                IAccountManager::PROPERTY_ORGANISATION,
4351
+                IAccountManager::PROPERTY_ROLE,
4352
+                IAccountManager::PROPERTY_HEADLINE,
4353
+                IAccountManager::PROPERTY_BIOGRAPHY,
4354
+                IAccountManager::PROPERTY_PROFILE_ENABLED,
4355
+                IAccountManager::PROPERTY_PRONOUNS,
4356
+            ]],
4357
+            [true, true, UserInterface::class, [
4358
+                IAccountManager::PROPERTY_EMAIL,
4359
+                IAccountManager::COLLECTION_EMAIL,
4360
+                IAccountManager::PROPERTY_PHONE,
4361
+                IAccountManager::PROPERTY_ADDRESS,
4362
+                IAccountManager::PROPERTY_WEBSITE,
4363
+                IAccountManager::PROPERTY_TWITTER,
4364
+                IAccountManager::PROPERTY_FEDIVERSE,
4365
+                IAccountManager::PROPERTY_ORGANISATION,
4366
+                IAccountManager::PROPERTY_ROLE,
4367
+                IAccountManager::PROPERTY_HEADLINE,
4368
+                IAccountManager::PROPERTY_BIOGRAPHY,
4369
+                IAccountManager::PROPERTY_PROFILE_ENABLED,
4370
+                IAccountManager::PROPERTY_PRONOUNS,
4371
+            ]],
4372
+            [false, false, UserInterface::class, [
4373
+                IAccountManager::COLLECTION_EMAIL,
4374
+                IAccountManager::PROPERTY_PHONE,
4375
+                IAccountManager::PROPERTY_ADDRESS,
4376
+                IAccountManager::PROPERTY_WEBSITE,
4377
+                IAccountManager::PROPERTY_TWITTER,
4378
+                IAccountManager::PROPERTY_FEDIVERSE,
4379
+                IAccountManager::PROPERTY_ORGANISATION,
4380
+                IAccountManager::PROPERTY_ROLE,
4381
+                IAccountManager::PROPERTY_HEADLINE,
4382
+                IAccountManager::PROPERTY_BIOGRAPHY,
4383
+                IAccountManager::PROPERTY_PROFILE_ENABLED,
4384
+                IAccountManager::PROPERTY_PRONOUNS,
4385
+            ]],
4386
+        ];
4387
+    }
4388
+
4389
+    /**
4390
+     * @dataProvider dataGetEditableFields
4391
+     *
4392
+     * @param bool $allowedToChangeDisplayName
4393
+     * @param string $userBackend
4394
+     * @param array $expected
4395
+     */
4396
+    public function testGetEditableFields(bool $allowedToChangeDisplayName, bool $allowedToChangeEmail, string $userBackend, array $expected): void {
4397
+        $this->config->method('getSystemValue')->willReturnCallback(fn (string $key, mixed $default) => match ($key) {
4398
+            'allow_user_to_change_display_name' => $allowedToChangeDisplayName,
4399
+            'allow_user_to_change_email' => $allowedToChangeEmail,
4400
+            default => throw new RuntimeException('Unexpected system config key: ' . $key),
4401
+        });
4402
+
4403
+        $user = $this->createMock(IUser::class);
4404
+        $this->userSession->method('getUser')
4405
+            ->willReturn($user);
4406
+
4407
+        $backend = $this->createMock($userBackend);
4408
+
4409
+        $user->method('getUID')
4410
+            ->willReturn('userId');
4411
+        $user->method('getBackend')
4412
+            ->willReturn($backend);
4413
+
4414
+        $expectedResp = new DataResponse($expected);
4415
+        $this->assertEquals($expectedResp, $this->api->getEditableFields('userId'));
4416
+    }
4417
+
4418
+    private function mockAccount($targetUser, $accountProperties) {
4419
+        $mockedProperties = [];
4420
+
4421
+        foreach ($accountProperties as $propertyName => $data) {
4422
+            $mockedProperty = $this->createMock(IAccountProperty::class);
4423
+            $mockedProperty->method('getValue')->willReturn($data['value'] ?? '');
4424
+            $mockedProperty->method('getScope')->willReturn($data['scope'] ?? '');
4425
+            $mockedProperties[] = [$propertyName, $mockedProperty];
4426
+        }
4427
+
4428
+        $account = $this->createMock(IAccount::class);
4429
+        $account->method('getProperty')
4430
+            ->will($this->returnValueMap($mockedProperties));
4431
+
4432
+        $this->accountManager->expects($this->any())->method('getAccount')
4433
+            ->with($targetUser)
4434
+            ->willReturn($account);
4435
+    }
4436 4436
 }
Please login to merge, or discard this patch.
apps/provisioning_api/lib/Controller/UsersController.php 1 patch
Indentation   +1724 added lines, -1724 removed lines patch added patch discarded remove patch
@@ -58,1728 +58,1728 @@
 block discarded – undo
58 58
  */
59 59
 class UsersController extends AUserDataOCSController {
60 60
 
61
-	private IL10N $l10n;
62
-
63
-	public function __construct(
64
-		string $appName,
65
-		IRequest $request,
66
-		IUserManager $userManager,
67
-		IConfig $config,
68
-		IGroupManager $groupManager,
69
-		IUserSession $userSession,
70
-		IAccountManager $accountManager,
71
-		ISubAdmin $subAdminManager,
72
-		IFactory $l10nFactory,
73
-		IRootFolder $rootFolder,
74
-		private IURLGenerator $urlGenerator,
75
-		private LoggerInterface $logger,
76
-		private NewUserMailHelper $newUserMailHelper,
77
-		private ISecureRandom $secureRandom,
78
-		private RemoteWipe $remoteWipe,
79
-		private KnownUserService $knownUserService,
80
-		private IEventDispatcher $eventDispatcher,
81
-		private IPhoneNumberUtil $phoneNumberUtil,
82
-	) {
83
-		parent::__construct(
84
-			$appName,
85
-			$request,
86
-			$userManager,
87
-			$config,
88
-			$groupManager,
89
-			$userSession,
90
-			$accountManager,
91
-			$subAdminManager,
92
-			$l10nFactory,
93
-			$rootFolder,
94
-		);
95
-
96
-		$this->l10n = $l10nFactory->get($appName);
97
-	}
98
-
99
-	/**
100
-	 * Get a list of users
101
-	 *
102
-	 * @param string $search Text to search for
103
-	 * @param int|null $limit Limit the amount of groups returned
104
-	 * @param int $offset Offset for searching for groups
105
-	 * @return DataResponse<Http::STATUS_OK, array{users: list<string>}, array{}>
106
-	 *
107
-	 * 200: Users returned
108
-	 */
109
-	#[NoAdminRequired]
110
-	public function getUsers(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
111
-		$user = $this->userSession->getUser();
112
-		$users = [];
113
-
114
-		// Admin? Or SubAdmin?
115
-		$uid = $user->getUID();
116
-		$subAdminManager = $this->groupManager->getSubAdmin();
117
-		$isAdmin = $this->groupManager->isAdmin($uid);
118
-		$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($uid);
119
-		if ($isAdmin || $isDelegatedAdmin) {
120
-			$users = $this->userManager->search($search, $limit, $offset);
121
-		} elseif ($subAdminManager->isSubAdmin($user)) {
122
-			$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($user);
123
-			foreach ($subAdminOfGroups as $key => $group) {
124
-				$subAdminOfGroups[$key] = $group->getGID();
125
-			}
126
-
127
-			$users = [];
128
-			foreach ($subAdminOfGroups as $group) {
129
-				$users = array_merge($users, $this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
130
-			}
131
-		}
132
-
133
-		/** @var list<string> $users */
134
-		$users = array_keys($users);
135
-
136
-		return new DataResponse([
137
-			'users' => $users
138
-		]);
139
-	}
140
-
141
-	/**
142
-	 * Get a list of users and their details
143
-	 *
144
-	 * @param string $search Text to search for
145
-	 * @param int|null $limit Limit the amount of groups returned
146
-	 * @param int $offset Offset for searching for groups
147
-	 * @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
148
-	 *
149
-	 * 200: Users details returned
150
-	 */
151
-	#[NoAdminRequired]
152
-	public function getUsersDetails(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
153
-		$currentUser = $this->userSession->getUser();
154
-		$users = [];
155
-
156
-		// Admin? Or SubAdmin?
157
-		$uid = $currentUser->getUID();
158
-		$subAdminManager = $this->groupManager->getSubAdmin();
159
-		$isAdmin = $this->groupManager->isAdmin($uid);
160
-		$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($uid);
161
-		if ($isAdmin || $isDelegatedAdmin) {
162
-			$users = $this->userManager->search($search, $limit, $offset);
163
-			$users = array_keys($users);
164
-		} elseif ($subAdminManager->isSubAdmin($currentUser)) {
165
-			$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
166
-			foreach ($subAdminOfGroups as $key => $group) {
167
-				$subAdminOfGroups[$key] = $group->getGID();
168
-			}
169
-
170
-			$users = [];
171
-			foreach ($subAdminOfGroups as $group) {
172
-				$users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
173
-			}
174
-			$users = array_merge(...$users);
175
-		}
176
-
177
-		$usersDetails = [];
178
-		foreach ($users as $userId) {
179
-			$userId = (string)$userId;
180
-			try {
181
-				$userData = $this->getUserData($userId);
182
-			} catch (OCSNotFoundException $e) {
183
-				// We still want to return all other accounts, but this one was removed from the backends
184
-				// yet they are still in our database. Might be a LDAP remnant.
185
-				$userData = null;
186
-				$this->logger->warning('Found one enabled account that is removed from its backend, but still exists in Nextcloud database', ['accountId' => $userId]);
187
-			}
188
-			// Do not insert empty entry
189
-			if ($userData !== null) {
190
-				$usersDetails[$userId] = $userData;
191
-			} else {
192
-				// Logged user does not have permissions to see this user
193
-				// only showing its id
194
-				$usersDetails[$userId] = ['id' => $userId];
195
-			}
196
-		}
197
-
198
-		return new DataResponse([
199
-			'users' => $usersDetails
200
-		]);
201
-	}
202
-
203
-	/**
204
-	 * Get the list of disabled users and their details
205
-	 *
206
-	 * @param string $search Text to search for
207
-	 * @param ?int $limit Limit the amount of users returned
208
-	 * @param int $offset Offset
209
-	 * @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
210
-	 *
211
-	 * 200: Disabled users details returned
212
-	 */
213
-	#[NoAdminRequired]
214
-	public function getDisabledUsersDetails(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
215
-		$currentUser = $this->userSession->getUser();
216
-		if ($currentUser === null) {
217
-			return new DataResponse(['users' => []]);
218
-		}
219
-		if ($limit !== null && $limit < 0) {
220
-			throw new InvalidArgumentException("Invalid limit value: $limit");
221
-		}
222
-		if ($offset < 0) {
223
-			throw new InvalidArgumentException("Invalid offset value: $offset");
224
-		}
225
-
226
-		$users = [];
227
-
228
-		// Admin? Or SubAdmin?
229
-		$uid = $currentUser->getUID();
230
-		$subAdminManager = $this->groupManager->getSubAdmin();
231
-		$isAdmin = $this->groupManager->isAdmin($uid);
232
-		$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($uid);
233
-		if ($isAdmin || $isDelegatedAdmin) {
234
-			$users = $this->userManager->getDisabledUsers($limit, $offset, $search);
235
-			$users = array_map(fn (IUser $user): string => $user->getUID(), $users);
236
-		} elseif ($subAdminManager->isSubAdmin($currentUser)) {
237
-			$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
238
-
239
-			$users = [];
240
-			/* We have to handle offset ourselve for correctness */
241
-			$tempLimit = ($limit === null ? null : $limit + $offset);
242
-			foreach ($subAdminOfGroups as $group) {
243
-				$users = array_unique(array_merge(
244
-					$users,
245
-					array_map(
246
-						fn (IUser $user): string => $user->getUID(),
247
-						array_filter(
248
-							$group->searchUsers($search),
249
-							fn (IUser $user): bool => !$user->isEnabled()
250
-						)
251
-					)
252
-				));
253
-				if (($tempLimit !== null) && (count($users) >= $tempLimit)) {
254
-					break;
255
-				}
256
-			}
257
-			$users = array_slice($users, $offset, $limit);
258
-		}
259
-
260
-		$usersDetails = [];
261
-		foreach ($users as $userId) {
262
-			try {
263
-				$userData = $this->getUserData($userId);
264
-			} catch (OCSNotFoundException $e) {
265
-				// We still want to return all other accounts, but this one was removed from the backends
266
-				// yet they are still in our database. Might be a LDAP remnant.
267
-				$userData = null;
268
-				$this->logger->warning('Found one disabled account that was removed from its backend, but still exists in Nextcloud database', ['accountId' => $userId]);
269
-			}
270
-			// Do not insert empty entry
271
-			if ($userData !== null) {
272
-				$usersDetails[$userId] = $userData;
273
-			} else {
274
-				// Currently logged in user does not have permissions to see this user
275
-				// only showing its id
276
-				$usersDetails[$userId] = ['id' => $userId];
277
-			}
278
-		}
279
-
280
-		return new DataResponse([
281
-			'users' => $usersDetails
282
-		]);
283
-	}
284
-
285
-	/**
286
-	 * Gets the list of users sorted by lastLogin, from most recent to least recent
287
-	 *
288
-	 * @param string $search Text to search for
289
-	 * @param ?int $limit Limit the amount of users returned
290
-	 * @param int $offset Offset
291
-	 * @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
292
-	 *
293
-	 * 200: Users details returned based on last logged in information
294
-	 */
295
-	#[AuthorizedAdminSetting(settings:Users::class)]
296
-	public function getLastLoggedInUsers(string $search = '',
297
-		?int $limit = null,
298
-		int $offset = 0,
299
-	): DataResponse {
300
-		$currentUser = $this->userSession->getUser();
301
-		if ($currentUser === null) {
302
-			return new DataResponse(['users' => []]);
303
-		}
304
-		if ($limit !== null && $limit < 0) {
305
-			throw new InvalidArgumentException("Invalid limit value: $limit");
306
-		}
307
-		if ($offset < 0) {
308
-			throw new InvalidArgumentException("Invalid offset value: $offset");
309
-		}
310
-
311
-		$users = [];
312
-
313
-		// For Admin alone user sorting based on lastLogin. For sub admin and groups this is not supported
314
-		$users = $this->userManager->getLastLoggedInUsers($limit, $offset, $search);
315
-
316
-		$usersDetails = [];
317
-		foreach ($users as $userId) {
318
-			try {
319
-				$userData = $this->getUserData($userId);
320
-			} catch (OCSNotFoundException $e) {
321
-				// We still want to return all other accounts, but this one was removed from the backends
322
-				// yet they are still in our database. Might be a LDAP remnant.
323
-				$userData = null;
324
-				$this->logger->warning('Found one account that was removed from its backend, but still exists in Nextcloud database', ['accountId' => $userId]);
325
-			}
326
-			// Do not insert empty entry
327
-			if ($userData !== null) {
328
-				$usersDetails[$userId] = $userData;
329
-			} else {
330
-				// Currently logged-in user does not have permissions to see this user
331
-				// only showing its id
332
-				$usersDetails[$userId] = ['id' => $userId];
333
-			}
334
-		}
335
-
336
-		return new DataResponse([
337
-			'users' => $usersDetails
338
-		]);
339
-	}
340
-
341
-
342
-
343
-	/**
344
-	 * @NoSubAdminRequired
345
-	 *
346
-	 * Search users by their phone numbers
347
-	 *
348
-	 * @param string $location Location of the phone number (for country code)
349
-	 * @param array<string, list<string>> $search Phone numbers to search for
350
-	 * @return DataResponse<Http::STATUS_OK, array<string, string>, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, list<empty>, array{}>
351
-	 *
352
-	 * 200: Users returned
353
-	 * 400: Invalid location
354
-	 */
355
-	#[NoAdminRequired]
356
-	public function searchByPhoneNumbers(string $location, array $search): DataResponse {
357
-		if ($this->phoneNumberUtil->getCountryCodeForRegion($location) === null) {
358
-			// Not a valid region code
359
-			return new DataResponse([], Http::STATUS_BAD_REQUEST);
360
-		}
361
-
362
-		/** @var IUser $user */
363
-		$user = $this->userSession->getUser();
364
-		$knownTo = $user->getUID();
365
-		$defaultPhoneRegion = $this->config->getSystemValueString('default_phone_region');
366
-
367
-		$normalizedNumberToKey = [];
368
-		foreach ($search as $key => $phoneNumbers) {
369
-			foreach ($phoneNumbers as $phone) {
370
-				$normalizedNumber = $this->phoneNumberUtil->convertToStandardFormat($phone, $location);
371
-				if ($normalizedNumber !== null) {
372
-					$normalizedNumberToKey[$normalizedNumber] = (string)$key;
373
-				}
374
-
375
-				if ($defaultPhoneRegion !== '' && $defaultPhoneRegion !== $location && str_starts_with($phone, '0')) {
376
-					// If the number has a leading zero (no country code),
377
-					// we also check the default phone region of the instance,
378
-					// when it's different to the user's given region.
379
-					$normalizedNumber = $this->phoneNumberUtil->convertToStandardFormat($phone, $defaultPhoneRegion);
380
-					if ($normalizedNumber !== null) {
381
-						$normalizedNumberToKey[$normalizedNumber] = (string)$key;
382
-					}
383
-				}
384
-			}
385
-		}
386
-
387
-		$phoneNumbers = array_keys($normalizedNumberToKey);
388
-
389
-		if (empty($phoneNumbers)) {
390
-			return new DataResponse();
391
-		}
392
-
393
-		// Cleanup all previous entries and only allow new matches
394
-		$this->knownUserService->deleteKnownTo($knownTo);
395
-
396
-		$userMatches = $this->accountManager->searchUsers(IAccountManager::PROPERTY_PHONE, $phoneNumbers);
397
-
398
-		if (empty($userMatches)) {
399
-			return new DataResponse();
400
-		}
401
-
402
-		$cloudUrl = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/');
403
-		if (strpos($cloudUrl, 'http://') === 0) {
404
-			$cloudUrl = substr($cloudUrl, strlen('http://'));
405
-		} elseif (strpos($cloudUrl, 'https://') === 0) {
406
-			$cloudUrl = substr($cloudUrl, strlen('https://'));
407
-		}
408
-
409
-		$matches = [];
410
-		foreach ($userMatches as $phone => $userId) {
411
-			// Not using the ICloudIdManager as that would run a search for each contact to find the display name in the address book
412
-			$matches[$normalizedNumberToKey[$phone]] = $userId . '@' . $cloudUrl;
413
-			$this->knownUserService->storeIsKnownToUser($knownTo, $userId);
414
-		}
415
-
416
-		return new DataResponse($matches);
417
-	}
418
-
419
-	/**
420
-	 * @throws OCSException
421
-	 */
422
-	private function createNewUserId(): string {
423
-		$attempts = 0;
424
-		do {
425
-			$uidCandidate = $this->secureRandom->generate(10, ISecureRandom::CHAR_HUMAN_READABLE);
426
-			if (!$this->userManager->userExists($uidCandidate)) {
427
-				return $uidCandidate;
428
-			}
429
-			$attempts++;
430
-		} while ($attempts < 10);
431
-		throw new OCSException($this->l10n->t('Could not create non-existing user ID'), 111);
432
-	}
433
-
434
-	/**
435
-	 * Create a new user
436
-	 *
437
-	 * @param string $userid ID of the user
438
-	 * @param string $password Password of the user
439
-	 * @param string $displayName Display name of the user
440
-	 * @param string $email Email of the user
441
-	 * @param list<string> $groups Groups of the user
442
-	 * @param list<string> $subadmin Groups where the user is subadmin
443
-	 * @param string $quota Quota of the user
444
-	 * @param string $language Language of the user
445
-	 * @param ?string $manager Manager of the user
446
-	 * @return DataResponse<Http::STATUS_OK, array{id: string}, array{}>
447
-	 * @throws OCSException
448
-	 * @throws OCSForbiddenException Missing permissions to make user subadmin
449
-	 *
450
-	 * 200: User added successfully
451
-	 */
452
-	#[PasswordConfirmationRequired]
453
-	#[NoAdminRequired]
454
-	public function addUser(
455
-		string $userid,
456
-		string $password = '',
457
-		string $displayName = '',
458
-		string $email = '',
459
-		array $groups = [],
460
-		array $subadmin = [],
461
-		string $quota = '',
462
-		string $language = '',
463
-		?string $manager = null,
464
-	): DataResponse {
465
-		$user = $this->userSession->getUser();
466
-		$isAdmin = $this->groupManager->isAdmin($user->getUID());
467
-		$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($user->getUID());
468
-		$subAdminManager = $this->groupManager->getSubAdmin();
469
-
470
-		if (empty($userid) && $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes') {
471
-			$userid = $this->createNewUserId();
472
-		}
473
-
474
-		if ($this->userManager->userExists($userid)) {
475
-			$this->logger->error('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']);
476
-			throw new OCSException($this->l10n->t('User already exists'), 102);
477
-		}
478
-
479
-		if ($groups !== []) {
480
-			foreach ($groups as $group) {
481
-				if (!$this->groupManager->groupExists($group)) {
482
-					throw new OCSException($this->l10n->t('Group %1$s does not exist', [$group]), 104);
483
-				}
484
-				if (!$isAdmin && !($isDelegatedAdmin && $group !== 'admin') && !$subAdminManager->isSubAdminOfGroup($user, $this->groupManager->get($group))) {
485
-					throw new OCSException($this->l10n->t('Insufficient privileges for group %1$s', [$group]), 105);
486
-				}
487
-			}
488
-		} else {
489
-			if (!$isAdmin && !$isDelegatedAdmin) {
490
-				throw new OCSException($this->l10n->t('No group specified (required for sub-admins)'), 106);
491
-			}
492
-		}
493
-
494
-		$subadminGroups = [];
495
-		if ($subadmin !== []) {
496
-			foreach ($subadmin as $groupid) {
497
-				$group = $this->groupManager->get($groupid);
498
-				// Check if group exists
499
-				if ($group === null) {
500
-					throw new OCSException($this->l10n->t('Sub-admin group does not exist'), 109);
501
-				}
502
-				// Check if trying to make subadmin of admin group
503
-				if ($group->getGID() === 'admin') {
504
-					throw new OCSException($this->l10n->t('Cannot create sub-admins for admin group'), 103);
505
-				}
506
-				// Check if has permission to promote subadmins
507
-				if (!$subAdminManager->isSubAdminOfGroup($user, $group) && !$isAdmin && !$isDelegatedAdmin) {
508
-					throw new OCSForbiddenException($this->l10n->t('No permissions to promote sub-admins'));
509
-				}
510
-				$subadminGroups[] = $group;
511
-			}
512
-		}
513
-
514
-		$generatePasswordResetToken = false;
515
-		if (strlen($password) > IUserManager::MAX_PASSWORD_LENGTH) {
516
-			throw new OCSException($this->l10n->t('Invalid password value'), 101);
517
-		}
518
-		if ($password === '') {
519
-			if ($email === '') {
520
-				throw new OCSException($this->l10n->t('An email address is required, to send a password link to the user.'), 108);
521
-			}
522
-
523
-			$passwordEvent = new GenerateSecurePasswordEvent();
524
-			$this->eventDispatcher->dispatchTyped($passwordEvent);
525
-
526
-			$password = $passwordEvent->getPassword();
527
-			if ($password === null) {
528
-				// Fallback: ensure to pass password_policy in any case
529
-				$password = $this->secureRandom->generate(10)
530
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_UPPER)
531
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_LOWER)
532
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_DIGITS)
533
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_SYMBOLS);
534
-			}
535
-			$generatePasswordResetToken = true;
536
-		}
537
-
538
-		if ($email === '' && $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes') {
539
-			throw new OCSException($this->l10n->t('Required email address was not provided'), 110);
540
-		}
541
-
542
-		try {
543
-			$newUser = $this->userManager->createUser($userid, $password);
544
-			$this->logger->info('Successful addUser call with userid: ' . $userid, ['app' => 'ocs_api']);
545
-
546
-			foreach ($groups as $group) {
547
-				$this->groupManager->get($group)->addUser($newUser);
548
-				$this->logger->info('Added userid ' . $userid . ' to group ' . $group, ['app' => 'ocs_api']);
549
-			}
550
-			foreach ($subadminGroups as $group) {
551
-				$subAdminManager->createSubAdmin($newUser, $group);
552
-			}
553
-
554
-			if ($displayName !== '') {
555
-				try {
556
-					$this->editUser($userid, self::USER_FIELD_DISPLAYNAME, $displayName);
557
-				} catch (OCSException $e) {
558
-					if ($newUser instanceof IUser) {
559
-						$newUser->delete();
560
-					}
561
-					throw $e;
562
-				}
563
-			}
564
-
565
-			if ($quota !== '') {
566
-				$this->editUser($userid, self::USER_FIELD_QUOTA, $quota);
567
-			}
568
-
569
-			if ($language !== '') {
570
-				$this->editUser($userid, self::USER_FIELD_LANGUAGE, $language);
571
-			}
572
-
573
-			/**
574
-			 * null -> nothing sent
575
-			 * '' -> unset manager
576
-			 * else -> set manager
577
-			 */
578
-			if ($manager !== null) {
579
-				$this->editUser($userid, self::USER_FIELD_MANAGER, $manager);
580
-			}
581
-
582
-			// Send new user mail only if a mail is set
583
-			if ($email !== '') {
584
-				$newUser->setEMailAddress($email);
585
-				if ($this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes') {
586
-					try {
587
-						$emailTemplate = $this->newUserMailHelper->generateTemplate($newUser, $generatePasswordResetToken);
588
-						$this->newUserMailHelper->sendMail($newUser, $emailTemplate);
589
-					} catch (\Exception $e) {
590
-						// Mail could be failing hard or just be plain not configured
591
-						// Logging error as it is the hardest of the two
592
-						$this->logger->error(
593
-							"Unable to send the invitation mail to $email",
594
-							[
595
-								'app' => 'ocs_api',
596
-								'exception' => $e,
597
-							]
598
-						);
599
-					}
600
-				}
601
-			}
602
-
603
-			return new DataResponse(['id' => $userid]);
604
-		} catch (HintException $e) {
605
-			$this->logger->warning(
606
-				'Failed addUser attempt with hint exception.',
607
-				[
608
-					'app' => 'ocs_api',
609
-					'exception' => $e,
610
-				]
611
-			);
612
-			throw new OCSException($e->getHint(), 107);
613
-		} catch (OCSException $e) {
614
-			$this->logger->warning(
615
-				'Failed addUser attempt with ocs exception.',
616
-				[
617
-					'app' => 'ocs_api',
618
-					'exception' => $e,
619
-				]
620
-			);
621
-			throw $e;
622
-		} catch (InvalidArgumentException $e) {
623
-			$this->logger->error(
624
-				'Failed addUser attempt with invalid argument exception.',
625
-				[
626
-					'app' => 'ocs_api',
627
-					'exception' => $e,
628
-				]
629
-			);
630
-			throw new OCSException($e->getMessage(), 101);
631
-		} catch (\Exception $e) {
632
-			$this->logger->error(
633
-				'Failed addUser attempt with exception.',
634
-				[
635
-					'app' => 'ocs_api',
636
-					'exception' => $e
637
-				]
638
-			);
639
-			throw new OCSException('Bad request', 101);
640
-		}
641
-	}
642
-
643
-	/**
644
-	 * @NoSubAdminRequired
645
-	 *
646
-	 * Get the details of a user
647
-	 *
648
-	 * @param string $userId ID of the user
649
-	 * @return DataResponse<Http::STATUS_OK, Provisioning_APIUserDetails, array{}>
650
-	 * @throws OCSException
651
-	 *
652
-	 * 200: User returned
653
-	 */
654
-	#[NoAdminRequired]
655
-	public function getUser(string $userId): DataResponse {
656
-		$includeScopes = false;
657
-		$currentUser = $this->userSession->getUser();
658
-		if ($currentUser && $currentUser->getUID() === $userId) {
659
-			$includeScopes = true;
660
-		}
661
-
662
-		$data = $this->getUserData($userId, $includeScopes);
663
-		// getUserData returns null if not enough permissions
664
-		if ($data === null) {
665
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
666
-		}
667
-		return new DataResponse($data);
668
-	}
669
-
670
-	/**
671
-	 * @NoSubAdminRequired
672
-	 *
673
-	 * Get the details of the current user
674
-	 *
675
-	 * @return DataResponse<Http::STATUS_OK, Provisioning_APIUserDetails, array{}>
676
-	 * @throws OCSException
677
-	 *
678
-	 * 200: Current user returned
679
-	 */
680
-	#[NoAdminRequired]
681
-	public function getCurrentUser(): DataResponse {
682
-		$user = $this->userSession->getUser();
683
-		if ($user) {
684
-			/** @var Provisioning_APIUserDetails $data */
685
-			$data = $this->getUserData($user->getUID(), true);
686
-			return new DataResponse($data);
687
-		}
688
-
689
-		throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
690
-	}
691
-
692
-	/**
693
-	 * @NoSubAdminRequired
694
-	 *
695
-	 * Get a list of fields that are editable for the current user
696
-	 *
697
-	 * @return DataResponse<Http::STATUS_OK, list<string>, array{}>
698
-	 * @throws OCSException
699
-	 *
700
-	 * 200: Editable fields returned
701
-	 */
702
-	#[NoAdminRequired]
703
-	public function getEditableFields(): DataResponse {
704
-		$currentLoggedInUser = $this->userSession->getUser();
705
-		if (!$currentLoggedInUser instanceof IUser) {
706
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
707
-		}
708
-
709
-		return $this->getEditableFieldsForUser($currentLoggedInUser->getUID());
710
-	}
711
-
712
-	/**
713
-	 * @NoSubAdminRequired
714
-	 *
715
-	 * Get a list of fields that are editable for a user
716
-	 *
717
-	 * @param string $userId ID of the user
718
-	 * @return DataResponse<Http::STATUS_OK, list<string>, array{}>
719
-	 * @throws OCSException
720
-	 *
721
-	 * 200: Editable fields for user returned
722
-	 */
723
-	#[NoAdminRequired]
724
-	public function getEditableFieldsForUser(string $userId): DataResponse {
725
-		$currentLoggedInUser = $this->userSession->getUser();
726
-		if (!$currentLoggedInUser instanceof IUser) {
727
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
728
-		}
729
-
730
-		$permittedFields = [];
731
-
732
-		if ($userId !== $currentLoggedInUser->getUID()) {
733
-			$targetUser = $this->userManager->get($userId);
734
-			if (!$targetUser instanceof IUser) {
735
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
736
-			}
737
-
738
-			$subAdminManager = $this->groupManager->getSubAdmin();
739
-			$isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
740
-			$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
741
-			if (
742
-				!($isAdmin || $isDelegatedAdmin)
743
-				&& !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
744
-			) {
745
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
746
-			}
747
-		} else {
748
-			$targetUser = $currentLoggedInUser;
749
-		}
750
-
751
-		$allowDisplayNameChange = $this->config->getSystemValue('allow_user_to_change_display_name', true);
752
-		if ($allowDisplayNameChange === true && (
753
-			$targetUser->getBackend() instanceof ISetDisplayNameBackend
754
-			|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
755
-		)) {
756
-			$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
757
-		}
758
-
759
-		// Fallback to display name value to avoid changing behavior with the new option.
760
-		if ($this->config->getSystemValue('allow_user_to_change_email', true)) {
761
-			$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
762
-		}
763
-
764
-		$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
765
-		$permittedFields[] = IAccountManager::PROPERTY_PHONE;
766
-		$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
767
-		$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
768
-		$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
769
-		$permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
770
-		$permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
771
-		$permittedFields[] = IAccountManager::PROPERTY_ROLE;
772
-		$permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
773
-		$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
774
-		$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
775
-		$permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
776
-
777
-		return new DataResponse($permittedFields);
778
-	}
779
-
780
-	/**
781
-	 * @NoSubAdminRequired
782
-	 *
783
-	 * Update multiple values of the user's details
784
-	 *
785
-	 * @param string $userId ID of the user
786
-	 * @param string $collectionName Collection to update
787
-	 * @param string $key Key that will be updated
788
-	 * @param string $value New value for the key
789
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
790
-	 * @throws OCSException
791
-	 *
792
-	 * 200: User values edited successfully
793
-	 */
794
-	#[PasswordConfirmationRequired]
795
-	#[NoAdminRequired]
796
-	#[UserRateLimit(limit: 5, period: 60)]
797
-	public function editUserMultiValue(
798
-		string $userId,
799
-		string $collectionName,
800
-		string $key,
801
-		string $value,
802
-	): DataResponse {
803
-		$currentLoggedInUser = $this->userSession->getUser();
804
-		if ($currentLoggedInUser === null) {
805
-			throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
806
-		}
807
-
808
-		$targetUser = $this->userManager->get($userId);
809
-		if ($targetUser === null) {
810
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
811
-		}
812
-
813
-		$subAdminManager = $this->groupManager->getSubAdmin();
814
-		$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
815
-		$isAdminOrSubadmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID())
816
-			|| $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser);
817
-
818
-		$permittedFields = [];
819
-		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
820
-			// Editing self (display, email)
821
-			$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
822
-			$permittedFields[] = IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX;
823
-		} else {
824
-			// Check if admin / subadmin
825
-			if ($isAdminOrSubadmin || $isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) {
826
-				// They have permissions over the user
827
-				$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
828
-			} else {
829
-				// No rights
830
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
831
-			}
832
-		}
833
-
834
-		// Check if permitted to edit this field
835
-		if (!in_array($collectionName, $permittedFields)) {
836
-			throw new OCSException('', 103);
837
-		}
838
-
839
-		switch ($collectionName) {
840
-			case IAccountManager::COLLECTION_EMAIL:
841
-				$userAccount = $this->accountManager->getAccount($targetUser);
842
-				$mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
843
-				$mailCollection->removePropertyByValue($key);
844
-				if ($value !== '') {
845
-					$mailCollection->addPropertyWithDefaults($value);
846
-					$property = $mailCollection->getPropertyByValue($key);
847
-					if ($isAdminOrSubadmin && $property) {
848
-						// admin set mails are auto-verified
849
-						$property->setLocallyVerified(IAccountManager::VERIFIED);
850
-					}
851
-				}
852
-				$this->accountManager->updateAccount($userAccount);
853
-				if ($value === '' && $key === $targetUser->getPrimaryEMailAddress()) {
854
-					$targetUser->setPrimaryEMailAddress('');
855
-				}
856
-				break;
857
-
858
-			case IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX:
859
-				$userAccount = $this->accountManager->getAccount($targetUser);
860
-				$mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
861
-				$targetProperty = null;
862
-				foreach ($mailCollection->getProperties() as $property) {
863
-					if ($property->getValue() === $key) {
864
-						$targetProperty = $property;
865
-						break;
866
-					}
867
-				}
868
-				if ($targetProperty instanceof IAccountProperty) {
869
-					try {
870
-						$targetProperty->setScope($value);
871
-						$this->accountManager->updateAccount($userAccount);
872
-					} catch (InvalidArgumentException $e) {
873
-						throw new OCSException('', 102);
874
-					}
875
-				} else {
876
-					throw new OCSException('', 102);
877
-				}
878
-				break;
879
-
880
-			default:
881
-				throw new OCSException('', 103);
882
-		}
883
-		return new DataResponse();
884
-	}
885
-
886
-	/**
887
-	 * @NoSubAdminRequired
888
-	 *
889
-	 * Update a value of the user's details
890
-	 *
891
-	 * @param string $userId ID of the user
892
-	 * @param string $key Key that will be updated
893
-	 * @param string $value New value for the key
894
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
895
-	 * @throws OCSException
896
-	 *
897
-	 * 200: User value edited successfully
898
-	 */
899
-	#[PasswordConfirmationRequired]
900
-	#[NoAdminRequired]
901
-	#[UserRateLimit(limit: 50, period: 600)]
902
-	public function editUser(string $userId, string $key, string $value): DataResponse {
903
-		$currentLoggedInUser = $this->userSession->getUser();
904
-
905
-		$targetUser = $this->userManager->get($userId);
906
-		if ($targetUser === null) {
907
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
908
-		}
909
-
910
-		$permittedFields = [];
911
-		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
912
-			$allowDisplayNameChange = $this->config->getSystemValue('allow_user_to_change_display_name', true);
913
-			if ($allowDisplayNameChange !== false && (
914
-				$targetUser->getBackend() instanceof ISetDisplayNameBackend
915
-				|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
916
-			)) {
917
-				$permittedFields[] = self::USER_FIELD_DISPLAYNAME;
918
-				$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
919
-			}
920
-
921
-			if ($this->config->getSystemValue('allow_user_to_change_email', true)) {
922
-				$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
923
-			}
924
-
925
-			$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX;
926
-			$permittedFields[] = IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX;
927
-
928
-			$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
929
-
930
-			$permittedFields[] = self::USER_FIELD_PASSWORD;
931
-			$permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
932
-			if (
933
-				$this->config->getSystemValue('force_language', false) === false ||
934
-				$this->groupManager->isAdmin($currentLoggedInUser->getUID()) ||
935
-				$this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID())
936
-			) {
937
-				$permittedFields[] = self::USER_FIELD_LANGUAGE;
938
-			}
939
-
940
-			if (
941
-				$this->config->getSystemValue('force_locale', false) === false ||
942
-				$this->groupManager->isAdmin($currentLoggedInUser->getUID()) ||
943
-				$this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID())
944
-			) {
945
-				$permittedFields[] = self::USER_FIELD_LOCALE;
946
-				$permittedFields[] = self::USER_FIELD_FIRST_DAY_OF_WEEK;
947
-			}
948
-
949
-			$permittedFields[] = IAccountManager::PROPERTY_PHONE;
950
-			$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
951
-			$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
952
-			$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
953
-			$permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
954
-			$permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
955
-			$permittedFields[] = IAccountManager::PROPERTY_ROLE;
956
-			$permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
957
-			$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
958
-			$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
959
-			$permittedFields[] = IAccountManager::PROPERTY_BIRTHDATE;
960
-			$permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
961
-
962
-			$permittedFields[] = IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX;
963
-			$permittedFields[] = IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX;
964
-			$permittedFields[] = IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX;
965
-			$permittedFields[] = IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX;
966
-			$permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE . self::SCOPE_SUFFIX;
967
-			$permittedFields[] = IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX;
968
-			$permittedFields[] = IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX;
969
-			$permittedFields[] = IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX;
970
-			$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX;
971
-			$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX;
972
-			$permittedFields[] = IAccountManager::PROPERTY_BIRTHDATE . self::SCOPE_SUFFIX;
973
-			$permittedFields[] = IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX;
974
-			$permittedFields[] = IAccountManager::PROPERTY_PRONOUNS . self::SCOPE_SUFFIX;
975
-
976
-			// If admin they can edit their own quota and manager
977
-			$isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
978
-			$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
979
-			if ($isAdmin || $isDelegatedAdmin) {
980
-				$permittedFields[] = self::USER_FIELD_QUOTA;
981
-				$permittedFields[] = self::USER_FIELD_MANAGER;
982
-			}
983
-		} else {
984
-			// Check if admin / subadmin
985
-			$subAdminManager = $this->groupManager->getSubAdmin();
986
-			if (
987
-				$this->groupManager->isAdmin($currentLoggedInUser->getUID()) ||
988
-				$this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID()) && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')
989
-				|| $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
990
-			) {
991
-				// They have permissions over the user
992
-				if (
993
-					$targetUser->getBackend() instanceof ISetDisplayNameBackend
994
-					|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
995
-				) {
996
-					$permittedFields[] = self::USER_FIELD_DISPLAYNAME;
997
-					$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
998
-				}
999
-				$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
1000
-				$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
1001
-				$permittedFields[] = self::USER_FIELD_PASSWORD;
1002
-				$permittedFields[] = self::USER_FIELD_LANGUAGE;
1003
-				$permittedFields[] = self::USER_FIELD_LOCALE;
1004
-				$permittedFields[] = self::USER_FIELD_FIRST_DAY_OF_WEEK;
1005
-				$permittedFields[] = IAccountManager::PROPERTY_PHONE;
1006
-				$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
1007
-				$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
1008
-				$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
1009
-				$permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
1010
-				$permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
1011
-				$permittedFields[] = IAccountManager::PROPERTY_ROLE;
1012
-				$permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
1013
-				$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
1014
-				$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
1015
-				$permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
1016
-				$permittedFields[] = self::USER_FIELD_QUOTA;
1017
-				$permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
1018
-				$permittedFields[] = self::USER_FIELD_MANAGER;
1019
-			} else {
1020
-				// No rights
1021
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1022
-			}
1023
-		}
1024
-		// Check if permitted to edit this field
1025
-		if (!in_array($key, $permittedFields)) {
1026
-			throw new OCSException('', 113);
1027
-		}
1028
-		// Process the edit
1029
-		switch ($key) {
1030
-			case self::USER_FIELD_DISPLAYNAME:
1031
-			case IAccountManager::PROPERTY_DISPLAYNAME:
1032
-				try {
1033
-					$targetUser->setDisplayName($value);
1034
-				} catch (InvalidArgumentException $e) {
1035
-					throw new OCSException($e->getMessage(), 101);
1036
-				}
1037
-				break;
1038
-			case self::USER_FIELD_QUOTA:
1039
-				$quota = $value;
1040
-				if ($quota !== 'none' && $quota !== 'default') {
1041
-					if (is_numeric($quota)) {
1042
-						$quota = (float)$quota;
1043
-					} else {
1044
-						$quota = Util::computerFileSize($quota);
1045
-					}
1046
-					if ($quota === false) {
1047
-						throw new OCSException($this->l10n->t('Invalid quota value: %1$s', [$value]), 101);
1048
-					}
1049
-					if ($quota === -1) {
1050
-						$quota = 'none';
1051
-					} else {
1052
-						$maxQuota = (int)$this->config->getAppValue('files', 'max_quota', '-1');
1053
-						if ($maxQuota !== -1 && $quota > $maxQuota) {
1054
-							throw new OCSException($this->l10n->t('Invalid quota value. %1$s is exceeding the maximum quota', [$value]), 101);
1055
-						}
1056
-						$quota = Util::humanFileSize($quota);
1057
-					}
1058
-				}
1059
-				// no else block because quota can be set to 'none' in previous if
1060
-				if ($quota === 'none') {
1061
-					$allowUnlimitedQuota = $this->config->getAppValue('files', 'allow_unlimited_quota', '1') === '1';
1062
-					if (!$allowUnlimitedQuota) {
1063
-						throw new OCSException($this->l10n->t('Unlimited quota is forbidden on this instance'), 101);
1064
-					}
1065
-				}
1066
-				$targetUser->setQuota($quota);
1067
-				break;
1068
-			case self::USER_FIELD_MANAGER:
1069
-				$targetUser->setManagerUids([$value]);
1070
-				break;
1071
-			case self::USER_FIELD_PASSWORD:
1072
-				try {
1073
-					if (strlen($value) > IUserManager::MAX_PASSWORD_LENGTH) {
1074
-						throw new OCSException($this->l10n->t('Invalid password value'), 101);
1075
-					}
1076
-					if (!$targetUser->canChangePassword()) {
1077
-						throw new OCSException($this->l10n->t('Setting the password is not supported by the users backend'), 112);
1078
-					}
1079
-					$targetUser->setPassword($value);
1080
-				} catch (HintException $e) { // password policy error
1081
-					throw new OCSException($e->getHint(), 107);
1082
-				}
1083
-				break;
1084
-			case self::USER_FIELD_LANGUAGE:
1085
-				$languagesCodes = $this->l10nFactory->findAvailableLanguages();
1086
-				if (!in_array($value, $languagesCodes, true) && $value !== 'en') {
1087
-					throw new OCSException($this->l10n->t('Invalid language'), 101);
1088
-				}
1089
-				$this->config->setUserValue($targetUser->getUID(), 'core', 'lang', $value);
1090
-				break;
1091
-			case self::USER_FIELD_LOCALE:
1092
-				if (!$this->l10nFactory->localeExists($value)) {
1093
-					throw new OCSException($this->l10n->t('Invalid locale'), 101);
1094
-				}
1095
-				$this->config->setUserValue($targetUser->getUID(), 'core', 'locale', $value);
1096
-				break;
1097
-			case self::USER_FIELD_FIRST_DAY_OF_WEEK:
1098
-				$intValue = (int)$value;
1099
-				if ($intValue < -1 || $intValue > 6) {
1100
-					throw new OCSException($this->l10n->t('Invalid first day of week'), 101);
1101
-				}
1102
-				if ($intValue === -1) {
1103
-					$this->config->deleteUserValue($targetUser->getUID(), 'core', AUserDataOCSController::USER_FIELD_FIRST_DAY_OF_WEEK);
1104
-				} else {
1105
-					$this->config->setUserValue($targetUser->getUID(), 'core', AUserDataOCSController::USER_FIELD_FIRST_DAY_OF_WEEK, $value);
1106
-				}
1107
-				break;
1108
-			case self::USER_FIELD_NOTIFICATION_EMAIL:
1109
-				$success = false;
1110
-				if ($value === '' || filter_var($value, FILTER_VALIDATE_EMAIL)) {
1111
-					try {
1112
-						$targetUser->setPrimaryEMailAddress($value);
1113
-						$success = true;
1114
-					} catch (InvalidArgumentException $e) {
1115
-						$this->logger->info(
1116
-							'Cannot set primary email, because provided address is not verified',
1117
-							[
1118
-								'app' => 'provisioning_api',
1119
-								'exception' => $e,
1120
-							]
1121
-						);
1122
-					}
1123
-				}
1124
-				if (!$success) {
1125
-					throw new OCSException('', 101);
1126
-				}
1127
-				break;
1128
-			case IAccountManager::PROPERTY_EMAIL:
1129
-				if (filter_var($value, FILTER_VALIDATE_EMAIL) || $value === '') {
1130
-					$targetUser->setEMailAddress($value);
1131
-				} else {
1132
-					throw new OCSException('', 101);
1133
-				}
1134
-				break;
1135
-			case IAccountManager::COLLECTION_EMAIL:
1136
-				if (filter_var($value, FILTER_VALIDATE_EMAIL) && $value !== $targetUser->getSystemEMailAddress()) {
1137
-					$userAccount = $this->accountManager->getAccount($targetUser);
1138
-					$mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
1139
-
1140
-					if ($mailCollection->getPropertyByValue($value)) {
1141
-						throw new OCSException('', 101);
1142
-					}
1143
-
1144
-					$mailCollection->addPropertyWithDefaults($value);
1145
-					$this->accountManager->updateAccount($userAccount);
1146
-				} else {
1147
-					throw new OCSException('', 101);
1148
-				}
1149
-				break;
1150
-			case IAccountManager::PROPERTY_PHONE:
1151
-			case IAccountManager::PROPERTY_ADDRESS:
1152
-			case IAccountManager::PROPERTY_WEBSITE:
1153
-			case IAccountManager::PROPERTY_TWITTER:
1154
-			case IAccountManager::PROPERTY_FEDIVERSE:
1155
-			case IAccountManager::PROPERTY_ORGANISATION:
1156
-			case IAccountManager::PROPERTY_ROLE:
1157
-			case IAccountManager::PROPERTY_HEADLINE:
1158
-			case IAccountManager::PROPERTY_BIOGRAPHY:
1159
-			case IAccountManager::PROPERTY_BIRTHDATE:
1160
-			case IAccountManager::PROPERTY_PRONOUNS:
1161
-				$userAccount = $this->accountManager->getAccount($targetUser);
1162
-				try {
1163
-					$userProperty = $userAccount->getProperty($key);
1164
-					if ($userProperty->getValue() !== $value) {
1165
-						try {
1166
-							$userProperty->setValue($value);
1167
-							if ($userProperty->getName() === IAccountManager::PROPERTY_PHONE) {
1168
-								$this->knownUserService->deleteByContactUserId($targetUser->getUID());
1169
-							}
1170
-						} catch (InvalidArgumentException $e) {
1171
-							throw new OCSException('Invalid ' . $e->getMessage(), 101);
1172
-						}
1173
-					}
1174
-				} catch (PropertyDoesNotExistException $e) {
1175
-					$userAccount->setProperty($key, $value, IAccountManager::SCOPE_PRIVATE, IAccountManager::NOT_VERIFIED);
1176
-				}
1177
-				try {
1178
-					$this->accountManager->updateAccount($userAccount);
1179
-				} catch (InvalidArgumentException $e) {
1180
-					throw new OCSException('Invalid ' . $e->getMessage(), 101);
1181
-				}
1182
-				break;
1183
-			case IAccountManager::PROPERTY_PROFILE_ENABLED:
1184
-				$userAccount = $this->accountManager->getAccount($targetUser);
1185
-				try {
1186
-					$userProperty = $userAccount->getProperty($key);
1187
-					if ($userProperty->getValue() !== $value) {
1188
-						$userProperty->setValue($value);
1189
-					}
1190
-				} catch (PropertyDoesNotExistException $e) {
1191
-					$userAccount->setProperty($key, $value, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
1192
-				}
1193
-				$this->accountManager->updateAccount($userAccount);
1194
-				break;
1195
-			case IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX:
1196
-			case IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX:
1197
-			case IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX:
1198
-			case IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX:
1199
-			case IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX:
1200
-			case IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX:
1201
-			case IAccountManager::PROPERTY_FEDIVERSE . self::SCOPE_SUFFIX:
1202
-			case IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX:
1203
-			case IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX:
1204
-			case IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX:
1205
-			case IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX:
1206
-			case IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX:
1207
-			case IAccountManager::PROPERTY_BIRTHDATE . self::SCOPE_SUFFIX:
1208
-			case IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX:
1209
-			case IAccountManager::PROPERTY_PRONOUNS . self::SCOPE_SUFFIX:
1210
-				$propertyName = substr($key, 0, strlen($key) - strlen(self::SCOPE_SUFFIX));
1211
-				$userAccount = $this->accountManager->getAccount($targetUser);
1212
-				$userProperty = $userAccount->getProperty($propertyName);
1213
-				if ($userProperty->getScope() !== $value) {
1214
-					try {
1215
-						$userProperty->setScope($value);
1216
-						$this->accountManager->updateAccount($userAccount);
1217
-					} catch (InvalidArgumentException $e) {
1218
-						throw new OCSException('Invalid ' . $e->getMessage(), 101);
1219
-					}
1220
-				}
1221
-				break;
1222
-			default:
1223
-				throw new OCSException('', 113);
1224
-		}
1225
-		return new DataResponse();
1226
-	}
1227
-
1228
-	/**
1229
-	 * Wipe all devices of a user
1230
-	 *
1231
-	 * @param string $userId ID of the user
1232
-	 *
1233
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1234
-	 *
1235
-	 * @throws OCSException
1236
-	 *
1237
-	 * 200: Wiped all user devices successfully
1238
-	 */
1239
-	#[PasswordConfirmationRequired]
1240
-	#[NoAdminRequired]
1241
-	public function wipeUserDevices(string $userId): DataResponse {
1242
-		/** @var IUser $currentLoggedInUser */
1243
-		$currentLoggedInUser = $this->userSession->getUser();
1244
-
1245
-		$targetUser = $this->userManager->get($userId);
1246
-
1247
-		if ($targetUser === null) {
1248
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1249
-		}
1250
-
1251
-		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
1252
-			throw new OCSException('', 101);
1253
-		}
1254
-
1255
-		// If not permitted
1256
-		$subAdminManager = $this->groupManager->getSubAdmin();
1257
-		$isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
1258
-		$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
1259
-		if (!$isAdmin && !($isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
1260
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1261
-		}
1262
-
1263
-		$this->remoteWipe->markAllTokensForWipe($targetUser);
1264
-
1265
-		return new DataResponse();
1266
-	}
1267
-
1268
-	/**
1269
-	 * Delete a user
1270
-	 *
1271
-	 * @param string $userId ID of the user
1272
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1273
-	 * @throws OCSException
1274
-	 *
1275
-	 * 200: User deleted successfully
1276
-	 */
1277
-	#[PasswordConfirmationRequired]
1278
-	#[NoAdminRequired]
1279
-	public function deleteUser(string $userId): DataResponse {
1280
-		$currentLoggedInUser = $this->userSession->getUser();
1281
-
1282
-		$targetUser = $this->userManager->get($userId);
1283
-
1284
-		if ($targetUser === null) {
1285
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1286
-		}
1287
-
1288
-		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
1289
-			throw new OCSException('', 101);
1290
-		}
1291
-
1292
-		// If not permitted
1293
-		$subAdminManager = $this->groupManager->getSubAdmin();
1294
-		$isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
1295
-		$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
1296
-		if (!$isAdmin && !($isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
1297
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1298
-		}
1299
-
1300
-		// Go ahead with the delete
1301
-		if ($targetUser->delete()) {
1302
-			return new DataResponse();
1303
-		} else {
1304
-			throw new OCSException('', 101);
1305
-		}
1306
-	}
1307
-
1308
-	/**
1309
-	 * Disable a user
1310
-	 *
1311
-	 * @param string $userId ID of the user
1312
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1313
-	 * @throws OCSException
1314
-	 *
1315
-	 * 200: User disabled successfully
1316
-	 */
1317
-	#[PasswordConfirmationRequired]
1318
-	#[NoAdminRequired]
1319
-	public function disableUser(string $userId): DataResponse {
1320
-		return $this->setEnabled($userId, false);
1321
-	}
1322
-
1323
-	/**
1324
-	 * Enable a user
1325
-	 *
1326
-	 * @param string $userId ID of the user
1327
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1328
-	 * @throws OCSException
1329
-	 *
1330
-	 * 200: User enabled successfully
1331
-	 */
1332
-	#[PasswordConfirmationRequired]
1333
-	#[NoAdminRequired]
1334
-	public function enableUser(string $userId): DataResponse {
1335
-		return $this->setEnabled($userId, true);
1336
-	}
1337
-
1338
-	/**
1339
-	 * @param string $userId
1340
-	 * @param bool $value
1341
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1342
-	 * @throws OCSException
1343
-	 */
1344
-	private function setEnabled(string $userId, bool $value): DataResponse {
1345
-		$currentLoggedInUser = $this->userSession->getUser();
1346
-
1347
-		$targetUser = $this->userManager->get($userId);
1348
-		if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
1349
-			throw new OCSException('', 101);
1350
-		}
1351
-
1352
-		// If not permitted
1353
-		$subAdminManager = $this->groupManager->getSubAdmin();
1354
-		$isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
1355
-		$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
1356
-		if (!$isAdmin && !($isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
1357
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1358
-		}
1359
-
1360
-		// enable/disable the user now
1361
-		$targetUser->setEnabled($value);
1362
-		return new DataResponse();
1363
-	}
1364
-
1365
-	/**
1366
-	 * @NoSubAdminRequired
1367
-	 *
1368
-	 * Get a list of groups the user belongs to
1369
-	 *
1370
-	 * @param string $userId ID of the user
1371
-	 * @return DataResponse<Http::STATUS_OK, array{groups: list<string>}, array{}>
1372
-	 * @throws OCSException
1373
-	 *
1374
-	 * 200: Users groups returned
1375
-	 */
1376
-	#[NoAdminRequired]
1377
-	public function getUsersGroups(string $userId): DataResponse {
1378
-		$loggedInUser = $this->userSession->getUser();
1379
-
1380
-		$targetUser = $this->userManager->get($userId);
1381
-		if ($targetUser === null) {
1382
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1383
-		}
1384
-
1385
-		$isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
1386
-		$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
1387
-		if ($targetUser->getUID() === $loggedInUser->getUID() || $isAdmin || $isDelegatedAdmin) {
1388
-			// Self lookup or admin lookup
1389
-			return new DataResponse([
1390
-				'groups' => $this->groupManager->getUserGroupIds($targetUser)
1391
-			]);
1392
-		} else {
1393
-			$subAdminManager = $this->groupManager->getSubAdmin();
1394
-
1395
-			// Looking up someone else
1396
-			if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
1397
-				// Return the group that the method caller is subadmin of for the user in question
1398
-				$groups = array_values(array_intersect(
1399
-					array_map(static fn (IGroup $group) => $group->getGID(), $subAdminManager->getSubAdminsGroups($loggedInUser)),
1400
-					$this->groupManager->getUserGroupIds($targetUser)
1401
-				));
1402
-				return new DataResponse(['groups' => $groups]);
1403
-			} else {
1404
-				// Not permitted
1405
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1406
-			}
1407
-		}
1408
-	}
1409
-
1410
-	/**
1411
-	 * @NoSubAdminRequired
1412
-	 *
1413
-	 * Get a list of groups with details
1414
-	 *
1415
-	 * @param string $userId ID of the user
1416
-	 * @return DataResponse<Http::STATUS_OK, array{groups: list<Provisioning_APIGroupDetails>}, array{}>
1417
-	 * @throws OCSException
1418
-	 *
1419
-	 * 200: Users groups returned
1420
-	 */
1421
-	#[NoAdminRequired]
1422
-	public function getUsersGroupsDetails(string $userId): DataResponse {
1423
-		$loggedInUser = $this->userSession->getUser();
1424
-
1425
-		$targetUser = $this->userManager->get($userId);
1426
-		if ($targetUser === null) {
1427
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1428
-		}
1429
-
1430
-		$isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
1431
-		$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
1432
-		if ($targetUser->getUID() === $loggedInUser->getUID() || $isAdmin || $isDelegatedAdmin) {
1433
-			// Self lookup or admin lookup
1434
-			$groups = array_map(
1435
-				function (Group $group) {
1436
-					return [
1437
-						'id' => $group->getGID(),
1438
-						'displayname' => $group->getDisplayName(),
1439
-						'usercount' => $group->count(),
1440
-						'disabled' => $group->countDisabled(),
1441
-						'canAdd' => $group->canAddUser(),
1442
-						'canRemove' => $group->canRemoveUser(),
1443
-					];
1444
-				},
1445
-				array_values($this->groupManager->getUserGroups($targetUser)),
1446
-			);
1447
-			return new DataResponse([
1448
-				'groups' => $groups,
1449
-			]);
1450
-		} else {
1451
-			$subAdminManager = $this->groupManager->getSubAdmin();
1452
-
1453
-			// Looking up someone else
1454
-			if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
1455
-				// Return the group that the method caller is subadmin of for the user in question
1456
-				$gids = array_values(array_intersect(
1457
-					array_map(
1458
-						static fn (IGroup $group) => $group->getGID(),
1459
-						$subAdminManager->getSubAdminsGroups($loggedInUser),
1460
-					),
1461
-					$this->groupManager->getUserGroupIds($targetUser)
1462
-				));
1463
-				$groups = array_map(
1464
-					function (string $gid) {
1465
-						$group = $this->groupManager->get($gid);
1466
-						return [
1467
-							'id' => $group->getGID(),
1468
-							'displayname' => $group->getDisplayName(),
1469
-							'usercount' => $group->count(),
1470
-							'disabled' => $group->countDisabled(),
1471
-							'canAdd' => $group->canAddUser(),
1472
-							'canRemove' => $group->canRemoveUser(),
1473
-						];
1474
-					},
1475
-					$gids,
1476
-				);
1477
-				return new DataResponse([
1478
-					'groups' => $groups,
1479
-				]);
1480
-			} else {
1481
-				// Not permitted
1482
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1483
-			}
1484
-		}
1485
-	}
1486
-
1487
-	/**
1488
-	 * @NoSubAdminRequired
1489
-	 *
1490
-	 * Get a list of the groups the user is a subadmin of, with details
1491
-	 *
1492
-	 * @param string $userId ID of the user
1493
-	 * @return DataResponse<Http::STATUS_OK, array{groups: list<Provisioning_APIGroupDetails>}, array{}>
1494
-	 * @throws OCSException
1495
-	 *
1496
-	 * 200: Users subadmin groups returned
1497
-	 */
1498
-	#[NoAdminRequired]
1499
-	public function getUserSubAdminGroupsDetails(string $userId): DataResponse {
1500
-		$loggedInUser = $this->userSession->getUser();
1501
-
1502
-		$targetUser = $this->userManager->get($userId);
1503
-		if ($targetUser === null) {
1504
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1505
-		}
1506
-
1507
-		$isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
1508
-		$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
1509
-		if ($targetUser->getUID() === $loggedInUser->getUID() || $isAdmin || $isDelegatedAdmin) {
1510
-			$subAdminManager = $this->groupManager->getSubAdmin();
1511
-			$groups = array_map(
1512
-				function (IGroup $group) {
1513
-					return [
1514
-						'id' => $group->getGID(),
1515
-						'displayname' => $group->getDisplayName(),
1516
-						'usercount' => $group->count(),
1517
-						'disabled' => $group->countDisabled(),
1518
-						'canAdd' => $group->canAddUser(),
1519
-						'canRemove' => $group->canRemoveUser(),
1520
-					];
1521
-				},
1522
-				array_values($subAdminManager->getSubAdminsGroups($targetUser)),
1523
-			);
1524
-			return new DataResponse([
1525
-				'groups' => $groups,
1526
-			]);
1527
-		}
1528
-		throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1529
-	}
1530
-
1531
-	/**
1532
-	 * Add a user to a group
1533
-	 *
1534
-	 * @param string $userId ID of the user
1535
-	 * @param string $groupid ID of the group
1536
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1537
-	 * @throws OCSException
1538
-	 *
1539
-	 * 200: User added to group successfully
1540
-	 */
1541
-	#[PasswordConfirmationRequired]
1542
-	#[NoAdminRequired]
1543
-	public function addToGroup(string $userId, string $groupid = ''): DataResponse {
1544
-		if ($groupid === '') {
1545
-			throw new OCSException('', 101);
1546
-		}
1547
-
1548
-		$group = $this->groupManager->get($groupid);
1549
-		$targetUser = $this->userManager->get($userId);
1550
-		if ($group === null) {
1551
-			throw new OCSException('', 102);
1552
-		}
1553
-		if ($targetUser === null) {
1554
-			throw new OCSException('', 103);
1555
-		}
1556
-
1557
-		// If they're not an admin, check they are a subadmin of the group in question
1558
-		$loggedInUser = $this->userSession->getUser();
1559
-		$subAdminManager = $this->groupManager->getSubAdmin();
1560
-		$isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
1561
-		$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
1562
-		if (!$isAdmin && !($isDelegatedAdmin && $groupid !== 'admin') && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
1563
-			throw new OCSException('', 104);
1564
-		}
1565
-
1566
-		// Add user to group
1567
-		$group->addUser($targetUser);
1568
-		return new DataResponse();
1569
-	}
1570
-
1571
-	/**
1572
-	 * Remove a user from a group
1573
-	 *
1574
-	 * @param string $userId ID of the user
1575
-	 * @param string $groupid ID of the group
1576
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1577
-	 * @throws OCSException
1578
-	 *
1579
-	 * 200: User removed from group successfully
1580
-	 */
1581
-	#[PasswordConfirmationRequired]
1582
-	#[NoAdminRequired]
1583
-	public function removeFromGroup(string $userId, string $groupid): DataResponse {
1584
-		$loggedInUser = $this->userSession->getUser();
1585
-
1586
-		if ($groupid === null || trim($groupid) === '') {
1587
-			throw new OCSException('', 101);
1588
-		}
1589
-
1590
-		$group = $this->groupManager->get($groupid);
1591
-		if ($group === null) {
1592
-			throw new OCSException('', 102);
1593
-		}
1594
-
1595
-		$targetUser = $this->userManager->get($userId);
1596
-		if ($targetUser === null) {
1597
-			throw new OCSException('', 103);
1598
-		}
1599
-
1600
-		// If they're not an admin, check they are a subadmin of the group in question
1601
-		$subAdminManager = $this->groupManager->getSubAdmin();
1602
-		$isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
1603
-		$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
1604
-		if (!$isAdmin && !($isDelegatedAdmin && $groupid !== 'admin') && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
1605
-			throw new OCSException('', 104);
1606
-		}
1607
-
1608
-		// Check they aren't removing themselves from 'admin' or their 'subadmin; group
1609
-		if ($targetUser->getUID() === $loggedInUser->getUID()) {
1610
-			if ($isAdmin || $isDelegatedAdmin) {
1611
-				if ($group->getGID() === 'admin') {
1612
-					throw new OCSException($this->l10n->t('Cannot remove yourself from the admin group'), 105);
1613
-				}
1614
-			} else {
1615
-				// Not an admin, so the user must be a subadmin of this group, but that is not allowed.
1616
-				throw new OCSException($this->l10n->t('Cannot remove yourself from this group as you are a sub-admin'), 105);
1617
-			}
1618
-		} elseif (!($isAdmin || $isDelegatedAdmin)) {
1619
-			/** @var IGroup[] $subAdminGroups */
1620
-			$subAdminGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
1621
-			$subAdminGroups = array_map(function (IGroup $subAdminGroup) {
1622
-				return $subAdminGroup->getGID();
1623
-			}, $subAdminGroups);
1624
-			$userGroups = $this->groupManager->getUserGroupIds($targetUser);
1625
-			$userSubAdminGroups = array_intersect($subAdminGroups, $userGroups);
1626
-
1627
-			if (count($userSubAdminGroups) <= 1) {
1628
-				// Subadmin must not be able to remove a user from all their subadmin groups.
1629
-				throw new OCSException($this->l10n->t('Not viable to remove user from the last group you are sub-admin of'), 105);
1630
-			}
1631
-		}
1632
-
1633
-		// Remove user from group
1634
-		$group->removeUser($targetUser);
1635
-		return new DataResponse();
1636
-	}
1637
-
1638
-	/**
1639
-	 * Make a user a subadmin of a group
1640
-	 *
1641
-	 * @param string $userId ID of the user
1642
-	 * @param string $groupid ID of the group
1643
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1644
-	 * @throws OCSException
1645
-	 *
1646
-	 * 200: User added as group subadmin successfully
1647
-	 */
1648
-	#[AuthorizedAdminSetting(settings:Users::class)]
1649
-	#[PasswordConfirmationRequired]
1650
-	public function addSubAdmin(string $userId, string $groupid): DataResponse {
1651
-		$group = $this->groupManager->get($groupid);
1652
-		$user = $this->userManager->get($userId);
1653
-
1654
-		// Check if the user exists
1655
-		if ($user === null) {
1656
-			throw new OCSException($this->l10n->t('User does not exist'), 101);
1657
-		}
1658
-		// Check if group exists
1659
-		if ($group === null) {
1660
-			throw new OCSException($this->l10n->t('Group does not exist'), 102);
1661
-		}
1662
-		// Check if trying to make subadmin of admin group
1663
-		if ($group->getGID() === 'admin') {
1664
-			throw new OCSException($this->l10n->t('Cannot create sub-admins for admin group'), 103);
1665
-		}
1666
-
1667
-		$subAdminManager = $this->groupManager->getSubAdmin();
1668
-
1669
-		// We cannot be subadmin twice
1670
-		if ($subAdminManager->isSubAdminOfGroup($user, $group)) {
1671
-			return new DataResponse();
1672
-		}
1673
-		// Go
1674
-		$subAdminManager->createSubAdmin($user, $group);
1675
-		return new DataResponse();
1676
-	}
1677
-
1678
-	/**
1679
-	 * Remove a user from the subadmins of a group
1680
-	 *
1681
-	 * @param string $userId ID of the user
1682
-	 * @param string $groupid ID of the group
1683
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1684
-	 * @throws OCSException
1685
-	 *
1686
-	 * 200: User removed as group subadmin successfully
1687
-	 */
1688
-	#[AuthorizedAdminSetting(settings:Users::class)]
1689
-	#[PasswordConfirmationRequired]
1690
-	public function removeSubAdmin(string $userId, string $groupid): DataResponse {
1691
-		$group = $this->groupManager->get($groupid);
1692
-		$user = $this->userManager->get($userId);
1693
-		$subAdminManager = $this->groupManager->getSubAdmin();
1694
-
1695
-		// Check if the user exists
1696
-		if ($user === null) {
1697
-			throw new OCSException($this->l10n->t('User does not exist'), 101);
1698
-		}
1699
-		// Check if the group exists
1700
-		if ($group === null) {
1701
-			throw new OCSException($this->l10n->t('Group does not exist'), 101);
1702
-		}
1703
-		// Check if they are a subadmin of this said group
1704
-		if (!$subAdminManager->isSubAdminOfGroup($user, $group)) {
1705
-			throw new OCSException($this->l10n->t('User is not a sub-admin of this group'), 102);
1706
-		}
1707
-
1708
-		// Go
1709
-		$subAdminManager->deleteSubAdmin($user, $group);
1710
-		return new DataResponse();
1711
-	}
1712
-
1713
-	/**
1714
-	 * Get the groups a user is a subadmin of
1715
-	 *
1716
-	 * @param string $userId ID if the user
1717
-	 * @return DataResponse<Http::STATUS_OK, list<string>, array{}>
1718
-	 * @throws OCSException
1719
-	 *
1720
-	 * 200: User subadmin groups returned
1721
-	 */
1722
-	#[AuthorizedAdminSetting(settings:Users::class)]
1723
-	public function getUserSubAdminGroups(string $userId): DataResponse {
1724
-		$groups = $this->getUserSubAdminGroupsData($userId);
1725
-		return new DataResponse($groups);
1726
-	}
1727
-
1728
-	/**
1729
-	 * Resend the welcome message
1730
-	 *
1731
-	 * @param string $userId ID if the user
1732
-	 * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1733
-	 * @throws OCSException
1734
-	 *
1735
-	 * 200: Resent welcome message successfully
1736
-	 */
1737
-	#[PasswordConfirmationRequired]
1738
-	#[NoAdminRequired]
1739
-	public function resendWelcomeMessage(string $userId): DataResponse {
1740
-		$currentLoggedInUser = $this->userSession->getUser();
1741
-
1742
-		$targetUser = $this->userManager->get($userId);
1743
-		if ($targetUser === null) {
1744
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1745
-		}
1746
-
1747
-		// Check if admin / subadmin
1748
-		$subAdminManager = $this->groupManager->getSubAdmin();
1749
-		$isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
1750
-		$isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
1751
-		if (
1752
-			!$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
1753
-			&& !($isAdmin || $isDelegatedAdmin)
1754
-		) {
1755
-			// No rights
1756
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1757
-		}
1758
-
1759
-		$email = $targetUser->getEMailAddress();
1760
-		if ($email === '' || $email === null) {
1761
-			throw new OCSException($this->l10n->t('Email address not available'), 101);
1762
-		}
1763
-
1764
-		try {
1765
-			if ($this->config->getUserValue($targetUser->getUID(), 'core', 'lostpassword')) {
1766
-				$emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, true);
1767
-			} else {
1768
-				$emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, false);
1769
-			}
1770
-
1771
-			$this->newUserMailHelper->sendMail($targetUser, $emailTemplate);
1772
-		} catch (\Exception $e) {
1773
-			$this->logger->error(
1774
-				"Can't send new user mail to $email",
1775
-				[
1776
-					'app' => 'settings',
1777
-					'exception' => $e,
1778
-				]
1779
-			);
1780
-			throw new OCSException($this->l10n->t('Sending email failed'), 102);
1781
-		}
1782
-
1783
-		return new DataResponse();
1784
-	}
61
+    private IL10N $l10n;
62
+
63
+    public function __construct(
64
+        string $appName,
65
+        IRequest $request,
66
+        IUserManager $userManager,
67
+        IConfig $config,
68
+        IGroupManager $groupManager,
69
+        IUserSession $userSession,
70
+        IAccountManager $accountManager,
71
+        ISubAdmin $subAdminManager,
72
+        IFactory $l10nFactory,
73
+        IRootFolder $rootFolder,
74
+        private IURLGenerator $urlGenerator,
75
+        private LoggerInterface $logger,
76
+        private NewUserMailHelper $newUserMailHelper,
77
+        private ISecureRandom $secureRandom,
78
+        private RemoteWipe $remoteWipe,
79
+        private KnownUserService $knownUserService,
80
+        private IEventDispatcher $eventDispatcher,
81
+        private IPhoneNumberUtil $phoneNumberUtil,
82
+    ) {
83
+        parent::__construct(
84
+            $appName,
85
+            $request,
86
+            $userManager,
87
+            $config,
88
+            $groupManager,
89
+            $userSession,
90
+            $accountManager,
91
+            $subAdminManager,
92
+            $l10nFactory,
93
+            $rootFolder,
94
+        );
95
+
96
+        $this->l10n = $l10nFactory->get($appName);
97
+    }
98
+
99
+    /**
100
+     * Get a list of users
101
+     *
102
+     * @param string $search Text to search for
103
+     * @param int|null $limit Limit the amount of groups returned
104
+     * @param int $offset Offset for searching for groups
105
+     * @return DataResponse<Http::STATUS_OK, array{users: list<string>}, array{}>
106
+     *
107
+     * 200: Users returned
108
+     */
109
+    #[NoAdminRequired]
110
+    public function getUsers(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
111
+        $user = $this->userSession->getUser();
112
+        $users = [];
113
+
114
+        // Admin? Or SubAdmin?
115
+        $uid = $user->getUID();
116
+        $subAdminManager = $this->groupManager->getSubAdmin();
117
+        $isAdmin = $this->groupManager->isAdmin($uid);
118
+        $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($uid);
119
+        if ($isAdmin || $isDelegatedAdmin) {
120
+            $users = $this->userManager->search($search, $limit, $offset);
121
+        } elseif ($subAdminManager->isSubAdmin($user)) {
122
+            $subAdminOfGroups = $subAdminManager->getSubAdminsGroups($user);
123
+            foreach ($subAdminOfGroups as $key => $group) {
124
+                $subAdminOfGroups[$key] = $group->getGID();
125
+            }
126
+
127
+            $users = [];
128
+            foreach ($subAdminOfGroups as $group) {
129
+                $users = array_merge($users, $this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
130
+            }
131
+        }
132
+
133
+        /** @var list<string> $users */
134
+        $users = array_keys($users);
135
+
136
+        return new DataResponse([
137
+            'users' => $users
138
+        ]);
139
+    }
140
+
141
+    /**
142
+     * Get a list of users and their details
143
+     *
144
+     * @param string $search Text to search for
145
+     * @param int|null $limit Limit the amount of groups returned
146
+     * @param int $offset Offset for searching for groups
147
+     * @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
148
+     *
149
+     * 200: Users details returned
150
+     */
151
+    #[NoAdminRequired]
152
+    public function getUsersDetails(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
153
+        $currentUser = $this->userSession->getUser();
154
+        $users = [];
155
+
156
+        // Admin? Or SubAdmin?
157
+        $uid = $currentUser->getUID();
158
+        $subAdminManager = $this->groupManager->getSubAdmin();
159
+        $isAdmin = $this->groupManager->isAdmin($uid);
160
+        $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($uid);
161
+        if ($isAdmin || $isDelegatedAdmin) {
162
+            $users = $this->userManager->search($search, $limit, $offset);
163
+            $users = array_keys($users);
164
+        } elseif ($subAdminManager->isSubAdmin($currentUser)) {
165
+            $subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
166
+            foreach ($subAdminOfGroups as $key => $group) {
167
+                $subAdminOfGroups[$key] = $group->getGID();
168
+            }
169
+
170
+            $users = [];
171
+            foreach ($subAdminOfGroups as $group) {
172
+                $users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
173
+            }
174
+            $users = array_merge(...$users);
175
+        }
176
+
177
+        $usersDetails = [];
178
+        foreach ($users as $userId) {
179
+            $userId = (string)$userId;
180
+            try {
181
+                $userData = $this->getUserData($userId);
182
+            } catch (OCSNotFoundException $e) {
183
+                // We still want to return all other accounts, but this one was removed from the backends
184
+                // yet they are still in our database. Might be a LDAP remnant.
185
+                $userData = null;
186
+                $this->logger->warning('Found one enabled account that is removed from its backend, but still exists in Nextcloud database', ['accountId' => $userId]);
187
+            }
188
+            // Do not insert empty entry
189
+            if ($userData !== null) {
190
+                $usersDetails[$userId] = $userData;
191
+            } else {
192
+                // Logged user does not have permissions to see this user
193
+                // only showing its id
194
+                $usersDetails[$userId] = ['id' => $userId];
195
+            }
196
+        }
197
+
198
+        return new DataResponse([
199
+            'users' => $usersDetails
200
+        ]);
201
+    }
202
+
203
+    /**
204
+     * Get the list of disabled users and their details
205
+     *
206
+     * @param string $search Text to search for
207
+     * @param ?int $limit Limit the amount of users returned
208
+     * @param int $offset Offset
209
+     * @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
210
+     *
211
+     * 200: Disabled users details returned
212
+     */
213
+    #[NoAdminRequired]
214
+    public function getDisabledUsersDetails(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
215
+        $currentUser = $this->userSession->getUser();
216
+        if ($currentUser === null) {
217
+            return new DataResponse(['users' => []]);
218
+        }
219
+        if ($limit !== null && $limit < 0) {
220
+            throw new InvalidArgumentException("Invalid limit value: $limit");
221
+        }
222
+        if ($offset < 0) {
223
+            throw new InvalidArgumentException("Invalid offset value: $offset");
224
+        }
225
+
226
+        $users = [];
227
+
228
+        // Admin? Or SubAdmin?
229
+        $uid = $currentUser->getUID();
230
+        $subAdminManager = $this->groupManager->getSubAdmin();
231
+        $isAdmin = $this->groupManager->isAdmin($uid);
232
+        $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($uid);
233
+        if ($isAdmin || $isDelegatedAdmin) {
234
+            $users = $this->userManager->getDisabledUsers($limit, $offset, $search);
235
+            $users = array_map(fn (IUser $user): string => $user->getUID(), $users);
236
+        } elseif ($subAdminManager->isSubAdmin($currentUser)) {
237
+            $subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
238
+
239
+            $users = [];
240
+            /* We have to handle offset ourselve for correctness */
241
+            $tempLimit = ($limit === null ? null : $limit + $offset);
242
+            foreach ($subAdminOfGroups as $group) {
243
+                $users = array_unique(array_merge(
244
+                    $users,
245
+                    array_map(
246
+                        fn (IUser $user): string => $user->getUID(),
247
+                        array_filter(
248
+                            $group->searchUsers($search),
249
+                            fn (IUser $user): bool => !$user->isEnabled()
250
+                        )
251
+                    )
252
+                ));
253
+                if (($tempLimit !== null) && (count($users) >= $tempLimit)) {
254
+                    break;
255
+                }
256
+            }
257
+            $users = array_slice($users, $offset, $limit);
258
+        }
259
+
260
+        $usersDetails = [];
261
+        foreach ($users as $userId) {
262
+            try {
263
+                $userData = $this->getUserData($userId);
264
+            } catch (OCSNotFoundException $e) {
265
+                // We still want to return all other accounts, but this one was removed from the backends
266
+                // yet they are still in our database. Might be a LDAP remnant.
267
+                $userData = null;
268
+                $this->logger->warning('Found one disabled account that was removed from its backend, but still exists in Nextcloud database', ['accountId' => $userId]);
269
+            }
270
+            // Do not insert empty entry
271
+            if ($userData !== null) {
272
+                $usersDetails[$userId] = $userData;
273
+            } else {
274
+                // Currently logged in user does not have permissions to see this user
275
+                // only showing its id
276
+                $usersDetails[$userId] = ['id' => $userId];
277
+            }
278
+        }
279
+
280
+        return new DataResponse([
281
+            'users' => $usersDetails
282
+        ]);
283
+    }
284
+
285
+    /**
286
+     * Gets the list of users sorted by lastLogin, from most recent to least recent
287
+     *
288
+     * @param string $search Text to search for
289
+     * @param ?int $limit Limit the amount of users returned
290
+     * @param int $offset Offset
291
+     * @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
292
+     *
293
+     * 200: Users details returned based on last logged in information
294
+     */
295
+    #[AuthorizedAdminSetting(settings:Users::class)]
296
+    public function getLastLoggedInUsers(string $search = '',
297
+        ?int $limit = null,
298
+        int $offset = 0,
299
+    ): DataResponse {
300
+        $currentUser = $this->userSession->getUser();
301
+        if ($currentUser === null) {
302
+            return new DataResponse(['users' => []]);
303
+        }
304
+        if ($limit !== null && $limit < 0) {
305
+            throw new InvalidArgumentException("Invalid limit value: $limit");
306
+        }
307
+        if ($offset < 0) {
308
+            throw new InvalidArgumentException("Invalid offset value: $offset");
309
+        }
310
+
311
+        $users = [];
312
+
313
+        // For Admin alone user sorting based on lastLogin. For sub admin and groups this is not supported
314
+        $users = $this->userManager->getLastLoggedInUsers($limit, $offset, $search);
315
+
316
+        $usersDetails = [];
317
+        foreach ($users as $userId) {
318
+            try {
319
+                $userData = $this->getUserData($userId);
320
+            } catch (OCSNotFoundException $e) {
321
+                // We still want to return all other accounts, but this one was removed from the backends
322
+                // yet they are still in our database. Might be a LDAP remnant.
323
+                $userData = null;
324
+                $this->logger->warning('Found one account that was removed from its backend, but still exists in Nextcloud database', ['accountId' => $userId]);
325
+            }
326
+            // Do not insert empty entry
327
+            if ($userData !== null) {
328
+                $usersDetails[$userId] = $userData;
329
+            } else {
330
+                // Currently logged-in user does not have permissions to see this user
331
+                // only showing its id
332
+                $usersDetails[$userId] = ['id' => $userId];
333
+            }
334
+        }
335
+
336
+        return new DataResponse([
337
+            'users' => $usersDetails
338
+        ]);
339
+    }
340
+
341
+
342
+
343
+    /**
344
+     * @NoSubAdminRequired
345
+     *
346
+     * Search users by their phone numbers
347
+     *
348
+     * @param string $location Location of the phone number (for country code)
349
+     * @param array<string, list<string>> $search Phone numbers to search for
350
+     * @return DataResponse<Http::STATUS_OK, array<string, string>, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, list<empty>, array{}>
351
+     *
352
+     * 200: Users returned
353
+     * 400: Invalid location
354
+     */
355
+    #[NoAdminRequired]
356
+    public function searchByPhoneNumbers(string $location, array $search): DataResponse {
357
+        if ($this->phoneNumberUtil->getCountryCodeForRegion($location) === null) {
358
+            // Not a valid region code
359
+            return new DataResponse([], Http::STATUS_BAD_REQUEST);
360
+        }
361
+
362
+        /** @var IUser $user */
363
+        $user = $this->userSession->getUser();
364
+        $knownTo = $user->getUID();
365
+        $defaultPhoneRegion = $this->config->getSystemValueString('default_phone_region');
366
+
367
+        $normalizedNumberToKey = [];
368
+        foreach ($search as $key => $phoneNumbers) {
369
+            foreach ($phoneNumbers as $phone) {
370
+                $normalizedNumber = $this->phoneNumberUtil->convertToStandardFormat($phone, $location);
371
+                if ($normalizedNumber !== null) {
372
+                    $normalizedNumberToKey[$normalizedNumber] = (string)$key;
373
+                }
374
+
375
+                if ($defaultPhoneRegion !== '' && $defaultPhoneRegion !== $location && str_starts_with($phone, '0')) {
376
+                    // If the number has a leading zero (no country code),
377
+                    // we also check the default phone region of the instance,
378
+                    // when it's different to the user's given region.
379
+                    $normalizedNumber = $this->phoneNumberUtil->convertToStandardFormat($phone, $defaultPhoneRegion);
380
+                    if ($normalizedNumber !== null) {
381
+                        $normalizedNumberToKey[$normalizedNumber] = (string)$key;
382
+                    }
383
+                }
384
+            }
385
+        }
386
+
387
+        $phoneNumbers = array_keys($normalizedNumberToKey);
388
+
389
+        if (empty($phoneNumbers)) {
390
+            return new DataResponse();
391
+        }
392
+
393
+        // Cleanup all previous entries and only allow new matches
394
+        $this->knownUserService->deleteKnownTo($knownTo);
395
+
396
+        $userMatches = $this->accountManager->searchUsers(IAccountManager::PROPERTY_PHONE, $phoneNumbers);
397
+
398
+        if (empty($userMatches)) {
399
+            return new DataResponse();
400
+        }
401
+
402
+        $cloudUrl = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/');
403
+        if (strpos($cloudUrl, 'http://') === 0) {
404
+            $cloudUrl = substr($cloudUrl, strlen('http://'));
405
+        } elseif (strpos($cloudUrl, 'https://') === 0) {
406
+            $cloudUrl = substr($cloudUrl, strlen('https://'));
407
+        }
408
+
409
+        $matches = [];
410
+        foreach ($userMatches as $phone => $userId) {
411
+            // Not using the ICloudIdManager as that would run a search for each contact to find the display name in the address book
412
+            $matches[$normalizedNumberToKey[$phone]] = $userId . '@' . $cloudUrl;
413
+            $this->knownUserService->storeIsKnownToUser($knownTo, $userId);
414
+        }
415
+
416
+        return new DataResponse($matches);
417
+    }
418
+
419
+    /**
420
+     * @throws OCSException
421
+     */
422
+    private function createNewUserId(): string {
423
+        $attempts = 0;
424
+        do {
425
+            $uidCandidate = $this->secureRandom->generate(10, ISecureRandom::CHAR_HUMAN_READABLE);
426
+            if (!$this->userManager->userExists($uidCandidate)) {
427
+                return $uidCandidate;
428
+            }
429
+            $attempts++;
430
+        } while ($attempts < 10);
431
+        throw new OCSException($this->l10n->t('Could not create non-existing user ID'), 111);
432
+    }
433
+
434
+    /**
435
+     * Create a new user
436
+     *
437
+     * @param string $userid ID of the user
438
+     * @param string $password Password of the user
439
+     * @param string $displayName Display name of the user
440
+     * @param string $email Email of the user
441
+     * @param list<string> $groups Groups of the user
442
+     * @param list<string> $subadmin Groups where the user is subadmin
443
+     * @param string $quota Quota of the user
444
+     * @param string $language Language of the user
445
+     * @param ?string $manager Manager of the user
446
+     * @return DataResponse<Http::STATUS_OK, array{id: string}, array{}>
447
+     * @throws OCSException
448
+     * @throws OCSForbiddenException Missing permissions to make user subadmin
449
+     *
450
+     * 200: User added successfully
451
+     */
452
+    #[PasswordConfirmationRequired]
453
+    #[NoAdminRequired]
454
+    public function addUser(
455
+        string $userid,
456
+        string $password = '',
457
+        string $displayName = '',
458
+        string $email = '',
459
+        array $groups = [],
460
+        array $subadmin = [],
461
+        string $quota = '',
462
+        string $language = '',
463
+        ?string $manager = null,
464
+    ): DataResponse {
465
+        $user = $this->userSession->getUser();
466
+        $isAdmin = $this->groupManager->isAdmin($user->getUID());
467
+        $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($user->getUID());
468
+        $subAdminManager = $this->groupManager->getSubAdmin();
469
+
470
+        if (empty($userid) && $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes') {
471
+            $userid = $this->createNewUserId();
472
+        }
473
+
474
+        if ($this->userManager->userExists($userid)) {
475
+            $this->logger->error('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']);
476
+            throw new OCSException($this->l10n->t('User already exists'), 102);
477
+        }
478
+
479
+        if ($groups !== []) {
480
+            foreach ($groups as $group) {
481
+                if (!$this->groupManager->groupExists($group)) {
482
+                    throw new OCSException($this->l10n->t('Group %1$s does not exist', [$group]), 104);
483
+                }
484
+                if (!$isAdmin && !($isDelegatedAdmin && $group !== 'admin') && !$subAdminManager->isSubAdminOfGroup($user, $this->groupManager->get($group))) {
485
+                    throw new OCSException($this->l10n->t('Insufficient privileges for group %1$s', [$group]), 105);
486
+                }
487
+            }
488
+        } else {
489
+            if (!$isAdmin && !$isDelegatedAdmin) {
490
+                throw new OCSException($this->l10n->t('No group specified (required for sub-admins)'), 106);
491
+            }
492
+        }
493
+
494
+        $subadminGroups = [];
495
+        if ($subadmin !== []) {
496
+            foreach ($subadmin as $groupid) {
497
+                $group = $this->groupManager->get($groupid);
498
+                // Check if group exists
499
+                if ($group === null) {
500
+                    throw new OCSException($this->l10n->t('Sub-admin group does not exist'), 109);
501
+                }
502
+                // Check if trying to make subadmin of admin group
503
+                if ($group->getGID() === 'admin') {
504
+                    throw new OCSException($this->l10n->t('Cannot create sub-admins for admin group'), 103);
505
+                }
506
+                // Check if has permission to promote subadmins
507
+                if (!$subAdminManager->isSubAdminOfGroup($user, $group) && !$isAdmin && !$isDelegatedAdmin) {
508
+                    throw new OCSForbiddenException($this->l10n->t('No permissions to promote sub-admins'));
509
+                }
510
+                $subadminGroups[] = $group;
511
+            }
512
+        }
513
+
514
+        $generatePasswordResetToken = false;
515
+        if (strlen($password) > IUserManager::MAX_PASSWORD_LENGTH) {
516
+            throw new OCSException($this->l10n->t('Invalid password value'), 101);
517
+        }
518
+        if ($password === '') {
519
+            if ($email === '') {
520
+                throw new OCSException($this->l10n->t('An email address is required, to send a password link to the user.'), 108);
521
+            }
522
+
523
+            $passwordEvent = new GenerateSecurePasswordEvent();
524
+            $this->eventDispatcher->dispatchTyped($passwordEvent);
525
+
526
+            $password = $passwordEvent->getPassword();
527
+            if ($password === null) {
528
+                // Fallback: ensure to pass password_policy in any case
529
+                $password = $this->secureRandom->generate(10)
530
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_UPPER)
531
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_LOWER)
532
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_DIGITS)
533
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_SYMBOLS);
534
+            }
535
+            $generatePasswordResetToken = true;
536
+        }
537
+
538
+        if ($email === '' && $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes') {
539
+            throw new OCSException($this->l10n->t('Required email address was not provided'), 110);
540
+        }
541
+
542
+        try {
543
+            $newUser = $this->userManager->createUser($userid, $password);
544
+            $this->logger->info('Successful addUser call with userid: ' . $userid, ['app' => 'ocs_api']);
545
+
546
+            foreach ($groups as $group) {
547
+                $this->groupManager->get($group)->addUser($newUser);
548
+                $this->logger->info('Added userid ' . $userid . ' to group ' . $group, ['app' => 'ocs_api']);
549
+            }
550
+            foreach ($subadminGroups as $group) {
551
+                $subAdminManager->createSubAdmin($newUser, $group);
552
+            }
553
+
554
+            if ($displayName !== '') {
555
+                try {
556
+                    $this->editUser($userid, self::USER_FIELD_DISPLAYNAME, $displayName);
557
+                } catch (OCSException $e) {
558
+                    if ($newUser instanceof IUser) {
559
+                        $newUser->delete();
560
+                    }
561
+                    throw $e;
562
+                }
563
+            }
564
+
565
+            if ($quota !== '') {
566
+                $this->editUser($userid, self::USER_FIELD_QUOTA, $quota);
567
+            }
568
+
569
+            if ($language !== '') {
570
+                $this->editUser($userid, self::USER_FIELD_LANGUAGE, $language);
571
+            }
572
+
573
+            /**
574
+             * null -> nothing sent
575
+             * '' -> unset manager
576
+             * else -> set manager
577
+             */
578
+            if ($manager !== null) {
579
+                $this->editUser($userid, self::USER_FIELD_MANAGER, $manager);
580
+            }
581
+
582
+            // Send new user mail only if a mail is set
583
+            if ($email !== '') {
584
+                $newUser->setEMailAddress($email);
585
+                if ($this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes') {
586
+                    try {
587
+                        $emailTemplate = $this->newUserMailHelper->generateTemplate($newUser, $generatePasswordResetToken);
588
+                        $this->newUserMailHelper->sendMail($newUser, $emailTemplate);
589
+                    } catch (\Exception $e) {
590
+                        // Mail could be failing hard or just be plain not configured
591
+                        // Logging error as it is the hardest of the two
592
+                        $this->logger->error(
593
+                            "Unable to send the invitation mail to $email",
594
+                            [
595
+                                'app' => 'ocs_api',
596
+                                'exception' => $e,
597
+                            ]
598
+                        );
599
+                    }
600
+                }
601
+            }
602
+
603
+            return new DataResponse(['id' => $userid]);
604
+        } catch (HintException $e) {
605
+            $this->logger->warning(
606
+                'Failed addUser attempt with hint exception.',
607
+                [
608
+                    'app' => 'ocs_api',
609
+                    'exception' => $e,
610
+                ]
611
+            );
612
+            throw new OCSException($e->getHint(), 107);
613
+        } catch (OCSException $e) {
614
+            $this->logger->warning(
615
+                'Failed addUser attempt with ocs exception.',
616
+                [
617
+                    'app' => 'ocs_api',
618
+                    'exception' => $e,
619
+                ]
620
+            );
621
+            throw $e;
622
+        } catch (InvalidArgumentException $e) {
623
+            $this->logger->error(
624
+                'Failed addUser attempt with invalid argument exception.',
625
+                [
626
+                    'app' => 'ocs_api',
627
+                    'exception' => $e,
628
+                ]
629
+            );
630
+            throw new OCSException($e->getMessage(), 101);
631
+        } catch (\Exception $e) {
632
+            $this->logger->error(
633
+                'Failed addUser attempt with exception.',
634
+                [
635
+                    'app' => 'ocs_api',
636
+                    'exception' => $e
637
+                ]
638
+            );
639
+            throw new OCSException('Bad request', 101);
640
+        }
641
+    }
642
+
643
+    /**
644
+     * @NoSubAdminRequired
645
+     *
646
+     * Get the details of a user
647
+     *
648
+     * @param string $userId ID of the user
649
+     * @return DataResponse<Http::STATUS_OK, Provisioning_APIUserDetails, array{}>
650
+     * @throws OCSException
651
+     *
652
+     * 200: User returned
653
+     */
654
+    #[NoAdminRequired]
655
+    public function getUser(string $userId): DataResponse {
656
+        $includeScopes = false;
657
+        $currentUser = $this->userSession->getUser();
658
+        if ($currentUser && $currentUser->getUID() === $userId) {
659
+            $includeScopes = true;
660
+        }
661
+
662
+        $data = $this->getUserData($userId, $includeScopes);
663
+        // getUserData returns null if not enough permissions
664
+        if ($data === null) {
665
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
666
+        }
667
+        return new DataResponse($data);
668
+    }
669
+
670
+    /**
671
+     * @NoSubAdminRequired
672
+     *
673
+     * Get the details of the current user
674
+     *
675
+     * @return DataResponse<Http::STATUS_OK, Provisioning_APIUserDetails, array{}>
676
+     * @throws OCSException
677
+     *
678
+     * 200: Current user returned
679
+     */
680
+    #[NoAdminRequired]
681
+    public function getCurrentUser(): DataResponse {
682
+        $user = $this->userSession->getUser();
683
+        if ($user) {
684
+            /** @var Provisioning_APIUserDetails $data */
685
+            $data = $this->getUserData($user->getUID(), true);
686
+            return new DataResponse($data);
687
+        }
688
+
689
+        throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
690
+    }
691
+
692
+    /**
693
+     * @NoSubAdminRequired
694
+     *
695
+     * Get a list of fields that are editable for the current user
696
+     *
697
+     * @return DataResponse<Http::STATUS_OK, list<string>, array{}>
698
+     * @throws OCSException
699
+     *
700
+     * 200: Editable fields returned
701
+     */
702
+    #[NoAdminRequired]
703
+    public function getEditableFields(): DataResponse {
704
+        $currentLoggedInUser = $this->userSession->getUser();
705
+        if (!$currentLoggedInUser instanceof IUser) {
706
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
707
+        }
708
+
709
+        return $this->getEditableFieldsForUser($currentLoggedInUser->getUID());
710
+    }
711
+
712
+    /**
713
+     * @NoSubAdminRequired
714
+     *
715
+     * Get a list of fields that are editable for a user
716
+     *
717
+     * @param string $userId ID of the user
718
+     * @return DataResponse<Http::STATUS_OK, list<string>, array{}>
719
+     * @throws OCSException
720
+     *
721
+     * 200: Editable fields for user returned
722
+     */
723
+    #[NoAdminRequired]
724
+    public function getEditableFieldsForUser(string $userId): DataResponse {
725
+        $currentLoggedInUser = $this->userSession->getUser();
726
+        if (!$currentLoggedInUser instanceof IUser) {
727
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
728
+        }
729
+
730
+        $permittedFields = [];
731
+
732
+        if ($userId !== $currentLoggedInUser->getUID()) {
733
+            $targetUser = $this->userManager->get($userId);
734
+            if (!$targetUser instanceof IUser) {
735
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
736
+            }
737
+
738
+            $subAdminManager = $this->groupManager->getSubAdmin();
739
+            $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
740
+            $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
741
+            if (
742
+                !($isAdmin || $isDelegatedAdmin)
743
+                && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
744
+            ) {
745
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
746
+            }
747
+        } else {
748
+            $targetUser = $currentLoggedInUser;
749
+        }
750
+
751
+        $allowDisplayNameChange = $this->config->getSystemValue('allow_user_to_change_display_name', true);
752
+        if ($allowDisplayNameChange === true && (
753
+            $targetUser->getBackend() instanceof ISetDisplayNameBackend
754
+            || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
755
+        )) {
756
+            $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
757
+        }
758
+
759
+        // Fallback to display name value to avoid changing behavior with the new option.
760
+        if ($this->config->getSystemValue('allow_user_to_change_email', true)) {
761
+            $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
762
+        }
763
+
764
+        $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
765
+        $permittedFields[] = IAccountManager::PROPERTY_PHONE;
766
+        $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
767
+        $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
768
+        $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
769
+        $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
770
+        $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
771
+        $permittedFields[] = IAccountManager::PROPERTY_ROLE;
772
+        $permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
773
+        $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
774
+        $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
775
+        $permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
776
+
777
+        return new DataResponse($permittedFields);
778
+    }
779
+
780
+    /**
781
+     * @NoSubAdminRequired
782
+     *
783
+     * Update multiple values of the user's details
784
+     *
785
+     * @param string $userId ID of the user
786
+     * @param string $collectionName Collection to update
787
+     * @param string $key Key that will be updated
788
+     * @param string $value New value for the key
789
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
790
+     * @throws OCSException
791
+     *
792
+     * 200: User values edited successfully
793
+     */
794
+    #[PasswordConfirmationRequired]
795
+    #[NoAdminRequired]
796
+    #[UserRateLimit(limit: 5, period: 60)]
797
+    public function editUserMultiValue(
798
+        string $userId,
799
+        string $collectionName,
800
+        string $key,
801
+        string $value,
802
+    ): DataResponse {
803
+        $currentLoggedInUser = $this->userSession->getUser();
804
+        if ($currentLoggedInUser === null) {
805
+            throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
806
+        }
807
+
808
+        $targetUser = $this->userManager->get($userId);
809
+        if ($targetUser === null) {
810
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
811
+        }
812
+
813
+        $subAdminManager = $this->groupManager->getSubAdmin();
814
+        $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
815
+        $isAdminOrSubadmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID())
816
+            || $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser);
817
+
818
+        $permittedFields = [];
819
+        if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
820
+            // Editing self (display, email)
821
+            $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
822
+            $permittedFields[] = IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX;
823
+        } else {
824
+            // Check if admin / subadmin
825
+            if ($isAdminOrSubadmin || $isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) {
826
+                // They have permissions over the user
827
+                $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
828
+            } else {
829
+                // No rights
830
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
831
+            }
832
+        }
833
+
834
+        // Check if permitted to edit this field
835
+        if (!in_array($collectionName, $permittedFields)) {
836
+            throw new OCSException('', 103);
837
+        }
838
+
839
+        switch ($collectionName) {
840
+            case IAccountManager::COLLECTION_EMAIL:
841
+                $userAccount = $this->accountManager->getAccount($targetUser);
842
+                $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
843
+                $mailCollection->removePropertyByValue($key);
844
+                if ($value !== '') {
845
+                    $mailCollection->addPropertyWithDefaults($value);
846
+                    $property = $mailCollection->getPropertyByValue($key);
847
+                    if ($isAdminOrSubadmin && $property) {
848
+                        // admin set mails are auto-verified
849
+                        $property->setLocallyVerified(IAccountManager::VERIFIED);
850
+                    }
851
+                }
852
+                $this->accountManager->updateAccount($userAccount);
853
+                if ($value === '' && $key === $targetUser->getPrimaryEMailAddress()) {
854
+                    $targetUser->setPrimaryEMailAddress('');
855
+                }
856
+                break;
857
+
858
+            case IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX:
859
+                $userAccount = $this->accountManager->getAccount($targetUser);
860
+                $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
861
+                $targetProperty = null;
862
+                foreach ($mailCollection->getProperties() as $property) {
863
+                    if ($property->getValue() === $key) {
864
+                        $targetProperty = $property;
865
+                        break;
866
+                    }
867
+                }
868
+                if ($targetProperty instanceof IAccountProperty) {
869
+                    try {
870
+                        $targetProperty->setScope($value);
871
+                        $this->accountManager->updateAccount($userAccount);
872
+                    } catch (InvalidArgumentException $e) {
873
+                        throw new OCSException('', 102);
874
+                    }
875
+                } else {
876
+                    throw new OCSException('', 102);
877
+                }
878
+                break;
879
+
880
+            default:
881
+                throw new OCSException('', 103);
882
+        }
883
+        return new DataResponse();
884
+    }
885
+
886
+    /**
887
+     * @NoSubAdminRequired
888
+     *
889
+     * Update a value of the user's details
890
+     *
891
+     * @param string $userId ID of the user
892
+     * @param string $key Key that will be updated
893
+     * @param string $value New value for the key
894
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
895
+     * @throws OCSException
896
+     *
897
+     * 200: User value edited successfully
898
+     */
899
+    #[PasswordConfirmationRequired]
900
+    #[NoAdminRequired]
901
+    #[UserRateLimit(limit: 50, period: 600)]
902
+    public function editUser(string $userId, string $key, string $value): DataResponse {
903
+        $currentLoggedInUser = $this->userSession->getUser();
904
+
905
+        $targetUser = $this->userManager->get($userId);
906
+        if ($targetUser === null) {
907
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
908
+        }
909
+
910
+        $permittedFields = [];
911
+        if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
912
+            $allowDisplayNameChange = $this->config->getSystemValue('allow_user_to_change_display_name', true);
913
+            if ($allowDisplayNameChange !== false && (
914
+                $targetUser->getBackend() instanceof ISetDisplayNameBackend
915
+                || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
916
+            )) {
917
+                $permittedFields[] = self::USER_FIELD_DISPLAYNAME;
918
+                $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
919
+            }
920
+
921
+            if ($this->config->getSystemValue('allow_user_to_change_email', true)) {
922
+                $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
923
+            }
924
+
925
+            $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX;
926
+            $permittedFields[] = IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX;
927
+
928
+            $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
929
+
930
+            $permittedFields[] = self::USER_FIELD_PASSWORD;
931
+            $permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
932
+            if (
933
+                $this->config->getSystemValue('force_language', false) === false ||
934
+                $this->groupManager->isAdmin($currentLoggedInUser->getUID()) ||
935
+                $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID())
936
+            ) {
937
+                $permittedFields[] = self::USER_FIELD_LANGUAGE;
938
+            }
939
+
940
+            if (
941
+                $this->config->getSystemValue('force_locale', false) === false ||
942
+                $this->groupManager->isAdmin($currentLoggedInUser->getUID()) ||
943
+                $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID())
944
+            ) {
945
+                $permittedFields[] = self::USER_FIELD_LOCALE;
946
+                $permittedFields[] = self::USER_FIELD_FIRST_DAY_OF_WEEK;
947
+            }
948
+
949
+            $permittedFields[] = IAccountManager::PROPERTY_PHONE;
950
+            $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
951
+            $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
952
+            $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
953
+            $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
954
+            $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
955
+            $permittedFields[] = IAccountManager::PROPERTY_ROLE;
956
+            $permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
957
+            $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
958
+            $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
959
+            $permittedFields[] = IAccountManager::PROPERTY_BIRTHDATE;
960
+            $permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
961
+
962
+            $permittedFields[] = IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX;
963
+            $permittedFields[] = IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX;
964
+            $permittedFields[] = IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX;
965
+            $permittedFields[] = IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX;
966
+            $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE . self::SCOPE_SUFFIX;
967
+            $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX;
968
+            $permittedFields[] = IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX;
969
+            $permittedFields[] = IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX;
970
+            $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX;
971
+            $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX;
972
+            $permittedFields[] = IAccountManager::PROPERTY_BIRTHDATE . self::SCOPE_SUFFIX;
973
+            $permittedFields[] = IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX;
974
+            $permittedFields[] = IAccountManager::PROPERTY_PRONOUNS . self::SCOPE_SUFFIX;
975
+
976
+            // If admin they can edit their own quota and manager
977
+            $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
978
+            $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
979
+            if ($isAdmin || $isDelegatedAdmin) {
980
+                $permittedFields[] = self::USER_FIELD_QUOTA;
981
+                $permittedFields[] = self::USER_FIELD_MANAGER;
982
+            }
983
+        } else {
984
+            // Check if admin / subadmin
985
+            $subAdminManager = $this->groupManager->getSubAdmin();
986
+            if (
987
+                $this->groupManager->isAdmin($currentLoggedInUser->getUID()) ||
988
+                $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID()) && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')
989
+                || $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
990
+            ) {
991
+                // They have permissions over the user
992
+                if (
993
+                    $targetUser->getBackend() instanceof ISetDisplayNameBackend
994
+                    || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
995
+                ) {
996
+                    $permittedFields[] = self::USER_FIELD_DISPLAYNAME;
997
+                    $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
998
+                }
999
+                $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
1000
+                $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
1001
+                $permittedFields[] = self::USER_FIELD_PASSWORD;
1002
+                $permittedFields[] = self::USER_FIELD_LANGUAGE;
1003
+                $permittedFields[] = self::USER_FIELD_LOCALE;
1004
+                $permittedFields[] = self::USER_FIELD_FIRST_DAY_OF_WEEK;
1005
+                $permittedFields[] = IAccountManager::PROPERTY_PHONE;
1006
+                $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
1007
+                $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
1008
+                $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
1009
+                $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
1010
+                $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
1011
+                $permittedFields[] = IAccountManager::PROPERTY_ROLE;
1012
+                $permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
1013
+                $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
1014
+                $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
1015
+                $permittedFields[] = IAccountManager::PROPERTY_PRONOUNS;
1016
+                $permittedFields[] = self::USER_FIELD_QUOTA;
1017
+                $permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
1018
+                $permittedFields[] = self::USER_FIELD_MANAGER;
1019
+            } else {
1020
+                // No rights
1021
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1022
+            }
1023
+        }
1024
+        // Check if permitted to edit this field
1025
+        if (!in_array($key, $permittedFields)) {
1026
+            throw new OCSException('', 113);
1027
+        }
1028
+        // Process the edit
1029
+        switch ($key) {
1030
+            case self::USER_FIELD_DISPLAYNAME:
1031
+            case IAccountManager::PROPERTY_DISPLAYNAME:
1032
+                try {
1033
+                    $targetUser->setDisplayName($value);
1034
+                } catch (InvalidArgumentException $e) {
1035
+                    throw new OCSException($e->getMessage(), 101);
1036
+                }
1037
+                break;
1038
+            case self::USER_FIELD_QUOTA:
1039
+                $quota = $value;
1040
+                if ($quota !== 'none' && $quota !== 'default') {
1041
+                    if (is_numeric($quota)) {
1042
+                        $quota = (float)$quota;
1043
+                    } else {
1044
+                        $quota = Util::computerFileSize($quota);
1045
+                    }
1046
+                    if ($quota === false) {
1047
+                        throw new OCSException($this->l10n->t('Invalid quota value: %1$s', [$value]), 101);
1048
+                    }
1049
+                    if ($quota === -1) {
1050
+                        $quota = 'none';
1051
+                    } else {
1052
+                        $maxQuota = (int)$this->config->getAppValue('files', 'max_quota', '-1');
1053
+                        if ($maxQuota !== -1 && $quota > $maxQuota) {
1054
+                            throw new OCSException($this->l10n->t('Invalid quota value. %1$s is exceeding the maximum quota', [$value]), 101);
1055
+                        }
1056
+                        $quota = Util::humanFileSize($quota);
1057
+                    }
1058
+                }
1059
+                // no else block because quota can be set to 'none' in previous if
1060
+                if ($quota === 'none') {
1061
+                    $allowUnlimitedQuota = $this->config->getAppValue('files', 'allow_unlimited_quota', '1') === '1';
1062
+                    if (!$allowUnlimitedQuota) {
1063
+                        throw new OCSException($this->l10n->t('Unlimited quota is forbidden on this instance'), 101);
1064
+                    }
1065
+                }
1066
+                $targetUser->setQuota($quota);
1067
+                break;
1068
+            case self::USER_FIELD_MANAGER:
1069
+                $targetUser->setManagerUids([$value]);
1070
+                break;
1071
+            case self::USER_FIELD_PASSWORD:
1072
+                try {
1073
+                    if (strlen($value) > IUserManager::MAX_PASSWORD_LENGTH) {
1074
+                        throw new OCSException($this->l10n->t('Invalid password value'), 101);
1075
+                    }
1076
+                    if (!$targetUser->canChangePassword()) {
1077
+                        throw new OCSException($this->l10n->t('Setting the password is not supported by the users backend'), 112);
1078
+                    }
1079
+                    $targetUser->setPassword($value);
1080
+                } catch (HintException $e) { // password policy error
1081
+                    throw new OCSException($e->getHint(), 107);
1082
+                }
1083
+                break;
1084
+            case self::USER_FIELD_LANGUAGE:
1085
+                $languagesCodes = $this->l10nFactory->findAvailableLanguages();
1086
+                if (!in_array($value, $languagesCodes, true) && $value !== 'en') {
1087
+                    throw new OCSException($this->l10n->t('Invalid language'), 101);
1088
+                }
1089
+                $this->config->setUserValue($targetUser->getUID(), 'core', 'lang', $value);
1090
+                break;
1091
+            case self::USER_FIELD_LOCALE:
1092
+                if (!$this->l10nFactory->localeExists($value)) {
1093
+                    throw new OCSException($this->l10n->t('Invalid locale'), 101);
1094
+                }
1095
+                $this->config->setUserValue($targetUser->getUID(), 'core', 'locale', $value);
1096
+                break;
1097
+            case self::USER_FIELD_FIRST_DAY_OF_WEEK:
1098
+                $intValue = (int)$value;
1099
+                if ($intValue < -1 || $intValue > 6) {
1100
+                    throw new OCSException($this->l10n->t('Invalid first day of week'), 101);
1101
+                }
1102
+                if ($intValue === -1) {
1103
+                    $this->config->deleteUserValue($targetUser->getUID(), 'core', AUserDataOCSController::USER_FIELD_FIRST_DAY_OF_WEEK);
1104
+                } else {
1105
+                    $this->config->setUserValue($targetUser->getUID(), 'core', AUserDataOCSController::USER_FIELD_FIRST_DAY_OF_WEEK, $value);
1106
+                }
1107
+                break;
1108
+            case self::USER_FIELD_NOTIFICATION_EMAIL:
1109
+                $success = false;
1110
+                if ($value === '' || filter_var($value, FILTER_VALIDATE_EMAIL)) {
1111
+                    try {
1112
+                        $targetUser->setPrimaryEMailAddress($value);
1113
+                        $success = true;
1114
+                    } catch (InvalidArgumentException $e) {
1115
+                        $this->logger->info(
1116
+                            'Cannot set primary email, because provided address is not verified',
1117
+                            [
1118
+                                'app' => 'provisioning_api',
1119
+                                'exception' => $e,
1120
+                            ]
1121
+                        );
1122
+                    }
1123
+                }
1124
+                if (!$success) {
1125
+                    throw new OCSException('', 101);
1126
+                }
1127
+                break;
1128
+            case IAccountManager::PROPERTY_EMAIL:
1129
+                if (filter_var($value, FILTER_VALIDATE_EMAIL) || $value === '') {
1130
+                    $targetUser->setEMailAddress($value);
1131
+                } else {
1132
+                    throw new OCSException('', 101);
1133
+                }
1134
+                break;
1135
+            case IAccountManager::COLLECTION_EMAIL:
1136
+                if (filter_var($value, FILTER_VALIDATE_EMAIL) && $value !== $targetUser->getSystemEMailAddress()) {
1137
+                    $userAccount = $this->accountManager->getAccount($targetUser);
1138
+                    $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
1139
+
1140
+                    if ($mailCollection->getPropertyByValue($value)) {
1141
+                        throw new OCSException('', 101);
1142
+                    }
1143
+
1144
+                    $mailCollection->addPropertyWithDefaults($value);
1145
+                    $this->accountManager->updateAccount($userAccount);
1146
+                } else {
1147
+                    throw new OCSException('', 101);
1148
+                }
1149
+                break;
1150
+            case IAccountManager::PROPERTY_PHONE:
1151
+            case IAccountManager::PROPERTY_ADDRESS:
1152
+            case IAccountManager::PROPERTY_WEBSITE:
1153
+            case IAccountManager::PROPERTY_TWITTER:
1154
+            case IAccountManager::PROPERTY_FEDIVERSE:
1155
+            case IAccountManager::PROPERTY_ORGANISATION:
1156
+            case IAccountManager::PROPERTY_ROLE:
1157
+            case IAccountManager::PROPERTY_HEADLINE:
1158
+            case IAccountManager::PROPERTY_BIOGRAPHY:
1159
+            case IAccountManager::PROPERTY_BIRTHDATE:
1160
+            case IAccountManager::PROPERTY_PRONOUNS:
1161
+                $userAccount = $this->accountManager->getAccount($targetUser);
1162
+                try {
1163
+                    $userProperty = $userAccount->getProperty($key);
1164
+                    if ($userProperty->getValue() !== $value) {
1165
+                        try {
1166
+                            $userProperty->setValue($value);
1167
+                            if ($userProperty->getName() === IAccountManager::PROPERTY_PHONE) {
1168
+                                $this->knownUserService->deleteByContactUserId($targetUser->getUID());
1169
+                            }
1170
+                        } catch (InvalidArgumentException $e) {
1171
+                            throw new OCSException('Invalid ' . $e->getMessage(), 101);
1172
+                        }
1173
+                    }
1174
+                } catch (PropertyDoesNotExistException $e) {
1175
+                    $userAccount->setProperty($key, $value, IAccountManager::SCOPE_PRIVATE, IAccountManager::NOT_VERIFIED);
1176
+                }
1177
+                try {
1178
+                    $this->accountManager->updateAccount($userAccount);
1179
+                } catch (InvalidArgumentException $e) {
1180
+                    throw new OCSException('Invalid ' . $e->getMessage(), 101);
1181
+                }
1182
+                break;
1183
+            case IAccountManager::PROPERTY_PROFILE_ENABLED:
1184
+                $userAccount = $this->accountManager->getAccount($targetUser);
1185
+                try {
1186
+                    $userProperty = $userAccount->getProperty($key);
1187
+                    if ($userProperty->getValue() !== $value) {
1188
+                        $userProperty->setValue($value);
1189
+                    }
1190
+                } catch (PropertyDoesNotExistException $e) {
1191
+                    $userAccount->setProperty($key, $value, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
1192
+                }
1193
+                $this->accountManager->updateAccount($userAccount);
1194
+                break;
1195
+            case IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX:
1196
+            case IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX:
1197
+            case IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX:
1198
+            case IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX:
1199
+            case IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX:
1200
+            case IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX:
1201
+            case IAccountManager::PROPERTY_FEDIVERSE . self::SCOPE_SUFFIX:
1202
+            case IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX:
1203
+            case IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX:
1204
+            case IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX:
1205
+            case IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX:
1206
+            case IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX:
1207
+            case IAccountManager::PROPERTY_BIRTHDATE . self::SCOPE_SUFFIX:
1208
+            case IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX:
1209
+            case IAccountManager::PROPERTY_PRONOUNS . self::SCOPE_SUFFIX:
1210
+                $propertyName = substr($key, 0, strlen($key) - strlen(self::SCOPE_SUFFIX));
1211
+                $userAccount = $this->accountManager->getAccount($targetUser);
1212
+                $userProperty = $userAccount->getProperty($propertyName);
1213
+                if ($userProperty->getScope() !== $value) {
1214
+                    try {
1215
+                        $userProperty->setScope($value);
1216
+                        $this->accountManager->updateAccount($userAccount);
1217
+                    } catch (InvalidArgumentException $e) {
1218
+                        throw new OCSException('Invalid ' . $e->getMessage(), 101);
1219
+                    }
1220
+                }
1221
+                break;
1222
+            default:
1223
+                throw new OCSException('', 113);
1224
+        }
1225
+        return new DataResponse();
1226
+    }
1227
+
1228
+    /**
1229
+     * Wipe all devices of a user
1230
+     *
1231
+     * @param string $userId ID of the user
1232
+     *
1233
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1234
+     *
1235
+     * @throws OCSException
1236
+     *
1237
+     * 200: Wiped all user devices successfully
1238
+     */
1239
+    #[PasswordConfirmationRequired]
1240
+    #[NoAdminRequired]
1241
+    public function wipeUserDevices(string $userId): DataResponse {
1242
+        /** @var IUser $currentLoggedInUser */
1243
+        $currentLoggedInUser = $this->userSession->getUser();
1244
+
1245
+        $targetUser = $this->userManager->get($userId);
1246
+
1247
+        if ($targetUser === null) {
1248
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1249
+        }
1250
+
1251
+        if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
1252
+            throw new OCSException('', 101);
1253
+        }
1254
+
1255
+        // If not permitted
1256
+        $subAdminManager = $this->groupManager->getSubAdmin();
1257
+        $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
1258
+        $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
1259
+        if (!$isAdmin && !($isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
1260
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1261
+        }
1262
+
1263
+        $this->remoteWipe->markAllTokensForWipe($targetUser);
1264
+
1265
+        return new DataResponse();
1266
+    }
1267
+
1268
+    /**
1269
+     * Delete a user
1270
+     *
1271
+     * @param string $userId ID of the user
1272
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1273
+     * @throws OCSException
1274
+     *
1275
+     * 200: User deleted successfully
1276
+     */
1277
+    #[PasswordConfirmationRequired]
1278
+    #[NoAdminRequired]
1279
+    public function deleteUser(string $userId): DataResponse {
1280
+        $currentLoggedInUser = $this->userSession->getUser();
1281
+
1282
+        $targetUser = $this->userManager->get($userId);
1283
+
1284
+        if ($targetUser === null) {
1285
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1286
+        }
1287
+
1288
+        if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
1289
+            throw new OCSException('', 101);
1290
+        }
1291
+
1292
+        // If not permitted
1293
+        $subAdminManager = $this->groupManager->getSubAdmin();
1294
+        $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
1295
+        $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
1296
+        if (!$isAdmin && !($isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
1297
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1298
+        }
1299
+
1300
+        // Go ahead with the delete
1301
+        if ($targetUser->delete()) {
1302
+            return new DataResponse();
1303
+        } else {
1304
+            throw new OCSException('', 101);
1305
+        }
1306
+    }
1307
+
1308
+    /**
1309
+     * Disable a user
1310
+     *
1311
+     * @param string $userId ID of the user
1312
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1313
+     * @throws OCSException
1314
+     *
1315
+     * 200: User disabled successfully
1316
+     */
1317
+    #[PasswordConfirmationRequired]
1318
+    #[NoAdminRequired]
1319
+    public function disableUser(string $userId): DataResponse {
1320
+        return $this->setEnabled($userId, false);
1321
+    }
1322
+
1323
+    /**
1324
+     * Enable a user
1325
+     *
1326
+     * @param string $userId ID of the user
1327
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1328
+     * @throws OCSException
1329
+     *
1330
+     * 200: User enabled successfully
1331
+     */
1332
+    #[PasswordConfirmationRequired]
1333
+    #[NoAdminRequired]
1334
+    public function enableUser(string $userId): DataResponse {
1335
+        return $this->setEnabled($userId, true);
1336
+    }
1337
+
1338
+    /**
1339
+     * @param string $userId
1340
+     * @param bool $value
1341
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1342
+     * @throws OCSException
1343
+     */
1344
+    private function setEnabled(string $userId, bool $value): DataResponse {
1345
+        $currentLoggedInUser = $this->userSession->getUser();
1346
+
1347
+        $targetUser = $this->userManager->get($userId);
1348
+        if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
1349
+            throw new OCSException('', 101);
1350
+        }
1351
+
1352
+        // If not permitted
1353
+        $subAdminManager = $this->groupManager->getSubAdmin();
1354
+        $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
1355
+        $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
1356
+        if (!$isAdmin && !($isDelegatedAdmin && !$this->groupManager->isInGroup($targetUser->getUID(), 'admin')) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
1357
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1358
+        }
1359
+
1360
+        // enable/disable the user now
1361
+        $targetUser->setEnabled($value);
1362
+        return new DataResponse();
1363
+    }
1364
+
1365
+    /**
1366
+     * @NoSubAdminRequired
1367
+     *
1368
+     * Get a list of groups the user belongs to
1369
+     *
1370
+     * @param string $userId ID of the user
1371
+     * @return DataResponse<Http::STATUS_OK, array{groups: list<string>}, array{}>
1372
+     * @throws OCSException
1373
+     *
1374
+     * 200: Users groups returned
1375
+     */
1376
+    #[NoAdminRequired]
1377
+    public function getUsersGroups(string $userId): DataResponse {
1378
+        $loggedInUser = $this->userSession->getUser();
1379
+
1380
+        $targetUser = $this->userManager->get($userId);
1381
+        if ($targetUser === null) {
1382
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1383
+        }
1384
+
1385
+        $isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
1386
+        $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
1387
+        if ($targetUser->getUID() === $loggedInUser->getUID() || $isAdmin || $isDelegatedAdmin) {
1388
+            // Self lookup or admin lookup
1389
+            return new DataResponse([
1390
+                'groups' => $this->groupManager->getUserGroupIds($targetUser)
1391
+            ]);
1392
+        } else {
1393
+            $subAdminManager = $this->groupManager->getSubAdmin();
1394
+
1395
+            // Looking up someone else
1396
+            if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
1397
+                // Return the group that the method caller is subadmin of for the user in question
1398
+                $groups = array_values(array_intersect(
1399
+                    array_map(static fn (IGroup $group) => $group->getGID(), $subAdminManager->getSubAdminsGroups($loggedInUser)),
1400
+                    $this->groupManager->getUserGroupIds($targetUser)
1401
+                ));
1402
+                return new DataResponse(['groups' => $groups]);
1403
+            } else {
1404
+                // Not permitted
1405
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1406
+            }
1407
+        }
1408
+    }
1409
+
1410
+    /**
1411
+     * @NoSubAdminRequired
1412
+     *
1413
+     * Get a list of groups with details
1414
+     *
1415
+     * @param string $userId ID of the user
1416
+     * @return DataResponse<Http::STATUS_OK, array{groups: list<Provisioning_APIGroupDetails>}, array{}>
1417
+     * @throws OCSException
1418
+     *
1419
+     * 200: Users groups returned
1420
+     */
1421
+    #[NoAdminRequired]
1422
+    public function getUsersGroupsDetails(string $userId): DataResponse {
1423
+        $loggedInUser = $this->userSession->getUser();
1424
+
1425
+        $targetUser = $this->userManager->get($userId);
1426
+        if ($targetUser === null) {
1427
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1428
+        }
1429
+
1430
+        $isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
1431
+        $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
1432
+        if ($targetUser->getUID() === $loggedInUser->getUID() || $isAdmin || $isDelegatedAdmin) {
1433
+            // Self lookup or admin lookup
1434
+            $groups = array_map(
1435
+                function (Group $group) {
1436
+                    return [
1437
+                        'id' => $group->getGID(),
1438
+                        'displayname' => $group->getDisplayName(),
1439
+                        'usercount' => $group->count(),
1440
+                        'disabled' => $group->countDisabled(),
1441
+                        'canAdd' => $group->canAddUser(),
1442
+                        'canRemove' => $group->canRemoveUser(),
1443
+                    ];
1444
+                },
1445
+                array_values($this->groupManager->getUserGroups($targetUser)),
1446
+            );
1447
+            return new DataResponse([
1448
+                'groups' => $groups,
1449
+            ]);
1450
+        } else {
1451
+            $subAdminManager = $this->groupManager->getSubAdmin();
1452
+
1453
+            // Looking up someone else
1454
+            if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
1455
+                // Return the group that the method caller is subadmin of for the user in question
1456
+                $gids = array_values(array_intersect(
1457
+                    array_map(
1458
+                        static fn (IGroup $group) => $group->getGID(),
1459
+                        $subAdminManager->getSubAdminsGroups($loggedInUser),
1460
+                    ),
1461
+                    $this->groupManager->getUserGroupIds($targetUser)
1462
+                ));
1463
+                $groups = array_map(
1464
+                    function (string $gid) {
1465
+                        $group = $this->groupManager->get($gid);
1466
+                        return [
1467
+                            'id' => $group->getGID(),
1468
+                            'displayname' => $group->getDisplayName(),
1469
+                            'usercount' => $group->count(),
1470
+                            'disabled' => $group->countDisabled(),
1471
+                            'canAdd' => $group->canAddUser(),
1472
+                            'canRemove' => $group->canRemoveUser(),
1473
+                        ];
1474
+                    },
1475
+                    $gids,
1476
+                );
1477
+                return new DataResponse([
1478
+                    'groups' => $groups,
1479
+                ]);
1480
+            } else {
1481
+                // Not permitted
1482
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1483
+            }
1484
+        }
1485
+    }
1486
+
1487
+    /**
1488
+     * @NoSubAdminRequired
1489
+     *
1490
+     * Get a list of the groups the user is a subadmin of, with details
1491
+     *
1492
+     * @param string $userId ID of the user
1493
+     * @return DataResponse<Http::STATUS_OK, array{groups: list<Provisioning_APIGroupDetails>}, array{}>
1494
+     * @throws OCSException
1495
+     *
1496
+     * 200: Users subadmin groups returned
1497
+     */
1498
+    #[NoAdminRequired]
1499
+    public function getUserSubAdminGroupsDetails(string $userId): DataResponse {
1500
+        $loggedInUser = $this->userSession->getUser();
1501
+
1502
+        $targetUser = $this->userManager->get($userId);
1503
+        if ($targetUser === null) {
1504
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1505
+        }
1506
+
1507
+        $isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
1508
+        $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
1509
+        if ($targetUser->getUID() === $loggedInUser->getUID() || $isAdmin || $isDelegatedAdmin) {
1510
+            $subAdminManager = $this->groupManager->getSubAdmin();
1511
+            $groups = array_map(
1512
+                function (IGroup $group) {
1513
+                    return [
1514
+                        'id' => $group->getGID(),
1515
+                        'displayname' => $group->getDisplayName(),
1516
+                        'usercount' => $group->count(),
1517
+                        'disabled' => $group->countDisabled(),
1518
+                        'canAdd' => $group->canAddUser(),
1519
+                        'canRemove' => $group->canRemoveUser(),
1520
+                    ];
1521
+                },
1522
+                array_values($subAdminManager->getSubAdminsGroups($targetUser)),
1523
+            );
1524
+            return new DataResponse([
1525
+                'groups' => $groups,
1526
+            ]);
1527
+        }
1528
+        throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1529
+    }
1530
+
1531
+    /**
1532
+     * Add a user to a group
1533
+     *
1534
+     * @param string $userId ID of the user
1535
+     * @param string $groupid ID of the group
1536
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1537
+     * @throws OCSException
1538
+     *
1539
+     * 200: User added to group successfully
1540
+     */
1541
+    #[PasswordConfirmationRequired]
1542
+    #[NoAdminRequired]
1543
+    public function addToGroup(string $userId, string $groupid = ''): DataResponse {
1544
+        if ($groupid === '') {
1545
+            throw new OCSException('', 101);
1546
+        }
1547
+
1548
+        $group = $this->groupManager->get($groupid);
1549
+        $targetUser = $this->userManager->get($userId);
1550
+        if ($group === null) {
1551
+            throw new OCSException('', 102);
1552
+        }
1553
+        if ($targetUser === null) {
1554
+            throw new OCSException('', 103);
1555
+        }
1556
+
1557
+        // If they're not an admin, check they are a subadmin of the group in question
1558
+        $loggedInUser = $this->userSession->getUser();
1559
+        $subAdminManager = $this->groupManager->getSubAdmin();
1560
+        $isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
1561
+        $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
1562
+        if (!$isAdmin && !($isDelegatedAdmin && $groupid !== 'admin') && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
1563
+            throw new OCSException('', 104);
1564
+        }
1565
+
1566
+        // Add user to group
1567
+        $group->addUser($targetUser);
1568
+        return new DataResponse();
1569
+    }
1570
+
1571
+    /**
1572
+     * Remove a user from a group
1573
+     *
1574
+     * @param string $userId ID of the user
1575
+     * @param string $groupid ID of the group
1576
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1577
+     * @throws OCSException
1578
+     *
1579
+     * 200: User removed from group successfully
1580
+     */
1581
+    #[PasswordConfirmationRequired]
1582
+    #[NoAdminRequired]
1583
+    public function removeFromGroup(string $userId, string $groupid): DataResponse {
1584
+        $loggedInUser = $this->userSession->getUser();
1585
+
1586
+        if ($groupid === null || trim($groupid) === '') {
1587
+            throw new OCSException('', 101);
1588
+        }
1589
+
1590
+        $group = $this->groupManager->get($groupid);
1591
+        if ($group === null) {
1592
+            throw new OCSException('', 102);
1593
+        }
1594
+
1595
+        $targetUser = $this->userManager->get($userId);
1596
+        if ($targetUser === null) {
1597
+            throw new OCSException('', 103);
1598
+        }
1599
+
1600
+        // If they're not an admin, check they are a subadmin of the group in question
1601
+        $subAdminManager = $this->groupManager->getSubAdmin();
1602
+        $isAdmin = $this->groupManager->isAdmin($loggedInUser->getUID());
1603
+        $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($loggedInUser->getUID());
1604
+        if (!$isAdmin && !($isDelegatedAdmin && $groupid !== 'admin') && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
1605
+            throw new OCSException('', 104);
1606
+        }
1607
+
1608
+        // Check they aren't removing themselves from 'admin' or their 'subadmin; group
1609
+        if ($targetUser->getUID() === $loggedInUser->getUID()) {
1610
+            if ($isAdmin || $isDelegatedAdmin) {
1611
+                if ($group->getGID() === 'admin') {
1612
+                    throw new OCSException($this->l10n->t('Cannot remove yourself from the admin group'), 105);
1613
+                }
1614
+            } else {
1615
+                // Not an admin, so the user must be a subadmin of this group, but that is not allowed.
1616
+                throw new OCSException($this->l10n->t('Cannot remove yourself from this group as you are a sub-admin'), 105);
1617
+            }
1618
+        } elseif (!($isAdmin || $isDelegatedAdmin)) {
1619
+            /** @var IGroup[] $subAdminGroups */
1620
+            $subAdminGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
1621
+            $subAdminGroups = array_map(function (IGroup $subAdminGroup) {
1622
+                return $subAdminGroup->getGID();
1623
+            }, $subAdminGroups);
1624
+            $userGroups = $this->groupManager->getUserGroupIds($targetUser);
1625
+            $userSubAdminGroups = array_intersect($subAdminGroups, $userGroups);
1626
+
1627
+            if (count($userSubAdminGroups) <= 1) {
1628
+                // Subadmin must not be able to remove a user from all their subadmin groups.
1629
+                throw new OCSException($this->l10n->t('Not viable to remove user from the last group you are sub-admin of'), 105);
1630
+            }
1631
+        }
1632
+
1633
+        // Remove user from group
1634
+        $group->removeUser($targetUser);
1635
+        return new DataResponse();
1636
+    }
1637
+
1638
+    /**
1639
+     * Make a user a subadmin of a group
1640
+     *
1641
+     * @param string $userId ID of the user
1642
+     * @param string $groupid ID of the group
1643
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1644
+     * @throws OCSException
1645
+     *
1646
+     * 200: User added as group subadmin successfully
1647
+     */
1648
+    #[AuthorizedAdminSetting(settings:Users::class)]
1649
+    #[PasswordConfirmationRequired]
1650
+    public function addSubAdmin(string $userId, string $groupid): DataResponse {
1651
+        $group = $this->groupManager->get($groupid);
1652
+        $user = $this->userManager->get($userId);
1653
+
1654
+        // Check if the user exists
1655
+        if ($user === null) {
1656
+            throw new OCSException($this->l10n->t('User does not exist'), 101);
1657
+        }
1658
+        // Check if group exists
1659
+        if ($group === null) {
1660
+            throw new OCSException($this->l10n->t('Group does not exist'), 102);
1661
+        }
1662
+        // Check if trying to make subadmin of admin group
1663
+        if ($group->getGID() === 'admin') {
1664
+            throw new OCSException($this->l10n->t('Cannot create sub-admins for admin group'), 103);
1665
+        }
1666
+
1667
+        $subAdminManager = $this->groupManager->getSubAdmin();
1668
+
1669
+        // We cannot be subadmin twice
1670
+        if ($subAdminManager->isSubAdminOfGroup($user, $group)) {
1671
+            return new DataResponse();
1672
+        }
1673
+        // Go
1674
+        $subAdminManager->createSubAdmin($user, $group);
1675
+        return new DataResponse();
1676
+    }
1677
+
1678
+    /**
1679
+     * Remove a user from the subadmins of a group
1680
+     *
1681
+     * @param string $userId ID of the user
1682
+     * @param string $groupid ID of the group
1683
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1684
+     * @throws OCSException
1685
+     *
1686
+     * 200: User removed as group subadmin successfully
1687
+     */
1688
+    #[AuthorizedAdminSetting(settings:Users::class)]
1689
+    #[PasswordConfirmationRequired]
1690
+    public function removeSubAdmin(string $userId, string $groupid): DataResponse {
1691
+        $group = $this->groupManager->get($groupid);
1692
+        $user = $this->userManager->get($userId);
1693
+        $subAdminManager = $this->groupManager->getSubAdmin();
1694
+
1695
+        // Check if the user exists
1696
+        if ($user === null) {
1697
+            throw new OCSException($this->l10n->t('User does not exist'), 101);
1698
+        }
1699
+        // Check if the group exists
1700
+        if ($group === null) {
1701
+            throw new OCSException($this->l10n->t('Group does not exist'), 101);
1702
+        }
1703
+        // Check if they are a subadmin of this said group
1704
+        if (!$subAdminManager->isSubAdminOfGroup($user, $group)) {
1705
+            throw new OCSException($this->l10n->t('User is not a sub-admin of this group'), 102);
1706
+        }
1707
+
1708
+        // Go
1709
+        $subAdminManager->deleteSubAdmin($user, $group);
1710
+        return new DataResponse();
1711
+    }
1712
+
1713
+    /**
1714
+     * Get the groups a user is a subadmin of
1715
+     *
1716
+     * @param string $userId ID if the user
1717
+     * @return DataResponse<Http::STATUS_OK, list<string>, array{}>
1718
+     * @throws OCSException
1719
+     *
1720
+     * 200: User subadmin groups returned
1721
+     */
1722
+    #[AuthorizedAdminSetting(settings:Users::class)]
1723
+    public function getUserSubAdminGroups(string $userId): DataResponse {
1724
+        $groups = $this->getUserSubAdminGroupsData($userId);
1725
+        return new DataResponse($groups);
1726
+    }
1727
+
1728
+    /**
1729
+     * Resend the welcome message
1730
+     *
1731
+     * @param string $userId ID if the user
1732
+     * @return DataResponse<Http::STATUS_OK, list<empty>, array{}>
1733
+     * @throws OCSException
1734
+     *
1735
+     * 200: Resent welcome message successfully
1736
+     */
1737
+    #[PasswordConfirmationRequired]
1738
+    #[NoAdminRequired]
1739
+    public function resendWelcomeMessage(string $userId): DataResponse {
1740
+        $currentLoggedInUser = $this->userSession->getUser();
1741
+
1742
+        $targetUser = $this->userManager->get($userId);
1743
+        if ($targetUser === null) {
1744
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1745
+        }
1746
+
1747
+        // Check if admin / subadmin
1748
+        $subAdminManager = $this->groupManager->getSubAdmin();
1749
+        $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
1750
+        $isDelegatedAdmin = $this->groupManager->isDelegatedAdmin($currentLoggedInUser->getUID());
1751
+        if (
1752
+            !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
1753
+            && !($isAdmin || $isDelegatedAdmin)
1754
+        ) {
1755
+            // No rights
1756
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1757
+        }
1758
+
1759
+        $email = $targetUser->getEMailAddress();
1760
+        if ($email === '' || $email === null) {
1761
+            throw new OCSException($this->l10n->t('Email address not available'), 101);
1762
+        }
1763
+
1764
+        try {
1765
+            if ($this->config->getUserValue($targetUser->getUID(), 'core', 'lostpassword')) {
1766
+                $emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, true);
1767
+            } else {
1768
+                $emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, false);
1769
+            }
1770
+
1771
+            $this->newUserMailHelper->sendMail($targetUser, $emailTemplate);
1772
+        } catch (\Exception $e) {
1773
+            $this->logger->error(
1774
+                "Can't send new user mail to $email",
1775
+                [
1776
+                    'app' => 'settings',
1777
+                    'exception' => $e,
1778
+                ]
1779
+            );
1780
+            throw new OCSException($this->l10n->t('Sending email failed'), 102);
1781
+        }
1782
+
1783
+        return new DataResponse();
1784
+    }
1785 1785
 }
Please login to merge, or discard this patch.
lib/private/User/LazyUser.php 1 patch
Indentation   +149 added lines, -149 removed lines patch added patch discarded remove patch
@@ -13,162 +13,162 @@
 block discarded – undo
13 13
 use OCP\UserInterface;
14 14
 
15 15
 class LazyUser implements IUser {
16
-	private ?IUser $user = null;
17
-	private string $uid;
18
-	private ?string $displayName;
19
-	private IUserManager $userManager;
20
-	private ?UserInterface $backend;
21
-
22
-	public function __construct(string $uid, IUserManager $userManager, ?string $displayName = null, ?UserInterface $backend = null) {
23
-		$this->uid = $uid;
24
-		$this->userManager = $userManager;
25
-		$this->displayName = $displayName;
26
-		$this->backend = $backend;
27
-	}
28
-
29
-	private function getUser(): IUser {
30
-		if ($this->user === null) {
31
-			if ($this->backend) {
32
-				/** @var \OC\User\Manager $manager */
33
-				$manager = $this->userManager;
34
-				$this->user = $manager->getUserObject($this->uid, $this->backend);
35
-			} else {
36
-				$this->user = $this->userManager->get($this->uid);
37
-			}
38
-		}
39
-
40
-		if ($this->user === null) {
41
-			throw new NoUserException('User not found in backend');
42
-		}
43
-
44
-		return $this->user;
45
-	}
46
-
47
-	public function getUID() {
48
-		return $this->uid;
49
-	}
50
-
51
-	public function getDisplayName() {
52
-		if ($this->displayName) {
53
-			return $this->displayName;
54
-		}
55
-
56
-		return $this->userManager->getDisplayName($this->uid) ?? $this->uid;
57
-	}
58
-
59
-	public function setDisplayName($displayName) {
60
-		return $this->getUser()->setDisplayName($displayName);
61
-	}
62
-
63
-	public function getLastLogin(): int {
64
-		return $this->getUser()->getLastLogin();
65
-	}
66
-
67
-	public function getFirstLogin(): int {
68
-		return $this->getUser()->getFirstLogin();
69
-	}
70
-
71
-	public function updateLastLoginTimestamp(): bool {
72
-		return $this->getUser()->updateLastLoginTimestamp();
73
-	}
74
-
75
-	public function delete() {
76
-		return $this->getUser()->delete();
77
-	}
78
-
79
-	public function setPassword($password, $recoveryPassword = null) {
80
-		return $this->getUser()->setPassword($password, $recoveryPassword);
81
-	}
82
-
83
-	public function getPasswordHash(): ?string {
84
-		return $this->getUser()->getPasswordHash();
85
-	}
86
-
87
-	public function setPasswordHash(string $passwordHash): bool {
88
-		return $this->getUser()->setPasswordHash($passwordHash);
89
-	}
90
-
91
-	public function getHome() {
92
-		return $this->getUser()->getHome();
93
-	}
94
-
95
-	public function getBackendClassName() {
96
-		return $this->getUser()->getBackendClassName();
97
-	}
98
-
99
-	public function getBackend(): ?UserInterface {
100
-		return $this->getUser()->getBackend();
101
-	}
102
-
103
-	public function canChangeAvatar() {
104
-		return $this->getUser()->canChangeAvatar();
105
-	}
106
-
107
-	public function canChangePassword() {
108
-		return $this->getUser()->canChangePassword();
109
-	}
110
-
111
-	public function canChangeDisplayName() {
112
-		return $this->getUser()->canChangeDisplayName();
113
-	}
114
-
115
-	public function canChangeEmail(): bool {
116
-		return $this->getUser()->canChangeEmail();
117
-	}
118
-
119
-	public function isEnabled() {
120
-		return $this->getUser()->isEnabled();
121
-	}
122
-
123
-	public function setEnabled(bool $enabled = true) {
124
-		return $this->getUser()->setEnabled($enabled);
125
-	}
126
-
127
-	public function getEMailAddress() {
128
-		return $this->getUser()->getEMailAddress();
129
-	}
130
-
131
-	public function getSystemEMailAddress(): ?string {
132
-		return $this->getUser()->getSystemEMailAddress();
133
-	}
134
-
135
-	public function getPrimaryEMailAddress(): ?string {
136
-		return $this->getUser()->getPrimaryEMailAddress();
137
-	}
16
+    private ?IUser $user = null;
17
+    private string $uid;
18
+    private ?string $displayName;
19
+    private IUserManager $userManager;
20
+    private ?UserInterface $backend;
21
+
22
+    public function __construct(string $uid, IUserManager $userManager, ?string $displayName = null, ?UserInterface $backend = null) {
23
+        $this->uid = $uid;
24
+        $this->userManager = $userManager;
25
+        $this->displayName = $displayName;
26
+        $this->backend = $backend;
27
+    }
28
+
29
+    private function getUser(): IUser {
30
+        if ($this->user === null) {
31
+            if ($this->backend) {
32
+                /** @var \OC\User\Manager $manager */
33
+                $manager = $this->userManager;
34
+                $this->user = $manager->getUserObject($this->uid, $this->backend);
35
+            } else {
36
+                $this->user = $this->userManager->get($this->uid);
37
+            }
38
+        }
39
+
40
+        if ($this->user === null) {
41
+            throw new NoUserException('User not found in backend');
42
+        }
43
+
44
+        return $this->user;
45
+    }
46
+
47
+    public function getUID() {
48
+        return $this->uid;
49
+    }
50
+
51
+    public function getDisplayName() {
52
+        if ($this->displayName) {
53
+            return $this->displayName;
54
+        }
55
+
56
+        return $this->userManager->getDisplayName($this->uid) ?? $this->uid;
57
+    }
58
+
59
+    public function setDisplayName($displayName) {
60
+        return $this->getUser()->setDisplayName($displayName);
61
+    }
62
+
63
+    public function getLastLogin(): int {
64
+        return $this->getUser()->getLastLogin();
65
+    }
66
+
67
+    public function getFirstLogin(): int {
68
+        return $this->getUser()->getFirstLogin();
69
+    }
70
+
71
+    public function updateLastLoginTimestamp(): bool {
72
+        return $this->getUser()->updateLastLoginTimestamp();
73
+    }
74
+
75
+    public function delete() {
76
+        return $this->getUser()->delete();
77
+    }
78
+
79
+    public function setPassword($password, $recoveryPassword = null) {
80
+        return $this->getUser()->setPassword($password, $recoveryPassword);
81
+    }
82
+
83
+    public function getPasswordHash(): ?string {
84
+        return $this->getUser()->getPasswordHash();
85
+    }
86
+
87
+    public function setPasswordHash(string $passwordHash): bool {
88
+        return $this->getUser()->setPasswordHash($passwordHash);
89
+    }
90
+
91
+    public function getHome() {
92
+        return $this->getUser()->getHome();
93
+    }
94
+
95
+    public function getBackendClassName() {
96
+        return $this->getUser()->getBackendClassName();
97
+    }
98
+
99
+    public function getBackend(): ?UserInterface {
100
+        return $this->getUser()->getBackend();
101
+    }
102
+
103
+    public function canChangeAvatar() {
104
+        return $this->getUser()->canChangeAvatar();
105
+    }
106
+
107
+    public function canChangePassword() {
108
+        return $this->getUser()->canChangePassword();
109
+    }
110
+
111
+    public function canChangeDisplayName() {
112
+        return $this->getUser()->canChangeDisplayName();
113
+    }
114
+
115
+    public function canChangeEmail(): bool {
116
+        return $this->getUser()->canChangeEmail();
117
+    }
118
+
119
+    public function isEnabled() {
120
+        return $this->getUser()->isEnabled();
121
+    }
122
+
123
+    public function setEnabled(bool $enabled = true) {
124
+        return $this->getUser()->setEnabled($enabled);
125
+    }
126
+
127
+    public function getEMailAddress() {
128
+        return $this->getUser()->getEMailAddress();
129
+    }
130
+
131
+    public function getSystemEMailAddress(): ?string {
132
+        return $this->getUser()->getSystemEMailAddress();
133
+    }
134
+
135
+    public function getPrimaryEMailAddress(): ?string {
136
+        return $this->getUser()->getPrimaryEMailAddress();
137
+    }
138 138
 
139
-	public function getAvatarImage($size) {
140
-		return $this->getUser()->getAvatarImage($size);
141
-	}
139
+    public function getAvatarImage($size) {
140
+        return $this->getUser()->getAvatarImage($size);
141
+    }
142 142
 
143
-	public function getCloudId() {
144
-		return $this->getUser()->getCloudId();
145
-	}
143
+    public function getCloudId() {
144
+        return $this->getUser()->getCloudId();
145
+    }
146 146
 
147
-	public function setEMailAddress($mailAddress) {
148
-		$this->getUser()->setEMailAddress($mailAddress);
149
-	}
147
+    public function setEMailAddress($mailAddress) {
148
+        $this->getUser()->setEMailAddress($mailAddress);
149
+    }
150 150
 
151
-	public function setSystemEMailAddress(string $mailAddress): void {
152
-		$this->getUser()->setSystemEMailAddress($mailAddress);
153
-	}
151
+    public function setSystemEMailAddress(string $mailAddress): void {
152
+        $this->getUser()->setSystemEMailAddress($mailAddress);
153
+    }
154 154
 
155
-	public function setPrimaryEMailAddress(string $mailAddress): void {
156
-		$this->getUser()->setPrimaryEMailAddress($mailAddress);
157
-	}
155
+    public function setPrimaryEMailAddress(string $mailAddress): void {
156
+        $this->getUser()->setPrimaryEMailAddress($mailAddress);
157
+    }
158 158
 
159
-	public function getQuota() {
160
-		return $this->getUser()->getQuota();
161
-	}
159
+    public function getQuota() {
160
+        return $this->getUser()->getQuota();
161
+    }
162 162
 
163
-	public function setQuota($quota) {
164
-		$this->getUser()->setQuota($quota);
165
-	}
163
+    public function setQuota($quota) {
164
+        $this->getUser()->setQuota($quota);
165
+    }
166 166
 
167
-	public function getManagerUids(): array {
168
-		return $this->getUser()->getManagerUids();
169
-	}
167
+    public function getManagerUids(): array {
168
+        return $this->getUser()->getManagerUids();
169
+    }
170 170
 
171
-	public function setManagerUids(array $uids): void {
172
-		$this->getUser()->setManagerUids($uids);
173
-	}
171
+    public function setManagerUids(array $uids): void {
172
+        $this->getUser()->setManagerUids($uids);
173
+    }
174 174
 }
Please login to merge, or discard this patch.
lib/private/User/User.php 1 patch
Indentation   +610 added lines, -610 removed lines patch added patch discarded remove patch
@@ -45,614 +45,614 @@
 block discarded – undo
45 45
 use function json_encode;
46 46
 
47 47
 class User implements IUser {
48
-	private const CONFIG_KEY_MANAGERS = 'manager';
49
-
50
-	private IConfig $config;
51
-	private IURLGenerator $urlGenerator;
52
-
53
-	/** @var IAccountManager */
54
-	protected $accountManager;
55
-
56
-	/** @var string|null */
57
-	private $displayName;
58
-
59
-	/** @var bool|null */
60
-	private $enabled;
61
-
62
-	/** @var Emitter|Manager|null */
63
-	private $emitter;
64
-
65
-	/** @var string */
66
-	private $home;
67
-
68
-	private ?int $lastLogin = null;
69
-	private ?int $firstLogin = null;
70
-
71
-	/** @var IAvatarManager */
72
-	private $avatarManager;
73
-
74
-	public function __construct(
75
-		private string $uid,
76
-		private ?UserInterface $backend,
77
-		private IEventDispatcher $dispatcher,
78
-		$emitter = null,
79
-		?IConfig $config = null,
80
-		$urlGenerator = null,
81
-	) {
82
-		$this->emitter = $emitter;
83
-		$this->config = $config ?? \OCP\Server::get(IConfig::class);
84
-		$this->urlGenerator = $urlGenerator ?? \OCP\Server::get(IURLGenerator::class);
85
-	}
86
-
87
-	/**
88
-	 * get the user id
89
-	 *
90
-	 * @return string
91
-	 */
92
-	public function getUID() {
93
-		return $this->uid;
94
-	}
95
-
96
-	/**
97
-	 * get the display name for the user, if no specific display name is set it will fallback to the user id
98
-	 *
99
-	 * @return string
100
-	 */
101
-	public function getDisplayName() {
102
-		if ($this->displayName === null) {
103
-			$displayName = '';
104
-			if ($this->backend && $this->backend->implementsActions(Backend::GET_DISPLAYNAME)) {
105
-				// get display name and strip whitespace from the beginning and end of it
106
-				$backendDisplayName = $this->backend->getDisplayName($this->uid);
107
-				if (is_string($backendDisplayName)) {
108
-					$displayName = trim($backendDisplayName);
109
-				}
110
-			}
111
-
112
-			if (!empty($displayName)) {
113
-				$this->displayName = $displayName;
114
-			} else {
115
-				$this->displayName = $this->uid;
116
-			}
117
-		}
118
-		return $this->displayName;
119
-	}
120
-
121
-	/**
122
-	 * set the displayname for the user
123
-	 *
124
-	 * @param string $displayName
125
-	 * @return bool
126
-	 *
127
-	 * @since 25.0.0 Throw InvalidArgumentException
128
-	 * @throws \InvalidArgumentException
129
-	 */
130
-	public function setDisplayName($displayName) {
131
-		$displayName = trim($displayName);
132
-		$oldDisplayName = $this->getDisplayName();
133
-		if ($this->backend->implementsActions(Backend::SET_DISPLAYNAME) && !empty($displayName) && $displayName !== $oldDisplayName) {
134
-			/** @var ISetDisplayNameBackend $backend */
135
-			$backend = $this->backend;
136
-			$result = $backend->setDisplayName($this->uid, $displayName);
137
-			if ($result) {
138
-				$this->displayName = $displayName;
139
-				$this->triggerChange('displayName', $displayName, $oldDisplayName);
140
-			}
141
-			return $result !== false;
142
-		}
143
-		return false;
144
-	}
145
-
146
-	/**
147
-	 * @inheritDoc
148
-	 */
149
-	public function setEMailAddress($mailAddress) {
150
-		$this->setSystemEMailAddress($mailAddress);
151
-	}
152
-
153
-	/**
154
-	 * @inheritDoc
155
-	 */
156
-	public function setSystemEMailAddress(string $mailAddress): void {
157
-		$oldMailAddress = $this->getSystemEMailAddress();
158
-
159
-		if ($mailAddress === '') {
160
-			$this->config->deleteUserValue($this->uid, 'settings', 'email');
161
-		} else {
162
-			$this->config->setUserValue($this->uid, 'settings', 'email', $mailAddress);
163
-		}
164
-
165
-		$primaryAddress = $this->getPrimaryEMailAddress();
166
-		if ($primaryAddress === $mailAddress) {
167
-			// on match no dedicated primary settings is necessary
168
-			$this->setPrimaryEMailAddress('');
169
-		}
170
-
171
-		if ($oldMailAddress !== strtolower($mailAddress)) {
172
-			$this->triggerChange('eMailAddress', $mailAddress, $oldMailAddress);
173
-		}
174
-	}
175
-
176
-	/**
177
-	 * @inheritDoc
178
-	 */
179
-	public function setPrimaryEMailAddress(string $mailAddress): void {
180
-		if ($mailAddress === '') {
181
-			$this->config->deleteUserValue($this->uid, 'settings', 'primary_email');
182
-			return;
183
-		}
184
-
185
-		$this->ensureAccountManager();
186
-		$account = $this->accountManager->getAccount($this);
187
-		$property = $account->getPropertyCollection(IAccountManager::COLLECTION_EMAIL)
188
-			->getPropertyByValue($mailAddress);
189
-
190
-		if ($property === null || $property->getLocallyVerified() !== IAccountManager::VERIFIED) {
191
-			throw new InvalidArgumentException('Only verified emails can be set as primary');
192
-		}
193
-		$this->config->setUserValue($this->uid, 'settings', 'primary_email', $mailAddress);
194
-	}
195
-
196
-	private function ensureAccountManager() {
197
-		if (!$this->accountManager instanceof IAccountManager) {
198
-			$this->accountManager = \OC::$server->get(IAccountManager::class);
199
-		}
200
-	}
201
-
202
-	/**
203
-	 * returns the timestamp of the user's last login or 0 if the user did never
204
-	 * login
205
-	 */
206
-	public function getLastLogin(): int {
207
-		if ($this->lastLogin === null) {
208
-			$this->lastLogin = (int)$this->config->getUserValue($this->uid, 'login', 'lastLogin', 0);
209
-		}
210
-		return $this->lastLogin;
211
-	}
212
-
213
-	/**
214
-	 * returns the timestamp of the user's last login or 0 if the user did never
215
-	 * login
216
-	 */
217
-	public function getFirstLogin(): int {
218
-		if ($this->firstLogin === null) {
219
-			$this->firstLogin = (int)$this->config->getUserValue($this->uid, 'login', 'firstLogin', 0);
220
-		}
221
-		return $this->firstLogin;
222
-	}
223
-
224
-	/**
225
-	 * updates the timestamp of the most recent login of this user
226
-	 */
227
-	public function updateLastLoginTimestamp(): bool {
228
-		$previousLogin = $this->getLastLogin();
229
-		$firstLogin = $this->getFirstLogin();
230
-		$now = time();
231
-		$firstTimeLogin = $previousLogin === 0;
232
-
233
-		if ($now - $previousLogin > 60) {
234
-			$this->lastLogin = $now;
235
-			$this->config->setUserValue($this->uid, 'login', 'lastLogin', (string)$this->lastLogin);
236
-		}
237
-
238
-		if ($firstLogin === 0) {
239
-			if ($firstTimeLogin) {
240
-				$this->firstLogin = $now;
241
-			} else {
242
-				/* Unknown first login, most likely was before upgrade to Nextcloud 31 */
243
-				$this->firstLogin = -1;
244
-			}
245
-			$this->config->setUserValue($this->uid, 'login', 'firstLogin', (string)$this->firstLogin);
246
-		}
247
-
248
-		return $firstTimeLogin;
249
-	}
250
-
251
-	/**
252
-	 * Delete the user
253
-	 *
254
-	 * @return bool
255
-	 */
256
-	public function delete() {
257
-		if ($this->backend === null) {
258
-			\OCP\Server::get(LoggerInterface::class)->error('Cannot delete user: No backend set');
259
-			return false;
260
-		}
261
-
262
-		if ($this->emitter) {
263
-			/** @deprecated 21.0.0 use BeforeUserDeletedEvent event with the IEventDispatcher instead */
264
-			$this->emitter->emit('\OC\User', 'preDelete', [$this]);
265
-		}
266
-		$this->dispatcher->dispatchTyped(new BeforeUserDeletedEvent($this));
267
-
268
-		// Set delete flag on the user - this is needed to ensure that the user data is removed if there happen any exception in the backend
269
-		// because we can not restore the user meaning we could not rollback to any stable state otherwise.
270
-		$this->config->setUserValue($this->uid, 'core', 'deleted', 'true');
271
-		// We also need to backup the home path as this can not be reconstructed later if the original backend uses custom home paths
272
-		$this->config->setUserValue($this->uid, 'core', 'deleted.home-path', $this->getHome());
273
-
274
-		// Try to delete the user on the backend
275
-		$result = $this->backend->deleteUser($this->uid);
276
-		if ($result === false) {
277
-			// The deletion was aborted or something else happened, we are in a defined state, so remove the delete flag
278
-			$this->config->deleteUserValue($this->uid, 'core', 'deleted');
279
-			return false;
280
-		}
281
-
282
-		// We have to delete the user from all groups
283
-		$groupManager = \OCP\Server::get(IGroupManager::class);
284
-		foreach ($groupManager->getUserGroupIds($this) as $groupId) {
285
-			$group = $groupManager->get($groupId);
286
-			if ($group) {
287
-				$this->dispatcher->dispatchTyped(new BeforeUserRemovedEvent($group, $this));
288
-				$group->removeUser($this);
289
-				$this->dispatcher->dispatchTyped(new UserRemovedEvent($group, $this));
290
-			}
291
-		}
292
-
293
-		$commentsManager = \OCP\Server::get(ICommentsManager::class);
294
-		$commentsManager->deleteReferencesOfActor('users', $this->uid);
295
-		$commentsManager->deleteReadMarksFromUser($this);
296
-
297
-		$avatarManager = \OCP\Server::get(AvatarManager::class);
298
-		$avatarManager->deleteUserAvatar($this->uid);
299
-
300
-		$notificationManager = \OCP\Server::get(INotificationManager::class);
301
-		$notification = $notificationManager->createNotification();
302
-		$notification->setUser($this->uid);
303
-		$notificationManager->markProcessed($notification);
304
-
305
-		$accountManager = \OCP\Server::get(AccountManager::class);
306
-		$accountManager->deleteUser($this);
307
-
308
-		$database = \OCP\Server::get(IDBConnection::class);
309
-		try {
310
-			// We need to create a transaction to make sure we are in a defined state
311
-			// because if all user values are removed also the flag is gone, but if an exception happens (e.g. database lost connection on the set operation)
312
-			// exactly here we are in an undefined state as the data is still present but the user does not exist on the system anymore.
313
-			$database->beginTransaction();
314
-			// Remove all user settings
315
-			$this->config->deleteAllUserValues($this->uid);
316
-			// But again set flag that this user is about to be deleted
317
-			$this->config->setUserValue($this->uid, 'core', 'deleted', 'true');
318
-			$this->config->setUserValue($this->uid, 'core', 'deleted.home-path', $this->getHome());
319
-			// Commit the transaction so we are in a defined state: either the preferences are removed or an exception occurred but the delete flag is still present
320
-			$database->commit();
321
-		} catch (\Throwable $e) {
322
-			$database->rollback();
323
-			throw $e;
324
-		}
325
-
326
-		if ($this->emitter !== null) {
327
-			/** @deprecated 21.0.0 use UserDeletedEvent event with the IEventDispatcher instead */
328
-			$this->emitter->emit('\OC\User', 'postDelete', [$this]);
329
-		}
330
-		$this->dispatcher->dispatchTyped(new UserDeletedEvent($this));
331
-
332
-		// Finally we can unset the delete flag and all other states
333
-		$this->config->deleteAllUserValues($this->uid);
334
-
335
-		return true;
336
-	}
337
-
338
-	/**
339
-	 * Set the password of the user
340
-	 *
341
-	 * @param string $password
342
-	 * @param string $recoveryPassword for the encryption app to reset encryption keys
343
-	 * @return bool
344
-	 */
345
-	public function setPassword($password, $recoveryPassword = null) {
346
-		$this->dispatcher->dispatchTyped(new BeforePasswordUpdatedEvent($this, $password, $recoveryPassword));
347
-		if ($this->emitter) {
348
-			$this->emitter->emit('\OC\User', 'preSetPassword', [$this, $password, $recoveryPassword]);
349
-		}
350
-		if ($this->backend->implementsActions(Backend::SET_PASSWORD)) {
351
-			/** @var ISetPasswordBackend $backend */
352
-			$backend = $this->backend;
353
-			$result = $backend->setPassword($this->uid, $password);
354
-
355
-			if ($result !== false) {
356
-				$this->dispatcher->dispatchTyped(new PasswordUpdatedEvent($this, $password, $recoveryPassword));
357
-				if ($this->emitter) {
358
-					$this->emitter->emit('\OC\User', 'postSetPassword', [$this, $password, $recoveryPassword]);
359
-				}
360
-			}
361
-
362
-			return !($result === false);
363
-		} else {
364
-			return false;
365
-		}
366
-	}
367
-
368
-	public function getPasswordHash(): ?string {
369
-		if (!($this->backend instanceof IPasswordHashBackend)) {
370
-			return null;
371
-		}
372
-		return $this->backend->getPasswordHash($this->uid);
373
-	}
374
-
375
-	public function setPasswordHash(string $passwordHash): bool {
376
-		if (!($this->backend instanceof IPasswordHashBackend)) {
377
-			return false;
378
-		}
379
-		return $this->backend->setPasswordHash($this->uid, $passwordHash);
380
-	}
381
-
382
-	/**
383
-	 * get the users home folder to mount
384
-	 *
385
-	 * @return string
386
-	 */
387
-	public function getHome() {
388
-		if (!$this->home) {
389
-			/** @psalm-suppress UndefinedInterfaceMethod Once we get rid of the legacy implementsActions, psalm won't complain anymore */
390
-			if (($this->backend instanceof IGetHomeBackend || $this->backend->implementsActions(Backend::GET_HOME)) && $home = $this->backend->getHome($this->uid)) {
391
-				$this->home = $home;
392
-			} else {
393
-				$this->home = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $this->uid;
394
-			}
395
-		}
396
-		return $this->home;
397
-	}
398
-
399
-	/**
400
-	 * Get the name of the backend class the user is connected with
401
-	 *
402
-	 * @return string
403
-	 */
404
-	public function getBackendClassName() {
405
-		if ($this->backend instanceof IUserBackend) {
406
-			return $this->backend->getBackendName();
407
-		}
408
-		return get_class($this->backend);
409
-	}
410
-
411
-	public function getBackend(): ?UserInterface {
412
-		return $this->backend;
413
-	}
414
-
415
-	/**
416
-	 * Check if the backend allows the user to change their avatar on Personal page
417
-	 *
418
-	 * @return bool
419
-	 */
420
-	public function canChangeAvatar() {
421
-		if ($this->backend instanceof IProvideAvatarBackend || $this->backend->implementsActions(Backend::PROVIDE_AVATAR)) {
422
-			/** @var IProvideAvatarBackend $backend */
423
-			$backend = $this->backend;
424
-			return $backend->canChangeAvatar($this->uid);
425
-		}
426
-		return true;
427
-	}
428
-
429
-	/**
430
-	 * check if the backend supports changing passwords
431
-	 *
432
-	 * @return bool
433
-	 */
434
-	public function canChangePassword() {
435
-		return $this->backend->implementsActions(Backend::SET_PASSWORD);
436
-	}
437
-
438
-	/**
439
-	 * check if the backend supports changing display names
440
-	 *
441
-	 * @return bool
442
-	 */
443
-	public function canChangeDisplayName() {
444
-		if (!$this->config->getSystemValueBool('allow_user_to_change_display_name', true)) {
445
-			return false;
446
-		}
447
-		return $this->backend->implementsActions(Backend::SET_DISPLAYNAME);
448
-	}
449
-
450
-	public function canChangeEmail(): bool {
451
-		return $this->config->getSystemValueBool('allow_user_to_change_email', true);
452
-	}
453
-
454
-	/**
455
-	 * check if the user is enabled
456
-	 *
457
-	 * @return bool
458
-	 */
459
-	public function isEnabled() {
460
-		$queryDatabaseValue = function (): bool {
461
-			if ($this->enabled === null) {
462
-				$enabled = $this->config->getUserValue($this->uid, 'core', 'enabled', 'true');
463
-				$this->enabled = $enabled === 'true';
464
-			}
465
-			return $this->enabled;
466
-		};
467
-		if ($this->backend instanceof IProvideEnabledStateBackend) {
468
-			return $this->backend->isUserEnabled($this->uid, $queryDatabaseValue);
469
-		} else {
470
-			return $queryDatabaseValue();
471
-		}
472
-	}
473
-
474
-	/**
475
-	 * set the enabled status for the user
476
-	 *
477
-	 * @return void
478
-	 */
479
-	public function setEnabled(bool $enabled = true) {
480
-		$oldStatus = $this->isEnabled();
481
-		$setDatabaseValue = function (bool $enabled): void {
482
-			$this->config->setUserValue($this->uid, 'core', 'enabled', $enabled ? 'true' : 'false');
483
-			$this->enabled = $enabled;
484
-		};
485
-		if ($this->backend instanceof IProvideEnabledStateBackend) {
486
-			$queryDatabaseValue = function (): bool {
487
-				if ($this->enabled === null) {
488
-					$enabled = $this->config->getUserValue($this->uid, 'core', 'enabled', 'true');
489
-					$this->enabled = $enabled === 'true';
490
-				}
491
-				return $this->enabled;
492
-			};
493
-			$enabled = $this->backend->setUserEnabled($this->uid, $enabled, $queryDatabaseValue, $setDatabaseValue);
494
-			if ($oldStatus !== $enabled) {
495
-				$this->triggerChange('enabled', $enabled, $oldStatus);
496
-			}
497
-		} elseif ($oldStatus !== $enabled) {
498
-			$setDatabaseValue($enabled);
499
-			$this->triggerChange('enabled', $enabled, $oldStatus);
500
-		}
501
-	}
502
-
503
-	/**
504
-	 * get the users email address
505
-	 *
506
-	 * @return string|null
507
-	 * @since 9.0.0
508
-	 */
509
-	public function getEMailAddress() {
510
-		return $this->getPrimaryEMailAddress() ?? $this->getSystemEMailAddress();
511
-	}
512
-
513
-	/**
514
-	 * @inheritDoc
515
-	 */
516
-	public function getSystemEMailAddress(): ?string {
517
-		return $this->config->getUserValue($this->uid, 'settings', 'email', null);
518
-	}
519
-
520
-	/**
521
-	 * @inheritDoc
522
-	 */
523
-	public function getPrimaryEMailAddress(): ?string {
524
-		return $this->config->getUserValue($this->uid, 'settings', 'primary_email', null);
525
-	}
526
-
527
-	/**
528
-	 * get the users' quota
529
-	 *
530
-	 * @return string
531
-	 * @since 9.0.0
532
-	 */
533
-	public function getQuota() {
534
-		// allow apps to modify the user quota by hooking into the event
535
-		$event = new GetQuotaEvent($this);
536
-		$this->dispatcher->dispatchTyped($event);
537
-		$overwriteQuota = $event->getQuota();
538
-		if ($overwriteQuota) {
539
-			$quota = $overwriteQuota;
540
-		} else {
541
-			$quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default');
542
-		}
543
-		if ($quota === 'default') {
544
-			$quota = $this->config->getAppValue('files', 'default_quota', 'none');
545
-
546
-			// if unlimited quota is not allowed => avoid getting 'unlimited' as default_quota fallback value
547
-			// use the first preset instead
548
-			$allowUnlimitedQuota = $this->config->getAppValue('files', 'allow_unlimited_quota', '1') === '1';
549
-			if (!$allowUnlimitedQuota) {
550
-				$presets = $this->config->getAppValue('files', 'quota_preset', '1 GB, 5 GB, 10 GB');
551
-				$presets = array_filter(array_map('trim', explode(',', $presets)));
552
-				$quotaPreset = array_values(array_diff($presets, ['default', 'none']));
553
-				if (count($quotaPreset) > 0) {
554
-					$quota = $this->config->getAppValue('files', 'default_quota', $quotaPreset[0]);
555
-				}
556
-			}
557
-		}
558
-		return $quota;
559
-	}
560
-
561
-	/**
562
-	 * set the users' quota
563
-	 *
564
-	 * @param string $quota
565
-	 * @return void
566
-	 * @throws InvalidArgumentException
567
-	 * @since 9.0.0
568
-	 */
569
-	public function setQuota($quota) {
570
-		$oldQuota = $this->config->getUserValue($this->uid, 'files', 'quota', '');
571
-		if ($quota !== 'none' and $quota !== 'default') {
572
-			$bytesQuota = OC_Helper::computerFileSize($quota);
573
-			if ($bytesQuota === false) {
574
-				throw new InvalidArgumentException('Failed to set quota to invalid value ' . $quota);
575
-			}
576
-			$quota = OC_Helper::humanFileSize($bytesQuota);
577
-		}
578
-		if ($quota !== $oldQuota) {
579
-			$this->config->setUserValue($this->uid, 'files', 'quota', $quota);
580
-			$this->triggerChange('quota', $quota, $oldQuota);
581
-		}
582
-		\OC_Helper::clearStorageInfo('/' . $this->uid . '/files');
583
-	}
584
-
585
-	public function getManagerUids(): array {
586
-		$encodedUids = $this->config->getUserValue(
587
-			$this->uid,
588
-			'settings',
589
-			self::CONFIG_KEY_MANAGERS,
590
-			'[]'
591
-		);
592
-		return json_decode($encodedUids, false, 512, JSON_THROW_ON_ERROR);
593
-	}
594
-
595
-	public function setManagerUids(array $uids): void {
596
-		$oldUids = $this->getManagerUids();
597
-		$this->config->setUserValue(
598
-			$this->uid,
599
-			'settings',
600
-			self::CONFIG_KEY_MANAGERS,
601
-			json_encode($uids, JSON_THROW_ON_ERROR)
602
-		);
603
-		$this->triggerChange('managers', $uids, $oldUids);
604
-	}
605
-
606
-	/**
607
-	 * get the avatar image if it exists
608
-	 *
609
-	 * @param int $size
610
-	 * @return IImage|null
611
-	 * @since 9.0.0
612
-	 */
613
-	public function getAvatarImage($size) {
614
-		// delay the initialization
615
-		if (is_null($this->avatarManager)) {
616
-			$this->avatarManager = \OC::$server->get(IAvatarManager::class);
617
-		}
618
-
619
-		$avatar = $this->avatarManager->getAvatar($this->uid);
620
-		$image = $avatar->get($size);
621
-		if ($image) {
622
-			return $image;
623
-		}
624
-
625
-		return null;
626
-	}
627
-
628
-	/**
629
-	 * get the federation cloud id
630
-	 *
631
-	 * @return string
632
-	 * @since 9.0.0
633
-	 */
634
-	public function getCloudId() {
635
-		$uid = $this->getUID();
636
-		$server = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/');
637
-		if (str_ends_with($server, '/index.php')) {
638
-			$server = substr($server, 0, -10);
639
-		}
640
-		$server = $this->removeProtocolFromUrl($server);
641
-		return $uid . '@' . $server;
642
-	}
643
-
644
-	private function removeProtocolFromUrl(string $url): string {
645
-		if (str_starts_with($url, 'https://')) {
646
-			return substr($url, strlen('https://'));
647
-		}
648
-
649
-		return $url;
650
-	}
651
-
652
-	public function triggerChange($feature, $value = null, $oldValue = null) {
653
-		$this->dispatcher->dispatchTyped(new UserChangedEvent($this, $feature, $value, $oldValue));
654
-		if ($this->emitter) {
655
-			$this->emitter->emit('\OC\User', 'changeUser', [$this, $feature, $value, $oldValue]);
656
-		}
657
-	}
48
+    private const CONFIG_KEY_MANAGERS = 'manager';
49
+
50
+    private IConfig $config;
51
+    private IURLGenerator $urlGenerator;
52
+
53
+    /** @var IAccountManager */
54
+    protected $accountManager;
55
+
56
+    /** @var string|null */
57
+    private $displayName;
58
+
59
+    /** @var bool|null */
60
+    private $enabled;
61
+
62
+    /** @var Emitter|Manager|null */
63
+    private $emitter;
64
+
65
+    /** @var string */
66
+    private $home;
67
+
68
+    private ?int $lastLogin = null;
69
+    private ?int $firstLogin = null;
70
+
71
+    /** @var IAvatarManager */
72
+    private $avatarManager;
73
+
74
+    public function __construct(
75
+        private string $uid,
76
+        private ?UserInterface $backend,
77
+        private IEventDispatcher $dispatcher,
78
+        $emitter = null,
79
+        ?IConfig $config = null,
80
+        $urlGenerator = null,
81
+    ) {
82
+        $this->emitter = $emitter;
83
+        $this->config = $config ?? \OCP\Server::get(IConfig::class);
84
+        $this->urlGenerator = $urlGenerator ?? \OCP\Server::get(IURLGenerator::class);
85
+    }
86
+
87
+    /**
88
+     * get the user id
89
+     *
90
+     * @return string
91
+     */
92
+    public function getUID() {
93
+        return $this->uid;
94
+    }
95
+
96
+    /**
97
+     * get the display name for the user, if no specific display name is set it will fallback to the user id
98
+     *
99
+     * @return string
100
+     */
101
+    public function getDisplayName() {
102
+        if ($this->displayName === null) {
103
+            $displayName = '';
104
+            if ($this->backend && $this->backend->implementsActions(Backend::GET_DISPLAYNAME)) {
105
+                // get display name and strip whitespace from the beginning and end of it
106
+                $backendDisplayName = $this->backend->getDisplayName($this->uid);
107
+                if (is_string($backendDisplayName)) {
108
+                    $displayName = trim($backendDisplayName);
109
+                }
110
+            }
111
+
112
+            if (!empty($displayName)) {
113
+                $this->displayName = $displayName;
114
+            } else {
115
+                $this->displayName = $this->uid;
116
+            }
117
+        }
118
+        return $this->displayName;
119
+    }
120
+
121
+    /**
122
+     * set the displayname for the user
123
+     *
124
+     * @param string $displayName
125
+     * @return bool
126
+     *
127
+     * @since 25.0.0 Throw InvalidArgumentException
128
+     * @throws \InvalidArgumentException
129
+     */
130
+    public function setDisplayName($displayName) {
131
+        $displayName = trim($displayName);
132
+        $oldDisplayName = $this->getDisplayName();
133
+        if ($this->backend->implementsActions(Backend::SET_DISPLAYNAME) && !empty($displayName) && $displayName !== $oldDisplayName) {
134
+            /** @var ISetDisplayNameBackend $backend */
135
+            $backend = $this->backend;
136
+            $result = $backend->setDisplayName($this->uid, $displayName);
137
+            if ($result) {
138
+                $this->displayName = $displayName;
139
+                $this->triggerChange('displayName', $displayName, $oldDisplayName);
140
+            }
141
+            return $result !== false;
142
+        }
143
+        return false;
144
+    }
145
+
146
+    /**
147
+     * @inheritDoc
148
+     */
149
+    public function setEMailAddress($mailAddress) {
150
+        $this->setSystemEMailAddress($mailAddress);
151
+    }
152
+
153
+    /**
154
+     * @inheritDoc
155
+     */
156
+    public function setSystemEMailAddress(string $mailAddress): void {
157
+        $oldMailAddress = $this->getSystemEMailAddress();
158
+
159
+        if ($mailAddress === '') {
160
+            $this->config->deleteUserValue($this->uid, 'settings', 'email');
161
+        } else {
162
+            $this->config->setUserValue($this->uid, 'settings', 'email', $mailAddress);
163
+        }
164
+
165
+        $primaryAddress = $this->getPrimaryEMailAddress();
166
+        if ($primaryAddress === $mailAddress) {
167
+            // on match no dedicated primary settings is necessary
168
+            $this->setPrimaryEMailAddress('');
169
+        }
170
+
171
+        if ($oldMailAddress !== strtolower($mailAddress)) {
172
+            $this->triggerChange('eMailAddress', $mailAddress, $oldMailAddress);
173
+        }
174
+    }
175
+
176
+    /**
177
+     * @inheritDoc
178
+     */
179
+    public function setPrimaryEMailAddress(string $mailAddress): void {
180
+        if ($mailAddress === '') {
181
+            $this->config->deleteUserValue($this->uid, 'settings', 'primary_email');
182
+            return;
183
+        }
184
+
185
+        $this->ensureAccountManager();
186
+        $account = $this->accountManager->getAccount($this);
187
+        $property = $account->getPropertyCollection(IAccountManager::COLLECTION_EMAIL)
188
+            ->getPropertyByValue($mailAddress);
189
+
190
+        if ($property === null || $property->getLocallyVerified() !== IAccountManager::VERIFIED) {
191
+            throw new InvalidArgumentException('Only verified emails can be set as primary');
192
+        }
193
+        $this->config->setUserValue($this->uid, 'settings', 'primary_email', $mailAddress);
194
+    }
195
+
196
+    private function ensureAccountManager() {
197
+        if (!$this->accountManager instanceof IAccountManager) {
198
+            $this->accountManager = \OC::$server->get(IAccountManager::class);
199
+        }
200
+    }
201
+
202
+    /**
203
+     * returns the timestamp of the user's last login or 0 if the user did never
204
+     * login
205
+     */
206
+    public function getLastLogin(): int {
207
+        if ($this->lastLogin === null) {
208
+            $this->lastLogin = (int)$this->config->getUserValue($this->uid, 'login', 'lastLogin', 0);
209
+        }
210
+        return $this->lastLogin;
211
+    }
212
+
213
+    /**
214
+     * returns the timestamp of the user's last login or 0 if the user did never
215
+     * login
216
+     */
217
+    public function getFirstLogin(): int {
218
+        if ($this->firstLogin === null) {
219
+            $this->firstLogin = (int)$this->config->getUserValue($this->uid, 'login', 'firstLogin', 0);
220
+        }
221
+        return $this->firstLogin;
222
+    }
223
+
224
+    /**
225
+     * updates the timestamp of the most recent login of this user
226
+     */
227
+    public function updateLastLoginTimestamp(): bool {
228
+        $previousLogin = $this->getLastLogin();
229
+        $firstLogin = $this->getFirstLogin();
230
+        $now = time();
231
+        $firstTimeLogin = $previousLogin === 0;
232
+
233
+        if ($now - $previousLogin > 60) {
234
+            $this->lastLogin = $now;
235
+            $this->config->setUserValue($this->uid, 'login', 'lastLogin', (string)$this->lastLogin);
236
+        }
237
+
238
+        if ($firstLogin === 0) {
239
+            if ($firstTimeLogin) {
240
+                $this->firstLogin = $now;
241
+            } else {
242
+                /* Unknown first login, most likely was before upgrade to Nextcloud 31 */
243
+                $this->firstLogin = -1;
244
+            }
245
+            $this->config->setUserValue($this->uid, 'login', 'firstLogin', (string)$this->firstLogin);
246
+        }
247
+
248
+        return $firstTimeLogin;
249
+    }
250
+
251
+    /**
252
+     * Delete the user
253
+     *
254
+     * @return bool
255
+     */
256
+    public function delete() {
257
+        if ($this->backend === null) {
258
+            \OCP\Server::get(LoggerInterface::class)->error('Cannot delete user: No backend set');
259
+            return false;
260
+        }
261
+
262
+        if ($this->emitter) {
263
+            /** @deprecated 21.0.0 use BeforeUserDeletedEvent event with the IEventDispatcher instead */
264
+            $this->emitter->emit('\OC\User', 'preDelete', [$this]);
265
+        }
266
+        $this->dispatcher->dispatchTyped(new BeforeUserDeletedEvent($this));
267
+
268
+        // Set delete flag on the user - this is needed to ensure that the user data is removed if there happen any exception in the backend
269
+        // because we can not restore the user meaning we could not rollback to any stable state otherwise.
270
+        $this->config->setUserValue($this->uid, 'core', 'deleted', 'true');
271
+        // We also need to backup the home path as this can not be reconstructed later if the original backend uses custom home paths
272
+        $this->config->setUserValue($this->uid, 'core', 'deleted.home-path', $this->getHome());
273
+
274
+        // Try to delete the user on the backend
275
+        $result = $this->backend->deleteUser($this->uid);
276
+        if ($result === false) {
277
+            // The deletion was aborted or something else happened, we are in a defined state, so remove the delete flag
278
+            $this->config->deleteUserValue($this->uid, 'core', 'deleted');
279
+            return false;
280
+        }
281
+
282
+        // We have to delete the user from all groups
283
+        $groupManager = \OCP\Server::get(IGroupManager::class);
284
+        foreach ($groupManager->getUserGroupIds($this) as $groupId) {
285
+            $group = $groupManager->get($groupId);
286
+            if ($group) {
287
+                $this->dispatcher->dispatchTyped(new BeforeUserRemovedEvent($group, $this));
288
+                $group->removeUser($this);
289
+                $this->dispatcher->dispatchTyped(new UserRemovedEvent($group, $this));
290
+            }
291
+        }
292
+
293
+        $commentsManager = \OCP\Server::get(ICommentsManager::class);
294
+        $commentsManager->deleteReferencesOfActor('users', $this->uid);
295
+        $commentsManager->deleteReadMarksFromUser($this);
296
+
297
+        $avatarManager = \OCP\Server::get(AvatarManager::class);
298
+        $avatarManager->deleteUserAvatar($this->uid);
299
+
300
+        $notificationManager = \OCP\Server::get(INotificationManager::class);
301
+        $notification = $notificationManager->createNotification();
302
+        $notification->setUser($this->uid);
303
+        $notificationManager->markProcessed($notification);
304
+
305
+        $accountManager = \OCP\Server::get(AccountManager::class);
306
+        $accountManager->deleteUser($this);
307
+
308
+        $database = \OCP\Server::get(IDBConnection::class);
309
+        try {
310
+            // We need to create a transaction to make sure we are in a defined state
311
+            // because if all user values are removed also the flag is gone, but if an exception happens (e.g. database lost connection on the set operation)
312
+            // exactly here we are in an undefined state as the data is still present but the user does not exist on the system anymore.
313
+            $database->beginTransaction();
314
+            // Remove all user settings
315
+            $this->config->deleteAllUserValues($this->uid);
316
+            // But again set flag that this user is about to be deleted
317
+            $this->config->setUserValue($this->uid, 'core', 'deleted', 'true');
318
+            $this->config->setUserValue($this->uid, 'core', 'deleted.home-path', $this->getHome());
319
+            // Commit the transaction so we are in a defined state: either the preferences are removed or an exception occurred but the delete flag is still present
320
+            $database->commit();
321
+        } catch (\Throwable $e) {
322
+            $database->rollback();
323
+            throw $e;
324
+        }
325
+
326
+        if ($this->emitter !== null) {
327
+            /** @deprecated 21.0.0 use UserDeletedEvent event with the IEventDispatcher instead */
328
+            $this->emitter->emit('\OC\User', 'postDelete', [$this]);
329
+        }
330
+        $this->dispatcher->dispatchTyped(new UserDeletedEvent($this));
331
+
332
+        // Finally we can unset the delete flag and all other states
333
+        $this->config->deleteAllUserValues($this->uid);
334
+
335
+        return true;
336
+    }
337
+
338
+    /**
339
+     * Set the password of the user
340
+     *
341
+     * @param string $password
342
+     * @param string $recoveryPassword for the encryption app to reset encryption keys
343
+     * @return bool
344
+     */
345
+    public function setPassword($password, $recoveryPassword = null) {
346
+        $this->dispatcher->dispatchTyped(new BeforePasswordUpdatedEvent($this, $password, $recoveryPassword));
347
+        if ($this->emitter) {
348
+            $this->emitter->emit('\OC\User', 'preSetPassword', [$this, $password, $recoveryPassword]);
349
+        }
350
+        if ($this->backend->implementsActions(Backend::SET_PASSWORD)) {
351
+            /** @var ISetPasswordBackend $backend */
352
+            $backend = $this->backend;
353
+            $result = $backend->setPassword($this->uid, $password);
354
+
355
+            if ($result !== false) {
356
+                $this->dispatcher->dispatchTyped(new PasswordUpdatedEvent($this, $password, $recoveryPassword));
357
+                if ($this->emitter) {
358
+                    $this->emitter->emit('\OC\User', 'postSetPassword', [$this, $password, $recoveryPassword]);
359
+                }
360
+            }
361
+
362
+            return !($result === false);
363
+        } else {
364
+            return false;
365
+        }
366
+    }
367
+
368
+    public function getPasswordHash(): ?string {
369
+        if (!($this->backend instanceof IPasswordHashBackend)) {
370
+            return null;
371
+        }
372
+        return $this->backend->getPasswordHash($this->uid);
373
+    }
374
+
375
+    public function setPasswordHash(string $passwordHash): bool {
376
+        if (!($this->backend instanceof IPasswordHashBackend)) {
377
+            return false;
378
+        }
379
+        return $this->backend->setPasswordHash($this->uid, $passwordHash);
380
+    }
381
+
382
+    /**
383
+     * get the users home folder to mount
384
+     *
385
+     * @return string
386
+     */
387
+    public function getHome() {
388
+        if (!$this->home) {
389
+            /** @psalm-suppress UndefinedInterfaceMethod Once we get rid of the legacy implementsActions, psalm won't complain anymore */
390
+            if (($this->backend instanceof IGetHomeBackend || $this->backend->implementsActions(Backend::GET_HOME)) && $home = $this->backend->getHome($this->uid)) {
391
+                $this->home = $home;
392
+            } else {
393
+                $this->home = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $this->uid;
394
+            }
395
+        }
396
+        return $this->home;
397
+    }
398
+
399
+    /**
400
+     * Get the name of the backend class the user is connected with
401
+     *
402
+     * @return string
403
+     */
404
+    public function getBackendClassName() {
405
+        if ($this->backend instanceof IUserBackend) {
406
+            return $this->backend->getBackendName();
407
+        }
408
+        return get_class($this->backend);
409
+    }
410
+
411
+    public function getBackend(): ?UserInterface {
412
+        return $this->backend;
413
+    }
414
+
415
+    /**
416
+     * Check if the backend allows the user to change their avatar on Personal page
417
+     *
418
+     * @return bool
419
+     */
420
+    public function canChangeAvatar() {
421
+        if ($this->backend instanceof IProvideAvatarBackend || $this->backend->implementsActions(Backend::PROVIDE_AVATAR)) {
422
+            /** @var IProvideAvatarBackend $backend */
423
+            $backend = $this->backend;
424
+            return $backend->canChangeAvatar($this->uid);
425
+        }
426
+        return true;
427
+    }
428
+
429
+    /**
430
+     * check if the backend supports changing passwords
431
+     *
432
+     * @return bool
433
+     */
434
+    public function canChangePassword() {
435
+        return $this->backend->implementsActions(Backend::SET_PASSWORD);
436
+    }
437
+
438
+    /**
439
+     * check if the backend supports changing display names
440
+     *
441
+     * @return bool
442
+     */
443
+    public function canChangeDisplayName() {
444
+        if (!$this->config->getSystemValueBool('allow_user_to_change_display_name', true)) {
445
+            return false;
446
+        }
447
+        return $this->backend->implementsActions(Backend::SET_DISPLAYNAME);
448
+    }
449
+
450
+    public function canChangeEmail(): bool {
451
+        return $this->config->getSystemValueBool('allow_user_to_change_email', true);
452
+    }
453
+
454
+    /**
455
+     * check if the user is enabled
456
+     *
457
+     * @return bool
458
+     */
459
+    public function isEnabled() {
460
+        $queryDatabaseValue = function (): bool {
461
+            if ($this->enabled === null) {
462
+                $enabled = $this->config->getUserValue($this->uid, 'core', 'enabled', 'true');
463
+                $this->enabled = $enabled === 'true';
464
+            }
465
+            return $this->enabled;
466
+        };
467
+        if ($this->backend instanceof IProvideEnabledStateBackend) {
468
+            return $this->backend->isUserEnabled($this->uid, $queryDatabaseValue);
469
+        } else {
470
+            return $queryDatabaseValue();
471
+        }
472
+    }
473
+
474
+    /**
475
+     * set the enabled status for the user
476
+     *
477
+     * @return void
478
+     */
479
+    public function setEnabled(bool $enabled = true) {
480
+        $oldStatus = $this->isEnabled();
481
+        $setDatabaseValue = function (bool $enabled): void {
482
+            $this->config->setUserValue($this->uid, 'core', 'enabled', $enabled ? 'true' : 'false');
483
+            $this->enabled = $enabled;
484
+        };
485
+        if ($this->backend instanceof IProvideEnabledStateBackend) {
486
+            $queryDatabaseValue = function (): bool {
487
+                if ($this->enabled === null) {
488
+                    $enabled = $this->config->getUserValue($this->uid, 'core', 'enabled', 'true');
489
+                    $this->enabled = $enabled === 'true';
490
+                }
491
+                return $this->enabled;
492
+            };
493
+            $enabled = $this->backend->setUserEnabled($this->uid, $enabled, $queryDatabaseValue, $setDatabaseValue);
494
+            if ($oldStatus !== $enabled) {
495
+                $this->triggerChange('enabled', $enabled, $oldStatus);
496
+            }
497
+        } elseif ($oldStatus !== $enabled) {
498
+            $setDatabaseValue($enabled);
499
+            $this->triggerChange('enabled', $enabled, $oldStatus);
500
+        }
501
+    }
502
+
503
+    /**
504
+     * get the users email address
505
+     *
506
+     * @return string|null
507
+     * @since 9.0.0
508
+     */
509
+    public function getEMailAddress() {
510
+        return $this->getPrimaryEMailAddress() ?? $this->getSystemEMailAddress();
511
+    }
512
+
513
+    /**
514
+     * @inheritDoc
515
+     */
516
+    public function getSystemEMailAddress(): ?string {
517
+        return $this->config->getUserValue($this->uid, 'settings', 'email', null);
518
+    }
519
+
520
+    /**
521
+     * @inheritDoc
522
+     */
523
+    public function getPrimaryEMailAddress(): ?string {
524
+        return $this->config->getUserValue($this->uid, 'settings', 'primary_email', null);
525
+    }
526
+
527
+    /**
528
+     * get the users' quota
529
+     *
530
+     * @return string
531
+     * @since 9.0.0
532
+     */
533
+    public function getQuota() {
534
+        // allow apps to modify the user quota by hooking into the event
535
+        $event = new GetQuotaEvent($this);
536
+        $this->dispatcher->dispatchTyped($event);
537
+        $overwriteQuota = $event->getQuota();
538
+        if ($overwriteQuota) {
539
+            $quota = $overwriteQuota;
540
+        } else {
541
+            $quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default');
542
+        }
543
+        if ($quota === 'default') {
544
+            $quota = $this->config->getAppValue('files', 'default_quota', 'none');
545
+
546
+            // if unlimited quota is not allowed => avoid getting 'unlimited' as default_quota fallback value
547
+            // use the first preset instead
548
+            $allowUnlimitedQuota = $this->config->getAppValue('files', 'allow_unlimited_quota', '1') === '1';
549
+            if (!$allowUnlimitedQuota) {
550
+                $presets = $this->config->getAppValue('files', 'quota_preset', '1 GB, 5 GB, 10 GB');
551
+                $presets = array_filter(array_map('trim', explode(',', $presets)));
552
+                $quotaPreset = array_values(array_diff($presets, ['default', 'none']));
553
+                if (count($quotaPreset) > 0) {
554
+                    $quota = $this->config->getAppValue('files', 'default_quota', $quotaPreset[0]);
555
+                }
556
+            }
557
+        }
558
+        return $quota;
559
+    }
560
+
561
+    /**
562
+     * set the users' quota
563
+     *
564
+     * @param string $quota
565
+     * @return void
566
+     * @throws InvalidArgumentException
567
+     * @since 9.0.0
568
+     */
569
+    public function setQuota($quota) {
570
+        $oldQuota = $this->config->getUserValue($this->uid, 'files', 'quota', '');
571
+        if ($quota !== 'none' and $quota !== 'default') {
572
+            $bytesQuota = OC_Helper::computerFileSize($quota);
573
+            if ($bytesQuota === false) {
574
+                throw new InvalidArgumentException('Failed to set quota to invalid value ' . $quota);
575
+            }
576
+            $quota = OC_Helper::humanFileSize($bytesQuota);
577
+        }
578
+        if ($quota !== $oldQuota) {
579
+            $this->config->setUserValue($this->uid, 'files', 'quota', $quota);
580
+            $this->triggerChange('quota', $quota, $oldQuota);
581
+        }
582
+        \OC_Helper::clearStorageInfo('/' . $this->uid . '/files');
583
+    }
584
+
585
+    public function getManagerUids(): array {
586
+        $encodedUids = $this->config->getUserValue(
587
+            $this->uid,
588
+            'settings',
589
+            self::CONFIG_KEY_MANAGERS,
590
+            '[]'
591
+        );
592
+        return json_decode($encodedUids, false, 512, JSON_THROW_ON_ERROR);
593
+    }
594
+
595
+    public function setManagerUids(array $uids): void {
596
+        $oldUids = $this->getManagerUids();
597
+        $this->config->setUserValue(
598
+            $this->uid,
599
+            'settings',
600
+            self::CONFIG_KEY_MANAGERS,
601
+            json_encode($uids, JSON_THROW_ON_ERROR)
602
+        );
603
+        $this->triggerChange('managers', $uids, $oldUids);
604
+    }
605
+
606
+    /**
607
+     * get the avatar image if it exists
608
+     *
609
+     * @param int $size
610
+     * @return IImage|null
611
+     * @since 9.0.0
612
+     */
613
+    public function getAvatarImage($size) {
614
+        // delay the initialization
615
+        if (is_null($this->avatarManager)) {
616
+            $this->avatarManager = \OC::$server->get(IAvatarManager::class);
617
+        }
618
+
619
+        $avatar = $this->avatarManager->getAvatar($this->uid);
620
+        $image = $avatar->get($size);
621
+        if ($image) {
622
+            return $image;
623
+        }
624
+
625
+        return null;
626
+    }
627
+
628
+    /**
629
+     * get the federation cloud id
630
+     *
631
+     * @return string
632
+     * @since 9.0.0
633
+     */
634
+    public function getCloudId() {
635
+        $uid = $this->getUID();
636
+        $server = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/');
637
+        if (str_ends_with($server, '/index.php')) {
638
+            $server = substr($server, 0, -10);
639
+        }
640
+        $server = $this->removeProtocolFromUrl($server);
641
+        return $uid . '@' . $server;
642
+    }
643
+
644
+    private function removeProtocolFromUrl(string $url): string {
645
+        if (str_starts_with($url, 'https://')) {
646
+            return substr($url, strlen('https://'));
647
+        }
648
+
649
+        return $url;
650
+    }
651
+
652
+    public function triggerChange($feature, $value = null, $oldValue = null) {
653
+        $this->dispatcher->dispatchTyped(new UserChangedEvent($this, $feature, $value, $oldValue));
654
+        if ($this->emitter) {
655
+            $this->emitter->emit('\OC\User', 'changeUser', [$this, $feature, $value, $oldValue]);
656
+        }
657
+    }
658 658
 }
Please login to merge, or discard this patch.
lib/public/IUser.php 1 patch
Indentation   +285 added lines, -285 removed lines patch added patch discarded remove patch
@@ -15,289 +15,289 @@
 block discarded – undo
15 15
  * @since 8.0.0
16 16
  */
17 17
 interface IUser {
18
-	/**
19
-	 * get the user id
20
-	 *
21
-	 * @return string
22
-	 * @since 8.0.0
23
-	 */
24
-	public function getUID();
25
-
26
-	/**
27
-	 * get the display name for the user, if no specific display name is set it will fallback to the user id
28
-	 *
29
-	 * @return string
30
-	 * @since 8.0.0
31
-	 */
32
-	public function getDisplayName();
33
-
34
-	/**
35
-	 * set the display name for the user
36
-	 *
37
-	 * @param string $displayName
38
-	 * @return bool
39
-	 * @since 8.0.0
40
-	 *
41
-	 * @since 25.0.0 Throw InvalidArgumentException
42
-	 * @throws \InvalidArgumentException
43
-	 */
44
-	public function setDisplayName($displayName);
45
-
46
-	/**
47
-	 * returns the timestamp of the user's last login or 0 if the user did never
48
-	 * login
49
-	 *
50
-	 * @return int
51
-	 * @since 8.0.0
52
-	 */
53
-	public function getLastLogin(): int;
54
-
55
-	/**
56
-	 * Returns the timestamp of the user's first login, 0 if the user did never login, or -1 if the data is unknown (first login was on an older version)
57
-	 *
58
-	 * @since 31.0.0
59
-	 */
60
-	public function getFirstLogin(): int;
61
-
62
-	/**
63
-	 * Updates the timestamp of the most recent login of this user (and first login if needed)
64
-	 *
65
-	 * @return bool whether this is the first login
66
-	 * @since 8.0.0
67
-	 */
68
-	public function updateLastLoginTimestamp(): bool;
69
-
70
-	/**
71
-	 * Delete the user
72
-	 *
73
-	 * @return bool
74
-	 * @since 8.0.0
75
-	 */
76
-	public function delete();
77
-
78
-	/**
79
-	 * Set the password of the user
80
-	 *
81
-	 * @param string $password
82
-	 * @param string $recoveryPassword for the encryption app to reset encryption keys
83
-	 * @return bool
84
-	 * @since 8.0.0
85
-	 */
86
-	public function setPassword($password, $recoveryPassword = null);
87
-
88
-	/**
89
-	 * Get the password hash of the user
90
-	 *
91
-	 * @return ?string the password hash hashed by `\OCP\Security\IHasher::hash()`
92
-	 * @since 30.0.0
93
-	 */
94
-	public function getPasswordHash(): ?string;
95
-
96
-	/**
97
-	 * Set the password hash of the user
98
-	 *
99
-	 * @param string $passwordHash the password hash hashed by `\OCP\Security\IHasher::hash()`
100
-	 * @throws InvalidArgumentException when `$passwordHash` is not a valid hash
101
-	 * @since 30.0.0
102
-	 */
103
-	public function setPasswordHash(string $passwordHash): bool;
104
-
105
-	/**
106
-	 * get the users home folder to mount
107
-	 *
108
-	 * @return string
109
-	 * @since 8.0.0
110
-	 */
111
-	public function getHome();
112
-
113
-	/**
114
-	 * Get the name of the backend class the user is connected with
115
-	 *
116
-	 * @return string
117
-	 * @since 8.0.0
118
-	 */
119
-	public function getBackendClassName();
120
-
121
-	/**
122
-	 * Get the backend for the current user object
123
-	 * @return ?UserInterface
124
-	 * @since 15.0.0
125
-	 */
126
-	public function getBackend();
127
-
128
-	/**
129
-	 * check if the backend allows the user to change their avatar on Personal page
130
-	 *
131
-	 * @return bool
132
-	 * @since 8.0.0
133
-	 */
134
-	public function canChangeAvatar();
135
-
136
-	/**
137
-	 * check if the backend supports changing passwords
138
-	 *
139
-	 * @return bool
140
-	 * @since 8.0.0
141
-	 */
142
-	public function canChangePassword();
143
-
144
-	/**
145
-	 * check if the backend supports changing display names
146
-	 *
147
-	 * @return bool
148
-	 * @since 8.0.0
149
-	 */
150
-	public function canChangeDisplayName();
151
-
152
-	/**
153
-	 * Check if the backend supports changing email
154
-	 *
155
-	 * @since 32.0.0
156
-	 */
157
-	public function canChangeEmail(): bool;
158
-
159
-	/**
160
-	 * check if the user is enabled
161
-	 *
162
-	 * @return bool
163
-	 * @since 8.0.0
164
-	 */
165
-	public function isEnabled();
166
-
167
-	/**
168
-	 * set the enabled status for the user
169
-	 *
170
-	 * @param bool $enabled
171
-	 * @since 8.0.0
172
-	 */
173
-	public function setEnabled(bool $enabled = true);
174
-
175
-	/**
176
-	 * get the user's email address
177
-	 *
178
-	 * @return string|null
179
-	 * @since 9.0.0
180
-	 */
181
-	public function getEMailAddress();
182
-
183
-	/**
184
-	 * get the user's system email address
185
-	 *
186
-	 * The system mail address may be read only and may be set from different
187
-	 * sources like LDAP, SAML or simply the admin.
188
-	 *
189
-	 * Use this getter only when the system address is needed. For picking the
190
-	 * proper address to e.g. send a mail to, use getEMailAddress().
191
-	 *
192
-	 * @return string|null
193
-	 * @since 23.0.0
194
-	 */
195
-	public function getSystemEMailAddress(): ?string;
196
-
197
-	/**
198
-	 * get the user's preferred email address
199
-	 *
200
-	 * The primary mail address may be set be the user to specify a different
201
-	 * email address where mails by Nextcloud are sent to. It is not necessarily
202
-	 * set.
203
-	 *
204
-	 * Use this getter only when the primary address is needed. For picking the
205
-	 * proper address to e.g. send a mail to, use getEMailAddress().
206
-	 *
207
-	 * @return string|null
208
-	 * @since 23.0.0
209
-	 */
210
-	public function getPrimaryEMailAddress(): ?string;
211
-
212
-	/**
213
-	 * get the avatar image if it exists
214
-	 *
215
-	 * @param int $size
216
-	 * @return IImage|null
217
-	 * @since 9.0.0
218
-	 */
219
-	public function getAvatarImage($size);
220
-
221
-	/**
222
-	 * get the federation cloud id
223
-	 *
224
-	 * @return string
225
-	 * @since 9.0.0
226
-	 */
227
-	public function getCloudId();
228
-
229
-	/**
230
-	 * set the email address of the user
231
-	 *
232
-	 * It is an alias to setSystemEMailAddress()
233
-	 *
234
-	 * @param string|null $mailAddress
235
-	 * @return void
236
-	 * @since 9.0.0
237
-	 * @deprecated 23.0.0 use setSystemEMailAddress() or setPrimaryEMailAddress()
238
-	 */
239
-	public function setEMailAddress($mailAddress);
240
-
241
-	/**
242
-	 * Set the system email address of the user
243
-	 *
244
-	 * This is supposed to be used when the email is set from different sources
245
-	 * (i.e. other user backends, admin).
246
-	 *
247
-	 * @since 23.0.0
248
-	 */
249
-	public function setSystemEMailAddress(string $mailAddress): void;
250
-
251
-	/**
252
-	 * Set the primary email address of the user.
253
-	 *
254
-	 * This method should be typically called when the user is changing their
255
-	 * own primary address and is not allowed to change their system email.
256
-	 *
257
-	 * The mail address provided here must be already registered as an
258
-	 * additional mail in the user account and also be verified locally. Also
259
-	 * an empty string is allowed to delete this preference.
260
-	 *
261
-	 * @throws InvalidArgumentException when the provided email address does not
262
-	 *                                  satisfy constraints.
263
-	 *
264
-	 * @since 23.0.0
265
-	 */
266
-	public function setPrimaryEMailAddress(string $mailAddress): void;
267
-
268
-	/**
269
-	 * get the users' quota in human readable form. If a specific quota is not
270
-	 * set for the user, the default value is returned. If a default setting
271
-	 * was not set otherwise, it is return as 'none', i.e. quota is not limited.
272
-	 *
273
-	 * @return string
274
-	 * @since 9.0.0
275
-	 */
276
-	public function getQuota();
277
-
278
-	/**
279
-	 * set the users' quota
280
-	 *
281
-	 * @param string $quota
282
-	 * @return void
283
-	 * @since 9.0.0
284
-	 */
285
-	public function setQuota($quota);
286
-
287
-	/**
288
-	 * Get the user's manager UIDs
289
-	 *
290
-	 * @since 27.0.0
291
-	 * @return string[]
292
-	 */
293
-	public function getManagerUids(): array;
294
-
295
-	/**
296
-	 * Set the user's manager UIDs
297
-	 *
298
-	 * @param string[] $uids UIDs of all managers
299
-	 * @return void
300
-	 * @since 27.0.0
301
-	 */
302
-	public function setManagerUids(array $uids): void;
18
+    /**
19
+     * get the user id
20
+     *
21
+     * @return string
22
+     * @since 8.0.0
23
+     */
24
+    public function getUID();
25
+
26
+    /**
27
+     * get the display name for the user, if no specific display name is set it will fallback to the user id
28
+     *
29
+     * @return string
30
+     * @since 8.0.0
31
+     */
32
+    public function getDisplayName();
33
+
34
+    /**
35
+     * set the display name for the user
36
+     *
37
+     * @param string $displayName
38
+     * @return bool
39
+     * @since 8.0.0
40
+     *
41
+     * @since 25.0.0 Throw InvalidArgumentException
42
+     * @throws \InvalidArgumentException
43
+     */
44
+    public function setDisplayName($displayName);
45
+
46
+    /**
47
+     * returns the timestamp of the user's last login or 0 if the user did never
48
+     * login
49
+     *
50
+     * @return int
51
+     * @since 8.0.0
52
+     */
53
+    public function getLastLogin(): int;
54
+
55
+    /**
56
+     * Returns the timestamp of the user's first login, 0 if the user did never login, or -1 if the data is unknown (first login was on an older version)
57
+     *
58
+     * @since 31.0.0
59
+     */
60
+    public function getFirstLogin(): int;
61
+
62
+    /**
63
+     * Updates the timestamp of the most recent login of this user (and first login if needed)
64
+     *
65
+     * @return bool whether this is the first login
66
+     * @since 8.0.0
67
+     */
68
+    public function updateLastLoginTimestamp(): bool;
69
+
70
+    /**
71
+     * Delete the user
72
+     *
73
+     * @return bool
74
+     * @since 8.0.0
75
+     */
76
+    public function delete();
77
+
78
+    /**
79
+     * Set the password of the user
80
+     *
81
+     * @param string $password
82
+     * @param string $recoveryPassword for the encryption app to reset encryption keys
83
+     * @return bool
84
+     * @since 8.0.0
85
+     */
86
+    public function setPassword($password, $recoveryPassword = null);
87
+
88
+    /**
89
+     * Get the password hash of the user
90
+     *
91
+     * @return ?string the password hash hashed by `\OCP\Security\IHasher::hash()`
92
+     * @since 30.0.0
93
+     */
94
+    public function getPasswordHash(): ?string;
95
+
96
+    /**
97
+     * Set the password hash of the user
98
+     *
99
+     * @param string $passwordHash the password hash hashed by `\OCP\Security\IHasher::hash()`
100
+     * @throws InvalidArgumentException when `$passwordHash` is not a valid hash
101
+     * @since 30.0.0
102
+     */
103
+    public function setPasswordHash(string $passwordHash): bool;
104
+
105
+    /**
106
+     * get the users home folder to mount
107
+     *
108
+     * @return string
109
+     * @since 8.0.0
110
+     */
111
+    public function getHome();
112
+
113
+    /**
114
+     * Get the name of the backend class the user is connected with
115
+     *
116
+     * @return string
117
+     * @since 8.0.0
118
+     */
119
+    public function getBackendClassName();
120
+
121
+    /**
122
+     * Get the backend for the current user object
123
+     * @return ?UserInterface
124
+     * @since 15.0.0
125
+     */
126
+    public function getBackend();
127
+
128
+    /**
129
+     * check if the backend allows the user to change their avatar on Personal page
130
+     *
131
+     * @return bool
132
+     * @since 8.0.0
133
+     */
134
+    public function canChangeAvatar();
135
+
136
+    /**
137
+     * check if the backend supports changing passwords
138
+     *
139
+     * @return bool
140
+     * @since 8.0.0
141
+     */
142
+    public function canChangePassword();
143
+
144
+    /**
145
+     * check if the backend supports changing display names
146
+     *
147
+     * @return bool
148
+     * @since 8.0.0
149
+     */
150
+    public function canChangeDisplayName();
151
+
152
+    /**
153
+     * Check if the backend supports changing email
154
+     *
155
+     * @since 32.0.0
156
+     */
157
+    public function canChangeEmail(): bool;
158
+
159
+    /**
160
+     * check if the user is enabled
161
+     *
162
+     * @return bool
163
+     * @since 8.0.0
164
+     */
165
+    public function isEnabled();
166
+
167
+    /**
168
+     * set the enabled status for the user
169
+     *
170
+     * @param bool $enabled
171
+     * @since 8.0.0
172
+     */
173
+    public function setEnabled(bool $enabled = true);
174
+
175
+    /**
176
+     * get the user's email address
177
+     *
178
+     * @return string|null
179
+     * @since 9.0.0
180
+     */
181
+    public function getEMailAddress();
182
+
183
+    /**
184
+     * get the user's system email address
185
+     *
186
+     * The system mail address may be read only and may be set from different
187
+     * sources like LDAP, SAML or simply the admin.
188
+     *
189
+     * Use this getter only when the system address is needed. For picking the
190
+     * proper address to e.g. send a mail to, use getEMailAddress().
191
+     *
192
+     * @return string|null
193
+     * @since 23.0.0
194
+     */
195
+    public function getSystemEMailAddress(): ?string;
196
+
197
+    /**
198
+     * get the user's preferred email address
199
+     *
200
+     * The primary mail address may be set be the user to specify a different
201
+     * email address where mails by Nextcloud are sent to. It is not necessarily
202
+     * set.
203
+     *
204
+     * Use this getter only when the primary address is needed. For picking the
205
+     * proper address to e.g. send a mail to, use getEMailAddress().
206
+     *
207
+     * @return string|null
208
+     * @since 23.0.0
209
+     */
210
+    public function getPrimaryEMailAddress(): ?string;
211
+
212
+    /**
213
+     * get the avatar image if it exists
214
+     *
215
+     * @param int $size
216
+     * @return IImage|null
217
+     * @since 9.0.0
218
+     */
219
+    public function getAvatarImage($size);
220
+
221
+    /**
222
+     * get the federation cloud id
223
+     *
224
+     * @return string
225
+     * @since 9.0.0
226
+     */
227
+    public function getCloudId();
228
+
229
+    /**
230
+     * set the email address of the user
231
+     *
232
+     * It is an alias to setSystemEMailAddress()
233
+     *
234
+     * @param string|null $mailAddress
235
+     * @return void
236
+     * @since 9.0.0
237
+     * @deprecated 23.0.0 use setSystemEMailAddress() or setPrimaryEMailAddress()
238
+     */
239
+    public function setEMailAddress($mailAddress);
240
+
241
+    /**
242
+     * Set the system email address of the user
243
+     *
244
+     * This is supposed to be used when the email is set from different sources
245
+     * (i.e. other user backends, admin).
246
+     *
247
+     * @since 23.0.0
248
+     */
249
+    public function setSystemEMailAddress(string $mailAddress): void;
250
+
251
+    /**
252
+     * Set the primary email address of the user.
253
+     *
254
+     * This method should be typically called when the user is changing their
255
+     * own primary address and is not allowed to change their system email.
256
+     *
257
+     * The mail address provided here must be already registered as an
258
+     * additional mail in the user account and also be verified locally. Also
259
+     * an empty string is allowed to delete this preference.
260
+     *
261
+     * @throws InvalidArgumentException when the provided email address does not
262
+     *                                  satisfy constraints.
263
+     *
264
+     * @since 23.0.0
265
+     */
266
+    public function setPrimaryEMailAddress(string $mailAddress): void;
267
+
268
+    /**
269
+     * get the users' quota in human readable form. If a specific quota is not
270
+     * set for the user, the default value is returned. If a default setting
271
+     * was not set otherwise, it is return as 'none', i.e. quota is not limited.
272
+     *
273
+     * @return string
274
+     * @since 9.0.0
275
+     */
276
+    public function getQuota();
277
+
278
+    /**
279
+     * set the users' quota
280
+     *
281
+     * @param string $quota
282
+     * @return void
283
+     * @since 9.0.0
284
+     */
285
+    public function setQuota($quota);
286
+
287
+    /**
288
+     * Get the user's manager UIDs
289
+     *
290
+     * @since 27.0.0
291
+     * @return string[]
292
+     */
293
+    public function getManagerUids(): array;
294
+
295
+    /**
296
+     * Set the user's manager UIDs
297
+     *
298
+     * @param string[] $uids UIDs of all managers
299
+     * @return void
300
+     * @since 27.0.0
301
+     */
302
+    public function setManagerUids(array $uids): void;
303 303
 }
Please login to merge, or discard this patch.
core/Migrations/Version32000Date20250402182800.php 1 patch
Indentation   +12 added lines, -12 removed lines patch added patch discarded remove patch
@@ -15,19 +15,19 @@
 block discarded – undo
15 15
  */
16 16
 class Version32000Date20250402182800 extends SimpleMigrationStep {
17 17
 
18
-	public function __construct(
19
-		private IConfig $config,
20
-	) {
21
-	}
18
+    public function __construct(
19
+        private IConfig $config,
20
+    ) {
21
+    }
22 22
 
23
-	public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) {
24
-		$allowDisplayName = $this->config->getSystemValue('allow_user_to_change_display_name', null);
25
-		$allowEmail = $this->config->getSystemValue('allow_user_to_change_email', null);
23
+    public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) {
24
+        $allowDisplayName = $this->config->getSystemValue('allow_user_to_change_display_name', null);
25
+        $allowEmail = $this->config->getSystemValue('allow_user_to_change_email', null);
26 26
 
27
-		// if displayname was set, but not the email setting, then set the email setting to the same as the email setting
28
-		if ($allowDisplayName !== null && $allowEmail === null) {
29
-			$this->config->setSystemValue('allow_user_to_change_email', $allowDisplayName === true);
30
-		}
31
-	}
27
+        // if displayname was set, but not the email setting, then set the email setting to the same as the email setting
28
+        if ($allowDisplayName !== null && $allowEmail === null) {
29
+            $this->config->setSystemValue('allow_user_to_change_email', $allowDisplayName === true);
30
+        }
31
+    }
32 32
 
33 33
 }
Please login to merge, or discard this patch.