Completed
Push — master ( 88ba65...9a0892 )
by Christoph
24:20
created
apps/settings/templates/settings/personal/personal.info.php 2 patches
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -27,12 +27,12 @@
 block discarded – undo
27 27
 /** @var array $_ */
28 28
 
29 29
 script('settings', [
30
-	'usersettings',
31
-	'templates',
32
-	'federationsettingsview',
33
-	'federationscopemenu',
34
-	'settings/personalInfo',
35
-	'vue-settings-personal-info',
30
+    'usersettings',
31
+    'templates',
32
+    'federationsettingsview',
33
+    'federationscopemenu',
34
+    'settings/personalInfo',
35
+    'vue-settings-personal-info',
36 36
 ]);
37 37
 ?>
38 38
 <?php if (!$_['isFairUseOfFreePushService']) : ?>
Please login to merge, or discard this patch.
Braces   +5 added lines, -2 removed lines patch added patch discarded remove patch
@@ -53,11 +53,14 @@
 block discarded – undo
53 53
 		<div class="personal-settings-setting-box personal-settings-setting-box-detail">
54 54
 			<div id="vue-details-section"></div>
55 55
 		</div>
56
-	<?php else: ?>
56
+	<?php else {
57
+    : ?>
57 58
 		<div class="personal-settings-setting-box personal-settings-setting-box-detail--without-profile">
58 59
 			<div id="vue-details-section"></div>
59 60
 		</div>
60
-	<?php endif; ?>
61
+	<?php endif;
62
+}
63
+?>
61 64
 	<div class="personal-settings-setting-box">
62 65
 		<div id="vue-displayname-section"></div>
63 66
 	</div>
Please login to merge, or discard this patch.
lib/public/Dashboard/IOptionWidget.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -30,9 +30,9 @@
 block discarded – undo
30 30
  * @since 25.0.0
31 31
  */
32 32
 interface IOptionWidget extends IWidget {
33
-	/**
34
-	 * Get additional options for the widget
35
-	 * @since 25.0.0
36
-	 */
37
-	public function getWidgetOptions(): WidgetOptions;
33
+    /**
34
+     * Get additional options for the widget
35
+     * @since 25.0.0
36
+     */
37
+    public function getWidgetOptions(): WidgetOptions;
38 38
 }
Please login to merge, or discard this patch.
lib/public/Dashboard/Model/WidgetOptions.php 1 patch
Indentation   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -29,33 +29,33 @@
 block discarded – undo
29 29
  * @since 25.0.0
30 30
  */
31 31
 class WidgetOptions {
32
-	private bool $roundItemIcons;
32
+    private bool $roundItemIcons;
33 33
 
34
-	/**
35
-	 * @param bool $roundItemIcons
36
-	 * @since 25.0.0
37
-	 */
38
-	public function __construct(bool $roundItemIcons) {
39
-		$this->roundItemIcons = $roundItemIcons;
40
-	}
34
+    /**
35
+     * @param bool $roundItemIcons
36
+     * @since 25.0.0
37
+     */
38
+    public function __construct(bool $roundItemIcons) {
39
+        $this->roundItemIcons = $roundItemIcons;
40
+    }
41 41
 
42
-	/**
43
-	 * Get the default set of options
44
-	 *
45
-	 * @return WidgetOptions
46
-	 * @since 25.0.0
47
-	 */
48
-	public static function getDefault(): WidgetOptions {
49
-		return new WidgetOptions(false);
50
-	}
42
+    /**
43
+     * Get the default set of options
44
+     *
45
+     * @return WidgetOptions
46
+     * @since 25.0.0
47
+     */
48
+    public static function getDefault(): WidgetOptions {
49
+        return new WidgetOptions(false);
50
+    }
51 51
 
52
-	/**
53
-	 * Whether the clients should render icons for widget items as round icons
54
-	 *
55
-	 * @return bool
56
-	 * @since 25.0.0
57
-	 */
58
-	public function withRoundItemIcons(): bool {
59
-		return $this->roundItemIcons;
60
-	}
52
+    /**
53
+     * Whether the clients should render icons for widget items as round icons
54
+     *
55
+     * @return bool
56
+     * @since 25.0.0
57
+     */
58
+    public function withRoundItemIcons(): bool {
59
+        return $this->roundItemIcons;
60
+    }
61 61
 }
Please login to merge, or discard this patch.
apps/settings/lib/Settings/Personal/PersonalInfo.php 2 patches
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -234,7 +234,7 @@  discard block
 block discarded – undo
234 234
 	 */
235 235
 	private function getGroups(IUser $user): array {
236 236
 		$groups = array_map(
237
-			static function (IGroup $group) {
237
+			static function(IGroup $group) {
238 238
 				return $group->getDisplayName();
239 239
 			},
240 240
 			$this->groupManager->getUserGroups($user)
@@ -257,7 +257,7 @@  discard block
 block discarded – undo
257 257
 		];
258 258
 
259 259
 		$additionalEmails = array_map(
260
-			function (IAccountProperty $property) {
260
+			function(IAccountProperty $property) {
261 261
 				return [
262 262
 					'name' => $property->getName(),
263 263
 					'value' => $property->getValue(),
@@ -272,7 +272,7 @@  discard block
 block discarded – undo
272 272
 		$emailMap = [
273 273
 			'primaryEmail' => $systemEmail,
274 274
 			'additionalEmails' => $additionalEmails,
275
-			'notificationEmail' => (string)$account->getUser()->getPrimaryEMailAddress(),
275
+			'notificationEmail' => (string) $account->getUser()->getPrimaryEMailAddress(),
276 276
 		];
277 277
 
278 278
 		return $emailMap;
@@ -366,7 +366,7 @@  discard block
 block discarded – undo
366 366
 				default:
367 367
 					$message = $this->l->t('Verify');
368 368
 			}
369
-			$messageParameters[$property . 'Message'] = $message;
369
+			$messageParameters[$property.'Message'] = $message;
370 370
 		}
371 371
 		return $messageParameters;
372 372
 	}
Please login to merge, or discard this patch.
Indentation   +285 added lines, -285 removed lines patch added patch discarded remove patch
@@ -33,289 +33,289 @@
 block discarded – undo
33 33
 
34 34
 class PersonalInfo implements ISettings {
35 35
 
36
-	/** @var ProfileManager */
37
-	private $profileManager;
38
-
39
-	public function __construct(
40
-		private IConfig $config,
41
-		private IUserManager $userManager,
42
-		private IGroupManager $groupManager,
43
-		private IAccountManager $accountManager,
44
-		ProfileManager $profileManager,
45
-		private IAppManager $appManager,
46
-		private IFactory $l10nFactory,
47
-		private IL10N $l,
48
-		private IInitialState $initialStateService,
49
-		private IManager $manager,
50
-	) {
51
-		$this->profileManager = $profileManager;
52
-	}
53
-
54
-	public function getForm(): TemplateResponse {
55
-		$federationEnabled = $this->appManager->isEnabledForUser('federation');
56
-		$federatedFileSharingEnabled = $this->appManager->isEnabledForUser('federatedfilesharing');
57
-		$lookupServerUploadEnabled = false;
58
-		if ($federatedFileSharingEnabled) {
59
-			/** @var FederatedShareProvider $shareProvider */
60
-			$shareProvider = Server::get(FederatedShareProvider::class);
61
-			$lookupServerUploadEnabled = $shareProvider->isLookupServerUploadEnabled();
62
-		}
63
-
64
-		$uid = \OC_User::getUser();
65
-		$user = $this->userManager->get($uid);
66
-		$account = $this->accountManager->getAccount($user);
67
-
68
-		// make sure FS is setup before querying storage related stuff...
69
-		\OC_Util::setupFS($user->getUID());
70
-
71
-		$storageInfo = \OC_Helper::getStorageInfo('/');
72
-		if ($storageInfo['quota'] === FileInfo::SPACE_UNLIMITED) {
73
-			$totalSpace = $this->l->t('Unlimited');
74
-		} else {
75
-			$totalSpace = Util::humanFileSize($storageInfo['total']);
76
-		}
77
-
78
-		$messageParameters = $this->getMessageParameters($account);
79
-
80
-		$parameters = [
81
-			'lookupServerUploadEnabled' => $lookupServerUploadEnabled,
82
-			'isFairUseOfFreePushService' => $this->isFairUseOfFreePushService(),
83
-			'profileEnabledGlobally' => $this->profileManager->isProfileEnabled(),
84
-		] + $messageParameters;
85
-
86
-		$personalInfoParameters = [
87
-			'userId' => $uid,
88
-			'avatar' => $this->getProperty($account, IAccountManager::PROPERTY_AVATAR),
89
-			'groups' => $this->getGroups($user),
90
-			'quota' => $storageInfo['quota'],
91
-			'totalSpace' => $totalSpace,
92
-			'usage' => Util::humanFileSize($storageInfo['used']),
93
-			'usageRelative' => round($storageInfo['relative']),
94
-			'displayName' => $this->getProperty($account, IAccountManager::PROPERTY_DISPLAYNAME),
95
-			'emailMap' => $this->getEmailMap($account),
96
-			'phone' => $this->getProperty($account, IAccountManager::PROPERTY_PHONE),
97
-			'defaultPhoneRegion' => $this->config->getSystemValueString('default_phone_region'),
98
-			'location' => $this->getProperty($account, IAccountManager::PROPERTY_ADDRESS),
99
-			'website' => $this->getProperty($account, IAccountManager::PROPERTY_WEBSITE),
100
-			'twitter' => $this->getProperty($account, IAccountManager::PROPERTY_TWITTER),
101
-			'bluesky' => $this->getProperty($account, IAccountManager::PROPERTY_BLUESKY),
102
-			'fediverse' => $this->getProperty($account, IAccountManager::PROPERTY_FEDIVERSE),
103
-			'languageMap' => $this->getLanguageMap($user),
104
-			'localeMap' => $this->getLocaleMap($user),
105
-			'profileEnabledGlobally' => $this->profileManager->isProfileEnabled(),
106
-			'profileEnabled' => $this->profileManager->isProfileEnabled($user),
107
-			'organisation' => $this->getProperty($account, IAccountManager::PROPERTY_ORGANISATION),
108
-			'role' => $this->getProperty($account, IAccountManager::PROPERTY_ROLE),
109
-			'headline' => $this->getProperty($account, IAccountManager::PROPERTY_HEADLINE),
110
-			'biography' => $this->getProperty($account, IAccountManager::PROPERTY_BIOGRAPHY),
111
-			'birthdate' => $this->getProperty($account, IAccountManager::PROPERTY_BIRTHDATE),
112
-			'firstDayOfWeek' => $this->config->getUserValue($uid, 'core', AUserDataOCSController::USER_FIELD_FIRST_DAY_OF_WEEK),
113
-			'timezone' => $this->config->getUserValue($uid, 'core', 'timezone', ''),
114
-			'pronouns' => $this->getProperty($account, IAccountManager::PROPERTY_PRONOUNS),
115
-		];
116
-
117
-		$accountParameters = [
118
-			'avatarChangeSupported' => $user->canChangeAvatar(),
119
-			'displayNameChangeSupported' => $user->canChangeDisplayName(),
120
-			'emailChangeSupported' => $user->canChangeEmail(),
121
-			'federationEnabled' => $federationEnabled,
122
-			'lookupServerUploadEnabled' => $lookupServerUploadEnabled,
123
-		];
124
-
125
-		$profileParameters = [
126
-			'profileConfig' => $this->profileManager->getProfileConfigWithMetadata($user, $user),
127
-		];
128
-
129
-		$this->initialStateService->provideInitialState('profileEnabledGlobally', $this->profileManager->isProfileEnabled());
130
-		$this->initialStateService->provideInitialState('personalInfoParameters', $personalInfoParameters);
131
-		$this->initialStateService->provideInitialState('accountParameters', $accountParameters);
132
-		$this->initialStateService->provideInitialState('profileParameters', $profileParameters);
133
-
134
-		return new TemplateResponse('settings', 'settings/personal/personal.info', $parameters, '');
135
-	}
136
-
137
-	/**
138
-	 * Check if is fair use of free push service
139
-	 * @return boolean
140
-	 */
141
-	private function isFairUseOfFreePushService(): bool {
142
-		return $this->manager->isFairUseOfFreePushService();
143
-	}
144
-
145
-	/**
146
-	 * returns the property data in an
147
-	 * associative array
148
-	 */
149
-	private function getProperty(IAccount $account, string $property): array {
150
-		$property = [
151
-			'name' => $account->getProperty($property)->getName(),
152
-			'value' => $account->getProperty($property)->getValue(),
153
-			'scope' => $account->getProperty($property)->getScope(),
154
-			'verified' => $account->getProperty($property)->getVerified(),
155
-		];
156
-
157
-		return $property;
158
-	}
159
-
160
-	/**
161
-	 * returns the section ID string, e.g. 'sharing'
162
-	 * @since 9.1
163
-	 */
164
-	public function getSection(): string {
165
-		return 'personal-info';
166
-	}
167
-
168
-	/**
169
-	 * @return int whether the form should be rather on the top or bottom of
170
-	 *             the admin section. The forms are arranged in ascending order of the
171
-	 *             priority values. It is required to return a value between 0 and 100.
172
-	 *
173
-	 * E.g.: 70
174
-	 * @since 9.1
175
-	 */
176
-	public function getPriority(): int {
177
-		return 10;
178
-	}
179
-
180
-	/**
181
-	 * returns a sorted list of the user's group GIDs
182
-	 */
183
-	private function getGroups(IUser $user): array {
184
-		$groups = array_map(
185
-			static function (IGroup $group) {
186
-				return $group->getDisplayName();
187
-			},
188
-			$this->groupManager->getUserGroups($user)
189
-		);
190
-		sort($groups);
191
-
192
-		return $groups;
193
-	}
194
-
195
-	/**
196
-	 * returns the primary email and additional emails in an
197
-	 * associative array
198
-	 */
199
-	private function getEmailMap(IAccount $account): array {
200
-		$systemEmail = [
201
-			'name' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getName(),
202
-			'value' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getValue(),
203
-			'scope' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope(),
204
-			'verified' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getVerified(),
205
-		];
206
-
207
-		$additionalEmails = array_map(
208
-			function (IAccountProperty $property) {
209
-				return [
210
-					'name' => $property->getName(),
211
-					'value' => $property->getValue(),
212
-					'scope' => $property->getScope(),
213
-					'verified' => $property->getVerified(),
214
-					'locallyVerified' => $property->getLocallyVerified(),
215
-				];
216
-			},
217
-			$account->getPropertyCollection(IAccountManager::COLLECTION_EMAIL)->getProperties(),
218
-		);
219
-
220
-		$emailMap = [
221
-			'primaryEmail' => $systemEmail,
222
-			'additionalEmails' => $additionalEmails,
223
-			'notificationEmail' => (string)$account->getUser()->getPrimaryEMailAddress(),
224
-		];
225
-
226
-		return $emailMap;
227
-	}
228
-
229
-	/**
230
-	 * returns the user's active language, common languages, and other languages in an
231
-	 * associative array
232
-	 */
233
-	private function getLanguageMap(IUser $user): array {
234
-		$forceLanguage = $this->config->getSystemValue('force_language', false);
235
-		if ($forceLanguage !== false) {
236
-			return [];
237
-		}
238
-
239
-		$uid = $user->getUID();
240
-
241
-		$userConfLang = $this->config->getUserValue($uid, 'core', 'lang', $this->l10nFactory->findLanguage());
242
-		$languages = $this->l10nFactory->getLanguages();
243
-
244
-		// associate the user language with the proper array
245
-		$userLangIndex = array_search($userConfLang, array_column($languages['commonLanguages'], 'code'));
246
-		$userLang = $languages['commonLanguages'][$userLangIndex];
247
-		// search in the other languages
248
-		if ($userLangIndex === false) {
249
-			$userLangIndex = array_search($userConfLang, array_column($languages['otherLanguages'], 'code'));
250
-			$userLang = $languages['otherLanguages'][$userLangIndex];
251
-		}
252
-		// if user language is not available but set somehow: show the actual code as name
253
-		if (!is_array($userLang)) {
254
-			$userLang = [
255
-				'code' => $userConfLang,
256
-				'name' => $userConfLang,
257
-			];
258
-		}
259
-
260
-		return array_merge(
261
-			['activeLanguage' => $userLang],
262
-			$languages
263
-		);
264
-	}
265
-
266
-	private function getLocaleMap(IUser $user): array {
267
-		$forceLanguage = $this->config->getSystemValue('force_locale', false);
268
-		if ($forceLanguage !== false) {
269
-			return [];
270
-		}
271
-
272
-		$uid = $user->getUID();
273
-		$userLang = $this->config->getUserValue($uid, 'core', 'lang', $this->l10nFactory->findLanguage());
274
-		$userLocaleString = $this->config->getUserValue($uid, 'core', 'locale', $this->l10nFactory->findLocale($userLang));
275
-		$localeCodes = $this->l10nFactory->findAvailableLocales();
276
-		$userLocale = array_filter($localeCodes, fn ($value) => $userLocaleString === $value['code']);
277
-
278
-		if (!empty($userLocale)) {
279
-			$userLocale = reset($userLocale);
280
-		}
281
-
282
-		$localesForLanguage = array_values(array_filter($localeCodes, fn ($localeCode) => str_starts_with($localeCode['code'], $userLang)));
283
-		$otherLocales = array_values(array_filter($localeCodes, fn ($localeCode) => !str_starts_with($localeCode['code'], $userLang)));
284
-
285
-		if (!$userLocale) {
286
-			$userLocale = [
287
-				'code' => 'en',
288
-				'name' => 'English'
289
-			];
290
-		}
291
-
292
-		return [
293
-			'activeLocaleLang' => $userLocaleString,
294
-			'activeLocale' => $userLocale,
295
-			'localesForLanguage' => $localesForLanguage,
296
-			'otherLocales' => $otherLocales,
297
-		];
298
-	}
299
-
300
-	/**
301
-	 * returns the message parameters
302
-	 */
303
-	private function getMessageParameters(IAccount $account): array {
304
-		$needVerifyMessage = [IAccountManager::PROPERTY_EMAIL, IAccountManager::PROPERTY_WEBSITE, IAccountManager::PROPERTY_TWITTER];
305
-		$messageParameters = [];
306
-		foreach ($needVerifyMessage as $property) {
307
-			switch ($account->getProperty($property)->getVerified()) {
308
-				case IAccountManager::VERIFIED:
309
-					$message = $this->l->t('Verifying');
310
-					break;
311
-				case IAccountManager::VERIFICATION_IN_PROGRESS:
312
-					$message = $this->l->t('Verifying …');
313
-					break;
314
-				default:
315
-					$message = $this->l->t('Verify');
316
-			}
317
-			$messageParameters[$property . 'Message'] = $message;
318
-		}
319
-		return $messageParameters;
320
-	}
36
+    /** @var ProfileManager */
37
+    private $profileManager;
38
+
39
+    public function __construct(
40
+        private IConfig $config,
41
+        private IUserManager $userManager,
42
+        private IGroupManager $groupManager,
43
+        private IAccountManager $accountManager,
44
+        ProfileManager $profileManager,
45
+        private IAppManager $appManager,
46
+        private IFactory $l10nFactory,
47
+        private IL10N $l,
48
+        private IInitialState $initialStateService,
49
+        private IManager $manager,
50
+    ) {
51
+        $this->profileManager = $profileManager;
52
+    }
53
+
54
+    public function getForm(): TemplateResponse {
55
+        $federationEnabled = $this->appManager->isEnabledForUser('federation');
56
+        $federatedFileSharingEnabled = $this->appManager->isEnabledForUser('federatedfilesharing');
57
+        $lookupServerUploadEnabled = false;
58
+        if ($federatedFileSharingEnabled) {
59
+            /** @var FederatedShareProvider $shareProvider */
60
+            $shareProvider = Server::get(FederatedShareProvider::class);
61
+            $lookupServerUploadEnabled = $shareProvider->isLookupServerUploadEnabled();
62
+        }
63
+
64
+        $uid = \OC_User::getUser();
65
+        $user = $this->userManager->get($uid);
66
+        $account = $this->accountManager->getAccount($user);
67
+
68
+        // make sure FS is setup before querying storage related stuff...
69
+        \OC_Util::setupFS($user->getUID());
70
+
71
+        $storageInfo = \OC_Helper::getStorageInfo('/');
72
+        if ($storageInfo['quota'] === FileInfo::SPACE_UNLIMITED) {
73
+            $totalSpace = $this->l->t('Unlimited');
74
+        } else {
75
+            $totalSpace = Util::humanFileSize($storageInfo['total']);
76
+        }
77
+
78
+        $messageParameters = $this->getMessageParameters($account);
79
+
80
+        $parameters = [
81
+            'lookupServerUploadEnabled' => $lookupServerUploadEnabled,
82
+            'isFairUseOfFreePushService' => $this->isFairUseOfFreePushService(),
83
+            'profileEnabledGlobally' => $this->profileManager->isProfileEnabled(),
84
+        ] + $messageParameters;
85
+
86
+        $personalInfoParameters = [
87
+            'userId' => $uid,
88
+            'avatar' => $this->getProperty($account, IAccountManager::PROPERTY_AVATAR),
89
+            'groups' => $this->getGroups($user),
90
+            'quota' => $storageInfo['quota'],
91
+            'totalSpace' => $totalSpace,
92
+            'usage' => Util::humanFileSize($storageInfo['used']),
93
+            'usageRelative' => round($storageInfo['relative']),
94
+            'displayName' => $this->getProperty($account, IAccountManager::PROPERTY_DISPLAYNAME),
95
+            'emailMap' => $this->getEmailMap($account),
96
+            'phone' => $this->getProperty($account, IAccountManager::PROPERTY_PHONE),
97
+            'defaultPhoneRegion' => $this->config->getSystemValueString('default_phone_region'),
98
+            'location' => $this->getProperty($account, IAccountManager::PROPERTY_ADDRESS),
99
+            'website' => $this->getProperty($account, IAccountManager::PROPERTY_WEBSITE),
100
+            'twitter' => $this->getProperty($account, IAccountManager::PROPERTY_TWITTER),
101
+            'bluesky' => $this->getProperty($account, IAccountManager::PROPERTY_BLUESKY),
102
+            'fediverse' => $this->getProperty($account, IAccountManager::PROPERTY_FEDIVERSE),
103
+            'languageMap' => $this->getLanguageMap($user),
104
+            'localeMap' => $this->getLocaleMap($user),
105
+            'profileEnabledGlobally' => $this->profileManager->isProfileEnabled(),
106
+            'profileEnabled' => $this->profileManager->isProfileEnabled($user),
107
+            'organisation' => $this->getProperty($account, IAccountManager::PROPERTY_ORGANISATION),
108
+            'role' => $this->getProperty($account, IAccountManager::PROPERTY_ROLE),
109
+            'headline' => $this->getProperty($account, IAccountManager::PROPERTY_HEADLINE),
110
+            'biography' => $this->getProperty($account, IAccountManager::PROPERTY_BIOGRAPHY),
111
+            'birthdate' => $this->getProperty($account, IAccountManager::PROPERTY_BIRTHDATE),
112
+            'firstDayOfWeek' => $this->config->getUserValue($uid, 'core', AUserDataOCSController::USER_FIELD_FIRST_DAY_OF_WEEK),
113
+            'timezone' => $this->config->getUserValue($uid, 'core', 'timezone', ''),
114
+            'pronouns' => $this->getProperty($account, IAccountManager::PROPERTY_PRONOUNS),
115
+        ];
116
+
117
+        $accountParameters = [
118
+            'avatarChangeSupported' => $user->canChangeAvatar(),
119
+            'displayNameChangeSupported' => $user->canChangeDisplayName(),
120
+            'emailChangeSupported' => $user->canChangeEmail(),
121
+            'federationEnabled' => $federationEnabled,
122
+            'lookupServerUploadEnabled' => $lookupServerUploadEnabled,
123
+        ];
124
+
125
+        $profileParameters = [
126
+            'profileConfig' => $this->profileManager->getProfileConfigWithMetadata($user, $user),
127
+        ];
128
+
129
+        $this->initialStateService->provideInitialState('profileEnabledGlobally', $this->profileManager->isProfileEnabled());
130
+        $this->initialStateService->provideInitialState('personalInfoParameters', $personalInfoParameters);
131
+        $this->initialStateService->provideInitialState('accountParameters', $accountParameters);
132
+        $this->initialStateService->provideInitialState('profileParameters', $profileParameters);
133
+
134
+        return new TemplateResponse('settings', 'settings/personal/personal.info', $parameters, '');
135
+    }
136
+
137
+    /**
138
+     * Check if is fair use of free push service
139
+     * @return boolean
140
+     */
141
+    private function isFairUseOfFreePushService(): bool {
142
+        return $this->manager->isFairUseOfFreePushService();
143
+    }
144
+
145
+    /**
146
+     * returns the property data in an
147
+     * associative array
148
+     */
149
+    private function getProperty(IAccount $account, string $property): array {
150
+        $property = [
151
+            'name' => $account->getProperty($property)->getName(),
152
+            'value' => $account->getProperty($property)->getValue(),
153
+            'scope' => $account->getProperty($property)->getScope(),
154
+            'verified' => $account->getProperty($property)->getVerified(),
155
+        ];
156
+
157
+        return $property;
158
+    }
159
+
160
+    /**
161
+     * returns the section ID string, e.g. 'sharing'
162
+     * @since 9.1
163
+     */
164
+    public function getSection(): string {
165
+        return 'personal-info';
166
+    }
167
+
168
+    /**
169
+     * @return int whether the form should be rather on the top or bottom of
170
+     *             the admin section. The forms are arranged in ascending order of the
171
+     *             priority values. It is required to return a value between 0 and 100.
172
+     *
173
+     * E.g.: 70
174
+     * @since 9.1
175
+     */
176
+    public function getPriority(): int {
177
+        return 10;
178
+    }
179
+
180
+    /**
181
+     * returns a sorted list of the user's group GIDs
182
+     */
183
+    private function getGroups(IUser $user): array {
184
+        $groups = array_map(
185
+            static function (IGroup $group) {
186
+                return $group->getDisplayName();
187
+            },
188
+            $this->groupManager->getUserGroups($user)
189
+        );
190
+        sort($groups);
191
+
192
+        return $groups;
193
+    }
194
+
195
+    /**
196
+     * returns the primary email and additional emails in an
197
+     * associative array
198
+     */
199
+    private function getEmailMap(IAccount $account): array {
200
+        $systemEmail = [
201
+            'name' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getName(),
202
+            'value' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getValue(),
203
+            'scope' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getScope(),
204
+            'verified' => $account->getProperty(IAccountManager::PROPERTY_EMAIL)->getVerified(),
205
+        ];
206
+
207
+        $additionalEmails = array_map(
208
+            function (IAccountProperty $property) {
209
+                return [
210
+                    'name' => $property->getName(),
211
+                    'value' => $property->getValue(),
212
+                    'scope' => $property->getScope(),
213
+                    'verified' => $property->getVerified(),
214
+                    'locallyVerified' => $property->getLocallyVerified(),
215
+                ];
216
+            },
217
+            $account->getPropertyCollection(IAccountManager::COLLECTION_EMAIL)->getProperties(),
218
+        );
219
+
220
+        $emailMap = [
221
+            'primaryEmail' => $systemEmail,
222
+            'additionalEmails' => $additionalEmails,
223
+            'notificationEmail' => (string)$account->getUser()->getPrimaryEMailAddress(),
224
+        ];
225
+
226
+        return $emailMap;
227
+    }
228
+
229
+    /**
230
+     * returns the user's active language, common languages, and other languages in an
231
+     * associative array
232
+     */
233
+    private function getLanguageMap(IUser $user): array {
234
+        $forceLanguage = $this->config->getSystemValue('force_language', false);
235
+        if ($forceLanguage !== false) {
236
+            return [];
237
+        }
238
+
239
+        $uid = $user->getUID();
240
+
241
+        $userConfLang = $this->config->getUserValue($uid, 'core', 'lang', $this->l10nFactory->findLanguage());
242
+        $languages = $this->l10nFactory->getLanguages();
243
+
244
+        // associate the user language with the proper array
245
+        $userLangIndex = array_search($userConfLang, array_column($languages['commonLanguages'], 'code'));
246
+        $userLang = $languages['commonLanguages'][$userLangIndex];
247
+        // search in the other languages
248
+        if ($userLangIndex === false) {
249
+            $userLangIndex = array_search($userConfLang, array_column($languages['otherLanguages'], 'code'));
250
+            $userLang = $languages['otherLanguages'][$userLangIndex];
251
+        }
252
+        // if user language is not available but set somehow: show the actual code as name
253
+        if (!is_array($userLang)) {
254
+            $userLang = [
255
+                'code' => $userConfLang,
256
+                'name' => $userConfLang,
257
+            ];
258
+        }
259
+
260
+        return array_merge(
261
+            ['activeLanguage' => $userLang],
262
+            $languages
263
+        );
264
+    }
265
+
266
+    private function getLocaleMap(IUser $user): array {
267
+        $forceLanguage = $this->config->getSystemValue('force_locale', false);
268
+        if ($forceLanguage !== false) {
269
+            return [];
270
+        }
271
+
272
+        $uid = $user->getUID();
273
+        $userLang = $this->config->getUserValue($uid, 'core', 'lang', $this->l10nFactory->findLanguage());
274
+        $userLocaleString = $this->config->getUserValue($uid, 'core', 'locale', $this->l10nFactory->findLocale($userLang));
275
+        $localeCodes = $this->l10nFactory->findAvailableLocales();
276
+        $userLocale = array_filter($localeCodes, fn ($value) => $userLocaleString === $value['code']);
277
+
278
+        if (!empty($userLocale)) {
279
+            $userLocale = reset($userLocale);
280
+        }
281
+
282
+        $localesForLanguage = array_values(array_filter($localeCodes, fn ($localeCode) => str_starts_with($localeCode['code'], $userLang)));
283
+        $otherLocales = array_values(array_filter($localeCodes, fn ($localeCode) => !str_starts_with($localeCode['code'], $userLang)));
284
+
285
+        if (!$userLocale) {
286
+            $userLocale = [
287
+                'code' => 'en',
288
+                'name' => 'English'
289
+            ];
290
+        }
291
+
292
+        return [
293
+            'activeLocaleLang' => $userLocaleString,
294
+            'activeLocale' => $userLocale,
295
+            'localesForLanguage' => $localesForLanguage,
296
+            'otherLocales' => $otherLocales,
297
+        ];
298
+    }
299
+
300
+    /**
301
+     * returns the message parameters
302
+     */
303
+    private function getMessageParameters(IAccount $account): array {
304
+        $needVerifyMessage = [IAccountManager::PROPERTY_EMAIL, IAccountManager::PROPERTY_WEBSITE, IAccountManager::PROPERTY_TWITTER];
305
+        $messageParameters = [];
306
+        foreach ($needVerifyMessage as $property) {
307
+            switch ($account->getProperty($property)->getVerified()) {
308
+                case IAccountManager::VERIFIED:
309
+                    $message = $this->l->t('Verifying');
310
+                    break;
311
+                case IAccountManager::VERIFICATION_IN_PROGRESS:
312
+                    $message = $this->l->t('Verifying …');
313
+                    break;
314
+                default:
315
+                    $message = $this->l->t('Verify');
316
+            }
317
+            $messageParameters[$property . 'Message'] = $message;
318
+        }
319
+        return $messageParameters;
320
+    }
321 321
 }
Please login to merge, or discard this patch.
lib/private/User/Listeners/BeforeUserDeletedListener.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -57,7 +57,7 @@
 block discarded – undo
57 57
 			// no avatar to remove
58 58
 		} catch (\Exception $e) {
59 59
 			// Ignore exceptions
60
-			$this->logger->info('Could not cleanup avatar of ' . $user->getUID(), [
60
+			$this->logger->info('Could not cleanup avatar of '.$user->getUID(), [
61 61
 				'exception' => $e,
62 62
 			]);
63 63
 		}
Please login to merge, or discard this patch.
Indentation   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -20,36 +20,36 @@
 block discarded – undo
20 20
  * @template-implements IEventListener<BeforeUserDeletedEvent>
21 21
  */
22 22
 class BeforeUserDeletedListener implements IEventListener {
23
-	private IAvatarManager $avatarManager;
24
-	private ICredentialsManager $credentialsManager;
25
-	private LoggerInterface $logger;
26
-
27
-	public function __construct(LoggerInterface $logger, IAvatarManager $avatarManager, ICredentialsManager $credentialsManager) {
28
-		$this->avatarManager = $avatarManager;
29
-		$this->credentialsManager = $credentialsManager;
30
-		$this->logger = $logger;
31
-	}
32
-
33
-	public function handle(Event $event): void {
34
-		if (!($event instanceof BeforeUserDeletedEvent)) {
35
-			return;
36
-		}
37
-
38
-		$user = $event->getUser();
39
-
40
-		// Delete avatar on user deletion
41
-		try {
42
-			$avatar = $this->avatarManager->getAvatar($user->getUID());
43
-			$avatar->remove(true);
44
-		} catch (NotFoundException $e) {
45
-			// no avatar to remove
46
-		} catch (\Exception $e) {
47
-			// Ignore exceptions
48
-			$this->logger->info('Could not cleanup avatar of ' . $user->getUID(), [
49
-				'exception' => $e,
50
-			]);
51
-		}
52
-		// Delete storages credentials on user deletion
53
-		$this->credentialsManager->erase($user->getUID());
54
-	}
23
+    private IAvatarManager $avatarManager;
24
+    private ICredentialsManager $credentialsManager;
25
+    private LoggerInterface $logger;
26
+
27
+    public function __construct(LoggerInterface $logger, IAvatarManager $avatarManager, ICredentialsManager $credentialsManager) {
28
+        $this->avatarManager = $avatarManager;
29
+        $this->credentialsManager = $credentialsManager;
30
+        $this->logger = $logger;
31
+    }
32
+
33
+    public function handle(Event $event): void {
34
+        if (!($event instanceof BeforeUserDeletedEvent)) {
35
+            return;
36
+        }
37
+
38
+        $user = $event->getUser();
39
+
40
+        // Delete avatar on user deletion
41
+        try {
42
+            $avatar = $this->avatarManager->getAvatar($user->getUID());
43
+            $avatar->remove(true);
44
+        } catch (NotFoundException $e) {
45
+            // no avatar to remove
46
+        } catch (\Exception $e) {
47
+            // Ignore exceptions
48
+            $this->logger->info('Could not cleanup avatar of ' . $user->getUID(), [
49
+                'exception' => $e,
50
+            ]);
51
+        }
52
+        // Delete storages credentials on user deletion
53
+        $this->credentialsManager->erase($user->getUID());
54
+    }
55 55
 }
Please login to merge, or discard this patch.
lib/private/TagManager.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -123,7 +123,7 @@
 block discarded – undo
123 123
 			return;
124 124
 		}
125 125
 
126
-		$tagsIds = array_map(fn (array $row) => (int)$row['id'], $result->fetchAll());
126
+		$tagsIds = array_map(fn (array $row) => (int) $row['id'], $result->fetchAll());
127 127
 		$result->closeCursor();
128 128
 
129 129
 		if (count($tagsIds) === 0) {
Please login to merge, or discard this patch.
Indentation   +98 added lines, -98 removed lines patch added patch discarded remove patch
@@ -25,113 +25,113 @@
 block discarded – undo
25 25
  */
26 26
 class TagManager implements ITagManager, IEventListener {
27 27
 
28
-	public function __construct(
29
-		private TagMapper $mapper,
30
-		private IUserSession $userSession,
31
-		private IDBConnection $connection,
32
-		private LoggerInterface $logger,
33
-		private IEventDispatcher $dispatcher,
34
-	) {
35
-	}
28
+    public function __construct(
29
+        private TagMapper $mapper,
30
+        private IUserSession $userSession,
31
+        private IDBConnection $connection,
32
+        private LoggerInterface $logger,
33
+        private IEventDispatcher $dispatcher,
34
+    ) {
35
+    }
36 36
 
37
-	/**
38
-	 * Create a new \OCP\ITags instance and load tags from db.
39
-	 *
40
-	 * @see \OCP\ITags
41
-	 * @param string $type The type identifier e.g. 'contact' or 'event'.
42
-	 * @param array $defaultTags An array of default tags to be used if none are stored.
43
-	 * @param boolean $includeShared Whether to include tags for items shared with this user by others.
44
-	 * @param string $userId user for which to retrieve the tags, defaults to the currently
45
-	 *                       logged in user
46
-	 * @return \OCP\ITags
47
-	 *
48
-	 * since 20.0.0 $includeShared isn't used anymore
49
-	 */
50
-	public function load($type, $defaultTags = [], $includeShared = false, $userId = null) {
51
-		if (is_null($userId)) {
52
-			$user = $this->userSession->getUser();
53
-			if ($user === null) {
54
-				// nothing we can do without a user
55
-				return null;
56
-			}
57
-			$userId = $this->userSession->getUser()->getUId();
58
-		}
59
-		return new Tags($this->mapper, $userId, $type, $this->logger, $this->connection, $this->dispatcher, $this->userSession, $defaultTags);
60
-	}
37
+    /**
38
+     * Create a new \OCP\ITags instance and load tags from db.
39
+     *
40
+     * @see \OCP\ITags
41
+     * @param string $type The type identifier e.g. 'contact' or 'event'.
42
+     * @param array $defaultTags An array of default tags to be used if none are stored.
43
+     * @param boolean $includeShared Whether to include tags for items shared with this user by others.
44
+     * @param string $userId user for which to retrieve the tags, defaults to the currently
45
+     *                       logged in user
46
+     * @return \OCP\ITags
47
+     *
48
+     * since 20.0.0 $includeShared isn't used anymore
49
+     */
50
+    public function load($type, $defaultTags = [], $includeShared = false, $userId = null) {
51
+        if (is_null($userId)) {
52
+            $user = $this->userSession->getUser();
53
+            if ($user === null) {
54
+                // nothing we can do without a user
55
+                return null;
56
+            }
57
+            $userId = $this->userSession->getUser()->getUId();
58
+        }
59
+        return new Tags($this->mapper, $userId, $type, $this->logger, $this->connection, $this->dispatcher, $this->userSession, $defaultTags);
60
+    }
61 61
 
62
-	/**
63
-	 * Get all users who favorited an object
64
-	 *
65
-	 * @param string $objectType
66
-	 * @param int $objectId
67
-	 * @return array
68
-	 */
69
-	public function getUsersFavoritingObject(string $objectType, int $objectId): array {
70
-		$query = $this->connection->getQueryBuilder();
71
-		$query->select('uid')
72
-			->from('vcategory_to_object', 'o')
73
-			->innerJoin('o', 'vcategory', 'c', $query->expr()->eq('o.categoryid', 'c.id'))
74
-			->where($query->expr()->eq('objid', $query->createNamedParameter($objectId, IQueryBuilder::PARAM_INT)))
75
-			->andWhere($query->expr()->eq('c.type', $query->createNamedParameter($objectType)))
76
-			->andWhere($query->expr()->eq('c.category', $query->createNamedParameter(ITags::TAG_FAVORITE)));
62
+    /**
63
+     * Get all users who favorited an object
64
+     *
65
+     * @param string $objectType
66
+     * @param int $objectId
67
+     * @return array
68
+     */
69
+    public function getUsersFavoritingObject(string $objectType, int $objectId): array {
70
+        $query = $this->connection->getQueryBuilder();
71
+        $query->select('uid')
72
+            ->from('vcategory_to_object', 'o')
73
+            ->innerJoin('o', 'vcategory', 'c', $query->expr()->eq('o.categoryid', 'c.id'))
74
+            ->where($query->expr()->eq('objid', $query->createNamedParameter($objectId, IQueryBuilder::PARAM_INT)))
75
+            ->andWhere($query->expr()->eq('c.type', $query->createNamedParameter($objectType)))
76
+            ->andWhere($query->expr()->eq('c.category', $query->createNamedParameter(ITags::TAG_FAVORITE)));
77 77
 
78
-		$result = $query->execute();
79
-		$users = $result->fetchAll(\PDO::FETCH_COLUMN);
80
-		$result->closeCursor();
78
+        $result = $query->execute();
79
+        $users = $result->fetchAll(\PDO::FETCH_COLUMN);
80
+        $result->closeCursor();
81 81
 
82
-		return $users;
83
-	}
82
+        return $users;
83
+    }
84 84
 
85
-	public function handle(Event $event): void {
86
-		if (!($event instanceof UserDeletedEvent)) {
87
-			return;
88
-		}
85
+    public function handle(Event $event): void {
86
+        if (!($event instanceof UserDeletedEvent)) {
87
+            return;
88
+        }
89 89
 
90
-		// Find all objectid/tagId pairs.
91
-		$user = $event->getUser();
92
-		$qb = $this->connection->getQueryBuilder();
93
-		$qb->select('id')
94
-			->from('vcategory')
95
-			->where($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())));
96
-		try {
97
-			$result = $qb->executeQuery();
98
-		} catch (DBException $e) {
99
-			$this->logger->error($e->getMessage(), [
100
-				'app' => 'core',
101
-				'exception' => $e,
102
-			]);
103
-			return;
104
-		}
90
+        // Find all objectid/tagId pairs.
91
+        $user = $event->getUser();
92
+        $qb = $this->connection->getQueryBuilder();
93
+        $qb->select('id')
94
+            ->from('vcategory')
95
+            ->where($qb->expr()->eq('uid', $qb->createNamedParameter($user->getUID())));
96
+        try {
97
+            $result = $qb->executeQuery();
98
+        } catch (DBException $e) {
99
+            $this->logger->error($e->getMessage(), [
100
+                'app' => 'core',
101
+                'exception' => $e,
102
+            ]);
103
+            return;
104
+        }
105 105
 
106
-		$tagsIds = array_map(fn (array $row) => (int)$row['id'], $result->fetchAll());
107
-		$result->closeCursor();
106
+        $tagsIds = array_map(fn (array $row) => (int)$row['id'], $result->fetchAll());
107
+        $result->closeCursor();
108 108
 
109
-		if (count($tagsIds) === 0) {
110
-			return;
111
-		}
109
+        if (count($tagsIds) === 0) {
110
+            return;
111
+        }
112 112
 
113
-		// Clean vcategory_to_object table
114
-		$qb = $this->connection->getQueryBuilder();
115
-		$qb = $qb->delete('vcategory_to_object')
116
-			->where($qb->expr()->in('categoryid', $qb->createParameter('chunk')));
113
+        // Clean vcategory_to_object table
114
+        $qb = $this->connection->getQueryBuilder();
115
+        $qb = $qb->delete('vcategory_to_object')
116
+            ->where($qb->expr()->in('categoryid', $qb->createParameter('chunk')));
117 117
 
118
-		// Clean vcategory
119
-		$qb1 = $this->connection->getQueryBuilder();
120
-		$qb1 = $qb1->delete('vcategory')
121
-			->where($qb1->expr()->in('uid', $qb1->createParameter('chunk')));
118
+        // Clean vcategory
119
+        $qb1 = $this->connection->getQueryBuilder();
120
+        $qb1 = $qb1->delete('vcategory')
121
+            ->where($qb1->expr()->in('uid', $qb1->createParameter('chunk')));
122 122
 
123
-		foreach (array_chunk($tagsIds, 1000) as $tagChunk) {
124
-			$qb->setParameter('chunk', $tagChunk, IQueryBuilder::PARAM_INT_ARRAY);
125
-			$qb1->setParameter('chunk', $tagChunk, IQueryBuilder::PARAM_INT_ARRAY);
126
-			try {
127
-				$qb->executeStatement();
128
-				$qb1->executeStatement();
129
-			} catch (DBException $e) {
130
-				$this->logger->error($e->getMessage(), [
131
-					'app' => 'core',
132
-					'exception' => $e,
133
-				]);
134
-			}
135
-		}
136
-	}
123
+        foreach (array_chunk($tagsIds, 1000) as $tagChunk) {
124
+            $qb->setParameter('chunk', $tagChunk, IQueryBuilder::PARAM_INT_ARRAY);
125
+            $qb1->setParameter('chunk', $tagChunk, IQueryBuilder::PARAM_INT_ARRAY);
126
+            try {
127
+                $qb->executeStatement();
128
+                $qb1->executeStatement();
129
+            } catch (DBException $e) {
130
+                $this->logger->error($e->getMessage(), [
131
+                    'app' => 'core',
132
+                    'exception' => $e,
133
+                ]);
134
+            }
135
+        }
136
+    }
137 137
 }
Please login to merge, or discard this patch.
apps/files/lib/Controller/OpenLocalEditorController.php 2 patches
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -100,7 +100,7 @@
 block discarded – undo
100 100
 			}
101 101
 		}
102 102
 
103
-		$this->logger->error('Giving up after ' . self::TOKEN_RETRIES . ' retries to generate a unique local editor token for path hash: ' . $pathHash);
103
+		$this->logger->error('Giving up after '.self::TOKEN_RETRIES.' retries to generate a unique local editor token for path hash: '.$pathHash);
104 104
 		return new DataResponse([], Http::STATUS_INTERNAL_SERVER_ERROR);
105 105
 	}
106 106
 
Please login to merge, or discard this patch.
Indentation   +99 added lines, -99 removed lines patch added patch discarded remove patch
@@ -25,104 +25,104 @@
 block discarded – undo
25 25
 use Psr\Log\LoggerInterface;
26 26
 
27 27
 class OpenLocalEditorController extends OCSController {
28
-	public const TOKEN_LENGTH = 128;
29
-	public const TOKEN_DURATION = 600; // 10 Minutes
30
-	public const TOKEN_RETRIES = 50;
31
-
32
-	public function __construct(
33
-		string $appName,
34
-		IRequest $request,
35
-		protected ITimeFactory $timeFactory,
36
-		protected OpenLocalEditorMapper $mapper,
37
-		protected ISecureRandom $secureRandom,
38
-		protected LoggerInterface $logger,
39
-		protected ?string $userId,
40
-	) {
41
-		parent::__construct($appName, $request);
42
-	}
43
-
44
-	/**
45
-	 * Create a local editor
46
-	 *
47
-	 * @param string $path Path of the file
48
-	 *
49
-	 * @return DataResponse<Http::STATUS_OK, array{userId: ?string, pathHash: string, expirationTime: int, token: string}, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR, list<empty>, array{}>
50
-	 *
51
-	 * 200: Local editor returned
52
-	 */
53
-	#[NoAdminRequired]
54
-	#[UserRateLimit(limit: 10, period: 120)]
55
-	public function create(string $path): DataResponse {
56
-		$pathHash = sha1($path);
57
-
58
-		$entity = new OpenLocalEditor();
59
-		$entity->setUserId($this->userId);
60
-		$entity->setPathHash($pathHash);
61
-		$entity->setExpirationTime($this->timeFactory->getTime() + self::TOKEN_DURATION); // Expire in 10 minutes
62
-
63
-		for ($i = 1; $i <= self::TOKEN_RETRIES; $i++) {
64
-			$token = $this->secureRandom->generate(self::TOKEN_LENGTH, ISecureRandom::CHAR_ALPHANUMERIC);
65
-			$entity->setToken($token);
66
-
67
-			try {
68
-				$this->mapper->insert($entity);
69
-
70
-				return new DataResponse([
71
-					'userId' => $this->userId,
72
-					'pathHash' => $pathHash,
73
-					'expirationTime' => $entity->getExpirationTime(),
74
-					'token' => $entity->getToken(),
75
-				]);
76
-			} catch (Exception $e) {
77
-				if ($e->getCode() !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
78
-					// Only retry on unique constraint violation
79
-					throw $e;
80
-				}
81
-			}
82
-		}
83
-
84
-		$this->logger->error('Giving up after ' . self::TOKEN_RETRIES . ' retries to generate a unique local editor token for path hash: ' . $pathHash);
85
-		return new DataResponse([], Http::STATUS_INTERNAL_SERVER_ERROR);
86
-	}
87
-
88
-	/**
89
-	 * Validate a local editor
90
-	 *
91
-	 * @param string $path Path of the file
92
-	 * @param string $token Token of the local editor
93
-	 *
94
-	 * @return DataResponse<Http::STATUS_OK, array{userId: string, pathHash: string, expirationTime: int, token: string}, array{}>|DataResponse<Http::STATUS_NOT_FOUND, list<empty>, array{}>
95
-	 *
96
-	 * 200: Local editor validated successfully
97
-	 * 404: Local editor not found
98
-	 */
99
-	#[NoAdminRequired]
100
-	#[BruteForceProtection(action: 'openLocalEditor')]
101
-	public function validate(string $path, string $token): DataResponse {
102
-		$pathHash = sha1($path);
103
-
104
-		try {
105
-			$entity = $this->mapper->verifyToken($this->userId, $pathHash, $token);
106
-		} catch (DoesNotExistException $e) {
107
-			$response = new DataResponse([], Http::STATUS_NOT_FOUND);
108
-			$response->throttle(['userId' => $this->userId, 'pathHash' => $pathHash]);
109
-			return $response;
110
-		}
111
-
112
-		$this->mapper->delete($entity);
113
-
114
-		if ($entity->getExpirationTime() <= $this->timeFactory->getTime()) {
115
-			$response = new DataResponse([], Http::STATUS_NOT_FOUND);
116
-			$response->throttle(['userId' => $this->userId, 'pathHash' => $pathHash]);
117
-			return $response;
118
-		}
119
-
120
-		return new DataResponse([
121
-			'userId' => $this->userId,
122
-			'pathHash' => $pathHash,
123
-			'expirationTime' => $entity->getExpirationTime(),
124
-			'token' => $entity->getToken(),
125
-		]);
126
-	}
28
+    public const TOKEN_LENGTH = 128;
29
+    public const TOKEN_DURATION = 600; // 10 Minutes
30
+    public const TOKEN_RETRIES = 50;
31
+
32
+    public function __construct(
33
+        string $appName,
34
+        IRequest $request,
35
+        protected ITimeFactory $timeFactory,
36
+        protected OpenLocalEditorMapper $mapper,
37
+        protected ISecureRandom $secureRandom,
38
+        protected LoggerInterface $logger,
39
+        protected ?string $userId,
40
+    ) {
41
+        parent::__construct($appName, $request);
42
+    }
43
+
44
+    /**
45
+     * Create a local editor
46
+     *
47
+     * @param string $path Path of the file
48
+     *
49
+     * @return DataResponse<Http::STATUS_OK, array{userId: ?string, pathHash: string, expirationTime: int, token: string}, array{}>|DataResponse<Http::STATUS_INTERNAL_SERVER_ERROR, list<empty>, array{}>
50
+     *
51
+     * 200: Local editor returned
52
+     */
53
+    #[NoAdminRequired]
54
+    #[UserRateLimit(limit: 10, period: 120)]
55
+    public function create(string $path): DataResponse {
56
+        $pathHash = sha1($path);
57
+
58
+        $entity = new OpenLocalEditor();
59
+        $entity->setUserId($this->userId);
60
+        $entity->setPathHash($pathHash);
61
+        $entity->setExpirationTime($this->timeFactory->getTime() + self::TOKEN_DURATION); // Expire in 10 minutes
62
+
63
+        for ($i = 1; $i <= self::TOKEN_RETRIES; $i++) {
64
+            $token = $this->secureRandom->generate(self::TOKEN_LENGTH, ISecureRandom::CHAR_ALPHANUMERIC);
65
+            $entity->setToken($token);
66
+
67
+            try {
68
+                $this->mapper->insert($entity);
69
+
70
+                return new DataResponse([
71
+                    'userId' => $this->userId,
72
+                    'pathHash' => $pathHash,
73
+                    'expirationTime' => $entity->getExpirationTime(),
74
+                    'token' => $entity->getToken(),
75
+                ]);
76
+            } catch (Exception $e) {
77
+                if ($e->getCode() !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
78
+                    // Only retry on unique constraint violation
79
+                    throw $e;
80
+                }
81
+            }
82
+        }
83
+
84
+        $this->logger->error('Giving up after ' . self::TOKEN_RETRIES . ' retries to generate a unique local editor token for path hash: ' . $pathHash);
85
+        return new DataResponse([], Http::STATUS_INTERNAL_SERVER_ERROR);
86
+    }
87
+
88
+    /**
89
+     * Validate a local editor
90
+     *
91
+     * @param string $path Path of the file
92
+     * @param string $token Token of the local editor
93
+     *
94
+     * @return DataResponse<Http::STATUS_OK, array{userId: string, pathHash: string, expirationTime: int, token: string}, array{}>|DataResponse<Http::STATUS_NOT_FOUND, list<empty>, array{}>
95
+     *
96
+     * 200: Local editor validated successfully
97
+     * 404: Local editor not found
98
+     */
99
+    #[NoAdminRequired]
100
+    #[BruteForceProtection(action: 'openLocalEditor')]
101
+    public function validate(string $path, string $token): DataResponse {
102
+        $pathHash = sha1($path);
103
+
104
+        try {
105
+            $entity = $this->mapper->verifyToken($this->userId, $pathHash, $token);
106
+        } catch (DoesNotExistException $e) {
107
+            $response = new DataResponse([], Http::STATUS_NOT_FOUND);
108
+            $response->throttle(['userId' => $this->userId, 'pathHash' => $pathHash]);
109
+            return $response;
110
+        }
111
+
112
+        $this->mapper->delete($entity);
113
+
114
+        if ($entity->getExpirationTime() <= $this->timeFactory->getTime()) {
115
+            $response = new DataResponse([], Http::STATUS_NOT_FOUND);
116
+            $response->throttle(['userId' => $this->userId, 'pathHash' => $pathHash]);
117
+            return $response;
118
+        }
119
+
120
+        return new DataResponse([
121
+            'userId' => $this->userId,
122
+            'pathHash' => $pathHash,
123
+            'expirationTime' => $entity->getExpirationTime(),
124
+            'token' => $entity->getToken(),
125
+        ]);
126
+    }
127 127
 
128 128
 }
Please login to merge, or discard this patch.
apps/files/lib/Db/OpenLocalEditor.php 1 patch
Indentation   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -39,22 +39,22 @@
 block discarded – undo
39 39
  * @method string getToken()
40 40
  */
41 41
 class OpenLocalEditor extends Entity {
42
-	/** @var string */
43
-	protected $userId;
42
+    /** @var string */
43
+    protected $userId;
44 44
 
45
-	/** @var string */
46
-	protected $pathHash;
45
+    /** @var string */
46
+    protected $pathHash;
47 47
 
48
-	/** @var int */
49
-	protected $expirationTime;
48
+    /** @var int */
49
+    protected $expirationTime;
50 50
 
51
-	/** @var string */
52
-	protected $token;
51
+    /** @var string */
52
+    protected $token;
53 53
 
54
-	public function __construct() {
55
-		$this->addType('userId', 'string');
56
-		$this->addType('pathHash', 'string');
57
-		$this->addType('expirationTime', 'integer');
58
-		$this->addType('token', 'string');
59
-	}
54
+    public function __construct() {
55
+        $this->addType('userId', 'string');
56
+        $this->addType('pathHash', 'string');
57
+        $this->addType('expirationTime', 'integer');
58
+        $this->addType('token', 'string');
59
+    }
60 60
 }
Please login to merge, or discard this patch.
apps/user_status/lib/Db/UserStatusMapper.php 2 patches
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -83,7 +83,7 @@  discard block
 block discarded – undo
83 83
 					$qb->expr()->isNotNull('custom_icon'),
84 84
 					$qb->expr()->isNotNull('custom_message'),
85 85
 				),
86
-				$qb->expr()->notLike('user_id', $qb->createNamedParameter($this->db->escapeLikeParameter('_') . '%'))
86
+				$qb->expr()->notLike('user_id', $qb->createNamedParameter($this->db->escapeLikeParameter('_').'%'))
87 87
 			));
88 88
 
89 89
 		if ($limit !== null) {
@@ -106,7 +106,7 @@  discard block
 block discarded – undo
106 106
 		$qb
107 107
 			->select('*')
108 108
 			->from($this->tableName)
109
-			->where($qb->expr()->eq('user_id', $qb->createNamedParameter($isBackup ? '_' . $userId : $userId, IQueryBuilder::PARAM_STR)));
109
+			->where($qb->expr()->eq('user_id', $qb->createNamedParameter($isBackup ? '_'.$userId : $userId, IQueryBuilder::PARAM_STR)));
110 110
 
111 111
 		return $this->findEntity($qb);
112 112
 	}
@@ -195,7 +195,7 @@  discard block
 block discarded – undo
195 195
 		$qb = $this->db->getQueryBuilder();
196 196
 		$qb->update($this->tableName)
197 197
 			->set('is_backup', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))
198
-			->set('user_id', $qb->createNamedParameter('_' . $userId))
198
+			->set('user_id', $qb->createNamedParameter('_'.$userId))
199 199
 			->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
200 200
 		return $qb->executeStatement() > 0;
201 201
 	}
Please login to merge, or discard this patch.
Indentation   +174 added lines, -174 removed lines patch added patch discarded remove patch
@@ -20,178 +20,178 @@
 block discarded – undo
20 20
  */
21 21
 class UserStatusMapper extends QBMapper {
22 22
 
23
-	/**
24
-	 * @param IDBConnection $db
25
-	 */
26
-	public function __construct(IDBConnection $db) {
27
-		parent::__construct($db, 'user_status');
28
-	}
29
-
30
-	/**
31
-	 * @param int|null $limit
32
-	 * @param int|null $offset
33
-	 * @return UserStatus[]
34
-	 */
35
-	public function findAll(?int $limit = null, ?int $offset = null):array {
36
-		$qb = $this->db->getQueryBuilder();
37
-		$qb
38
-			->select('*')
39
-			->from($this->tableName);
40
-
41
-		if ($limit !== null) {
42
-			$qb->setMaxResults($limit);
43
-		}
44
-		if ($offset !== null) {
45
-			$qb->setFirstResult($offset);
46
-		}
47
-
48
-		return $this->findEntities($qb);
49
-	}
50
-
51
-	/**
52
-	 * @param int|null $limit
53
-	 * @param int|null $offset
54
-	 * @return array
55
-	 */
56
-	public function findAllRecent(?int $limit = null, ?int $offset = null): array {
57
-		$qb = $this->db->getQueryBuilder();
58
-
59
-		$qb
60
-			->select('*')
61
-			->from($this->tableName)
62
-			->orderBy('status_message_timestamp', 'DESC')
63
-			->where($qb->expr()->andX(
64
-				$qb->expr()->neq('status_message_timestamp', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT),
65
-				$qb->expr()->orX(
66
-					$qb->expr()->notIn('status', $qb->createNamedParameter([IUserStatus::ONLINE, IUserStatus::AWAY, IUserStatus::OFFLINE], IQueryBuilder::PARAM_STR_ARRAY)),
67
-					$qb->expr()->isNotNull('message_id'),
68
-					$qb->expr()->isNotNull('custom_icon'),
69
-					$qb->expr()->isNotNull('custom_message'),
70
-				),
71
-				$qb->expr()->notLike('user_id', $qb->createNamedParameter($this->db->escapeLikeParameter('_') . '%'))
72
-			));
73
-
74
-		if ($limit !== null) {
75
-			$qb->setMaxResults($limit);
76
-		}
77
-		if ($offset !== null) {
78
-			$qb->setFirstResult($offset);
79
-		}
80
-
81
-		return $this->findEntities($qb);
82
-	}
83
-
84
-	/**
85
-	 * @param string $userId
86
-	 * @return UserStatus
87
-	 * @throws DoesNotExistException
88
-	 */
89
-	public function findByUserId(string $userId, bool $isBackup = false): UserStatus {
90
-		$qb = $this->db->getQueryBuilder();
91
-		$qb
92
-			->select('*')
93
-			->from($this->tableName)
94
-			->where($qb->expr()->eq('user_id', $qb->createNamedParameter($isBackup ? '_' . $userId : $userId, IQueryBuilder::PARAM_STR)));
95
-
96
-		return $this->findEntity($qb);
97
-	}
98
-
99
-	/**
100
-	 * @param array $userIds
101
-	 * @return array
102
-	 */
103
-	public function findByUserIds(array $userIds): array {
104
-		$qb = $this->db->getQueryBuilder();
105
-		$qb
106
-			->select('*')
107
-			->from($this->tableName)
108
-			->where($qb->expr()->in('user_id', $qb->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)));
109
-
110
-		return $this->findEntities($qb);
111
-	}
112
-
113
-	/**
114
-	 * @param int $olderThan
115
-	 * @param int $now
116
-	 */
117
-	public function clearStatusesOlderThan(int $olderThan, int $now): void {
118
-		$qb = $this->db->getQueryBuilder();
119
-		$qb->update($this->tableName)
120
-			->set('status', $qb->createNamedParameter(IUserStatus::OFFLINE))
121
-			->set('is_user_defined', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL))
122
-			->set('status_timestamp', $qb->createNamedParameter($now, IQueryBuilder::PARAM_INT))
123
-			->where($qb->expr()->lte('status_timestamp', $qb->createNamedParameter($olderThan, IQueryBuilder::PARAM_INT)))
124
-			->andWhere($qb->expr()->neq('status', $qb->createNamedParameter(IUserStatus::OFFLINE)))
125
-			->andWhere($qb->expr()->orX(
126
-				$qb->expr()->eq('is_user_defined', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL), IQueryBuilder::PARAM_BOOL),
127
-				$qb->expr()->eq('status', $qb->createNamedParameter(IUserStatus::ONLINE))
128
-			));
129
-
130
-		$qb->executeStatement();
131
-	}
132
-
133
-	/**
134
-	 * Clear all statuses older than a given timestamp
135
-	 *
136
-	 * @param int $timestamp
137
-	 */
138
-	public function clearOlderThanClearAt(int $timestamp): void {
139
-		$qb = $this->db->getQueryBuilder();
140
-		$qb->delete($this->tableName)
141
-			->where($qb->expr()->isNotNull('clear_at'))
142
-			->andWhere($qb->expr()->lte('clear_at', $qb->createNamedParameter($timestamp, IQueryBuilder::PARAM_INT)));
143
-
144
-		$qb->executeStatement();
145
-	}
146
-
147
-
148
-	/**
149
-	 * Deletes a user status so we can restore the backup
150
-	 *
151
-	 * @param string $userId
152
-	 * @param string $messageId
153
-	 * @return bool True if an entry was deleted
154
-	 */
155
-	public function deleteCurrentStatusToRestoreBackup(string $userId, string $messageId): bool {
156
-		$qb = $this->db->getQueryBuilder();
157
-		$qb->delete($this->tableName)
158
-			->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)))
159
-			->andWhere($qb->expr()->eq('message_id', $qb->createNamedParameter($messageId)))
160
-			->andWhere($qb->expr()->eq('is_backup', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)));
161
-		return $qb->executeStatement() > 0;
162
-	}
163
-
164
-	public function deleteByIds(array $ids): void {
165
-		$qb = $this->db->getQueryBuilder();
166
-		$qb->delete($this->tableName)
167
-			->where($qb->expr()->in('id', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)));
168
-		$qb->executeStatement();
169
-	}
170
-
171
-	/**
172
-	 * @param string $userId
173
-	 * @return bool
174
-	 * @throws \OCP\DB\Exception
175
-	 */
176
-	public function createBackupStatus(string $userId): bool {
177
-		// Prefix user account with an underscore because user_id is marked as unique
178
-		// in the table. Starting a username with an underscore is not allowed so this
179
-		// shouldn't create any trouble.
180
-		$qb = $this->db->getQueryBuilder();
181
-		$qb->update($this->tableName)
182
-			->set('is_backup', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))
183
-			->set('user_id', $qb->createNamedParameter('_' . $userId))
184
-			->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
185
-		return $qb->executeStatement() > 0;
186
-	}
187
-
188
-	public function restoreBackupStatuses(array $ids): void {
189
-		$qb = $this->db->getQueryBuilder();
190
-		$qb->update($this->tableName)
191
-			->set('is_backup', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL))
192
-			->set('user_id', $qb->func()->substring('user_id', $qb->createNamedParameter(2, IQueryBuilder::PARAM_INT)))
193
-			->where($qb->expr()->in('id', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)));
194
-
195
-		$qb->executeStatement();
196
-	}
23
+    /**
24
+     * @param IDBConnection $db
25
+     */
26
+    public function __construct(IDBConnection $db) {
27
+        parent::__construct($db, 'user_status');
28
+    }
29
+
30
+    /**
31
+     * @param int|null $limit
32
+     * @param int|null $offset
33
+     * @return UserStatus[]
34
+     */
35
+    public function findAll(?int $limit = null, ?int $offset = null):array {
36
+        $qb = $this->db->getQueryBuilder();
37
+        $qb
38
+            ->select('*')
39
+            ->from($this->tableName);
40
+
41
+        if ($limit !== null) {
42
+            $qb->setMaxResults($limit);
43
+        }
44
+        if ($offset !== null) {
45
+            $qb->setFirstResult($offset);
46
+        }
47
+
48
+        return $this->findEntities($qb);
49
+    }
50
+
51
+    /**
52
+     * @param int|null $limit
53
+     * @param int|null $offset
54
+     * @return array
55
+     */
56
+    public function findAllRecent(?int $limit = null, ?int $offset = null): array {
57
+        $qb = $this->db->getQueryBuilder();
58
+
59
+        $qb
60
+            ->select('*')
61
+            ->from($this->tableName)
62
+            ->orderBy('status_message_timestamp', 'DESC')
63
+            ->where($qb->expr()->andX(
64
+                $qb->expr()->neq('status_message_timestamp', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT),
65
+                $qb->expr()->orX(
66
+                    $qb->expr()->notIn('status', $qb->createNamedParameter([IUserStatus::ONLINE, IUserStatus::AWAY, IUserStatus::OFFLINE], IQueryBuilder::PARAM_STR_ARRAY)),
67
+                    $qb->expr()->isNotNull('message_id'),
68
+                    $qb->expr()->isNotNull('custom_icon'),
69
+                    $qb->expr()->isNotNull('custom_message'),
70
+                ),
71
+                $qb->expr()->notLike('user_id', $qb->createNamedParameter($this->db->escapeLikeParameter('_') . '%'))
72
+            ));
73
+
74
+        if ($limit !== null) {
75
+            $qb->setMaxResults($limit);
76
+        }
77
+        if ($offset !== null) {
78
+            $qb->setFirstResult($offset);
79
+        }
80
+
81
+        return $this->findEntities($qb);
82
+    }
83
+
84
+    /**
85
+     * @param string $userId
86
+     * @return UserStatus
87
+     * @throws DoesNotExistException
88
+     */
89
+    public function findByUserId(string $userId, bool $isBackup = false): UserStatus {
90
+        $qb = $this->db->getQueryBuilder();
91
+        $qb
92
+            ->select('*')
93
+            ->from($this->tableName)
94
+            ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($isBackup ? '_' . $userId : $userId, IQueryBuilder::PARAM_STR)));
95
+
96
+        return $this->findEntity($qb);
97
+    }
98
+
99
+    /**
100
+     * @param array $userIds
101
+     * @return array
102
+     */
103
+    public function findByUserIds(array $userIds): array {
104
+        $qb = $this->db->getQueryBuilder();
105
+        $qb
106
+            ->select('*')
107
+            ->from($this->tableName)
108
+            ->where($qb->expr()->in('user_id', $qb->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)));
109
+
110
+        return $this->findEntities($qb);
111
+    }
112
+
113
+    /**
114
+     * @param int $olderThan
115
+     * @param int $now
116
+     */
117
+    public function clearStatusesOlderThan(int $olderThan, int $now): void {
118
+        $qb = $this->db->getQueryBuilder();
119
+        $qb->update($this->tableName)
120
+            ->set('status', $qb->createNamedParameter(IUserStatus::OFFLINE))
121
+            ->set('is_user_defined', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL))
122
+            ->set('status_timestamp', $qb->createNamedParameter($now, IQueryBuilder::PARAM_INT))
123
+            ->where($qb->expr()->lte('status_timestamp', $qb->createNamedParameter($olderThan, IQueryBuilder::PARAM_INT)))
124
+            ->andWhere($qb->expr()->neq('status', $qb->createNamedParameter(IUserStatus::OFFLINE)))
125
+            ->andWhere($qb->expr()->orX(
126
+                $qb->expr()->eq('is_user_defined', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL), IQueryBuilder::PARAM_BOOL),
127
+                $qb->expr()->eq('status', $qb->createNamedParameter(IUserStatus::ONLINE))
128
+            ));
129
+
130
+        $qb->executeStatement();
131
+    }
132
+
133
+    /**
134
+     * Clear all statuses older than a given timestamp
135
+     *
136
+     * @param int $timestamp
137
+     */
138
+    public function clearOlderThanClearAt(int $timestamp): void {
139
+        $qb = $this->db->getQueryBuilder();
140
+        $qb->delete($this->tableName)
141
+            ->where($qb->expr()->isNotNull('clear_at'))
142
+            ->andWhere($qb->expr()->lte('clear_at', $qb->createNamedParameter($timestamp, IQueryBuilder::PARAM_INT)));
143
+
144
+        $qb->executeStatement();
145
+    }
146
+
147
+
148
+    /**
149
+     * Deletes a user status so we can restore the backup
150
+     *
151
+     * @param string $userId
152
+     * @param string $messageId
153
+     * @return bool True if an entry was deleted
154
+     */
155
+    public function deleteCurrentStatusToRestoreBackup(string $userId, string $messageId): bool {
156
+        $qb = $this->db->getQueryBuilder();
157
+        $qb->delete($this->tableName)
158
+            ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)))
159
+            ->andWhere($qb->expr()->eq('message_id', $qb->createNamedParameter($messageId)))
160
+            ->andWhere($qb->expr()->eq('is_backup', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL)));
161
+        return $qb->executeStatement() > 0;
162
+    }
163
+
164
+    public function deleteByIds(array $ids): void {
165
+        $qb = $this->db->getQueryBuilder();
166
+        $qb->delete($this->tableName)
167
+            ->where($qb->expr()->in('id', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)));
168
+        $qb->executeStatement();
169
+    }
170
+
171
+    /**
172
+     * @param string $userId
173
+     * @return bool
174
+     * @throws \OCP\DB\Exception
175
+     */
176
+    public function createBackupStatus(string $userId): bool {
177
+        // Prefix user account with an underscore because user_id is marked as unique
178
+        // in the table. Starting a username with an underscore is not allowed so this
179
+        // shouldn't create any trouble.
180
+        $qb = $this->db->getQueryBuilder();
181
+        $qb->update($this->tableName)
182
+            ->set('is_backup', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL))
183
+            ->set('user_id', $qb->createNamedParameter('_' . $userId))
184
+            ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
185
+        return $qb->executeStatement() > 0;
186
+    }
187
+
188
+    public function restoreBackupStatuses(array $ids): void {
189
+        $qb = $this->db->getQueryBuilder();
190
+        $qb->update($this->tableName)
191
+            ->set('is_backup', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL))
192
+            ->set('user_id', $qb->func()->substring('user_id', $qb->createNamedParameter(2, IQueryBuilder::PARAM_INT)))
193
+            ->where($qb->expr()->in('id', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY)));
194
+
195
+        $qb->executeStatement();
196
+    }
197 197
 }
Please login to merge, or discard this patch.