Passed
Push — master ( 7e3d5d...244031 )
by Christoph
17:27 queued 12s
created
lib/public/IUser.php 1 patch
Indentation   +226 added lines, -226 removed lines patch added patch discarded remove patch
@@ -35,256 +35,256 @@
 block discarded – undo
35 35
  * @since 8.0.0
36 36
  */
37 37
 interface IUser {
38
-	/**
39
-	 * get the user id
40
-	 *
41
-	 * @return string
42
-	 * @since 8.0.0
43
-	 */
44
-	public function getUID();
38
+    /**
39
+     * get the user id
40
+     *
41
+     * @return string
42
+     * @since 8.0.0
43
+     */
44
+    public function getUID();
45 45
 
46
-	/**
47
-	 * get the display name for the user, if no specific display name is set it will fallback to the user id
48
-	 *
49
-	 * @return string
50
-	 * @since 8.0.0
51
-	 */
52
-	public function getDisplayName();
46
+    /**
47
+     * get the display name for the user, if no specific display name is set it will fallback to the user id
48
+     *
49
+     * @return string
50
+     * @since 8.0.0
51
+     */
52
+    public function getDisplayName();
53 53
 
54
-	/**
55
-	 * set the display name for the user
56
-	 *
57
-	 * @param string $displayName
58
-	 * @return bool
59
-	 * @since 8.0.0
60
-	 *
61
-	 * @since 25.0.0 Throw InvalidArgumentException
62
-	 * @throws \InvalidArgumentException
63
-	 */
64
-	public function setDisplayName($displayName);
54
+    /**
55
+     * set the display name for the user
56
+     *
57
+     * @param string $displayName
58
+     * @return bool
59
+     * @since 8.0.0
60
+     *
61
+     * @since 25.0.0 Throw InvalidArgumentException
62
+     * @throws \InvalidArgumentException
63
+     */
64
+    public function setDisplayName($displayName);
65 65
 
66
-	/**
67
-	 * returns the timestamp of the user's last login or 0 if the user did never
68
-	 * login
69
-	 *
70
-	 * @return int
71
-	 * @since 8.0.0
72
-	 */
73
-	public function getLastLogin();
66
+    /**
67
+     * returns the timestamp of the user's last login or 0 if the user did never
68
+     * login
69
+     *
70
+     * @return int
71
+     * @since 8.0.0
72
+     */
73
+    public function getLastLogin();
74 74
 
75
-	/**
76
-	 * updates the timestamp of the most recent login of this user
77
-	 * @since 8.0.0
78
-	 */
79
-	public function updateLastLoginTimestamp();
75
+    /**
76
+     * updates the timestamp of the most recent login of this user
77
+     * @since 8.0.0
78
+     */
79
+    public function updateLastLoginTimestamp();
80 80
 
81
-	/**
82
-	 * Delete the user
83
-	 *
84
-	 * @return bool
85
-	 * @since 8.0.0
86
-	 */
87
-	public function delete();
81
+    /**
82
+     * Delete the user
83
+     *
84
+     * @return bool
85
+     * @since 8.0.0
86
+     */
87
+    public function delete();
88 88
 
89
-	/**
90
-	 * Set the password of the user
91
-	 *
92
-	 * @param string $password
93
-	 * @param string $recoveryPassword for the encryption app to reset encryption keys
94
-	 * @return bool
95
-	 * @since 8.0.0
96
-	 */
97
-	public function setPassword($password, $recoveryPassword = null);
89
+    /**
90
+     * Set the password of the user
91
+     *
92
+     * @param string $password
93
+     * @param string $recoveryPassword for the encryption app to reset encryption keys
94
+     * @return bool
95
+     * @since 8.0.0
96
+     */
97
+    public function setPassword($password, $recoveryPassword = null);
98 98
 
99
-	/**
100
-	 * get the users home folder to mount
101
-	 *
102
-	 * @return string
103
-	 * @since 8.0.0
104
-	 */
105
-	public function getHome();
99
+    /**
100
+     * get the users home folder to mount
101
+     *
102
+     * @return string
103
+     * @since 8.0.0
104
+     */
105
+    public function getHome();
106 106
 
107
-	/**
108
-	 * Get the name of the backend class the user is connected with
109
-	 *
110
-	 * @return string
111
-	 * @since 8.0.0
112
-	 */
113
-	public function getBackendClassName();
107
+    /**
108
+     * Get the name of the backend class the user is connected with
109
+     *
110
+     * @return string
111
+     * @since 8.0.0
112
+     */
113
+    public function getBackendClassName();
114 114
 
115
-	/**
116
-	 * Get the backend for the current user object
117
-	 * @return ?UserInterface
118
-	 * @since 15.0.0
119
-	 */
120
-	public function getBackend();
115
+    /**
116
+     * Get the backend for the current user object
117
+     * @return ?UserInterface
118
+     * @since 15.0.0
119
+     */
120
+    public function getBackend();
121 121
 
122
-	/**
123
-	 * check if the backend allows the user to change his avatar on Personal page
124
-	 *
125
-	 * @return bool
126
-	 * @since 8.0.0
127
-	 */
128
-	public function canChangeAvatar();
122
+    /**
123
+     * check if the backend allows the user to change his avatar on Personal page
124
+     *
125
+     * @return bool
126
+     * @since 8.0.0
127
+     */
128
+    public function canChangeAvatar();
129 129
 
130
-	/**
131
-	 * check if the backend supports changing passwords
132
-	 *
133
-	 * @return bool
134
-	 * @since 8.0.0
135
-	 */
136
-	public function canChangePassword();
130
+    /**
131
+     * check if the backend supports changing passwords
132
+     *
133
+     * @return bool
134
+     * @since 8.0.0
135
+     */
136
+    public function canChangePassword();
137 137
 
138
-	/**
139
-	 * check if the backend supports changing display names
140
-	 *
141
-	 * @return bool
142
-	 * @since 8.0.0
143
-	 */
144
-	public function canChangeDisplayName();
138
+    /**
139
+     * check if the backend supports changing display names
140
+     *
141
+     * @return bool
142
+     * @since 8.0.0
143
+     */
144
+    public function canChangeDisplayName();
145 145
 
146
-	/**
147
-	 * check if the user is enabled
148
-	 *
149
-	 * @return bool
150
-	 * @since 8.0.0
151
-	 */
152
-	public function isEnabled();
146
+    /**
147
+     * check if the user is enabled
148
+     *
149
+     * @return bool
150
+     * @since 8.0.0
151
+     */
152
+    public function isEnabled();
153 153
 
154
-	/**
155
-	 * set the enabled status for the user
156
-	 *
157
-	 * @param bool $enabled
158
-	 * @since 8.0.0
159
-	 */
160
-	public function setEnabled(bool $enabled = true);
154
+    /**
155
+     * set the enabled status for the user
156
+     *
157
+     * @param bool $enabled
158
+     * @since 8.0.0
159
+     */
160
+    public function setEnabled(bool $enabled = true);
161 161
 
162
-	/**
163
-	 * get the user's email address
164
-	 *
165
-	 * @return string|null
166
-	 * @since 9.0.0
167
-	 */
168
-	public function getEMailAddress();
162
+    /**
163
+     * get the user's email address
164
+     *
165
+     * @return string|null
166
+     * @since 9.0.0
167
+     */
168
+    public function getEMailAddress();
169 169
 
170
-	/**
171
-	 * get the user's system email address
172
-	 *
173
-	 * The system mail address may be read only and may be set from different
174
-	 * sources like LDAP, SAML or simply the admin.
175
-	 *
176
-	 * Use this getter only when the system address is needed. For picking the
177
-	 * proper address to e.g. send a mail to, use getEMailAddress().
178
-	 *
179
-	 * @return string|null
180
-	 * @since 23.0.0
181
-	 */
182
-	public function getSystemEMailAddress(): ?string;
170
+    /**
171
+     * get the user's system email address
172
+     *
173
+     * The system mail address may be read only and may be set from different
174
+     * sources like LDAP, SAML or simply the admin.
175
+     *
176
+     * Use this getter only when the system address is needed. For picking the
177
+     * proper address to e.g. send a mail to, use getEMailAddress().
178
+     *
179
+     * @return string|null
180
+     * @since 23.0.0
181
+     */
182
+    public function getSystemEMailAddress(): ?string;
183 183
 
184
-	/**
185
-	 * get the user's preferred email address
186
-	 *
187
-	 * The primary mail address may be set be the user to specify a different
188
-	 * email address where mails by Nextcloud are sent to. It is not necessarily
189
-	 * set.
190
-	 *
191
-	 * Use this getter only when the primary address is needed. For picking the
192
-	 * proper address to e.g. send a mail to, use getEMailAddress().
193
-	 *
194
-	 * @return string|null
195
-	 * @since 23.0.0
196
-	 */
197
-	public function getPrimaryEMailAddress(): ?string;
184
+    /**
185
+     * get the user's preferred email address
186
+     *
187
+     * The primary mail address may be set be the user to specify a different
188
+     * email address where mails by Nextcloud are sent to. It is not necessarily
189
+     * set.
190
+     *
191
+     * Use this getter only when the primary address is needed. For picking the
192
+     * proper address to e.g. send a mail to, use getEMailAddress().
193
+     *
194
+     * @return string|null
195
+     * @since 23.0.0
196
+     */
197
+    public function getPrimaryEMailAddress(): ?string;
198 198
 
199
-	/**
200
-	 * get the avatar image if it exists
201
-	 *
202
-	 * @param int $size
203
-	 * @return IImage|null
204
-	 * @since 9.0.0
205
-	 */
206
-	public function getAvatarImage($size);
199
+    /**
200
+     * get the avatar image if it exists
201
+     *
202
+     * @param int $size
203
+     * @return IImage|null
204
+     * @since 9.0.0
205
+     */
206
+    public function getAvatarImage($size);
207 207
 
208
-	/**
209
-	 * get the federation cloud id
210
-	 *
211
-	 * @return string
212
-	 * @since 9.0.0
213
-	 */
214
-	public function getCloudId();
208
+    /**
209
+     * get the federation cloud id
210
+     *
211
+     * @return string
212
+     * @since 9.0.0
213
+     */
214
+    public function getCloudId();
215 215
 
216
-	/**
217
-	 * set the email address of the user
218
-	 *
219
-	 * It is an alias to setSystemEMailAddress()
220
-	 *
221
-	 * @param string|null $mailAddress
222
-	 * @return void
223
-	 * @since 9.0.0
224
-	 * @deprecated 23.0.0 use setSystemEMailAddress() or setPrimaryEMailAddress()
225
-	 */
226
-	public function setEMailAddress($mailAddress);
216
+    /**
217
+     * set the email address of the user
218
+     *
219
+     * It is an alias to setSystemEMailAddress()
220
+     *
221
+     * @param string|null $mailAddress
222
+     * @return void
223
+     * @since 9.0.0
224
+     * @deprecated 23.0.0 use setSystemEMailAddress() or setPrimaryEMailAddress()
225
+     */
226
+    public function setEMailAddress($mailAddress);
227 227
 
228
-	/**
229
-	 * Set the system email address of the user
230
-	 *
231
-	 * This is supposed to be used when the email is set from different sources
232
-	 * (i.e. other user backends, admin).
233
-	 *
234
-	 * @since 23.0.0
235
-	 */
236
-	public function setSystemEMailAddress(string $mailAddress): void;
228
+    /**
229
+     * Set the system email address of the user
230
+     *
231
+     * This is supposed to be used when the email is set from different sources
232
+     * (i.e. other user backends, admin).
233
+     *
234
+     * @since 23.0.0
235
+     */
236
+    public function setSystemEMailAddress(string $mailAddress): void;
237 237
 
238
-	/**
239
-	 * Set the primary email address of the user.
240
-	 *
241
-	 * This method should be typically called when the user is changing their
242
-	 * own primary address and is not allowed to change their system email.
243
-	 *
244
-	 * The mail address provided here must be already registered as an
245
-	 * additional mail in the user account and also be verified locally. Also
246
-	 * an empty string is allowed to delete this preference.
247
-	 *
248
-	 * @throws InvalidArgumentException when the provided email address does not
249
-	 *                                  satisfy constraints.
250
-	 *
251
-	 * @since 23.0.0
252
-	 */
253
-	public function setPrimaryEMailAddress(string $mailAddress): void;
238
+    /**
239
+     * Set the primary email address of the user.
240
+     *
241
+     * This method should be typically called when the user is changing their
242
+     * own primary address and is not allowed to change their system email.
243
+     *
244
+     * The mail address provided here must be already registered as an
245
+     * additional mail in the user account and also be verified locally. Also
246
+     * an empty string is allowed to delete this preference.
247
+     *
248
+     * @throws InvalidArgumentException when the provided email address does not
249
+     *                                  satisfy constraints.
250
+     *
251
+     * @since 23.0.0
252
+     */
253
+    public function setPrimaryEMailAddress(string $mailAddress): void;
254 254
 
255
-	/**
256
-	 * get the users' quota in human readable form. If a specific quota is not
257
-	 * set for the user, the default value is returned. If a default setting
258
-	 * was not set otherwise, it is return as 'none', i.e. quota is not limited.
259
-	 *
260
-	 * @return string
261
-	 * @since 9.0.0
262
-	 */
263
-	public function getQuota();
255
+    /**
256
+     * get the users' quota in human readable form. If a specific quota is not
257
+     * set for the user, the default value is returned. If a default setting
258
+     * was not set otherwise, it is return as 'none', i.e. quota is not limited.
259
+     *
260
+     * @return string
261
+     * @since 9.0.0
262
+     */
263
+    public function getQuota();
264 264
 
265
-	/**
266
-	 * set the users' quota
267
-	 *
268
-	 * @param string $quota
269
-	 * @return void
270
-	 * @since 9.0.0
271
-	 */
272
-	public function setQuota($quota);
265
+    /**
266
+     * set the users' quota
267
+     *
268
+     * @param string $quota
269
+     * @return void
270
+     * @since 9.0.0
271
+     */
272
+    public function setQuota($quota);
273 273
 
274
-	/**
275
-	 * Get the user's manager UIDs
276
-	 *
277
-	 * @since 27.0.0
278
-	 * @return string[]
279
-	 */
280
-	public function getManagerUids(): array;
274
+    /**
275
+     * Get the user's manager UIDs
276
+     *
277
+     * @since 27.0.0
278
+     * @return string[]
279
+     */
280
+    public function getManagerUids(): array;
281 281
 
282
-	/**
283
-	 * Set the user's manager UIDs
284
-	 *
285
-	 * @param string[] $uids UIDs of all managers
286
-	 * @return void
287
-	 * @since 27.0.0
288
-	 */
289
-	public function setManagerUids(array $uids): void;
282
+    /**
283
+     * Set the user's manager UIDs
284
+     *
285
+     * @param string[] $uids UIDs of all managers
286
+     * @return void
287
+     * @since 27.0.0
288
+     */
289
+    public function setManagerUids(array $uids): void;
290 290
 }
Please login to merge, or discard this patch.
lib/private/User/User.php 2 patches
Indentation   +550 added lines, -550 removed lines patch added patch discarded remove patch
@@ -63,554 +63,554 @@
 block discarded – undo
63 63
 use function json_encode;
64 64
 
65 65
 class User implements IUser {
66
-	private const CONFIG_KEY_MANAGERS = 'manager';
67
-
68
-	/** @var IAccountManager */
69
-	protected $accountManager;
70
-	/** @var string */
71
-	private $uid;
72
-
73
-	/** @var string|null */
74
-	private $displayName;
75
-
76
-	/** @var UserInterface|null */
77
-	private $backend;
78
-	/** @var EventDispatcherInterface */
79
-	private $legacyDispatcher;
80
-
81
-	/** @var IEventDispatcher */
82
-	private $dispatcher;
83
-
84
-	/** @var bool|null */
85
-	private $enabled;
86
-
87
-	/** @var Emitter|Manager */
88
-	private $emitter;
89
-
90
-	/** @var string */
91
-	private $home;
92
-
93
-	/** @var int|null */
94
-	private $lastLogin;
95
-
96
-	/** @var \OCP\IConfig */
97
-	private $config;
98
-
99
-	/** @var IAvatarManager */
100
-	private $avatarManager;
101
-
102
-	/** @var IURLGenerator */
103
-	private $urlGenerator;
104
-
105
-	public function __construct(string $uid, ?UserInterface $backend, EventDispatcherInterface $dispatcher, $emitter = null, IConfig $config = null, $urlGenerator = null) {
106
-		$this->uid = $uid;
107
-		$this->backend = $backend;
108
-		$this->legacyDispatcher = $dispatcher;
109
-		$this->emitter = $emitter;
110
-		if (is_null($config)) {
111
-			$config = \OC::$server->getConfig();
112
-		}
113
-		$this->config = $config;
114
-		$this->urlGenerator = $urlGenerator;
115
-		if (is_null($this->urlGenerator)) {
116
-			$this->urlGenerator = \OC::$server->getURLGenerator();
117
-		}
118
-		// TODO: inject
119
-		$this->dispatcher = \OC::$server->query(IEventDispatcher::class);
120
-	}
121
-
122
-	/**
123
-	 * get the user id
124
-	 *
125
-	 * @return string
126
-	 */
127
-	public function getUID() {
128
-		return $this->uid;
129
-	}
130
-
131
-	/**
132
-	 * get the display name for the user, if no specific display name is set it will fallback to the user id
133
-	 *
134
-	 * @return string
135
-	 */
136
-	public function getDisplayName() {
137
-		if ($this->displayName === null) {
138
-			$displayName = '';
139
-			if ($this->backend && $this->backend->implementsActions(Backend::GET_DISPLAYNAME)) {
140
-				// get display name and strip whitespace from the beginning and end of it
141
-				$backendDisplayName = $this->backend->getDisplayName($this->uid);
142
-				if (is_string($backendDisplayName)) {
143
-					$displayName = trim($backendDisplayName);
144
-				}
145
-			}
146
-
147
-			if (!empty($displayName)) {
148
-				$this->displayName = $displayName;
149
-			} else {
150
-				$this->displayName = $this->uid;
151
-			}
152
-		}
153
-		return $this->displayName;
154
-	}
155
-
156
-	/**
157
-	 * set the displayname for the user
158
-	 *
159
-	 * @param string $displayName
160
-	 * @return bool
161
-	 *
162
-	 * @since 25.0.0 Throw InvalidArgumentException
163
-	 * @throws \InvalidArgumentException
164
-	 */
165
-	public function setDisplayName($displayName) {
166
-		$displayName = trim($displayName);
167
-		$oldDisplayName = $this->getDisplayName();
168
-		if ($this->backend->implementsActions(Backend::SET_DISPLAYNAME) && !empty($displayName) && $displayName !== $oldDisplayName) {
169
-			/** @var ISetDisplayNameBackend $backend */
170
-			$backend = $this->backend;
171
-			$result = $backend->setDisplayName($this->uid, $displayName);
172
-			if ($result) {
173
-				$this->displayName = $displayName;
174
-				$this->triggerChange('displayName', $displayName, $oldDisplayName);
175
-			}
176
-			return $result !== false;
177
-		}
178
-		return false;
179
-	}
180
-
181
-	/**
182
-	 * @inheritDoc
183
-	 */
184
-	public function setEMailAddress($mailAddress) {
185
-		$this->setSystemEMailAddress($mailAddress);
186
-	}
187
-
188
-	/**
189
-	 * @inheritDoc
190
-	 */
191
-	public function setSystemEMailAddress(string $mailAddress): void {
192
-		$oldMailAddress = $this->getSystemEMailAddress();
193
-
194
-		if ($mailAddress === '') {
195
-			$this->config->deleteUserValue($this->uid, 'settings', 'email');
196
-		} else {
197
-			$this->config->setUserValue($this->uid, 'settings', 'email', $mailAddress);
198
-		}
199
-
200
-		$primaryAddress = $this->getPrimaryEMailAddress();
201
-		if ($primaryAddress === $mailAddress) {
202
-			// on match no dedicated primary settings is necessary
203
-			$this->setPrimaryEMailAddress('');
204
-		}
205
-
206
-		if ($oldMailAddress !== strtolower($mailAddress)) {
207
-			$this->triggerChange('eMailAddress', $mailAddress, $oldMailAddress);
208
-		}
209
-	}
210
-
211
-	/**
212
-	 * @inheritDoc
213
-	 */
214
-	public function setPrimaryEMailAddress(string $mailAddress): void {
215
-		if ($mailAddress === '') {
216
-			$this->config->deleteUserValue($this->uid, 'settings', 'primary_email');
217
-			return;
218
-		}
219
-
220
-		$this->ensureAccountManager();
221
-		$account = $this->accountManager->getAccount($this);
222
-		$property = $account->getPropertyCollection(IAccountManager::COLLECTION_EMAIL)
223
-			->getPropertyByValue($mailAddress);
224
-
225
-		if ($property === null || $property->getLocallyVerified() !== IAccountManager::VERIFIED) {
226
-			throw new InvalidArgumentException('Only verified emails can be set as primary');
227
-		}
228
-		$this->config->setUserValue($this->uid, 'settings', 'primary_email', $mailAddress);
229
-	}
230
-
231
-	private function ensureAccountManager() {
232
-		if (!$this->accountManager instanceof IAccountManager) {
233
-			$this->accountManager = \OC::$server->get(IAccountManager::class);
234
-		}
235
-	}
236
-
237
-	/**
238
-	 * returns the timestamp of the user's last login or 0 if the user did never
239
-	 * login
240
-	 *
241
-	 * @return int
242
-	 */
243
-	public function getLastLogin() {
244
-		if ($this->lastLogin === null) {
245
-			$this->lastLogin = (int) $this->config->getUserValue($this->uid, 'login', 'lastLogin', 0);
246
-		}
247
-		return (int) $this->lastLogin;
248
-	}
249
-
250
-	/**
251
-	 * updates the timestamp of the most recent login of this user
252
-	 */
253
-	public function updateLastLoginTimestamp() {
254
-		$previousLogin = $this->getLastLogin();
255
-		$now = time();
256
-		$firstTimeLogin = $previousLogin === 0;
257
-
258
-		if ($now - $previousLogin > 60) {
259
-			$this->lastLogin = time();
260
-			$this->config->setUserValue(
261
-				$this->uid, 'login', 'lastLogin', (string)$this->lastLogin);
262
-		}
263
-
264
-		return $firstTimeLogin;
265
-	}
266
-
267
-	/**
268
-	 * Delete the user
269
-	 *
270
-	 * @return bool
271
-	 */
272
-	public function delete() {
273
-		/** @deprecated 21.0.0 use BeforeUserDeletedEvent event with the IEventDispatcher instead */
274
-		$this->legacyDispatcher->dispatch(IUser::class . '::preDelete', new GenericEvent($this));
275
-		if ($this->emitter) {
276
-			/** @deprecated 21.0.0 use BeforeUserDeletedEvent event with the IEventDispatcher instead */
277
-			$this->emitter->emit('\OC\User', 'preDelete', [$this]);
278
-		}
279
-		$this->dispatcher->dispatchTyped(new BeforeUserDeletedEvent($this));
280
-		$result = $this->backend->deleteUser($this->uid);
281
-		if ($result) {
282
-			// FIXME: Feels like an hack - suggestions?
283
-
284
-			$groupManager = \OC::$server->getGroupManager();
285
-			// We have to delete the user from all groups
286
-			foreach ($groupManager->getUserGroupIds($this) as $groupId) {
287
-				$group = $groupManager->get($groupId);
288
-				if ($group) {
289
-					$this->dispatcher->dispatchTyped(new BeforeUserRemovedEvent($group, $this));
290
-					$group->removeUser($this);
291
-					$this->dispatcher->dispatchTyped(new UserRemovedEvent($group, $this));
292
-				}
293
-			}
294
-			// Delete the user's keys in preferences
295
-			\OC::$server->getConfig()->deleteAllUserValues($this->uid);
296
-
297
-			\OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->uid);
298
-			\OC::$server->getCommentsManager()->deleteReadMarksFromUser($this);
299
-
300
-			/** @var AvatarManager $avatarManager */
301
-			$avatarManager = \OC::$server->query(AvatarManager::class);
302
-			$avatarManager->deleteUserAvatar($this->uid);
303
-
304
-			$notification = \OC::$server->getNotificationManager()->createNotification();
305
-			$notification->setUser($this->uid);
306
-			\OC::$server->getNotificationManager()->markProcessed($notification);
307
-
308
-			/** @var AccountManager $accountManager */
309
-			$accountManager = \OC::$server->query(AccountManager::class);
310
-			$accountManager->deleteUser($this);
311
-
312
-			/** @deprecated 21.0.0 use UserDeletedEvent event with the IEventDispatcher instead */
313
-			$this->legacyDispatcher->dispatch(IUser::class . '::postDelete', new GenericEvent($this));
314
-			if ($this->emitter) {
315
-				/** @deprecated 21.0.0 use UserDeletedEvent event with the IEventDispatcher instead */
316
-				$this->emitter->emit('\OC\User', 'postDelete', [$this]);
317
-			}
318
-			$this->dispatcher->dispatchTyped(new UserDeletedEvent($this));
319
-		}
320
-		return !($result === false);
321
-	}
322
-
323
-	/**
324
-	 * Set the password of the user
325
-	 *
326
-	 * @param string $password
327
-	 * @param string $recoveryPassword for the encryption app to reset encryption keys
328
-	 * @return bool
329
-	 */
330
-	public function setPassword($password, $recoveryPassword = null) {
331
-		$this->legacyDispatcher->dispatch(IUser::class . '::preSetPassword', new GenericEvent($this, [
332
-			'password' => $password,
333
-			'recoveryPassword' => $recoveryPassword,
334
-		]));
335
-		if ($this->emitter) {
336
-			$this->emitter->emit('\OC\User', 'preSetPassword', [$this, $password, $recoveryPassword]);
337
-		}
338
-		if ($this->backend->implementsActions(Backend::SET_PASSWORD)) {
339
-			/** @var ISetPasswordBackend $backend */
340
-			$backend = $this->backend;
341
-			$result = $backend->setPassword($this->uid, $password);
342
-
343
-			if ($result !== false) {
344
-				$this->legacyDispatcher->dispatch(IUser::class . '::postSetPassword', new GenericEvent($this, [
345
-					'password' => $password,
346
-					'recoveryPassword' => $recoveryPassword,
347
-				]));
348
-				if ($this->emitter) {
349
-					$this->emitter->emit('\OC\User', 'postSetPassword', [$this, $password, $recoveryPassword]);
350
-				}
351
-			}
352
-
353
-			return !($result === false);
354
-		} else {
355
-			return false;
356
-		}
357
-	}
358
-
359
-	/**
360
-	 * get the users home folder to mount
361
-	 *
362
-	 * @return string
363
-	 */
364
-	public function getHome() {
365
-		if (!$this->home) {
366
-			/** @psalm-suppress UndefinedInterfaceMethod Once we get rid of the legacy implementsActions, psalm won't complain anymore */
367
-			if (($this->backend instanceof IGetHomeBackend || $this->backend->implementsActions(Backend::GET_HOME)) && $home = $this->backend->getHome($this->uid)) {
368
-				$this->home = $home;
369
-			} elseif ($this->config) {
370
-				$this->home = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $this->uid;
371
-			} else {
372
-				$this->home = \OC::$SERVERROOT . '/data/' . $this->uid;
373
-			}
374
-		}
375
-		return $this->home;
376
-	}
377
-
378
-	/**
379
-	 * Get the name of the backend class the user is connected with
380
-	 *
381
-	 * @return string
382
-	 */
383
-	public function getBackendClassName() {
384
-		if ($this->backend instanceof IUserBackend) {
385
-			return $this->backend->getBackendName();
386
-		}
387
-		return get_class($this->backend);
388
-	}
389
-
390
-	public function getBackend(): ?UserInterface {
391
-		return $this->backend;
392
-	}
393
-
394
-	/**
395
-	 * Check if the backend allows the user to change his avatar on Personal page
396
-	 *
397
-	 * @return bool
398
-	 */
399
-	public function canChangeAvatar() {
400
-		if ($this->backend instanceof IProvideAvatarBackend || $this->backend->implementsActions(Backend::PROVIDE_AVATAR)) {
401
-			/** @var IProvideAvatarBackend $backend */
402
-			$backend = $this->backend;
403
-			return $backend->canChangeAvatar($this->uid);
404
-		}
405
-		return true;
406
-	}
407
-
408
-	/**
409
-	 * check if the backend supports changing passwords
410
-	 *
411
-	 * @return bool
412
-	 */
413
-	public function canChangePassword() {
414
-		return $this->backend->implementsActions(Backend::SET_PASSWORD);
415
-	}
416
-
417
-	/**
418
-	 * check if the backend supports changing display names
419
-	 *
420
-	 * @return bool
421
-	 */
422
-	public function canChangeDisplayName() {
423
-		if (!$this->config->getSystemValueBool('allow_user_to_change_display_name', true)) {
424
-			return false;
425
-		}
426
-		return $this->backend->implementsActions(Backend::SET_DISPLAYNAME);
427
-	}
428
-
429
-	/**
430
-	 * check if the user is enabled
431
-	 *
432
-	 * @return bool
433
-	 */
434
-	public function isEnabled() {
435
-		if ($this->enabled === null) {
436
-			$enabled = $this->config->getUserValue($this->uid, 'core', 'enabled', 'true');
437
-			$this->enabled = $enabled === 'true';
438
-		}
439
-		return (bool) $this->enabled;
440
-	}
441
-
442
-	/**
443
-	 * set the enabled status for the user
444
-	 *
445
-	 * @param bool $enabled
446
-	 */
447
-	public function setEnabled(bool $enabled = true) {
448
-		$oldStatus = $this->isEnabled();
449
-		$this->enabled = $enabled;
450
-		if ($oldStatus !== $this->enabled) {
451
-			// TODO: First change the value, then trigger the event as done for all other properties.
452
-			$this->triggerChange('enabled', $enabled, $oldStatus);
453
-			$this->config->setUserValue($this->uid, 'core', 'enabled', $enabled ? 'true' : 'false');
454
-		}
455
-	}
456
-
457
-	/**
458
-	 * get the users email address
459
-	 *
460
-	 * @return string|null
461
-	 * @since 9.0.0
462
-	 */
463
-	public function getEMailAddress() {
464
-		return $this->getPrimaryEMailAddress() ?? $this->getSystemEMailAddress();
465
-	}
466
-
467
-	/**
468
-	 * @inheritDoc
469
-	 */
470
-	public function getSystemEMailAddress(): ?string {
471
-		return $this->config->getUserValue($this->uid, 'settings', 'email', null);
472
-	}
473
-
474
-	/**
475
-	 * @inheritDoc
476
-	 */
477
-	public function getPrimaryEMailAddress(): ?string {
478
-		return $this->config->getUserValue($this->uid, 'settings', 'primary_email', null);
479
-	}
480
-
481
-	/**
482
-	 * get the users' quota
483
-	 *
484
-	 * @return string
485
-	 * @since 9.0.0
486
-	 */
487
-	public function getQuota() {
488
-		// allow apps to modify the user quota by hooking into the event
489
-		$event = new GetQuotaEvent($this);
490
-		$this->dispatcher->dispatchTyped($event);
491
-		$overwriteQuota = $event->getQuota();
492
-		if ($overwriteQuota) {
493
-			$quota = $overwriteQuota;
494
-		} else {
495
-			$quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default');
496
-		}
497
-		if ($quota === 'default') {
498
-			$quota = $this->config->getAppValue('files', 'default_quota', 'none');
499
-
500
-			// if unlimited quota is not allowed => avoid getting 'unlimited' as default_quota fallback value
501
-			// use the first preset instead
502
-			$allowUnlimitedQuota = $this->config->getAppValue('files', 'allow_unlimited_quota', '1') === '1';
503
-			if (!$allowUnlimitedQuota) {
504
-				$presets = $this->config->getAppValue('files', 'quota_preset', '1 GB, 5 GB, 10 GB');
505
-				$presets = array_filter(array_map('trim', explode(',', $presets)));
506
-				$quotaPreset = array_values(array_diff($presets, ['default', 'none']));
507
-				if (count($quotaPreset) > 0) {
508
-					$quota = $this->config->getAppValue('files', 'default_quota', $quotaPreset[0]);
509
-				}
510
-			}
511
-		}
512
-		return $quota;
513
-	}
514
-
515
-	/**
516
-	 * set the users' quota
517
-	 *
518
-	 * @param string $quota
519
-	 * @return void
520
-	 * @throws InvalidArgumentException
521
-	 * @since 9.0.0
522
-	 */
523
-	public function setQuota($quota) {
524
-		$oldQuota = $this->config->getUserValue($this->uid, 'files', 'quota', '');
525
-		if ($quota !== 'none' and $quota !== 'default') {
526
-			$bytesQuota = OC_Helper::computerFileSize($quota);
527
-			if ($bytesQuota === false) {
528
-				throw new InvalidArgumentException('Failed to set quota to invalid value '.$quota);
529
-			}
530
-			$quota = OC_Helper::humanFileSize($bytesQuota);
531
-		}
532
-		if ($quota !== $oldQuota) {
533
-			$this->config->setUserValue($this->uid, 'files', 'quota', $quota);
534
-			$this->triggerChange('quota', $quota, $oldQuota);
535
-		}
536
-		\OC_Helper::clearStorageInfo('/' . $this->uid . '/files');
537
-	}
538
-
539
-	public function getManagerUids(): array {
540
-		$encodedUids = $this->config->getUserValue(
541
-			$this->uid,
542
-			'settings',
543
-			self::CONFIG_KEY_MANAGERS,
544
-			'[]'
545
-		);
546
-		return json_decode($encodedUids, false, 512, JSON_THROW_ON_ERROR);
547
-	}
548
-
549
-	public function setManagerUids(array $uids): void {
550
-		$oldUids = $this->getManagerUids();
551
-		$this->config->setUserValue(
552
-			$this->uid,
553
-			'settings',
554
-			self::CONFIG_KEY_MANAGERS,
555
-			json_encode($uids, JSON_THROW_ON_ERROR)
556
-		);
557
-		$this->triggerChange('managers', $uids, $oldUids);
558
-	}
559
-
560
-	/**
561
-	 * get the avatar image if it exists
562
-	 *
563
-	 * @param int $size
564
-	 * @return IImage|null
565
-	 * @since 9.0.0
566
-	 */
567
-	public function getAvatarImage($size) {
568
-		// delay the initialization
569
-		if (is_null($this->avatarManager)) {
570
-			$this->avatarManager = \OC::$server->getAvatarManager();
571
-		}
572
-
573
-		$avatar = $this->avatarManager->getAvatar($this->uid);
574
-		$image = $avatar->get(-1);
575
-		if ($image) {
576
-			return $image;
577
-		}
578
-
579
-		return null;
580
-	}
581
-
582
-	/**
583
-	 * get the federation cloud id
584
-	 *
585
-	 * @return string
586
-	 * @since 9.0.0
587
-	 */
588
-	public function getCloudId() {
589
-		$uid = $this->getUID();
590
-		$server = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/');
591
-		if (substr($server, -10) === '/index.php') {
592
-			$server = substr($server, 0, -10);
593
-		}
594
-		$server = $this->removeProtocolFromUrl($server);
595
-		return $uid . '@' . $server;
596
-	}
597
-
598
-	private function removeProtocolFromUrl(string $url): string {
599
-		if (strpos($url, 'https://') === 0) {
600
-			return substr($url, strlen('https://'));
601
-		}
602
-
603
-		return $url;
604
-	}
605
-
606
-	public function triggerChange($feature, $value = null, $oldValue = null) {
607
-		$this->legacyDispatcher->dispatch(IUser::class . '::changeUser', new GenericEvent($this, [
608
-			'feature' => $feature,
609
-			'value' => $value,
610
-			'oldValue' => $oldValue,
611
-		]));
612
-		if ($this->emitter) {
613
-			$this->emitter->emit('\OC\User', 'changeUser', [$this, $feature, $value, $oldValue]);
614
-		}
615
-	}
66
+    private const CONFIG_KEY_MANAGERS = 'manager';
67
+
68
+    /** @var IAccountManager */
69
+    protected $accountManager;
70
+    /** @var string */
71
+    private $uid;
72
+
73
+    /** @var string|null */
74
+    private $displayName;
75
+
76
+    /** @var UserInterface|null */
77
+    private $backend;
78
+    /** @var EventDispatcherInterface */
79
+    private $legacyDispatcher;
80
+
81
+    /** @var IEventDispatcher */
82
+    private $dispatcher;
83
+
84
+    /** @var bool|null */
85
+    private $enabled;
86
+
87
+    /** @var Emitter|Manager */
88
+    private $emitter;
89
+
90
+    /** @var string */
91
+    private $home;
92
+
93
+    /** @var int|null */
94
+    private $lastLogin;
95
+
96
+    /** @var \OCP\IConfig */
97
+    private $config;
98
+
99
+    /** @var IAvatarManager */
100
+    private $avatarManager;
101
+
102
+    /** @var IURLGenerator */
103
+    private $urlGenerator;
104
+
105
+    public function __construct(string $uid, ?UserInterface $backend, EventDispatcherInterface $dispatcher, $emitter = null, IConfig $config = null, $urlGenerator = null) {
106
+        $this->uid = $uid;
107
+        $this->backend = $backend;
108
+        $this->legacyDispatcher = $dispatcher;
109
+        $this->emitter = $emitter;
110
+        if (is_null($config)) {
111
+            $config = \OC::$server->getConfig();
112
+        }
113
+        $this->config = $config;
114
+        $this->urlGenerator = $urlGenerator;
115
+        if (is_null($this->urlGenerator)) {
116
+            $this->urlGenerator = \OC::$server->getURLGenerator();
117
+        }
118
+        // TODO: inject
119
+        $this->dispatcher = \OC::$server->query(IEventDispatcher::class);
120
+    }
121
+
122
+    /**
123
+     * get the user id
124
+     *
125
+     * @return string
126
+     */
127
+    public function getUID() {
128
+        return $this->uid;
129
+    }
130
+
131
+    /**
132
+     * get the display name for the user, if no specific display name is set it will fallback to the user id
133
+     *
134
+     * @return string
135
+     */
136
+    public function getDisplayName() {
137
+        if ($this->displayName === null) {
138
+            $displayName = '';
139
+            if ($this->backend && $this->backend->implementsActions(Backend::GET_DISPLAYNAME)) {
140
+                // get display name and strip whitespace from the beginning and end of it
141
+                $backendDisplayName = $this->backend->getDisplayName($this->uid);
142
+                if (is_string($backendDisplayName)) {
143
+                    $displayName = trim($backendDisplayName);
144
+                }
145
+            }
146
+
147
+            if (!empty($displayName)) {
148
+                $this->displayName = $displayName;
149
+            } else {
150
+                $this->displayName = $this->uid;
151
+            }
152
+        }
153
+        return $this->displayName;
154
+    }
155
+
156
+    /**
157
+     * set the displayname for the user
158
+     *
159
+     * @param string $displayName
160
+     * @return bool
161
+     *
162
+     * @since 25.0.0 Throw InvalidArgumentException
163
+     * @throws \InvalidArgumentException
164
+     */
165
+    public function setDisplayName($displayName) {
166
+        $displayName = trim($displayName);
167
+        $oldDisplayName = $this->getDisplayName();
168
+        if ($this->backend->implementsActions(Backend::SET_DISPLAYNAME) && !empty($displayName) && $displayName !== $oldDisplayName) {
169
+            /** @var ISetDisplayNameBackend $backend */
170
+            $backend = $this->backend;
171
+            $result = $backend->setDisplayName($this->uid, $displayName);
172
+            if ($result) {
173
+                $this->displayName = $displayName;
174
+                $this->triggerChange('displayName', $displayName, $oldDisplayName);
175
+            }
176
+            return $result !== false;
177
+        }
178
+        return false;
179
+    }
180
+
181
+    /**
182
+     * @inheritDoc
183
+     */
184
+    public function setEMailAddress($mailAddress) {
185
+        $this->setSystemEMailAddress($mailAddress);
186
+    }
187
+
188
+    /**
189
+     * @inheritDoc
190
+     */
191
+    public function setSystemEMailAddress(string $mailAddress): void {
192
+        $oldMailAddress = $this->getSystemEMailAddress();
193
+
194
+        if ($mailAddress === '') {
195
+            $this->config->deleteUserValue($this->uid, 'settings', 'email');
196
+        } else {
197
+            $this->config->setUserValue($this->uid, 'settings', 'email', $mailAddress);
198
+        }
199
+
200
+        $primaryAddress = $this->getPrimaryEMailAddress();
201
+        if ($primaryAddress === $mailAddress) {
202
+            // on match no dedicated primary settings is necessary
203
+            $this->setPrimaryEMailAddress('');
204
+        }
205
+
206
+        if ($oldMailAddress !== strtolower($mailAddress)) {
207
+            $this->triggerChange('eMailAddress', $mailAddress, $oldMailAddress);
208
+        }
209
+    }
210
+
211
+    /**
212
+     * @inheritDoc
213
+     */
214
+    public function setPrimaryEMailAddress(string $mailAddress): void {
215
+        if ($mailAddress === '') {
216
+            $this->config->deleteUserValue($this->uid, 'settings', 'primary_email');
217
+            return;
218
+        }
219
+
220
+        $this->ensureAccountManager();
221
+        $account = $this->accountManager->getAccount($this);
222
+        $property = $account->getPropertyCollection(IAccountManager::COLLECTION_EMAIL)
223
+            ->getPropertyByValue($mailAddress);
224
+
225
+        if ($property === null || $property->getLocallyVerified() !== IAccountManager::VERIFIED) {
226
+            throw new InvalidArgumentException('Only verified emails can be set as primary');
227
+        }
228
+        $this->config->setUserValue($this->uid, 'settings', 'primary_email', $mailAddress);
229
+    }
230
+
231
+    private function ensureAccountManager() {
232
+        if (!$this->accountManager instanceof IAccountManager) {
233
+            $this->accountManager = \OC::$server->get(IAccountManager::class);
234
+        }
235
+    }
236
+
237
+    /**
238
+     * returns the timestamp of the user's last login or 0 if the user did never
239
+     * login
240
+     *
241
+     * @return int
242
+     */
243
+    public function getLastLogin() {
244
+        if ($this->lastLogin === null) {
245
+            $this->lastLogin = (int) $this->config->getUserValue($this->uid, 'login', 'lastLogin', 0);
246
+        }
247
+        return (int) $this->lastLogin;
248
+    }
249
+
250
+    /**
251
+     * updates the timestamp of the most recent login of this user
252
+     */
253
+    public function updateLastLoginTimestamp() {
254
+        $previousLogin = $this->getLastLogin();
255
+        $now = time();
256
+        $firstTimeLogin = $previousLogin === 0;
257
+
258
+        if ($now - $previousLogin > 60) {
259
+            $this->lastLogin = time();
260
+            $this->config->setUserValue(
261
+                $this->uid, 'login', 'lastLogin', (string)$this->lastLogin);
262
+        }
263
+
264
+        return $firstTimeLogin;
265
+    }
266
+
267
+    /**
268
+     * Delete the user
269
+     *
270
+     * @return bool
271
+     */
272
+    public function delete() {
273
+        /** @deprecated 21.0.0 use BeforeUserDeletedEvent event with the IEventDispatcher instead */
274
+        $this->legacyDispatcher->dispatch(IUser::class . '::preDelete', new GenericEvent($this));
275
+        if ($this->emitter) {
276
+            /** @deprecated 21.0.0 use BeforeUserDeletedEvent event with the IEventDispatcher instead */
277
+            $this->emitter->emit('\OC\User', 'preDelete', [$this]);
278
+        }
279
+        $this->dispatcher->dispatchTyped(new BeforeUserDeletedEvent($this));
280
+        $result = $this->backend->deleteUser($this->uid);
281
+        if ($result) {
282
+            // FIXME: Feels like an hack - suggestions?
283
+
284
+            $groupManager = \OC::$server->getGroupManager();
285
+            // We have to delete the user from all groups
286
+            foreach ($groupManager->getUserGroupIds($this) as $groupId) {
287
+                $group = $groupManager->get($groupId);
288
+                if ($group) {
289
+                    $this->dispatcher->dispatchTyped(new BeforeUserRemovedEvent($group, $this));
290
+                    $group->removeUser($this);
291
+                    $this->dispatcher->dispatchTyped(new UserRemovedEvent($group, $this));
292
+                }
293
+            }
294
+            // Delete the user's keys in preferences
295
+            \OC::$server->getConfig()->deleteAllUserValues($this->uid);
296
+
297
+            \OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->uid);
298
+            \OC::$server->getCommentsManager()->deleteReadMarksFromUser($this);
299
+
300
+            /** @var AvatarManager $avatarManager */
301
+            $avatarManager = \OC::$server->query(AvatarManager::class);
302
+            $avatarManager->deleteUserAvatar($this->uid);
303
+
304
+            $notification = \OC::$server->getNotificationManager()->createNotification();
305
+            $notification->setUser($this->uid);
306
+            \OC::$server->getNotificationManager()->markProcessed($notification);
307
+
308
+            /** @var AccountManager $accountManager */
309
+            $accountManager = \OC::$server->query(AccountManager::class);
310
+            $accountManager->deleteUser($this);
311
+
312
+            /** @deprecated 21.0.0 use UserDeletedEvent event with the IEventDispatcher instead */
313
+            $this->legacyDispatcher->dispatch(IUser::class . '::postDelete', new GenericEvent($this));
314
+            if ($this->emitter) {
315
+                /** @deprecated 21.0.0 use UserDeletedEvent event with the IEventDispatcher instead */
316
+                $this->emitter->emit('\OC\User', 'postDelete', [$this]);
317
+            }
318
+            $this->dispatcher->dispatchTyped(new UserDeletedEvent($this));
319
+        }
320
+        return !($result === false);
321
+    }
322
+
323
+    /**
324
+     * Set the password of the user
325
+     *
326
+     * @param string $password
327
+     * @param string $recoveryPassword for the encryption app to reset encryption keys
328
+     * @return bool
329
+     */
330
+    public function setPassword($password, $recoveryPassword = null) {
331
+        $this->legacyDispatcher->dispatch(IUser::class . '::preSetPassword', new GenericEvent($this, [
332
+            'password' => $password,
333
+            'recoveryPassword' => $recoveryPassword,
334
+        ]));
335
+        if ($this->emitter) {
336
+            $this->emitter->emit('\OC\User', 'preSetPassword', [$this, $password, $recoveryPassword]);
337
+        }
338
+        if ($this->backend->implementsActions(Backend::SET_PASSWORD)) {
339
+            /** @var ISetPasswordBackend $backend */
340
+            $backend = $this->backend;
341
+            $result = $backend->setPassword($this->uid, $password);
342
+
343
+            if ($result !== false) {
344
+                $this->legacyDispatcher->dispatch(IUser::class . '::postSetPassword', new GenericEvent($this, [
345
+                    'password' => $password,
346
+                    'recoveryPassword' => $recoveryPassword,
347
+                ]));
348
+                if ($this->emitter) {
349
+                    $this->emitter->emit('\OC\User', 'postSetPassword', [$this, $password, $recoveryPassword]);
350
+                }
351
+            }
352
+
353
+            return !($result === false);
354
+        } else {
355
+            return false;
356
+        }
357
+    }
358
+
359
+    /**
360
+     * get the users home folder to mount
361
+     *
362
+     * @return string
363
+     */
364
+    public function getHome() {
365
+        if (!$this->home) {
366
+            /** @psalm-suppress UndefinedInterfaceMethod Once we get rid of the legacy implementsActions, psalm won't complain anymore */
367
+            if (($this->backend instanceof IGetHomeBackend || $this->backend->implementsActions(Backend::GET_HOME)) && $home = $this->backend->getHome($this->uid)) {
368
+                $this->home = $home;
369
+            } elseif ($this->config) {
370
+                $this->home = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $this->uid;
371
+            } else {
372
+                $this->home = \OC::$SERVERROOT . '/data/' . $this->uid;
373
+            }
374
+        }
375
+        return $this->home;
376
+    }
377
+
378
+    /**
379
+     * Get the name of the backend class the user is connected with
380
+     *
381
+     * @return string
382
+     */
383
+    public function getBackendClassName() {
384
+        if ($this->backend instanceof IUserBackend) {
385
+            return $this->backend->getBackendName();
386
+        }
387
+        return get_class($this->backend);
388
+    }
389
+
390
+    public function getBackend(): ?UserInterface {
391
+        return $this->backend;
392
+    }
393
+
394
+    /**
395
+     * Check if the backend allows the user to change his avatar on Personal page
396
+     *
397
+     * @return bool
398
+     */
399
+    public function canChangeAvatar() {
400
+        if ($this->backend instanceof IProvideAvatarBackend || $this->backend->implementsActions(Backend::PROVIDE_AVATAR)) {
401
+            /** @var IProvideAvatarBackend $backend */
402
+            $backend = $this->backend;
403
+            return $backend->canChangeAvatar($this->uid);
404
+        }
405
+        return true;
406
+    }
407
+
408
+    /**
409
+     * check if the backend supports changing passwords
410
+     *
411
+     * @return bool
412
+     */
413
+    public function canChangePassword() {
414
+        return $this->backend->implementsActions(Backend::SET_PASSWORD);
415
+    }
416
+
417
+    /**
418
+     * check if the backend supports changing display names
419
+     *
420
+     * @return bool
421
+     */
422
+    public function canChangeDisplayName() {
423
+        if (!$this->config->getSystemValueBool('allow_user_to_change_display_name', true)) {
424
+            return false;
425
+        }
426
+        return $this->backend->implementsActions(Backend::SET_DISPLAYNAME);
427
+    }
428
+
429
+    /**
430
+     * check if the user is enabled
431
+     *
432
+     * @return bool
433
+     */
434
+    public function isEnabled() {
435
+        if ($this->enabled === null) {
436
+            $enabled = $this->config->getUserValue($this->uid, 'core', 'enabled', 'true');
437
+            $this->enabled = $enabled === 'true';
438
+        }
439
+        return (bool) $this->enabled;
440
+    }
441
+
442
+    /**
443
+     * set the enabled status for the user
444
+     *
445
+     * @param bool $enabled
446
+     */
447
+    public function setEnabled(bool $enabled = true) {
448
+        $oldStatus = $this->isEnabled();
449
+        $this->enabled = $enabled;
450
+        if ($oldStatus !== $this->enabled) {
451
+            // TODO: First change the value, then trigger the event as done for all other properties.
452
+            $this->triggerChange('enabled', $enabled, $oldStatus);
453
+            $this->config->setUserValue($this->uid, 'core', 'enabled', $enabled ? 'true' : 'false');
454
+        }
455
+    }
456
+
457
+    /**
458
+     * get the users email address
459
+     *
460
+     * @return string|null
461
+     * @since 9.0.0
462
+     */
463
+    public function getEMailAddress() {
464
+        return $this->getPrimaryEMailAddress() ?? $this->getSystemEMailAddress();
465
+    }
466
+
467
+    /**
468
+     * @inheritDoc
469
+     */
470
+    public function getSystemEMailAddress(): ?string {
471
+        return $this->config->getUserValue($this->uid, 'settings', 'email', null);
472
+    }
473
+
474
+    /**
475
+     * @inheritDoc
476
+     */
477
+    public function getPrimaryEMailAddress(): ?string {
478
+        return $this->config->getUserValue($this->uid, 'settings', 'primary_email', null);
479
+    }
480
+
481
+    /**
482
+     * get the users' quota
483
+     *
484
+     * @return string
485
+     * @since 9.0.0
486
+     */
487
+    public function getQuota() {
488
+        // allow apps to modify the user quota by hooking into the event
489
+        $event = new GetQuotaEvent($this);
490
+        $this->dispatcher->dispatchTyped($event);
491
+        $overwriteQuota = $event->getQuota();
492
+        if ($overwriteQuota) {
493
+            $quota = $overwriteQuota;
494
+        } else {
495
+            $quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default');
496
+        }
497
+        if ($quota === 'default') {
498
+            $quota = $this->config->getAppValue('files', 'default_quota', 'none');
499
+
500
+            // if unlimited quota is not allowed => avoid getting 'unlimited' as default_quota fallback value
501
+            // use the first preset instead
502
+            $allowUnlimitedQuota = $this->config->getAppValue('files', 'allow_unlimited_quota', '1') === '1';
503
+            if (!$allowUnlimitedQuota) {
504
+                $presets = $this->config->getAppValue('files', 'quota_preset', '1 GB, 5 GB, 10 GB');
505
+                $presets = array_filter(array_map('trim', explode(',', $presets)));
506
+                $quotaPreset = array_values(array_diff($presets, ['default', 'none']));
507
+                if (count($quotaPreset) > 0) {
508
+                    $quota = $this->config->getAppValue('files', 'default_quota', $quotaPreset[0]);
509
+                }
510
+            }
511
+        }
512
+        return $quota;
513
+    }
514
+
515
+    /**
516
+     * set the users' quota
517
+     *
518
+     * @param string $quota
519
+     * @return void
520
+     * @throws InvalidArgumentException
521
+     * @since 9.0.0
522
+     */
523
+    public function setQuota($quota) {
524
+        $oldQuota = $this->config->getUserValue($this->uid, 'files', 'quota', '');
525
+        if ($quota !== 'none' and $quota !== 'default') {
526
+            $bytesQuota = OC_Helper::computerFileSize($quota);
527
+            if ($bytesQuota === false) {
528
+                throw new InvalidArgumentException('Failed to set quota to invalid value '.$quota);
529
+            }
530
+            $quota = OC_Helper::humanFileSize($bytesQuota);
531
+        }
532
+        if ($quota !== $oldQuota) {
533
+            $this->config->setUserValue($this->uid, 'files', 'quota', $quota);
534
+            $this->triggerChange('quota', $quota, $oldQuota);
535
+        }
536
+        \OC_Helper::clearStorageInfo('/' . $this->uid . '/files');
537
+    }
538
+
539
+    public function getManagerUids(): array {
540
+        $encodedUids = $this->config->getUserValue(
541
+            $this->uid,
542
+            'settings',
543
+            self::CONFIG_KEY_MANAGERS,
544
+            '[]'
545
+        );
546
+        return json_decode($encodedUids, false, 512, JSON_THROW_ON_ERROR);
547
+    }
548
+
549
+    public function setManagerUids(array $uids): void {
550
+        $oldUids = $this->getManagerUids();
551
+        $this->config->setUserValue(
552
+            $this->uid,
553
+            'settings',
554
+            self::CONFIG_KEY_MANAGERS,
555
+            json_encode($uids, JSON_THROW_ON_ERROR)
556
+        );
557
+        $this->triggerChange('managers', $uids, $oldUids);
558
+    }
559
+
560
+    /**
561
+     * get the avatar image if it exists
562
+     *
563
+     * @param int $size
564
+     * @return IImage|null
565
+     * @since 9.0.0
566
+     */
567
+    public function getAvatarImage($size) {
568
+        // delay the initialization
569
+        if (is_null($this->avatarManager)) {
570
+            $this->avatarManager = \OC::$server->getAvatarManager();
571
+        }
572
+
573
+        $avatar = $this->avatarManager->getAvatar($this->uid);
574
+        $image = $avatar->get(-1);
575
+        if ($image) {
576
+            return $image;
577
+        }
578
+
579
+        return null;
580
+    }
581
+
582
+    /**
583
+     * get the federation cloud id
584
+     *
585
+     * @return string
586
+     * @since 9.0.0
587
+     */
588
+    public function getCloudId() {
589
+        $uid = $this->getUID();
590
+        $server = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/');
591
+        if (substr($server, -10) === '/index.php') {
592
+            $server = substr($server, 0, -10);
593
+        }
594
+        $server = $this->removeProtocolFromUrl($server);
595
+        return $uid . '@' . $server;
596
+    }
597
+
598
+    private function removeProtocolFromUrl(string $url): string {
599
+        if (strpos($url, 'https://') === 0) {
600
+            return substr($url, strlen('https://'));
601
+        }
602
+
603
+        return $url;
604
+    }
605
+
606
+    public function triggerChange($feature, $value = null, $oldValue = null) {
607
+        $this->legacyDispatcher->dispatch(IUser::class . '::changeUser', new GenericEvent($this, [
608
+            'feature' => $feature,
609
+            'value' => $value,
610
+            'oldValue' => $oldValue,
611
+        ]));
612
+        if ($this->emitter) {
613
+            $this->emitter->emit('\OC\User', 'changeUser', [$this, $feature, $value, $oldValue]);
614
+        }
615
+    }
616 616
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -258,7 +258,7 @@  discard block
 block discarded – undo
258 258
 		if ($now - $previousLogin > 60) {
259 259
 			$this->lastLogin = time();
260 260
 			$this->config->setUserValue(
261
-				$this->uid, 'login', 'lastLogin', (string)$this->lastLogin);
261
+				$this->uid, 'login', 'lastLogin', (string) $this->lastLogin);
262 262
 		}
263 263
 
264 264
 		return $firstTimeLogin;
@@ -271,7 +271,7 @@  discard block
 block discarded – undo
271 271
 	 */
272 272
 	public function delete() {
273 273
 		/** @deprecated 21.0.0 use BeforeUserDeletedEvent event with the IEventDispatcher instead */
274
-		$this->legacyDispatcher->dispatch(IUser::class . '::preDelete', new GenericEvent($this));
274
+		$this->legacyDispatcher->dispatch(IUser::class.'::preDelete', new GenericEvent($this));
275 275
 		if ($this->emitter) {
276 276
 			/** @deprecated 21.0.0 use BeforeUserDeletedEvent event with the IEventDispatcher instead */
277 277
 			$this->emitter->emit('\OC\User', 'preDelete', [$this]);
@@ -310,7 +310,7 @@  discard block
 block discarded – undo
310 310
 			$accountManager->deleteUser($this);
311 311
 
312 312
 			/** @deprecated 21.0.0 use UserDeletedEvent event with the IEventDispatcher instead */
313
-			$this->legacyDispatcher->dispatch(IUser::class . '::postDelete', new GenericEvent($this));
313
+			$this->legacyDispatcher->dispatch(IUser::class.'::postDelete', new GenericEvent($this));
314 314
 			if ($this->emitter) {
315 315
 				/** @deprecated 21.0.0 use UserDeletedEvent event with the IEventDispatcher instead */
316 316
 				$this->emitter->emit('\OC\User', 'postDelete', [$this]);
@@ -328,7 +328,7 @@  discard block
 block discarded – undo
328 328
 	 * @return bool
329 329
 	 */
330 330
 	public function setPassword($password, $recoveryPassword = null) {
331
-		$this->legacyDispatcher->dispatch(IUser::class . '::preSetPassword', new GenericEvent($this, [
331
+		$this->legacyDispatcher->dispatch(IUser::class.'::preSetPassword', new GenericEvent($this, [
332 332
 			'password' => $password,
333 333
 			'recoveryPassword' => $recoveryPassword,
334 334
 		]));
@@ -341,7 +341,7 @@  discard block
 block discarded – undo
341 341
 			$result = $backend->setPassword($this->uid, $password);
342 342
 
343 343
 			if ($result !== false) {
344
-				$this->legacyDispatcher->dispatch(IUser::class . '::postSetPassword', new GenericEvent($this, [
344
+				$this->legacyDispatcher->dispatch(IUser::class.'::postSetPassword', new GenericEvent($this, [
345 345
 					'password' => $password,
346 346
 					'recoveryPassword' => $recoveryPassword,
347 347
 				]));
@@ -367,9 +367,9 @@  discard block
 block discarded – undo
367 367
 			if (($this->backend instanceof IGetHomeBackend || $this->backend->implementsActions(Backend::GET_HOME)) && $home = $this->backend->getHome($this->uid)) {
368 368
 				$this->home = $home;
369 369
 			} elseif ($this->config) {
370
-				$this->home = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $this->uid;
370
+				$this->home = $this->config->getSystemValueString('datadirectory', \OC::$SERVERROOT.'/data').'/'.$this->uid;
371 371
 			} else {
372
-				$this->home = \OC::$SERVERROOT . '/data/' . $this->uid;
372
+				$this->home = \OC::$SERVERROOT.'/data/'.$this->uid;
373 373
 			}
374 374
 		}
375 375
 		return $this->home;
@@ -533,7 +533,7 @@  discard block
 block discarded – undo
533 533
 			$this->config->setUserValue($this->uid, 'files', 'quota', $quota);
534 534
 			$this->triggerChange('quota', $quota, $oldQuota);
535 535
 		}
536
-		\OC_Helper::clearStorageInfo('/' . $this->uid . '/files');
536
+		\OC_Helper::clearStorageInfo('/'.$this->uid.'/files');
537 537
 	}
538 538
 
539 539
 	public function getManagerUids(): array {
@@ -592,7 +592,7 @@  discard block
 block discarded – undo
592 592
 			$server = substr($server, 0, -10);
593 593
 		}
594 594
 		$server = $this->removeProtocolFromUrl($server);
595
-		return $uid . '@' . $server;
595
+		return $uid.'@'.$server;
596 596
 	}
597 597
 
598 598
 	private function removeProtocolFromUrl(string $url): string {
@@ -604,7 +604,7 @@  discard block
 block discarded – undo
604 604
 	}
605 605
 
606 606
 	public function triggerChange($feature, $value = null, $oldValue = null) {
607
-		$this->legacyDispatcher->dispatch(IUser::class . '::changeUser', new GenericEvent($this, [
607
+		$this->legacyDispatcher->dispatch(IUser::class.'::changeUser', new GenericEvent($this, [
608 608
 			'feature' => $feature,
609 609
 			'value' => $value,
610 610
 			'oldValue' => $oldValue,
Please login to merge, or discard this patch.
lib/private/User/LazyUser.php 1 patch
Indentation   +136 added lines, -136 removed lines patch added patch discarded remove patch
@@ -28,143 +28,143 @@
 block discarded – undo
28 28
 use OCP\UserInterface;
29 29
 
30 30
 class LazyUser implements IUser {
31
-	private ?IUser $user = null;
32
-	private string $uid;
33
-	private ?string $displayName;
34
-	private IUserManager $userManager;
35
-	private ?UserInterface $backend;
36
-
37
-	public function __construct(string $uid, IUserManager $userManager, ?string $displayName = null, ?UserInterface $backend = null) {
38
-		$this->uid = $uid;
39
-		$this->userManager = $userManager;
40
-		$this->displayName = $displayName;
41
-		$this->backend = $backend;
42
-	}
43
-
44
-	private function getUser(): IUser {
45
-		if ($this->user === null) {
46
-			if ($this->backend) {
47
-				/** @var \OC\User\Manager $manager */
48
-				$manager = $this->userManager;
49
-				$this->user = $manager->getUserObject($this->uid, $this->backend);
50
-			} else {
51
-				$this->user = $this->userManager->get($this->uid);
52
-			}
53
-		}
54
-		/** @var IUser */
55
-		$user = $this->user;
56
-		return $user;
57
-	}
58
-
59
-	public function getUID() {
60
-		return $this->uid;
61
-	}
62
-
63
-	public function getDisplayName() {
64
-		if ($this->displayName) {
65
-			return $this->displayName;
66
-		}
67
-
68
-		return $this->userManager->getDisplayName($this->uid) ?? $this->uid;
69
-	}
70
-
71
-	public function setDisplayName($displayName) {
72
-		return $this->getUser()->setDisplayName($displayName);
73
-	}
74
-
75
-	public function getLastLogin() {
76
-		return $this->getUser()->getLastLogin();
77
-	}
78
-
79
-	public function updateLastLoginTimestamp() {
80
-		return $this->getUser()->updateLastLoginTimestamp();
81
-	}
82
-
83
-	public function delete() {
84
-		return $this->getUser()->delete();
85
-	}
86
-
87
-	public function setPassword($password, $recoveryPassword = null) {
88
-		return $this->getUser()->setPassword($password, $recoveryPassword);
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 isEnabled() {
116
-		return $this->getUser()->isEnabled();
117
-	}
118
-
119
-	public function setEnabled(bool $enabled = true) {
120
-		return $this->getUser()->setEnabled($enabled);
121
-	}
122
-
123
-	public function getEMailAddress() {
124
-		return $this->getUser()->getEMailAddress();
125
-	}
126
-
127
-	public function getSystemEMailAddress(): ?string {
128
-		return $this->getUser()->getSystemEMailAddress();
129
-	}
130
-
131
-	public function getPrimaryEMailAddress(): ?string {
132
-		return $this->getUser()->getPrimaryEMailAddress();
133
-	}
134
-
135
-	public function getAvatarImage($size) {
136
-		return $this->getUser()->getAvatarImage($size);
137
-	}
138
-
139
-	public function getCloudId() {
140
-		return $this->getUser()->getCloudId();
141
-	}
142
-
143
-	public function setEMailAddress($mailAddress) {
144
-		$this->getUser()->setEMailAddress($mailAddress);
145
-	}
146
-
147
-	public function setSystemEMailAddress(string $mailAddress): void {
148
-		$this->getUser()->setSystemEMailAddress($mailAddress);
149
-	}
150
-
151
-	public function setPrimaryEMailAddress(string $mailAddress): void {
152
-		$this->getUser()->setPrimaryEMailAddress($mailAddress);
153
-	}
154
-
155
-	public function getQuota() {
156
-		return $this->getUser()->getQuota();
157
-	}
31
+    private ?IUser $user = null;
32
+    private string $uid;
33
+    private ?string $displayName;
34
+    private IUserManager $userManager;
35
+    private ?UserInterface $backend;
36
+
37
+    public function __construct(string $uid, IUserManager $userManager, ?string $displayName = null, ?UserInterface $backend = null) {
38
+        $this->uid = $uid;
39
+        $this->userManager = $userManager;
40
+        $this->displayName = $displayName;
41
+        $this->backend = $backend;
42
+    }
43
+
44
+    private function getUser(): IUser {
45
+        if ($this->user === null) {
46
+            if ($this->backend) {
47
+                /** @var \OC\User\Manager $manager */
48
+                $manager = $this->userManager;
49
+                $this->user = $manager->getUserObject($this->uid, $this->backend);
50
+            } else {
51
+                $this->user = $this->userManager->get($this->uid);
52
+            }
53
+        }
54
+        /** @var IUser */
55
+        $user = $this->user;
56
+        return $user;
57
+    }
58
+
59
+    public function getUID() {
60
+        return $this->uid;
61
+    }
62
+
63
+    public function getDisplayName() {
64
+        if ($this->displayName) {
65
+            return $this->displayName;
66
+        }
67
+
68
+        return $this->userManager->getDisplayName($this->uid) ?? $this->uid;
69
+    }
70
+
71
+    public function setDisplayName($displayName) {
72
+        return $this->getUser()->setDisplayName($displayName);
73
+    }
74
+
75
+    public function getLastLogin() {
76
+        return $this->getUser()->getLastLogin();
77
+    }
78
+
79
+    public function updateLastLoginTimestamp() {
80
+        return $this->getUser()->updateLastLoginTimestamp();
81
+    }
82
+
83
+    public function delete() {
84
+        return $this->getUser()->delete();
85
+    }
86
+
87
+    public function setPassword($password, $recoveryPassword = null) {
88
+        return $this->getUser()->setPassword($password, $recoveryPassword);
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 isEnabled() {
116
+        return $this->getUser()->isEnabled();
117
+    }
118
+
119
+    public function setEnabled(bool $enabled = true) {
120
+        return $this->getUser()->setEnabled($enabled);
121
+    }
122
+
123
+    public function getEMailAddress() {
124
+        return $this->getUser()->getEMailAddress();
125
+    }
126
+
127
+    public function getSystemEMailAddress(): ?string {
128
+        return $this->getUser()->getSystemEMailAddress();
129
+    }
130
+
131
+    public function getPrimaryEMailAddress(): ?string {
132
+        return $this->getUser()->getPrimaryEMailAddress();
133
+    }
134
+
135
+    public function getAvatarImage($size) {
136
+        return $this->getUser()->getAvatarImage($size);
137
+    }
138
+
139
+    public function getCloudId() {
140
+        return $this->getUser()->getCloudId();
141
+    }
142
+
143
+    public function setEMailAddress($mailAddress) {
144
+        $this->getUser()->setEMailAddress($mailAddress);
145
+    }
146
+
147
+    public function setSystemEMailAddress(string $mailAddress): void {
148
+        $this->getUser()->setSystemEMailAddress($mailAddress);
149
+    }
150
+
151
+    public function setPrimaryEMailAddress(string $mailAddress): void {
152
+        $this->getUser()->setPrimaryEMailAddress($mailAddress);
153
+    }
154
+
155
+    public function getQuota() {
156
+        return $this->getUser()->getQuota();
157
+    }
158 158
 
159
-	public function setQuota($quota) {
160
-		$this->getUser()->setQuota($quota);
161
-	}
159
+    public function setQuota($quota) {
160
+        $this->getUser()->setQuota($quota);
161
+    }
162 162
 
163
-	public function getManagerUids(): array {
164
-		return $this->getUser()->getManagerUids();
165
-	}
163
+    public function getManagerUids(): array {
164
+        return $this->getUser()->getManagerUids();
165
+    }
166 166
 
167
-	public function setManagerUids(array $uids): void {
168
-		$this->getUser()->setManagerUids($uids);
169
-	}
167
+    public function setManagerUids(array $uids): void {
168
+        $this->getUser()->setManagerUids($uids);
169
+    }
170 170
 }
Please login to merge, or discard this patch.
apps/dav/lib/CardDAV/Converter.php 1 patch
Indentation   +120 added lines, -120 removed lines patch added patch discarded remove patch
@@ -36,124 +36,124 @@
 block discarded – undo
36 36
 use Sabre\VObject\Property\Text;
37 37
 
38 38
 class Converter {
39
-	/** @var IAccountManager */
40
-	private $accountManager;
41
-	private IUserManager $userManager;
42
-
43
-	public function __construct(IAccountManager $accountManager,
44
-		IUserManager $userManager) {
45
-		$this->accountManager = $accountManager;
46
-		$this->userManager = $userManager;
47
-	}
48
-
49
-	public function createCardFromUser(IUser $user): ?VCard {
50
-		$userProperties = $this->accountManager->getAccount($user)->getAllProperties();
51
-
52
-		$uid = $user->getUID();
53
-		$cloudId = $user->getCloudId();
54
-		$image = $this->getAvatarImage($user);
55
-
56
-		$vCard = new VCard();
57
-		$vCard->VERSION = '3.0';
58
-		$vCard->UID = $uid;
59
-
60
-		$publish = false;
61
-
62
-		foreach ($userProperties as $property) {
63
-			if (empty($property->getValue())) {
64
-				continue;
65
-			}
66
-
67
-			$scope = $property->getScope();
68
-			// Do not write private data to the system address book at all
69
-			if ($scope === IAccountManager::SCOPE_PRIVATE || empty($scope)) {
70
-				continue;
71
-			}
72
-
73
-			$publish = true;
74
-			switch ($property->getName()) {
75
-				case IAccountManager::PROPERTY_DISPLAYNAME:
76
-					$vCard->add(new Text($vCard, 'FN', $property->getValue(), ['X-NC-SCOPE' => $scope]));
77
-					$vCard->add(new Text($vCard, 'N', $this->splitFullName($property->getValue()), ['X-NC-SCOPE' => $scope]));
78
-					break;
79
-				case IAccountManager::PROPERTY_AVATAR:
80
-					if ($image !== null) {
81
-						$vCard->add('PHOTO', $image->data(), ['ENCODING' => 'b', 'TYPE' => $image->mimeType(), ['X-NC-SCOPE' => $scope]]);
82
-					}
83
-					break;
84
-				case IAccountManager::COLLECTION_EMAIL:
85
-				case IAccountManager::PROPERTY_EMAIL:
86
-					$vCard->add(new Text($vCard, 'EMAIL', $property->getValue(), ['TYPE' => 'OTHER', 'X-NC-SCOPE' => $scope]));
87
-					break;
88
-				case IAccountManager::PROPERTY_WEBSITE:
89
-					$vCard->add(new Text($vCard, 'URL', $property->getValue(), ['X-NC-SCOPE' => $scope]));
90
-					break;
91
-				case IAccountManager::PROPERTY_PHONE:
92
-					$vCard->add(new Text($vCard, 'TEL', $property->getValue(), ['TYPE' => 'OTHER', 'X-NC-SCOPE' => $scope]));
93
-					break;
94
-				case IAccountManager::PROPERTY_ADDRESS:
95
-					$vCard->add(new Text($vCard, 'ADR', $property->getValue(), ['TYPE' => 'OTHER', 'X-NC-SCOPE' => $scope]));
96
-					break;
97
-				case IAccountManager::PROPERTY_TWITTER:
98
-					$vCard->add(new Text($vCard, 'X-SOCIALPROFILE', $property->getValue(), ['TYPE' => 'TWITTER', 'X-NC-SCOPE' => $scope]));
99
-					break;
100
-				case IAccountManager::PROPERTY_ORGANISATION:
101
-					$vCard->add(new Text($vCard, 'ORG', $property->getValue(), ['X-NC-SCOPE' => $scope]));
102
-					break;
103
-				case IAccountManager::PROPERTY_ROLE:
104
-					$vCard->add(new Text($vCard, 'TITLE', $property->getValue(), ['X-NC-SCOPE' => $scope]));
105
-					break;
106
-			}
107
-		}
108
-
109
-		// Local properties
110
-		$managers = $user->getManagerUids();
111
-		// X-MANAGERSNAME only allows a single value, so we take the first manager
112
-		if (isset($managers[0])) {
113
-			$displayName = $this->userManager->getDisplayName($managers[0]);
114
-			// Only set the manager if a user object is found
115
-			if ($displayName !== null) {
116
-				$vCard->add(new Text($vCard, 'X-MANAGERSNAME', $displayName, [
117
-					'uid' => $managers[0],
118
-					'X-NC-SCOPE' => IAccountManager::SCOPE_LOCAL,
119
-				]));
120
-			}
121
-		}
122
-
123
-		if ($publish && !empty($cloudId)) {
124
-			$vCard->add(new Text($vCard, 'CLOUD', $cloudId));
125
-			$vCard->validate();
126
-			return $vCard;
127
-		}
128
-
129
-		return null;
130
-	}
131
-
132
-	public function splitFullName(string $fullName): array {
133
-		// Very basic western style parsing. I'm not gonna implement
134
-		// https://github.com/android/platform_packages_providers_contactsprovider/blob/master/src/com/android/providers/contacts/NameSplitter.java ;)
135
-
136
-		$elements = explode(' ', $fullName);
137
-		$result = ['', '', '', '', ''];
138
-		if (count($elements) > 2) {
139
-			$result[0] = implode(' ', array_slice($elements, count($elements) - 1));
140
-			$result[1] = $elements[0];
141
-			$result[2] = implode(' ', array_slice($elements, 1, count($elements) - 2));
142
-		} elseif (count($elements) === 2) {
143
-			$result[0] = $elements[1];
144
-			$result[1] = $elements[0];
145
-		} else {
146
-			$result[0] = $elements[0];
147
-		}
148
-
149
-		return $result;
150
-	}
151
-
152
-	private function getAvatarImage(IUser $user): ?IImage {
153
-		try {
154
-			return $user->getAvatarImage(-1);
155
-		} catch (Exception $ex) {
156
-			return null;
157
-		}
158
-	}
39
+    /** @var IAccountManager */
40
+    private $accountManager;
41
+    private IUserManager $userManager;
42
+
43
+    public function __construct(IAccountManager $accountManager,
44
+        IUserManager $userManager) {
45
+        $this->accountManager = $accountManager;
46
+        $this->userManager = $userManager;
47
+    }
48
+
49
+    public function createCardFromUser(IUser $user): ?VCard {
50
+        $userProperties = $this->accountManager->getAccount($user)->getAllProperties();
51
+
52
+        $uid = $user->getUID();
53
+        $cloudId = $user->getCloudId();
54
+        $image = $this->getAvatarImage($user);
55
+
56
+        $vCard = new VCard();
57
+        $vCard->VERSION = '3.0';
58
+        $vCard->UID = $uid;
59
+
60
+        $publish = false;
61
+
62
+        foreach ($userProperties as $property) {
63
+            if (empty($property->getValue())) {
64
+                continue;
65
+            }
66
+
67
+            $scope = $property->getScope();
68
+            // Do not write private data to the system address book at all
69
+            if ($scope === IAccountManager::SCOPE_PRIVATE || empty($scope)) {
70
+                continue;
71
+            }
72
+
73
+            $publish = true;
74
+            switch ($property->getName()) {
75
+                case IAccountManager::PROPERTY_DISPLAYNAME:
76
+                    $vCard->add(new Text($vCard, 'FN', $property->getValue(), ['X-NC-SCOPE' => $scope]));
77
+                    $vCard->add(new Text($vCard, 'N', $this->splitFullName($property->getValue()), ['X-NC-SCOPE' => $scope]));
78
+                    break;
79
+                case IAccountManager::PROPERTY_AVATAR:
80
+                    if ($image !== null) {
81
+                        $vCard->add('PHOTO', $image->data(), ['ENCODING' => 'b', 'TYPE' => $image->mimeType(), ['X-NC-SCOPE' => $scope]]);
82
+                    }
83
+                    break;
84
+                case IAccountManager::COLLECTION_EMAIL:
85
+                case IAccountManager::PROPERTY_EMAIL:
86
+                    $vCard->add(new Text($vCard, 'EMAIL', $property->getValue(), ['TYPE' => 'OTHER', 'X-NC-SCOPE' => $scope]));
87
+                    break;
88
+                case IAccountManager::PROPERTY_WEBSITE:
89
+                    $vCard->add(new Text($vCard, 'URL', $property->getValue(), ['X-NC-SCOPE' => $scope]));
90
+                    break;
91
+                case IAccountManager::PROPERTY_PHONE:
92
+                    $vCard->add(new Text($vCard, 'TEL', $property->getValue(), ['TYPE' => 'OTHER', 'X-NC-SCOPE' => $scope]));
93
+                    break;
94
+                case IAccountManager::PROPERTY_ADDRESS:
95
+                    $vCard->add(new Text($vCard, 'ADR', $property->getValue(), ['TYPE' => 'OTHER', 'X-NC-SCOPE' => $scope]));
96
+                    break;
97
+                case IAccountManager::PROPERTY_TWITTER:
98
+                    $vCard->add(new Text($vCard, 'X-SOCIALPROFILE', $property->getValue(), ['TYPE' => 'TWITTER', 'X-NC-SCOPE' => $scope]));
99
+                    break;
100
+                case IAccountManager::PROPERTY_ORGANISATION:
101
+                    $vCard->add(new Text($vCard, 'ORG', $property->getValue(), ['X-NC-SCOPE' => $scope]));
102
+                    break;
103
+                case IAccountManager::PROPERTY_ROLE:
104
+                    $vCard->add(new Text($vCard, 'TITLE', $property->getValue(), ['X-NC-SCOPE' => $scope]));
105
+                    break;
106
+            }
107
+        }
108
+
109
+        // Local properties
110
+        $managers = $user->getManagerUids();
111
+        // X-MANAGERSNAME only allows a single value, so we take the first manager
112
+        if (isset($managers[0])) {
113
+            $displayName = $this->userManager->getDisplayName($managers[0]);
114
+            // Only set the manager if a user object is found
115
+            if ($displayName !== null) {
116
+                $vCard->add(new Text($vCard, 'X-MANAGERSNAME', $displayName, [
117
+                    'uid' => $managers[0],
118
+                    'X-NC-SCOPE' => IAccountManager::SCOPE_LOCAL,
119
+                ]));
120
+            }
121
+        }
122
+
123
+        if ($publish && !empty($cloudId)) {
124
+            $vCard->add(new Text($vCard, 'CLOUD', $cloudId));
125
+            $vCard->validate();
126
+            return $vCard;
127
+        }
128
+
129
+        return null;
130
+    }
131
+
132
+    public function splitFullName(string $fullName): array {
133
+        // Very basic western style parsing. I'm not gonna implement
134
+        // https://github.com/android/platform_packages_providers_contactsprovider/blob/master/src/com/android/providers/contacts/NameSplitter.java ;)
135
+
136
+        $elements = explode(' ', $fullName);
137
+        $result = ['', '', '', '', ''];
138
+        if (count($elements) > 2) {
139
+            $result[0] = implode(' ', array_slice($elements, count($elements) - 1));
140
+            $result[1] = $elements[0];
141
+            $result[2] = implode(' ', array_slice($elements, 1, count($elements) - 2));
142
+        } elseif (count($elements) === 2) {
143
+            $result[0] = $elements[1];
144
+            $result[1] = $elements[0];
145
+        } else {
146
+            $result[0] = $elements[0];
147
+        }
148
+
149
+        return $result;
150
+    }
151
+
152
+    private function getAvatarImage(IUser $user): ?IImage {
153
+        try {
154
+            return $user->getAvatarImage(-1);
155
+        } catch (Exception $ex) {
156
+            return null;
157
+        }
158
+    }
159 159
 }
Please login to merge, or discard this patch.
apps/provisioning_api/lib/Controller/AUserData.php 1 patch
Indentation   +215 added lines, -215 removed lines patch added patch discarded remove patch
@@ -53,242 +53,242 @@
 block discarded – undo
53 53
 use OCP\User\Backend\ISetPasswordBackend;
54 54
 
55 55
 abstract class AUserData extends OCSController {
56
-	public const SCOPE_SUFFIX = 'Scope';
56
+    public const SCOPE_SUFFIX = 'Scope';
57 57
 
58
-	public const USER_FIELD_DISPLAYNAME = 'display';
59
-	public const USER_FIELD_LANGUAGE = 'language';
60
-	public const USER_FIELD_LOCALE = 'locale';
61
-	public const USER_FIELD_PASSWORD = 'password';
62
-	public const USER_FIELD_QUOTA = 'quota';
63
-	public const USER_FIELD_MANAGER = 'manager';
64
-	public const USER_FIELD_NOTIFICATION_EMAIL = 'notify_email';
58
+    public const USER_FIELD_DISPLAYNAME = 'display';
59
+    public const USER_FIELD_LANGUAGE = 'language';
60
+    public const USER_FIELD_LOCALE = 'locale';
61
+    public const USER_FIELD_PASSWORD = 'password';
62
+    public const USER_FIELD_QUOTA = 'quota';
63
+    public const USER_FIELD_MANAGER = 'manager';
64
+    public const USER_FIELD_NOTIFICATION_EMAIL = 'notify_email';
65 65
 
66
-	/** @var IUserManager */
67
-	protected $userManager;
68
-	/** @var IConfig */
69
-	protected $config;
70
-	/** @var Manager */
71
-	protected $groupManager;
72
-	/** @var IUserSession */
73
-	protected $userSession;
74
-	/** @var IAccountManager */
75
-	protected $accountManager;
76
-	/** @var IFactory */
77
-	protected $l10nFactory;
66
+    /** @var IUserManager */
67
+    protected $userManager;
68
+    /** @var IConfig */
69
+    protected $config;
70
+    /** @var Manager */
71
+    protected $groupManager;
72
+    /** @var IUserSession */
73
+    protected $userSession;
74
+    /** @var IAccountManager */
75
+    protected $accountManager;
76
+    /** @var IFactory */
77
+    protected $l10nFactory;
78 78
 
79
-	public function __construct(string $appName,
80
-								IRequest $request,
81
-								IUserManager $userManager,
82
-								IConfig $config,
83
-								IGroupManager $groupManager,
84
-								IUserSession $userSession,
85
-								IAccountManager $accountManager,
86
-								IFactory $l10nFactory) {
87
-		parent::__construct($appName, $request);
79
+    public function __construct(string $appName,
80
+                                IRequest $request,
81
+                                IUserManager $userManager,
82
+                                IConfig $config,
83
+                                IGroupManager $groupManager,
84
+                                IUserSession $userSession,
85
+                                IAccountManager $accountManager,
86
+                                IFactory $l10nFactory) {
87
+        parent::__construct($appName, $request);
88 88
 
89
-		$this->userManager = $userManager;
90
-		$this->config = $config;
91
-		$this->groupManager = $groupManager;
92
-		$this->userSession = $userSession;
93
-		$this->accountManager = $accountManager;
94
-		$this->l10nFactory = $l10nFactory;
95
-	}
89
+        $this->userManager = $userManager;
90
+        $this->config = $config;
91
+        $this->groupManager = $groupManager;
92
+        $this->userSession = $userSession;
93
+        $this->accountManager = $accountManager;
94
+        $this->l10nFactory = $l10nFactory;
95
+    }
96 96
 
97
-	/**
98
-	 * creates a array with all user data
99
-	 *
100
-	 * @param string $userId
101
-	 * @param bool $includeScopes
102
-	 * @return array
103
-	 * @throws NotFoundException
104
-	 * @throws OCSException
105
-	 * @throws OCSNotFoundException
106
-	 */
107
-	protected function getUserData(string $userId, bool $includeScopes = false): array {
108
-		$currentLoggedInUser = $this->userSession->getUser();
109
-		assert($currentLoggedInUser !== null, 'No user logged in');
97
+    /**
98
+     * creates a array with all user data
99
+     *
100
+     * @param string $userId
101
+     * @param bool $includeScopes
102
+     * @return array
103
+     * @throws NotFoundException
104
+     * @throws OCSException
105
+     * @throws OCSNotFoundException
106
+     */
107
+    protected function getUserData(string $userId, bool $includeScopes = false): array {
108
+        $currentLoggedInUser = $this->userSession->getUser();
109
+        assert($currentLoggedInUser !== null, 'No user logged in');
110 110
 
111
-		$data = [];
111
+        $data = [];
112 112
 
113
-		// Check if the target user exists
114
-		$targetUserObject = $this->userManager->get($userId);
115
-		if ($targetUserObject === null) {
116
-			throw new OCSNotFoundException('User does not exist');
117
-		}
113
+        // Check if the target user exists
114
+        $targetUserObject = $this->userManager->get($userId);
115
+        if ($targetUserObject === null) {
116
+            throw new OCSNotFoundException('User does not exist');
117
+        }
118 118
 
119
-		$isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
120
-		if ($isAdmin
121
-			|| $this->groupManager->getSubAdmin()->isUserAccessible($currentLoggedInUser, $targetUserObject)) {
122
-			$data['enabled'] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'enabled', 'true') === 'true';
123
-		} else {
124
-			// Check they are looking up themselves
125
-			if ($currentLoggedInUser->getUID() !== $targetUserObject->getUID()) {
126
-				return $data;
127
-			}
128
-		}
119
+        $isAdmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID());
120
+        if ($isAdmin
121
+            || $this->groupManager->getSubAdmin()->isUserAccessible($currentLoggedInUser, $targetUserObject)) {
122
+            $data['enabled'] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'enabled', 'true') === 'true';
123
+        } else {
124
+            // Check they are looking up themselves
125
+            if ($currentLoggedInUser->getUID() !== $targetUserObject->getUID()) {
126
+                return $data;
127
+            }
128
+        }
129 129
 
130
-		// Get groups data
131
-		$userAccount = $this->accountManager->getAccount($targetUserObject);
132
-		$groups = $this->groupManager->getUserGroups($targetUserObject);
133
-		$gids = [];
134
-		foreach ($groups as $group) {
135
-			$gids[] = $group->getGID();
136
-		}
130
+        // Get groups data
131
+        $userAccount = $this->accountManager->getAccount($targetUserObject);
132
+        $groups = $this->groupManager->getUserGroups($targetUserObject);
133
+        $gids = [];
134
+        foreach ($groups as $group) {
135
+            $gids[] = $group->getGID();
136
+        }
137 137
 
138
-		if ($isAdmin) {
139
-			try {
140
-				# might be thrown by LDAP due to handling of users disappears
141
-				# from the external source (reasons unknown to us)
142
-				# cf. https://github.com/nextcloud/server/issues/12991
143
-				$data['storageLocation'] = $targetUserObject->getHome();
144
-			} catch (NoUserException $e) {
145
-				throw new OCSNotFoundException($e->getMessage(), $e);
146
-			}
147
-		}
138
+        if ($isAdmin) {
139
+            try {
140
+                # might be thrown by LDAP due to handling of users disappears
141
+                # from the external source (reasons unknown to us)
142
+                # cf. https://github.com/nextcloud/server/issues/12991
143
+                $data['storageLocation'] = $targetUserObject->getHome();
144
+            } catch (NoUserException $e) {
145
+                throw new OCSNotFoundException($e->getMessage(), $e);
146
+            }
147
+        }
148 148
 
149
-		// Find the data
150
-		$data['id'] = $targetUserObject->getUID();
151
-		$data['lastLogin'] = $targetUserObject->getLastLogin() * 1000;
152
-		$data['backend'] = $targetUserObject->getBackendClassName();
153
-		$data['subadmin'] = $this->getUserSubAdminGroupsData($targetUserObject->getUID());
154
-		$data[self::USER_FIELD_QUOTA] = $this->fillStorageInfo($targetUserObject->getUID());
155
-		$managerUids = $targetUserObject->getManagerUids();
156
-		$data[self::USER_FIELD_MANAGER] = empty($managerUids) ? '' : $managerUids[0];
149
+        // Find the data
150
+        $data['id'] = $targetUserObject->getUID();
151
+        $data['lastLogin'] = $targetUserObject->getLastLogin() * 1000;
152
+        $data['backend'] = $targetUserObject->getBackendClassName();
153
+        $data['subadmin'] = $this->getUserSubAdminGroupsData($targetUserObject->getUID());
154
+        $data[self::USER_FIELD_QUOTA] = $this->fillStorageInfo($targetUserObject->getUID());
155
+        $managerUids = $targetUserObject->getManagerUids();
156
+        $data[self::USER_FIELD_MANAGER] = empty($managerUids) ? '' : $managerUids[0];
157 157
 
158
-		try {
159
-			if ($includeScopes) {
160
-				$data[IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_AVATAR)->getScope();
161
-			}
158
+        try {
159
+            if ($includeScopes) {
160
+                $data[IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_AVATAR)->getScope();
161
+            }
162 162
 
163
-			$data[IAccountManager::PROPERTY_EMAIL] = $targetUserObject->getSystemEMailAddress();
164
-			if ($includeScopes) {
165
-				$data[IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope();
166
-			}
163
+            $data[IAccountManager::PROPERTY_EMAIL] = $targetUserObject->getSystemEMailAddress();
164
+            if ($includeScopes) {
165
+                $data[IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope();
166
+            }
167 167
 
168
-			$additionalEmails = $additionalEmailScopes = [];
169
-			$emailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
170
-			foreach ($emailCollection->getProperties() as $property) {
171
-				$additionalEmails[] = $property->getValue();
172
-				if ($includeScopes) {
173
-					$additionalEmailScopes[] = $property->getScope();
174
-				}
175
-			}
176
-			$data[IAccountManager::COLLECTION_EMAIL] = $additionalEmails;
177
-			if ($includeScopes) {
178
-				$data[IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX] = $additionalEmailScopes;
179
-			}
168
+            $additionalEmails = $additionalEmailScopes = [];
169
+            $emailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
170
+            foreach ($emailCollection->getProperties() as $property) {
171
+                $additionalEmails[] = $property->getValue();
172
+                if ($includeScopes) {
173
+                    $additionalEmailScopes[] = $property->getScope();
174
+                }
175
+            }
176
+            $data[IAccountManager::COLLECTION_EMAIL] = $additionalEmails;
177
+            if ($includeScopes) {
178
+                $data[IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX] = $additionalEmailScopes;
179
+            }
180 180
 
181
-			$data[IAccountManager::PROPERTY_DISPLAYNAME] = $targetUserObject->getDisplayName();
182
-			$data[IAccountManager::PROPERTY_DISPLAYNAME_LEGACY] = $data[IAccountManager::PROPERTY_DISPLAYNAME];
183
-			if ($includeScopes) {
184
-				$data[IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME)->getScope();
185
-			}
181
+            $data[IAccountManager::PROPERTY_DISPLAYNAME] = $targetUserObject->getDisplayName();
182
+            $data[IAccountManager::PROPERTY_DISPLAYNAME_LEGACY] = $data[IAccountManager::PROPERTY_DISPLAYNAME];
183
+            if ($includeScopes) {
184
+                $data[IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX] = $userAccount->getProperty(IAccountManager::PROPERTY_DISPLAYNAME)->getScope();
185
+            }
186 186
 
187
-			foreach ([
188
-				IAccountManager::PROPERTY_PHONE,
189
-				IAccountManager::PROPERTY_ADDRESS,
190
-				IAccountManager::PROPERTY_WEBSITE,
191
-				IAccountManager::PROPERTY_TWITTER,
192
-				IAccountManager::PROPERTY_FEDIVERSE,
193
-				IAccountManager::PROPERTY_ORGANISATION,
194
-				IAccountManager::PROPERTY_ROLE,
195
-				IAccountManager::PROPERTY_HEADLINE,
196
-				IAccountManager::PROPERTY_BIOGRAPHY,
197
-				IAccountManager::PROPERTY_PROFILE_ENABLED,
198
-			] as $propertyName) {
199
-				$property = $userAccount->getProperty($propertyName);
200
-				$data[$propertyName] = $property->getValue();
201
-				if ($includeScopes) {
202
-					$data[$propertyName . self::SCOPE_SUFFIX] = $property->getScope();
203
-				}
204
-			}
205
-		} catch (PropertyDoesNotExistException $e) {
206
-			// hard coded properties should exist
207
-			throw new OCSException($e->getMessage(), Http::STATUS_INTERNAL_SERVER_ERROR, $e);
208
-		}
187
+            foreach ([
188
+                IAccountManager::PROPERTY_PHONE,
189
+                IAccountManager::PROPERTY_ADDRESS,
190
+                IAccountManager::PROPERTY_WEBSITE,
191
+                IAccountManager::PROPERTY_TWITTER,
192
+                IAccountManager::PROPERTY_FEDIVERSE,
193
+                IAccountManager::PROPERTY_ORGANISATION,
194
+                IAccountManager::PROPERTY_ROLE,
195
+                IAccountManager::PROPERTY_HEADLINE,
196
+                IAccountManager::PROPERTY_BIOGRAPHY,
197
+                IAccountManager::PROPERTY_PROFILE_ENABLED,
198
+            ] as $propertyName) {
199
+                $property = $userAccount->getProperty($propertyName);
200
+                $data[$propertyName] = $property->getValue();
201
+                if ($includeScopes) {
202
+                    $data[$propertyName . self::SCOPE_SUFFIX] = $property->getScope();
203
+                }
204
+            }
205
+        } catch (PropertyDoesNotExistException $e) {
206
+            // hard coded properties should exist
207
+            throw new OCSException($e->getMessage(), Http::STATUS_INTERNAL_SERVER_ERROR, $e);
208
+        }
209 209
 
210
-		$data['groups'] = $gids;
211
-		$data[self::USER_FIELD_LANGUAGE] = $this->l10nFactory->getUserLanguage($targetUserObject);
212
-		$data[self::USER_FIELD_LOCALE] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'locale');
213
-		$data[self::USER_FIELD_NOTIFICATION_EMAIL] = $targetUserObject->getPrimaryEMailAddress();
210
+        $data['groups'] = $gids;
211
+        $data[self::USER_FIELD_LANGUAGE] = $this->l10nFactory->getUserLanguage($targetUserObject);
212
+        $data[self::USER_FIELD_LOCALE] = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'locale');
213
+        $data[self::USER_FIELD_NOTIFICATION_EMAIL] = $targetUserObject->getPrimaryEMailAddress();
214 214
 
215
-		$backend = $targetUserObject->getBackend();
216
-		$data['backendCapabilities'] = [
217
-			'setDisplayName' => $backend instanceof ISetDisplayNameBackend || $backend->implementsActions(Backend::SET_DISPLAYNAME),
218
-			'setPassword' => $backend instanceof ISetPasswordBackend || $backend->implementsActions(Backend::SET_PASSWORD),
219
-		];
215
+        $backend = $targetUserObject->getBackend();
216
+        $data['backendCapabilities'] = [
217
+            'setDisplayName' => $backend instanceof ISetDisplayNameBackend || $backend->implementsActions(Backend::SET_DISPLAYNAME),
218
+            'setPassword' => $backend instanceof ISetPasswordBackend || $backend->implementsActions(Backend::SET_PASSWORD),
219
+        ];
220 220
 
221
-		return $data;
222
-	}
221
+        return $data;
222
+    }
223 223
 
224
-	/**
225
-	 * Get the groups a user is a subadmin of
226
-	 *
227
-	 * @param string $userId
228
-	 * @return array
229
-	 * @throws OCSException
230
-	 */
231
-	protected function getUserSubAdminGroupsData(string $userId): array {
232
-		$user = $this->userManager->get($userId);
233
-		// Check if the user exists
234
-		if ($user === null) {
235
-			throw new OCSNotFoundException('User does not exist');
236
-		}
224
+    /**
225
+     * Get the groups a user is a subadmin of
226
+     *
227
+     * @param string $userId
228
+     * @return array
229
+     * @throws OCSException
230
+     */
231
+    protected function getUserSubAdminGroupsData(string $userId): array {
232
+        $user = $this->userManager->get($userId);
233
+        // Check if the user exists
234
+        if ($user === null) {
235
+            throw new OCSNotFoundException('User does not exist');
236
+        }
237 237
 
238
-		// Get the subadmin groups
239
-		$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
240
-		$groups = [];
241
-		foreach ($subAdminGroups as $key => $group) {
242
-			$groups[] = $group->getGID();
243
-		}
238
+        // Get the subadmin groups
239
+        $subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($user);
240
+        $groups = [];
241
+        foreach ($subAdminGroups as $key => $group) {
242
+            $groups[] = $group->getGID();
243
+        }
244 244
 
245
-		return $groups;
246
-	}
245
+        return $groups;
246
+    }
247 247
 
248
-	/**
249
-	 * @param string $userId
250
-	 * @return array
251
-	 * @throws OCSException
252
-	 */
253
-	protected function fillStorageInfo(string $userId): array {
254
-		try {
255
-			\OC_Util::tearDownFS();
256
-			\OC_Util::setupFS($userId);
257
-			$storage = OC_Helper::getStorageInfo('/', null, true, false);
258
-			$data = [
259
-				'free' => $storage['free'],
260
-				'used' => $storage['used'],
261
-				'total' => $storage['total'],
262
-				'relative' => $storage['relative'],
263
-				self::USER_FIELD_QUOTA => $storage['quota'],
264
-			];
265
-		} catch (NotFoundException $ex) {
266
-			// User fs is not setup yet
267
-			$user = $this->userManager->get($userId);
268
-			if ($user === null) {
269
-				throw new OCSException('User does not exist', 101);
270
-			}
271
-			$quota = $user->getQuota();
272
-			if ($quota !== 'none') {
273
-				$quota = OC_Helper::computerFileSize($quota);
274
-			}
275
-			$data = [
276
-				self::USER_FIELD_QUOTA => $quota !== false ? $quota : 'none',
277
-				'used' => 0
278
-			];
279
-		} catch (\Exception $e) {
280
-			\OC::$server->get(\Psr\Log\LoggerInterface::class)->error(
281
-				"Could not load storage info for {user}",
282
-				[
283
-					'app' => 'provisioning_api',
284
-					'user' => $userId,
285
-					'exception' => $e,
286
-				]
287
-			);
288
-			/* In case the Exception left things in a bad state */
289
-			\OC_Util::tearDownFS();
290
-			return [];
291
-		}
292
-		return $data;
293
-	}
248
+    /**
249
+     * @param string $userId
250
+     * @return array
251
+     * @throws OCSException
252
+     */
253
+    protected function fillStorageInfo(string $userId): array {
254
+        try {
255
+            \OC_Util::tearDownFS();
256
+            \OC_Util::setupFS($userId);
257
+            $storage = OC_Helper::getStorageInfo('/', null, true, false);
258
+            $data = [
259
+                'free' => $storage['free'],
260
+                'used' => $storage['used'],
261
+                'total' => $storage['total'],
262
+                'relative' => $storage['relative'],
263
+                self::USER_FIELD_QUOTA => $storage['quota'],
264
+            ];
265
+        } catch (NotFoundException $ex) {
266
+            // User fs is not setup yet
267
+            $user = $this->userManager->get($userId);
268
+            if ($user === null) {
269
+                throw new OCSException('User does not exist', 101);
270
+            }
271
+            $quota = $user->getQuota();
272
+            if ($quota !== 'none') {
273
+                $quota = OC_Helper::computerFileSize($quota);
274
+            }
275
+            $data = [
276
+                self::USER_FIELD_QUOTA => $quota !== false ? $quota : 'none',
277
+                'used' => 0
278
+            ];
279
+        } catch (\Exception $e) {
280
+            \OC::$server->get(\Psr\Log\LoggerInterface::class)->error(
281
+                "Could not load storage info for {user}",
282
+                [
283
+                    'app' => 'provisioning_api',
284
+                    'user' => $userId,
285
+                    'exception' => $e,
286
+                ]
287
+            );
288
+            /* In case the Exception left things in a bad state */
289
+            \OC_Util::tearDownFS();
290
+            return [];
291
+        }
292
+        return $data;
293
+    }
294 294
 }
Please login to merge, or discard this patch.
apps/provisioning_api/lib/Controller/UsersController.php 2 patches
Indentation   +1359 added lines, -1359 removed lines patch added patch discarded remove patch
@@ -78,1363 +78,1363 @@
 block discarded – undo
78 78
 use Psr\Log\LoggerInterface;
79 79
 
80 80
 class UsersController extends AUserData {
81
-	/** @var IURLGenerator */
82
-	protected $urlGenerator;
83
-	/** @var LoggerInterface */
84
-	private $logger;
85
-	/** @var IFactory */
86
-	protected $l10nFactory;
87
-	/** @var NewUserMailHelper */
88
-	private $newUserMailHelper;
89
-	/** @var ISecureRandom */
90
-	private $secureRandom;
91
-	/** @var RemoteWipe */
92
-	private $remoteWipe;
93
-	/** @var KnownUserService */
94
-	private $knownUserService;
95
-	/** @var IEventDispatcher */
96
-	private $eventDispatcher;
97
-
98
-	public function __construct(
99
-		string $appName,
100
-		IRequest $request,
101
-		IUserManager $userManager,
102
-		IConfig $config,
103
-		IGroupManager $groupManager,
104
-		IUserSession $userSession,
105
-		IAccountManager $accountManager,
106
-		IURLGenerator $urlGenerator,
107
-		LoggerInterface $logger,
108
-		IFactory $l10nFactory,
109
-		NewUserMailHelper $newUserMailHelper,
110
-		ISecureRandom $secureRandom,
111
-		RemoteWipe $remoteWipe,
112
-		KnownUserService $knownUserService,
113
-		IEventDispatcher $eventDispatcher
114
-	) {
115
-		parent::__construct(
116
-			$appName,
117
-			$request,
118
-			$userManager,
119
-			$config,
120
-			$groupManager,
121
-			$userSession,
122
-			$accountManager,
123
-			$l10nFactory
124
-		);
125
-
126
-		$this->urlGenerator = $urlGenerator;
127
-		$this->logger = $logger;
128
-		$this->l10nFactory = $l10nFactory;
129
-		$this->newUserMailHelper = $newUserMailHelper;
130
-		$this->secureRandom = $secureRandom;
131
-		$this->remoteWipe = $remoteWipe;
132
-		$this->knownUserService = $knownUserService;
133
-		$this->eventDispatcher = $eventDispatcher;
134
-	}
135
-
136
-	/**
137
-	 * @NoAdminRequired
138
-	 *
139
-	 * returns a list of users
140
-	 *
141
-	 * @param string $search
142
-	 * @param int $limit
143
-	 * @param int $offset
144
-	 * @return DataResponse
145
-	 */
146
-	public function getUsers(string $search = '', int $limit = null, int $offset = 0): DataResponse {
147
-		$user = $this->userSession->getUser();
148
-		$users = [];
149
-
150
-		// Admin? Or SubAdmin?
151
-		$uid = $user->getUID();
152
-		$subAdminManager = $this->groupManager->getSubAdmin();
153
-		if ($this->groupManager->isAdmin($uid)) {
154
-			$users = $this->userManager->search($search, $limit, $offset);
155
-		} elseif ($subAdminManager->isSubAdmin($user)) {
156
-			$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($user);
157
-			foreach ($subAdminOfGroups as $key => $group) {
158
-				$subAdminOfGroups[$key] = $group->getGID();
159
-			}
160
-
161
-			$users = [];
162
-			foreach ($subAdminOfGroups as $group) {
163
-				$users = array_merge($users, $this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
164
-			}
165
-		}
166
-
167
-		$users = array_keys($users);
168
-
169
-		return new DataResponse([
170
-			'users' => $users
171
-		]);
172
-	}
173
-
174
-	/**
175
-	 * @NoAdminRequired
176
-	 *
177
-	 * returns a list of users and their data
178
-	 */
179
-	public function getUsersDetails(string $search = '', int $limit = null, int $offset = 0): DataResponse {
180
-		$currentUser = $this->userSession->getUser();
181
-		$users = [];
182
-
183
-		// Admin? Or SubAdmin?
184
-		$uid = $currentUser->getUID();
185
-		$subAdminManager = $this->groupManager->getSubAdmin();
186
-		if ($this->groupManager->isAdmin($uid)) {
187
-			$users = $this->userManager->search($search, $limit, $offset);
188
-			$users = array_keys($users);
189
-		} elseif ($subAdminManager->isSubAdmin($currentUser)) {
190
-			$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
191
-			foreach ($subAdminOfGroups as $key => $group) {
192
-				$subAdminOfGroups[$key] = $group->getGID();
193
-			}
194
-
195
-			$users = [];
196
-			foreach ($subAdminOfGroups as $group) {
197
-				$users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
198
-			}
199
-			$users = array_merge(...$users);
200
-		}
201
-
202
-		$usersDetails = [];
203
-		foreach ($users as $userId) {
204
-			$userId = (string) $userId;
205
-			$userData = $this->getUserData($userId);
206
-			// Do not insert empty entry
207
-			if (!empty($userData)) {
208
-				$usersDetails[$userId] = $userData;
209
-			} else {
210
-				// Logged user does not have permissions to see this user
211
-				// only showing its id
212
-				$usersDetails[$userId] = ['id' => $userId];
213
-			}
214
-		}
215
-
216
-		return new DataResponse([
217
-			'users' => $usersDetails
218
-		]);
219
-	}
220
-
221
-
222
-	/**
223
-	 * @NoAdminRequired
224
-	 * @NoSubAdminRequired
225
-	 *
226
-	 * @param string $location
227
-	 * @param array $search
228
-	 * @return DataResponse
229
-	 */
230
-	public function searchByPhoneNumbers(string $location, array $search): DataResponse {
231
-		$phoneUtil = PhoneNumberUtil::getInstance();
232
-
233
-		if ($phoneUtil->getCountryCodeForRegion($location) === 0) {
234
-			// Not a valid region code
235
-			return new DataResponse([], Http::STATUS_BAD_REQUEST);
236
-		}
237
-
238
-		/** @var IUser $user */
239
-		$user = $this->userSession->getUser();
240
-		$knownTo = $user->getUID();
241
-		$defaultPhoneRegion = $this->config->getSystemValueString('default_phone_region');
242
-
243
-		$normalizedNumberToKey = [];
244
-		foreach ($search as $key => $phoneNumbers) {
245
-			foreach ($phoneNumbers as $phone) {
246
-				try {
247
-					$phoneNumber = $phoneUtil->parse($phone, $location);
248
-					if ($phoneNumber instanceof PhoneNumber && $phoneUtil->isValidNumber($phoneNumber)) {
249
-						$normalizedNumber = $phoneUtil->format($phoneNumber, PhoneNumberFormat::E164);
250
-						$normalizedNumberToKey[$normalizedNumber] = (string) $key;
251
-					}
252
-				} catch (NumberParseException $e) {
253
-				}
254
-
255
-				if ($defaultPhoneRegion !== '' && $defaultPhoneRegion !== $location && strpos($phone, '0') === 0) {
256
-					// If the number has a leading zero (no country code),
257
-					// we also check the default phone region of the instance,
258
-					// when it's different to the user's given region.
259
-					try {
260
-						$phoneNumber = $phoneUtil->parse($phone, $defaultPhoneRegion);
261
-						if ($phoneNumber instanceof PhoneNumber && $phoneUtil->isValidNumber($phoneNumber)) {
262
-							$normalizedNumber = $phoneUtil->format($phoneNumber, PhoneNumberFormat::E164);
263
-							$normalizedNumberToKey[$normalizedNumber] = (string) $key;
264
-						}
265
-					} catch (NumberParseException $e) {
266
-					}
267
-				}
268
-			}
269
-		}
270
-
271
-		$phoneNumbers = array_keys($normalizedNumberToKey);
272
-
273
-		if (empty($phoneNumbers)) {
274
-			return new DataResponse();
275
-		}
276
-
277
-		// Cleanup all previous entries and only allow new matches
278
-		$this->knownUserService->deleteKnownTo($knownTo);
279
-
280
-		$userMatches = $this->accountManager->searchUsers(IAccountManager::PROPERTY_PHONE, $phoneNumbers);
281
-
282
-		if (empty($userMatches)) {
283
-			return new DataResponse();
284
-		}
285
-
286
-		$cloudUrl = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/');
287
-		if (strpos($cloudUrl, 'http://') === 0) {
288
-			$cloudUrl = substr($cloudUrl, strlen('http://'));
289
-		} elseif (strpos($cloudUrl, 'https://') === 0) {
290
-			$cloudUrl = substr($cloudUrl, strlen('https://'));
291
-		}
292
-
293
-		$matches = [];
294
-		foreach ($userMatches as $phone => $userId) {
295
-			// Not using the ICloudIdManager as that would run a search for each contact to find the display name in the address book
296
-			$matches[$normalizedNumberToKey[$phone]] = $userId . '@' . $cloudUrl;
297
-			$this->knownUserService->storeIsKnownToUser($knownTo, $userId);
298
-		}
299
-
300
-		return new DataResponse($matches);
301
-	}
302
-
303
-	/**
304
-	 * @throws OCSException
305
-	 */
306
-	private function createNewUserId(): string {
307
-		$attempts = 0;
308
-		do {
309
-			$uidCandidate = $this->secureRandom->generate(10, ISecureRandom::CHAR_HUMAN_READABLE);
310
-			if (!$this->userManager->userExists($uidCandidate)) {
311
-				return $uidCandidate;
312
-			}
313
-			$attempts++;
314
-		} while ($attempts < 10);
315
-		throw new OCSException('Could not create non-existing user id', 111);
316
-	}
317
-
318
-	/**
319
-	 * @PasswordConfirmationRequired
320
-	 * @NoAdminRequired
321
-	 *
322
-	 * @param string $userid
323
-	 * @param string $password
324
-	 * @param string $displayName
325
-	 * @param string $email
326
-	 * @param array $groups
327
-	 * @param array $subadmin
328
-	 * @param string $quota
329
-	 * @param string $language
330
-	 * @return DataResponse
331
-	 * @throws OCSException
332
-	 */
333
-	public function addUser(
334
-		string $userid,
335
-		string $password = '',
336
-		string $displayName = '',
337
-		string $email = '',
338
-		array $groups = [],
339
-		array $subadmin = [],
340
-		string $quota = '',
341
-		string $language = '',
342
-		?string $manager = null,
343
-	): DataResponse {
344
-		$user = $this->userSession->getUser();
345
-		$isAdmin = $this->groupManager->isAdmin($user->getUID());
346
-		$subAdminManager = $this->groupManager->getSubAdmin();
347
-
348
-		if (empty($userid) && $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes') {
349
-			$userid = $this->createNewUserId();
350
-		}
351
-
352
-		if ($this->userManager->userExists($userid)) {
353
-			$this->logger->error('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']);
354
-			throw new OCSException($this->l10nFactory->get('provisioning_api')->t('User already exists'), 102);
355
-		}
356
-
357
-		if ($groups !== []) {
358
-			foreach ($groups as $group) {
359
-				if (!$this->groupManager->groupExists($group)) {
360
-					throw new OCSException('group ' . $group . ' does not exist', 104);
361
-				}
362
-				if (!$isAdmin && !$subAdminManager->isSubAdminOfGroup($user, $this->groupManager->get($group))) {
363
-					throw new OCSException('insufficient privileges for group ' . $group, 105);
364
-				}
365
-			}
366
-		} else {
367
-			if (!$isAdmin) {
368
-				throw new OCSException('no group specified (required for subadmins)', 106);
369
-			}
370
-		}
371
-
372
-		$subadminGroups = [];
373
-		if ($subadmin !== []) {
374
-			foreach ($subadmin as $groupid) {
375
-				$group = $this->groupManager->get($groupid);
376
-				// Check if group exists
377
-				if ($group === null) {
378
-					throw new OCSException('Subadmin group does not exist', 102);
379
-				}
380
-				// Check if trying to make subadmin of admin group
381
-				if ($group->getGID() === 'admin') {
382
-					throw new OCSException('Cannot create subadmins for admin group', 103);
383
-				}
384
-				// Check if has permission to promote subadmins
385
-				if (!$subAdminManager->isSubAdminOfGroup($user, $group) && !$isAdmin) {
386
-					throw new OCSForbiddenException('No permissions to promote subadmins');
387
-				}
388
-				$subadminGroups[] = $group;
389
-			}
390
-		}
391
-
392
-		$generatePasswordResetToken = false;
393
-		if (strlen($password) > IUserManager::MAX_PASSWORD_LENGTH) {
394
-			throw new OCSException('Invalid password value', 101);
395
-		}
396
-		if ($password === '') {
397
-			if ($email === '') {
398
-				throw new OCSException('To send a password link to the user an email address is required.', 108);
399
-			}
400
-
401
-			$passwordEvent = new GenerateSecurePasswordEvent();
402
-			$this->eventDispatcher->dispatchTyped($passwordEvent);
403
-
404
-			$password = $passwordEvent->getPassword();
405
-			if ($password === null) {
406
-				// Fallback: ensure to pass password_policy in any case
407
-				$password = $this->secureRandom->generate(10)
408
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_UPPER)
409
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_LOWER)
410
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_DIGITS)
411
-					. $this->secureRandom->generate(1, ISecureRandom::CHAR_SYMBOLS);
412
-			}
413
-			$generatePasswordResetToken = true;
414
-		}
415
-
416
-		if ($email === '' && $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes') {
417
-			throw new OCSException('Required email address was not provided', 110);
418
-		}
419
-
420
-		try {
421
-			$newUser = $this->userManager->createUser($userid, $password);
422
-			$this->logger->info('Successful addUser call with userid: ' . $userid, ['app' => 'ocs_api']);
423
-
424
-			foreach ($groups as $group) {
425
-				$this->groupManager->get($group)->addUser($newUser);
426
-				$this->logger->info('Added userid ' . $userid . ' to group ' . $group, ['app' => 'ocs_api']);
427
-			}
428
-			foreach ($subadminGroups as $group) {
429
-				$subAdminManager->createSubAdmin($newUser, $group);
430
-			}
431
-
432
-			if ($displayName !== '') {
433
-				try {
434
-					$this->editUser($userid, self::USER_FIELD_DISPLAYNAME, $displayName);
435
-				} catch (OCSException $e) {
436
-					if ($newUser instanceof IUser) {
437
-						$newUser->delete();
438
-					}
439
-					throw $e;
440
-				}
441
-			}
442
-
443
-			if ($quota !== '') {
444
-				$this->editUser($userid, self::USER_FIELD_QUOTA, $quota);
445
-			}
446
-
447
-			if ($language !== '') {
448
-				$this->editUser($userid, self::USER_FIELD_LANGUAGE, $language);
449
-			}
450
-
451
-			/**
452
-			 * null -> nothing sent
453
-			 * '' -> unset manager
454
-			 * else -> set manager
455
-			 */
456
-			if ($manager !== null) {
457
-				$this->editUser($userid, self::USER_FIELD_MANAGER, $manager);
458
-			}
459
-
460
-			// Send new user mail only if a mail is set
461
-			if ($email !== '') {
462
-				$newUser->setEMailAddress($email);
463
-				if ($this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes') {
464
-					try {
465
-						$emailTemplate = $this->newUserMailHelper->generateTemplate($newUser, $generatePasswordResetToken);
466
-						$this->newUserMailHelper->sendMail($newUser, $emailTemplate);
467
-					} catch (\Exception $e) {
468
-						// Mail could be failing hard or just be plain not configured
469
-						// Logging error as it is the hardest of the two
470
-						$this->logger->error(
471
-							"Unable to send the invitation mail to $email",
472
-							[
473
-								'app' => 'ocs_api',
474
-								'exception' => $e,
475
-							]
476
-						);
477
-					}
478
-				}
479
-			}
480
-
481
-			return new DataResponse(['id' => $userid]);
482
-		} catch (HintException $e) {
483
-			$this->logger->warning(
484
-				'Failed addUser attempt with hint exception.',
485
-				[
486
-					'app' => 'ocs_api',
487
-					'exception' => $e,
488
-				]
489
-			);
490
-			throw new OCSException($e->getHint(), 107);
491
-		} catch (OCSException $e) {
492
-			$this->logger->warning(
493
-				'Failed addUser attempt with ocs exception.',
494
-				[
495
-					'app' => 'ocs_api',
496
-					'exception' => $e,
497
-				]
498
-			);
499
-			throw $e;
500
-		} catch (InvalidArgumentException $e) {
501
-			$this->logger->error(
502
-				'Failed addUser attempt with invalid argument exception.',
503
-				[
504
-					'app' => 'ocs_api',
505
-					'exception' => $e,
506
-				]
507
-			);
508
-			throw new OCSException($e->getMessage(), 101);
509
-		} catch (\Exception $e) {
510
-			$this->logger->error(
511
-				'Failed addUser attempt with exception.',
512
-				[
513
-					'app' => 'ocs_api',
514
-					'exception' => $e
515
-				]
516
-			);
517
-			throw new OCSException('Bad request', 101);
518
-		}
519
-	}
520
-
521
-	/**
522
-	 * @NoAdminRequired
523
-	 * @NoSubAdminRequired
524
-	 *
525
-	 * gets user info
526
-	 *
527
-	 * @param string $userId
528
-	 * @return DataResponse
529
-	 * @throws OCSException
530
-	 */
531
-	public function getUser(string $userId): DataResponse {
532
-		$includeScopes = false;
533
-		$currentUser = $this->userSession->getUser();
534
-		if ($currentUser && $currentUser->getUID() === $userId) {
535
-			$includeScopes = true;
536
-		}
537
-
538
-		$data = $this->getUserData($userId, $includeScopes);
539
-		// getUserData returns empty array if not enough permissions
540
-		if (empty($data)) {
541
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
542
-		}
543
-		return new DataResponse($data);
544
-	}
545
-
546
-	/**
547
-	 * @NoAdminRequired
548
-	 * @NoSubAdminRequired
549
-	 *
550
-	 * gets user info from the currently logged in user
551
-	 *
552
-	 * @return DataResponse
553
-	 * @throws OCSException
554
-	 */
555
-	public function getCurrentUser(): DataResponse {
556
-		$user = $this->userSession->getUser();
557
-		if ($user) {
558
-			$data = $this->getUserData($user->getUID(), true);
559
-			return new DataResponse($data);
560
-		}
561
-
562
-		throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
563
-	}
564
-
565
-	/**
566
-	 * @NoAdminRequired
567
-	 * @NoSubAdminRequired
568
-	 *
569
-	 * @return DataResponse
570
-	 * @throws OCSException
571
-	 */
572
-	public function getEditableFields(): DataResponse {
573
-		$currentLoggedInUser = $this->userSession->getUser();
574
-		if (!$currentLoggedInUser instanceof IUser) {
575
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
576
-		}
577
-
578
-		return $this->getEditableFieldsForUser($currentLoggedInUser->getUID());
579
-	}
580
-
581
-	/**
582
-	 * @NoAdminRequired
583
-	 * @NoSubAdminRequired
584
-	 *
585
-	 * @param string $userId
586
-	 * @return DataResponse
587
-	 * @throws OCSException
588
-	 */
589
-	public function getEditableFieldsForUser(string $userId): DataResponse {
590
-		$currentLoggedInUser = $this->userSession->getUser();
591
-		if (!$currentLoggedInUser instanceof IUser) {
592
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
593
-		}
594
-
595
-		$permittedFields = [];
596
-
597
-		if ($userId !== $currentLoggedInUser->getUID()) {
598
-			$targetUser = $this->userManager->get($userId);
599
-			if (!$targetUser instanceof IUser) {
600
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
601
-			}
602
-
603
-			$subAdminManager = $this->groupManager->getSubAdmin();
604
-			if (
605
-				!$this->groupManager->isAdmin($currentLoggedInUser->getUID())
606
-				&& !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
607
-			) {
608
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
609
-			}
610
-		} else {
611
-			$targetUser = $currentLoggedInUser;
612
-		}
613
-
614
-		// Editing self (display, email)
615
-		if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
616
-			if (
617
-				$targetUser->getBackend() instanceof ISetDisplayNameBackend
618
-				|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
619
-			) {
620
-				$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
621
-			}
622
-			$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
623
-		}
624
-
625
-		$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
626
-		$permittedFields[] = IAccountManager::PROPERTY_PHONE;
627
-		$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
628
-		$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
629
-		$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
630
-		$permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
631
-		$permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
632
-		$permittedFields[] = IAccountManager::PROPERTY_ROLE;
633
-		$permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
634
-		$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
635
-		$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
636
-
637
-		return new DataResponse($permittedFields);
638
-	}
639
-
640
-	/**
641
-	 * @NoAdminRequired
642
-	 * @NoSubAdminRequired
643
-	 * @PasswordConfirmationRequired
644
-	 * @UserRateThrottle(limit=5, period=60)
645
-	 *
646
-	 * @throws OCSException
647
-	 */
648
-	public function editUserMultiValue(
649
-		string $userId,
650
-		string $collectionName,
651
-		string $key,
652
-		string $value
653
-	): DataResponse {
654
-		$currentLoggedInUser = $this->userSession->getUser();
655
-		if ($currentLoggedInUser === null) {
656
-			throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
657
-		}
658
-
659
-		$targetUser = $this->userManager->get($userId);
660
-		if ($targetUser === null) {
661
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
662
-		}
663
-
664
-		$subAdminManager = $this->groupManager->getSubAdmin();
665
-		$isAdminOrSubadmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID())
666
-			|| $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser);
667
-
668
-		$permittedFields = [];
669
-		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
670
-			// Editing self (display, email)
671
-			$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
672
-			$permittedFields[] = IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX;
673
-		} else {
674
-			// Check if admin / subadmin
675
-			if ($isAdminOrSubadmin) {
676
-				// They have permissions over the user
677
-				$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
678
-			} else {
679
-				// No rights
680
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
681
-			}
682
-		}
683
-
684
-		// Check if permitted to edit this field
685
-		if (!in_array($collectionName, $permittedFields)) {
686
-			throw new OCSException('', 103);
687
-		}
688
-
689
-		switch ($collectionName) {
690
-			case IAccountManager::COLLECTION_EMAIL:
691
-				$userAccount = $this->accountManager->getAccount($targetUser);
692
-				$mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
693
-				$mailCollection->removePropertyByValue($key);
694
-				if ($value !== '') {
695
-					$mailCollection->addPropertyWithDefaults($value);
696
-					$property = $mailCollection->getPropertyByValue($key);
697
-					if ($isAdminOrSubadmin && $property) {
698
-						// admin set mails are auto-verified
699
-						$property->setLocallyVerified(IAccountManager::VERIFIED);
700
-					}
701
-				}
702
-				$this->accountManager->updateAccount($userAccount);
703
-				break;
704
-
705
-			case IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX:
706
-				$userAccount = $this->accountManager->getAccount($targetUser);
707
-				$mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
708
-				$targetProperty = null;
709
-				foreach ($mailCollection->getProperties() as $property) {
710
-					if ($property->getValue() === $key) {
711
-						$targetProperty = $property;
712
-						break;
713
-					}
714
-				}
715
-				if ($targetProperty instanceof IAccountProperty) {
716
-					try {
717
-						$targetProperty->setScope($value);
718
-						$this->accountManager->updateAccount($userAccount);
719
-					} catch (InvalidArgumentException $e) {
720
-						throw new OCSException('', 102);
721
-					}
722
-				} else {
723
-					throw new OCSException('', 102);
724
-				}
725
-				break;
726
-
727
-			default:
728
-				throw new OCSException('', 103);
729
-		}
730
-		return new DataResponse();
731
-	}
732
-
733
-	/**
734
-	 * @NoAdminRequired
735
-	 * @NoSubAdminRequired
736
-	 * @PasswordConfirmationRequired
737
-	 * @UserRateThrottle(limit=50, period=600)
738
-	 *
739
-	 * edit users
740
-	 *
741
-	 * @param string $userId
742
-	 * @param string $key
743
-	 * @param string $value
744
-	 * @return DataResponse
745
-	 * @throws OCSException
746
-	 */
747
-	public function editUser(string $userId, string $key, string $value): DataResponse {
748
-		$currentLoggedInUser = $this->userSession->getUser();
749
-
750
-		$targetUser = $this->userManager->get($userId);
751
-		if ($targetUser === null) {
752
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
753
-		}
754
-
755
-		$permittedFields = [];
756
-		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
757
-			// Editing self (display, email)
758
-			if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
759
-				if (
760
-					$targetUser->getBackend() instanceof ISetDisplayNameBackend
761
-					|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
762
-				) {
763
-					$permittedFields[] = self::USER_FIELD_DISPLAYNAME;
764
-					$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
765
-				}
766
-				$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
767
-			}
768
-
769
-			$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX;
770
-			$permittedFields[] = IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX;
771
-
772
-			$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
773
-
774
-			$permittedFields[] = self::USER_FIELD_PASSWORD;
775
-			$permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
776
-			if (
777
-				$this->config->getSystemValue('force_language', false) === false ||
778
-				$this->groupManager->isAdmin($currentLoggedInUser->getUID())
779
-			) {
780
-				$permittedFields[] = self::USER_FIELD_LANGUAGE;
781
-			}
782
-
783
-			if (
784
-				$this->config->getSystemValue('force_locale', false) === false ||
785
-				$this->groupManager->isAdmin($currentLoggedInUser->getUID())
786
-			) {
787
-				$permittedFields[] = self::USER_FIELD_LOCALE;
788
-			}
789
-
790
-			$permittedFields[] = IAccountManager::PROPERTY_PHONE;
791
-			$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
792
-			$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
793
-			$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
794
-			$permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
795
-			$permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
796
-			$permittedFields[] = IAccountManager::PROPERTY_ROLE;
797
-			$permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
798
-			$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
799
-			$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
800
-			$permittedFields[] = IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX;
801
-			$permittedFields[] = IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX;
802
-			$permittedFields[] = IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX;
803
-			$permittedFields[] = IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX;
804
-			$permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE . self::SCOPE_SUFFIX;
805
-			$permittedFields[] = IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX;
806
-			$permittedFields[] = IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX;
807
-			$permittedFields[] = IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX;
808
-			$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX;
809
-			$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX;
810
-
811
-			$permittedFields[] = IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX;
812
-
813
-			// If admin they can edit their own quota and manager
814
-			if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
815
-				$permittedFields[] = self::USER_FIELD_QUOTA;
816
-				$permittedFields[] = self::USER_FIELD_MANAGER;
817
-
818
-			}
819
-		} else {
820
-			// Check if admin / subadmin
821
-			$subAdminManager = $this->groupManager->getSubAdmin();
822
-			if (
823
-				$this->groupManager->isAdmin($currentLoggedInUser->getUID())
824
-				|| $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
825
-			) {
826
-				// They have permissions over the user
827
-				if (
828
-					$targetUser->getBackend() instanceof ISetDisplayNameBackend
829
-					|| $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
830
-				) {
831
-					$permittedFields[] = self::USER_FIELD_DISPLAYNAME;
832
-					$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
833
-				}
834
-				$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
835
-				$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
836
-				$permittedFields[] = self::USER_FIELD_PASSWORD;
837
-				$permittedFields[] = self::USER_FIELD_LANGUAGE;
838
-				$permittedFields[] = self::USER_FIELD_LOCALE;
839
-				$permittedFields[] = IAccountManager::PROPERTY_PHONE;
840
-				$permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
841
-				$permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
842
-				$permittedFields[] = IAccountManager::PROPERTY_TWITTER;
843
-				$permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
844
-				$permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
845
-				$permittedFields[] = IAccountManager::PROPERTY_ROLE;
846
-				$permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
847
-				$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
848
-				$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
849
-				$permittedFields[] = self::USER_FIELD_QUOTA;
850
-				$permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
851
-				$permittedFields[] = self::USER_FIELD_MANAGER;
852
-			} else {
853
-				// No rights
854
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
855
-			}
856
-		}
857
-		// Check if permitted to edit this field
858
-		if (!in_array($key, $permittedFields)) {
859
-			throw new OCSException('', 103);
860
-		}
861
-		// Process the edit
862
-		switch ($key) {
863
-			case self::USER_FIELD_DISPLAYNAME:
864
-			case IAccountManager::PROPERTY_DISPLAYNAME:
865
-				try {
866
-					$targetUser->setDisplayName($value);
867
-				} catch (InvalidArgumentException $e) {
868
-					throw new OCSException($e->getMessage(), 101);
869
-				}
870
-				break;
871
-			case self::USER_FIELD_QUOTA:
872
-				$quota = $value;
873
-				if ($quota !== 'none' && $quota !== 'default') {
874
-					if (is_numeric($quota)) {
875
-						$quota = (float) $quota;
876
-					} else {
877
-						$quota = \OCP\Util::computerFileSize($quota);
878
-					}
879
-					if ($quota === false) {
880
-						throw new OCSException('Invalid quota value ' . $value, 102);
881
-					}
882
-					if ($quota === -1) {
883
-						$quota = 'none';
884
-					} else {
885
-						$maxQuota = (int) $this->config->getAppValue('files', 'max_quota', '-1');
886
-						if ($maxQuota !== -1 && $quota > $maxQuota) {
887
-							throw new OCSException('Invalid quota value. ' . $value . ' is exceeding the maximum quota', 102);
888
-						}
889
-						$quota = \OCP\Util::humanFileSize($quota);
890
-					}
891
-				}
892
-				// no else block because quota can be set to 'none' in previous if
893
-				if ($quota === 'none') {
894
-					$allowUnlimitedQuota = $this->config->getAppValue('files', 'allow_unlimited_quota', '1') === '1';
895
-					if (!$allowUnlimitedQuota) {
896
-						throw new OCSException('Unlimited quota is forbidden on this instance', 102);
897
-					}
898
-				}
899
-				$targetUser->setQuota($quota);
900
-				break;
901
-			case self::USER_FIELD_MANAGER:
902
-				$targetUser->setManagerUids([$value]);
903
-				break;
904
-			case self::USER_FIELD_PASSWORD:
905
-				try {
906
-					if (strlen($value) > IUserManager::MAX_PASSWORD_LENGTH) {
907
-						throw new OCSException('Invalid password value', 102);
908
-					}
909
-					if (!$targetUser->canChangePassword()) {
910
-						throw new OCSException('Setting the password is not supported by the users backend', 103);
911
-					}
912
-					$targetUser->setPassword($value);
913
-				} catch (HintException $e) { // password policy error
914
-					throw new OCSException($e->getMessage(), 103);
915
-				}
916
-				break;
917
-			case self::USER_FIELD_LANGUAGE:
918
-				$languagesCodes = $this->l10nFactory->findAvailableLanguages();
919
-				if (!in_array($value, $languagesCodes, true) && $value !== 'en') {
920
-					throw new OCSException('Invalid language', 102);
921
-				}
922
-				$this->config->setUserValue($targetUser->getUID(), 'core', 'lang', $value);
923
-				break;
924
-			case self::USER_FIELD_LOCALE:
925
-				if (!$this->l10nFactory->localeExists($value)) {
926
-					throw new OCSException('Invalid locale', 102);
927
-				}
928
-				$this->config->setUserValue($targetUser->getUID(), 'core', 'locale', $value);
929
-				break;
930
-			case self::USER_FIELD_NOTIFICATION_EMAIL:
931
-				$success = false;
932
-				if ($value === '' || filter_var($value, FILTER_VALIDATE_EMAIL)) {
933
-					try {
934
-						$targetUser->setPrimaryEMailAddress($value);
935
-						$success = true;
936
-					} catch (InvalidArgumentException $e) {
937
-						$this->logger->info(
938
-							'Cannot set primary email, because provided address is not verified',
939
-							[
940
-								'app' => 'provisioning_api',
941
-								'exception' => $e,
942
-							]
943
-						);
944
-					}
945
-				}
946
-				if (!$success) {
947
-					throw new OCSException('', 102);
948
-				}
949
-				break;
950
-			case IAccountManager::PROPERTY_EMAIL:
951
-				if (filter_var($value, FILTER_VALIDATE_EMAIL) || $value === '') {
952
-					$targetUser->setEMailAddress($value);
953
-				} else {
954
-					throw new OCSException('', 102);
955
-				}
956
-				break;
957
-			case IAccountManager::COLLECTION_EMAIL:
958
-				if (filter_var($value, FILTER_VALIDATE_EMAIL) && $value !== $targetUser->getSystemEMailAddress()) {
959
-					$userAccount = $this->accountManager->getAccount($targetUser);
960
-					$mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
961
-
962
-					if ($mailCollection->getPropertyByValue($value)) {
963
-						throw new OCSException('', 102);
964
-					}
965
-
966
-					$mailCollection->addPropertyWithDefaults($value);
967
-					$this->accountManager->updateAccount($userAccount);
968
-				} else {
969
-					throw new OCSException('', 102);
970
-				}
971
-				break;
972
-			case IAccountManager::PROPERTY_PHONE:
973
-			case IAccountManager::PROPERTY_ADDRESS:
974
-			case IAccountManager::PROPERTY_WEBSITE:
975
-			case IAccountManager::PROPERTY_TWITTER:
976
-			case IAccountManager::PROPERTY_FEDIVERSE:
977
-			case IAccountManager::PROPERTY_ORGANISATION:
978
-			case IAccountManager::PROPERTY_ROLE:
979
-			case IAccountManager::PROPERTY_HEADLINE:
980
-			case IAccountManager::PROPERTY_BIOGRAPHY:
981
-				$userAccount = $this->accountManager->getAccount($targetUser);
982
-				try {
983
-					$userProperty = $userAccount->getProperty($key);
984
-					if ($userProperty->getValue() !== $value) {
985
-						try {
986
-							$userProperty->setValue($value);
987
-							if ($userProperty->getName() === IAccountManager::PROPERTY_PHONE) {
988
-								$this->knownUserService->deleteByContactUserId($targetUser->getUID());
989
-							}
990
-						} catch (InvalidArgumentException $e) {
991
-							throw new OCSException('Invalid ' . $e->getMessage(), 102);
992
-						}
993
-					}
994
-				} catch (PropertyDoesNotExistException $e) {
995
-					$userAccount->setProperty($key, $value, IAccountManager::SCOPE_PRIVATE, IAccountManager::NOT_VERIFIED);
996
-				}
997
-				try {
998
-					$this->accountManager->updateAccount($userAccount);
999
-				} catch (InvalidArgumentException $e) {
1000
-					throw new OCSException('Invalid ' . $e->getMessage(), 102);
1001
-				}
1002
-				break;
1003
-			case IAccountManager::PROPERTY_PROFILE_ENABLED:
1004
-				$userAccount = $this->accountManager->getAccount($targetUser);
1005
-				try {
1006
-					$userProperty = $userAccount->getProperty($key);
1007
-					if ($userProperty->getValue() !== $value) {
1008
-						$userProperty->setValue($value);
1009
-					}
1010
-				} catch (PropertyDoesNotExistException $e) {
1011
-					$userAccount->setProperty($key, $value, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
1012
-				}
1013
-				$this->accountManager->updateAccount($userAccount);
1014
-				break;
1015
-			case IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX:
1016
-			case IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX:
1017
-			case IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX:
1018
-			case IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX:
1019
-			case IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX:
1020
-			case IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX:
1021
-			case IAccountManager::PROPERTY_FEDIVERSE . self::SCOPE_SUFFIX:
1022
-			case IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX:
1023
-			case IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX:
1024
-			case IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX:
1025
-			case IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX:
1026
-			case IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX:
1027
-			case IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX:
1028
-				$propertyName = substr($key, 0, strlen($key) - strlen(self::SCOPE_SUFFIX));
1029
-				$userAccount = $this->accountManager->getAccount($targetUser);
1030
-				$userProperty = $userAccount->getProperty($propertyName);
1031
-				if ($userProperty->getScope() !== $value) {
1032
-					try {
1033
-						$userProperty->setScope($value);
1034
-						$this->accountManager->updateAccount($userAccount);
1035
-					} catch (InvalidArgumentException $e) {
1036
-						throw new OCSException('Invalid ' . $e->getMessage(), 102);
1037
-					}
1038
-				}
1039
-				break;
1040
-			default:
1041
-				throw new OCSException('', 103);
1042
-		}
1043
-		return new DataResponse();
1044
-	}
1045
-
1046
-	/**
1047
-	 * @PasswordConfirmationRequired
1048
-	 * @NoAdminRequired
1049
-	 *
1050
-	 * @param string $userId
1051
-	 *
1052
-	 * @return DataResponse
1053
-	 *
1054
-	 * @throws OCSException
1055
-	 */
1056
-	public function wipeUserDevices(string $userId): DataResponse {
1057
-		/** @var IUser $currentLoggedInUser */
1058
-		$currentLoggedInUser = $this->userSession->getUser();
1059
-
1060
-		$targetUser = $this->userManager->get($userId);
1061
-
1062
-		if ($targetUser === null) {
1063
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1064
-		}
1065
-
1066
-		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
1067
-			throw new OCSException('', 101);
1068
-		}
1069
-
1070
-		// If not permitted
1071
-		$subAdminManager = $this->groupManager->getSubAdmin();
1072
-		if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
1073
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1074
-		}
1075
-
1076
-		$this->remoteWipe->markAllTokensForWipe($targetUser);
1077
-
1078
-		return new DataResponse();
1079
-	}
1080
-
1081
-	/**
1082
-	 * @PasswordConfirmationRequired
1083
-	 * @NoAdminRequired
1084
-	 *
1085
-	 * @param string $userId
1086
-	 * @return DataResponse
1087
-	 * @throws OCSException
1088
-	 */
1089
-	public function deleteUser(string $userId): DataResponse {
1090
-		$currentLoggedInUser = $this->userSession->getUser();
1091
-
1092
-		$targetUser = $this->userManager->get($userId);
1093
-
1094
-		if ($targetUser === null) {
1095
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1096
-		}
1097
-
1098
-		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
1099
-			throw new OCSException('', 101);
1100
-		}
1101
-
1102
-		// If not permitted
1103
-		$subAdminManager = $this->groupManager->getSubAdmin();
1104
-		if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
1105
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1106
-		}
1107
-
1108
-		// Go ahead with the delete
1109
-		if ($targetUser->delete()) {
1110
-			return new DataResponse();
1111
-		} else {
1112
-			throw new OCSException('', 101);
1113
-		}
1114
-	}
1115
-
1116
-	/**
1117
-	 * @PasswordConfirmationRequired
1118
-	 * @NoAdminRequired
1119
-	 *
1120
-	 * @param string $userId
1121
-	 * @return DataResponse
1122
-	 * @throws OCSException
1123
-	 * @throws OCSForbiddenException
1124
-	 */
1125
-	public function disableUser(string $userId): DataResponse {
1126
-		return $this->setEnabled($userId, false);
1127
-	}
1128
-
1129
-	/**
1130
-	 * @PasswordConfirmationRequired
1131
-	 * @NoAdminRequired
1132
-	 *
1133
-	 * @param string $userId
1134
-	 * @return DataResponse
1135
-	 * @throws OCSException
1136
-	 * @throws OCSForbiddenException
1137
-	 */
1138
-	public function enableUser(string $userId): DataResponse {
1139
-		return $this->setEnabled($userId, true);
1140
-	}
1141
-
1142
-	/**
1143
-	 * @param string $userId
1144
-	 * @param bool $value
1145
-	 * @return DataResponse
1146
-	 * @throws OCSException
1147
-	 */
1148
-	private function setEnabled(string $userId, bool $value): DataResponse {
1149
-		$currentLoggedInUser = $this->userSession->getUser();
1150
-
1151
-		$targetUser = $this->userManager->get($userId);
1152
-		if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
1153
-			throw new OCSException('', 101);
1154
-		}
1155
-
1156
-		// If not permitted
1157
-		$subAdminManager = $this->groupManager->getSubAdmin();
1158
-		if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
1159
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1160
-		}
1161
-
1162
-		// enable/disable the user now
1163
-		$targetUser->setEnabled($value);
1164
-		return new DataResponse();
1165
-	}
1166
-
1167
-	/**
1168
-	 * @NoAdminRequired
1169
-	 * @NoSubAdminRequired
1170
-	 *
1171
-	 * @param string $userId
1172
-	 * @return DataResponse
1173
-	 * @throws OCSException
1174
-	 */
1175
-	public function getUsersGroups(string $userId): DataResponse {
1176
-		$loggedInUser = $this->userSession->getUser();
1177
-
1178
-		$targetUser = $this->userManager->get($userId);
1179
-		if ($targetUser === null) {
1180
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1181
-		}
1182
-
1183
-		if ($targetUser->getUID() === $loggedInUser->getUID() || $this->groupManager->isAdmin($loggedInUser->getUID())) {
1184
-			// Self lookup or admin lookup
1185
-			return new DataResponse([
1186
-				'groups' => $this->groupManager->getUserGroupIds($targetUser)
1187
-			]);
1188
-		} else {
1189
-			$subAdminManager = $this->groupManager->getSubAdmin();
1190
-
1191
-			// Looking up someone else
1192
-			if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
1193
-				// Return the group that the method caller is subadmin of for the user in question
1194
-				/** @var IGroup[] $getSubAdminsGroups */
1195
-				$getSubAdminsGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
1196
-				foreach ($getSubAdminsGroups as $key => $group) {
1197
-					$getSubAdminsGroups[$key] = $group->getGID();
1198
-				}
1199
-				$groups = array_intersect(
1200
-					$getSubAdminsGroups,
1201
-					$this->groupManager->getUserGroupIds($targetUser)
1202
-				);
1203
-				return new DataResponse(['groups' => $groups]);
1204
-			} else {
1205
-				// Not permitted
1206
-				throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1207
-			}
1208
-		}
1209
-	}
1210
-
1211
-	/**
1212
-	 * @PasswordConfirmationRequired
1213
-	 * @NoAdminRequired
1214
-	 *
1215
-	 * @param string $userId
1216
-	 * @param string $groupid
1217
-	 * @return DataResponse
1218
-	 * @throws OCSException
1219
-	 */
1220
-	public function addToGroup(string $userId, string $groupid = ''): DataResponse {
1221
-		if ($groupid === '') {
1222
-			throw new OCSException('', 101);
1223
-		}
1224
-
1225
-		$group = $this->groupManager->get($groupid);
1226
-		$targetUser = $this->userManager->get($userId);
1227
-		if ($group === null) {
1228
-			throw new OCSException('', 102);
1229
-		}
1230
-		if ($targetUser === null) {
1231
-			throw new OCSException('', 103);
1232
-		}
1233
-
1234
-		// If they're not an admin, check they are a subadmin of the group in question
1235
-		$loggedInUser = $this->userSession->getUser();
1236
-		$subAdminManager = $this->groupManager->getSubAdmin();
1237
-		if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
1238
-			throw new OCSException('', 104);
1239
-		}
1240
-
1241
-		// Add user to group
1242
-		$group->addUser($targetUser);
1243
-		return new DataResponse();
1244
-	}
1245
-
1246
-	/**
1247
-	 * @PasswordConfirmationRequired
1248
-	 * @NoAdminRequired
1249
-	 *
1250
-	 * @param string $userId
1251
-	 * @param string $groupid
1252
-	 * @return DataResponse
1253
-	 * @throws OCSException
1254
-	 */
1255
-	public function removeFromGroup(string $userId, string $groupid): DataResponse {
1256
-		$loggedInUser = $this->userSession->getUser();
1257
-
1258
-		if ($groupid === null || trim($groupid) === '') {
1259
-			throw new OCSException('', 101);
1260
-		}
1261
-
1262
-		$group = $this->groupManager->get($groupid);
1263
-		if ($group === null) {
1264
-			throw new OCSException('', 102);
1265
-		}
1266
-
1267
-		$targetUser = $this->userManager->get($userId);
1268
-		if ($targetUser === null) {
1269
-			throw new OCSException('', 103);
1270
-		}
1271
-
1272
-		// If they're not an admin, check they are a subadmin of the group in question
1273
-		$subAdminManager = $this->groupManager->getSubAdmin();
1274
-		if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
1275
-			throw new OCSException('', 104);
1276
-		}
1277
-
1278
-		// Check they aren't removing themselves from 'admin' or their 'subadmin; group
1279
-		if ($targetUser->getUID() === $loggedInUser->getUID()) {
1280
-			if ($this->groupManager->isAdmin($loggedInUser->getUID())) {
1281
-				if ($group->getGID() === 'admin') {
1282
-					throw new OCSException('Cannot remove yourself from the admin group', 105);
1283
-				}
1284
-			} else {
1285
-				// Not an admin, so the user must be a subadmin of this group, but that is not allowed.
1286
-				throw new OCSException('Cannot remove yourself from this group as you are a SubAdmin', 105);
1287
-			}
1288
-		} elseif (!$this->groupManager->isAdmin($loggedInUser->getUID())) {
1289
-			/** @var IGroup[] $subAdminGroups */
1290
-			$subAdminGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
1291
-			$subAdminGroups = array_map(function (IGroup $subAdminGroup) {
1292
-				return $subAdminGroup->getGID();
1293
-			}, $subAdminGroups);
1294
-			$userGroups = $this->groupManager->getUserGroupIds($targetUser);
1295
-			$userSubAdminGroups = array_intersect($subAdminGroups, $userGroups);
1296
-
1297
-			if (count($userSubAdminGroups) <= 1) {
1298
-				// Subadmin must not be able to remove a user from all their subadmin groups.
1299
-				throw new OCSException('Not viable to remove user from the last group you are SubAdmin of', 105);
1300
-			}
1301
-		}
1302
-
1303
-		// Remove user from group
1304
-		$group->removeUser($targetUser);
1305
-		return new DataResponse();
1306
-	}
1307
-
1308
-	/**
1309
-	 * Creates a subadmin
1310
-	 *
1311
-	 * @PasswordConfirmationRequired
1312
-	 *
1313
-	 * @param string $userId
1314
-	 * @param string $groupid
1315
-	 * @return DataResponse
1316
-	 * @throws OCSException
1317
-	 */
1318
-	public function addSubAdmin(string $userId, string $groupid): DataResponse {
1319
-		$group = $this->groupManager->get($groupid);
1320
-		$user = $this->userManager->get($userId);
1321
-
1322
-		// Check if the user exists
1323
-		if ($user === null) {
1324
-			throw new OCSException('User does not exist', 101);
1325
-		}
1326
-		// Check if group exists
1327
-		if ($group === null) {
1328
-			throw new OCSException('Group does not exist', 102);
1329
-		}
1330
-		// Check if trying to make subadmin of admin group
1331
-		if ($group->getGID() === 'admin') {
1332
-			throw new OCSException('Cannot create subadmins for admin group', 103);
1333
-		}
1334
-
1335
-		$subAdminManager = $this->groupManager->getSubAdmin();
1336
-
1337
-		// We cannot be subadmin twice
1338
-		if ($subAdminManager->isSubAdminOfGroup($user, $group)) {
1339
-			return new DataResponse();
1340
-		}
1341
-		// Go
1342
-		$subAdminManager->createSubAdmin($user, $group);
1343
-		return new DataResponse();
1344
-	}
1345
-
1346
-	/**
1347
-	 * Removes a subadmin from a group
1348
-	 *
1349
-	 * @PasswordConfirmationRequired
1350
-	 *
1351
-	 * @param string $userId
1352
-	 * @param string $groupid
1353
-	 * @return DataResponse
1354
-	 * @throws OCSException
1355
-	 */
1356
-	public function removeSubAdmin(string $userId, string $groupid): DataResponse {
1357
-		$group = $this->groupManager->get($groupid);
1358
-		$user = $this->userManager->get($userId);
1359
-		$subAdminManager = $this->groupManager->getSubAdmin();
1360
-
1361
-		// Check if the user exists
1362
-		if ($user === null) {
1363
-			throw new OCSException('User does not exist', 101);
1364
-		}
1365
-		// Check if the group exists
1366
-		if ($group === null) {
1367
-			throw new OCSException('Group does not exist', 101);
1368
-		}
1369
-		// Check if they are a subadmin of this said group
1370
-		if (!$subAdminManager->isSubAdminOfGroup($user, $group)) {
1371
-			throw new OCSException('User is not a subadmin of this group', 102);
1372
-		}
1373
-
1374
-		// Go
1375
-		$subAdminManager->deleteSubAdmin($user, $group);
1376
-		return new DataResponse();
1377
-	}
1378
-
1379
-	/**
1380
-	 * Get the groups a user is a subadmin of
1381
-	 *
1382
-	 * @param string $userId
1383
-	 * @return DataResponse
1384
-	 * @throws OCSException
1385
-	 */
1386
-	public function getUserSubAdminGroups(string $userId): DataResponse {
1387
-		$groups = $this->getUserSubAdminGroupsData($userId);
1388
-		return new DataResponse($groups);
1389
-	}
1390
-
1391
-	/**
1392
-	 * @NoAdminRequired
1393
-	 * @PasswordConfirmationRequired
1394
-	 *
1395
-	 * resend welcome message
1396
-	 *
1397
-	 * @param string $userId
1398
-	 * @return DataResponse
1399
-	 * @throws OCSException
1400
-	 */
1401
-	public function resendWelcomeMessage(string $userId): DataResponse {
1402
-		$currentLoggedInUser = $this->userSession->getUser();
1403
-
1404
-		$targetUser = $this->userManager->get($userId);
1405
-		if ($targetUser === null) {
1406
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1407
-		}
1408
-
1409
-		// Check if admin / subadmin
1410
-		$subAdminManager = $this->groupManager->getSubAdmin();
1411
-		if (
1412
-			!$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
1413
-			&& !$this->groupManager->isAdmin($currentLoggedInUser->getUID())
1414
-		) {
1415
-			// No rights
1416
-			throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1417
-		}
1418
-
1419
-		$email = $targetUser->getEMailAddress();
1420
-		if ($email === '' || $email === null) {
1421
-			throw new OCSException('Email address not available', 101);
1422
-		}
1423
-
1424
-		try {
1425
-			$emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, false);
1426
-			$this->newUserMailHelper->sendMail($targetUser, $emailTemplate);
1427
-		} catch (\Exception $e) {
1428
-			$this->logger->error(
1429
-				"Can't send new user mail to $email",
1430
-				[
1431
-					'app' => 'settings',
1432
-					'exception' => $e,
1433
-				]
1434
-			);
1435
-			throw new OCSException('Sending email failed', 102);
1436
-		}
1437
-
1438
-		return new DataResponse();
1439
-	}
81
+    /** @var IURLGenerator */
82
+    protected $urlGenerator;
83
+    /** @var LoggerInterface */
84
+    private $logger;
85
+    /** @var IFactory */
86
+    protected $l10nFactory;
87
+    /** @var NewUserMailHelper */
88
+    private $newUserMailHelper;
89
+    /** @var ISecureRandom */
90
+    private $secureRandom;
91
+    /** @var RemoteWipe */
92
+    private $remoteWipe;
93
+    /** @var KnownUserService */
94
+    private $knownUserService;
95
+    /** @var IEventDispatcher */
96
+    private $eventDispatcher;
97
+
98
+    public function __construct(
99
+        string $appName,
100
+        IRequest $request,
101
+        IUserManager $userManager,
102
+        IConfig $config,
103
+        IGroupManager $groupManager,
104
+        IUserSession $userSession,
105
+        IAccountManager $accountManager,
106
+        IURLGenerator $urlGenerator,
107
+        LoggerInterface $logger,
108
+        IFactory $l10nFactory,
109
+        NewUserMailHelper $newUserMailHelper,
110
+        ISecureRandom $secureRandom,
111
+        RemoteWipe $remoteWipe,
112
+        KnownUserService $knownUserService,
113
+        IEventDispatcher $eventDispatcher
114
+    ) {
115
+        parent::__construct(
116
+            $appName,
117
+            $request,
118
+            $userManager,
119
+            $config,
120
+            $groupManager,
121
+            $userSession,
122
+            $accountManager,
123
+            $l10nFactory
124
+        );
125
+
126
+        $this->urlGenerator = $urlGenerator;
127
+        $this->logger = $logger;
128
+        $this->l10nFactory = $l10nFactory;
129
+        $this->newUserMailHelper = $newUserMailHelper;
130
+        $this->secureRandom = $secureRandom;
131
+        $this->remoteWipe = $remoteWipe;
132
+        $this->knownUserService = $knownUserService;
133
+        $this->eventDispatcher = $eventDispatcher;
134
+    }
135
+
136
+    /**
137
+     * @NoAdminRequired
138
+     *
139
+     * returns a list of users
140
+     *
141
+     * @param string $search
142
+     * @param int $limit
143
+     * @param int $offset
144
+     * @return DataResponse
145
+     */
146
+    public function getUsers(string $search = '', int $limit = null, int $offset = 0): DataResponse {
147
+        $user = $this->userSession->getUser();
148
+        $users = [];
149
+
150
+        // Admin? Or SubAdmin?
151
+        $uid = $user->getUID();
152
+        $subAdminManager = $this->groupManager->getSubAdmin();
153
+        if ($this->groupManager->isAdmin($uid)) {
154
+            $users = $this->userManager->search($search, $limit, $offset);
155
+        } elseif ($subAdminManager->isSubAdmin($user)) {
156
+            $subAdminOfGroups = $subAdminManager->getSubAdminsGroups($user);
157
+            foreach ($subAdminOfGroups as $key => $group) {
158
+                $subAdminOfGroups[$key] = $group->getGID();
159
+            }
160
+
161
+            $users = [];
162
+            foreach ($subAdminOfGroups as $group) {
163
+                $users = array_merge($users, $this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
164
+            }
165
+        }
166
+
167
+        $users = array_keys($users);
168
+
169
+        return new DataResponse([
170
+            'users' => $users
171
+        ]);
172
+    }
173
+
174
+    /**
175
+     * @NoAdminRequired
176
+     *
177
+     * returns a list of users and their data
178
+     */
179
+    public function getUsersDetails(string $search = '', int $limit = null, int $offset = 0): DataResponse {
180
+        $currentUser = $this->userSession->getUser();
181
+        $users = [];
182
+
183
+        // Admin? Or SubAdmin?
184
+        $uid = $currentUser->getUID();
185
+        $subAdminManager = $this->groupManager->getSubAdmin();
186
+        if ($this->groupManager->isAdmin($uid)) {
187
+            $users = $this->userManager->search($search, $limit, $offset);
188
+            $users = array_keys($users);
189
+        } elseif ($subAdminManager->isSubAdmin($currentUser)) {
190
+            $subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
191
+            foreach ($subAdminOfGroups as $key => $group) {
192
+                $subAdminOfGroups[$key] = $group->getGID();
193
+            }
194
+
195
+            $users = [];
196
+            foreach ($subAdminOfGroups as $group) {
197
+                $users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
198
+            }
199
+            $users = array_merge(...$users);
200
+        }
201
+
202
+        $usersDetails = [];
203
+        foreach ($users as $userId) {
204
+            $userId = (string) $userId;
205
+            $userData = $this->getUserData($userId);
206
+            // Do not insert empty entry
207
+            if (!empty($userData)) {
208
+                $usersDetails[$userId] = $userData;
209
+            } else {
210
+                // Logged user does not have permissions to see this user
211
+                // only showing its id
212
+                $usersDetails[$userId] = ['id' => $userId];
213
+            }
214
+        }
215
+
216
+        return new DataResponse([
217
+            'users' => $usersDetails
218
+        ]);
219
+    }
220
+
221
+
222
+    /**
223
+     * @NoAdminRequired
224
+     * @NoSubAdminRequired
225
+     *
226
+     * @param string $location
227
+     * @param array $search
228
+     * @return DataResponse
229
+     */
230
+    public function searchByPhoneNumbers(string $location, array $search): DataResponse {
231
+        $phoneUtil = PhoneNumberUtil::getInstance();
232
+
233
+        if ($phoneUtil->getCountryCodeForRegion($location) === 0) {
234
+            // Not a valid region code
235
+            return new DataResponse([], Http::STATUS_BAD_REQUEST);
236
+        }
237
+
238
+        /** @var IUser $user */
239
+        $user = $this->userSession->getUser();
240
+        $knownTo = $user->getUID();
241
+        $defaultPhoneRegion = $this->config->getSystemValueString('default_phone_region');
242
+
243
+        $normalizedNumberToKey = [];
244
+        foreach ($search as $key => $phoneNumbers) {
245
+            foreach ($phoneNumbers as $phone) {
246
+                try {
247
+                    $phoneNumber = $phoneUtil->parse($phone, $location);
248
+                    if ($phoneNumber instanceof PhoneNumber && $phoneUtil->isValidNumber($phoneNumber)) {
249
+                        $normalizedNumber = $phoneUtil->format($phoneNumber, PhoneNumberFormat::E164);
250
+                        $normalizedNumberToKey[$normalizedNumber] = (string) $key;
251
+                    }
252
+                } catch (NumberParseException $e) {
253
+                }
254
+
255
+                if ($defaultPhoneRegion !== '' && $defaultPhoneRegion !== $location && strpos($phone, '0') === 0) {
256
+                    // If the number has a leading zero (no country code),
257
+                    // we also check the default phone region of the instance,
258
+                    // when it's different to the user's given region.
259
+                    try {
260
+                        $phoneNumber = $phoneUtil->parse($phone, $defaultPhoneRegion);
261
+                        if ($phoneNumber instanceof PhoneNumber && $phoneUtil->isValidNumber($phoneNumber)) {
262
+                            $normalizedNumber = $phoneUtil->format($phoneNumber, PhoneNumberFormat::E164);
263
+                            $normalizedNumberToKey[$normalizedNumber] = (string) $key;
264
+                        }
265
+                    } catch (NumberParseException $e) {
266
+                    }
267
+                }
268
+            }
269
+        }
270
+
271
+        $phoneNumbers = array_keys($normalizedNumberToKey);
272
+
273
+        if (empty($phoneNumbers)) {
274
+            return new DataResponse();
275
+        }
276
+
277
+        // Cleanup all previous entries and only allow new matches
278
+        $this->knownUserService->deleteKnownTo($knownTo);
279
+
280
+        $userMatches = $this->accountManager->searchUsers(IAccountManager::PROPERTY_PHONE, $phoneNumbers);
281
+
282
+        if (empty($userMatches)) {
283
+            return new DataResponse();
284
+        }
285
+
286
+        $cloudUrl = rtrim($this->urlGenerator->getAbsoluteURL('/'), '/');
287
+        if (strpos($cloudUrl, 'http://') === 0) {
288
+            $cloudUrl = substr($cloudUrl, strlen('http://'));
289
+        } elseif (strpos($cloudUrl, 'https://') === 0) {
290
+            $cloudUrl = substr($cloudUrl, strlen('https://'));
291
+        }
292
+
293
+        $matches = [];
294
+        foreach ($userMatches as $phone => $userId) {
295
+            // Not using the ICloudIdManager as that would run a search for each contact to find the display name in the address book
296
+            $matches[$normalizedNumberToKey[$phone]] = $userId . '@' . $cloudUrl;
297
+            $this->knownUserService->storeIsKnownToUser($knownTo, $userId);
298
+        }
299
+
300
+        return new DataResponse($matches);
301
+    }
302
+
303
+    /**
304
+     * @throws OCSException
305
+     */
306
+    private function createNewUserId(): string {
307
+        $attempts = 0;
308
+        do {
309
+            $uidCandidate = $this->secureRandom->generate(10, ISecureRandom::CHAR_HUMAN_READABLE);
310
+            if (!$this->userManager->userExists($uidCandidate)) {
311
+                return $uidCandidate;
312
+            }
313
+            $attempts++;
314
+        } while ($attempts < 10);
315
+        throw new OCSException('Could not create non-existing user id', 111);
316
+    }
317
+
318
+    /**
319
+     * @PasswordConfirmationRequired
320
+     * @NoAdminRequired
321
+     *
322
+     * @param string $userid
323
+     * @param string $password
324
+     * @param string $displayName
325
+     * @param string $email
326
+     * @param array $groups
327
+     * @param array $subadmin
328
+     * @param string $quota
329
+     * @param string $language
330
+     * @return DataResponse
331
+     * @throws OCSException
332
+     */
333
+    public function addUser(
334
+        string $userid,
335
+        string $password = '',
336
+        string $displayName = '',
337
+        string $email = '',
338
+        array $groups = [],
339
+        array $subadmin = [],
340
+        string $quota = '',
341
+        string $language = '',
342
+        ?string $manager = null,
343
+    ): DataResponse {
344
+        $user = $this->userSession->getUser();
345
+        $isAdmin = $this->groupManager->isAdmin($user->getUID());
346
+        $subAdminManager = $this->groupManager->getSubAdmin();
347
+
348
+        if (empty($userid) && $this->config->getAppValue('core', 'newUser.generateUserID', 'no') === 'yes') {
349
+            $userid = $this->createNewUserId();
350
+        }
351
+
352
+        if ($this->userManager->userExists($userid)) {
353
+            $this->logger->error('Failed addUser attempt: User already exists.', ['app' => 'ocs_api']);
354
+            throw new OCSException($this->l10nFactory->get('provisioning_api')->t('User already exists'), 102);
355
+        }
356
+
357
+        if ($groups !== []) {
358
+            foreach ($groups as $group) {
359
+                if (!$this->groupManager->groupExists($group)) {
360
+                    throw new OCSException('group ' . $group . ' does not exist', 104);
361
+                }
362
+                if (!$isAdmin && !$subAdminManager->isSubAdminOfGroup($user, $this->groupManager->get($group))) {
363
+                    throw new OCSException('insufficient privileges for group ' . $group, 105);
364
+                }
365
+            }
366
+        } else {
367
+            if (!$isAdmin) {
368
+                throw new OCSException('no group specified (required for subadmins)', 106);
369
+            }
370
+        }
371
+
372
+        $subadminGroups = [];
373
+        if ($subadmin !== []) {
374
+            foreach ($subadmin as $groupid) {
375
+                $group = $this->groupManager->get($groupid);
376
+                // Check if group exists
377
+                if ($group === null) {
378
+                    throw new OCSException('Subadmin group does not exist', 102);
379
+                }
380
+                // Check if trying to make subadmin of admin group
381
+                if ($group->getGID() === 'admin') {
382
+                    throw new OCSException('Cannot create subadmins for admin group', 103);
383
+                }
384
+                // Check if has permission to promote subadmins
385
+                if (!$subAdminManager->isSubAdminOfGroup($user, $group) && !$isAdmin) {
386
+                    throw new OCSForbiddenException('No permissions to promote subadmins');
387
+                }
388
+                $subadminGroups[] = $group;
389
+            }
390
+        }
391
+
392
+        $generatePasswordResetToken = false;
393
+        if (strlen($password) > IUserManager::MAX_PASSWORD_LENGTH) {
394
+            throw new OCSException('Invalid password value', 101);
395
+        }
396
+        if ($password === '') {
397
+            if ($email === '') {
398
+                throw new OCSException('To send a password link to the user an email address is required.', 108);
399
+            }
400
+
401
+            $passwordEvent = new GenerateSecurePasswordEvent();
402
+            $this->eventDispatcher->dispatchTyped($passwordEvent);
403
+
404
+            $password = $passwordEvent->getPassword();
405
+            if ($password === null) {
406
+                // Fallback: ensure to pass password_policy in any case
407
+                $password = $this->secureRandom->generate(10)
408
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_UPPER)
409
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_LOWER)
410
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_DIGITS)
411
+                    . $this->secureRandom->generate(1, ISecureRandom::CHAR_SYMBOLS);
412
+            }
413
+            $generatePasswordResetToken = true;
414
+        }
415
+
416
+        if ($email === '' && $this->config->getAppValue('core', 'newUser.requireEmail', 'no') === 'yes') {
417
+            throw new OCSException('Required email address was not provided', 110);
418
+        }
419
+
420
+        try {
421
+            $newUser = $this->userManager->createUser($userid, $password);
422
+            $this->logger->info('Successful addUser call with userid: ' . $userid, ['app' => 'ocs_api']);
423
+
424
+            foreach ($groups as $group) {
425
+                $this->groupManager->get($group)->addUser($newUser);
426
+                $this->logger->info('Added userid ' . $userid . ' to group ' . $group, ['app' => 'ocs_api']);
427
+            }
428
+            foreach ($subadminGroups as $group) {
429
+                $subAdminManager->createSubAdmin($newUser, $group);
430
+            }
431
+
432
+            if ($displayName !== '') {
433
+                try {
434
+                    $this->editUser($userid, self::USER_FIELD_DISPLAYNAME, $displayName);
435
+                } catch (OCSException $e) {
436
+                    if ($newUser instanceof IUser) {
437
+                        $newUser->delete();
438
+                    }
439
+                    throw $e;
440
+                }
441
+            }
442
+
443
+            if ($quota !== '') {
444
+                $this->editUser($userid, self::USER_FIELD_QUOTA, $quota);
445
+            }
446
+
447
+            if ($language !== '') {
448
+                $this->editUser($userid, self::USER_FIELD_LANGUAGE, $language);
449
+            }
450
+
451
+            /**
452
+             * null -> nothing sent
453
+             * '' -> unset manager
454
+             * else -> set manager
455
+             */
456
+            if ($manager !== null) {
457
+                $this->editUser($userid, self::USER_FIELD_MANAGER, $manager);
458
+            }
459
+
460
+            // Send new user mail only if a mail is set
461
+            if ($email !== '') {
462
+                $newUser->setEMailAddress($email);
463
+                if ($this->config->getAppValue('core', 'newUser.sendEmail', 'yes') === 'yes') {
464
+                    try {
465
+                        $emailTemplate = $this->newUserMailHelper->generateTemplate($newUser, $generatePasswordResetToken);
466
+                        $this->newUserMailHelper->sendMail($newUser, $emailTemplate);
467
+                    } catch (\Exception $e) {
468
+                        // Mail could be failing hard or just be plain not configured
469
+                        // Logging error as it is the hardest of the two
470
+                        $this->logger->error(
471
+                            "Unable to send the invitation mail to $email",
472
+                            [
473
+                                'app' => 'ocs_api',
474
+                                'exception' => $e,
475
+                            ]
476
+                        );
477
+                    }
478
+                }
479
+            }
480
+
481
+            return new DataResponse(['id' => $userid]);
482
+        } catch (HintException $e) {
483
+            $this->logger->warning(
484
+                'Failed addUser attempt with hint exception.',
485
+                [
486
+                    'app' => 'ocs_api',
487
+                    'exception' => $e,
488
+                ]
489
+            );
490
+            throw new OCSException($e->getHint(), 107);
491
+        } catch (OCSException $e) {
492
+            $this->logger->warning(
493
+                'Failed addUser attempt with ocs exception.',
494
+                [
495
+                    'app' => 'ocs_api',
496
+                    'exception' => $e,
497
+                ]
498
+            );
499
+            throw $e;
500
+        } catch (InvalidArgumentException $e) {
501
+            $this->logger->error(
502
+                'Failed addUser attempt with invalid argument exception.',
503
+                [
504
+                    'app' => 'ocs_api',
505
+                    'exception' => $e,
506
+                ]
507
+            );
508
+            throw new OCSException($e->getMessage(), 101);
509
+        } catch (\Exception $e) {
510
+            $this->logger->error(
511
+                'Failed addUser attempt with exception.',
512
+                [
513
+                    'app' => 'ocs_api',
514
+                    'exception' => $e
515
+                ]
516
+            );
517
+            throw new OCSException('Bad request', 101);
518
+        }
519
+    }
520
+
521
+    /**
522
+     * @NoAdminRequired
523
+     * @NoSubAdminRequired
524
+     *
525
+     * gets user info
526
+     *
527
+     * @param string $userId
528
+     * @return DataResponse
529
+     * @throws OCSException
530
+     */
531
+    public function getUser(string $userId): DataResponse {
532
+        $includeScopes = false;
533
+        $currentUser = $this->userSession->getUser();
534
+        if ($currentUser && $currentUser->getUID() === $userId) {
535
+            $includeScopes = true;
536
+        }
537
+
538
+        $data = $this->getUserData($userId, $includeScopes);
539
+        // getUserData returns empty array if not enough permissions
540
+        if (empty($data)) {
541
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
542
+        }
543
+        return new DataResponse($data);
544
+    }
545
+
546
+    /**
547
+     * @NoAdminRequired
548
+     * @NoSubAdminRequired
549
+     *
550
+     * gets user info from the currently logged in user
551
+     *
552
+     * @return DataResponse
553
+     * @throws OCSException
554
+     */
555
+    public function getCurrentUser(): DataResponse {
556
+        $user = $this->userSession->getUser();
557
+        if ($user) {
558
+            $data = $this->getUserData($user->getUID(), true);
559
+            return new DataResponse($data);
560
+        }
561
+
562
+        throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
563
+    }
564
+
565
+    /**
566
+     * @NoAdminRequired
567
+     * @NoSubAdminRequired
568
+     *
569
+     * @return DataResponse
570
+     * @throws OCSException
571
+     */
572
+    public function getEditableFields(): DataResponse {
573
+        $currentLoggedInUser = $this->userSession->getUser();
574
+        if (!$currentLoggedInUser instanceof IUser) {
575
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
576
+        }
577
+
578
+        return $this->getEditableFieldsForUser($currentLoggedInUser->getUID());
579
+    }
580
+
581
+    /**
582
+     * @NoAdminRequired
583
+     * @NoSubAdminRequired
584
+     *
585
+     * @param string $userId
586
+     * @return DataResponse
587
+     * @throws OCSException
588
+     */
589
+    public function getEditableFieldsForUser(string $userId): DataResponse {
590
+        $currentLoggedInUser = $this->userSession->getUser();
591
+        if (!$currentLoggedInUser instanceof IUser) {
592
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
593
+        }
594
+
595
+        $permittedFields = [];
596
+
597
+        if ($userId !== $currentLoggedInUser->getUID()) {
598
+            $targetUser = $this->userManager->get($userId);
599
+            if (!$targetUser instanceof IUser) {
600
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
601
+            }
602
+
603
+            $subAdminManager = $this->groupManager->getSubAdmin();
604
+            if (
605
+                !$this->groupManager->isAdmin($currentLoggedInUser->getUID())
606
+                && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
607
+            ) {
608
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
609
+            }
610
+        } else {
611
+            $targetUser = $currentLoggedInUser;
612
+        }
613
+
614
+        // Editing self (display, email)
615
+        if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
616
+            if (
617
+                $targetUser->getBackend() instanceof ISetDisplayNameBackend
618
+                || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
619
+            ) {
620
+                $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
621
+            }
622
+            $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
623
+        }
624
+
625
+        $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
626
+        $permittedFields[] = IAccountManager::PROPERTY_PHONE;
627
+        $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
628
+        $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
629
+        $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
630
+        $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
631
+        $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
632
+        $permittedFields[] = IAccountManager::PROPERTY_ROLE;
633
+        $permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
634
+        $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
635
+        $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
636
+
637
+        return new DataResponse($permittedFields);
638
+    }
639
+
640
+    /**
641
+     * @NoAdminRequired
642
+     * @NoSubAdminRequired
643
+     * @PasswordConfirmationRequired
644
+     * @UserRateThrottle(limit=5, period=60)
645
+     *
646
+     * @throws OCSException
647
+     */
648
+    public function editUserMultiValue(
649
+        string $userId,
650
+        string $collectionName,
651
+        string $key,
652
+        string $value
653
+    ): DataResponse {
654
+        $currentLoggedInUser = $this->userSession->getUser();
655
+        if ($currentLoggedInUser === null) {
656
+            throw new OCSException('', OCSController::RESPOND_UNAUTHORISED);
657
+        }
658
+
659
+        $targetUser = $this->userManager->get($userId);
660
+        if ($targetUser === null) {
661
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
662
+        }
663
+
664
+        $subAdminManager = $this->groupManager->getSubAdmin();
665
+        $isAdminOrSubadmin = $this->groupManager->isAdmin($currentLoggedInUser->getUID())
666
+            || $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser);
667
+
668
+        $permittedFields = [];
669
+        if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
670
+            // Editing self (display, email)
671
+            $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
672
+            $permittedFields[] = IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX;
673
+        } else {
674
+            // Check if admin / subadmin
675
+            if ($isAdminOrSubadmin) {
676
+                // They have permissions over the user
677
+                $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
678
+            } else {
679
+                // No rights
680
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
681
+            }
682
+        }
683
+
684
+        // Check if permitted to edit this field
685
+        if (!in_array($collectionName, $permittedFields)) {
686
+            throw new OCSException('', 103);
687
+        }
688
+
689
+        switch ($collectionName) {
690
+            case IAccountManager::COLLECTION_EMAIL:
691
+                $userAccount = $this->accountManager->getAccount($targetUser);
692
+                $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
693
+                $mailCollection->removePropertyByValue($key);
694
+                if ($value !== '') {
695
+                    $mailCollection->addPropertyWithDefaults($value);
696
+                    $property = $mailCollection->getPropertyByValue($key);
697
+                    if ($isAdminOrSubadmin && $property) {
698
+                        // admin set mails are auto-verified
699
+                        $property->setLocallyVerified(IAccountManager::VERIFIED);
700
+                    }
701
+                }
702
+                $this->accountManager->updateAccount($userAccount);
703
+                break;
704
+
705
+            case IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX:
706
+                $userAccount = $this->accountManager->getAccount($targetUser);
707
+                $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
708
+                $targetProperty = null;
709
+                foreach ($mailCollection->getProperties() as $property) {
710
+                    if ($property->getValue() === $key) {
711
+                        $targetProperty = $property;
712
+                        break;
713
+                    }
714
+                }
715
+                if ($targetProperty instanceof IAccountProperty) {
716
+                    try {
717
+                        $targetProperty->setScope($value);
718
+                        $this->accountManager->updateAccount($userAccount);
719
+                    } catch (InvalidArgumentException $e) {
720
+                        throw new OCSException('', 102);
721
+                    }
722
+                } else {
723
+                    throw new OCSException('', 102);
724
+                }
725
+                break;
726
+
727
+            default:
728
+                throw new OCSException('', 103);
729
+        }
730
+        return new DataResponse();
731
+    }
732
+
733
+    /**
734
+     * @NoAdminRequired
735
+     * @NoSubAdminRequired
736
+     * @PasswordConfirmationRequired
737
+     * @UserRateThrottle(limit=50, period=600)
738
+     *
739
+     * edit users
740
+     *
741
+     * @param string $userId
742
+     * @param string $key
743
+     * @param string $value
744
+     * @return DataResponse
745
+     * @throws OCSException
746
+     */
747
+    public function editUser(string $userId, string $key, string $value): DataResponse {
748
+        $currentLoggedInUser = $this->userSession->getUser();
749
+
750
+        $targetUser = $this->userManager->get($userId);
751
+        if ($targetUser === null) {
752
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
753
+        }
754
+
755
+        $permittedFields = [];
756
+        if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
757
+            // Editing self (display, email)
758
+            if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
759
+                if (
760
+                    $targetUser->getBackend() instanceof ISetDisplayNameBackend
761
+                    || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
762
+                ) {
763
+                    $permittedFields[] = self::USER_FIELD_DISPLAYNAME;
764
+                    $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
765
+                }
766
+                $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
767
+            }
768
+
769
+            $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX;
770
+            $permittedFields[] = IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX;
771
+
772
+            $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
773
+
774
+            $permittedFields[] = self::USER_FIELD_PASSWORD;
775
+            $permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
776
+            if (
777
+                $this->config->getSystemValue('force_language', false) === false ||
778
+                $this->groupManager->isAdmin($currentLoggedInUser->getUID())
779
+            ) {
780
+                $permittedFields[] = self::USER_FIELD_LANGUAGE;
781
+            }
782
+
783
+            if (
784
+                $this->config->getSystemValue('force_locale', false) === false ||
785
+                $this->groupManager->isAdmin($currentLoggedInUser->getUID())
786
+            ) {
787
+                $permittedFields[] = self::USER_FIELD_LOCALE;
788
+            }
789
+
790
+            $permittedFields[] = IAccountManager::PROPERTY_PHONE;
791
+            $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
792
+            $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
793
+            $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
794
+            $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
795
+            $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
796
+            $permittedFields[] = IAccountManager::PROPERTY_ROLE;
797
+            $permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
798
+            $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
799
+            $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
800
+            $permittedFields[] = IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX;
801
+            $permittedFields[] = IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX;
802
+            $permittedFields[] = IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX;
803
+            $permittedFields[] = IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX;
804
+            $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE . self::SCOPE_SUFFIX;
805
+            $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX;
806
+            $permittedFields[] = IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX;
807
+            $permittedFields[] = IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX;
808
+            $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX;
809
+            $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX;
810
+
811
+            $permittedFields[] = IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX;
812
+
813
+            // If admin they can edit their own quota and manager
814
+            if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
815
+                $permittedFields[] = self::USER_FIELD_QUOTA;
816
+                $permittedFields[] = self::USER_FIELD_MANAGER;
817
+
818
+            }
819
+        } else {
820
+            // Check if admin / subadmin
821
+            $subAdminManager = $this->groupManager->getSubAdmin();
822
+            if (
823
+                $this->groupManager->isAdmin($currentLoggedInUser->getUID())
824
+                || $subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
825
+            ) {
826
+                // They have permissions over the user
827
+                if (
828
+                    $targetUser->getBackend() instanceof ISetDisplayNameBackend
829
+                    || $targetUser->getBackend()->implementsActions(Backend::SET_DISPLAYNAME)
830
+                ) {
831
+                    $permittedFields[] = self::USER_FIELD_DISPLAYNAME;
832
+                    $permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME;
833
+                }
834
+                $permittedFields[] = IAccountManager::PROPERTY_EMAIL;
835
+                $permittedFields[] = IAccountManager::COLLECTION_EMAIL;
836
+                $permittedFields[] = self::USER_FIELD_PASSWORD;
837
+                $permittedFields[] = self::USER_FIELD_LANGUAGE;
838
+                $permittedFields[] = self::USER_FIELD_LOCALE;
839
+                $permittedFields[] = IAccountManager::PROPERTY_PHONE;
840
+                $permittedFields[] = IAccountManager::PROPERTY_ADDRESS;
841
+                $permittedFields[] = IAccountManager::PROPERTY_WEBSITE;
842
+                $permittedFields[] = IAccountManager::PROPERTY_TWITTER;
843
+                $permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE;
844
+                $permittedFields[] = IAccountManager::PROPERTY_ORGANISATION;
845
+                $permittedFields[] = IAccountManager::PROPERTY_ROLE;
846
+                $permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
847
+                $permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
848
+                $permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
849
+                $permittedFields[] = self::USER_FIELD_QUOTA;
850
+                $permittedFields[] = self::USER_FIELD_NOTIFICATION_EMAIL;
851
+                $permittedFields[] = self::USER_FIELD_MANAGER;
852
+            } else {
853
+                // No rights
854
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
855
+            }
856
+        }
857
+        // Check if permitted to edit this field
858
+        if (!in_array($key, $permittedFields)) {
859
+            throw new OCSException('', 103);
860
+        }
861
+        // Process the edit
862
+        switch ($key) {
863
+            case self::USER_FIELD_DISPLAYNAME:
864
+            case IAccountManager::PROPERTY_DISPLAYNAME:
865
+                try {
866
+                    $targetUser->setDisplayName($value);
867
+                } catch (InvalidArgumentException $e) {
868
+                    throw new OCSException($e->getMessage(), 101);
869
+                }
870
+                break;
871
+            case self::USER_FIELD_QUOTA:
872
+                $quota = $value;
873
+                if ($quota !== 'none' && $quota !== 'default') {
874
+                    if (is_numeric($quota)) {
875
+                        $quota = (float) $quota;
876
+                    } else {
877
+                        $quota = \OCP\Util::computerFileSize($quota);
878
+                    }
879
+                    if ($quota === false) {
880
+                        throw new OCSException('Invalid quota value ' . $value, 102);
881
+                    }
882
+                    if ($quota === -1) {
883
+                        $quota = 'none';
884
+                    } else {
885
+                        $maxQuota = (int) $this->config->getAppValue('files', 'max_quota', '-1');
886
+                        if ($maxQuota !== -1 && $quota > $maxQuota) {
887
+                            throw new OCSException('Invalid quota value. ' . $value . ' is exceeding the maximum quota', 102);
888
+                        }
889
+                        $quota = \OCP\Util::humanFileSize($quota);
890
+                    }
891
+                }
892
+                // no else block because quota can be set to 'none' in previous if
893
+                if ($quota === 'none') {
894
+                    $allowUnlimitedQuota = $this->config->getAppValue('files', 'allow_unlimited_quota', '1') === '1';
895
+                    if (!$allowUnlimitedQuota) {
896
+                        throw new OCSException('Unlimited quota is forbidden on this instance', 102);
897
+                    }
898
+                }
899
+                $targetUser->setQuota($quota);
900
+                break;
901
+            case self::USER_FIELD_MANAGER:
902
+                $targetUser->setManagerUids([$value]);
903
+                break;
904
+            case self::USER_FIELD_PASSWORD:
905
+                try {
906
+                    if (strlen($value) > IUserManager::MAX_PASSWORD_LENGTH) {
907
+                        throw new OCSException('Invalid password value', 102);
908
+                    }
909
+                    if (!$targetUser->canChangePassword()) {
910
+                        throw new OCSException('Setting the password is not supported by the users backend', 103);
911
+                    }
912
+                    $targetUser->setPassword($value);
913
+                } catch (HintException $e) { // password policy error
914
+                    throw new OCSException($e->getMessage(), 103);
915
+                }
916
+                break;
917
+            case self::USER_FIELD_LANGUAGE:
918
+                $languagesCodes = $this->l10nFactory->findAvailableLanguages();
919
+                if (!in_array($value, $languagesCodes, true) && $value !== 'en') {
920
+                    throw new OCSException('Invalid language', 102);
921
+                }
922
+                $this->config->setUserValue($targetUser->getUID(), 'core', 'lang', $value);
923
+                break;
924
+            case self::USER_FIELD_LOCALE:
925
+                if (!$this->l10nFactory->localeExists($value)) {
926
+                    throw new OCSException('Invalid locale', 102);
927
+                }
928
+                $this->config->setUserValue($targetUser->getUID(), 'core', 'locale', $value);
929
+                break;
930
+            case self::USER_FIELD_NOTIFICATION_EMAIL:
931
+                $success = false;
932
+                if ($value === '' || filter_var($value, FILTER_VALIDATE_EMAIL)) {
933
+                    try {
934
+                        $targetUser->setPrimaryEMailAddress($value);
935
+                        $success = true;
936
+                    } catch (InvalidArgumentException $e) {
937
+                        $this->logger->info(
938
+                            'Cannot set primary email, because provided address is not verified',
939
+                            [
940
+                                'app' => 'provisioning_api',
941
+                                'exception' => $e,
942
+                            ]
943
+                        );
944
+                    }
945
+                }
946
+                if (!$success) {
947
+                    throw new OCSException('', 102);
948
+                }
949
+                break;
950
+            case IAccountManager::PROPERTY_EMAIL:
951
+                if (filter_var($value, FILTER_VALIDATE_EMAIL) || $value === '') {
952
+                    $targetUser->setEMailAddress($value);
953
+                } else {
954
+                    throw new OCSException('', 102);
955
+                }
956
+                break;
957
+            case IAccountManager::COLLECTION_EMAIL:
958
+                if (filter_var($value, FILTER_VALIDATE_EMAIL) && $value !== $targetUser->getSystemEMailAddress()) {
959
+                    $userAccount = $this->accountManager->getAccount($targetUser);
960
+                    $mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
961
+
962
+                    if ($mailCollection->getPropertyByValue($value)) {
963
+                        throw new OCSException('', 102);
964
+                    }
965
+
966
+                    $mailCollection->addPropertyWithDefaults($value);
967
+                    $this->accountManager->updateAccount($userAccount);
968
+                } else {
969
+                    throw new OCSException('', 102);
970
+                }
971
+                break;
972
+            case IAccountManager::PROPERTY_PHONE:
973
+            case IAccountManager::PROPERTY_ADDRESS:
974
+            case IAccountManager::PROPERTY_WEBSITE:
975
+            case IAccountManager::PROPERTY_TWITTER:
976
+            case IAccountManager::PROPERTY_FEDIVERSE:
977
+            case IAccountManager::PROPERTY_ORGANISATION:
978
+            case IAccountManager::PROPERTY_ROLE:
979
+            case IAccountManager::PROPERTY_HEADLINE:
980
+            case IAccountManager::PROPERTY_BIOGRAPHY:
981
+                $userAccount = $this->accountManager->getAccount($targetUser);
982
+                try {
983
+                    $userProperty = $userAccount->getProperty($key);
984
+                    if ($userProperty->getValue() !== $value) {
985
+                        try {
986
+                            $userProperty->setValue($value);
987
+                            if ($userProperty->getName() === IAccountManager::PROPERTY_PHONE) {
988
+                                $this->knownUserService->deleteByContactUserId($targetUser->getUID());
989
+                            }
990
+                        } catch (InvalidArgumentException $e) {
991
+                            throw new OCSException('Invalid ' . $e->getMessage(), 102);
992
+                        }
993
+                    }
994
+                } catch (PropertyDoesNotExistException $e) {
995
+                    $userAccount->setProperty($key, $value, IAccountManager::SCOPE_PRIVATE, IAccountManager::NOT_VERIFIED);
996
+                }
997
+                try {
998
+                    $this->accountManager->updateAccount($userAccount);
999
+                } catch (InvalidArgumentException $e) {
1000
+                    throw new OCSException('Invalid ' . $e->getMessage(), 102);
1001
+                }
1002
+                break;
1003
+            case IAccountManager::PROPERTY_PROFILE_ENABLED:
1004
+                $userAccount = $this->accountManager->getAccount($targetUser);
1005
+                try {
1006
+                    $userProperty = $userAccount->getProperty($key);
1007
+                    if ($userProperty->getValue() !== $value) {
1008
+                        $userProperty->setValue($value);
1009
+                    }
1010
+                } catch (PropertyDoesNotExistException $e) {
1011
+                    $userAccount->setProperty($key, $value, IAccountManager::SCOPE_LOCAL, IAccountManager::NOT_VERIFIED);
1012
+                }
1013
+                $this->accountManager->updateAccount($userAccount);
1014
+                break;
1015
+            case IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX:
1016
+            case IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX:
1017
+            case IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX:
1018
+            case IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX:
1019
+            case IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX:
1020
+            case IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX:
1021
+            case IAccountManager::PROPERTY_FEDIVERSE . self::SCOPE_SUFFIX:
1022
+            case IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX:
1023
+            case IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX:
1024
+            case IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX:
1025
+            case IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX:
1026
+            case IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX:
1027
+            case IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX:
1028
+                $propertyName = substr($key, 0, strlen($key) - strlen(self::SCOPE_SUFFIX));
1029
+                $userAccount = $this->accountManager->getAccount($targetUser);
1030
+                $userProperty = $userAccount->getProperty($propertyName);
1031
+                if ($userProperty->getScope() !== $value) {
1032
+                    try {
1033
+                        $userProperty->setScope($value);
1034
+                        $this->accountManager->updateAccount($userAccount);
1035
+                    } catch (InvalidArgumentException $e) {
1036
+                        throw new OCSException('Invalid ' . $e->getMessage(), 102);
1037
+                    }
1038
+                }
1039
+                break;
1040
+            default:
1041
+                throw new OCSException('', 103);
1042
+        }
1043
+        return new DataResponse();
1044
+    }
1045
+
1046
+    /**
1047
+     * @PasswordConfirmationRequired
1048
+     * @NoAdminRequired
1049
+     *
1050
+     * @param string $userId
1051
+     *
1052
+     * @return DataResponse
1053
+     *
1054
+     * @throws OCSException
1055
+     */
1056
+    public function wipeUserDevices(string $userId): DataResponse {
1057
+        /** @var IUser $currentLoggedInUser */
1058
+        $currentLoggedInUser = $this->userSession->getUser();
1059
+
1060
+        $targetUser = $this->userManager->get($userId);
1061
+
1062
+        if ($targetUser === null) {
1063
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1064
+        }
1065
+
1066
+        if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
1067
+            throw new OCSException('', 101);
1068
+        }
1069
+
1070
+        // If not permitted
1071
+        $subAdminManager = $this->groupManager->getSubAdmin();
1072
+        if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
1073
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1074
+        }
1075
+
1076
+        $this->remoteWipe->markAllTokensForWipe($targetUser);
1077
+
1078
+        return new DataResponse();
1079
+    }
1080
+
1081
+    /**
1082
+     * @PasswordConfirmationRequired
1083
+     * @NoAdminRequired
1084
+     *
1085
+     * @param string $userId
1086
+     * @return DataResponse
1087
+     * @throws OCSException
1088
+     */
1089
+    public function deleteUser(string $userId): DataResponse {
1090
+        $currentLoggedInUser = $this->userSession->getUser();
1091
+
1092
+        $targetUser = $this->userManager->get($userId);
1093
+
1094
+        if ($targetUser === null) {
1095
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1096
+        }
1097
+
1098
+        if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
1099
+            throw new OCSException('', 101);
1100
+        }
1101
+
1102
+        // If not permitted
1103
+        $subAdminManager = $this->groupManager->getSubAdmin();
1104
+        if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
1105
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1106
+        }
1107
+
1108
+        // Go ahead with the delete
1109
+        if ($targetUser->delete()) {
1110
+            return new DataResponse();
1111
+        } else {
1112
+            throw new OCSException('', 101);
1113
+        }
1114
+    }
1115
+
1116
+    /**
1117
+     * @PasswordConfirmationRequired
1118
+     * @NoAdminRequired
1119
+     *
1120
+     * @param string $userId
1121
+     * @return DataResponse
1122
+     * @throws OCSException
1123
+     * @throws OCSForbiddenException
1124
+     */
1125
+    public function disableUser(string $userId): DataResponse {
1126
+        return $this->setEnabled($userId, false);
1127
+    }
1128
+
1129
+    /**
1130
+     * @PasswordConfirmationRequired
1131
+     * @NoAdminRequired
1132
+     *
1133
+     * @param string $userId
1134
+     * @return DataResponse
1135
+     * @throws OCSException
1136
+     * @throws OCSForbiddenException
1137
+     */
1138
+    public function enableUser(string $userId): DataResponse {
1139
+        return $this->setEnabled($userId, true);
1140
+    }
1141
+
1142
+    /**
1143
+     * @param string $userId
1144
+     * @param bool $value
1145
+     * @return DataResponse
1146
+     * @throws OCSException
1147
+     */
1148
+    private function setEnabled(string $userId, bool $value): DataResponse {
1149
+        $currentLoggedInUser = $this->userSession->getUser();
1150
+
1151
+        $targetUser = $this->userManager->get($userId);
1152
+        if ($targetUser === null || $targetUser->getUID() === $currentLoggedInUser->getUID()) {
1153
+            throw new OCSException('', 101);
1154
+        }
1155
+
1156
+        // If not permitted
1157
+        $subAdminManager = $this->groupManager->getSubAdmin();
1158
+        if (!$this->groupManager->isAdmin($currentLoggedInUser->getUID()) && !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)) {
1159
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1160
+        }
1161
+
1162
+        // enable/disable the user now
1163
+        $targetUser->setEnabled($value);
1164
+        return new DataResponse();
1165
+    }
1166
+
1167
+    /**
1168
+     * @NoAdminRequired
1169
+     * @NoSubAdminRequired
1170
+     *
1171
+     * @param string $userId
1172
+     * @return DataResponse
1173
+     * @throws OCSException
1174
+     */
1175
+    public function getUsersGroups(string $userId): DataResponse {
1176
+        $loggedInUser = $this->userSession->getUser();
1177
+
1178
+        $targetUser = $this->userManager->get($userId);
1179
+        if ($targetUser === null) {
1180
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1181
+        }
1182
+
1183
+        if ($targetUser->getUID() === $loggedInUser->getUID() || $this->groupManager->isAdmin($loggedInUser->getUID())) {
1184
+            // Self lookup or admin lookup
1185
+            return new DataResponse([
1186
+                'groups' => $this->groupManager->getUserGroupIds($targetUser)
1187
+            ]);
1188
+        } else {
1189
+            $subAdminManager = $this->groupManager->getSubAdmin();
1190
+
1191
+            // Looking up someone else
1192
+            if ($subAdminManager->isUserAccessible($loggedInUser, $targetUser)) {
1193
+                // Return the group that the method caller is subadmin of for the user in question
1194
+                /** @var IGroup[] $getSubAdminsGroups */
1195
+                $getSubAdminsGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
1196
+                foreach ($getSubAdminsGroups as $key => $group) {
1197
+                    $getSubAdminsGroups[$key] = $group->getGID();
1198
+                }
1199
+                $groups = array_intersect(
1200
+                    $getSubAdminsGroups,
1201
+                    $this->groupManager->getUserGroupIds($targetUser)
1202
+                );
1203
+                return new DataResponse(['groups' => $groups]);
1204
+            } else {
1205
+                // Not permitted
1206
+                throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1207
+            }
1208
+        }
1209
+    }
1210
+
1211
+    /**
1212
+     * @PasswordConfirmationRequired
1213
+     * @NoAdminRequired
1214
+     *
1215
+     * @param string $userId
1216
+     * @param string $groupid
1217
+     * @return DataResponse
1218
+     * @throws OCSException
1219
+     */
1220
+    public function addToGroup(string $userId, string $groupid = ''): DataResponse {
1221
+        if ($groupid === '') {
1222
+            throw new OCSException('', 101);
1223
+        }
1224
+
1225
+        $group = $this->groupManager->get($groupid);
1226
+        $targetUser = $this->userManager->get($userId);
1227
+        if ($group === null) {
1228
+            throw new OCSException('', 102);
1229
+        }
1230
+        if ($targetUser === null) {
1231
+            throw new OCSException('', 103);
1232
+        }
1233
+
1234
+        // If they're not an admin, check they are a subadmin of the group in question
1235
+        $loggedInUser = $this->userSession->getUser();
1236
+        $subAdminManager = $this->groupManager->getSubAdmin();
1237
+        if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
1238
+            throw new OCSException('', 104);
1239
+        }
1240
+
1241
+        // Add user to group
1242
+        $group->addUser($targetUser);
1243
+        return new DataResponse();
1244
+    }
1245
+
1246
+    /**
1247
+     * @PasswordConfirmationRequired
1248
+     * @NoAdminRequired
1249
+     *
1250
+     * @param string $userId
1251
+     * @param string $groupid
1252
+     * @return DataResponse
1253
+     * @throws OCSException
1254
+     */
1255
+    public function removeFromGroup(string $userId, string $groupid): DataResponse {
1256
+        $loggedInUser = $this->userSession->getUser();
1257
+
1258
+        if ($groupid === null || trim($groupid) === '') {
1259
+            throw new OCSException('', 101);
1260
+        }
1261
+
1262
+        $group = $this->groupManager->get($groupid);
1263
+        if ($group === null) {
1264
+            throw new OCSException('', 102);
1265
+        }
1266
+
1267
+        $targetUser = $this->userManager->get($userId);
1268
+        if ($targetUser === null) {
1269
+            throw new OCSException('', 103);
1270
+        }
1271
+
1272
+        // If they're not an admin, check they are a subadmin of the group in question
1273
+        $subAdminManager = $this->groupManager->getSubAdmin();
1274
+        if (!$this->groupManager->isAdmin($loggedInUser->getUID()) && !$subAdminManager->isSubAdminOfGroup($loggedInUser, $group)) {
1275
+            throw new OCSException('', 104);
1276
+        }
1277
+
1278
+        // Check they aren't removing themselves from 'admin' or their 'subadmin; group
1279
+        if ($targetUser->getUID() === $loggedInUser->getUID()) {
1280
+            if ($this->groupManager->isAdmin($loggedInUser->getUID())) {
1281
+                if ($group->getGID() === 'admin') {
1282
+                    throw new OCSException('Cannot remove yourself from the admin group', 105);
1283
+                }
1284
+            } else {
1285
+                // Not an admin, so the user must be a subadmin of this group, but that is not allowed.
1286
+                throw new OCSException('Cannot remove yourself from this group as you are a SubAdmin', 105);
1287
+            }
1288
+        } elseif (!$this->groupManager->isAdmin($loggedInUser->getUID())) {
1289
+            /** @var IGroup[] $subAdminGroups */
1290
+            $subAdminGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
1291
+            $subAdminGroups = array_map(function (IGroup $subAdminGroup) {
1292
+                return $subAdminGroup->getGID();
1293
+            }, $subAdminGroups);
1294
+            $userGroups = $this->groupManager->getUserGroupIds($targetUser);
1295
+            $userSubAdminGroups = array_intersect($subAdminGroups, $userGroups);
1296
+
1297
+            if (count($userSubAdminGroups) <= 1) {
1298
+                // Subadmin must not be able to remove a user from all their subadmin groups.
1299
+                throw new OCSException('Not viable to remove user from the last group you are SubAdmin of', 105);
1300
+            }
1301
+        }
1302
+
1303
+        // Remove user from group
1304
+        $group->removeUser($targetUser);
1305
+        return new DataResponse();
1306
+    }
1307
+
1308
+    /**
1309
+     * Creates a subadmin
1310
+     *
1311
+     * @PasswordConfirmationRequired
1312
+     *
1313
+     * @param string $userId
1314
+     * @param string $groupid
1315
+     * @return DataResponse
1316
+     * @throws OCSException
1317
+     */
1318
+    public function addSubAdmin(string $userId, string $groupid): DataResponse {
1319
+        $group = $this->groupManager->get($groupid);
1320
+        $user = $this->userManager->get($userId);
1321
+
1322
+        // Check if the user exists
1323
+        if ($user === null) {
1324
+            throw new OCSException('User does not exist', 101);
1325
+        }
1326
+        // Check if group exists
1327
+        if ($group === null) {
1328
+            throw new OCSException('Group does not exist', 102);
1329
+        }
1330
+        // Check if trying to make subadmin of admin group
1331
+        if ($group->getGID() === 'admin') {
1332
+            throw new OCSException('Cannot create subadmins for admin group', 103);
1333
+        }
1334
+
1335
+        $subAdminManager = $this->groupManager->getSubAdmin();
1336
+
1337
+        // We cannot be subadmin twice
1338
+        if ($subAdminManager->isSubAdminOfGroup($user, $group)) {
1339
+            return new DataResponse();
1340
+        }
1341
+        // Go
1342
+        $subAdminManager->createSubAdmin($user, $group);
1343
+        return new DataResponse();
1344
+    }
1345
+
1346
+    /**
1347
+     * Removes a subadmin from a group
1348
+     *
1349
+     * @PasswordConfirmationRequired
1350
+     *
1351
+     * @param string $userId
1352
+     * @param string $groupid
1353
+     * @return DataResponse
1354
+     * @throws OCSException
1355
+     */
1356
+    public function removeSubAdmin(string $userId, string $groupid): DataResponse {
1357
+        $group = $this->groupManager->get($groupid);
1358
+        $user = $this->userManager->get($userId);
1359
+        $subAdminManager = $this->groupManager->getSubAdmin();
1360
+
1361
+        // Check if the user exists
1362
+        if ($user === null) {
1363
+            throw new OCSException('User does not exist', 101);
1364
+        }
1365
+        // Check if the group exists
1366
+        if ($group === null) {
1367
+            throw new OCSException('Group does not exist', 101);
1368
+        }
1369
+        // Check if they are a subadmin of this said group
1370
+        if (!$subAdminManager->isSubAdminOfGroup($user, $group)) {
1371
+            throw new OCSException('User is not a subadmin of this group', 102);
1372
+        }
1373
+
1374
+        // Go
1375
+        $subAdminManager->deleteSubAdmin($user, $group);
1376
+        return new DataResponse();
1377
+    }
1378
+
1379
+    /**
1380
+     * Get the groups a user is a subadmin of
1381
+     *
1382
+     * @param string $userId
1383
+     * @return DataResponse
1384
+     * @throws OCSException
1385
+     */
1386
+    public function getUserSubAdminGroups(string $userId): DataResponse {
1387
+        $groups = $this->getUserSubAdminGroupsData($userId);
1388
+        return new DataResponse($groups);
1389
+    }
1390
+
1391
+    /**
1392
+     * @NoAdminRequired
1393
+     * @PasswordConfirmationRequired
1394
+     *
1395
+     * resend welcome message
1396
+     *
1397
+     * @param string $userId
1398
+     * @return DataResponse
1399
+     * @throws OCSException
1400
+     */
1401
+    public function resendWelcomeMessage(string $userId): DataResponse {
1402
+        $currentLoggedInUser = $this->userSession->getUser();
1403
+
1404
+        $targetUser = $this->userManager->get($userId);
1405
+        if ($targetUser === null) {
1406
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1407
+        }
1408
+
1409
+        // Check if admin / subadmin
1410
+        $subAdminManager = $this->groupManager->getSubAdmin();
1411
+        if (
1412
+            !$subAdminManager->isUserAccessible($currentLoggedInUser, $targetUser)
1413
+            && !$this->groupManager->isAdmin($currentLoggedInUser->getUID())
1414
+        ) {
1415
+            // No rights
1416
+            throw new OCSException('', OCSController::RESPOND_NOT_FOUND);
1417
+        }
1418
+
1419
+        $email = $targetUser->getEMailAddress();
1420
+        if ($email === '' || $email === null) {
1421
+            throw new OCSException('Email address not available', 101);
1422
+        }
1423
+
1424
+        try {
1425
+            $emailTemplate = $this->newUserMailHelper->generateTemplate($targetUser, false);
1426
+            $this->newUserMailHelper->sendMail($targetUser, $emailTemplate);
1427
+        } catch (\Exception $e) {
1428
+            $this->logger->error(
1429
+                "Can't send new user mail to $email",
1430
+                [
1431
+                    'app' => 'settings',
1432
+                    'exception' => $e,
1433
+                ]
1434
+            );
1435
+            throw new OCSException('Sending email failed', 102);
1436
+        }
1437
+
1438
+        return new DataResponse();
1439
+    }
1440 1440
 }
Please login to merge, or discard this patch.
Spacing   +40 added lines, -40 removed lines patch added patch discarded remove patch
@@ -293,7 +293,7 @@  discard block
 block discarded – undo
293 293
 		$matches = [];
294 294
 		foreach ($userMatches as $phone => $userId) {
295 295
 			// Not using the ICloudIdManager as that would run a search for each contact to find the display name in the address book
296
-			$matches[$normalizedNumberToKey[$phone]] = $userId . '@' . $cloudUrl;
296
+			$matches[$normalizedNumberToKey[$phone]] = $userId.'@'.$cloudUrl;
297 297
 			$this->knownUserService->storeIsKnownToUser($knownTo, $userId);
298 298
 		}
299 299
 
@@ -357,10 +357,10 @@  discard block
 block discarded – undo
357 357
 		if ($groups !== []) {
358 358
 			foreach ($groups as $group) {
359 359
 				if (!$this->groupManager->groupExists($group)) {
360
-					throw new OCSException('group ' . $group . ' does not exist', 104);
360
+					throw new OCSException('group '.$group.' does not exist', 104);
361 361
 				}
362 362
 				if (!$isAdmin && !$subAdminManager->isSubAdminOfGroup($user, $this->groupManager->get($group))) {
363
-					throw new OCSException('insufficient privileges for group ' . $group, 105);
363
+					throw new OCSException('insufficient privileges for group '.$group, 105);
364 364
 				}
365 365
 			}
366 366
 		} else {
@@ -419,11 +419,11 @@  discard block
 block discarded – undo
419 419
 
420 420
 		try {
421 421
 			$newUser = $this->userManager->createUser($userid, $password);
422
-			$this->logger->info('Successful addUser call with userid: ' . $userid, ['app' => 'ocs_api']);
422
+			$this->logger->info('Successful addUser call with userid: '.$userid, ['app' => 'ocs_api']);
423 423
 
424 424
 			foreach ($groups as $group) {
425 425
 				$this->groupManager->get($group)->addUser($newUser);
426
-				$this->logger->info('Added userid ' . $userid . ' to group ' . $group, ['app' => 'ocs_api']);
426
+				$this->logger->info('Added userid '.$userid.' to group '.$group, ['app' => 'ocs_api']);
427 427
 			}
428 428
 			foreach ($subadminGroups as $group) {
429 429
 				$subAdminManager->createSubAdmin($newUser, $group);
@@ -669,7 +669,7 @@  discard block
 block discarded – undo
669 669
 		if ($targetUser->getUID() === $currentLoggedInUser->getUID()) {
670 670
 			// Editing self (display, email)
671 671
 			$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
672
-			$permittedFields[] = IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX;
672
+			$permittedFields[] = IAccountManager::COLLECTION_EMAIL.self::SCOPE_SUFFIX;
673 673
 		} else {
674 674
 			// Check if admin / subadmin
675 675
 			if ($isAdminOrSubadmin) {
@@ -702,7 +702,7 @@  discard block
 block discarded – undo
702 702
 				$this->accountManager->updateAccount($userAccount);
703 703
 				break;
704 704
 
705
-			case IAccountManager::COLLECTION_EMAIL . self::SCOPE_SUFFIX:
705
+			case IAccountManager::COLLECTION_EMAIL.self::SCOPE_SUFFIX:
706 706
 				$userAccount = $this->accountManager->getAccount($targetUser);
707 707
 				$mailCollection = $userAccount->getPropertyCollection(IAccountManager::COLLECTION_EMAIL);
708 708
 				$targetProperty = null;
@@ -766,8 +766,8 @@  discard block
 block discarded – undo
766 766
 				$permittedFields[] = IAccountManager::PROPERTY_EMAIL;
767 767
 			}
768 768
 
769
-			$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX;
770
-			$permittedFields[] = IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX;
769
+			$permittedFields[] = IAccountManager::PROPERTY_DISPLAYNAME.self::SCOPE_SUFFIX;
770
+			$permittedFields[] = IAccountManager::PROPERTY_EMAIL.self::SCOPE_SUFFIX;
771 771
 
772 772
 			$permittedFields[] = IAccountManager::COLLECTION_EMAIL;
773 773
 
@@ -797,18 +797,18 @@  discard block
 block discarded – undo
797 797
 			$permittedFields[] = IAccountManager::PROPERTY_HEADLINE;
798 798
 			$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY;
799 799
 			$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED;
800
-			$permittedFields[] = IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX;
801
-			$permittedFields[] = IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX;
802
-			$permittedFields[] = IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX;
803
-			$permittedFields[] = IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX;
804
-			$permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE . self::SCOPE_SUFFIX;
805
-			$permittedFields[] = IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX;
806
-			$permittedFields[] = IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX;
807
-			$permittedFields[] = IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX;
808
-			$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX;
809
-			$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX;
810
-
811
-			$permittedFields[] = IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX;
800
+			$permittedFields[] = IAccountManager::PROPERTY_PHONE.self::SCOPE_SUFFIX;
801
+			$permittedFields[] = IAccountManager::PROPERTY_ADDRESS.self::SCOPE_SUFFIX;
802
+			$permittedFields[] = IAccountManager::PROPERTY_WEBSITE.self::SCOPE_SUFFIX;
803
+			$permittedFields[] = IAccountManager::PROPERTY_TWITTER.self::SCOPE_SUFFIX;
804
+			$permittedFields[] = IAccountManager::PROPERTY_FEDIVERSE.self::SCOPE_SUFFIX;
805
+			$permittedFields[] = IAccountManager::PROPERTY_ORGANISATION.self::SCOPE_SUFFIX;
806
+			$permittedFields[] = IAccountManager::PROPERTY_ROLE.self::SCOPE_SUFFIX;
807
+			$permittedFields[] = IAccountManager::PROPERTY_HEADLINE.self::SCOPE_SUFFIX;
808
+			$permittedFields[] = IAccountManager::PROPERTY_BIOGRAPHY.self::SCOPE_SUFFIX;
809
+			$permittedFields[] = IAccountManager::PROPERTY_PROFILE_ENABLED.self::SCOPE_SUFFIX;
810
+
811
+			$permittedFields[] = IAccountManager::PROPERTY_AVATAR.self::SCOPE_SUFFIX;
812 812
 
813 813
 			// If admin they can edit their own quota and manager
814 814
 			if ($this->groupManager->isAdmin($currentLoggedInUser->getUID())) {
@@ -877,14 +877,14 @@  discard block
 block discarded – undo
877 877
 						$quota = \OCP\Util::computerFileSize($quota);
878 878
 					}
879 879
 					if ($quota === false) {
880
-						throw new OCSException('Invalid quota value ' . $value, 102);
880
+						throw new OCSException('Invalid quota value '.$value, 102);
881 881
 					}
882 882
 					if ($quota === -1) {
883 883
 						$quota = 'none';
884 884
 					} else {
885 885
 						$maxQuota = (int) $this->config->getAppValue('files', 'max_quota', '-1');
886 886
 						if ($maxQuota !== -1 && $quota > $maxQuota) {
887
-							throw new OCSException('Invalid quota value. ' . $value . ' is exceeding the maximum quota', 102);
887
+							throw new OCSException('Invalid quota value. '.$value.' is exceeding the maximum quota', 102);
888 888
 						}
889 889
 						$quota = \OCP\Util::humanFileSize($quota);
890 890
 					}
@@ -988,7 +988,7 @@  discard block
 block discarded – undo
988 988
 								$this->knownUserService->deleteByContactUserId($targetUser->getUID());
989 989
 							}
990 990
 						} catch (InvalidArgumentException $e) {
991
-							throw new OCSException('Invalid ' . $e->getMessage(), 102);
991
+							throw new OCSException('Invalid '.$e->getMessage(), 102);
992 992
 						}
993 993
 					}
994 994
 				} catch (PropertyDoesNotExistException $e) {
@@ -997,7 +997,7 @@  discard block
 block discarded – undo
997 997
 				try {
998 998
 					$this->accountManager->updateAccount($userAccount);
999 999
 				} catch (InvalidArgumentException $e) {
1000
-					throw new OCSException('Invalid ' . $e->getMessage(), 102);
1000
+					throw new OCSException('Invalid '.$e->getMessage(), 102);
1001 1001
 				}
1002 1002
 				break;
1003 1003
 			case IAccountManager::PROPERTY_PROFILE_ENABLED:
@@ -1012,19 +1012,19 @@  discard block
 block discarded – undo
1012 1012
 				}
1013 1013
 				$this->accountManager->updateAccount($userAccount);
1014 1014
 				break;
1015
-			case IAccountManager::PROPERTY_DISPLAYNAME . self::SCOPE_SUFFIX:
1016
-			case IAccountManager::PROPERTY_EMAIL . self::SCOPE_SUFFIX:
1017
-			case IAccountManager::PROPERTY_PHONE . self::SCOPE_SUFFIX:
1018
-			case IAccountManager::PROPERTY_ADDRESS . self::SCOPE_SUFFIX:
1019
-			case IAccountManager::PROPERTY_WEBSITE . self::SCOPE_SUFFIX:
1020
-			case IAccountManager::PROPERTY_TWITTER . self::SCOPE_SUFFIX:
1021
-			case IAccountManager::PROPERTY_FEDIVERSE . self::SCOPE_SUFFIX:
1022
-			case IAccountManager::PROPERTY_ORGANISATION . self::SCOPE_SUFFIX:
1023
-			case IAccountManager::PROPERTY_ROLE . self::SCOPE_SUFFIX:
1024
-			case IAccountManager::PROPERTY_HEADLINE . self::SCOPE_SUFFIX:
1025
-			case IAccountManager::PROPERTY_BIOGRAPHY . self::SCOPE_SUFFIX:
1026
-			case IAccountManager::PROPERTY_PROFILE_ENABLED . self::SCOPE_SUFFIX:
1027
-			case IAccountManager::PROPERTY_AVATAR . self::SCOPE_SUFFIX:
1015
+			case IAccountManager::PROPERTY_DISPLAYNAME.self::SCOPE_SUFFIX:
1016
+			case IAccountManager::PROPERTY_EMAIL.self::SCOPE_SUFFIX:
1017
+			case IAccountManager::PROPERTY_PHONE.self::SCOPE_SUFFIX:
1018
+			case IAccountManager::PROPERTY_ADDRESS.self::SCOPE_SUFFIX:
1019
+			case IAccountManager::PROPERTY_WEBSITE.self::SCOPE_SUFFIX:
1020
+			case IAccountManager::PROPERTY_TWITTER.self::SCOPE_SUFFIX:
1021
+			case IAccountManager::PROPERTY_FEDIVERSE.self::SCOPE_SUFFIX:
1022
+			case IAccountManager::PROPERTY_ORGANISATION.self::SCOPE_SUFFIX:
1023
+			case IAccountManager::PROPERTY_ROLE.self::SCOPE_SUFFIX:
1024
+			case IAccountManager::PROPERTY_HEADLINE.self::SCOPE_SUFFIX:
1025
+			case IAccountManager::PROPERTY_BIOGRAPHY.self::SCOPE_SUFFIX:
1026
+			case IAccountManager::PROPERTY_PROFILE_ENABLED.self::SCOPE_SUFFIX:
1027
+			case IAccountManager::PROPERTY_AVATAR.self::SCOPE_SUFFIX:
1028 1028
 				$propertyName = substr($key, 0, strlen($key) - strlen(self::SCOPE_SUFFIX));
1029 1029
 				$userAccount = $this->accountManager->getAccount($targetUser);
1030 1030
 				$userProperty = $userAccount->getProperty($propertyName);
@@ -1033,7 +1033,7 @@  discard block
 block discarded – undo
1033 1033
 						$userProperty->setScope($value);
1034 1034
 						$this->accountManager->updateAccount($userAccount);
1035 1035
 					} catch (InvalidArgumentException $e) {
1036
-						throw new OCSException('Invalid ' . $e->getMessage(), 102);
1036
+						throw new OCSException('Invalid '.$e->getMessage(), 102);
1037 1037
 					}
1038 1038
 				}
1039 1039
 				break;
@@ -1288,7 +1288,7 @@  discard block
 block discarded – undo
1288 1288
 		} elseif (!$this->groupManager->isAdmin($loggedInUser->getUID())) {
1289 1289
 			/** @var IGroup[] $subAdminGroups */
1290 1290
 			$subAdminGroups = $subAdminManager->getSubAdminsGroups($loggedInUser);
1291
-			$subAdminGroups = array_map(function (IGroup $subAdminGroup) {
1291
+			$subAdminGroups = array_map(function(IGroup $subAdminGroup) {
1292 1292
 				return $subAdminGroup->getGID();
1293 1293
 			}, $subAdminGroups);
1294 1294
 			$userGroups = $this->groupManager->getUserGroupIds($targetUser);
Please login to merge, or discard this patch.