Completed
Pull Request — master (#9293)
by Blizzz
18:49
created
lib/public/Util.php 1 patch
Indentation   +499 added lines, -499 removed lines patch added patch discarded remove patch
@@ -57,505 +57,505 @@
 block discarded – undo
57 57
  * @since 4.0.0
58 58
  */
59 59
 class Util {
60
-	/**
61
-	 * @deprecated 14.0.0 use \OCP\ILogger::DEBUG
62
-	 */
63
-	const DEBUG=0;
64
-	/**
65
-	 * @deprecated 14.0.0 use \OCP\ILogger::INFO
66
-	 */
67
-	const INFO=1;
68
-	/**
69
-	 * @deprecated 14.0.0 use \OCP\ILogger::WARN
70
-	 */
71
-	const WARN=2;
72
-	/**
73
-	 * @deprecated 14.0.0 use \OCP\ILogger::ERROR
74
-	 */
75
-	const ERROR=3;
76
-	/**
77
-	 * @deprecated 14.0.0 use \OCP\ILogger::FATAL
78
-	 */
79
-	const FATAL=4;
80
-
81
-	/** \OCP\Share\IManager */
82
-	private static $shareManager;
83
-
84
-	/**
85
-	 * get the current installed version of ownCloud
86
-	 * @return array
87
-	 * @since 4.0.0
88
-	 */
89
-	public static function getVersion() {
90
-		return \OC_Util::getVersion();
91
-	}
60
+    /**
61
+     * @deprecated 14.0.0 use \OCP\ILogger::DEBUG
62
+     */
63
+    const DEBUG=0;
64
+    /**
65
+     * @deprecated 14.0.0 use \OCP\ILogger::INFO
66
+     */
67
+    const INFO=1;
68
+    /**
69
+     * @deprecated 14.0.0 use \OCP\ILogger::WARN
70
+     */
71
+    const WARN=2;
72
+    /**
73
+     * @deprecated 14.0.0 use \OCP\ILogger::ERROR
74
+     */
75
+    const ERROR=3;
76
+    /**
77
+     * @deprecated 14.0.0 use \OCP\ILogger::FATAL
78
+     */
79
+    const FATAL=4;
80
+
81
+    /** \OCP\Share\IManager */
82
+    private static $shareManager;
83
+
84
+    /**
85
+     * get the current installed version of ownCloud
86
+     * @return array
87
+     * @since 4.0.0
88
+     */
89
+    public static function getVersion() {
90
+        return \OC_Util::getVersion();
91
+    }
92 92
 	
93
-	/**
94
-	 * Set current update channel
95
-	 * @param string $channel
96
-	 * @since 8.1.0
97
-	 */
98
-	public static function setChannel($channel) {
99
-		\OC::$server->getConfig()->setSystemValue('updater.release.channel', $channel);
100
-	}
93
+    /**
94
+     * Set current update channel
95
+     * @param string $channel
96
+     * @since 8.1.0
97
+     */
98
+    public static function setChannel($channel) {
99
+        \OC::$server->getConfig()->setSystemValue('updater.release.channel', $channel);
100
+    }
101 101
 	
102
-	/**
103
-	 * Get current update channel
104
-	 * @return string
105
-	 * @since 8.1.0
106
-	 */
107
-	public static function getChannel() {
108
-		return \OC_Util::getChannel();
109
-	}
110
-
111
-	/**
112
-	 * write a message in the log
113
-	 * @param string $app
114
-	 * @param string $message
115
-	 * @param int $level
116
-	 * @since 4.0.0
117
-	 * @deprecated 13.0.0 use log of \OCP\ILogger
118
-	 */
119
-	public static function writeLog( $app, $message, $level ) {
120
-		$context = ['app' => $app];
121
-		\OC::$server->getLogger()->log($level, $message, $context);
122
-	}
123
-
124
-	/**
125
-	 * write exception into the log
126
-	 * @param string $app app name
127
-	 * @param \Exception $ex exception to log
128
-	 * @param int $level log level, defaults to \OCP\Util::FATAL
129
-	 * @since ....0.0 - parameter $level was added in 7.0.0
130
-	 * @deprecated 8.2.0 use logException of \OCP\ILogger
131
-	 */
132
-	public static function logException( $app, \Exception $ex, $level = ILogger::FATAL) {
133
-		\OC::$server->getLogger()->logException($ex, ['app' => $app]);
134
-	}
135
-
136
-	/**
137
-	 * check if sharing is disabled for the current user
138
-	 *
139
-	 * @return boolean
140
-	 * @since 7.0.0
141
-	 * @deprecated 9.1.0 Use \OC::$server->getShareManager()->sharingDisabledForUser
142
-	 */
143
-	public static function isSharingDisabledForUser() {
144
-		if (self::$shareManager === null) {
145
-			self::$shareManager = \OC::$server->getShareManager();
146
-		}
147
-
148
-		$user = \OC::$server->getUserSession()->getUser();
149
-		if ($user !== null) {
150
-			$user = $user->getUID();
151
-		}
152
-
153
-		return self::$shareManager->sharingDisabledForUser($user);
154
-	}
155
-
156
-	/**
157
-	 * get l10n object
158
-	 * @param string $application
159
-	 * @param string|null $language
160
-	 * @return \OCP\IL10N
161
-	 * @since 6.0.0 - parameter $language was added in 8.0.0
162
-	 */
163
-	public static function getL10N($application, $language = null) {
164
-		return \OC::$server->getL10N($application, $language);
165
-	}
166
-
167
-	/**
168
-	 * add a css file
169
-	 * @param string $application
170
-	 * @param string $file
171
-	 * @since 4.0.0
172
-	 */
173
-	public static function addStyle( $application, $file = null ) {
174
-		\OC_Util::addStyle( $application, $file );
175
-	}
176
-
177
-	/**
178
-	 * add a javascript file
179
-	 * @param string $application
180
-	 * @param string $file
181
-	 * @since 4.0.0
182
-	 */
183
-	public static function addScript( $application, $file = null ) {
184
-		\OC_Util::addScript( $application, $file );
185
-	}
186
-
187
-	/**
188
-	 * Add a translation JS file
189
-	 * @param string $application application id
190
-	 * @param string $languageCode language code, defaults to the current locale
191
-	 * @since 8.0.0
192
-	 */
193
-	public static function addTranslations($application, $languageCode = null) {
194
-		\OC_Util::addTranslations($application, $languageCode);
195
-	}
196
-
197
-	/**
198
-	 * Add a custom element to the header
199
-	 * If $text is null then the element will be written as empty element.
200
-	 * So use "" to get a closing tag.
201
-	 * @param string $tag tag name of the element
202
-	 * @param array $attributes array of attributes for the element
203
-	 * @param string $text the text content for the element
204
-	 * @since 4.0.0
205
-	 */
206
-	public static function addHeader($tag, $attributes, $text=null) {
207
-		\OC_Util::addHeader($tag, $attributes, $text);
208
-	}
209
-
210
-	/**
211
-	 * Creates an absolute url to the given app and file.
212
-	 * @param string $app app
213
-	 * @param string $file file
214
-	 * @param array $args array with param=>value, will be appended to the returned url
215
-	 * 	The value of $args will be urlencoded
216
-	 * @return string the url
217
-	 * @since 4.0.0 - parameter $args was added in 4.5.0
218
-	 */
219
-	public static function linkToAbsolute( $app, $file, $args = array() ) {
220
-		$urlGenerator = \OC::$server->getURLGenerator();
221
-		return $urlGenerator->getAbsoluteURL(
222
-			$urlGenerator->linkTo($app, $file, $args)
223
-		);
224
-	}
225
-
226
-	/**
227
-	 * Creates an absolute url for remote use.
228
-	 * @param string $service id
229
-	 * @return string the url
230
-	 * @since 4.0.0
231
-	 */
232
-	public static function linkToRemote( $service ) {
233
-		$urlGenerator = \OC::$server->getURLGenerator();
234
-		$remoteBase = $urlGenerator->linkTo('', 'remote.php') . '/' . $service;
235
-		return $urlGenerator->getAbsoluteURL(
236
-			$remoteBase . (($service[strlen($service) - 1] != '/') ? '/' : '')
237
-		);
238
-	}
239
-
240
-	/**
241
-	 * Creates an absolute url for public use
242
-	 * @param string $service id
243
-	 * @return string the url
244
-	 * @since 4.5.0
245
-	 */
246
-	public static function linkToPublic($service) {
247
-		return \OC_Helper::linkToPublic($service);
248
-	}
249
-
250
-	/**
251
-	 * Returns the server host name without an eventual port number
252
-	 * @return string the server hostname
253
-	 * @since 5.0.0
254
-	 */
255
-	public static function getServerHostName() {
256
-		$host_name = \OC::$server->getRequest()->getServerHost();
257
-		// strip away port number (if existing)
258
-		$colon_pos = strpos($host_name, ':');
259
-		if ($colon_pos != FALSE) {
260
-			$host_name = substr($host_name, 0, $colon_pos);
261
-		}
262
-		return $host_name;
263
-	}
264
-
265
-	/**
266
-	 * Returns the default email address
267
-	 * @param string $user_part the user part of the address
268
-	 * @return string the default email address
269
-	 *
270
-	 * Assembles a default email address (using the server hostname
271
-	 * and the given user part, and returns it
272
-	 * Example: when given lostpassword-noreply as $user_part param,
273
-	 *     and is currently accessed via http(s)://example.com/,
274
-	 *     it would return '[email protected]'
275
-	 *
276
-	 * If the configuration value 'mail_from_address' is set in
277
-	 * config.php, this value will override the $user_part that
278
-	 * is passed to this function
279
-	 * @since 5.0.0
280
-	 */
281
-	public static function getDefaultEmailAddress($user_part) {
282
-		$config = \OC::$server->getConfig();
283
-		$user_part = $config->getSystemValue('mail_from_address', $user_part);
284
-		$host_name = self::getServerHostName();
285
-		$host_name = $config->getSystemValue('mail_domain', $host_name);
286
-		$defaultEmailAddress = $user_part.'@'.$host_name;
287
-
288
-		$mailer = \OC::$server->getMailer();
289
-		if ($mailer->validateMailAddress($defaultEmailAddress)) {
290
-			return $defaultEmailAddress;
291
-		}
292
-
293
-		// in case we cannot build a valid email address from the hostname let's fallback to 'localhost.localdomain'
294
-		return $user_part.'@localhost.localdomain';
295
-	}
296
-
297
-	/**
298
-	 * Make a human file size (2048 to 2 kB)
299
-	 * @param int $bytes file size in bytes
300
-	 * @return string a human readable file size
301
-	 * @since 4.0.0
302
-	 */
303
-	public static function humanFileSize($bytes) {
304
-		return \OC_Helper::humanFileSize($bytes);
305
-	}
306
-
307
-	/**
308
-	 * Make a computer file size (2 kB to 2048)
309
-	 * @param string $str file size in a fancy format
310
-	 * @return float a file size in bytes
311
-	 *
312
-	 * Inspired by: http://www.php.net/manual/en/function.filesize.php#92418
313
-	 * @since 4.0.0
314
-	 */
315
-	public static function computerFileSize($str) {
316
-		return \OC_Helper::computerFileSize($str);
317
-	}
318
-
319
-	/**
320
-	 * connects a function to a hook
321
-	 *
322
-	 * @param string $signalClass class name of emitter
323
-	 * @param string $signalName name of signal
324
-	 * @param string|object $slotClass class name of slot
325
-	 * @param string $slotName name of slot
326
-	 * @return bool
327
-	 *
328
-	 * This function makes it very easy to connect to use hooks.
329
-	 *
330
-	 * TODO: write example
331
-	 * @since 4.0.0
332
-	 */
333
-	static public function connectHook($signalClass, $signalName, $slotClass, $slotName) {
334
-		return \OC_Hook::connect($signalClass, $signalName, $slotClass, $slotName);
335
-	}
336
-
337
-	/**
338
-	 * Emits a signal. To get data from the slot use references!
339
-	 * @param string $signalclass class name of emitter
340
-	 * @param string $signalname name of signal
341
-	 * @param array $params default: array() array with additional data
342
-	 * @return bool true if slots exists or false if not
343
-	 *
344
-	 * TODO: write example
345
-	 * @since 4.0.0
346
-	 */
347
-	static public function emitHook($signalclass, $signalname, $params = array()) {
348
-		return \OC_Hook::emit($signalclass, $signalname, $params);
349
-	}
350
-
351
-	/**
352
-	 * Cached encrypted CSRF token. Some static unit-tests of ownCloud compare
353
-	 * multiple OC_Template elements which invoke `callRegister`. If the value
354
-	 * would not be cached these unit-tests would fail.
355
-	 * @var string
356
-	 */
357
-	private static $token = '';
358
-
359
-	/**
360
-	 * Register an get/post call. This is important to prevent CSRF attacks
361
-	 * @since 4.5.0
362
-	 */
363
-	public static function callRegister() {
364
-		if(self::$token === '') {
365
-			self::$token = \OC::$server->getCsrfTokenManager()->getToken()->getEncryptedValue();
366
-		}
367
-		return self::$token;
368
-	}
369
-
370
-	/**
371
-	 * Check an ajax get/post call if the request token is valid. exit if not.
372
-	 * @since 4.5.0
373
-	 * @deprecated 9.0.0 Use annotations based on the app framework.
374
-	 */
375
-	public static function callCheck() {
376
-		if(!\OC::$server->getRequest()->passesStrictCookieCheck()) {
377
-			header('Location: '.\OC::$WEBROOT);
378
-			exit();
379
-		}
380
-
381
-		if (!\OC::$server->getRequest()->passesCSRFCheck()) {
382
-			exit();
383
-		}
384
-	}
385
-
386
-	/**
387
-	 * Used to sanitize HTML
388
-	 *
389
-	 * This function is used to sanitize HTML and should be applied on any
390
-	 * string or array of strings before displaying it on a web page.
391
-	 *
392
-	 * @param string|array $value
393
-	 * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter.
394
-	 * @since 4.5.0
395
-	 */
396
-	public static function sanitizeHTML($value) {
397
-		return \OC_Util::sanitizeHTML($value);
398
-	}
399
-
400
-	/**
401
-	 * Public function to encode url parameters
402
-	 *
403
-	 * This function is used to encode path to file before output.
404
-	 * Encoding is done according to RFC 3986 with one exception:
405
-	 * Character '/' is preserved as is.
406
-	 *
407
-	 * @param string $component part of URI to encode
408
-	 * @return string
409
-	 * @since 6.0.0
410
-	 */
411
-	public static function encodePath($component) {
412
-		return \OC_Util::encodePath($component);
413
-	}
414
-
415
-	/**
416
-	 * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is.
417
-	 *
418
-	 * @param array $input The array to work on
419
-	 * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default)
420
-	 * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
421
-	 * @return array
422
-	 * @since 4.5.0
423
-	 */
424
-	public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8') {
425
-		return \OC_Helper::mb_array_change_key_case($input, $case, $encoding);
426
-	}
427
-
428
-	/**
429
-	 * replaces a copy of string delimited by the start and (optionally) length parameters with the string given in replacement.
430
-	 *
431
-	 * @param string $string The input string. Opposite to the PHP build-in function does not accept an array.
432
-	 * @param string $replacement The replacement string.
433
-	 * @param int $start If start is positive, the replacing will begin at the start'th offset into string. If start is negative, the replacing will begin at the start'th character from the end of string.
434
-	 * @param int $length Length of the part to be replaced
435
-	 * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
436
-	 * @return string
437
-	 * @since 4.5.0
438
-	 * @deprecated 8.2.0 Use substr_replace() instead.
439
-	 */
440
-	public static function mb_substr_replace($string, $replacement, $start, $length = null, $encoding = 'UTF-8') {
441
-		return substr_replace($string, $replacement, $start, $length);
442
-	}
443
-
444
-	/**
445
-	 * Replace all occurrences of the search string with the replacement string
446
-	 *
447
-	 * @param string $search The value being searched for, otherwise known as the needle. String.
448
-	 * @param string $replace The replacement string.
449
-	 * @param string $subject The string or array being searched and replaced on, otherwise known as the haystack.
450
-	 * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
451
-	 * @param int $count If passed, this will be set to the number of replacements performed.
452
-	 * @return string
453
-	 * @since 4.5.0
454
-	 * @deprecated 8.2.0 Use str_replace() instead.
455
-	 */
456
-	public static function mb_str_replace($search, $replace, $subject, $encoding = 'UTF-8', &$count = null) {
457
-		return str_replace($search, $replace, $subject, $count);
458
-	}
459
-
460
-	/**
461
-	 * performs a search in a nested array
462
-	 *
463
-	 * @param array $haystack the array to be searched
464
-	 * @param string $needle the search string
465
-	 * @param mixed $index optional, only search this key name
466
-	 * @return mixed the key of the matching field, otherwise false
467
-	 * @since 4.5.0
468
-	 */
469
-	public static function recursiveArraySearch($haystack, $needle, $index = null) {
470
-		return \OC_Helper::recursiveArraySearch($haystack, $needle, $index);
471
-	}
472
-
473
-	/**
474
-	 * calculates the maximum upload size respecting system settings, free space and user quota
475
-	 *
476
-	 * @param string $dir the current folder where the user currently operates
477
-	 * @param int $free the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly
478
-	 * @return int number of bytes representing
479
-	 * @since 5.0.0
480
-	 */
481
-	public static function maxUploadFilesize($dir, $free = null) {
482
-		return \OC_Helper::maxUploadFilesize($dir, $free);
483
-	}
484
-
485
-	/**
486
-	 * Calculate free space left within user quota
487
-	 * @param string $dir the current folder where the user currently operates
488
-	 * @return int number of bytes representing
489
-	 * @since 7.0.0
490
-	 */
491
-	public static function freeSpace($dir) {
492
-		return \OC_Helper::freeSpace($dir);
493
-	}
494
-
495
-	/**
496
-	 * Calculate PHP upload limit
497
-	 *
498
-	 * @return int number of bytes representing
499
-	 * @since 7.0.0
500
-	 */
501
-	public static function uploadLimit() {
502
-		return \OC_Helper::uploadLimit();
503
-	}
504
-
505
-	/**
506
-	 * Returns whether the given file name is valid
507
-	 * @param string $file file name to check
508
-	 * @return bool true if the file name is valid, false otherwise
509
-	 * @deprecated 8.1.0 use \OC\Files\View::verifyPath()
510
-	 * @since 7.0.0
511
-	 * @suppress PhanDeprecatedFunction
512
-	 */
513
-	public static function isValidFileName($file) {
514
-		return \OC_Util::isValidFileName($file);
515
-	}
516
-
517
-	/**
518
-	 * Compare two strings to provide a natural sort
519
-	 * @param string $a first string to compare
520
-	 * @param string $b second string to compare
521
-	 * @return int -1 if $b comes before $a, 1 if $a comes before $b
522
-	 * or 0 if the strings are identical
523
-	 * @since 7.0.0
524
-	 */
525
-	public static function naturalSortCompare($a, $b) {
526
-		return \OC\NaturalSort::getInstance()->compare($a, $b);
527
-	}
528
-
529
-	/**
530
-	 * check if a password is required for each public link
531
-	 * @return boolean
532
-	 * @since 7.0.0
533
-	 */
534
-	public static function isPublicLinkPasswordRequired() {
535
-		return \OC_Util::isPublicLinkPasswordRequired();
536
-	}
537
-
538
-	/**
539
-	 * check if share API enforces a default expire date
540
-	 * @return boolean
541
-	 * @since 8.0.0
542
-	 */
543
-	public static function isDefaultExpireDateEnforced() {
544
-		return \OC_Util::isDefaultExpireDateEnforced();
545
-	}
546
-
547
-	protected static $needUpgradeCache = null;
548
-
549
-	/**
550
-	 * Checks whether the current version needs upgrade.
551
-	 *
552
-	 * @return bool true if upgrade is needed, false otherwise
553
-	 * @since 7.0.0
554
-	 */
555
-	public static function needUpgrade() {
556
-		if (!isset(self::$needUpgradeCache)) {
557
-			self::$needUpgradeCache=\OC_Util::needUpgrade(\OC::$server->getSystemConfig());
558
-		}		
559
-		return self::$needUpgradeCache;
560
-	}
102
+    /**
103
+     * Get current update channel
104
+     * @return string
105
+     * @since 8.1.0
106
+     */
107
+    public static function getChannel() {
108
+        return \OC_Util::getChannel();
109
+    }
110
+
111
+    /**
112
+     * write a message in the log
113
+     * @param string $app
114
+     * @param string $message
115
+     * @param int $level
116
+     * @since 4.0.0
117
+     * @deprecated 13.0.0 use log of \OCP\ILogger
118
+     */
119
+    public static function writeLog( $app, $message, $level ) {
120
+        $context = ['app' => $app];
121
+        \OC::$server->getLogger()->log($level, $message, $context);
122
+    }
123
+
124
+    /**
125
+     * write exception into the log
126
+     * @param string $app app name
127
+     * @param \Exception $ex exception to log
128
+     * @param int $level log level, defaults to \OCP\Util::FATAL
129
+     * @since ....0.0 - parameter $level was added in 7.0.0
130
+     * @deprecated 8.2.0 use logException of \OCP\ILogger
131
+     */
132
+    public static function logException( $app, \Exception $ex, $level = ILogger::FATAL) {
133
+        \OC::$server->getLogger()->logException($ex, ['app' => $app]);
134
+    }
135
+
136
+    /**
137
+     * check if sharing is disabled for the current user
138
+     *
139
+     * @return boolean
140
+     * @since 7.0.0
141
+     * @deprecated 9.1.0 Use \OC::$server->getShareManager()->sharingDisabledForUser
142
+     */
143
+    public static function isSharingDisabledForUser() {
144
+        if (self::$shareManager === null) {
145
+            self::$shareManager = \OC::$server->getShareManager();
146
+        }
147
+
148
+        $user = \OC::$server->getUserSession()->getUser();
149
+        if ($user !== null) {
150
+            $user = $user->getUID();
151
+        }
152
+
153
+        return self::$shareManager->sharingDisabledForUser($user);
154
+    }
155
+
156
+    /**
157
+     * get l10n object
158
+     * @param string $application
159
+     * @param string|null $language
160
+     * @return \OCP\IL10N
161
+     * @since 6.0.0 - parameter $language was added in 8.0.0
162
+     */
163
+    public static function getL10N($application, $language = null) {
164
+        return \OC::$server->getL10N($application, $language);
165
+    }
166
+
167
+    /**
168
+     * add a css file
169
+     * @param string $application
170
+     * @param string $file
171
+     * @since 4.0.0
172
+     */
173
+    public static function addStyle( $application, $file = null ) {
174
+        \OC_Util::addStyle( $application, $file );
175
+    }
176
+
177
+    /**
178
+     * add a javascript file
179
+     * @param string $application
180
+     * @param string $file
181
+     * @since 4.0.0
182
+     */
183
+    public static function addScript( $application, $file = null ) {
184
+        \OC_Util::addScript( $application, $file );
185
+    }
186
+
187
+    /**
188
+     * Add a translation JS file
189
+     * @param string $application application id
190
+     * @param string $languageCode language code, defaults to the current locale
191
+     * @since 8.0.0
192
+     */
193
+    public static function addTranslations($application, $languageCode = null) {
194
+        \OC_Util::addTranslations($application, $languageCode);
195
+    }
196
+
197
+    /**
198
+     * Add a custom element to the header
199
+     * If $text is null then the element will be written as empty element.
200
+     * So use "" to get a closing tag.
201
+     * @param string $tag tag name of the element
202
+     * @param array $attributes array of attributes for the element
203
+     * @param string $text the text content for the element
204
+     * @since 4.0.0
205
+     */
206
+    public static function addHeader($tag, $attributes, $text=null) {
207
+        \OC_Util::addHeader($tag, $attributes, $text);
208
+    }
209
+
210
+    /**
211
+     * Creates an absolute url to the given app and file.
212
+     * @param string $app app
213
+     * @param string $file file
214
+     * @param array $args array with param=>value, will be appended to the returned url
215
+     * 	The value of $args will be urlencoded
216
+     * @return string the url
217
+     * @since 4.0.0 - parameter $args was added in 4.5.0
218
+     */
219
+    public static function linkToAbsolute( $app, $file, $args = array() ) {
220
+        $urlGenerator = \OC::$server->getURLGenerator();
221
+        return $urlGenerator->getAbsoluteURL(
222
+            $urlGenerator->linkTo($app, $file, $args)
223
+        );
224
+    }
225
+
226
+    /**
227
+     * Creates an absolute url for remote use.
228
+     * @param string $service id
229
+     * @return string the url
230
+     * @since 4.0.0
231
+     */
232
+    public static function linkToRemote( $service ) {
233
+        $urlGenerator = \OC::$server->getURLGenerator();
234
+        $remoteBase = $urlGenerator->linkTo('', 'remote.php') . '/' . $service;
235
+        return $urlGenerator->getAbsoluteURL(
236
+            $remoteBase . (($service[strlen($service) - 1] != '/') ? '/' : '')
237
+        );
238
+    }
239
+
240
+    /**
241
+     * Creates an absolute url for public use
242
+     * @param string $service id
243
+     * @return string the url
244
+     * @since 4.5.0
245
+     */
246
+    public static function linkToPublic($service) {
247
+        return \OC_Helper::linkToPublic($service);
248
+    }
249
+
250
+    /**
251
+     * Returns the server host name without an eventual port number
252
+     * @return string the server hostname
253
+     * @since 5.0.0
254
+     */
255
+    public static function getServerHostName() {
256
+        $host_name = \OC::$server->getRequest()->getServerHost();
257
+        // strip away port number (if existing)
258
+        $colon_pos = strpos($host_name, ':');
259
+        if ($colon_pos != FALSE) {
260
+            $host_name = substr($host_name, 0, $colon_pos);
261
+        }
262
+        return $host_name;
263
+    }
264
+
265
+    /**
266
+     * Returns the default email address
267
+     * @param string $user_part the user part of the address
268
+     * @return string the default email address
269
+     *
270
+     * Assembles a default email address (using the server hostname
271
+     * and the given user part, and returns it
272
+     * Example: when given lostpassword-noreply as $user_part param,
273
+     *     and is currently accessed via http(s)://example.com/,
274
+     *     it would return '[email protected]'
275
+     *
276
+     * If the configuration value 'mail_from_address' is set in
277
+     * config.php, this value will override the $user_part that
278
+     * is passed to this function
279
+     * @since 5.0.0
280
+     */
281
+    public static function getDefaultEmailAddress($user_part) {
282
+        $config = \OC::$server->getConfig();
283
+        $user_part = $config->getSystemValue('mail_from_address', $user_part);
284
+        $host_name = self::getServerHostName();
285
+        $host_name = $config->getSystemValue('mail_domain', $host_name);
286
+        $defaultEmailAddress = $user_part.'@'.$host_name;
287
+
288
+        $mailer = \OC::$server->getMailer();
289
+        if ($mailer->validateMailAddress($defaultEmailAddress)) {
290
+            return $defaultEmailAddress;
291
+        }
292
+
293
+        // in case we cannot build a valid email address from the hostname let's fallback to 'localhost.localdomain'
294
+        return $user_part.'@localhost.localdomain';
295
+    }
296
+
297
+    /**
298
+     * Make a human file size (2048 to 2 kB)
299
+     * @param int $bytes file size in bytes
300
+     * @return string a human readable file size
301
+     * @since 4.0.0
302
+     */
303
+    public static function humanFileSize($bytes) {
304
+        return \OC_Helper::humanFileSize($bytes);
305
+    }
306
+
307
+    /**
308
+     * Make a computer file size (2 kB to 2048)
309
+     * @param string $str file size in a fancy format
310
+     * @return float a file size in bytes
311
+     *
312
+     * Inspired by: http://www.php.net/manual/en/function.filesize.php#92418
313
+     * @since 4.0.0
314
+     */
315
+    public static function computerFileSize($str) {
316
+        return \OC_Helper::computerFileSize($str);
317
+    }
318
+
319
+    /**
320
+     * connects a function to a hook
321
+     *
322
+     * @param string $signalClass class name of emitter
323
+     * @param string $signalName name of signal
324
+     * @param string|object $slotClass class name of slot
325
+     * @param string $slotName name of slot
326
+     * @return bool
327
+     *
328
+     * This function makes it very easy to connect to use hooks.
329
+     *
330
+     * TODO: write example
331
+     * @since 4.0.0
332
+     */
333
+    static public function connectHook($signalClass, $signalName, $slotClass, $slotName) {
334
+        return \OC_Hook::connect($signalClass, $signalName, $slotClass, $slotName);
335
+    }
336
+
337
+    /**
338
+     * Emits a signal. To get data from the slot use references!
339
+     * @param string $signalclass class name of emitter
340
+     * @param string $signalname name of signal
341
+     * @param array $params default: array() array with additional data
342
+     * @return bool true if slots exists or false if not
343
+     *
344
+     * TODO: write example
345
+     * @since 4.0.0
346
+     */
347
+    static public function emitHook($signalclass, $signalname, $params = array()) {
348
+        return \OC_Hook::emit($signalclass, $signalname, $params);
349
+    }
350
+
351
+    /**
352
+     * Cached encrypted CSRF token. Some static unit-tests of ownCloud compare
353
+     * multiple OC_Template elements which invoke `callRegister`. If the value
354
+     * would not be cached these unit-tests would fail.
355
+     * @var string
356
+     */
357
+    private static $token = '';
358
+
359
+    /**
360
+     * Register an get/post call. This is important to prevent CSRF attacks
361
+     * @since 4.5.0
362
+     */
363
+    public static function callRegister() {
364
+        if(self::$token === '') {
365
+            self::$token = \OC::$server->getCsrfTokenManager()->getToken()->getEncryptedValue();
366
+        }
367
+        return self::$token;
368
+    }
369
+
370
+    /**
371
+     * Check an ajax get/post call if the request token is valid. exit if not.
372
+     * @since 4.5.0
373
+     * @deprecated 9.0.0 Use annotations based on the app framework.
374
+     */
375
+    public static function callCheck() {
376
+        if(!\OC::$server->getRequest()->passesStrictCookieCheck()) {
377
+            header('Location: '.\OC::$WEBROOT);
378
+            exit();
379
+        }
380
+
381
+        if (!\OC::$server->getRequest()->passesCSRFCheck()) {
382
+            exit();
383
+        }
384
+    }
385
+
386
+    /**
387
+     * Used to sanitize HTML
388
+     *
389
+     * This function is used to sanitize HTML and should be applied on any
390
+     * string or array of strings before displaying it on a web page.
391
+     *
392
+     * @param string|array $value
393
+     * @return string|array an array of sanitized strings or a single sanitized string, depends on the input parameter.
394
+     * @since 4.5.0
395
+     */
396
+    public static function sanitizeHTML($value) {
397
+        return \OC_Util::sanitizeHTML($value);
398
+    }
399
+
400
+    /**
401
+     * Public function to encode url parameters
402
+     *
403
+     * This function is used to encode path to file before output.
404
+     * Encoding is done according to RFC 3986 with one exception:
405
+     * Character '/' is preserved as is.
406
+     *
407
+     * @param string $component part of URI to encode
408
+     * @return string
409
+     * @since 6.0.0
410
+     */
411
+    public static function encodePath($component) {
412
+        return \OC_Util::encodePath($component);
413
+    }
414
+
415
+    /**
416
+     * Returns an array with all keys from input lowercased or uppercased. Numbered indices are left as is.
417
+     *
418
+     * @param array $input The array to work on
419
+     * @param int $case Either MB_CASE_UPPER or MB_CASE_LOWER (default)
420
+     * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
421
+     * @return array
422
+     * @since 4.5.0
423
+     */
424
+    public static function mb_array_change_key_case($input, $case = MB_CASE_LOWER, $encoding = 'UTF-8') {
425
+        return \OC_Helper::mb_array_change_key_case($input, $case, $encoding);
426
+    }
427
+
428
+    /**
429
+     * replaces a copy of string delimited by the start and (optionally) length parameters with the string given in replacement.
430
+     *
431
+     * @param string $string The input string. Opposite to the PHP build-in function does not accept an array.
432
+     * @param string $replacement The replacement string.
433
+     * @param int $start If start is positive, the replacing will begin at the start'th offset into string. If start is negative, the replacing will begin at the start'th character from the end of string.
434
+     * @param int $length Length of the part to be replaced
435
+     * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
436
+     * @return string
437
+     * @since 4.5.0
438
+     * @deprecated 8.2.0 Use substr_replace() instead.
439
+     */
440
+    public static function mb_substr_replace($string, $replacement, $start, $length = null, $encoding = 'UTF-8') {
441
+        return substr_replace($string, $replacement, $start, $length);
442
+    }
443
+
444
+    /**
445
+     * Replace all occurrences of the search string with the replacement string
446
+     *
447
+     * @param string $search The value being searched for, otherwise known as the needle. String.
448
+     * @param string $replace The replacement string.
449
+     * @param string $subject The string or array being searched and replaced on, otherwise known as the haystack.
450
+     * @param string $encoding The encoding parameter is the character encoding. Defaults to UTF-8
451
+     * @param int $count If passed, this will be set to the number of replacements performed.
452
+     * @return string
453
+     * @since 4.5.0
454
+     * @deprecated 8.2.0 Use str_replace() instead.
455
+     */
456
+    public static function mb_str_replace($search, $replace, $subject, $encoding = 'UTF-8', &$count = null) {
457
+        return str_replace($search, $replace, $subject, $count);
458
+    }
459
+
460
+    /**
461
+     * performs a search in a nested array
462
+     *
463
+     * @param array $haystack the array to be searched
464
+     * @param string $needle the search string
465
+     * @param mixed $index optional, only search this key name
466
+     * @return mixed the key of the matching field, otherwise false
467
+     * @since 4.5.0
468
+     */
469
+    public static function recursiveArraySearch($haystack, $needle, $index = null) {
470
+        return \OC_Helper::recursiveArraySearch($haystack, $needle, $index);
471
+    }
472
+
473
+    /**
474
+     * calculates the maximum upload size respecting system settings, free space and user quota
475
+     *
476
+     * @param string $dir the current folder where the user currently operates
477
+     * @param int $free the number of bytes free on the storage holding $dir, if not set this will be received from the storage directly
478
+     * @return int number of bytes representing
479
+     * @since 5.0.0
480
+     */
481
+    public static function maxUploadFilesize($dir, $free = null) {
482
+        return \OC_Helper::maxUploadFilesize($dir, $free);
483
+    }
484
+
485
+    /**
486
+     * Calculate free space left within user quota
487
+     * @param string $dir the current folder where the user currently operates
488
+     * @return int number of bytes representing
489
+     * @since 7.0.0
490
+     */
491
+    public static function freeSpace($dir) {
492
+        return \OC_Helper::freeSpace($dir);
493
+    }
494
+
495
+    /**
496
+     * Calculate PHP upload limit
497
+     *
498
+     * @return int number of bytes representing
499
+     * @since 7.0.0
500
+     */
501
+    public static function uploadLimit() {
502
+        return \OC_Helper::uploadLimit();
503
+    }
504
+
505
+    /**
506
+     * Returns whether the given file name is valid
507
+     * @param string $file file name to check
508
+     * @return bool true if the file name is valid, false otherwise
509
+     * @deprecated 8.1.0 use \OC\Files\View::verifyPath()
510
+     * @since 7.0.0
511
+     * @suppress PhanDeprecatedFunction
512
+     */
513
+    public static function isValidFileName($file) {
514
+        return \OC_Util::isValidFileName($file);
515
+    }
516
+
517
+    /**
518
+     * Compare two strings to provide a natural sort
519
+     * @param string $a first string to compare
520
+     * @param string $b second string to compare
521
+     * @return int -1 if $b comes before $a, 1 if $a comes before $b
522
+     * or 0 if the strings are identical
523
+     * @since 7.0.0
524
+     */
525
+    public static function naturalSortCompare($a, $b) {
526
+        return \OC\NaturalSort::getInstance()->compare($a, $b);
527
+    }
528
+
529
+    /**
530
+     * check if a password is required for each public link
531
+     * @return boolean
532
+     * @since 7.0.0
533
+     */
534
+    public static function isPublicLinkPasswordRequired() {
535
+        return \OC_Util::isPublicLinkPasswordRequired();
536
+    }
537
+
538
+    /**
539
+     * check if share API enforces a default expire date
540
+     * @return boolean
541
+     * @since 8.0.0
542
+     */
543
+    public static function isDefaultExpireDateEnforced() {
544
+        return \OC_Util::isDefaultExpireDateEnforced();
545
+    }
546
+
547
+    protected static $needUpgradeCache = null;
548
+
549
+    /**
550
+     * Checks whether the current version needs upgrade.
551
+     *
552
+     * @return bool true if upgrade is needed, false otherwise
553
+     * @since 7.0.0
554
+     */
555
+    public static function needUpgrade() {
556
+        if (!isset(self::$needUpgradeCache)) {
557
+            self::$needUpgradeCache=\OC_Util::needUpgrade(\OC::$server->getSystemConfig());
558
+        }		
559
+        return self::$needUpgradeCache;
560
+    }
561 561
 }
Please login to merge, or discard this patch.
lib/public/ILogger.php 1 patch
Indentation   +120 added lines, -120 removed lines patch added patch discarded remove patch
@@ -36,134 +36,134 @@
 block discarded – undo
36 36
  * https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#3-psrlogloggerinterface
37 37
  */
38 38
 interface ILogger {
39
-	/**
40
-	 * @since 14.0.0
41
-	 */
42
-	const DEBUG=0;
43
-	/**
44
-	 * @since 14.0.0
45
-	 */
46
-	const INFO=1;
47
-	/**
48
-	 * @since 14.0.0
49
-	 */
50
-	const WARN=2;
51
-	/**
52
-	 * @since 14.0.0
53
-	 */
54
-	const ERROR=3;
55
-	/**
56
-	 * @since 14.0.0
57
-	 */
58
-	const FATAL=4;
39
+    /**
40
+     * @since 14.0.0
41
+     */
42
+    const DEBUG=0;
43
+    /**
44
+     * @since 14.0.0
45
+     */
46
+    const INFO=1;
47
+    /**
48
+     * @since 14.0.0
49
+     */
50
+    const WARN=2;
51
+    /**
52
+     * @since 14.0.0
53
+     */
54
+    const ERROR=3;
55
+    /**
56
+     * @since 14.0.0
57
+     */
58
+    const FATAL=4;
59 59
 
60
-	/**
61
-	 * System is unusable.
62
-	 *
63
-	 * @param string $message
64
-	 * @param array $context
65
-	 * @return null
66
-	 * @since 7.0.0
67
-	 */
68
-	public function emergency(string $message, array $context = []);
60
+    /**
61
+     * System is unusable.
62
+     *
63
+     * @param string $message
64
+     * @param array $context
65
+     * @return null
66
+     * @since 7.0.0
67
+     */
68
+    public function emergency(string $message, array $context = []);
69 69
 
70
-	/**
71
-	 * Action must be taken immediately.
72
-	 *
73
-	 * @param string $message
74
-	 * @param array $context
75
-	 * @return null
76
-	 * @since 7.0.0
77
-	 */
78
-	public function alert(string $message, array $context = []);
70
+    /**
71
+     * Action must be taken immediately.
72
+     *
73
+     * @param string $message
74
+     * @param array $context
75
+     * @return null
76
+     * @since 7.0.0
77
+     */
78
+    public function alert(string $message, array $context = []);
79 79
 
80
-	/**
81
-	 * Critical conditions.
82
-	 *
83
-	 * @param string $message
84
-	 * @param array $context
85
-	 * @return null
86
-	 * @since 7.0.0
87
-	 */
88
-	public function critical(string $message, array $context = []);
80
+    /**
81
+     * Critical conditions.
82
+     *
83
+     * @param string $message
84
+     * @param array $context
85
+     * @return null
86
+     * @since 7.0.0
87
+     */
88
+    public function critical(string $message, array $context = []);
89 89
 
90
-	/**
91
-	 * Runtime errors that do not require immediate action but should typically
92
-	 * be logged and monitored.
93
-	 *
94
-	 * @param string $message
95
-	 * @param array $context
96
-	 * @return null
97
-	 * @since 7.0.0
98
-	 */
99
-	public function error(string $message, array $context = []);
90
+    /**
91
+     * Runtime errors that do not require immediate action but should typically
92
+     * be logged and monitored.
93
+     *
94
+     * @param string $message
95
+     * @param array $context
96
+     * @return null
97
+     * @since 7.0.0
98
+     */
99
+    public function error(string $message, array $context = []);
100 100
 
101
-	/**
102
-	 * Exceptional occurrences that are not errors.
103
-	 *
104
-	 * @param string $message
105
-	 * @param array $context
106
-	 * @return null
107
-	 * @since 7.0.0
108
-	 */
109
-	public function warning(string $message, array $context = []);
101
+    /**
102
+     * Exceptional occurrences that are not errors.
103
+     *
104
+     * @param string $message
105
+     * @param array $context
106
+     * @return null
107
+     * @since 7.0.0
108
+     */
109
+    public function warning(string $message, array $context = []);
110 110
 
111
-	/**
112
-	 * Normal but significant events.
113
-	 *
114
-	 * @param string $message
115
-	 * @param array $context
116
-	 * @return null
117
-	 * @since 7.0.0
118
-	 */
119
-	public function notice(string $message, array $context = []);
111
+    /**
112
+     * Normal but significant events.
113
+     *
114
+     * @param string $message
115
+     * @param array $context
116
+     * @return null
117
+     * @since 7.0.0
118
+     */
119
+    public function notice(string $message, array $context = []);
120 120
 
121
-	/**
122
-	 * Interesting events.
123
-	 *
124
-	 * @param string $message
125
-	 * @param array $context
126
-	 * @return null
127
-	 * @since 7.0.0
128
-	 */
129
-	public function info(string $message, array $context = []);
121
+    /**
122
+     * Interesting events.
123
+     *
124
+     * @param string $message
125
+     * @param array $context
126
+     * @return null
127
+     * @since 7.0.0
128
+     */
129
+    public function info(string $message, array $context = []);
130 130
 
131
-	/**
132
-	 * Detailed debug information.
133
-	 *
134
-	 * @param string $message
135
-	 * @param array $context
136
-	 * @return null
137
-	 * @since 7.0.0
138
-	 */
139
-	public function debug(string $message, array $context = []);
131
+    /**
132
+     * Detailed debug information.
133
+     *
134
+     * @param string $message
135
+     * @param array $context
136
+     * @return null
137
+     * @since 7.0.0
138
+     */
139
+    public function debug(string $message, array $context = []);
140 140
 
141
-	/**
142
-	 * Logs with an arbitrary level.
143
-	 *
144
-	 * @param int $level
145
-	 * @param string $message
146
-	 * @param array $context
147
-	 * @return mixed
148
-	 * @since 7.0.0
149
-	 */
150
-	public function log(int $level, string $message, array $context = []);
141
+    /**
142
+     * Logs with an arbitrary level.
143
+     *
144
+     * @param int $level
145
+     * @param string $message
146
+     * @param array $context
147
+     * @return mixed
148
+     * @since 7.0.0
149
+     */
150
+    public function log(int $level, string $message, array $context = []);
151 151
 
152
-	/**
153
-	 * Logs an exception very detailed
154
-	 * An additional message can we written to the log by adding it to the
155
-	 * context.
156
-	 *
157
-	 * <code>
158
-	 * $logger->logException($ex, [
159
-	 *     'message' => 'Exception during background job execution'
160
-	 * ]);
161
-	 * </code>
162
-	 *
163
-	 * @param \Exception|\Throwable $exception
164
-	 * @param array $context
165
-	 * @return void
166
-	 * @since 8.2.0
167
-	 */
168
-	public function logException(\Throwable $exception, array $context = []);
152
+    /**
153
+     * Logs an exception very detailed
154
+     * An additional message can we written to the log by adding it to the
155
+     * context.
156
+     *
157
+     * <code>
158
+     * $logger->logException($ex, [
159
+     *     'message' => 'Exception during background job execution'
160
+     * ]);
161
+     * </code>
162
+     *
163
+     * @param \Exception|\Throwable $exception
164
+     * @param array $context
165
+     * @return void
166
+     * @since 8.2.0
167
+     */
168
+    public function logException(\Throwable $exception, array $context = []);
169 169
 }
Please login to merge, or discard this patch.
settings/ajax/enableapp.php 1 patch
Indentation   +18 added lines, -18 removed lines patch added patch discarded remove patch
@@ -32,30 +32,30 @@
 block discarded – undo
32 32
 
33 33
 $lastConfirm = (int) \OC::$server->getSession()->get('last-password-confirm');
34 34
 if ($lastConfirm < (time() - 30 * 60 + 15)) { // allow 15 seconds delay
35
-	$l = \OC::$server->getL10N('core');
36
-	OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required'))));
37
-	exit();
35
+    $l = \OC::$server->getL10N('core');
36
+    OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required'))));
37
+    exit();
38 38
 }
39 39
 
40 40
 $groups = isset($_POST['groups']) ? (array)$_POST['groups'] : [];
41 41
 $appIds = isset($_POST['appIds']) ? (array)$_POST['appIds'] : [];
42 42
 
43 43
 try {
44
-	$updateRequired = false;
45
-	foreach($appIds as $appId) {
46
-		$app = new OC_App();
47
-		$appId = OC_App::cleanAppId($appId);
48
-		$app->enable($appId, $groups);
49
-		if(\OC_App::shouldUpgrade($appId)) {
50
-			$updateRequired = true;
51
-		}
52
-	}
44
+    $updateRequired = false;
45
+    foreach($appIds as $appId) {
46
+        $app = new OC_App();
47
+        $appId = OC_App::cleanAppId($appId);
48
+        $app->enable($appId, $groups);
49
+        if(\OC_App::shouldUpgrade($appId)) {
50
+            $updateRequired = true;
51
+        }
52
+    }
53 53
 
54
-	OC_JSON::success(['data' => ['update_required' => $updateRequired]]);
54
+    OC_JSON::success(['data' => ['update_required' => $updateRequired]]);
55 55
 } catch (Exception $e) {
56
-	\OC::$server->getLogger()->logException($e, [
57
-		'level' => ILogger::DEBUG,
58
-		'app' => 'core',
59
-	]);
60
-	OC_JSON::error(array("data" => array("message" => $e->getMessage()) ));
56
+    \OC::$server->getLogger()->logException($e, [
57
+        'level' => ILogger::DEBUG,
58
+        'app' => 'core',
59
+    ]);
60
+    OC_JSON::error(array("data" => array("message" => $e->getMessage()) ));
61 61
 }
Please login to merge, or discard this patch.
settings/Controller/UsersController.php 1 patch
Indentation   +943 added lines, -943 removed lines patch added patch discarded remove patch
@@ -71,948 +71,948 @@
 block discarded – undo
71 71
  * @package OC\Settings\Controller
72 72
  */
73 73
 class UsersController extends Controller {
74
-	/** @var IL10N */
75
-	private $l10n;
76
-	/** @var IUserSession */
77
-	private $userSession;
78
-	/** @var bool */
79
-	private $isAdmin;
80
-	/** @var IUserManager */
81
-	private $userManager;
82
-	/** @var IGroupManager */
83
-	private $groupManager;
84
-	/** @var IConfig */
85
-	private $config;
86
-	/** @var ILogger */
87
-	private $log;
88
-	/** @var IMailer */
89
-	private $mailer;
90
-	/** @var bool contains the state of the encryption app */
91
-	private $isEncryptionAppEnabled;
92
-	/** @var bool contains the state of the admin recovery setting */
93
-	private $isRestoreEnabled = false;
94
-	/** @var IAppManager */
95
-	private $appManager;
96
-	/** @var IAvatarManager */
97
-	private $avatarManager;
98
-	/** @var AccountManager */
99
-	private $accountManager;
100
-	/** @var ISecureRandom */
101
-	private $secureRandom;
102
-	/** @var NewUserMailHelper */
103
-	private $newUserMailHelper;
104
-	/** @var Manager */
105
-	private $keyManager;
106
-	/** @var IJobList */
107
-	private $jobList;
108
-
109
-	/** @var IUserMountCache */
110
-	private $userMountCache;
111
-
112
-	/** @var IManager */
113
-	private $encryptionManager;
114
-
115
-	public function __construct(string $appName,
116
-								IRequest $request,
117
-								IUserManager $userManager,
118
-								IGroupManager $groupManager,
119
-								IUserSession $userSession,
120
-								IConfig $config,
121
-								bool $isAdmin,
122
-								IL10N $l10n,
123
-								ILogger $log,
124
-								IMailer $mailer,
125
-								IURLGenerator $urlGenerator,
126
-								IAppManager $appManager,
127
-								IAvatarManager $avatarManager,
128
-								AccountManager $accountManager,
129
-								ISecureRandom $secureRandom,
130
-								NewUserMailHelper $newUserMailHelper,
131
-								Manager $keyManager,
132
-								IJobList $jobList,
133
-								IUserMountCache $userMountCache,
134
-								IManager $encryptionManager) {
135
-		parent::__construct($appName, $request);
136
-		$this->userManager = $userManager;
137
-		$this->groupManager = $groupManager;
138
-		$this->userSession = $userSession;
139
-		$this->config = $config;
140
-		$this->isAdmin = $isAdmin;
141
-		$this->l10n = $l10n;
142
-		$this->log = $log;
143
-		$this->mailer = $mailer;
144
-		$this->appManager = $appManager;
145
-		$this->avatarManager = $avatarManager;
146
-		$this->accountManager = $accountManager;
147
-		$this->secureRandom = $secureRandom;
148
-		$this->newUserMailHelper = $newUserMailHelper;
149
-		$this->keyManager = $keyManager;
150
-		$this->jobList = $jobList;
151
-		$this->userMountCache = $userMountCache;
152
-		$this->encryptionManager = $encryptionManager;
153
-
154
-		// check for encryption state - TODO see formatUserForIndex
155
-		$this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
156
-		if ($this->isEncryptionAppEnabled) {
157
-			// putting this directly in empty is possible in PHP 5.5+
158
-			$result = $config->getAppValue('encryption', 'recoveryAdminEnabled', '0');
159
-			$this->isRestoreEnabled = !empty($result);
160
-		}
161
-	}
162
-
163
-	/**
164
-	 * @param IUser $user
165
-	 * @param array|null $userGroups
166
-	 * @return array
167
-	 */
168
-	private function formatUserForIndex(IUser $user, array $userGroups = null): array {
169
-
170
-		// TODO: eliminate this encryption specific code below and somehow
171
-		// hook in additional user info from other apps
172
-
173
-		// recovery isn't possible if admin or user has it disabled and encryption
174
-		// is enabled - so we eliminate the else paths in the conditional tree
175
-		// below
176
-		$restorePossible = false;
177
-
178
-		if ($this->isEncryptionAppEnabled) {
179
-			if ($this->isRestoreEnabled) {
180
-				// check for the users recovery setting
181
-				$recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
182
-				// method call inside empty is possible with PHP 5.5+
183
-				$recoveryModeEnabled = !empty($recoveryMode);
184
-				if ($recoveryModeEnabled) {
185
-					// user also has recovery mode enabled
186
-					$restorePossible = true;
187
-				}
188
-			} else {
189
-				$modules = $this->encryptionManager->getEncryptionModules();
190
-				$restorePossible = true;
191
-				foreach ($modules as $id => $module) {
192
-					/* @var IEncryptionModule $instance */
193
-					$instance = call_user_func($module['callback']);
194
-					if ($instance->needDetailedAccessList()) {
195
-						$restorePossible = false;
196
-						break;
197
-					}
198
-				}
199
-			}
200
-		} else {
201
-			// recovery is possible if encryption is disabled (plain files are
202
-			// available)
203
-			$restorePossible = true;
204
-		}
205
-
206
-		$subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroupsName($user);
207
-
208
-		$displayName = $user->getEMailAddress();
209
-		if (is_null($displayName)) {
210
-			$displayName = '';
211
-		}
212
-
213
-		$avatarAvailable = false;
214
-		try {
215
-			$avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
216
-		} catch (\Exception $e) {
217
-			//No avatar yet
218
-		}
219
-
220
-		return [
221
-			'name' => $user->getUID(),
222
-			'displayname' => $user->getDisplayName(),
223
-			'groups' => empty($userGroups) ? $this->groupManager->getUserGroupNames($user) : $userGroups,
224
-			'subadmin' => $subAdminGroups,
225
-			'quota' => $user->getQuota(),
226
-			'quota_bytes' => Util::computerFileSize($user->getQuota()),
227
-			'storageLocation' => $user->getHome(),
228
-			'lastLogin' => $user->getLastLogin() * 1000,
229
-			'backend' => $user->getBackendClassName(),
230
-			'email' => $displayName,
231
-			'isRestoreDisabled' => !$restorePossible,
232
-			'isAvatarAvailable' => $avatarAvailable,
233
-			'isEnabled' => $user->isEnabled(),
234
-		];
235
-	}
236
-
237
-	/**
238
-	 * @param array $userIDs Array with schema [$uid => $displayName]
239
-	 * @return IUser[]
240
-	 */
241
-	private function getUsersForUID(array $userIDs): array {
242
-		$users = [];
243
-		foreach ($userIDs as $uid => $displayName) {
244
-			$users[$uid] = $this->userManager->get($uid);
245
-		}
246
-		return $users;
247
-	}
248
-
249
-	/**
250
-	 * @NoAdminRequired
251
-	 *
252
-	 * @param int $offset
253
-	 * @param int $limit
254
-	 * @param string $gid GID to filter for
255
-	 * @param string $pattern Pattern to search for in the username
256
-	 * @param string $backend Backend to filter for (class-name)
257
-	 * @return DataResponse
258
-	 *
259
-	 * TODO: Tidy up and write unit tests - code is mainly static method calls
260
-	 */
261
-	public function index(int $offset = 0, int $limit = 10, string $gid = '', string $pattern = '', string $backend = ''): DataResponse {
262
-		// Remove backends
263
-		if (!empty($backend)) {
264
-			$activeBackends = $this->userManager->getBackends();
265
-			$this->userManager->clearBackends();
266
-			foreach ($activeBackends as $singleActiveBackend) {
267
-				if ($backend === get_class($singleActiveBackend)) {
268
-					$this->userManager->registerBackend($singleActiveBackend);
269
-					break;
270
-				}
271
-			}
272
-		}
273
-
274
-		$userObjects = [];
275
-		$users = [];
276
-		if ($this->isAdmin) {
277
-			if ($gid !== '' && $gid !== '_disabledUsers' && $gid !== '_everyone') {
278
-				$batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
279
-			} else {
280
-				$batch = $this->userManager->search($pattern, $limit, $offset);
281
-			}
282
-
283
-			foreach ($batch as $user) {
284
-				if (($gid !== '_disabledUsers' && $user->isEnabled()) ||
285
-					($gid === '_disabledUsers' && !$user->isEnabled())
286
-				) {
287
-					$userObjects[] = $user;
288
-					$users[] = $this->formatUserForIndex($user);
289
-				}
290
-			}
291
-
292
-		} else {
293
-			$subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
294
-			// New class returns IGroup[] so convert back
295
-			$gids = [];
296
-			foreach ($subAdminOfGroups as $group) {
297
-				$gids[] = $group->getGID();
298
-			}
299
-			$subAdminOfGroups = $gids;
300
-
301
-			// Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
302
-			if ($gid !== '' && $gid !== '_disabledUsers' && !in_array($gid, $subAdminOfGroups)) {
303
-				$gid = '';
304
-			}
305
-
306
-			// Batch all groups the user is subadmin of when a group is specified
307
-			$batch = [];
308
-			if ($gid !== '' && $gid !== '_disabledUsers' && $gid !== '_everyone') {
309
-				$batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
310
-			} else {
311
-				foreach ($subAdminOfGroups as $group) {
312
-					$groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
313
-
314
-					foreach ($groupUsers as $uid => $displayName) {
315
-						$batch[$uid] = $displayName;
316
-					}
317
-				}
318
-			}
319
-			$batch = $this->getUsersForUID($batch);
320
-
321
-			foreach ($batch as $user) {
322
-				// Only add the groups, this user is a subadmin of
323
-				$userGroups = array_values(array_intersect(
324
-					$this->groupManager->getUserGroupIds($user),
325
-					$subAdminOfGroups
326
-				));
327
-				if (($gid !== '_disabledUsers' && $user->isEnabled()) ||
328
-					($gid === '_disabledUsers' && !$user->isEnabled())
329
-				) {
330
-					$userObjects[] = $user;
331
-					$users[] = $this->formatUserForIndex($user, $userGroups);
332
-				}
333
-			}
334
-		}
335
-
336
-		$usedSpace = $this->userMountCache->getUsedSpaceForUsers($userObjects);
337
-
338
-		foreach ($users as &$userData) {
339
-			$userData['size'] = isset($usedSpace[$userData['name']]) ? $usedSpace[$userData['name']] : 0;
340
-		}
341
-
342
-		return new DataResponse($users);
343
-	}
344
-
345
-	/**
346
-	 * @NoAdminRequired
347
-	 * @PasswordConfirmationRequired
348
-	 *
349
-	 * @param string $username
350
-	 * @param string $password
351
-	 * @param array $groups
352
-	 * @param string $email
353
-	 * @return DataResponse
354
-	 */
355
-	public function create(string $username, string $password, array $groups = [], $email = ''): DataResponse {
356
-		if ($email !== '' && !$this->mailer->validateMailAddress($email)) {
357
-			return new DataResponse(
358
-				[
359
-					'message' => $this->l10n->t('Invalid mail address')
360
-				],
361
-				Http::STATUS_UNPROCESSABLE_ENTITY
362
-			);
363
-		}
364
-
365
-		$currentUser = $this->userSession->getUser();
366
-
367
-		if (!$this->isAdmin) {
368
-			if (!empty($groups)) {
369
-				foreach ($groups as $key => $group) {
370
-					$groupObject = $this->groupManager->get($group);
371
-					if ($groupObject === null) {
372
-						unset($groups[$key]);
373
-						continue;
374
-					}
375
-
376
-					if (!$this->groupManager->getSubAdmin()->isSubAdminOfGroup($currentUser, $groupObject)) {
377
-						unset($groups[$key]);
378
-					}
379
-				}
380
-			}
381
-
382
-			if (empty($groups)) {
383
-				return new DataResponse(
384
-					[
385
-						'message' => $this->l10n->t('No valid group selected'),
386
-					],
387
-					Http::STATUS_FORBIDDEN
388
-				);
389
-			}
390
-		}
391
-
392
-		if ($this->userManager->userExists($username)) {
393
-			return new DataResponse(
394
-				[
395
-					'message' => $this->l10n->t('A user with that name already exists.')
396
-				],
397
-				Http::STATUS_CONFLICT
398
-			);
399
-		}
400
-
401
-		$generatePasswordResetToken = false;
402
-		if ($password === '') {
403
-			if ($email === '') {
404
-				return new DataResponse(
405
-					[
406
-						'message' => $this->l10n->t('To send a password link to the user an email address is required.')
407
-					],
408
-					Http::STATUS_UNPROCESSABLE_ENTITY
409
-				);
410
-			}
411
-
412
-			$password = $this->secureRandom->generate(30);
413
-			// Make sure we pass the password_policy
414
-			$password .= $this->secureRandom->generate(2, '$!.,;:-~+*[]{}()');
415
-			$generatePasswordResetToken = true;
416
-		}
417
-
418
-		try {
419
-			$user = $this->userManager->createUser($username, $password);
420
-		} catch (\Exception $exception) {
421
-			$message = $exception->getMessage();
422
-			if ($exception instanceof HintException && $exception->getHint()) {
423
-				$message = $exception->getHint();
424
-			}
425
-			if (!$message) {
426
-				$message = $this->l10n->t('Unable to create user.');
427
-			}
428
-			return new DataResponse(
429
-				[
430
-					'message' => (string)$message,
431
-				],
432
-				Http::STATUS_FORBIDDEN
433
-			);
434
-		}
435
-
436
-		if ($user instanceof IUser) {
437
-			if ($groups !== null) {
438
-				foreach ($groups as $groupName) {
439
-					$group = $this->groupManager->get($groupName);
440
-
441
-					if (empty($group)) {
442
-						$group = $this->groupManager->createGroup($groupName);
443
-					}
444
-					$group->addUser($user);
445
-				}
446
-			}
447
-			/**
448
-			 * Send new user mail only if a mail is set
449
-			 */
450
-			if ($email !== '') {
451
-				$user->setEMailAddress($email);
452
-				try {
453
-					$emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
454
-					$this->newUserMailHelper->sendMail($user, $emailTemplate);
455
-				} catch (\Exception $e) {
456
-					$this->log->logException($e, [
457
-						'message' => "Can't send new user mail to $email",
458
-						'level' => ILogger::ERROR,
459
-						'app' => 'settings',
460
-					]);
461
-				}
462
-			}
463
-			// fetch users groups
464
-			$userGroups = $this->groupManager->getUserGroupNames($user);
465
-
466
-			return new DataResponse(
467
-				$this->formatUserForIndex($user, $userGroups),
468
-				Http::STATUS_CREATED
469
-			);
470
-		}
471
-
472
-		return new DataResponse(
473
-			[
474
-				'message' => $this->l10n->t('Unable to create user.')
475
-			],
476
-			Http::STATUS_FORBIDDEN
477
-		);
478
-
479
-	}
480
-
481
-	/**
482
-	 * @NoAdminRequired
483
-	 * @PasswordConfirmationRequired
484
-	 *
485
-	 * @param string $id
486
-	 * @return DataResponse
487
-	 */
488
-	public function destroy(string $id): DataResponse {
489
-		$userId = $this->userSession->getUser()->getUID();
490
-		$user = $this->userManager->get($id);
491
-
492
-		if ($userId === $id) {
493
-			return new DataResponse(
494
-				[
495
-					'status' => 'error',
496
-					'data' => [
497
-						'message' => $this->l10n->t('Unable to delete user.')
498
-					]
499
-				],
500
-				Http::STATUS_FORBIDDEN
501
-			);
502
-		}
503
-
504
-		if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
505
-			return new DataResponse(
506
-				[
507
-					'status' => 'error',
508
-					'data' => [
509
-						'message' => $this->l10n->t('Authentication error')
510
-					]
511
-				],
512
-				Http::STATUS_FORBIDDEN
513
-			);
514
-		}
515
-
516
-		if ($user && $user->delete()) {
517
-			return new DataResponse(
518
-				[
519
-					'status' => 'success',
520
-					'data' => [
521
-						'username' => $id
522
-					]
523
-				],
524
-				Http::STATUS_NO_CONTENT
525
-			);
526
-		}
527
-
528
-		return new DataResponse(
529
-			[
530
-				'status' => 'error',
531
-				'data' => [
532
-					'message' => $this->l10n->t('Unable to delete user.')
533
-				]
534
-			],
535
-			Http::STATUS_FORBIDDEN
536
-		);
537
-	}
538
-
539
-	/**
540
-	 * @NoAdminRequired
541
-	 *
542
-	 * @param string $id
543
-	 * @param int $enabled
544
-	 * @return DataResponse
545
-	 */
546
-	public function setEnabled(string $id, int $enabled): DataResponse {
547
-		$enabled = (bool)$enabled;
548
-		if ($enabled) {
549
-			$errorMsgGeneral = $this->l10n->t('Error while enabling user.');
550
-		} else {
551
-			$errorMsgGeneral = $this->l10n->t('Error while disabling user.');
552
-		}
553
-
554
-		$userId = $this->userSession->getUser()->getUID();
555
-		$user = $this->userManager->get($id);
556
-
557
-		if ($userId === $id) {
558
-			return new DataResponse(
559
-				[
560
-					'status' => 'error',
561
-					'data' => [
562
-						'message' => $errorMsgGeneral
563
-					]
564
-				], Http::STATUS_FORBIDDEN
565
-			);
566
-		}
567
-
568
-		if ($user) {
569
-			if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
570
-				return new DataResponse(
571
-					[
572
-						'status' => 'error',
573
-						'data' => [
574
-							'message' => $this->l10n->t('Authentication error')
575
-						]
576
-					],
577
-					Http::STATUS_FORBIDDEN
578
-				);
579
-			}
580
-
581
-			$user->setEnabled($enabled);
582
-			return new DataResponse(
583
-				[
584
-					'status' => 'success',
585
-					'data' => [
586
-						'username' => $id,
587
-						'enabled' => $enabled
588
-					]
589
-				]
590
-			);
591
-		} else {
592
-			return new DataResponse(
593
-				[
594
-					'status' => 'error',
595
-					'data' => [
596
-						'message' => $errorMsgGeneral
597
-					]
598
-				],
599
-				Http::STATUS_FORBIDDEN
600
-			);
601
-		}
602
-
603
-	}
604
-
605
-	/**
606
-	 * Set the mail address of a user
607
-	 *
608
-	 * @NoAdminRequired
609
-	 * @NoSubadminRequired
610
-	 * @PasswordConfirmationRequired
611
-	 *
612
-	 * @param string $account
613
-	 * @param bool $onlyVerificationCode only return verification code without updating the data
614
-	 * @return DataResponse
615
-	 */
616
-	public function getVerificationCode(string $account, bool $onlyVerificationCode): DataResponse {
617
-
618
-		$user = $this->userSession->getUser();
619
-
620
-		if ($user === null) {
621
-			return new DataResponse([], Http::STATUS_BAD_REQUEST);
622
-		}
623
-
624
-		$accountData = $this->accountManager->getUser($user);
625
-		$cloudId = $user->getCloudId();
626
-		$message = 'Use my Federated Cloud ID to share with me: ' . $cloudId;
627
-		$signature = $this->signMessage($user, $message);
628
-
629
-		$code = $message . ' ' . $signature;
630
-		$codeMd5 = $message . ' ' . md5($signature);
631
-
632
-		switch ($account) {
633
-			case 'verify-twitter':
634
-				$accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
635
-				$msg = $this->l10n->t('In order to verify your Twitter account, post the following tweet on Twitter (please make sure to post it without any line breaks):');
636
-				$code = $codeMd5;
637
-				$type = AccountManager::PROPERTY_TWITTER;
638
-				$data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
639
-				$accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
640
-				break;
641
-			case 'verify-website':
642
-				$accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
643
-				$msg = $this->l10n->t('In order to verify your Website, store the following content in your web-root at \'.well-known/CloudIdVerificationCode.txt\' (please make sure that the complete text is in one line):');
644
-				$type = AccountManager::PROPERTY_WEBSITE;
645
-				$data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
646
-				$accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
647
-				break;
648
-			default:
649
-				return new DataResponse([], Http::STATUS_BAD_REQUEST);
650
-		}
651
-
652
-		if ($onlyVerificationCode === false) {
653
-			$this->accountManager->updateUser($user, $accountData);
654
-
655
-			$this->jobList->add(VerifyUserData::class,
656
-				[
657
-					'verificationCode' => $code,
658
-					'data' => $data,
659
-					'type' => $type,
660
-					'uid' => $user->getUID(),
661
-					'try' => 0,
662
-					'lastRun' => $this->getCurrentTime()
663
-				]
664
-			);
665
-		}
666
-
667
-		return new DataResponse(['msg' => $msg, 'code' => $code]);
668
-	}
669
-
670
-	/**
671
-	 * get current timestamp
672
-	 *
673
-	 * @return int
674
-	 */
675
-	protected function getCurrentTime(): int {
676
-		return time();
677
-	}
678
-
679
-	/**
680
-	 * sign message with users private key
681
-	 *
682
-	 * @param IUser $user
683
-	 * @param string $message
684
-	 *
685
-	 * @return string base64 encoded signature
686
-	 */
687
-	protected function signMessage(IUser $user, string $message): string {
688
-		$privateKey = $this->keyManager->getKey($user)->getPrivate();
689
-		openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
690
-		return base64_encode($signature);
691
-	}
692
-
693
-	/**
694
-	 * @NoAdminRequired
695
-	 * @NoSubadminRequired
696
-	 * @PasswordConfirmationRequired
697
-	 *
698
-	 * @param string $avatarScope
699
-	 * @param string $displayname
700
-	 * @param string $displaynameScope
701
-	 * @param string $phone
702
-	 * @param string $phoneScope
703
-	 * @param string $email
704
-	 * @param string $emailScope
705
-	 * @param string $website
706
-	 * @param string $websiteScope
707
-	 * @param string $address
708
-	 * @param string $addressScope
709
-	 * @param string $twitter
710
-	 * @param string $twitterScope
711
-	 * @return DataResponse
712
-	 */
713
-	public function setUserSettings($avatarScope,
714
-									$displayname,
715
-									$displaynameScope,
716
-									$phone,
717
-									$phoneScope,
718
-									$email,
719
-									$emailScope,
720
-									$website,
721
-									$websiteScope,
722
-									$address,
723
-									$addressScope,
724
-									$twitter,
725
-									$twitterScope
726
-	) {
727
-
728
-		if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
729
-			return new DataResponse(
730
-				[
731
-					'status' => 'error',
732
-					'data' => [
733
-						'message' => $this->l10n->t('Invalid mail address')
734
-					]
735
-				],
736
-				Http::STATUS_UNPROCESSABLE_ENTITY
737
-			);
738
-		}
739
-
740
-		$user = $this->userSession->getUser();
741
-
742
-		$data = $this->accountManager->getUser($user);
743
-
744
-		$data[AccountManager::PROPERTY_AVATAR] = ['scope' => $avatarScope];
745
-		if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
746
-			$data[AccountManager::PROPERTY_DISPLAYNAME] = ['value' => $displayname, 'scope' => $displaynameScope];
747
-			$data[AccountManager::PROPERTY_EMAIL] = ['value' => $email, 'scope' => $emailScope];
748
-		}
749
-
750
-		if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
751
-			$federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application();
752
-			$shareProvider = $federatedFileSharing->getFederatedShareProvider();
753
-			if ($shareProvider->isLookupServerUploadEnabled()) {
754
-				$data[AccountManager::PROPERTY_WEBSITE] = ['value' => $website, 'scope' => $websiteScope];
755
-				$data[AccountManager::PROPERTY_ADDRESS] = ['value' => $address, 'scope' => $addressScope];
756
-				$data[AccountManager::PROPERTY_PHONE] = ['value' => $phone, 'scope' => $phoneScope];
757
-				$data[AccountManager::PROPERTY_TWITTER] = ['value' => $twitter, 'scope' => $twitterScope];
758
-			}
759
-		}
760
-
761
-		try {
762
-			$this->saveUserSettings($user, $data);
763
-			return new DataResponse(
764
-				[
765
-					'status' => 'success',
766
-					'data' => [
767
-						'userId' => $user->getUID(),
768
-						'avatarScope' => $data[AccountManager::PROPERTY_AVATAR]['scope'],
769
-						'displayname' => $data[AccountManager::PROPERTY_DISPLAYNAME]['value'],
770
-						'displaynameScope' => $data[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
771
-						'email' => $data[AccountManager::PROPERTY_EMAIL]['value'],
772
-						'emailScope' => $data[AccountManager::PROPERTY_EMAIL]['scope'],
773
-						'website' => $data[AccountManager::PROPERTY_WEBSITE]['value'],
774
-						'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
775
-						'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
776
-						'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
777
-						'message' => $this->l10n->t('Settings saved')
778
-					]
779
-				],
780
-				Http::STATUS_OK
781
-			);
782
-		} catch (ForbiddenException $e) {
783
-			return new DataResponse([
784
-				'status' => 'error',
785
-				'data' => [
786
-					'message' => $e->getMessage()
787
-				],
788
-			]);
789
-		}
790
-
791
-	}
792
-
793
-
794
-	/**
795
-	 * update account manager with new user data
796
-	 *
797
-	 * @param IUser $user
798
-	 * @param array $data
799
-	 * @throws ForbiddenException
800
-	 */
801
-	protected function saveUserSettings(IUser $user, array $data) {
802
-
803
-		// keep the user back-end up-to-date with the latest display name and email
804
-		// address
805
-		$oldDisplayName = $user->getDisplayName();
806
-		$oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
807
-		if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
808
-			&& $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
809
-		) {
810
-			$result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
811
-			if ($result === false) {
812
-				throw new ForbiddenException($this->l10n->t('Unable to change full name'));
813
-			}
814
-		}
815
-
816
-		$oldEmailAddress = $user->getEMailAddress();
817
-		$oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
818
-		if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
819
-			&& $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
820
-		) {
821
-			// this is the only permission a backend provides and is also used
822
-			// for the permission of setting a email address
823
-			if (!$user->canChangeDisplayName()) {
824
-				throw new ForbiddenException($this->l10n->t('Unable to change email address'));
825
-			}
826
-			$user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
827
-		}
828
-
829
-		$this->accountManager->updateUser($user, $data);
830
-	}
831
-
832
-	/**
833
-	 * Count all unique users visible for the current admin/subadmin.
834
-	 *
835
-	 * @NoAdminRequired
836
-	 *
837
-	 * @return DataResponse
838
-	 */
839
-	public function stats(): DataResponse {
840
-		$userCount = 0;
841
-		if ($this->isAdmin) {
842
-			$countByBackend = $this->userManager->countUsers();
843
-
844
-			if (!empty($countByBackend)) {
845
-				foreach ($countByBackend as $count) {
846
-					$userCount += $count;
847
-				}
848
-			}
849
-		} else {
850
-			$groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
851
-
852
-			$uniqueUsers = [];
853
-			foreach ($groups as $group) {
854
-				foreach ($group->getUsers() as $uid => $displayName) {
855
-					$uniqueUsers[$uid] = true;
856
-				}
857
-			}
858
-
859
-			$userCount = count($uniqueUsers);
860
-		}
861
-
862
-		return new DataResponse(
863
-			[
864
-				'totalUsers' => $userCount
865
-			]
866
-		);
867
-	}
868
-
869
-
870
-	/**
871
-	 * Set the displayName of a user
872
-	 *
873
-	 * @NoAdminRequired
874
-	 * @NoSubadminRequired
875
-	 * @PasswordConfirmationRequired
876
-	 * @todo merge into saveUserSettings
877
-	 *
878
-	 * @param string $username
879
-	 * @param string $displayName
880
-	 * @return DataResponse
881
-	 */
882
-	public function setDisplayName(string $username, string $displayName) {
883
-		$currentUser = $this->userSession->getUser();
884
-		$user = $this->userManager->get($username);
885
-
886
-		if ($user === null ||
887
-			!$user->canChangeDisplayName() ||
888
-			(
889
-				!$this->groupManager->isAdmin($currentUser->getUID()) &&
890
-				!$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
891
-				$currentUser->getUID() !== $username
892
-
893
-			)
894
-		) {
895
-			return new DataResponse([
896
-				'status' => 'error',
897
-				'data' => [
898
-					'message' => $this->l10n->t('Authentication error'),
899
-				],
900
-			]);
901
-		}
902
-
903
-		$userData = $this->accountManager->getUser($user);
904
-		$userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
905
-
906
-
907
-		try {
908
-			$this->saveUserSettings($user, $userData);
909
-			return new DataResponse([
910
-				'status' => 'success',
911
-				'data' => [
912
-					'message' => $this->l10n->t('Your full name has been changed.'),
913
-					'username' => $username,
914
-					'displayName' => $displayName,
915
-				],
916
-			]);
917
-		} catch (ForbiddenException $e) {
918
-			return new DataResponse([
919
-				'status' => 'error',
920
-				'data' => [
921
-					'message' => $e->getMessage(),
922
-					'displayName' => $user->getDisplayName(),
923
-				],
924
-			]);
925
-		}
926
-	}
927
-
928
-	/**
929
-	 * Set the mail address of a user
930
-	 *
931
-	 * @NoAdminRequired
932
-	 * @NoSubadminRequired
933
-	 * @PasswordConfirmationRequired
934
-	 *
935
-	 * @param string $id
936
-	 * @param string $mailAddress
937
-	 * @return DataResponse
938
-	 */
939
-	public function setEMailAddress(string $id, string $mailAddress) {
940
-		$user = $this->userManager->get($id);
941
-		if (!$this->isAdmin
942
-			&& !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
943
-		) {
944
-			return new DataResponse(
945
-				[
946
-					'status' => 'error',
947
-					'data' => [
948
-						'message' => $this->l10n->t('Forbidden')
949
-					]
950
-				],
951
-				Http::STATUS_FORBIDDEN
952
-			);
953
-		}
954
-
955
-		if ($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
956
-			return new DataResponse(
957
-				[
958
-					'status' => 'error',
959
-					'data' => [
960
-						'message' => $this->l10n->t('Invalid mail address')
961
-					]
962
-				],
963
-				Http::STATUS_UNPROCESSABLE_ENTITY
964
-			);
965
-		}
966
-
967
-		if (!$user) {
968
-			return new DataResponse(
969
-				[
970
-					'status' => 'error',
971
-					'data' => [
972
-						'message' => $this->l10n->t('Invalid user')
973
-					]
974
-				],
975
-				Http::STATUS_UNPROCESSABLE_ENTITY
976
-			);
977
-		}
978
-		// this is the only permission a backend provides and is also used
979
-		// for the permission of setting a email address
980
-		if (!$user->canChangeDisplayName()) {
981
-			return new DataResponse(
982
-				[
983
-					'status' => 'error',
984
-					'data' => [
985
-						'message' => $this->l10n->t('Unable to change mail address')
986
-					]
987
-				],
988
-				Http::STATUS_FORBIDDEN
989
-			);
990
-		}
991
-
992
-		$userData = $this->accountManager->getUser($user);
993
-		$userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
994
-
995
-		try {
996
-			$this->saveUserSettings($user, $userData);
997
-			return new DataResponse(
998
-				[
999
-					'status' => 'success',
1000
-					'data' => [
1001
-						'username' => $id,
1002
-						'mailAddress' => $mailAddress,
1003
-						'message' => $this->l10n->t('Email saved')
1004
-					]
1005
-				],
1006
-				Http::STATUS_OK
1007
-			);
1008
-		} catch (ForbiddenException $e) {
1009
-			return new DataResponse([
1010
-				'status' => 'error',
1011
-				'data' => [
1012
-					'message' => $e->getMessage()
1013
-				],
1014
-			]);
1015
-		}
1016
-	}
74
+    /** @var IL10N */
75
+    private $l10n;
76
+    /** @var IUserSession */
77
+    private $userSession;
78
+    /** @var bool */
79
+    private $isAdmin;
80
+    /** @var IUserManager */
81
+    private $userManager;
82
+    /** @var IGroupManager */
83
+    private $groupManager;
84
+    /** @var IConfig */
85
+    private $config;
86
+    /** @var ILogger */
87
+    private $log;
88
+    /** @var IMailer */
89
+    private $mailer;
90
+    /** @var bool contains the state of the encryption app */
91
+    private $isEncryptionAppEnabled;
92
+    /** @var bool contains the state of the admin recovery setting */
93
+    private $isRestoreEnabled = false;
94
+    /** @var IAppManager */
95
+    private $appManager;
96
+    /** @var IAvatarManager */
97
+    private $avatarManager;
98
+    /** @var AccountManager */
99
+    private $accountManager;
100
+    /** @var ISecureRandom */
101
+    private $secureRandom;
102
+    /** @var NewUserMailHelper */
103
+    private $newUserMailHelper;
104
+    /** @var Manager */
105
+    private $keyManager;
106
+    /** @var IJobList */
107
+    private $jobList;
108
+
109
+    /** @var IUserMountCache */
110
+    private $userMountCache;
111
+
112
+    /** @var IManager */
113
+    private $encryptionManager;
114
+
115
+    public function __construct(string $appName,
116
+                                IRequest $request,
117
+                                IUserManager $userManager,
118
+                                IGroupManager $groupManager,
119
+                                IUserSession $userSession,
120
+                                IConfig $config,
121
+                                bool $isAdmin,
122
+                                IL10N $l10n,
123
+                                ILogger $log,
124
+                                IMailer $mailer,
125
+                                IURLGenerator $urlGenerator,
126
+                                IAppManager $appManager,
127
+                                IAvatarManager $avatarManager,
128
+                                AccountManager $accountManager,
129
+                                ISecureRandom $secureRandom,
130
+                                NewUserMailHelper $newUserMailHelper,
131
+                                Manager $keyManager,
132
+                                IJobList $jobList,
133
+                                IUserMountCache $userMountCache,
134
+                                IManager $encryptionManager) {
135
+        parent::__construct($appName, $request);
136
+        $this->userManager = $userManager;
137
+        $this->groupManager = $groupManager;
138
+        $this->userSession = $userSession;
139
+        $this->config = $config;
140
+        $this->isAdmin = $isAdmin;
141
+        $this->l10n = $l10n;
142
+        $this->log = $log;
143
+        $this->mailer = $mailer;
144
+        $this->appManager = $appManager;
145
+        $this->avatarManager = $avatarManager;
146
+        $this->accountManager = $accountManager;
147
+        $this->secureRandom = $secureRandom;
148
+        $this->newUserMailHelper = $newUserMailHelper;
149
+        $this->keyManager = $keyManager;
150
+        $this->jobList = $jobList;
151
+        $this->userMountCache = $userMountCache;
152
+        $this->encryptionManager = $encryptionManager;
153
+
154
+        // check for encryption state - TODO see formatUserForIndex
155
+        $this->isEncryptionAppEnabled = $appManager->isEnabledForUser('encryption');
156
+        if ($this->isEncryptionAppEnabled) {
157
+            // putting this directly in empty is possible in PHP 5.5+
158
+            $result = $config->getAppValue('encryption', 'recoveryAdminEnabled', '0');
159
+            $this->isRestoreEnabled = !empty($result);
160
+        }
161
+    }
162
+
163
+    /**
164
+     * @param IUser $user
165
+     * @param array|null $userGroups
166
+     * @return array
167
+     */
168
+    private function formatUserForIndex(IUser $user, array $userGroups = null): array {
169
+
170
+        // TODO: eliminate this encryption specific code below and somehow
171
+        // hook in additional user info from other apps
172
+
173
+        // recovery isn't possible if admin or user has it disabled and encryption
174
+        // is enabled - so we eliminate the else paths in the conditional tree
175
+        // below
176
+        $restorePossible = false;
177
+
178
+        if ($this->isEncryptionAppEnabled) {
179
+            if ($this->isRestoreEnabled) {
180
+                // check for the users recovery setting
181
+                $recoveryMode = $this->config->getUserValue($user->getUID(), 'encryption', 'recoveryEnabled', '0');
182
+                // method call inside empty is possible with PHP 5.5+
183
+                $recoveryModeEnabled = !empty($recoveryMode);
184
+                if ($recoveryModeEnabled) {
185
+                    // user also has recovery mode enabled
186
+                    $restorePossible = true;
187
+                }
188
+            } else {
189
+                $modules = $this->encryptionManager->getEncryptionModules();
190
+                $restorePossible = true;
191
+                foreach ($modules as $id => $module) {
192
+                    /* @var IEncryptionModule $instance */
193
+                    $instance = call_user_func($module['callback']);
194
+                    if ($instance->needDetailedAccessList()) {
195
+                        $restorePossible = false;
196
+                        break;
197
+                    }
198
+                }
199
+            }
200
+        } else {
201
+            // recovery is possible if encryption is disabled (plain files are
202
+            // available)
203
+            $restorePossible = true;
204
+        }
205
+
206
+        $subAdminGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroupsName($user);
207
+
208
+        $displayName = $user->getEMailAddress();
209
+        if (is_null($displayName)) {
210
+            $displayName = '';
211
+        }
212
+
213
+        $avatarAvailable = false;
214
+        try {
215
+            $avatarAvailable = $this->avatarManager->getAvatar($user->getUID())->exists();
216
+        } catch (\Exception $e) {
217
+            //No avatar yet
218
+        }
219
+
220
+        return [
221
+            'name' => $user->getUID(),
222
+            'displayname' => $user->getDisplayName(),
223
+            'groups' => empty($userGroups) ? $this->groupManager->getUserGroupNames($user) : $userGroups,
224
+            'subadmin' => $subAdminGroups,
225
+            'quota' => $user->getQuota(),
226
+            'quota_bytes' => Util::computerFileSize($user->getQuota()),
227
+            'storageLocation' => $user->getHome(),
228
+            'lastLogin' => $user->getLastLogin() * 1000,
229
+            'backend' => $user->getBackendClassName(),
230
+            'email' => $displayName,
231
+            'isRestoreDisabled' => !$restorePossible,
232
+            'isAvatarAvailable' => $avatarAvailable,
233
+            'isEnabled' => $user->isEnabled(),
234
+        ];
235
+    }
236
+
237
+    /**
238
+     * @param array $userIDs Array with schema [$uid => $displayName]
239
+     * @return IUser[]
240
+     */
241
+    private function getUsersForUID(array $userIDs): array {
242
+        $users = [];
243
+        foreach ($userIDs as $uid => $displayName) {
244
+            $users[$uid] = $this->userManager->get($uid);
245
+        }
246
+        return $users;
247
+    }
248
+
249
+    /**
250
+     * @NoAdminRequired
251
+     *
252
+     * @param int $offset
253
+     * @param int $limit
254
+     * @param string $gid GID to filter for
255
+     * @param string $pattern Pattern to search for in the username
256
+     * @param string $backend Backend to filter for (class-name)
257
+     * @return DataResponse
258
+     *
259
+     * TODO: Tidy up and write unit tests - code is mainly static method calls
260
+     */
261
+    public function index(int $offset = 0, int $limit = 10, string $gid = '', string $pattern = '', string $backend = ''): DataResponse {
262
+        // Remove backends
263
+        if (!empty($backend)) {
264
+            $activeBackends = $this->userManager->getBackends();
265
+            $this->userManager->clearBackends();
266
+            foreach ($activeBackends as $singleActiveBackend) {
267
+                if ($backend === get_class($singleActiveBackend)) {
268
+                    $this->userManager->registerBackend($singleActiveBackend);
269
+                    break;
270
+                }
271
+            }
272
+        }
273
+
274
+        $userObjects = [];
275
+        $users = [];
276
+        if ($this->isAdmin) {
277
+            if ($gid !== '' && $gid !== '_disabledUsers' && $gid !== '_everyone') {
278
+                $batch = $this->getUsersForUID($this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset));
279
+            } else {
280
+                $batch = $this->userManager->search($pattern, $limit, $offset);
281
+            }
282
+
283
+            foreach ($batch as $user) {
284
+                if (($gid !== '_disabledUsers' && $user->isEnabled()) ||
285
+                    ($gid === '_disabledUsers' && !$user->isEnabled())
286
+                ) {
287
+                    $userObjects[] = $user;
288
+                    $users[] = $this->formatUserForIndex($user);
289
+                }
290
+            }
291
+
292
+        } else {
293
+            $subAdminOfGroups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
294
+            // New class returns IGroup[] so convert back
295
+            $gids = [];
296
+            foreach ($subAdminOfGroups as $group) {
297
+                $gids[] = $group->getGID();
298
+            }
299
+            $subAdminOfGroups = $gids;
300
+
301
+            // Set the $gid parameter to an empty value if the subadmin has no rights to access a specific group
302
+            if ($gid !== '' && $gid !== '_disabledUsers' && !in_array($gid, $subAdminOfGroups)) {
303
+                $gid = '';
304
+            }
305
+
306
+            // Batch all groups the user is subadmin of when a group is specified
307
+            $batch = [];
308
+            if ($gid !== '' && $gid !== '_disabledUsers' && $gid !== '_everyone') {
309
+                $batch = $this->groupManager->displayNamesInGroup($gid, $pattern, $limit, $offset);
310
+            } else {
311
+                foreach ($subAdminOfGroups as $group) {
312
+                    $groupUsers = $this->groupManager->displayNamesInGroup($group, $pattern, $limit, $offset);
313
+
314
+                    foreach ($groupUsers as $uid => $displayName) {
315
+                        $batch[$uid] = $displayName;
316
+                    }
317
+                }
318
+            }
319
+            $batch = $this->getUsersForUID($batch);
320
+
321
+            foreach ($batch as $user) {
322
+                // Only add the groups, this user is a subadmin of
323
+                $userGroups = array_values(array_intersect(
324
+                    $this->groupManager->getUserGroupIds($user),
325
+                    $subAdminOfGroups
326
+                ));
327
+                if (($gid !== '_disabledUsers' && $user->isEnabled()) ||
328
+                    ($gid === '_disabledUsers' && !$user->isEnabled())
329
+                ) {
330
+                    $userObjects[] = $user;
331
+                    $users[] = $this->formatUserForIndex($user, $userGroups);
332
+                }
333
+            }
334
+        }
335
+
336
+        $usedSpace = $this->userMountCache->getUsedSpaceForUsers($userObjects);
337
+
338
+        foreach ($users as &$userData) {
339
+            $userData['size'] = isset($usedSpace[$userData['name']]) ? $usedSpace[$userData['name']] : 0;
340
+        }
341
+
342
+        return new DataResponse($users);
343
+    }
344
+
345
+    /**
346
+     * @NoAdminRequired
347
+     * @PasswordConfirmationRequired
348
+     *
349
+     * @param string $username
350
+     * @param string $password
351
+     * @param array $groups
352
+     * @param string $email
353
+     * @return DataResponse
354
+     */
355
+    public function create(string $username, string $password, array $groups = [], $email = ''): DataResponse {
356
+        if ($email !== '' && !$this->mailer->validateMailAddress($email)) {
357
+            return new DataResponse(
358
+                [
359
+                    'message' => $this->l10n->t('Invalid mail address')
360
+                ],
361
+                Http::STATUS_UNPROCESSABLE_ENTITY
362
+            );
363
+        }
364
+
365
+        $currentUser = $this->userSession->getUser();
366
+
367
+        if (!$this->isAdmin) {
368
+            if (!empty($groups)) {
369
+                foreach ($groups as $key => $group) {
370
+                    $groupObject = $this->groupManager->get($group);
371
+                    if ($groupObject === null) {
372
+                        unset($groups[$key]);
373
+                        continue;
374
+                    }
375
+
376
+                    if (!$this->groupManager->getSubAdmin()->isSubAdminOfGroup($currentUser, $groupObject)) {
377
+                        unset($groups[$key]);
378
+                    }
379
+                }
380
+            }
381
+
382
+            if (empty($groups)) {
383
+                return new DataResponse(
384
+                    [
385
+                        'message' => $this->l10n->t('No valid group selected'),
386
+                    ],
387
+                    Http::STATUS_FORBIDDEN
388
+                );
389
+            }
390
+        }
391
+
392
+        if ($this->userManager->userExists($username)) {
393
+            return new DataResponse(
394
+                [
395
+                    'message' => $this->l10n->t('A user with that name already exists.')
396
+                ],
397
+                Http::STATUS_CONFLICT
398
+            );
399
+        }
400
+
401
+        $generatePasswordResetToken = false;
402
+        if ($password === '') {
403
+            if ($email === '') {
404
+                return new DataResponse(
405
+                    [
406
+                        'message' => $this->l10n->t('To send a password link to the user an email address is required.')
407
+                    ],
408
+                    Http::STATUS_UNPROCESSABLE_ENTITY
409
+                );
410
+            }
411
+
412
+            $password = $this->secureRandom->generate(30);
413
+            // Make sure we pass the password_policy
414
+            $password .= $this->secureRandom->generate(2, '$!.,;:-~+*[]{}()');
415
+            $generatePasswordResetToken = true;
416
+        }
417
+
418
+        try {
419
+            $user = $this->userManager->createUser($username, $password);
420
+        } catch (\Exception $exception) {
421
+            $message = $exception->getMessage();
422
+            if ($exception instanceof HintException && $exception->getHint()) {
423
+                $message = $exception->getHint();
424
+            }
425
+            if (!$message) {
426
+                $message = $this->l10n->t('Unable to create user.');
427
+            }
428
+            return new DataResponse(
429
+                [
430
+                    'message' => (string)$message,
431
+                ],
432
+                Http::STATUS_FORBIDDEN
433
+            );
434
+        }
435
+
436
+        if ($user instanceof IUser) {
437
+            if ($groups !== null) {
438
+                foreach ($groups as $groupName) {
439
+                    $group = $this->groupManager->get($groupName);
440
+
441
+                    if (empty($group)) {
442
+                        $group = $this->groupManager->createGroup($groupName);
443
+                    }
444
+                    $group->addUser($user);
445
+                }
446
+            }
447
+            /**
448
+             * Send new user mail only if a mail is set
449
+             */
450
+            if ($email !== '') {
451
+                $user->setEMailAddress($email);
452
+                try {
453
+                    $emailTemplate = $this->newUserMailHelper->generateTemplate($user, $generatePasswordResetToken);
454
+                    $this->newUserMailHelper->sendMail($user, $emailTemplate);
455
+                } catch (\Exception $e) {
456
+                    $this->log->logException($e, [
457
+                        'message' => "Can't send new user mail to $email",
458
+                        'level' => ILogger::ERROR,
459
+                        'app' => 'settings',
460
+                    ]);
461
+                }
462
+            }
463
+            // fetch users groups
464
+            $userGroups = $this->groupManager->getUserGroupNames($user);
465
+
466
+            return new DataResponse(
467
+                $this->formatUserForIndex($user, $userGroups),
468
+                Http::STATUS_CREATED
469
+            );
470
+        }
471
+
472
+        return new DataResponse(
473
+            [
474
+                'message' => $this->l10n->t('Unable to create user.')
475
+            ],
476
+            Http::STATUS_FORBIDDEN
477
+        );
478
+
479
+    }
480
+
481
+    /**
482
+     * @NoAdminRequired
483
+     * @PasswordConfirmationRequired
484
+     *
485
+     * @param string $id
486
+     * @return DataResponse
487
+     */
488
+    public function destroy(string $id): DataResponse {
489
+        $userId = $this->userSession->getUser()->getUID();
490
+        $user = $this->userManager->get($id);
491
+
492
+        if ($userId === $id) {
493
+            return new DataResponse(
494
+                [
495
+                    'status' => 'error',
496
+                    'data' => [
497
+                        'message' => $this->l10n->t('Unable to delete user.')
498
+                    ]
499
+                ],
500
+                Http::STATUS_FORBIDDEN
501
+            );
502
+        }
503
+
504
+        if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
505
+            return new DataResponse(
506
+                [
507
+                    'status' => 'error',
508
+                    'data' => [
509
+                        'message' => $this->l10n->t('Authentication error')
510
+                    ]
511
+                ],
512
+                Http::STATUS_FORBIDDEN
513
+            );
514
+        }
515
+
516
+        if ($user && $user->delete()) {
517
+            return new DataResponse(
518
+                [
519
+                    'status' => 'success',
520
+                    'data' => [
521
+                        'username' => $id
522
+                    ]
523
+                ],
524
+                Http::STATUS_NO_CONTENT
525
+            );
526
+        }
527
+
528
+        return new DataResponse(
529
+            [
530
+                'status' => 'error',
531
+                'data' => [
532
+                    'message' => $this->l10n->t('Unable to delete user.')
533
+                ]
534
+            ],
535
+            Http::STATUS_FORBIDDEN
536
+        );
537
+    }
538
+
539
+    /**
540
+     * @NoAdminRequired
541
+     *
542
+     * @param string $id
543
+     * @param int $enabled
544
+     * @return DataResponse
545
+     */
546
+    public function setEnabled(string $id, int $enabled): DataResponse {
547
+        $enabled = (bool)$enabled;
548
+        if ($enabled) {
549
+            $errorMsgGeneral = $this->l10n->t('Error while enabling user.');
550
+        } else {
551
+            $errorMsgGeneral = $this->l10n->t('Error while disabling user.');
552
+        }
553
+
554
+        $userId = $this->userSession->getUser()->getUID();
555
+        $user = $this->userManager->get($id);
556
+
557
+        if ($userId === $id) {
558
+            return new DataResponse(
559
+                [
560
+                    'status' => 'error',
561
+                    'data' => [
562
+                        'message' => $errorMsgGeneral
563
+                    ]
564
+                ], Http::STATUS_FORBIDDEN
565
+            );
566
+        }
567
+
568
+        if ($user) {
569
+            if (!$this->isAdmin && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)) {
570
+                return new DataResponse(
571
+                    [
572
+                        'status' => 'error',
573
+                        'data' => [
574
+                            'message' => $this->l10n->t('Authentication error')
575
+                        ]
576
+                    ],
577
+                    Http::STATUS_FORBIDDEN
578
+                );
579
+            }
580
+
581
+            $user->setEnabled($enabled);
582
+            return new DataResponse(
583
+                [
584
+                    'status' => 'success',
585
+                    'data' => [
586
+                        'username' => $id,
587
+                        'enabled' => $enabled
588
+                    ]
589
+                ]
590
+            );
591
+        } else {
592
+            return new DataResponse(
593
+                [
594
+                    'status' => 'error',
595
+                    'data' => [
596
+                        'message' => $errorMsgGeneral
597
+                    ]
598
+                ],
599
+                Http::STATUS_FORBIDDEN
600
+            );
601
+        }
602
+
603
+    }
604
+
605
+    /**
606
+     * Set the mail address of a user
607
+     *
608
+     * @NoAdminRequired
609
+     * @NoSubadminRequired
610
+     * @PasswordConfirmationRequired
611
+     *
612
+     * @param string $account
613
+     * @param bool $onlyVerificationCode only return verification code without updating the data
614
+     * @return DataResponse
615
+     */
616
+    public function getVerificationCode(string $account, bool $onlyVerificationCode): DataResponse {
617
+
618
+        $user = $this->userSession->getUser();
619
+
620
+        if ($user === null) {
621
+            return new DataResponse([], Http::STATUS_BAD_REQUEST);
622
+        }
623
+
624
+        $accountData = $this->accountManager->getUser($user);
625
+        $cloudId = $user->getCloudId();
626
+        $message = 'Use my Federated Cloud ID to share with me: ' . $cloudId;
627
+        $signature = $this->signMessage($user, $message);
628
+
629
+        $code = $message . ' ' . $signature;
630
+        $codeMd5 = $message . ' ' . md5($signature);
631
+
632
+        switch ($account) {
633
+            case 'verify-twitter':
634
+                $accountData[AccountManager::PROPERTY_TWITTER]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
635
+                $msg = $this->l10n->t('In order to verify your Twitter account, post the following tweet on Twitter (please make sure to post it without any line breaks):');
636
+                $code = $codeMd5;
637
+                $type = AccountManager::PROPERTY_TWITTER;
638
+                $data = $accountData[AccountManager::PROPERTY_TWITTER]['value'];
639
+                $accountData[AccountManager::PROPERTY_TWITTER]['signature'] = $signature;
640
+                break;
641
+            case 'verify-website':
642
+                $accountData[AccountManager::PROPERTY_WEBSITE]['verified'] = AccountManager::VERIFICATION_IN_PROGRESS;
643
+                $msg = $this->l10n->t('In order to verify your Website, store the following content in your web-root at \'.well-known/CloudIdVerificationCode.txt\' (please make sure that the complete text is in one line):');
644
+                $type = AccountManager::PROPERTY_WEBSITE;
645
+                $data = $accountData[AccountManager::PROPERTY_WEBSITE]['value'];
646
+                $accountData[AccountManager::PROPERTY_WEBSITE]['signature'] = $signature;
647
+                break;
648
+            default:
649
+                return new DataResponse([], Http::STATUS_BAD_REQUEST);
650
+        }
651
+
652
+        if ($onlyVerificationCode === false) {
653
+            $this->accountManager->updateUser($user, $accountData);
654
+
655
+            $this->jobList->add(VerifyUserData::class,
656
+                [
657
+                    'verificationCode' => $code,
658
+                    'data' => $data,
659
+                    'type' => $type,
660
+                    'uid' => $user->getUID(),
661
+                    'try' => 0,
662
+                    'lastRun' => $this->getCurrentTime()
663
+                ]
664
+            );
665
+        }
666
+
667
+        return new DataResponse(['msg' => $msg, 'code' => $code]);
668
+    }
669
+
670
+    /**
671
+     * get current timestamp
672
+     *
673
+     * @return int
674
+     */
675
+    protected function getCurrentTime(): int {
676
+        return time();
677
+    }
678
+
679
+    /**
680
+     * sign message with users private key
681
+     *
682
+     * @param IUser $user
683
+     * @param string $message
684
+     *
685
+     * @return string base64 encoded signature
686
+     */
687
+    protected function signMessage(IUser $user, string $message): string {
688
+        $privateKey = $this->keyManager->getKey($user)->getPrivate();
689
+        openssl_sign(json_encode($message), $signature, $privateKey, OPENSSL_ALGO_SHA512);
690
+        return base64_encode($signature);
691
+    }
692
+
693
+    /**
694
+     * @NoAdminRequired
695
+     * @NoSubadminRequired
696
+     * @PasswordConfirmationRequired
697
+     *
698
+     * @param string $avatarScope
699
+     * @param string $displayname
700
+     * @param string $displaynameScope
701
+     * @param string $phone
702
+     * @param string $phoneScope
703
+     * @param string $email
704
+     * @param string $emailScope
705
+     * @param string $website
706
+     * @param string $websiteScope
707
+     * @param string $address
708
+     * @param string $addressScope
709
+     * @param string $twitter
710
+     * @param string $twitterScope
711
+     * @return DataResponse
712
+     */
713
+    public function setUserSettings($avatarScope,
714
+                                    $displayname,
715
+                                    $displaynameScope,
716
+                                    $phone,
717
+                                    $phoneScope,
718
+                                    $email,
719
+                                    $emailScope,
720
+                                    $website,
721
+                                    $websiteScope,
722
+                                    $address,
723
+                                    $addressScope,
724
+                                    $twitter,
725
+                                    $twitterScope
726
+    ) {
727
+
728
+        if (!empty($email) && !$this->mailer->validateMailAddress($email)) {
729
+            return new DataResponse(
730
+                [
731
+                    'status' => 'error',
732
+                    'data' => [
733
+                        'message' => $this->l10n->t('Invalid mail address')
734
+                    ]
735
+                ],
736
+                Http::STATUS_UNPROCESSABLE_ENTITY
737
+            );
738
+        }
739
+
740
+        $user = $this->userSession->getUser();
741
+
742
+        $data = $this->accountManager->getUser($user);
743
+
744
+        $data[AccountManager::PROPERTY_AVATAR] = ['scope' => $avatarScope];
745
+        if ($this->config->getSystemValue('allow_user_to_change_display_name', true) !== false) {
746
+            $data[AccountManager::PROPERTY_DISPLAYNAME] = ['value' => $displayname, 'scope' => $displaynameScope];
747
+            $data[AccountManager::PROPERTY_EMAIL] = ['value' => $email, 'scope' => $emailScope];
748
+        }
749
+
750
+        if ($this->appManager->isEnabledForUser('federatedfilesharing')) {
751
+            $federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application();
752
+            $shareProvider = $federatedFileSharing->getFederatedShareProvider();
753
+            if ($shareProvider->isLookupServerUploadEnabled()) {
754
+                $data[AccountManager::PROPERTY_WEBSITE] = ['value' => $website, 'scope' => $websiteScope];
755
+                $data[AccountManager::PROPERTY_ADDRESS] = ['value' => $address, 'scope' => $addressScope];
756
+                $data[AccountManager::PROPERTY_PHONE] = ['value' => $phone, 'scope' => $phoneScope];
757
+                $data[AccountManager::PROPERTY_TWITTER] = ['value' => $twitter, 'scope' => $twitterScope];
758
+            }
759
+        }
760
+
761
+        try {
762
+            $this->saveUserSettings($user, $data);
763
+            return new DataResponse(
764
+                [
765
+                    'status' => 'success',
766
+                    'data' => [
767
+                        'userId' => $user->getUID(),
768
+                        'avatarScope' => $data[AccountManager::PROPERTY_AVATAR]['scope'],
769
+                        'displayname' => $data[AccountManager::PROPERTY_DISPLAYNAME]['value'],
770
+                        'displaynameScope' => $data[AccountManager::PROPERTY_DISPLAYNAME]['scope'],
771
+                        'email' => $data[AccountManager::PROPERTY_EMAIL]['value'],
772
+                        'emailScope' => $data[AccountManager::PROPERTY_EMAIL]['scope'],
773
+                        'website' => $data[AccountManager::PROPERTY_WEBSITE]['value'],
774
+                        'websiteScope' => $data[AccountManager::PROPERTY_WEBSITE]['scope'],
775
+                        'address' => $data[AccountManager::PROPERTY_ADDRESS]['value'],
776
+                        'addressScope' => $data[AccountManager::PROPERTY_ADDRESS]['scope'],
777
+                        'message' => $this->l10n->t('Settings saved')
778
+                    ]
779
+                ],
780
+                Http::STATUS_OK
781
+            );
782
+        } catch (ForbiddenException $e) {
783
+            return new DataResponse([
784
+                'status' => 'error',
785
+                'data' => [
786
+                    'message' => $e->getMessage()
787
+                ],
788
+            ]);
789
+        }
790
+
791
+    }
792
+
793
+
794
+    /**
795
+     * update account manager with new user data
796
+     *
797
+     * @param IUser $user
798
+     * @param array $data
799
+     * @throws ForbiddenException
800
+     */
801
+    protected function saveUserSettings(IUser $user, array $data) {
802
+
803
+        // keep the user back-end up-to-date with the latest display name and email
804
+        // address
805
+        $oldDisplayName = $user->getDisplayName();
806
+        $oldDisplayName = is_null($oldDisplayName) ? '' : $oldDisplayName;
807
+        if (isset($data[AccountManager::PROPERTY_DISPLAYNAME]['value'])
808
+            && $oldDisplayName !== $data[AccountManager::PROPERTY_DISPLAYNAME]['value']
809
+        ) {
810
+            $result = $user->setDisplayName($data[AccountManager::PROPERTY_DISPLAYNAME]['value']);
811
+            if ($result === false) {
812
+                throw new ForbiddenException($this->l10n->t('Unable to change full name'));
813
+            }
814
+        }
815
+
816
+        $oldEmailAddress = $user->getEMailAddress();
817
+        $oldEmailAddress = is_null($oldEmailAddress) ? '' : $oldEmailAddress;
818
+        if (isset($data[AccountManager::PROPERTY_EMAIL]['value'])
819
+            && $oldEmailAddress !== $data[AccountManager::PROPERTY_EMAIL]['value']
820
+        ) {
821
+            // this is the only permission a backend provides and is also used
822
+            // for the permission of setting a email address
823
+            if (!$user->canChangeDisplayName()) {
824
+                throw new ForbiddenException($this->l10n->t('Unable to change email address'));
825
+            }
826
+            $user->setEMailAddress($data[AccountManager::PROPERTY_EMAIL]['value']);
827
+        }
828
+
829
+        $this->accountManager->updateUser($user, $data);
830
+    }
831
+
832
+    /**
833
+     * Count all unique users visible for the current admin/subadmin.
834
+     *
835
+     * @NoAdminRequired
836
+     *
837
+     * @return DataResponse
838
+     */
839
+    public function stats(): DataResponse {
840
+        $userCount = 0;
841
+        if ($this->isAdmin) {
842
+            $countByBackend = $this->userManager->countUsers();
843
+
844
+            if (!empty($countByBackend)) {
845
+                foreach ($countByBackend as $count) {
846
+                    $userCount += $count;
847
+                }
848
+            }
849
+        } else {
850
+            $groups = $this->groupManager->getSubAdmin()->getSubAdminsGroups($this->userSession->getUser());
851
+
852
+            $uniqueUsers = [];
853
+            foreach ($groups as $group) {
854
+                foreach ($group->getUsers() as $uid => $displayName) {
855
+                    $uniqueUsers[$uid] = true;
856
+                }
857
+            }
858
+
859
+            $userCount = count($uniqueUsers);
860
+        }
861
+
862
+        return new DataResponse(
863
+            [
864
+                'totalUsers' => $userCount
865
+            ]
866
+        );
867
+    }
868
+
869
+
870
+    /**
871
+     * Set the displayName of a user
872
+     *
873
+     * @NoAdminRequired
874
+     * @NoSubadminRequired
875
+     * @PasswordConfirmationRequired
876
+     * @todo merge into saveUserSettings
877
+     *
878
+     * @param string $username
879
+     * @param string $displayName
880
+     * @return DataResponse
881
+     */
882
+    public function setDisplayName(string $username, string $displayName) {
883
+        $currentUser = $this->userSession->getUser();
884
+        $user = $this->userManager->get($username);
885
+
886
+        if ($user === null ||
887
+            !$user->canChangeDisplayName() ||
888
+            (
889
+                !$this->groupManager->isAdmin($currentUser->getUID()) &&
890
+                !$this->groupManager->getSubAdmin()->isUserAccessible($currentUser, $user) &&
891
+                $currentUser->getUID() !== $username
892
+
893
+            )
894
+        ) {
895
+            return new DataResponse([
896
+                'status' => 'error',
897
+                'data' => [
898
+                    'message' => $this->l10n->t('Authentication error'),
899
+                ],
900
+            ]);
901
+        }
902
+
903
+        $userData = $this->accountManager->getUser($user);
904
+        $userData[AccountManager::PROPERTY_DISPLAYNAME]['value'] = $displayName;
905
+
906
+
907
+        try {
908
+            $this->saveUserSettings($user, $userData);
909
+            return new DataResponse([
910
+                'status' => 'success',
911
+                'data' => [
912
+                    'message' => $this->l10n->t('Your full name has been changed.'),
913
+                    'username' => $username,
914
+                    'displayName' => $displayName,
915
+                ],
916
+            ]);
917
+        } catch (ForbiddenException $e) {
918
+            return new DataResponse([
919
+                'status' => 'error',
920
+                'data' => [
921
+                    'message' => $e->getMessage(),
922
+                    'displayName' => $user->getDisplayName(),
923
+                ],
924
+            ]);
925
+        }
926
+    }
927
+
928
+    /**
929
+     * Set the mail address of a user
930
+     *
931
+     * @NoAdminRequired
932
+     * @NoSubadminRequired
933
+     * @PasswordConfirmationRequired
934
+     *
935
+     * @param string $id
936
+     * @param string $mailAddress
937
+     * @return DataResponse
938
+     */
939
+    public function setEMailAddress(string $id, string $mailAddress) {
940
+        $user = $this->userManager->get($id);
941
+        if (!$this->isAdmin
942
+            && !$this->groupManager->getSubAdmin()->isUserAccessible($this->userSession->getUser(), $user)
943
+        ) {
944
+            return new DataResponse(
945
+                [
946
+                    'status' => 'error',
947
+                    'data' => [
948
+                        'message' => $this->l10n->t('Forbidden')
949
+                    ]
950
+                ],
951
+                Http::STATUS_FORBIDDEN
952
+            );
953
+        }
954
+
955
+        if ($mailAddress !== '' && !$this->mailer->validateMailAddress($mailAddress)) {
956
+            return new DataResponse(
957
+                [
958
+                    'status' => 'error',
959
+                    'data' => [
960
+                        'message' => $this->l10n->t('Invalid mail address')
961
+                    ]
962
+                ],
963
+                Http::STATUS_UNPROCESSABLE_ENTITY
964
+            );
965
+        }
966
+
967
+        if (!$user) {
968
+            return new DataResponse(
969
+                [
970
+                    'status' => 'error',
971
+                    'data' => [
972
+                        'message' => $this->l10n->t('Invalid user')
973
+                    ]
974
+                ],
975
+                Http::STATUS_UNPROCESSABLE_ENTITY
976
+            );
977
+        }
978
+        // this is the only permission a backend provides and is also used
979
+        // for the permission of setting a email address
980
+        if (!$user->canChangeDisplayName()) {
981
+            return new DataResponse(
982
+                [
983
+                    'status' => 'error',
984
+                    'data' => [
985
+                        'message' => $this->l10n->t('Unable to change mail address')
986
+                    ]
987
+                ],
988
+                Http::STATUS_FORBIDDEN
989
+            );
990
+        }
991
+
992
+        $userData = $this->accountManager->getUser($user);
993
+        $userData[AccountManager::PROPERTY_EMAIL]['value'] = $mailAddress;
994
+
995
+        try {
996
+            $this->saveUserSettings($user, $userData);
997
+            return new DataResponse(
998
+                [
999
+                    'status' => 'success',
1000
+                    'data' => [
1001
+                        'username' => $id,
1002
+                        'mailAddress' => $mailAddress,
1003
+                        'message' => $this->l10n->t('Email saved')
1004
+                    ]
1005
+                ],
1006
+                Http::STATUS_OK
1007
+            );
1008
+        } catch (ForbiddenException $e) {
1009
+            return new DataResponse([
1010
+                'status' => 'error',
1011
+                'data' => [
1012
+                    'message' => $e->getMessage()
1013
+                ],
1014
+            ]);
1015
+        }
1016
+    }
1017 1017
 
1018 1018
 }
Please login to merge, or discard this patch.
lib/private/Log/File.php 1 patch
Indentation   +151 added lines, -151 removed lines patch added patch discarded remove patch
@@ -48,159 +48,159 @@
 block discarded – undo
48 48
  */
49 49
 
50 50
 class File implements IWriter, IFileBased {
51
-	/** @var string */
52
-	protected $logFile;
53
-	/** @var IConfig */
54
-	private $config;
51
+    /** @var string */
52
+    protected $logFile;
53
+    /** @var IConfig */
54
+    private $config;
55 55
 
56
-	public function __construct(string $path, string $fallbackPath = '', IConfig $config) {
57
-		$this->logFile = $path;
58
-		if (!file_exists($this->logFile)) {
59
-			if(
60
-				(
61
-					!is_writable(dirname($this->logFile))
62
-					|| !touch($this->logFile)
63
-				)
64
-				&& $fallbackPath !== ''
65
-			) {
66
-				$this->logFile = $fallbackPath;
67
-			}
68
-		}
69
-		$this->config = $config;
70
-	}
56
+    public function __construct(string $path, string $fallbackPath = '', IConfig $config) {
57
+        $this->logFile = $path;
58
+        if (!file_exists($this->logFile)) {
59
+            if(
60
+                (
61
+                    !is_writable(dirname($this->logFile))
62
+                    || !touch($this->logFile)
63
+                )
64
+                && $fallbackPath !== ''
65
+            ) {
66
+                $this->logFile = $fallbackPath;
67
+            }
68
+        }
69
+        $this->config = $config;
70
+    }
71 71
 
72
-	/**
73
-	 * write a message in the log
74
-	 * @param string $app
75
-	 * @param string|array $message
76
-	 * @param int $level
77
-	 */
78
-	public function write(string $app, $message, int $level) {
79
-		// default to ISO8601
80
-		$format = $this->config->getSystemValue('logdateformat', \DateTime::ATOM);
81
-		$logTimeZone = $this->config->getSystemValue('logtimezone', 'UTC');
82
-		try {
83
-			$timezone = new \DateTimeZone($logTimeZone);
84
-		} catch (\Exception $e) {
85
-			$timezone = new \DateTimeZone('UTC');
86
-		}
87
-		$time = \DateTime::createFromFormat("U.u", number_format(microtime(true), 4, ".", ""));
88
-		if ($time === false) {
89
-			$time = new \DateTime(null, $timezone);
90
-		} else {
91
-			// apply timezone if $time is created from UNIX timestamp
92
-			$time->setTimezone($timezone);
93
-		}
94
-		$request = \OC::$server->getRequest();
95
-		$reqId = $request->getId();
96
-		$remoteAddr = $request->getRemoteAddress();
97
-		// remove username/passwords from URLs before writing the to the log file
98
-		$time = $time->format($format);
99
-		$url = ($request->getRequestUri() !== '') ? $request->getRequestUri() : '--';
100
-		$method = is_string($request->getMethod()) ? $request->getMethod() : '--';
101
-		if($this->config->getSystemValue('installed', false)) {
102
-			$user = \OC_User::getUser() ? \OC_User::getUser() : '--';
103
-		} else {
104
-			$user = '--';
105
-		}
106
-		$userAgent = $request->getHeader('User-Agent');
107
-		if ($userAgent === '') {
108
-			$userAgent = '--';
109
-		}
110
-		$version = $this->config->getSystemValue('version', '');
111
-		$entry = compact(
112
-			'reqId',
113
-			'level',
114
-			'time',
115
-			'remoteAddr',
116
-			'user',
117
-			'app',
118
-			'method',
119
-			'url',
120
-			'message',
121
-			'userAgent',
122
-			'version'
123
-		);
124
-		// PHP's json_encode only accept proper UTF-8 strings, loop over all
125
-		// elements to ensure that they are properly UTF-8 compliant or convert
126
-		// them manually.
127
-		foreach($entry as $key => $value) {
128
-			if(is_string($value)) {
129
-				$testEncode = json_encode($value);
130
-				if($testEncode === false) {
131
-					$entry[$key] = utf8_encode($value);
132
-				}
133
-			}
134
-		}
135
-		$entry = json_encode($entry, JSON_PARTIAL_OUTPUT_ON_ERROR);
136
-		$handle = @fopen($this->logFile, 'a');
137
-		if ((fileperms($this->logFile) & 0777) != 0640) {
138
-			@chmod($this->logFile, 0640);
139
-		}
140
-		if ($handle) {
141
-			fwrite($handle, $entry."\n");
142
-			fclose($handle);
143
-		} else {
144
-			// Fall back to error_log
145
-			error_log($entry);
146
-		}
147
-		if (php_sapi_name() === 'cli-server') {
148
-			error_log($message, 4);
149
-		}
150
-	}
72
+    /**
73
+     * write a message in the log
74
+     * @param string $app
75
+     * @param string|array $message
76
+     * @param int $level
77
+     */
78
+    public function write(string $app, $message, int $level) {
79
+        // default to ISO8601
80
+        $format = $this->config->getSystemValue('logdateformat', \DateTime::ATOM);
81
+        $logTimeZone = $this->config->getSystemValue('logtimezone', 'UTC');
82
+        try {
83
+            $timezone = new \DateTimeZone($logTimeZone);
84
+        } catch (\Exception $e) {
85
+            $timezone = new \DateTimeZone('UTC');
86
+        }
87
+        $time = \DateTime::createFromFormat("U.u", number_format(microtime(true), 4, ".", ""));
88
+        if ($time === false) {
89
+            $time = new \DateTime(null, $timezone);
90
+        } else {
91
+            // apply timezone if $time is created from UNIX timestamp
92
+            $time->setTimezone($timezone);
93
+        }
94
+        $request = \OC::$server->getRequest();
95
+        $reqId = $request->getId();
96
+        $remoteAddr = $request->getRemoteAddress();
97
+        // remove username/passwords from URLs before writing the to the log file
98
+        $time = $time->format($format);
99
+        $url = ($request->getRequestUri() !== '') ? $request->getRequestUri() : '--';
100
+        $method = is_string($request->getMethod()) ? $request->getMethod() : '--';
101
+        if($this->config->getSystemValue('installed', false)) {
102
+            $user = \OC_User::getUser() ? \OC_User::getUser() : '--';
103
+        } else {
104
+            $user = '--';
105
+        }
106
+        $userAgent = $request->getHeader('User-Agent');
107
+        if ($userAgent === '') {
108
+            $userAgent = '--';
109
+        }
110
+        $version = $this->config->getSystemValue('version', '');
111
+        $entry = compact(
112
+            'reqId',
113
+            'level',
114
+            'time',
115
+            'remoteAddr',
116
+            'user',
117
+            'app',
118
+            'method',
119
+            'url',
120
+            'message',
121
+            'userAgent',
122
+            'version'
123
+        );
124
+        // PHP's json_encode only accept proper UTF-8 strings, loop over all
125
+        // elements to ensure that they are properly UTF-8 compliant or convert
126
+        // them manually.
127
+        foreach($entry as $key => $value) {
128
+            if(is_string($value)) {
129
+                $testEncode = json_encode($value);
130
+                if($testEncode === false) {
131
+                    $entry[$key] = utf8_encode($value);
132
+                }
133
+            }
134
+        }
135
+        $entry = json_encode($entry, JSON_PARTIAL_OUTPUT_ON_ERROR);
136
+        $handle = @fopen($this->logFile, 'a');
137
+        if ((fileperms($this->logFile) & 0777) != 0640) {
138
+            @chmod($this->logFile, 0640);
139
+        }
140
+        if ($handle) {
141
+            fwrite($handle, $entry."\n");
142
+            fclose($handle);
143
+        } else {
144
+            // Fall back to error_log
145
+            error_log($entry);
146
+        }
147
+        if (php_sapi_name() === 'cli-server') {
148
+            error_log($message, 4);
149
+        }
150
+    }
151 151
 
152
-	/**
153
-	 * get entries from the log in reverse chronological order
154
-	 * @param int $limit
155
-	 * @param int $offset
156
-	 * @return array
157
-	 */
158
-	public function getEntries(int $limit=50, int $offset=0):array {
159
-		$minLevel = $this->config->getSystemValue("loglevel", ILogger::WARN);
160
-		$entries = array();
161
-		$handle = @fopen($this->logFile, 'rb');
162
-		if ($handle) {
163
-			fseek($handle, 0, SEEK_END);
164
-			$pos = ftell($handle);
165
-			$line = '';
166
-			$entriesCount = 0;
167
-			$lines = 0;
168
-			// Loop through each character of the file looking for new lines
169
-			while ($pos >= 0 && ($limit === null ||$entriesCount < $limit)) {
170
-				fseek($handle, $pos);
171
-				$ch = fgetc($handle);
172
-				if ($ch == "\n" || $pos == 0) {
173
-					if ($line != '') {
174
-						// Add the first character if at the start of the file,
175
-						// because it doesn't hit the else in the loop
176
-						if ($pos == 0) {
177
-							$line = $ch.$line;
178
-						}
179
-						$entry = json_decode($line);
180
-						// Add the line as an entry if it is passed the offset and is equal or above the log level
181
-						if ($entry->level >= $minLevel) {
182
-							$lines++;
183
-							if ($lines > $offset) {
184
-								$entries[] = $entry;
185
-								$entriesCount++;
186
-							}
187
-						}
188
-						$line = '';
189
-					}
190
-				} else {
191
-					$line = $ch.$line;
192
-				}
193
-				$pos--;
194
-			}
195
-			fclose($handle);
196
-		}
197
-		return $entries;
198
-	}
152
+    /**
153
+     * get entries from the log in reverse chronological order
154
+     * @param int $limit
155
+     * @param int $offset
156
+     * @return array
157
+     */
158
+    public function getEntries(int $limit=50, int $offset=0):array {
159
+        $minLevel = $this->config->getSystemValue("loglevel", ILogger::WARN);
160
+        $entries = array();
161
+        $handle = @fopen($this->logFile, 'rb');
162
+        if ($handle) {
163
+            fseek($handle, 0, SEEK_END);
164
+            $pos = ftell($handle);
165
+            $line = '';
166
+            $entriesCount = 0;
167
+            $lines = 0;
168
+            // Loop through each character of the file looking for new lines
169
+            while ($pos >= 0 && ($limit === null ||$entriesCount < $limit)) {
170
+                fseek($handle, $pos);
171
+                $ch = fgetc($handle);
172
+                if ($ch == "\n" || $pos == 0) {
173
+                    if ($line != '') {
174
+                        // Add the first character if at the start of the file,
175
+                        // because it doesn't hit the else in the loop
176
+                        if ($pos == 0) {
177
+                            $line = $ch.$line;
178
+                        }
179
+                        $entry = json_decode($line);
180
+                        // Add the line as an entry if it is passed the offset and is equal or above the log level
181
+                        if ($entry->level >= $minLevel) {
182
+                            $lines++;
183
+                            if ($lines > $offset) {
184
+                                $entries[] = $entry;
185
+                                $entriesCount++;
186
+                            }
187
+                        }
188
+                        $line = '';
189
+                    }
190
+                } else {
191
+                    $line = $ch.$line;
192
+                }
193
+                $pos--;
194
+            }
195
+            fclose($handle);
196
+        }
197
+        return $entries;
198
+    }
199 199
 
200
-	/**
201
-	 * @return string
202
-	 */
203
-	public function getLogFilePath():string {
204
-		return $this->logFile;
205
-	}
200
+    /**
201
+     * @return string
202
+     */
203
+    public function getLogFilePath():string {
204
+        return $this->logFile;
205
+    }
206 206
 }
Please login to merge, or discard this patch.
lib/public/Log/IFileBased.php 1 patch
Indentation   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -31,13 +31,13 @@
 block discarded – undo
31 31
  * @since 14.0.0
32 32
  */
33 33
 interface IFileBased {
34
-	/**
35
-	 * @since 14.0.0
36
-	 */
37
-	public function getLogFilePath():string;
34
+    /**
35
+     * @since 14.0.0
36
+     */
37
+    public function getLogFilePath():string;
38 38
 
39
-	/**
40
-	 * @since 14.0.0
41
-	 */
42
-	public function getEntries(int $limit=50, int $offset=0): array;
39
+    /**
40
+     * @since 14.0.0
41
+     */
42
+    public function getEntries(int $limit=50, int $offset=0): array;
43 43
 }
Please login to merge, or discard this patch.
apps/federation/lib/BackgroundJob/GetSharedSecret.php 1 patch
Indentation   +174 added lines, -174 removed lines patch added patch discarded remove patch
@@ -55,203 +55,203 @@
 block discarded – undo
55 55
  */
56 56
 class GetSharedSecret extends Job {
57 57
 
58
-	/** @var IClient */
59
-	private $httpClient;
58
+    /** @var IClient */
59
+    private $httpClient;
60 60
 
61
-	/** @var IJobList */
62
-	private $jobList;
61
+    /** @var IJobList */
62
+    private $jobList;
63 63
 
64
-	/** @var IURLGenerator */
65
-	private $urlGenerator;
64
+    /** @var IURLGenerator */
65
+    private $urlGenerator;
66 66
 
67
-	/** @var TrustedServers  */
68
-	private $trustedServers;
67
+    /** @var TrustedServers  */
68
+    private $trustedServers;
69 69
 
70
-	/** @var IDiscoveryService  */
71
-	private $ocsDiscoveryService;
70
+    /** @var IDiscoveryService  */
71
+    private $ocsDiscoveryService;
72 72
 
73
-	/** @var ILogger */
74
-	private $logger;
73
+    /** @var ILogger */
74
+    private $logger;
75 75
 
76
-	/** @var ITimeFactory */
77
-	private $timeFactory;
76
+    /** @var ITimeFactory */
77
+    private $timeFactory;
78 78
 
79
-	/** @var bool */
80
-	protected $retainJob = false;
79
+    /** @var bool */
80
+    protected $retainJob = false;
81 81
 
82
-	private $defaultEndPoint = '/ocs/v2.php/apps/federation/api/v1/shared-secret';
82
+    private $defaultEndPoint = '/ocs/v2.php/apps/federation/api/v1/shared-secret';
83 83
 
84
-	/** @var  int  30 day = 2592000sec */
85
-	private $maxLifespan = 2592000;
84
+    /** @var  int  30 day = 2592000sec */
85
+    private $maxLifespan = 2592000;
86 86
 
87
-	/**
88
-	 * RequestSharedSecret constructor.
89
-	 *
90
-	 * @param IClientService $httpClientService
91
-	 * @param IURLGenerator $urlGenerator
92
-	 * @param IJobList $jobList
93
-	 * @param TrustedServers $trustedServers
94
-	 * @param ILogger $logger
95
-	 * @param IDiscoveryService $ocsDiscoveryService
96
-	 * @param ITimeFactory $timeFactory
97
-	 */
98
-	public function __construct(
99
-		IClientService $httpClientService,
100
-		IURLGenerator $urlGenerator,
101
-		IJobList $jobList,
102
-		TrustedServers $trustedServers,
103
-		ILogger $logger,
104
-		IDiscoveryService $ocsDiscoveryService,
105
-		ITimeFactory $timeFactory
106
-	) {
107
-		$this->logger = $logger;
108
-		$this->httpClient = $httpClientService->newClient();
109
-		$this->jobList = $jobList;
110
-		$this->urlGenerator = $urlGenerator;
111
-		$this->ocsDiscoveryService = $ocsDiscoveryService;
112
-		$this->trustedServers = $trustedServers;
113
-		$this->timeFactory = $timeFactory;
114
-	}
87
+    /**
88
+     * RequestSharedSecret constructor.
89
+     *
90
+     * @param IClientService $httpClientService
91
+     * @param IURLGenerator $urlGenerator
92
+     * @param IJobList $jobList
93
+     * @param TrustedServers $trustedServers
94
+     * @param ILogger $logger
95
+     * @param IDiscoveryService $ocsDiscoveryService
96
+     * @param ITimeFactory $timeFactory
97
+     */
98
+    public function __construct(
99
+        IClientService $httpClientService,
100
+        IURLGenerator $urlGenerator,
101
+        IJobList $jobList,
102
+        TrustedServers $trustedServers,
103
+        ILogger $logger,
104
+        IDiscoveryService $ocsDiscoveryService,
105
+        ITimeFactory $timeFactory
106
+    ) {
107
+        $this->logger = $logger;
108
+        $this->httpClient = $httpClientService->newClient();
109
+        $this->jobList = $jobList;
110
+        $this->urlGenerator = $urlGenerator;
111
+        $this->ocsDiscoveryService = $ocsDiscoveryService;
112
+        $this->trustedServers = $trustedServers;
113
+        $this->timeFactory = $timeFactory;
114
+    }
115 115
 
116
-	/**
117
-	 * run the job, then remove it from the joblist
118
-	 *
119
-	 * @param JobList $jobList
120
-	 * @param ILogger|null $logger
121
-	 */
122
-	public function execute($jobList, ILogger $logger = null) {
123
-		$target = $this->argument['url'];
124
-		// only execute if target is still in the list of trusted domains
125
-		if ($this->trustedServers->isTrustedServer($target)) {
126
-			$this->parentExecute($jobList, $logger);
127
-		}
116
+    /**
117
+     * run the job, then remove it from the joblist
118
+     *
119
+     * @param JobList $jobList
120
+     * @param ILogger|null $logger
121
+     */
122
+    public function execute($jobList, ILogger $logger = null) {
123
+        $target = $this->argument['url'];
124
+        // only execute if target is still in the list of trusted domains
125
+        if ($this->trustedServers->isTrustedServer($target)) {
126
+            $this->parentExecute($jobList, $logger);
127
+        }
128 128
 
129
-		$jobList->remove($this, $this->argument);
129
+        $jobList->remove($this, $this->argument);
130 130
 
131
-		if ($this->retainJob) {
132
-			$this->reAddJob($this->argument);
133
-		}
134
-	}
131
+        if ($this->retainJob) {
132
+            $this->reAddJob($this->argument);
133
+        }
134
+    }
135 135
 
136
-	/**
137
-	 * call execute() method of parent
138
-	 *
139
-	 * @param JobList $jobList
140
-	 * @param ILogger $logger
141
-	 */
142
-	protected function parentExecute($jobList, $logger = null) {
143
-		parent::execute($jobList, $logger);
144
-	}
136
+    /**
137
+     * call execute() method of parent
138
+     *
139
+     * @param JobList $jobList
140
+     * @param ILogger $logger
141
+     */
142
+    protected function parentExecute($jobList, $logger = null) {
143
+        parent::execute($jobList, $logger);
144
+    }
145 145
 
146
-	protected function run($argument) {
147
-		$target = $argument['url'];
148
-		$created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime();
149
-		$currentTime = $this->timeFactory->getTime();
150
-		$source = $this->urlGenerator->getAbsoluteURL('/');
151
-		$source = rtrim($source, '/');
152
-		$token = $argument['token'];
146
+    protected function run($argument) {
147
+        $target = $argument['url'];
148
+        $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime();
149
+        $currentTime = $this->timeFactory->getTime();
150
+        $source = $this->urlGenerator->getAbsoluteURL('/');
151
+        $source = rtrim($source, '/');
152
+        $token = $argument['token'];
153 153
 
154
-		// kill job after 30 days of trying
155
-		$deadline = $currentTime - $this->maxLifespan;
156
-		if ($created < $deadline) {
157
-			$this->retainJob = false;
158
-			$this->trustedServers->setServerStatus($target,TrustedServers::STATUS_FAILURE);
159
-			return;
160
-		}
154
+        // kill job after 30 days of trying
155
+        $deadline = $currentTime - $this->maxLifespan;
156
+        if ($created < $deadline) {
157
+            $this->retainJob = false;
158
+            $this->trustedServers->setServerStatus($target,TrustedServers::STATUS_FAILURE);
159
+            return;
160
+        }
161 161
 
162
-		$endPoints = $this->ocsDiscoveryService->discover($target, 'FEDERATED_SHARING');
163
-		$endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint;
162
+        $endPoints = $this->ocsDiscoveryService->discover($target, 'FEDERATED_SHARING');
163
+        $endPoint = isset($endPoints['shared-secret']) ? $endPoints['shared-secret'] : $this->defaultEndPoint;
164 164
 
165
-		// make sure that we have a well formatted url
166
-		$url = rtrim($target, '/') . '/' . trim($endPoint, '/');
165
+        // make sure that we have a well formatted url
166
+        $url = rtrim($target, '/') . '/' . trim($endPoint, '/');
167 167
 
168
-		$result = null;
169
-		try {
170
-			$result = $this->httpClient->get(
171
-				$url,
172
-				[
173
-					'query' =>
174
-						[
175
-							'url' => $source,
176
-							'token' => $token,
177
-							'format' => 'json',
178
-						],
179
-					'timeout' => 3,
180
-					'connect_timeout' => 3,
181
-				]
182
-			);
168
+        $result = null;
169
+        try {
170
+            $result = $this->httpClient->get(
171
+                $url,
172
+                [
173
+                    'query' =>
174
+                        [
175
+                            'url' => $source,
176
+                            'token' => $token,
177
+                            'format' => 'json',
178
+                        ],
179
+                    'timeout' => 3,
180
+                    'connect_timeout' => 3,
181
+                ]
182
+            );
183 183
 
184
-			$status = $result->getStatusCode();
184
+            $status = $result->getStatusCode();
185 185
 
186
-		} catch (ClientException $e) {
187
-			$status = $e->getCode();
188
-			if ($status === Http::STATUS_FORBIDDEN) {
189
-				$this->logger->info($target . ' refused to exchange a shared secret with you.', ['app' => 'federation']);
190
-			} else {
191
-				$this->logger->info($target . ' responded with a ' . $status . ' containing: ' . $e->getMessage(), ['app' => 'federation']);
192
-			}
193
-		} catch (RequestException $e) {
194
-			$status = -1; // There is no status code if we could not connect
195
-			$this->logger->logException($e, [
196
-				'message' => 'Could not connect to ' . $target,
197
-				'level' => ILogger::INFO,
198
-				'app' => 'federation',
199
-			]);
200
-		} catch (RingException $e) {
201
-			$status = -1; // There is no status code if we could not connect
202
-			$this->logger->logException($e, [
203
-				'message' => 'Could not connect to ' . $target,
204
-				'level' => ILogger::INFO,
205
-				'app' => 'federation',
206
-			]);
207
-		} catch (\Exception $e) {
208
-			$status = Http::STATUS_INTERNAL_SERVER_ERROR;
209
-			$this->logger->logException($e, ['app' => 'federation']);
210
-		}
186
+        } catch (ClientException $e) {
187
+            $status = $e->getCode();
188
+            if ($status === Http::STATUS_FORBIDDEN) {
189
+                $this->logger->info($target . ' refused to exchange a shared secret with you.', ['app' => 'federation']);
190
+            } else {
191
+                $this->logger->info($target . ' responded with a ' . $status . ' containing: ' . $e->getMessage(), ['app' => 'federation']);
192
+            }
193
+        } catch (RequestException $e) {
194
+            $status = -1; // There is no status code if we could not connect
195
+            $this->logger->logException($e, [
196
+                'message' => 'Could not connect to ' . $target,
197
+                'level' => ILogger::INFO,
198
+                'app' => 'federation',
199
+            ]);
200
+        } catch (RingException $e) {
201
+            $status = -1; // There is no status code if we could not connect
202
+            $this->logger->logException($e, [
203
+                'message' => 'Could not connect to ' . $target,
204
+                'level' => ILogger::INFO,
205
+                'app' => 'federation',
206
+            ]);
207
+        } catch (\Exception $e) {
208
+            $status = Http::STATUS_INTERNAL_SERVER_ERROR;
209
+            $this->logger->logException($e, ['app' => 'federation']);
210
+        }
211 211
 
212
-		// if we received a unexpected response we try again later
213
-		if (
214
-			$status !== Http::STATUS_OK
215
-			&& $status !== Http::STATUS_FORBIDDEN
216
-		) {
217
-			$this->retainJob = true;
218
-		}
212
+        // if we received a unexpected response we try again later
213
+        if (
214
+            $status !== Http::STATUS_OK
215
+            && $status !== Http::STATUS_FORBIDDEN
216
+        ) {
217
+            $this->retainJob = true;
218
+        }
219 219
 
220
-		if ($status === Http::STATUS_OK && $result instanceof IResponse) {
221
-			$body = $result->getBody();
222
-			$result = json_decode($body, true);
223
-			if (isset($result['ocs']['data']['sharedSecret'])) {
224
-				$this->trustedServers->addSharedSecret(
225
-						$target,
226
-						$result['ocs']['data']['sharedSecret']
227
-				);
228
-			} else {
229
-				$this->logger->error(
230
-						'remote server "' . $target . '"" does not return a valid shared secret. Received data: ' . $body,
231
-						['app' => 'federation']
232
-				);
233
-				$this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE);
234
-			}
235
-		}
220
+        if ($status === Http::STATUS_OK && $result instanceof IResponse) {
221
+            $body = $result->getBody();
222
+            $result = json_decode($body, true);
223
+            if (isset($result['ocs']['data']['sharedSecret'])) {
224
+                $this->trustedServers->addSharedSecret(
225
+                        $target,
226
+                        $result['ocs']['data']['sharedSecret']
227
+                );
228
+            } else {
229
+                $this->logger->error(
230
+                        'remote server "' . $target . '"" does not return a valid shared secret. Received data: ' . $body,
231
+                        ['app' => 'federation']
232
+                );
233
+                $this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE);
234
+            }
235
+        }
236 236
 
237
-	}
237
+    }
238 238
 
239
-	/**
240
-	 * re-add background job
241
-	 *
242
-	 * @param array $argument
243
-	 */
244
-	protected function reAddJob(array $argument) {
245
-		$url = $argument['url'];
246
-		$created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime();
247
-		$token = $argument['token'];
248
-		$this->jobList->add(
249
-			GetSharedSecret::class,
250
-			[
251
-				'url' => $url,
252
-				'token' => $token,
253
-				'created' => $created
254
-			]
255
-		);
256
-	}
239
+    /**
240
+     * re-add background job
241
+     *
242
+     * @param array $argument
243
+     */
244
+    protected function reAddJob(array $argument) {
245
+        $url = $argument['url'];
246
+        $created = isset($argument['created']) ? (int)$argument['created'] : $this->timeFactory->getTime();
247
+        $token = $argument['token'];
248
+        $this->jobList->add(
249
+            GetSharedSecret::class,
250
+            [
251
+                'url' => $url,
252
+                'token' => $token,
253
+                'created' => $created
254
+            ]
255
+        );
256
+    }
257 257
 }
Please login to merge, or discard this patch.
settings/Controller/LogSettingsController.php 1 patch
Indentation   +22 added lines, -22 removed lines patch added patch discarded remove patch
@@ -39,28 +39,28 @@
 block discarded – undo
39 39
  */
40 40
 class LogSettingsController extends Controller {
41 41
 
42
-	/** @var ILogger */
43
-	private $log;
42
+    /** @var ILogger */
43
+    private $log;
44 44
 
45
-	public function __construct(string $appName, IRequest $request, ILogger $logger) {
46
-		parent::__construct($appName, $request);
47
-		$this->log = $logger;
48
-	}
45
+    public function __construct(string $appName, IRequest $request, ILogger $logger) {
46
+        parent::__construct($appName, $request);
47
+        $this->log = $logger;
48
+    }
49 49
 
50
-	/**
51
-	 * download logfile
52
-	 *
53
-	 * @NoCSRFRequired
54
-	 *
55
-	 * @return StreamResponse
56
-	 */
57
-	public function download() {
58
-		if(!$this->log instanceof Log) {
59
-			throw new \UnexpectedValueException('Log file not available');
60
-		}
61
-		$resp = new StreamResponse($this->log->getLogPath());
62
-		$resp->addHeader('Content-Type', 'application/octet-stream');
63
-		$resp->addHeader('Content-Disposition', 'attachment; filename="nextcloud.log"');
64
-		return $resp;
65
-	}
50
+    /**
51
+     * download logfile
52
+     *
53
+     * @NoCSRFRequired
54
+     *
55
+     * @return StreamResponse
56
+     */
57
+    public function download() {
58
+        if(!$this->log instanceof Log) {
59
+            throw new \UnexpectedValueException('Log file not available');
60
+        }
61
+        $resp = new StreamResponse($this->log->getLogPath());
62
+        $resp->addHeader('Content-Type', 'application/octet-stream');
63
+        $resp->addHeader('Content-Disposition', 'attachment; filename="nextcloud.log"');
64
+        return $resp;
65
+    }
66 66
 }
Please login to merge, or discard this patch.
lib/private/Log/Rotate.php 1 patch
Indentation   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -33,17 +33,17 @@
 block discarded – undo
33 33
  * location and manage that with your own tools.
34 34
  */
35 35
 class Rotate extends \OC\BackgroundJob\Job {
36
-	use RotationTrait;
36
+    use RotationTrait;
37 37
 
38
-	public function run($dummy) {
39
-		$systemConfig = \OC::$server->getSystemConfig();
40
-		$this->filePath = $systemConfig->getValue('logfile', $systemConfig->getValue('datadirectory', \OC::$SERVERROOT . '/data') . '/nextcloud.log');
38
+    public function run($dummy) {
39
+        $systemConfig = \OC::$server->getSystemConfig();
40
+        $this->filePath = $systemConfig->getValue('logfile', $systemConfig->getValue('datadirectory', \OC::$SERVERROOT . '/data') . '/nextcloud.log');
41 41
 
42
-		$this->maxSize = \OC::$server->getConfig()->getSystemValue('log_rotate_size', 100 * 1024 * 1024);
43
-		if($this->shouldRotateBySize()) {
44
-			$rotatedFile = $this->rotate();
45
-			$msg = 'Log file "'.$this->filePath.'" was over '.$this->maxSize.' bytes, moved to "'.$rotatedFile.'"';
46
-			\OC::$server->getLogger()->warning($msg, ['app' => Rotate::class]);
47
-		}
48
-	}
42
+        $this->maxSize = \OC::$server->getConfig()->getSystemValue('log_rotate_size', 100 * 1024 * 1024);
43
+        if($this->shouldRotateBySize()) {
44
+            $rotatedFile = $this->rotate();
45
+            $msg = 'Log file "'.$this->filePath.'" was over '.$this->maxSize.' bytes, moved to "'.$rotatedFile.'"';
46
+            \OC::$server->getLogger()->warning($msg, ['app' => Rotate::class]);
47
+        }
48
+    }
49 49
 }
Please login to merge, or discard this patch.