Completed
Pull Request — master (#5952)
by Morris
14:58
created
lib/private/legacy/api.php 2 patches
Indentation   +459 added lines, -459 removed lines patch added patch discarded remove patch
@@ -37,463 +37,463 @@
 block discarded – undo
37 37
 
38 38
 class OC_API {
39 39
 
40
-	/**
41
-	 * API authentication levels
42
-	 */
43
-
44
-	/** @deprecated Use \OCP\API::GUEST_AUTH instead */
45
-	const GUEST_AUTH = 0;
46
-
47
-	/** @deprecated Use \OCP\API::USER_AUTH instead */
48
-	const USER_AUTH = 1;
49
-
50
-	/** @deprecated Use \OCP\API::SUBADMIN_AUTH instead */
51
-	const SUBADMIN_AUTH = 2;
52
-
53
-	/** @deprecated Use \OCP\API::ADMIN_AUTH instead */
54
-	const ADMIN_AUTH = 3;
55
-
56
-	/**
57
-	 * API Response Codes
58
-	 */
59
-
60
-	/** @deprecated Use \OCP\API::RESPOND_UNAUTHORISED instead */
61
-	const RESPOND_UNAUTHORISED = 997;
62
-
63
-	/** @deprecated Use \OCP\API::RESPOND_SERVER_ERROR instead */
64
-	const RESPOND_SERVER_ERROR = 996;
65
-
66
-	/** @deprecated Use \OCP\API::RESPOND_NOT_FOUND instead */
67
-	const RESPOND_NOT_FOUND = 998;
68
-
69
-	/** @deprecated Use \OCP\API::RESPOND_UNKNOWN_ERROR instead */
70
-	const RESPOND_UNKNOWN_ERROR = 999;
71
-
72
-	/**
73
-	 * api actions
74
-	 */
75
-	protected static $actions = array();
76
-	private static $logoutRequired = false;
77
-	private static $isLoggedIn = false;
78
-
79
-	/**
80
-	 * registers an api call
81
-	 * @param string $method the http method
82
-	 * @param string $url the url to match
83
-	 * @param callable $action the function to run
84
-	 * @param string $app the id of the app registering the call
85
-	 * @param int $authLevel the level of authentication required for the call
86
-	 * @param array $defaults
87
-	 * @param array $requirements
88
-	 */
89
-	public static function register($method, $url, $action, $app,
90
-				$authLevel = API::USER_AUTH,
91
-				$defaults = array(),
92
-				$requirements = array()) {
93
-		$name = strtolower($method).$url;
94
-		$name = str_replace(array('/', '{', '}'), '_', $name);
95
-		if(!isset(self::$actions[$name])) {
96
-			$oldCollection = OC::$server->getRouter()->getCurrentCollection();
97
-			OC::$server->getRouter()->useCollection('ocs');
98
-			OC::$server->getRouter()->create($name, $url)
99
-				->method($method)
100
-				->defaults($defaults)
101
-				->requirements($requirements)
102
-				->action('OC_API', 'call');
103
-			self::$actions[$name] = array();
104
-			OC::$server->getRouter()->useCollection($oldCollection);
105
-		}
106
-		self::$actions[$name][] = array('app' => $app, 'action' => $action, 'authlevel' => $authLevel);
107
-	}
108
-
109
-	/**
110
-	 * handles an api call
111
-	 * @param array $parameters
112
-	 */
113
-	public static function call($parameters) {
114
-		$request = \OC::$server->getRequest();
115
-		$method = $request->getMethod();
116
-
117
-		// Prepare the request variables
118
-		if($method === 'PUT') {
119
-			$parameters['_put'] = $request->getParams();
120
-		} else if($method === 'DELETE') {
121
-			$parameters['_delete'] = $request->getParams();
122
-		}
123
-		$name = $parameters['_route'];
124
-		// Foreach registered action
125
-		$responses = array();
126
-		$appManager = \OC::$server->getAppManager();
127
-		foreach(self::$actions[$name] as $action) {
128
-			// Check authentication and availability
129
-			if(!self::isAuthorised($action)) {
130
-				$responses[] = array(
131
-					'app' => $action['app'],
132
-					'response' => new OC_OCS_Result(null, API::RESPOND_UNAUTHORISED, 'Unauthorised'),
133
-					'shipped' => $appManager->isShipped($action['app']),
134
-					);
135
-				continue;
136
-			}
137
-			if(!is_callable($action['action'])) {
138
-				$responses[] = array(
139
-					'app' => $action['app'],
140
-					'response' => new OC_OCS_Result(null, API::RESPOND_NOT_FOUND, 'Api method not found'),
141
-					'shipped' => $appManager->isShipped($action['app']),
142
-					);
143
-				continue;
144
-			}
145
-			// Run the action
146
-			$responses[] = array(
147
-				'app' => $action['app'],
148
-				'response' => call_user_func($action['action'], $parameters),
149
-				'shipped' => $appManager->isShipped($action['app']),
150
-				);
151
-		}
152
-		$response = self::mergeResponses($responses);
153
-		$format = self::requestedFormat();
154
-		if (self::$logoutRequired) {
155
-			\OC::$server->getUserSession()->logout();
156
-		}
157
-
158
-		self::respond($response, $format);
159
-	}
160
-
161
-	/**
162
-	 * merge the returned result objects into one response
163
-	 * @param array $responses
164
-	 * @return OC_OCS_Result
165
-	 */
166
-	public static function mergeResponses($responses) {
167
-		// Sort into shipped and third-party
168
-		$shipped = array(
169
-			'succeeded' => array(),
170
-			'failed' => array(),
171
-			);
172
-		$thirdparty = array(
173
-			'succeeded' => array(),
174
-			'failed' => array(),
175
-			);
176
-
177
-		foreach($responses as $response) {
178
-			if($response['shipped'] || ($response['app'] === 'core')) {
179
-				if($response['response']->succeeded()) {
180
-					$shipped['succeeded'][$response['app']] = $response;
181
-				} else {
182
-					$shipped['failed'][$response['app']] = $response;
183
-				}
184
-			} else {
185
-				if($response['response']->succeeded()) {
186
-					$thirdparty['succeeded'][$response['app']] = $response;
187
-				} else {
188
-					$thirdparty['failed'][$response['app']] = $response;
189
-				}
190
-			}
191
-		}
192
-
193
-		// Remove any error responses if there is one shipped response that succeeded
194
-		if(!empty($shipped['failed'])) {
195
-			// Which shipped response do we use if they all failed?
196
-			// They may have failed for different reasons (different status codes)
197
-			// Which response code should we return?
198
-			// Maybe any that are not \OCP\API::RESPOND_SERVER_ERROR
199
-			// Merge failed responses if more than one
200
-			$data = array();
201
-			foreach($shipped['failed'] as $failure) {
202
-				$data = array_merge_recursive($data, $failure['response']->getData());
203
-			}
204
-			$picked = reset($shipped['failed']);
205
-			$code = $picked['response']->getStatusCode();
206
-			$meta = $picked['response']->getMeta();
207
-			$headers = $picked['response']->getHeaders();
208
-			$response = new OC_OCS_Result($data, $code, $meta['message'], $headers);
209
-			return $response;
210
-		} elseif(!empty($shipped['succeeded'])) {
211
-			$responses = array_merge($shipped['succeeded'], $thirdparty['succeeded']);
212
-		} elseif(!empty($thirdparty['failed'])) {
213
-			// Merge failed responses if more than one
214
-			$data = array();
215
-			foreach($thirdparty['failed'] as $failure) {
216
-				$data = array_merge_recursive($data, $failure['response']->getData());
217
-			}
218
-			$picked = reset($thirdparty['failed']);
219
-			$code = $picked['response']->getStatusCode();
220
-			$meta = $picked['response']->getMeta();
221
-			$headers = $picked['response']->getHeaders();
222
-			$response = new OC_OCS_Result($data, $code, $meta['message'], $headers);
223
-			return $response;
224
-		} else {
225
-			$responses = $thirdparty['succeeded'];
226
-		}
227
-		// Merge the successful responses
228
-		$data = [];
229
-		$codes = [];
230
-		$header = [];
231
-
232
-		foreach($responses as $response) {
233
-			if($response['shipped']) {
234
-				$data = array_merge_recursive($response['response']->getData(), $data);
235
-			} else {
236
-				$data = array_merge_recursive($data, $response['response']->getData());
237
-			}
238
-			$header = array_merge_recursive($header, $response['response']->getHeaders());
239
-			$codes[] = ['code' => $response['response']->getStatusCode(),
240
-				'meta' => $response['response']->getMeta()];
241
-		}
242
-
243
-		// Use any non 100 status codes
244
-		$statusCode = 100;
245
-		$statusMessage = null;
246
-		foreach($codes as $code) {
247
-			if($code['code'] != 100) {
248
-				$statusCode = $code['code'];
249
-				$statusMessage = $code['meta']['message'];
250
-				break;
251
-			}
252
-		}
253
-
254
-		return new OC_OCS_Result($data, $statusCode, $statusMessage, $header);
255
-	}
256
-
257
-	/**
258
-	 * authenticate the api call
259
-	 * @param array $action the action details as supplied to OC_API::register()
260
-	 * @return bool
261
-	 */
262
-	private static function isAuthorised($action) {
263
-		$level = $action['authlevel'];
264
-		switch($level) {
265
-			case API::GUEST_AUTH:
266
-				// Anyone can access
267
-				return true;
268
-			case API::USER_AUTH:
269
-				// User required
270
-				return self::loginUser();
271
-			case API::SUBADMIN_AUTH:
272
-				// Check for subadmin
273
-				$user = self::loginUser();
274
-				if(!$user) {
275
-					return false;
276
-				} else {
277
-					$userObject = \OC::$server->getUserSession()->getUser();
278
-					if($userObject === null) {
279
-						return false;
280
-					}
281
-					$isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
282
-					$admin = OC_User::isAdminUser($user);
283
-					if($isSubAdmin || $admin) {
284
-						return true;
285
-					} else {
286
-						return false;
287
-					}
288
-				}
289
-			case API::ADMIN_AUTH:
290
-				// Check for admin
291
-				$user = self::loginUser();
292
-				if(!$user) {
293
-					return false;
294
-				} else {
295
-					return OC_User::isAdminUser($user);
296
-				}
297
-			default:
298
-				// oops looks like invalid level supplied
299
-				return false;
300
-		}
301
-	}
302
-
303
-	/**
304
-	 * http basic auth
305
-	 * @return string|false (username, or false on failure)
306
-	 */
307
-	private static function loginUser() {
308
-		if(self::$isLoggedIn === true) {
309
-			return \OC_User::getUser();
310
-		}
311
-
312
-		// reuse existing login
313
-		$loggedIn = \OC::$server->getUserSession()->isLoggedIn();
314
-		if ($loggedIn === true) {
315
-			if (\OC::$server->getTwoFactorAuthManager()->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
316
-				// Do not allow access to OCS until the 2FA challenge was solved successfully
317
-				return false;
318
-			}
319
-			$ocsApiRequest = isset($_SERVER['HTTP_OCS_APIREQUEST']) ? $_SERVER['HTTP_OCS_APIREQUEST'] === 'true' : false;
320
-			if ($ocsApiRequest) {
321
-
322
-				// initialize the user's filesystem
323
-				\OC_Util::setupFS(\OC_User::getUser());
324
-				self::$isLoggedIn = true;
325
-
326
-				return OC_User::getUser();
327
-			}
328
-			return false;
329
-		}
330
-
331
-		// basic auth - because OC_User::login will create a new session we shall only try to login
332
-		// if user and pass are set
333
-		$userSession = \OC::$server->getUserSession();
334
-		$request = \OC::$server->getRequest();
335
-		try {
336
-			if ($userSession->tryTokenLogin($request)
337
-				|| $userSession->tryBasicAuthLogin($request, \OC::$server->getBruteForceThrottler())) {
338
-				self::$logoutRequired = true;
339
-			} else {
340
-				return false;
341
-			}
342
-			// initialize the user's filesystem
343
-			\OC_Util::setupFS(\OC_User::getUser());
344
-			self::$isLoggedIn = true;
345
-
346
-			return \OC_User::getUser();
347
-		} catch (\OC\User\LoginException $e) {
348
-			return false;
349
-		}
350
-	}
351
-
352
-	/**
353
-	 * respond to a call
354
-	 * @param OC_OCS_Result $result
355
-	 * @param string $format the format xml|json
356
-	 */
357
-	public static function respond($result, $format='xml') {
358
-		$request = \OC::$server->getRequest();
359
-
360
-		// Send 401 headers if unauthorised
361
-		if($result->getStatusCode() === API::RESPOND_UNAUTHORISED) {
362
-			// If request comes from JS return dummy auth request
363
-			if($request->getHeader('X-Requested-With') === 'XMLHttpRequest') {
364
-				header('WWW-Authenticate: DummyBasic realm="Authorisation Required"');
365
-			} else {
366
-				header('WWW-Authenticate: Basic realm="Authorisation Required"');
367
-			}
368
-			header('HTTP/1.0 401 Unauthorized');
369
-		}
370
-
371
-		foreach($result->getHeaders() as $name => $value) {
372
-			header($name . ': ' . $value);
373
-		}
374
-
375
-		$meta = $result->getMeta();
376
-		$data = $result->getData();
377
-		if (self::isV2($request)) {
378
-			$statusCode = self::mapStatusCodes($result->getStatusCode());
379
-			if (!is_null($statusCode)) {
380
-				$meta['statuscode'] = $statusCode;
381
-				OC_Response::setStatus($statusCode);
382
-			}
383
-		}
384
-
385
-		self::setContentType($format);
386
-		$body = self::renderResult($format, $meta, $data);
387
-		echo $body;
388
-	}
389
-
390
-	/**
391
-	 * @param XMLWriter $writer
392
-	 */
393
-	private static function toXML($array, $writer) {
394
-		foreach($array as $k => $v) {
395
-			if ($k[0] === '@') {
396
-				$writer->writeAttribute(substr($k, 1), $v);
397
-				continue;
398
-			} else if (is_numeric($k)) {
399
-				$k = 'element';
400
-			}
401
-			if(is_array($v)) {
402
-				$writer->startElement($k);
403
-				self::toXML($v, $writer);
404
-				$writer->endElement();
405
-			} else {
406
-				$writer->writeElement($k, $v);
407
-			}
408
-		}
409
-	}
410
-
411
-	/**
412
-	 * @return string
413
-	 */
414
-	public static function requestedFormat() {
415
-		$formats = array('json', 'xml');
416
-
417
-		$format = !empty($_GET['format']) && in_array($_GET['format'], $formats) ? $_GET['format'] : 'xml';
418
-		return $format;
419
-	}
420
-
421
-	/**
422
-	 * Based on the requested format the response content type is set
423
-	 * @param string $format
424
-	 */
425
-	public static function setContentType($format = null) {
426
-		$format = is_null($format) ? self::requestedFormat() : $format;
427
-		if ($format === 'xml') {
428
-			header('Content-type: text/xml; charset=UTF-8');
429
-			return;
430
-		}
431
-
432
-		if ($format === 'json') {
433
-			header('Content-Type: application/json; charset=utf-8');
434
-			return;
435
-		}
436
-
437
-		header('Content-Type: application/octet-stream; charset=utf-8');
438
-	}
439
-
440
-	/**
441
-	 * @param \OCP\IRequest $request
442
-	 * @return bool
443
-	 */
444
-	protected static function isV2(\OCP\IRequest $request) {
445
-		$script = $request->getScriptName();
446
-
447
-		return substr($script, -11) === '/ocs/v2.php';
448
-	}
449
-
450
-	/**
451
-	 * @param integer $sc
452
-	 * @return int
453
-	 */
454
-	public static function mapStatusCodes($sc) {
455
-		switch ($sc) {
456
-			case API::RESPOND_NOT_FOUND:
457
-				return Http::STATUS_NOT_FOUND;
458
-			case API::RESPOND_SERVER_ERROR:
459
-				return Http::STATUS_INTERNAL_SERVER_ERROR;
460
-			case API::RESPOND_UNKNOWN_ERROR:
461
-				return Http::STATUS_INTERNAL_SERVER_ERROR;
462
-			case API::RESPOND_UNAUTHORISED:
463
-				// already handled for v1
464
-				return null;
465
-			case 100:
466
-				return Http::STATUS_OK;
467
-		}
468
-		// any 2xx, 4xx and 5xx will be used as is
469
-		if ($sc >= 200 && $sc < 600) {
470
-			return $sc;
471
-		}
472
-
473
-		return Http::STATUS_BAD_REQUEST;
474
-	}
475
-
476
-	/**
477
-	 * @param string $format
478
-	 * @return string
479
-	 */
480
-	public static function renderResult($format, $meta, $data) {
481
-		$response = array(
482
-			'ocs' => array(
483
-				'meta' => $meta,
484
-				'data' => $data,
485
-			),
486
-		);
487
-		if ($format == 'json') {
488
-			return OC_JSON::encode($response);
489
-		}
490
-
491
-		$writer = new XMLWriter();
492
-		$writer->openMemory();
493
-		$writer->setIndent(true);
494
-		$writer->startDocument();
495
-		self::toXML($response, $writer);
496
-		$writer->endDocument();
497
-		return $writer->outputMemory(true);
498
-	}
40
+    /**
41
+     * API authentication levels
42
+     */
43
+
44
+    /** @deprecated Use \OCP\API::GUEST_AUTH instead */
45
+    const GUEST_AUTH = 0;
46
+
47
+    /** @deprecated Use \OCP\API::USER_AUTH instead */
48
+    const USER_AUTH = 1;
49
+
50
+    /** @deprecated Use \OCP\API::SUBADMIN_AUTH instead */
51
+    const SUBADMIN_AUTH = 2;
52
+
53
+    /** @deprecated Use \OCP\API::ADMIN_AUTH instead */
54
+    const ADMIN_AUTH = 3;
55
+
56
+    /**
57
+     * API Response Codes
58
+     */
59
+
60
+    /** @deprecated Use \OCP\API::RESPOND_UNAUTHORISED instead */
61
+    const RESPOND_UNAUTHORISED = 997;
62
+
63
+    /** @deprecated Use \OCP\API::RESPOND_SERVER_ERROR instead */
64
+    const RESPOND_SERVER_ERROR = 996;
65
+
66
+    /** @deprecated Use \OCP\API::RESPOND_NOT_FOUND instead */
67
+    const RESPOND_NOT_FOUND = 998;
68
+
69
+    /** @deprecated Use \OCP\API::RESPOND_UNKNOWN_ERROR instead */
70
+    const RESPOND_UNKNOWN_ERROR = 999;
71
+
72
+    /**
73
+     * api actions
74
+     */
75
+    protected static $actions = array();
76
+    private static $logoutRequired = false;
77
+    private static $isLoggedIn = false;
78
+
79
+    /**
80
+     * registers an api call
81
+     * @param string $method the http method
82
+     * @param string $url the url to match
83
+     * @param callable $action the function to run
84
+     * @param string $app the id of the app registering the call
85
+     * @param int $authLevel the level of authentication required for the call
86
+     * @param array $defaults
87
+     * @param array $requirements
88
+     */
89
+    public static function register($method, $url, $action, $app,
90
+                $authLevel = API::USER_AUTH,
91
+                $defaults = array(),
92
+                $requirements = array()) {
93
+        $name = strtolower($method).$url;
94
+        $name = str_replace(array('/', '{', '}'), '_', $name);
95
+        if(!isset(self::$actions[$name])) {
96
+            $oldCollection = OC::$server->getRouter()->getCurrentCollection();
97
+            OC::$server->getRouter()->useCollection('ocs');
98
+            OC::$server->getRouter()->create($name, $url)
99
+                ->method($method)
100
+                ->defaults($defaults)
101
+                ->requirements($requirements)
102
+                ->action('OC_API', 'call');
103
+            self::$actions[$name] = array();
104
+            OC::$server->getRouter()->useCollection($oldCollection);
105
+        }
106
+        self::$actions[$name][] = array('app' => $app, 'action' => $action, 'authlevel' => $authLevel);
107
+    }
108
+
109
+    /**
110
+     * handles an api call
111
+     * @param array $parameters
112
+     */
113
+    public static function call($parameters) {
114
+        $request = \OC::$server->getRequest();
115
+        $method = $request->getMethod();
116
+
117
+        // Prepare the request variables
118
+        if($method === 'PUT') {
119
+            $parameters['_put'] = $request->getParams();
120
+        } else if($method === 'DELETE') {
121
+            $parameters['_delete'] = $request->getParams();
122
+        }
123
+        $name = $parameters['_route'];
124
+        // Foreach registered action
125
+        $responses = array();
126
+        $appManager = \OC::$server->getAppManager();
127
+        foreach(self::$actions[$name] as $action) {
128
+            // Check authentication and availability
129
+            if(!self::isAuthorised($action)) {
130
+                $responses[] = array(
131
+                    'app' => $action['app'],
132
+                    'response' => new OC_OCS_Result(null, API::RESPOND_UNAUTHORISED, 'Unauthorised'),
133
+                    'shipped' => $appManager->isShipped($action['app']),
134
+                    );
135
+                continue;
136
+            }
137
+            if(!is_callable($action['action'])) {
138
+                $responses[] = array(
139
+                    'app' => $action['app'],
140
+                    'response' => new OC_OCS_Result(null, API::RESPOND_NOT_FOUND, 'Api method not found'),
141
+                    'shipped' => $appManager->isShipped($action['app']),
142
+                    );
143
+                continue;
144
+            }
145
+            // Run the action
146
+            $responses[] = array(
147
+                'app' => $action['app'],
148
+                'response' => call_user_func($action['action'], $parameters),
149
+                'shipped' => $appManager->isShipped($action['app']),
150
+                );
151
+        }
152
+        $response = self::mergeResponses($responses);
153
+        $format = self::requestedFormat();
154
+        if (self::$logoutRequired) {
155
+            \OC::$server->getUserSession()->logout();
156
+        }
157
+
158
+        self::respond($response, $format);
159
+    }
160
+
161
+    /**
162
+     * merge the returned result objects into one response
163
+     * @param array $responses
164
+     * @return OC_OCS_Result
165
+     */
166
+    public static function mergeResponses($responses) {
167
+        // Sort into shipped and third-party
168
+        $shipped = array(
169
+            'succeeded' => array(),
170
+            'failed' => array(),
171
+            );
172
+        $thirdparty = array(
173
+            'succeeded' => array(),
174
+            'failed' => array(),
175
+            );
176
+
177
+        foreach($responses as $response) {
178
+            if($response['shipped'] || ($response['app'] === 'core')) {
179
+                if($response['response']->succeeded()) {
180
+                    $shipped['succeeded'][$response['app']] = $response;
181
+                } else {
182
+                    $shipped['failed'][$response['app']] = $response;
183
+                }
184
+            } else {
185
+                if($response['response']->succeeded()) {
186
+                    $thirdparty['succeeded'][$response['app']] = $response;
187
+                } else {
188
+                    $thirdparty['failed'][$response['app']] = $response;
189
+                }
190
+            }
191
+        }
192
+
193
+        // Remove any error responses if there is one shipped response that succeeded
194
+        if(!empty($shipped['failed'])) {
195
+            // Which shipped response do we use if they all failed?
196
+            // They may have failed for different reasons (different status codes)
197
+            // Which response code should we return?
198
+            // Maybe any that are not \OCP\API::RESPOND_SERVER_ERROR
199
+            // Merge failed responses if more than one
200
+            $data = array();
201
+            foreach($shipped['failed'] as $failure) {
202
+                $data = array_merge_recursive($data, $failure['response']->getData());
203
+            }
204
+            $picked = reset($shipped['failed']);
205
+            $code = $picked['response']->getStatusCode();
206
+            $meta = $picked['response']->getMeta();
207
+            $headers = $picked['response']->getHeaders();
208
+            $response = new OC_OCS_Result($data, $code, $meta['message'], $headers);
209
+            return $response;
210
+        } elseif(!empty($shipped['succeeded'])) {
211
+            $responses = array_merge($shipped['succeeded'], $thirdparty['succeeded']);
212
+        } elseif(!empty($thirdparty['failed'])) {
213
+            // Merge failed responses if more than one
214
+            $data = array();
215
+            foreach($thirdparty['failed'] as $failure) {
216
+                $data = array_merge_recursive($data, $failure['response']->getData());
217
+            }
218
+            $picked = reset($thirdparty['failed']);
219
+            $code = $picked['response']->getStatusCode();
220
+            $meta = $picked['response']->getMeta();
221
+            $headers = $picked['response']->getHeaders();
222
+            $response = new OC_OCS_Result($data, $code, $meta['message'], $headers);
223
+            return $response;
224
+        } else {
225
+            $responses = $thirdparty['succeeded'];
226
+        }
227
+        // Merge the successful responses
228
+        $data = [];
229
+        $codes = [];
230
+        $header = [];
231
+
232
+        foreach($responses as $response) {
233
+            if($response['shipped']) {
234
+                $data = array_merge_recursive($response['response']->getData(), $data);
235
+            } else {
236
+                $data = array_merge_recursive($data, $response['response']->getData());
237
+            }
238
+            $header = array_merge_recursive($header, $response['response']->getHeaders());
239
+            $codes[] = ['code' => $response['response']->getStatusCode(),
240
+                'meta' => $response['response']->getMeta()];
241
+        }
242
+
243
+        // Use any non 100 status codes
244
+        $statusCode = 100;
245
+        $statusMessage = null;
246
+        foreach($codes as $code) {
247
+            if($code['code'] != 100) {
248
+                $statusCode = $code['code'];
249
+                $statusMessage = $code['meta']['message'];
250
+                break;
251
+            }
252
+        }
253
+
254
+        return new OC_OCS_Result($data, $statusCode, $statusMessage, $header);
255
+    }
256
+
257
+    /**
258
+     * authenticate the api call
259
+     * @param array $action the action details as supplied to OC_API::register()
260
+     * @return bool
261
+     */
262
+    private static function isAuthorised($action) {
263
+        $level = $action['authlevel'];
264
+        switch($level) {
265
+            case API::GUEST_AUTH:
266
+                // Anyone can access
267
+                return true;
268
+            case API::USER_AUTH:
269
+                // User required
270
+                return self::loginUser();
271
+            case API::SUBADMIN_AUTH:
272
+                // Check for subadmin
273
+                $user = self::loginUser();
274
+                if(!$user) {
275
+                    return false;
276
+                } else {
277
+                    $userObject = \OC::$server->getUserSession()->getUser();
278
+                    if($userObject === null) {
279
+                        return false;
280
+                    }
281
+                    $isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
282
+                    $admin = OC_User::isAdminUser($user);
283
+                    if($isSubAdmin || $admin) {
284
+                        return true;
285
+                    } else {
286
+                        return false;
287
+                    }
288
+                }
289
+            case API::ADMIN_AUTH:
290
+                // Check for admin
291
+                $user = self::loginUser();
292
+                if(!$user) {
293
+                    return false;
294
+                } else {
295
+                    return OC_User::isAdminUser($user);
296
+                }
297
+            default:
298
+                // oops looks like invalid level supplied
299
+                return false;
300
+        }
301
+    }
302
+
303
+    /**
304
+     * http basic auth
305
+     * @return string|false (username, or false on failure)
306
+     */
307
+    private static function loginUser() {
308
+        if(self::$isLoggedIn === true) {
309
+            return \OC_User::getUser();
310
+        }
311
+
312
+        // reuse existing login
313
+        $loggedIn = \OC::$server->getUserSession()->isLoggedIn();
314
+        if ($loggedIn === true) {
315
+            if (\OC::$server->getTwoFactorAuthManager()->needsSecondFactor(\OC::$server->getUserSession()->getUser())) {
316
+                // Do not allow access to OCS until the 2FA challenge was solved successfully
317
+                return false;
318
+            }
319
+            $ocsApiRequest = isset($_SERVER['HTTP_OCS_APIREQUEST']) ? $_SERVER['HTTP_OCS_APIREQUEST'] === 'true' : false;
320
+            if ($ocsApiRequest) {
321
+
322
+                // initialize the user's filesystem
323
+                \OC_Util::setupFS(\OC_User::getUser());
324
+                self::$isLoggedIn = true;
325
+
326
+                return OC_User::getUser();
327
+            }
328
+            return false;
329
+        }
330
+
331
+        // basic auth - because OC_User::login will create a new session we shall only try to login
332
+        // if user and pass are set
333
+        $userSession = \OC::$server->getUserSession();
334
+        $request = \OC::$server->getRequest();
335
+        try {
336
+            if ($userSession->tryTokenLogin($request)
337
+                || $userSession->tryBasicAuthLogin($request, \OC::$server->getBruteForceThrottler())) {
338
+                self::$logoutRequired = true;
339
+            } else {
340
+                return false;
341
+            }
342
+            // initialize the user's filesystem
343
+            \OC_Util::setupFS(\OC_User::getUser());
344
+            self::$isLoggedIn = true;
345
+
346
+            return \OC_User::getUser();
347
+        } catch (\OC\User\LoginException $e) {
348
+            return false;
349
+        }
350
+    }
351
+
352
+    /**
353
+     * respond to a call
354
+     * @param OC_OCS_Result $result
355
+     * @param string $format the format xml|json
356
+     */
357
+    public static function respond($result, $format='xml') {
358
+        $request = \OC::$server->getRequest();
359
+
360
+        // Send 401 headers if unauthorised
361
+        if($result->getStatusCode() === API::RESPOND_UNAUTHORISED) {
362
+            // If request comes from JS return dummy auth request
363
+            if($request->getHeader('X-Requested-With') === 'XMLHttpRequest') {
364
+                header('WWW-Authenticate: DummyBasic realm="Authorisation Required"');
365
+            } else {
366
+                header('WWW-Authenticate: Basic realm="Authorisation Required"');
367
+            }
368
+            header('HTTP/1.0 401 Unauthorized');
369
+        }
370
+
371
+        foreach($result->getHeaders() as $name => $value) {
372
+            header($name . ': ' . $value);
373
+        }
374
+
375
+        $meta = $result->getMeta();
376
+        $data = $result->getData();
377
+        if (self::isV2($request)) {
378
+            $statusCode = self::mapStatusCodes($result->getStatusCode());
379
+            if (!is_null($statusCode)) {
380
+                $meta['statuscode'] = $statusCode;
381
+                OC_Response::setStatus($statusCode);
382
+            }
383
+        }
384
+
385
+        self::setContentType($format);
386
+        $body = self::renderResult($format, $meta, $data);
387
+        echo $body;
388
+    }
389
+
390
+    /**
391
+     * @param XMLWriter $writer
392
+     */
393
+    private static function toXML($array, $writer) {
394
+        foreach($array as $k => $v) {
395
+            if ($k[0] === '@') {
396
+                $writer->writeAttribute(substr($k, 1), $v);
397
+                continue;
398
+            } else if (is_numeric($k)) {
399
+                $k = 'element';
400
+            }
401
+            if(is_array($v)) {
402
+                $writer->startElement($k);
403
+                self::toXML($v, $writer);
404
+                $writer->endElement();
405
+            } else {
406
+                $writer->writeElement($k, $v);
407
+            }
408
+        }
409
+    }
410
+
411
+    /**
412
+     * @return string
413
+     */
414
+    public static function requestedFormat() {
415
+        $formats = array('json', 'xml');
416
+
417
+        $format = !empty($_GET['format']) && in_array($_GET['format'], $formats) ? $_GET['format'] : 'xml';
418
+        return $format;
419
+    }
420
+
421
+    /**
422
+     * Based on the requested format the response content type is set
423
+     * @param string $format
424
+     */
425
+    public static function setContentType($format = null) {
426
+        $format = is_null($format) ? self::requestedFormat() : $format;
427
+        if ($format === 'xml') {
428
+            header('Content-type: text/xml; charset=UTF-8');
429
+            return;
430
+        }
431
+
432
+        if ($format === 'json') {
433
+            header('Content-Type: application/json; charset=utf-8');
434
+            return;
435
+        }
436
+
437
+        header('Content-Type: application/octet-stream; charset=utf-8');
438
+    }
439
+
440
+    /**
441
+     * @param \OCP\IRequest $request
442
+     * @return bool
443
+     */
444
+    protected static function isV2(\OCP\IRequest $request) {
445
+        $script = $request->getScriptName();
446
+
447
+        return substr($script, -11) === '/ocs/v2.php';
448
+    }
449
+
450
+    /**
451
+     * @param integer $sc
452
+     * @return int
453
+     */
454
+    public static function mapStatusCodes($sc) {
455
+        switch ($sc) {
456
+            case API::RESPOND_NOT_FOUND:
457
+                return Http::STATUS_NOT_FOUND;
458
+            case API::RESPOND_SERVER_ERROR:
459
+                return Http::STATUS_INTERNAL_SERVER_ERROR;
460
+            case API::RESPOND_UNKNOWN_ERROR:
461
+                return Http::STATUS_INTERNAL_SERVER_ERROR;
462
+            case API::RESPOND_UNAUTHORISED:
463
+                // already handled for v1
464
+                return null;
465
+            case 100:
466
+                return Http::STATUS_OK;
467
+        }
468
+        // any 2xx, 4xx and 5xx will be used as is
469
+        if ($sc >= 200 && $sc < 600) {
470
+            return $sc;
471
+        }
472
+
473
+        return Http::STATUS_BAD_REQUEST;
474
+    }
475
+
476
+    /**
477
+     * @param string $format
478
+     * @return string
479
+     */
480
+    public static function renderResult($format, $meta, $data) {
481
+        $response = array(
482
+            'ocs' => array(
483
+                'meta' => $meta,
484
+                'data' => $data,
485
+            ),
486
+        );
487
+        if ($format == 'json') {
488
+            return OC_JSON::encode($response);
489
+        }
490
+
491
+        $writer = new XMLWriter();
492
+        $writer->openMemory();
493
+        $writer->setIndent(true);
494
+        $writer->startDocument();
495
+        self::toXML($response, $writer);
496
+        $writer->endDocument();
497
+        return $writer->outputMemory(true);
498
+    }
499 499
 }
Please login to merge, or discard this patch.
Spacing   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -92,7 +92,7 @@  discard block
 block discarded – undo
92 92
 				$requirements = array()) {
93 93
 		$name = strtolower($method).$url;
94 94
 		$name = str_replace(array('/', '{', '}'), '_', $name);
95
-		if(!isset(self::$actions[$name])) {
95
+		if (!isset(self::$actions[$name])) {
96 96
 			$oldCollection = OC::$server->getRouter()->getCurrentCollection();
97 97
 			OC::$server->getRouter()->useCollection('ocs');
98 98
 			OC::$server->getRouter()->create($name, $url)
@@ -115,18 +115,18 @@  discard block
 block discarded – undo
115 115
 		$method = $request->getMethod();
116 116
 
117 117
 		// Prepare the request variables
118
-		if($method === 'PUT') {
118
+		if ($method === 'PUT') {
119 119
 			$parameters['_put'] = $request->getParams();
120
-		} else if($method === 'DELETE') {
120
+		} else if ($method === 'DELETE') {
121 121
 			$parameters['_delete'] = $request->getParams();
122 122
 		}
123 123
 		$name = $parameters['_route'];
124 124
 		// Foreach registered action
125 125
 		$responses = array();
126 126
 		$appManager = \OC::$server->getAppManager();
127
-		foreach(self::$actions[$name] as $action) {
127
+		foreach (self::$actions[$name] as $action) {
128 128
 			// Check authentication and availability
129
-			if(!self::isAuthorised($action)) {
129
+			if (!self::isAuthorised($action)) {
130 130
 				$responses[] = array(
131 131
 					'app' => $action['app'],
132 132
 					'response' => new OC_OCS_Result(null, API::RESPOND_UNAUTHORISED, 'Unauthorised'),
@@ -134,7 +134,7 @@  discard block
 block discarded – undo
134 134
 					);
135 135
 				continue;
136 136
 			}
137
-			if(!is_callable($action['action'])) {
137
+			if (!is_callable($action['action'])) {
138 138
 				$responses[] = array(
139 139
 					'app' => $action['app'],
140 140
 					'response' => new OC_OCS_Result(null, API::RESPOND_NOT_FOUND, 'Api method not found'),
@@ -174,15 +174,15 @@  discard block
 block discarded – undo
174 174
 			'failed' => array(),
175 175
 			);
176 176
 
177
-		foreach($responses as $response) {
178
-			if($response['shipped'] || ($response['app'] === 'core')) {
179
-				if($response['response']->succeeded()) {
177
+		foreach ($responses as $response) {
178
+			if ($response['shipped'] || ($response['app'] === 'core')) {
179
+				if ($response['response']->succeeded()) {
180 180
 					$shipped['succeeded'][$response['app']] = $response;
181 181
 				} else {
182 182
 					$shipped['failed'][$response['app']] = $response;
183 183
 				}
184 184
 			} else {
185
-				if($response['response']->succeeded()) {
185
+				if ($response['response']->succeeded()) {
186 186
 					$thirdparty['succeeded'][$response['app']] = $response;
187 187
 				} else {
188 188
 					$thirdparty['failed'][$response['app']] = $response;
@@ -191,14 +191,14 @@  discard block
 block discarded – undo
191 191
 		}
192 192
 
193 193
 		// Remove any error responses if there is one shipped response that succeeded
194
-		if(!empty($shipped['failed'])) {
194
+		if (!empty($shipped['failed'])) {
195 195
 			// Which shipped response do we use if they all failed?
196 196
 			// They may have failed for different reasons (different status codes)
197 197
 			// Which response code should we return?
198 198
 			// Maybe any that are not \OCP\API::RESPOND_SERVER_ERROR
199 199
 			// Merge failed responses if more than one
200 200
 			$data = array();
201
-			foreach($shipped['failed'] as $failure) {
201
+			foreach ($shipped['failed'] as $failure) {
202 202
 				$data = array_merge_recursive($data, $failure['response']->getData());
203 203
 			}
204 204
 			$picked = reset($shipped['failed']);
@@ -207,12 +207,12 @@  discard block
 block discarded – undo
207 207
 			$headers = $picked['response']->getHeaders();
208 208
 			$response = new OC_OCS_Result($data, $code, $meta['message'], $headers);
209 209
 			return $response;
210
-		} elseif(!empty($shipped['succeeded'])) {
210
+		} elseif (!empty($shipped['succeeded'])) {
211 211
 			$responses = array_merge($shipped['succeeded'], $thirdparty['succeeded']);
212
-		} elseif(!empty($thirdparty['failed'])) {
212
+		} elseif (!empty($thirdparty['failed'])) {
213 213
 			// Merge failed responses if more than one
214 214
 			$data = array();
215
-			foreach($thirdparty['failed'] as $failure) {
215
+			foreach ($thirdparty['failed'] as $failure) {
216 216
 				$data = array_merge_recursive($data, $failure['response']->getData());
217 217
 			}
218 218
 			$picked = reset($thirdparty['failed']);
@@ -229,8 +229,8 @@  discard block
 block discarded – undo
229 229
 		$codes = [];
230 230
 		$header = [];
231 231
 
232
-		foreach($responses as $response) {
233
-			if($response['shipped']) {
232
+		foreach ($responses as $response) {
233
+			if ($response['shipped']) {
234 234
 				$data = array_merge_recursive($response['response']->getData(), $data);
235 235
 			} else {
236 236
 				$data = array_merge_recursive($data, $response['response']->getData());
@@ -243,8 +243,8 @@  discard block
 block discarded – undo
243 243
 		// Use any non 100 status codes
244 244
 		$statusCode = 100;
245 245
 		$statusMessage = null;
246
-		foreach($codes as $code) {
247
-			if($code['code'] != 100) {
246
+		foreach ($codes as $code) {
247
+			if ($code['code'] != 100) {
248 248
 				$statusCode = $code['code'];
249 249
 				$statusMessage = $code['meta']['message'];
250 250
 				break;
@@ -261,7 +261,7 @@  discard block
 block discarded – undo
261 261
 	 */
262 262
 	private static function isAuthorised($action) {
263 263
 		$level = $action['authlevel'];
264
-		switch($level) {
264
+		switch ($level) {
265 265
 			case API::GUEST_AUTH:
266 266
 				// Anyone can access
267 267
 				return true;
@@ -271,16 +271,16 @@  discard block
 block discarded – undo
271 271
 			case API::SUBADMIN_AUTH:
272 272
 				// Check for subadmin
273 273
 				$user = self::loginUser();
274
-				if(!$user) {
274
+				if (!$user) {
275 275
 					return false;
276 276
 				} else {
277 277
 					$userObject = \OC::$server->getUserSession()->getUser();
278
-					if($userObject === null) {
278
+					if ($userObject === null) {
279 279
 						return false;
280 280
 					}
281 281
 					$isSubAdmin = \OC::$server->getGroupManager()->getSubAdmin()->isSubAdmin($userObject);
282 282
 					$admin = OC_User::isAdminUser($user);
283
-					if($isSubAdmin || $admin) {
283
+					if ($isSubAdmin || $admin) {
284 284
 						return true;
285 285
 					} else {
286 286
 						return false;
@@ -289,7 +289,7 @@  discard block
 block discarded – undo
289 289
 			case API::ADMIN_AUTH:
290 290
 				// Check for admin
291 291
 				$user = self::loginUser();
292
-				if(!$user) {
292
+				if (!$user) {
293 293
 					return false;
294 294
 				} else {
295 295
 					return OC_User::isAdminUser($user);
@@ -305,7 +305,7 @@  discard block
 block discarded – undo
305 305
 	 * @return string|false (username, or false on failure)
306 306
 	 */
307 307
 	private static function loginUser() {
308
-		if(self::$isLoggedIn === true) {
308
+		if (self::$isLoggedIn === true) {
309 309
 			return \OC_User::getUser();
310 310
 		}
311 311
 
@@ -354,13 +354,13 @@  discard block
 block discarded – undo
354 354
 	 * @param OC_OCS_Result $result
355 355
 	 * @param string $format the format xml|json
356 356
 	 */
357
-	public static function respond($result, $format='xml') {
357
+	public static function respond($result, $format = 'xml') {
358 358
 		$request = \OC::$server->getRequest();
359 359
 
360 360
 		// Send 401 headers if unauthorised
361
-		if($result->getStatusCode() === API::RESPOND_UNAUTHORISED) {
361
+		if ($result->getStatusCode() === API::RESPOND_UNAUTHORISED) {
362 362
 			// If request comes from JS return dummy auth request
363
-			if($request->getHeader('X-Requested-With') === 'XMLHttpRequest') {
363
+			if ($request->getHeader('X-Requested-With') === 'XMLHttpRequest') {
364 364
 				header('WWW-Authenticate: DummyBasic realm="Authorisation Required"');
365 365
 			} else {
366 366
 				header('WWW-Authenticate: Basic realm="Authorisation Required"');
@@ -368,8 +368,8 @@  discard block
 block discarded – undo
368 368
 			header('HTTP/1.0 401 Unauthorized');
369 369
 		}
370 370
 
371
-		foreach($result->getHeaders() as $name => $value) {
372
-			header($name . ': ' . $value);
371
+		foreach ($result->getHeaders() as $name => $value) {
372
+			header($name.': '.$value);
373 373
 		}
374 374
 
375 375
 		$meta = $result->getMeta();
@@ -391,14 +391,14 @@  discard block
 block discarded – undo
391 391
 	 * @param XMLWriter $writer
392 392
 	 */
393 393
 	private static function toXML($array, $writer) {
394
-		foreach($array as $k => $v) {
394
+		foreach ($array as $k => $v) {
395 395
 			if ($k[0] === '@') {
396 396
 				$writer->writeAttribute(substr($k, 1), $v);
397 397
 				continue;
398 398
 			} else if (is_numeric($k)) {
399 399
 				$k = 'element';
400 400
 			}
401
-			if(is_array($v)) {
401
+			if (is_array($v)) {
402 402
 				$writer->startElement($k);
403 403
 				self::toXML($v, $writer);
404 404
 				$writer->endElement();
Please login to merge, or discard this patch.
lib/private/legacy/app.php 2 patches
Indentation   +1180 added lines, -1180 removed lines patch added patch discarded remove patch
@@ -61,1184 +61,1184 @@
 block discarded – undo
61 61
  * upgrading and removing apps.
62 62
  */
63 63
 class OC_App {
64
-	static private $appVersion = [];
65
-	static private $adminForms = array();
66
-	static private $personalForms = array();
67
-	static private $appInfo = array();
68
-	static private $appTypes = array();
69
-	static private $loadedApps = array();
70
-	static private $altLogin = array();
71
-	static private $alreadyRegistered = [];
72
-	const officialApp = 200;
73
-
74
-	/**
75
-	 * clean the appId
76
-	 *
77
-	 * @param string|boolean $app AppId that needs to be cleaned
78
-	 * @return string
79
-	 */
80
-	public static function cleanAppId($app) {
81
-		return str_replace(array('\0', '/', '\\', '..'), '', $app);
82
-	}
83
-
84
-	/**
85
-	 * Check if an app is loaded
86
-	 *
87
-	 * @param string $app
88
-	 * @return bool
89
-	 */
90
-	public static function isAppLoaded($app) {
91
-		return in_array($app, self::$loadedApps, true);
92
-	}
93
-
94
-	/**
95
-	 * loads all apps
96
-	 *
97
-	 * @param string[] | string | null $types
98
-	 * @return bool
99
-	 *
100
-	 * This function walks through the ownCloud directory and loads all apps
101
-	 * it can find. A directory contains an app if the file /appinfo/info.xml
102
-	 * exists.
103
-	 *
104
-	 * if $types is set, only apps of those types will be loaded
105
-	 */
106
-	public static function loadApps($types = null) {
107
-		if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
108
-			return false;
109
-		}
110
-		// Load the enabled apps here
111
-		$apps = self::getEnabledApps();
112
-
113
-		// Add each apps' folder as allowed class path
114
-		foreach($apps as $app) {
115
-			$path = self::getAppPath($app);
116
-			if($path !== false) {
117
-				self::registerAutoloading($app, $path);
118
-			}
119
-		}
120
-
121
-		// prevent app.php from printing output
122
-		ob_start();
123
-		foreach ($apps as $app) {
124
-			if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
125
-				self::loadApp($app);
126
-			}
127
-		}
128
-		ob_end_clean();
129
-
130
-		return true;
131
-	}
132
-
133
-	/**
134
-	 * load a single app
135
-	 *
136
-	 * @param string $app
137
-	 */
138
-	public static function loadApp($app) {
139
-		self::$loadedApps[] = $app;
140
-		$appPath = self::getAppPath($app);
141
-		if($appPath === false) {
142
-			return;
143
-		}
144
-
145
-		// in case someone calls loadApp() directly
146
-		self::registerAutoloading($app, $appPath);
147
-
148
-		if (is_file($appPath . '/appinfo/app.php')) {
149
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
150
-			self::requireAppFile($app);
151
-			if (self::isType($app, array('authentication'))) {
152
-				// since authentication apps affect the "is app enabled for group" check,
153
-				// the enabled apps cache needs to be cleared to make sure that the
154
-				// next time getEnableApps() is called it will also include apps that were
155
-				// enabled for groups
156
-				self::$enabledAppsCache = array();
157
-			}
158
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
159
-		}
160
-
161
-		$info = self::getAppInfo($app);
162
-		if (!empty($info['activity']['filters'])) {
163
-			foreach ($info['activity']['filters'] as $filter) {
164
-				\OC::$server->getActivityManager()->registerFilter($filter);
165
-			}
166
-		}
167
-		if (!empty($info['activity']['settings'])) {
168
-			foreach ($info['activity']['settings'] as $setting) {
169
-				\OC::$server->getActivityManager()->registerSetting($setting);
170
-			}
171
-		}
172
-		if (!empty($info['activity']['providers'])) {
173
-			foreach ($info['activity']['providers'] as $provider) {
174
-				\OC::$server->getActivityManager()->registerProvider($provider);
175
-			}
176
-		}
177
-	}
178
-
179
-	/**
180
-	 * @internal
181
-	 * @param string $app
182
-	 * @param string $path
183
-	 */
184
-	public static function registerAutoloading($app, $path) {
185
-		$key = $app . '-' . $path;
186
-		if(isset(self::$alreadyRegistered[$key])) {
187
-			return;
188
-		}
189
-		self::$alreadyRegistered[$key] = true;
190
-		// Register on PSR-4 composer autoloader
191
-		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
192
-		\OC::$server->registerNamespace($app, $appNamespace);
193
-		\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
194
-		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
195
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
196
-		}
197
-
198
-		// Register on legacy autoloader
199
-		\OC::$loader->addValidRoot($path);
200
-	}
201
-
202
-	/**
203
-	 * Load app.php from the given app
204
-	 *
205
-	 * @param string $app app name
206
-	 */
207
-	private static function requireAppFile($app) {
208
-		try {
209
-			// encapsulated here to avoid variable scope conflicts
210
-			require_once $app . '/appinfo/app.php';
211
-		} catch (Error $ex) {
212
-			\OC::$server->getLogger()->logException($ex);
213
-			$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
214
-			if (!in_array($app, $blacklist)) {
215
-				self::disable($app);
216
-			}
217
-		}
218
-	}
219
-
220
-	/**
221
-	 * check if an app is of a specific type
222
-	 *
223
-	 * @param string $app
224
-	 * @param string|array $types
225
-	 * @return bool
226
-	 */
227
-	public static function isType($app, $types) {
228
-		if (is_string($types)) {
229
-			$types = array($types);
230
-		}
231
-		$appTypes = self::getAppTypes($app);
232
-		foreach ($types as $type) {
233
-			if (array_search($type, $appTypes) !== false) {
234
-				return true;
235
-			}
236
-		}
237
-		return false;
238
-	}
239
-
240
-	/**
241
-	 * get the types of an app
242
-	 *
243
-	 * @param string $app
244
-	 * @return array
245
-	 */
246
-	private static function getAppTypes($app) {
247
-		//load the cache
248
-		if (count(self::$appTypes) == 0) {
249
-			self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
250
-		}
251
-
252
-		if (isset(self::$appTypes[$app])) {
253
-			return explode(',', self::$appTypes[$app]);
254
-		} else {
255
-			return array();
256
-		}
257
-	}
258
-
259
-	/**
260
-	 * read app types from info.xml and cache them in the database
261
-	 */
262
-	public static function setAppTypes($app) {
263
-		$appData = self::getAppInfo($app);
264
-		if(!is_array($appData)) {
265
-			return;
266
-		}
267
-
268
-		if (isset($appData['types'])) {
269
-			$appTypes = implode(',', $appData['types']);
270
-		} else {
271
-			$appTypes = '';
272
-			$appData['types'] = [];
273
-		}
274
-
275
-		\OC::$server->getAppConfig()->setValue($app, 'types', $appTypes);
276
-
277
-		if (\OC::$server->getAppManager()->hasProtectedAppType($appData['types'])) {
278
-			$enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'yes');
279
-			if ($enabled !== 'yes' && $enabled !== 'no') {
280
-				\OC::$server->getAppConfig()->setValue($app, 'enabled', 'yes');
281
-			}
282
-		}
283
-	}
284
-
285
-	/**
286
-	 * get all enabled apps
287
-	 */
288
-	protected static $enabledAppsCache = array();
289
-
290
-	/**
291
-	 * Returns apps enabled for the current user.
292
-	 *
293
-	 * @param bool $forceRefresh whether to refresh the cache
294
-	 * @param bool $all whether to return apps for all users, not only the
295
-	 * currently logged in one
296
-	 * @return string[]
297
-	 */
298
-	public static function getEnabledApps($forceRefresh = false, $all = false) {
299
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
300
-			return array();
301
-		}
302
-		// in incognito mode or when logged out, $user will be false,
303
-		// which is also the case during an upgrade
304
-		$appManager = \OC::$server->getAppManager();
305
-		if ($all) {
306
-			$user = null;
307
-		} else {
308
-			$user = \OC::$server->getUserSession()->getUser();
309
-		}
310
-
311
-		if (is_null($user)) {
312
-			$apps = $appManager->getInstalledApps();
313
-		} else {
314
-			$apps = $appManager->getEnabledAppsForUser($user);
315
-		}
316
-		$apps = array_filter($apps, function ($app) {
317
-			return $app !== 'files';//we add this manually
318
-		});
319
-		sort($apps);
320
-		array_unshift($apps, 'files');
321
-		return $apps;
322
-	}
323
-
324
-	/**
325
-	 * checks whether or not an app is enabled
326
-	 *
327
-	 * @param string $app app
328
-	 * @return bool
329
-	 *
330
-	 * This function checks whether or not an app is enabled.
331
-	 */
332
-	public static function isEnabled($app) {
333
-		return \OC::$server->getAppManager()->isEnabledForUser($app);
334
-	}
335
-
336
-	/**
337
-	 * enables an app
338
-	 *
339
-	 * @param string $appId
340
-	 * @param array $groups (optional) when set, only these groups will have access to the app
341
-	 * @throws \Exception
342
-	 * @return void
343
-	 *
344
-	 * This function set an app as enabled in appconfig.
345
-	 */
346
-	public function enable($appId,
347
-						   $groups = null) {
348
-		self::$enabledAppsCache = []; // flush
349
-
350
-		// Check if app is already downloaded
351
-		$installer = new Installer(
352
-			\OC::$server->getAppFetcher(),
353
-			\OC::$server->getHTTPClientService(),
354
-			\OC::$server->getTempManager(),
355
-			\OC::$server->getLogger(),
356
-			\OC::$server->getConfig()
357
-		);
358
-		$isDownloaded = $installer->isDownloaded($appId);
359
-
360
-		if(!$isDownloaded) {
361
-			$installer->downloadApp($appId);
362
-		}
363
-
364
-		$installer->installApp($appId);
365
-
366
-		$appManager = \OC::$server->getAppManager();
367
-		if (!is_null($groups)) {
368
-			$groupManager = \OC::$server->getGroupManager();
369
-			$groupsList = [];
370
-			foreach ($groups as $group) {
371
-				$groupItem = $groupManager->get($group);
372
-				if ($groupItem instanceof \OCP\IGroup) {
373
-					$groupsList[] = $groupManager->get($group);
374
-				}
375
-			}
376
-			$appManager->enableAppForGroups($appId, $groupsList);
377
-		} else {
378
-			$appManager->enableApp($appId);
379
-		}
380
-	}
381
-
382
-	/**
383
-	 * @param string $app
384
-	 * @return bool
385
-	 */
386
-	public static function removeApp($app) {
387
-		if (\OC::$server->getAppManager()->isShipped($app)) {
388
-			return false;
389
-		}
390
-
391
-		$installer = new Installer(
392
-			\OC::$server->getAppFetcher(),
393
-			\OC::$server->getHTTPClientService(),
394
-			\OC::$server->getTempManager(),
395
-			\OC::$server->getLogger(),
396
-			\OC::$server->getConfig()
397
-		);
398
-		return $installer->removeApp($app);
399
-	}
400
-
401
-	/**
402
-	 * This function set an app as disabled in appconfig.
403
-	 *
404
-	 * @param string $app app
405
-	 * @throws Exception
406
-	 */
407
-	public static function disable($app) {
408
-		// flush
409
-		self::$enabledAppsCache = array();
410
-
411
-		// run uninstall steps
412
-		$appData = OC_App::getAppInfo($app);
413
-		if (!is_null($appData)) {
414
-			OC_App::executeRepairSteps($app, $appData['repair-steps']['uninstall']);
415
-		}
416
-
417
-		// emit disable hook - needed anymore ?
418
-		\OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
419
-
420
-		// finally disable it
421
-		$appManager = \OC::$server->getAppManager();
422
-		$appManager->disableApp($app);
423
-	}
424
-
425
-	// This is private as well. It simply works, so don't ask for more details
426
-	private static function proceedNavigation($list) {
427
-		usort($list, function($a, $b) {
428
-			if (isset($a['order']) && isset($b['order'])) {
429
-				return ($a['order'] < $b['order']) ? -1 : 1;
430
-			} else if (isset($a['order']) || isset($b['order'])) {
431
-				return isset($a['order']) ? -1 : 1;
432
-			} else {
433
-				return ($a['name'] < $b['name']) ? -1 : 1;
434
-			}
435
-		});
436
-
437
-		$activeApp = OC::$server->getNavigationManager()->getActiveEntry();
438
-		foreach ($list as $index => &$navEntry) {
439
-			if ($navEntry['id'] == $activeApp) {
440
-				$navEntry['active'] = true;
441
-			} else {
442
-				$navEntry['active'] = false;
443
-			}
444
-		}
445
-		unset($navEntry);
446
-
447
-		return $list;
448
-	}
449
-
450
-	/**
451
-	 * Get the path where to install apps
452
-	 *
453
-	 * @return string|false
454
-	 */
455
-	public static function getInstallPath() {
456
-		if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
457
-			return false;
458
-		}
459
-
460
-		foreach (OC::$APPSROOTS as $dir) {
461
-			if (isset($dir['writable']) && $dir['writable'] === true) {
462
-				return $dir['path'];
463
-			}
464
-		}
465
-
466
-		\OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
467
-		return null;
468
-	}
469
-
470
-
471
-	/**
472
-	 * search for an app in all app-directories
473
-	 *
474
-	 * @param string $appId
475
-	 * @return false|string
476
-	 */
477
-	public static function findAppInDirectories($appId) {
478
-		$sanitizedAppId = self::cleanAppId($appId);
479
-		if($sanitizedAppId !== $appId) {
480
-			return false;
481
-		}
482
-		static $app_dir = array();
483
-
484
-		if (isset($app_dir[$appId])) {
485
-			return $app_dir[$appId];
486
-		}
487
-
488
-		$possibleApps = array();
489
-		foreach (OC::$APPSROOTS as $dir) {
490
-			if (file_exists($dir['path'] . '/' . $appId)) {
491
-				$possibleApps[] = $dir;
492
-			}
493
-		}
494
-
495
-		if (empty($possibleApps)) {
496
-			return false;
497
-		} elseif (count($possibleApps) === 1) {
498
-			$dir = array_shift($possibleApps);
499
-			$app_dir[$appId] = $dir;
500
-			return $dir;
501
-		} else {
502
-			$versionToLoad = array();
503
-			foreach ($possibleApps as $possibleApp) {
504
-				$version = self::getAppVersionByPath($possibleApp['path']);
505
-				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
506
-					$versionToLoad = array(
507
-						'dir' => $possibleApp,
508
-						'version' => $version,
509
-					);
510
-				}
511
-			}
512
-			$app_dir[$appId] = $versionToLoad['dir'];
513
-			return $versionToLoad['dir'];
514
-			//TODO - write test
515
-		}
516
-	}
517
-
518
-	/**
519
-	 * Get the directory for the given app.
520
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
521
-	 *
522
-	 * @param string $appId
523
-	 * @return string|false
524
-	 */
525
-	public static function getAppPath($appId) {
526
-		if ($appId === null || trim($appId) === '') {
527
-			return false;
528
-		}
529
-
530
-		if (($dir = self::findAppInDirectories($appId)) != false) {
531
-			return $dir['path'] . '/' . $appId;
532
-		}
533
-		return false;
534
-	}
535
-
536
-	/**
537
-	 * Get the path for the given app on the access
538
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
539
-	 *
540
-	 * @param string $appId
541
-	 * @return string|false
542
-	 */
543
-	public static function getAppWebPath($appId) {
544
-		if (($dir = self::findAppInDirectories($appId)) != false) {
545
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
546
-		}
547
-		return false;
548
-	}
549
-
550
-	/**
551
-	 * get the last version of the app from appinfo/info.xml
552
-	 *
553
-	 * @param string $appId
554
-	 * @param bool $useCache
555
-	 * @return string
556
-	 */
557
-	public static function getAppVersion($appId, $useCache = true) {
558
-		if($useCache && isset(self::$appVersion[$appId])) {
559
-			return self::$appVersion[$appId];
560
-		}
561
-
562
-		$file = self::getAppPath($appId);
563
-		self::$appVersion[$appId] = ($file !== false) ? self::getAppVersionByPath($file) : '0';
564
-		return self::$appVersion[$appId];
565
-	}
566
-
567
-	/**
568
-	 * get app's version based on it's path
569
-	 *
570
-	 * @param string $path
571
-	 * @return string
572
-	 */
573
-	public static function getAppVersionByPath($path) {
574
-		$infoFile = $path . '/appinfo/info.xml';
575
-		$appData = self::getAppInfo($infoFile, true);
576
-		return isset($appData['version']) ? $appData['version'] : '';
577
-	}
578
-
579
-
580
-	/**
581
-	 * Read all app metadata from the info.xml file
582
-	 *
583
-	 * @param string $appId id of the app or the path of the info.xml file
584
-	 * @param bool $path
585
-	 * @param string $lang
586
-	 * @return array|null
587
-	 * @note all data is read from info.xml, not just pre-defined fields
588
-	 */
589
-	public static function getAppInfo($appId, $path = false, $lang = null) {
590
-		if ($path) {
591
-			$file = $appId;
592
-		} else {
593
-			if ($lang === null && isset(self::$appInfo[$appId])) {
594
-				return self::$appInfo[$appId];
595
-			}
596
-			$appPath = self::getAppPath($appId);
597
-			if($appPath === false) {
598
-				return null;
599
-			}
600
-			$file = $appPath . '/appinfo/info.xml';
601
-		}
602
-
603
-		$parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
604
-		$data = $parser->parse($file);
605
-
606
-		if (is_array($data)) {
607
-			$data = OC_App::parseAppInfo($data, $lang);
608
-		}
609
-		if(isset($data['ocsid'])) {
610
-			$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
611
-			if($storedId !== '' && $storedId !== $data['ocsid']) {
612
-				$data['ocsid'] = $storedId;
613
-			}
614
-		}
615
-
616
-		if ($lang === null) {
617
-			self::$appInfo[$appId] = $data;
618
-		}
619
-
620
-		return $data;
621
-	}
622
-
623
-	/**
624
-	 * Returns the navigation
625
-	 *
626
-	 * @return array
627
-	 *
628
-	 * This function returns an array containing all entries added. The
629
-	 * entries are sorted by the key 'order' ascending. Additional to the keys
630
-	 * given for each app the following keys exist:
631
-	 *   - active: boolean, signals if the user is on this navigation entry
632
-	 */
633
-	public static function getNavigation() {
634
-		$entries = OC::$server->getNavigationManager()->getAll();
635
-		return self::proceedNavigation($entries);
636
-	}
637
-
638
-	/**
639
-	 * Returns the Settings Navigation
640
-	 *
641
-	 * @return string[]
642
-	 *
643
-	 * This function returns an array containing all settings pages added. The
644
-	 * entries are sorted by the key 'order' ascending.
645
-	 */
646
-	public static function getSettingsNavigation() {
647
-		$entries = OC::$server->getNavigationManager()->getAll('settings');
648
-		return self::proceedNavigation($entries);
649
-	}
650
-
651
-	/**
652
-	 * get the id of loaded app
653
-	 *
654
-	 * @return string
655
-	 */
656
-	public static function getCurrentApp() {
657
-		$request = \OC::$server->getRequest();
658
-		$script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
659
-		$topFolder = substr($script, 0, strpos($script, '/'));
660
-		if (empty($topFolder)) {
661
-			$path_info = $request->getPathInfo();
662
-			if ($path_info) {
663
-				$topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
664
-			}
665
-		}
666
-		if ($topFolder == 'apps') {
667
-			$length = strlen($topFolder);
668
-			return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
669
-		} else {
670
-			return $topFolder;
671
-		}
672
-	}
673
-
674
-	/**
675
-	 * @param string $type
676
-	 * @return array
677
-	 */
678
-	public static function getForms($type) {
679
-		$forms = array();
680
-		switch ($type) {
681
-			case 'admin':
682
-				$source = self::$adminForms;
683
-				break;
684
-			case 'personal':
685
-				$source = self::$personalForms;
686
-				break;
687
-			default:
688
-				return array();
689
-		}
690
-		foreach ($source as $form) {
691
-			$forms[] = include $form;
692
-		}
693
-		return $forms;
694
-	}
695
-
696
-	/**
697
-	 * register an admin form to be shown
698
-	 *
699
-	 * @param string $app
700
-	 * @param string $page
701
-	 */
702
-	public static function registerAdmin($app, $page) {
703
-		self::$adminForms[] = $app . '/' . $page . '.php';
704
-	}
705
-
706
-	/**
707
-	 * register a personal form to be shown
708
-	 * @param string $app
709
-	 * @param string $page
710
-	 */
711
-	public static function registerPersonal($app, $page) {
712
-		self::$personalForms[] = $app . '/' . $page . '.php';
713
-	}
714
-
715
-	/**
716
-	 * @param array $entry
717
-	 */
718
-	public static function registerLogIn(array $entry) {
719
-		self::$altLogin[] = $entry;
720
-	}
721
-
722
-	/**
723
-	 * @return array
724
-	 */
725
-	public static function getAlternativeLogIns() {
726
-		return self::$altLogin;
727
-	}
728
-
729
-	/**
730
-	 * get a list of all apps in the apps folder
731
-	 *
732
-	 * @return array an array of app names (string IDs)
733
-	 * @todo: change the name of this method to getInstalledApps, which is more accurate
734
-	 */
735
-	public static function getAllApps() {
736
-
737
-		$apps = array();
738
-
739
-		foreach (OC::$APPSROOTS as $apps_dir) {
740
-			if (!is_readable($apps_dir['path'])) {
741
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
742
-				continue;
743
-			}
744
-			$dh = opendir($apps_dir['path']);
745
-
746
-			if (is_resource($dh)) {
747
-				while (($file = readdir($dh)) !== false) {
748
-
749
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
750
-
751
-						$apps[] = $file;
752
-					}
753
-				}
754
-			}
755
-		}
756
-
757
-		return $apps;
758
-	}
759
-
760
-	/**
761
-	 * List all apps, this is used in apps.php
762
-	 *
763
-	 * @return array
764
-	 */
765
-	public function listAllApps() {
766
-		$installedApps = OC_App::getAllApps();
767
-
768
-		$appManager = \OC::$server->getAppManager();
769
-		//we don't want to show configuration for these
770
-		$blacklist = $appManager->getAlwaysEnabledApps();
771
-		$appList = array();
772
-		$langCode = \OC::$server->getL10N('core')->getLanguageCode();
773
-		$urlGenerator = \OC::$server->getURLGenerator();
774
-
775
-		foreach ($installedApps as $app) {
776
-			if (array_search($app, $blacklist) === false) {
777
-
778
-				$info = OC_App::getAppInfo($app, false, $langCode);
779
-				if (!is_array($info)) {
780
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
781
-					continue;
782
-				}
783
-
784
-				if (!isset($info['name'])) {
785
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
786
-					continue;
787
-				}
788
-
789
-				$enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'no');
790
-				$info['groups'] = null;
791
-				if ($enabled === 'yes') {
792
-					$active = true;
793
-				} else if ($enabled === 'no') {
794
-					$active = false;
795
-				} else {
796
-					$active = true;
797
-					$info['groups'] = $enabled;
798
-				}
799
-
800
-				$info['active'] = $active;
801
-
802
-				if ($appManager->isShipped($app)) {
803
-					$info['internal'] = true;
804
-					$info['level'] = self::officialApp;
805
-					$info['removable'] = false;
806
-				} else {
807
-					$info['internal'] = false;
808
-					$info['removable'] = true;
809
-				}
810
-
811
-				$appPath = self::getAppPath($app);
812
-				if($appPath !== false) {
813
-					$appIcon = $appPath . '/img/' . $app . '.svg';
814
-					if (file_exists($appIcon)) {
815
-						$info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
816
-						$info['previewAsIcon'] = true;
817
-					} else {
818
-						$appIcon = $appPath . '/img/app.svg';
819
-						if (file_exists($appIcon)) {
820
-							$info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
821
-							$info['previewAsIcon'] = true;
822
-						}
823
-					}
824
-				}
825
-				// fix documentation
826
-				if (isset($info['documentation']) && is_array($info['documentation'])) {
827
-					foreach ($info['documentation'] as $key => $url) {
828
-						// If it is not an absolute URL we assume it is a key
829
-						// i.e. admin-ldap will get converted to go.php?to=admin-ldap
830
-						if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
831
-							$url = $urlGenerator->linkToDocs($url);
832
-						}
833
-
834
-						$info['documentation'][$key] = $url;
835
-					}
836
-				}
837
-
838
-				$info['version'] = OC_App::getAppVersion($app);
839
-				$appList[] = $info;
840
-			}
841
-		}
842
-
843
-		return $appList;
844
-	}
845
-
846
-	/**
847
-	 * Returns the internal app ID or false
848
-	 * @param string $ocsID
849
-	 * @return string|false
850
-	 */
851
-	public static function getInternalAppIdByOcs($ocsID) {
852
-		if(is_numeric($ocsID)) {
853
-			$idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
854
-			if(array_search($ocsID, $idArray)) {
855
-				return array_search($ocsID, $idArray);
856
-			}
857
-		}
858
-		return false;
859
-	}
860
-
861
-	public static function shouldUpgrade($app) {
862
-		$versions = self::getAppVersions();
863
-		$currentVersion = OC_App::getAppVersion($app);
864
-		if ($currentVersion && isset($versions[$app])) {
865
-			$installedVersion = $versions[$app];
866
-			if (!version_compare($currentVersion, $installedVersion, '=')) {
867
-				return true;
868
-			}
869
-		}
870
-		return false;
871
-	}
872
-
873
-	/**
874
-	 * Adjust the number of version parts of $version1 to match
875
-	 * the number of version parts of $version2.
876
-	 *
877
-	 * @param string $version1 version to adjust
878
-	 * @param string $version2 version to take the number of parts from
879
-	 * @return string shortened $version1
880
-	 */
881
-	private static function adjustVersionParts($version1, $version2) {
882
-		$version1 = explode('.', $version1);
883
-		$version2 = explode('.', $version2);
884
-		// reduce $version1 to match the number of parts in $version2
885
-		while (count($version1) > count($version2)) {
886
-			array_pop($version1);
887
-		}
888
-		// if $version1 does not have enough parts, add some
889
-		while (count($version1) < count($version2)) {
890
-			$version1[] = '0';
891
-		}
892
-		return implode('.', $version1);
893
-	}
894
-
895
-	/**
896
-	 * Check whether the current ownCloud version matches the given
897
-	 * application's version requirements.
898
-	 *
899
-	 * The comparison is made based on the number of parts that the
900
-	 * app info version has. For example for ownCloud 6.0.3 if the
901
-	 * app info version is expecting version 6.0, the comparison is
902
-	 * made on the first two parts of the ownCloud version.
903
-	 * This means that it's possible to specify "requiremin" => 6
904
-	 * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
905
-	 *
906
-	 * @param string $ocVersion ownCloud version to check against
907
-	 * @param array $appInfo app info (from xml)
908
-	 *
909
-	 * @return boolean true if compatible, otherwise false
910
-	 */
911
-	public static function isAppCompatible($ocVersion, $appInfo) {
912
-		$requireMin = '';
913
-		$requireMax = '';
914
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
915
-			$requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
916
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
917
-			$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
918
-		} else if (isset($appInfo['requiremin'])) {
919
-			$requireMin = $appInfo['requiremin'];
920
-		} else if (isset($appInfo['require'])) {
921
-			$requireMin = $appInfo['require'];
922
-		}
923
-
924
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
925
-			$requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
926
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
927
-			$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
928
-		} else if (isset($appInfo['requiremax'])) {
929
-			$requireMax = $appInfo['requiremax'];
930
-		}
931
-
932
-		if (is_array($ocVersion)) {
933
-			$ocVersion = implode('.', $ocVersion);
934
-		}
935
-
936
-		if (!empty($requireMin)
937
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
938
-		) {
939
-
940
-			return false;
941
-		}
942
-
943
-		if (!empty($requireMax)
944
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
945
-		) {
946
-			return false;
947
-		}
948
-
949
-		return true;
950
-	}
951
-
952
-	/**
953
-	 * get the installed version of all apps
954
-	 */
955
-	public static function getAppVersions() {
956
-		static $versions;
957
-
958
-		if(!$versions) {
959
-			$appConfig = \OC::$server->getAppConfig();
960
-			$versions = $appConfig->getValues(false, 'installed_version');
961
-		}
962
-		return $versions;
963
-	}
964
-
965
-	/**
966
-	 * @param string $app
967
-	 * @param \OCP\IConfig $config
968
-	 * @param \OCP\IL10N $l
969
-	 * @return bool
970
-	 *
971
-	 * @throws Exception if app is not compatible with this version of ownCloud
972
-	 * @throws Exception if no app-name was specified
973
-	 */
974
-	public function installApp($app,
975
-							   \OCP\IConfig $config,
976
-							   \OCP\IL10N $l) {
977
-		if ($app !== false) {
978
-			// check if the app is compatible with this version of ownCloud
979
-			$info = self::getAppInfo($app);
980
-			if(!is_array($info)) {
981
-				throw new \Exception(
982
-					$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
983
-						[$info['name']]
984
-					)
985
-				);
986
-			}
987
-
988
-			$version = \OCP\Util::getVersion();
989
-			if (!self::isAppCompatible($version, $info)) {
990
-				throw new \Exception(
991
-					$l->t('App "%s" cannot be installed because it is not compatible with this version of the server.',
992
-						array($info['name'])
993
-					)
994
-				);
995
-			}
996
-
997
-			// check for required dependencies
998
-			self::checkAppDependencies($config, $l, $info);
999
-
1000
-			$config->setAppValue($app, 'enabled', 'yes');
1001
-			if (isset($appData['id'])) {
1002
-				$config->setAppValue($app, 'ocsid', $appData['id']);
1003
-			}
1004
-
1005
-			if(isset($info['settings']) && is_array($info['settings'])) {
1006
-				$appPath = self::getAppPath($app);
1007
-				self::registerAutoloading($app, $appPath);
1008
-				\OC::$server->getSettingsManager()->setupSettings($info['settings']);
1009
-			}
1010
-
1011
-			\OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1012
-		} else {
1013
-			if(empty($appName) ) {
1014
-				throw new \Exception($l->t("No app name specified"));
1015
-			} else {
1016
-				throw new \Exception($l->t("App '%s' could not be installed!", $appName));
1017
-			}
1018
-		}
1019
-
1020
-		return $app;
1021
-	}
1022
-
1023
-	/**
1024
-	 * update the database for the app and call the update script
1025
-	 *
1026
-	 * @param string $appId
1027
-	 * @return bool
1028
-	 */
1029
-	public static function updateApp($appId) {
1030
-		$appPath = self::getAppPath($appId);
1031
-		if($appPath === false) {
1032
-			return false;
1033
-		}
1034
-		self::registerAutoloading($appId, $appPath);
1035
-
1036
-		$appData = self::getAppInfo($appId);
1037
-		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1038
-
1039
-		if (file_exists($appPath . '/appinfo/database.xml')) {
1040
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1041
-		} else {
1042
-			$ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
1043
-			$ms->migrate();
1044
-		}
1045
-
1046
-		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1047
-		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1048
-		unset(self::$appVersion[$appId]);
1049
-
1050
-		// run upgrade code
1051
-		if (file_exists($appPath . '/appinfo/update.php')) {
1052
-			self::loadApp($appId);
1053
-			include $appPath . '/appinfo/update.php';
1054
-		}
1055
-		self::setupBackgroundJobs($appData['background-jobs']);
1056
-		if(isset($appData['settings']) && is_array($appData['settings'])) {
1057
-			\OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1058
-		}
1059
-
1060
-		//set remote/public handlers
1061
-		if (array_key_exists('ocsid', $appData)) {
1062
-			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1063
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1064
-			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1065
-		}
1066
-		foreach ($appData['remote'] as $name => $path) {
1067
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1068
-		}
1069
-		foreach ($appData['public'] as $name => $path) {
1070
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1071
-		}
1072
-
1073
-		self::setAppTypes($appId);
1074
-
1075
-		$version = \OC_App::getAppVersion($appId);
1076
-		\OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
1077
-
1078
-		\OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
1079
-			ManagerEvent::EVENT_APP_UPDATE, $appId
1080
-		));
1081
-
1082
-		return true;
1083
-	}
1084
-
1085
-	/**
1086
-	 * @param string $appId
1087
-	 * @param string[] $steps
1088
-	 * @throws \OC\NeedsUpdateException
1089
-	 */
1090
-	public static function executeRepairSteps($appId, array $steps) {
1091
-		if (empty($steps)) {
1092
-			return;
1093
-		}
1094
-		// load the app
1095
-		self::loadApp($appId);
1096
-
1097
-		$dispatcher = OC::$server->getEventDispatcher();
1098
-
1099
-		// load the steps
1100
-		$r = new Repair([], $dispatcher);
1101
-		foreach ($steps as $step) {
1102
-			try {
1103
-				$r->addStep($step);
1104
-			} catch (Exception $ex) {
1105
-				$r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1106
-				\OC::$server->getLogger()->logException($ex);
1107
-			}
1108
-		}
1109
-		// run the steps
1110
-		$r->run();
1111
-	}
1112
-
1113
-	public static function setupBackgroundJobs(array $jobs) {
1114
-		$queue = \OC::$server->getJobList();
1115
-		foreach ($jobs as $job) {
1116
-			$queue->add($job);
1117
-		}
1118
-	}
1119
-
1120
-	/**
1121
-	 * @param string $appId
1122
-	 * @param string[] $steps
1123
-	 */
1124
-	private static function setupLiveMigrations($appId, array $steps) {
1125
-		$queue = \OC::$server->getJobList();
1126
-		foreach ($steps as $step) {
1127
-			$queue->add('OC\Migration\BackgroundRepair', [
1128
-				'app' => $appId,
1129
-				'step' => $step]);
1130
-		}
1131
-	}
1132
-
1133
-	/**
1134
-	 * @param string $appId
1135
-	 * @return \OC\Files\View|false
1136
-	 */
1137
-	public static function getStorage($appId) {
1138
-		if (OC_App::isEnabled($appId)) { //sanity check
1139
-			if (\OC::$server->getUserSession()->isLoggedIn()) {
1140
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1141
-				if (!$view->file_exists($appId)) {
1142
-					$view->mkdir($appId);
1143
-				}
1144
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1145
-			} else {
1146
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1147
-				return false;
1148
-			}
1149
-		} else {
1150
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1151
-			return false;
1152
-		}
1153
-	}
1154
-
1155
-	protected static function findBestL10NOption($options, $lang) {
1156
-		$fallback = $similarLangFallback = $englishFallback = false;
1157
-
1158
-		$lang = strtolower($lang);
1159
-		$similarLang = $lang;
1160
-		if (strpos($similarLang, '_')) {
1161
-			// For "de_DE" we want to find "de" and the other way around
1162
-			$similarLang = substr($lang, 0, strpos($lang, '_'));
1163
-		}
1164
-
1165
-		foreach ($options as $option) {
1166
-			if (is_array($option)) {
1167
-				if ($fallback === false) {
1168
-					$fallback = $option['@value'];
1169
-				}
1170
-
1171
-				if (!isset($option['@attributes']['lang'])) {
1172
-					continue;
1173
-				}
1174
-
1175
-				$attributeLang = strtolower($option['@attributes']['lang']);
1176
-				if ($attributeLang === $lang) {
1177
-					return $option['@value'];
1178
-				}
1179
-
1180
-				if ($attributeLang === $similarLang) {
1181
-					$similarLangFallback = $option['@value'];
1182
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1183
-					if ($similarLangFallback === false) {
1184
-						$similarLangFallback =  $option['@value'];
1185
-					}
1186
-				}
1187
-			} else {
1188
-				$englishFallback = $option;
1189
-			}
1190
-		}
1191
-
1192
-		if ($similarLangFallback !== false) {
1193
-			return $similarLangFallback;
1194
-		} else if ($englishFallback !== false) {
1195
-			return $englishFallback;
1196
-		}
1197
-		return (string) $fallback;
1198
-	}
1199
-
1200
-	/**
1201
-	 * parses the app data array and enhanced the 'description' value
1202
-	 *
1203
-	 * @param array $data the app data
1204
-	 * @param string $lang
1205
-	 * @return array improved app data
1206
-	 */
1207
-	public static function parseAppInfo(array $data, $lang = null) {
1208
-
1209
-		if ($lang && isset($data['name']) && is_array($data['name'])) {
1210
-			$data['name'] = self::findBestL10NOption($data['name'], $lang);
1211
-		}
1212
-		if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1213
-			$data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1214
-		}
1215
-		if ($lang && isset($data['description']) && is_array($data['description'])) {
1216
-			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1217
-		} else if (isset($data['description']) && is_string($data['description'])) {
1218
-			$data['description'] = trim($data['description']);
1219
-		} else  {
1220
-			$data['description'] = '';
1221
-		}
1222
-
1223
-		return $data;
1224
-	}
1225
-
1226
-	/**
1227
-	 * @param \OCP\IConfig $config
1228
-	 * @param \OCP\IL10N $l
1229
-	 * @param array $info
1230
-	 * @throws \Exception
1231
-	 */
1232
-	public static function checkAppDependencies($config, $l, $info) {
1233
-		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1234
-		$missing = $dependencyAnalyzer->analyze($info);
1235
-		if (!empty($missing)) {
1236
-			$missingMsg = implode(PHP_EOL, $missing);
1237
-			throw new \Exception(
1238
-				$l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1239
-					[$info['name'], $missingMsg]
1240
-				)
1241
-			);
1242
-		}
1243
-	}
64
+    static private $appVersion = [];
65
+    static private $adminForms = array();
66
+    static private $personalForms = array();
67
+    static private $appInfo = array();
68
+    static private $appTypes = array();
69
+    static private $loadedApps = array();
70
+    static private $altLogin = array();
71
+    static private $alreadyRegistered = [];
72
+    const officialApp = 200;
73
+
74
+    /**
75
+     * clean the appId
76
+     *
77
+     * @param string|boolean $app AppId that needs to be cleaned
78
+     * @return string
79
+     */
80
+    public static function cleanAppId($app) {
81
+        return str_replace(array('\0', '/', '\\', '..'), '', $app);
82
+    }
83
+
84
+    /**
85
+     * Check if an app is loaded
86
+     *
87
+     * @param string $app
88
+     * @return bool
89
+     */
90
+    public static function isAppLoaded($app) {
91
+        return in_array($app, self::$loadedApps, true);
92
+    }
93
+
94
+    /**
95
+     * loads all apps
96
+     *
97
+     * @param string[] | string | null $types
98
+     * @return bool
99
+     *
100
+     * This function walks through the ownCloud directory and loads all apps
101
+     * it can find. A directory contains an app if the file /appinfo/info.xml
102
+     * exists.
103
+     *
104
+     * if $types is set, only apps of those types will be loaded
105
+     */
106
+    public static function loadApps($types = null) {
107
+        if (\OC::$server->getSystemConfig()->getValue('maintenance', false)) {
108
+            return false;
109
+        }
110
+        // Load the enabled apps here
111
+        $apps = self::getEnabledApps();
112
+
113
+        // Add each apps' folder as allowed class path
114
+        foreach($apps as $app) {
115
+            $path = self::getAppPath($app);
116
+            if($path !== false) {
117
+                self::registerAutoloading($app, $path);
118
+            }
119
+        }
120
+
121
+        // prevent app.php from printing output
122
+        ob_start();
123
+        foreach ($apps as $app) {
124
+            if ((is_null($types) or self::isType($app, $types)) && !in_array($app, self::$loadedApps)) {
125
+                self::loadApp($app);
126
+            }
127
+        }
128
+        ob_end_clean();
129
+
130
+        return true;
131
+    }
132
+
133
+    /**
134
+     * load a single app
135
+     *
136
+     * @param string $app
137
+     */
138
+    public static function loadApp($app) {
139
+        self::$loadedApps[] = $app;
140
+        $appPath = self::getAppPath($app);
141
+        if($appPath === false) {
142
+            return;
143
+        }
144
+
145
+        // in case someone calls loadApp() directly
146
+        self::registerAutoloading($app, $appPath);
147
+
148
+        if (is_file($appPath . '/appinfo/app.php')) {
149
+            \OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
150
+            self::requireAppFile($app);
151
+            if (self::isType($app, array('authentication'))) {
152
+                // since authentication apps affect the "is app enabled for group" check,
153
+                // the enabled apps cache needs to be cleared to make sure that the
154
+                // next time getEnableApps() is called it will also include apps that were
155
+                // enabled for groups
156
+                self::$enabledAppsCache = array();
157
+            }
158
+            \OC::$server->getEventLogger()->end('load_app_' . $app);
159
+        }
160
+
161
+        $info = self::getAppInfo($app);
162
+        if (!empty($info['activity']['filters'])) {
163
+            foreach ($info['activity']['filters'] as $filter) {
164
+                \OC::$server->getActivityManager()->registerFilter($filter);
165
+            }
166
+        }
167
+        if (!empty($info['activity']['settings'])) {
168
+            foreach ($info['activity']['settings'] as $setting) {
169
+                \OC::$server->getActivityManager()->registerSetting($setting);
170
+            }
171
+        }
172
+        if (!empty($info['activity']['providers'])) {
173
+            foreach ($info['activity']['providers'] as $provider) {
174
+                \OC::$server->getActivityManager()->registerProvider($provider);
175
+            }
176
+        }
177
+    }
178
+
179
+    /**
180
+     * @internal
181
+     * @param string $app
182
+     * @param string $path
183
+     */
184
+    public static function registerAutoloading($app, $path) {
185
+        $key = $app . '-' . $path;
186
+        if(isset(self::$alreadyRegistered[$key])) {
187
+            return;
188
+        }
189
+        self::$alreadyRegistered[$key] = true;
190
+        // Register on PSR-4 composer autoloader
191
+        $appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
192
+        \OC::$server->registerNamespace($app, $appNamespace);
193
+        \OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
194
+        if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
195
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
196
+        }
197
+
198
+        // Register on legacy autoloader
199
+        \OC::$loader->addValidRoot($path);
200
+    }
201
+
202
+    /**
203
+     * Load app.php from the given app
204
+     *
205
+     * @param string $app app name
206
+     */
207
+    private static function requireAppFile($app) {
208
+        try {
209
+            // encapsulated here to avoid variable scope conflicts
210
+            require_once $app . '/appinfo/app.php';
211
+        } catch (Error $ex) {
212
+            \OC::$server->getLogger()->logException($ex);
213
+            $blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
214
+            if (!in_array($app, $blacklist)) {
215
+                self::disable($app);
216
+            }
217
+        }
218
+    }
219
+
220
+    /**
221
+     * check if an app is of a specific type
222
+     *
223
+     * @param string $app
224
+     * @param string|array $types
225
+     * @return bool
226
+     */
227
+    public static function isType($app, $types) {
228
+        if (is_string($types)) {
229
+            $types = array($types);
230
+        }
231
+        $appTypes = self::getAppTypes($app);
232
+        foreach ($types as $type) {
233
+            if (array_search($type, $appTypes) !== false) {
234
+                return true;
235
+            }
236
+        }
237
+        return false;
238
+    }
239
+
240
+    /**
241
+     * get the types of an app
242
+     *
243
+     * @param string $app
244
+     * @return array
245
+     */
246
+    private static function getAppTypes($app) {
247
+        //load the cache
248
+        if (count(self::$appTypes) == 0) {
249
+            self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
250
+        }
251
+
252
+        if (isset(self::$appTypes[$app])) {
253
+            return explode(',', self::$appTypes[$app]);
254
+        } else {
255
+            return array();
256
+        }
257
+    }
258
+
259
+    /**
260
+     * read app types from info.xml and cache them in the database
261
+     */
262
+    public static function setAppTypes($app) {
263
+        $appData = self::getAppInfo($app);
264
+        if(!is_array($appData)) {
265
+            return;
266
+        }
267
+
268
+        if (isset($appData['types'])) {
269
+            $appTypes = implode(',', $appData['types']);
270
+        } else {
271
+            $appTypes = '';
272
+            $appData['types'] = [];
273
+        }
274
+
275
+        \OC::$server->getAppConfig()->setValue($app, 'types', $appTypes);
276
+
277
+        if (\OC::$server->getAppManager()->hasProtectedAppType($appData['types'])) {
278
+            $enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'yes');
279
+            if ($enabled !== 'yes' && $enabled !== 'no') {
280
+                \OC::$server->getAppConfig()->setValue($app, 'enabled', 'yes');
281
+            }
282
+        }
283
+    }
284
+
285
+    /**
286
+     * get all enabled apps
287
+     */
288
+    protected static $enabledAppsCache = array();
289
+
290
+    /**
291
+     * Returns apps enabled for the current user.
292
+     *
293
+     * @param bool $forceRefresh whether to refresh the cache
294
+     * @param bool $all whether to return apps for all users, not only the
295
+     * currently logged in one
296
+     * @return string[]
297
+     */
298
+    public static function getEnabledApps($forceRefresh = false, $all = false) {
299
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
300
+            return array();
301
+        }
302
+        // in incognito mode or when logged out, $user will be false,
303
+        // which is also the case during an upgrade
304
+        $appManager = \OC::$server->getAppManager();
305
+        if ($all) {
306
+            $user = null;
307
+        } else {
308
+            $user = \OC::$server->getUserSession()->getUser();
309
+        }
310
+
311
+        if (is_null($user)) {
312
+            $apps = $appManager->getInstalledApps();
313
+        } else {
314
+            $apps = $appManager->getEnabledAppsForUser($user);
315
+        }
316
+        $apps = array_filter($apps, function ($app) {
317
+            return $app !== 'files';//we add this manually
318
+        });
319
+        sort($apps);
320
+        array_unshift($apps, 'files');
321
+        return $apps;
322
+    }
323
+
324
+    /**
325
+     * checks whether or not an app is enabled
326
+     *
327
+     * @param string $app app
328
+     * @return bool
329
+     *
330
+     * This function checks whether or not an app is enabled.
331
+     */
332
+    public static function isEnabled($app) {
333
+        return \OC::$server->getAppManager()->isEnabledForUser($app);
334
+    }
335
+
336
+    /**
337
+     * enables an app
338
+     *
339
+     * @param string $appId
340
+     * @param array $groups (optional) when set, only these groups will have access to the app
341
+     * @throws \Exception
342
+     * @return void
343
+     *
344
+     * This function set an app as enabled in appconfig.
345
+     */
346
+    public function enable($appId,
347
+                            $groups = null) {
348
+        self::$enabledAppsCache = []; // flush
349
+
350
+        // Check if app is already downloaded
351
+        $installer = new Installer(
352
+            \OC::$server->getAppFetcher(),
353
+            \OC::$server->getHTTPClientService(),
354
+            \OC::$server->getTempManager(),
355
+            \OC::$server->getLogger(),
356
+            \OC::$server->getConfig()
357
+        );
358
+        $isDownloaded = $installer->isDownloaded($appId);
359
+
360
+        if(!$isDownloaded) {
361
+            $installer->downloadApp($appId);
362
+        }
363
+
364
+        $installer->installApp($appId);
365
+
366
+        $appManager = \OC::$server->getAppManager();
367
+        if (!is_null($groups)) {
368
+            $groupManager = \OC::$server->getGroupManager();
369
+            $groupsList = [];
370
+            foreach ($groups as $group) {
371
+                $groupItem = $groupManager->get($group);
372
+                if ($groupItem instanceof \OCP\IGroup) {
373
+                    $groupsList[] = $groupManager->get($group);
374
+                }
375
+            }
376
+            $appManager->enableAppForGroups($appId, $groupsList);
377
+        } else {
378
+            $appManager->enableApp($appId);
379
+        }
380
+    }
381
+
382
+    /**
383
+     * @param string $app
384
+     * @return bool
385
+     */
386
+    public static function removeApp($app) {
387
+        if (\OC::$server->getAppManager()->isShipped($app)) {
388
+            return false;
389
+        }
390
+
391
+        $installer = new Installer(
392
+            \OC::$server->getAppFetcher(),
393
+            \OC::$server->getHTTPClientService(),
394
+            \OC::$server->getTempManager(),
395
+            \OC::$server->getLogger(),
396
+            \OC::$server->getConfig()
397
+        );
398
+        return $installer->removeApp($app);
399
+    }
400
+
401
+    /**
402
+     * This function set an app as disabled in appconfig.
403
+     *
404
+     * @param string $app app
405
+     * @throws Exception
406
+     */
407
+    public static function disable($app) {
408
+        // flush
409
+        self::$enabledAppsCache = array();
410
+
411
+        // run uninstall steps
412
+        $appData = OC_App::getAppInfo($app);
413
+        if (!is_null($appData)) {
414
+            OC_App::executeRepairSteps($app, $appData['repair-steps']['uninstall']);
415
+        }
416
+
417
+        // emit disable hook - needed anymore ?
418
+        \OC_Hook::emit('OC_App', 'pre_disable', array('app' => $app));
419
+
420
+        // finally disable it
421
+        $appManager = \OC::$server->getAppManager();
422
+        $appManager->disableApp($app);
423
+    }
424
+
425
+    // This is private as well. It simply works, so don't ask for more details
426
+    private static function proceedNavigation($list) {
427
+        usort($list, function($a, $b) {
428
+            if (isset($a['order']) && isset($b['order'])) {
429
+                return ($a['order'] < $b['order']) ? -1 : 1;
430
+            } else if (isset($a['order']) || isset($b['order'])) {
431
+                return isset($a['order']) ? -1 : 1;
432
+            } else {
433
+                return ($a['name'] < $b['name']) ? -1 : 1;
434
+            }
435
+        });
436
+
437
+        $activeApp = OC::$server->getNavigationManager()->getActiveEntry();
438
+        foreach ($list as $index => &$navEntry) {
439
+            if ($navEntry['id'] == $activeApp) {
440
+                $navEntry['active'] = true;
441
+            } else {
442
+                $navEntry['active'] = false;
443
+            }
444
+        }
445
+        unset($navEntry);
446
+
447
+        return $list;
448
+    }
449
+
450
+    /**
451
+     * Get the path where to install apps
452
+     *
453
+     * @return string|false
454
+     */
455
+    public static function getInstallPath() {
456
+        if (\OC::$server->getSystemConfig()->getValue('appstoreenabled', true) == false) {
457
+            return false;
458
+        }
459
+
460
+        foreach (OC::$APPSROOTS as $dir) {
461
+            if (isset($dir['writable']) && $dir['writable'] === true) {
462
+                return $dir['path'];
463
+            }
464
+        }
465
+
466
+        \OCP\Util::writeLog('core', 'No application directories are marked as writable.', \OCP\Util::ERROR);
467
+        return null;
468
+    }
469
+
470
+
471
+    /**
472
+     * search for an app in all app-directories
473
+     *
474
+     * @param string $appId
475
+     * @return false|string
476
+     */
477
+    public static function findAppInDirectories($appId) {
478
+        $sanitizedAppId = self::cleanAppId($appId);
479
+        if($sanitizedAppId !== $appId) {
480
+            return false;
481
+        }
482
+        static $app_dir = array();
483
+
484
+        if (isset($app_dir[$appId])) {
485
+            return $app_dir[$appId];
486
+        }
487
+
488
+        $possibleApps = array();
489
+        foreach (OC::$APPSROOTS as $dir) {
490
+            if (file_exists($dir['path'] . '/' . $appId)) {
491
+                $possibleApps[] = $dir;
492
+            }
493
+        }
494
+
495
+        if (empty($possibleApps)) {
496
+            return false;
497
+        } elseif (count($possibleApps) === 1) {
498
+            $dir = array_shift($possibleApps);
499
+            $app_dir[$appId] = $dir;
500
+            return $dir;
501
+        } else {
502
+            $versionToLoad = array();
503
+            foreach ($possibleApps as $possibleApp) {
504
+                $version = self::getAppVersionByPath($possibleApp['path']);
505
+                if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
506
+                    $versionToLoad = array(
507
+                        'dir' => $possibleApp,
508
+                        'version' => $version,
509
+                    );
510
+                }
511
+            }
512
+            $app_dir[$appId] = $versionToLoad['dir'];
513
+            return $versionToLoad['dir'];
514
+            //TODO - write test
515
+        }
516
+    }
517
+
518
+    /**
519
+     * Get the directory for the given app.
520
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
521
+     *
522
+     * @param string $appId
523
+     * @return string|false
524
+     */
525
+    public static function getAppPath($appId) {
526
+        if ($appId === null || trim($appId) === '') {
527
+            return false;
528
+        }
529
+
530
+        if (($dir = self::findAppInDirectories($appId)) != false) {
531
+            return $dir['path'] . '/' . $appId;
532
+        }
533
+        return false;
534
+    }
535
+
536
+    /**
537
+     * Get the path for the given app on the access
538
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
539
+     *
540
+     * @param string $appId
541
+     * @return string|false
542
+     */
543
+    public static function getAppWebPath($appId) {
544
+        if (($dir = self::findAppInDirectories($appId)) != false) {
545
+            return OC::$WEBROOT . $dir['url'] . '/' . $appId;
546
+        }
547
+        return false;
548
+    }
549
+
550
+    /**
551
+     * get the last version of the app from appinfo/info.xml
552
+     *
553
+     * @param string $appId
554
+     * @param bool $useCache
555
+     * @return string
556
+     */
557
+    public static function getAppVersion($appId, $useCache = true) {
558
+        if($useCache && isset(self::$appVersion[$appId])) {
559
+            return self::$appVersion[$appId];
560
+        }
561
+
562
+        $file = self::getAppPath($appId);
563
+        self::$appVersion[$appId] = ($file !== false) ? self::getAppVersionByPath($file) : '0';
564
+        return self::$appVersion[$appId];
565
+    }
566
+
567
+    /**
568
+     * get app's version based on it's path
569
+     *
570
+     * @param string $path
571
+     * @return string
572
+     */
573
+    public static function getAppVersionByPath($path) {
574
+        $infoFile = $path . '/appinfo/info.xml';
575
+        $appData = self::getAppInfo($infoFile, true);
576
+        return isset($appData['version']) ? $appData['version'] : '';
577
+    }
578
+
579
+
580
+    /**
581
+     * Read all app metadata from the info.xml file
582
+     *
583
+     * @param string $appId id of the app or the path of the info.xml file
584
+     * @param bool $path
585
+     * @param string $lang
586
+     * @return array|null
587
+     * @note all data is read from info.xml, not just pre-defined fields
588
+     */
589
+    public static function getAppInfo($appId, $path = false, $lang = null) {
590
+        if ($path) {
591
+            $file = $appId;
592
+        } else {
593
+            if ($lang === null && isset(self::$appInfo[$appId])) {
594
+                return self::$appInfo[$appId];
595
+            }
596
+            $appPath = self::getAppPath($appId);
597
+            if($appPath === false) {
598
+                return null;
599
+            }
600
+            $file = $appPath . '/appinfo/info.xml';
601
+        }
602
+
603
+        $parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
604
+        $data = $parser->parse($file);
605
+
606
+        if (is_array($data)) {
607
+            $data = OC_App::parseAppInfo($data, $lang);
608
+        }
609
+        if(isset($data['ocsid'])) {
610
+            $storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
611
+            if($storedId !== '' && $storedId !== $data['ocsid']) {
612
+                $data['ocsid'] = $storedId;
613
+            }
614
+        }
615
+
616
+        if ($lang === null) {
617
+            self::$appInfo[$appId] = $data;
618
+        }
619
+
620
+        return $data;
621
+    }
622
+
623
+    /**
624
+     * Returns the navigation
625
+     *
626
+     * @return array
627
+     *
628
+     * This function returns an array containing all entries added. The
629
+     * entries are sorted by the key 'order' ascending. Additional to the keys
630
+     * given for each app the following keys exist:
631
+     *   - active: boolean, signals if the user is on this navigation entry
632
+     */
633
+    public static function getNavigation() {
634
+        $entries = OC::$server->getNavigationManager()->getAll();
635
+        return self::proceedNavigation($entries);
636
+    }
637
+
638
+    /**
639
+     * Returns the Settings Navigation
640
+     *
641
+     * @return string[]
642
+     *
643
+     * This function returns an array containing all settings pages added. The
644
+     * entries are sorted by the key 'order' ascending.
645
+     */
646
+    public static function getSettingsNavigation() {
647
+        $entries = OC::$server->getNavigationManager()->getAll('settings');
648
+        return self::proceedNavigation($entries);
649
+    }
650
+
651
+    /**
652
+     * get the id of loaded app
653
+     *
654
+     * @return string
655
+     */
656
+    public static function getCurrentApp() {
657
+        $request = \OC::$server->getRequest();
658
+        $script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
659
+        $topFolder = substr($script, 0, strpos($script, '/'));
660
+        if (empty($topFolder)) {
661
+            $path_info = $request->getPathInfo();
662
+            if ($path_info) {
663
+                $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
664
+            }
665
+        }
666
+        if ($topFolder == 'apps') {
667
+            $length = strlen($topFolder);
668
+            return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1);
669
+        } else {
670
+            return $topFolder;
671
+        }
672
+    }
673
+
674
+    /**
675
+     * @param string $type
676
+     * @return array
677
+     */
678
+    public static function getForms($type) {
679
+        $forms = array();
680
+        switch ($type) {
681
+            case 'admin':
682
+                $source = self::$adminForms;
683
+                break;
684
+            case 'personal':
685
+                $source = self::$personalForms;
686
+                break;
687
+            default:
688
+                return array();
689
+        }
690
+        foreach ($source as $form) {
691
+            $forms[] = include $form;
692
+        }
693
+        return $forms;
694
+    }
695
+
696
+    /**
697
+     * register an admin form to be shown
698
+     *
699
+     * @param string $app
700
+     * @param string $page
701
+     */
702
+    public static function registerAdmin($app, $page) {
703
+        self::$adminForms[] = $app . '/' . $page . '.php';
704
+    }
705
+
706
+    /**
707
+     * register a personal form to be shown
708
+     * @param string $app
709
+     * @param string $page
710
+     */
711
+    public static function registerPersonal($app, $page) {
712
+        self::$personalForms[] = $app . '/' . $page . '.php';
713
+    }
714
+
715
+    /**
716
+     * @param array $entry
717
+     */
718
+    public static function registerLogIn(array $entry) {
719
+        self::$altLogin[] = $entry;
720
+    }
721
+
722
+    /**
723
+     * @return array
724
+     */
725
+    public static function getAlternativeLogIns() {
726
+        return self::$altLogin;
727
+    }
728
+
729
+    /**
730
+     * get a list of all apps in the apps folder
731
+     *
732
+     * @return array an array of app names (string IDs)
733
+     * @todo: change the name of this method to getInstalledApps, which is more accurate
734
+     */
735
+    public static function getAllApps() {
736
+
737
+        $apps = array();
738
+
739
+        foreach (OC::$APPSROOTS as $apps_dir) {
740
+            if (!is_readable($apps_dir['path'])) {
741
+                \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
742
+                continue;
743
+            }
744
+            $dh = opendir($apps_dir['path']);
745
+
746
+            if (is_resource($dh)) {
747
+                while (($file = readdir($dh)) !== false) {
748
+
749
+                    if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
750
+
751
+                        $apps[] = $file;
752
+                    }
753
+                }
754
+            }
755
+        }
756
+
757
+        return $apps;
758
+    }
759
+
760
+    /**
761
+     * List all apps, this is used in apps.php
762
+     *
763
+     * @return array
764
+     */
765
+    public function listAllApps() {
766
+        $installedApps = OC_App::getAllApps();
767
+
768
+        $appManager = \OC::$server->getAppManager();
769
+        //we don't want to show configuration for these
770
+        $blacklist = $appManager->getAlwaysEnabledApps();
771
+        $appList = array();
772
+        $langCode = \OC::$server->getL10N('core')->getLanguageCode();
773
+        $urlGenerator = \OC::$server->getURLGenerator();
774
+
775
+        foreach ($installedApps as $app) {
776
+            if (array_search($app, $blacklist) === false) {
777
+
778
+                $info = OC_App::getAppInfo($app, false, $langCode);
779
+                if (!is_array($info)) {
780
+                    \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
781
+                    continue;
782
+                }
783
+
784
+                if (!isset($info['name'])) {
785
+                    \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
786
+                    continue;
787
+                }
788
+
789
+                $enabled = \OC::$server->getAppConfig()->getValue($app, 'enabled', 'no');
790
+                $info['groups'] = null;
791
+                if ($enabled === 'yes') {
792
+                    $active = true;
793
+                } else if ($enabled === 'no') {
794
+                    $active = false;
795
+                } else {
796
+                    $active = true;
797
+                    $info['groups'] = $enabled;
798
+                }
799
+
800
+                $info['active'] = $active;
801
+
802
+                if ($appManager->isShipped($app)) {
803
+                    $info['internal'] = true;
804
+                    $info['level'] = self::officialApp;
805
+                    $info['removable'] = false;
806
+                } else {
807
+                    $info['internal'] = false;
808
+                    $info['removable'] = true;
809
+                }
810
+
811
+                $appPath = self::getAppPath($app);
812
+                if($appPath !== false) {
813
+                    $appIcon = $appPath . '/img/' . $app . '.svg';
814
+                    if (file_exists($appIcon)) {
815
+                        $info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
816
+                        $info['previewAsIcon'] = true;
817
+                    } else {
818
+                        $appIcon = $appPath . '/img/app.svg';
819
+                        if (file_exists($appIcon)) {
820
+                            $info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
821
+                            $info['previewAsIcon'] = true;
822
+                        }
823
+                    }
824
+                }
825
+                // fix documentation
826
+                if (isset($info['documentation']) && is_array($info['documentation'])) {
827
+                    foreach ($info['documentation'] as $key => $url) {
828
+                        // If it is not an absolute URL we assume it is a key
829
+                        // i.e. admin-ldap will get converted to go.php?to=admin-ldap
830
+                        if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
831
+                            $url = $urlGenerator->linkToDocs($url);
832
+                        }
833
+
834
+                        $info['documentation'][$key] = $url;
835
+                    }
836
+                }
837
+
838
+                $info['version'] = OC_App::getAppVersion($app);
839
+                $appList[] = $info;
840
+            }
841
+        }
842
+
843
+        return $appList;
844
+    }
845
+
846
+    /**
847
+     * Returns the internal app ID or false
848
+     * @param string $ocsID
849
+     * @return string|false
850
+     */
851
+    public static function getInternalAppIdByOcs($ocsID) {
852
+        if(is_numeric($ocsID)) {
853
+            $idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
854
+            if(array_search($ocsID, $idArray)) {
855
+                return array_search($ocsID, $idArray);
856
+            }
857
+        }
858
+        return false;
859
+    }
860
+
861
+    public static function shouldUpgrade($app) {
862
+        $versions = self::getAppVersions();
863
+        $currentVersion = OC_App::getAppVersion($app);
864
+        if ($currentVersion && isset($versions[$app])) {
865
+            $installedVersion = $versions[$app];
866
+            if (!version_compare($currentVersion, $installedVersion, '=')) {
867
+                return true;
868
+            }
869
+        }
870
+        return false;
871
+    }
872
+
873
+    /**
874
+     * Adjust the number of version parts of $version1 to match
875
+     * the number of version parts of $version2.
876
+     *
877
+     * @param string $version1 version to adjust
878
+     * @param string $version2 version to take the number of parts from
879
+     * @return string shortened $version1
880
+     */
881
+    private static function adjustVersionParts($version1, $version2) {
882
+        $version1 = explode('.', $version1);
883
+        $version2 = explode('.', $version2);
884
+        // reduce $version1 to match the number of parts in $version2
885
+        while (count($version1) > count($version2)) {
886
+            array_pop($version1);
887
+        }
888
+        // if $version1 does not have enough parts, add some
889
+        while (count($version1) < count($version2)) {
890
+            $version1[] = '0';
891
+        }
892
+        return implode('.', $version1);
893
+    }
894
+
895
+    /**
896
+     * Check whether the current ownCloud version matches the given
897
+     * application's version requirements.
898
+     *
899
+     * The comparison is made based on the number of parts that the
900
+     * app info version has. For example for ownCloud 6.0.3 if the
901
+     * app info version is expecting version 6.0, the comparison is
902
+     * made on the first two parts of the ownCloud version.
903
+     * This means that it's possible to specify "requiremin" => 6
904
+     * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
905
+     *
906
+     * @param string $ocVersion ownCloud version to check against
907
+     * @param array $appInfo app info (from xml)
908
+     *
909
+     * @return boolean true if compatible, otherwise false
910
+     */
911
+    public static function isAppCompatible($ocVersion, $appInfo) {
912
+        $requireMin = '';
913
+        $requireMax = '';
914
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
915
+            $requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
916
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
917
+            $requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
918
+        } else if (isset($appInfo['requiremin'])) {
919
+            $requireMin = $appInfo['requiremin'];
920
+        } else if (isset($appInfo['require'])) {
921
+            $requireMin = $appInfo['require'];
922
+        }
923
+
924
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
925
+            $requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
926
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
927
+            $requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
928
+        } else if (isset($appInfo['requiremax'])) {
929
+            $requireMax = $appInfo['requiremax'];
930
+        }
931
+
932
+        if (is_array($ocVersion)) {
933
+            $ocVersion = implode('.', $ocVersion);
934
+        }
935
+
936
+        if (!empty($requireMin)
937
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
938
+        ) {
939
+
940
+            return false;
941
+        }
942
+
943
+        if (!empty($requireMax)
944
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
945
+        ) {
946
+            return false;
947
+        }
948
+
949
+        return true;
950
+    }
951
+
952
+    /**
953
+     * get the installed version of all apps
954
+     */
955
+    public static function getAppVersions() {
956
+        static $versions;
957
+
958
+        if(!$versions) {
959
+            $appConfig = \OC::$server->getAppConfig();
960
+            $versions = $appConfig->getValues(false, 'installed_version');
961
+        }
962
+        return $versions;
963
+    }
964
+
965
+    /**
966
+     * @param string $app
967
+     * @param \OCP\IConfig $config
968
+     * @param \OCP\IL10N $l
969
+     * @return bool
970
+     *
971
+     * @throws Exception if app is not compatible with this version of ownCloud
972
+     * @throws Exception if no app-name was specified
973
+     */
974
+    public function installApp($app,
975
+                                \OCP\IConfig $config,
976
+                                \OCP\IL10N $l) {
977
+        if ($app !== false) {
978
+            // check if the app is compatible with this version of ownCloud
979
+            $info = self::getAppInfo($app);
980
+            if(!is_array($info)) {
981
+                throw new \Exception(
982
+                    $l->t('App "%s" cannot be installed because appinfo file cannot be read.',
983
+                        [$info['name']]
984
+                    )
985
+                );
986
+            }
987
+
988
+            $version = \OCP\Util::getVersion();
989
+            if (!self::isAppCompatible($version, $info)) {
990
+                throw new \Exception(
991
+                    $l->t('App "%s" cannot be installed because it is not compatible with this version of the server.',
992
+                        array($info['name'])
993
+                    )
994
+                );
995
+            }
996
+
997
+            // check for required dependencies
998
+            self::checkAppDependencies($config, $l, $info);
999
+
1000
+            $config->setAppValue($app, 'enabled', 'yes');
1001
+            if (isset($appData['id'])) {
1002
+                $config->setAppValue($app, 'ocsid', $appData['id']);
1003
+            }
1004
+
1005
+            if(isset($info['settings']) && is_array($info['settings'])) {
1006
+                $appPath = self::getAppPath($app);
1007
+                self::registerAutoloading($app, $appPath);
1008
+                \OC::$server->getSettingsManager()->setupSettings($info['settings']);
1009
+            }
1010
+
1011
+            \OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1012
+        } else {
1013
+            if(empty($appName) ) {
1014
+                throw new \Exception($l->t("No app name specified"));
1015
+            } else {
1016
+                throw new \Exception($l->t("App '%s' could not be installed!", $appName));
1017
+            }
1018
+        }
1019
+
1020
+        return $app;
1021
+    }
1022
+
1023
+    /**
1024
+     * update the database for the app and call the update script
1025
+     *
1026
+     * @param string $appId
1027
+     * @return bool
1028
+     */
1029
+    public static function updateApp($appId) {
1030
+        $appPath = self::getAppPath($appId);
1031
+        if($appPath === false) {
1032
+            return false;
1033
+        }
1034
+        self::registerAutoloading($appId, $appPath);
1035
+
1036
+        $appData = self::getAppInfo($appId);
1037
+        self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1038
+
1039
+        if (file_exists($appPath . '/appinfo/database.xml')) {
1040
+            OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1041
+        } else {
1042
+            $ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
1043
+            $ms->migrate();
1044
+        }
1045
+
1046
+        self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
1047
+        self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
1048
+        unset(self::$appVersion[$appId]);
1049
+
1050
+        // run upgrade code
1051
+        if (file_exists($appPath . '/appinfo/update.php')) {
1052
+            self::loadApp($appId);
1053
+            include $appPath . '/appinfo/update.php';
1054
+        }
1055
+        self::setupBackgroundJobs($appData['background-jobs']);
1056
+        if(isset($appData['settings']) && is_array($appData['settings'])) {
1057
+            \OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1058
+        }
1059
+
1060
+        //set remote/public handlers
1061
+        if (array_key_exists('ocsid', $appData)) {
1062
+            \OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1063
+        } elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1064
+            \OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1065
+        }
1066
+        foreach ($appData['remote'] as $name => $path) {
1067
+            \OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1068
+        }
1069
+        foreach ($appData['public'] as $name => $path) {
1070
+            \OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1071
+        }
1072
+
1073
+        self::setAppTypes($appId);
1074
+
1075
+        $version = \OC_App::getAppVersion($appId);
1076
+        \OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
1077
+
1078
+        \OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
1079
+            ManagerEvent::EVENT_APP_UPDATE, $appId
1080
+        ));
1081
+
1082
+        return true;
1083
+    }
1084
+
1085
+    /**
1086
+     * @param string $appId
1087
+     * @param string[] $steps
1088
+     * @throws \OC\NeedsUpdateException
1089
+     */
1090
+    public static function executeRepairSteps($appId, array $steps) {
1091
+        if (empty($steps)) {
1092
+            return;
1093
+        }
1094
+        // load the app
1095
+        self::loadApp($appId);
1096
+
1097
+        $dispatcher = OC::$server->getEventDispatcher();
1098
+
1099
+        // load the steps
1100
+        $r = new Repair([], $dispatcher);
1101
+        foreach ($steps as $step) {
1102
+            try {
1103
+                $r->addStep($step);
1104
+            } catch (Exception $ex) {
1105
+                $r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1106
+                \OC::$server->getLogger()->logException($ex);
1107
+            }
1108
+        }
1109
+        // run the steps
1110
+        $r->run();
1111
+    }
1112
+
1113
+    public static function setupBackgroundJobs(array $jobs) {
1114
+        $queue = \OC::$server->getJobList();
1115
+        foreach ($jobs as $job) {
1116
+            $queue->add($job);
1117
+        }
1118
+    }
1119
+
1120
+    /**
1121
+     * @param string $appId
1122
+     * @param string[] $steps
1123
+     */
1124
+    private static function setupLiveMigrations($appId, array $steps) {
1125
+        $queue = \OC::$server->getJobList();
1126
+        foreach ($steps as $step) {
1127
+            $queue->add('OC\Migration\BackgroundRepair', [
1128
+                'app' => $appId,
1129
+                'step' => $step]);
1130
+        }
1131
+    }
1132
+
1133
+    /**
1134
+     * @param string $appId
1135
+     * @return \OC\Files\View|false
1136
+     */
1137
+    public static function getStorage($appId) {
1138
+        if (OC_App::isEnabled($appId)) { //sanity check
1139
+            if (\OC::$server->getUserSession()->isLoggedIn()) {
1140
+                $view = new \OC\Files\View('/' . OC_User::getUser());
1141
+                if (!$view->file_exists($appId)) {
1142
+                    $view->mkdir($appId);
1143
+                }
1144
+                return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1145
+            } else {
1146
+                \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1147
+                return false;
1148
+            }
1149
+        } else {
1150
+            \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1151
+            return false;
1152
+        }
1153
+    }
1154
+
1155
+    protected static function findBestL10NOption($options, $lang) {
1156
+        $fallback = $similarLangFallback = $englishFallback = false;
1157
+
1158
+        $lang = strtolower($lang);
1159
+        $similarLang = $lang;
1160
+        if (strpos($similarLang, '_')) {
1161
+            // For "de_DE" we want to find "de" and the other way around
1162
+            $similarLang = substr($lang, 0, strpos($lang, '_'));
1163
+        }
1164
+
1165
+        foreach ($options as $option) {
1166
+            if (is_array($option)) {
1167
+                if ($fallback === false) {
1168
+                    $fallback = $option['@value'];
1169
+                }
1170
+
1171
+                if (!isset($option['@attributes']['lang'])) {
1172
+                    continue;
1173
+                }
1174
+
1175
+                $attributeLang = strtolower($option['@attributes']['lang']);
1176
+                if ($attributeLang === $lang) {
1177
+                    return $option['@value'];
1178
+                }
1179
+
1180
+                if ($attributeLang === $similarLang) {
1181
+                    $similarLangFallback = $option['@value'];
1182
+                } else if (strpos($attributeLang, $similarLang . '_') === 0) {
1183
+                    if ($similarLangFallback === false) {
1184
+                        $similarLangFallback =  $option['@value'];
1185
+                    }
1186
+                }
1187
+            } else {
1188
+                $englishFallback = $option;
1189
+            }
1190
+        }
1191
+
1192
+        if ($similarLangFallback !== false) {
1193
+            return $similarLangFallback;
1194
+        } else if ($englishFallback !== false) {
1195
+            return $englishFallback;
1196
+        }
1197
+        return (string) $fallback;
1198
+    }
1199
+
1200
+    /**
1201
+     * parses the app data array and enhanced the 'description' value
1202
+     *
1203
+     * @param array $data the app data
1204
+     * @param string $lang
1205
+     * @return array improved app data
1206
+     */
1207
+    public static function parseAppInfo(array $data, $lang = null) {
1208
+
1209
+        if ($lang && isset($data['name']) && is_array($data['name'])) {
1210
+            $data['name'] = self::findBestL10NOption($data['name'], $lang);
1211
+        }
1212
+        if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1213
+            $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1214
+        }
1215
+        if ($lang && isset($data['description']) && is_array($data['description'])) {
1216
+            $data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1217
+        } else if (isset($data['description']) && is_string($data['description'])) {
1218
+            $data['description'] = trim($data['description']);
1219
+        } else  {
1220
+            $data['description'] = '';
1221
+        }
1222
+
1223
+        return $data;
1224
+    }
1225
+
1226
+    /**
1227
+     * @param \OCP\IConfig $config
1228
+     * @param \OCP\IL10N $l
1229
+     * @param array $info
1230
+     * @throws \Exception
1231
+     */
1232
+    public static function checkAppDependencies($config, $l, $info) {
1233
+        $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1234
+        $missing = $dependencyAnalyzer->analyze($info);
1235
+        if (!empty($missing)) {
1236
+            $missingMsg = implode(PHP_EOL, $missing);
1237
+            throw new \Exception(
1238
+                $l->t('App "%s" cannot be installed because the following dependencies are not fulfilled: %s',
1239
+                    [$info['name'], $missingMsg]
1240
+                )
1241
+            );
1242
+        }
1243
+    }
1244 1244
 }
Please login to merge, or discard this patch.
Spacing   +57 added lines, -57 removed lines patch added patch discarded remove patch
@@ -111,9 +111,9 @@  discard block
 block discarded – undo
111 111
 		$apps = self::getEnabledApps();
112 112
 
113 113
 		// Add each apps' folder as allowed class path
114
-		foreach($apps as $app) {
114
+		foreach ($apps as $app) {
115 115
 			$path = self::getAppPath($app);
116
-			if($path !== false) {
116
+			if ($path !== false) {
117 117
 				self::registerAutoloading($app, $path);
118 118
 			}
119 119
 		}
@@ -138,15 +138,15 @@  discard block
 block discarded – undo
138 138
 	public static function loadApp($app) {
139 139
 		self::$loadedApps[] = $app;
140 140
 		$appPath = self::getAppPath($app);
141
-		if($appPath === false) {
141
+		if ($appPath === false) {
142 142
 			return;
143 143
 		}
144 144
 
145 145
 		// in case someone calls loadApp() directly
146 146
 		self::registerAutoloading($app, $appPath);
147 147
 
148
-		if (is_file($appPath . '/appinfo/app.php')) {
149
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
148
+		if (is_file($appPath.'/appinfo/app.php')) {
149
+			\OC::$server->getEventLogger()->start('load_app_'.$app, 'Load app: '.$app);
150 150
 			self::requireAppFile($app);
151 151
 			if (self::isType($app, array('authentication'))) {
152 152
 				// since authentication apps affect the "is app enabled for group" check,
@@ -155,7 +155,7 @@  discard block
 block discarded – undo
155 155
 				// enabled for groups
156 156
 				self::$enabledAppsCache = array();
157 157
 			}
158
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
158
+			\OC::$server->getEventLogger()->end('load_app_'.$app);
159 159
 		}
160 160
 
161 161
 		$info = self::getAppInfo($app);
@@ -182,17 +182,17 @@  discard block
 block discarded – undo
182 182
 	 * @param string $path
183 183
 	 */
184 184
 	public static function registerAutoloading($app, $path) {
185
-		$key = $app . '-' . $path;
186
-		if(isset(self::$alreadyRegistered[$key])) {
185
+		$key = $app.'-'.$path;
186
+		if (isset(self::$alreadyRegistered[$key])) {
187 187
 			return;
188 188
 		}
189 189
 		self::$alreadyRegistered[$key] = true;
190 190
 		// Register on PSR-4 composer autoloader
191 191
 		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
192 192
 		\OC::$server->registerNamespace($app, $appNamespace);
193
-		\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
193
+		\OC::$composerAutoloader->addPsr4($appNamespace.'\\', $path.'/lib/', true);
194 194
 		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
195
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
195
+			\OC::$composerAutoloader->addPsr4($appNamespace.'\\Tests\\', $path.'/tests/', true);
196 196
 		}
197 197
 
198 198
 		// Register on legacy autoloader
@@ -207,7 +207,7 @@  discard block
 block discarded – undo
207 207
 	private static function requireAppFile($app) {
208 208
 		try {
209 209
 			// encapsulated here to avoid variable scope conflicts
210
-			require_once $app . '/appinfo/app.php';
210
+			require_once $app.'/appinfo/app.php';
211 211
 		} catch (Error $ex) {
212 212
 			\OC::$server->getLogger()->logException($ex);
213 213
 			$blacklist = \OC::$server->getAppManager()->getAlwaysEnabledApps();
@@ -261,7 +261,7 @@  discard block
 block discarded – undo
261 261
 	 */
262 262
 	public static function setAppTypes($app) {
263 263
 		$appData = self::getAppInfo($app);
264
-		if(!is_array($appData)) {
264
+		if (!is_array($appData)) {
265 265
 			return;
266 266
 		}
267 267
 
@@ -313,8 +313,8 @@  discard block
 block discarded – undo
313 313
 		} else {
314 314
 			$apps = $appManager->getEnabledAppsForUser($user);
315 315
 		}
316
-		$apps = array_filter($apps, function ($app) {
317
-			return $app !== 'files';//we add this manually
316
+		$apps = array_filter($apps, function($app) {
317
+			return $app !== 'files'; //we add this manually
318 318
 		});
319 319
 		sort($apps);
320 320
 		array_unshift($apps, 'files');
@@ -357,7 +357,7 @@  discard block
 block discarded – undo
357 357
 		);
358 358
 		$isDownloaded = $installer->isDownloaded($appId);
359 359
 
360
-		if(!$isDownloaded) {
360
+		if (!$isDownloaded) {
361 361
 			$installer->downloadApp($appId);
362 362
 		}
363 363
 
@@ -476,7 +476,7 @@  discard block
 block discarded – undo
476 476
 	 */
477 477
 	public static function findAppInDirectories($appId) {
478 478
 		$sanitizedAppId = self::cleanAppId($appId);
479
-		if($sanitizedAppId !== $appId) {
479
+		if ($sanitizedAppId !== $appId) {
480 480
 			return false;
481 481
 		}
482 482
 		static $app_dir = array();
@@ -487,7 +487,7 @@  discard block
 block discarded – undo
487 487
 
488 488
 		$possibleApps = array();
489 489
 		foreach (OC::$APPSROOTS as $dir) {
490
-			if (file_exists($dir['path'] . '/' . $appId)) {
490
+			if (file_exists($dir['path'].'/'.$appId)) {
491 491
 				$possibleApps[] = $dir;
492 492
 			}
493 493
 		}
@@ -528,7 +528,7 @@  discard block
 block discarded – undo
528 528
 		}
529 529
 
530 530
 		if (($dir = self::findAppInDirectories($appId)) != false) {
531
-			return $dir['path'] . '/' . $appId;
531
+			return $dir['path'].'/'.$appId;
532 532
 		}
533 533
 		return false;
534 534
 	}
@@ -542,7 +542,7 @@  discard block
 block discarded – undo
542 542
 	 */
543 543
 	public static function getAppWebPath($appId) {
544 544
 		if (($dir = self::findAppInDirectories($appId)) != false) {
545
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
545
+			return OC::$WEBROOT.$dir['url'].'/'.$appId;
546 546
 		}
547 547
 		return false;
548 548
 	}
@@ -555,7 +555,7 @@  discard block
 block discarded – undo
555 555
 	 * @return string
556 556
 	 */
557 557
 	public static function getAppVersion($appId, $useCache = true) {
558
-		if($useCache && isset(self::$appVersion[$appId])) {
558
+		if ($useCache && isset(self::$appVersion[$appId])) {
559 559
 			return self::$appVersion[$appId];
560 560
 		}
561 561
 
@@ -571,7 +571,7 @@  discard block
 block discarded – undo
571 571
 	 * @return string
572 572
 	 */
573 573
 	public static function getAppVersionByPath($path) {
574
-		$infoFile = $path . '/appinfo/info.xml';
574
+		$infoFile = $path.'/appinfo/info.xml';
575 575
 		$appData = self::getAppInfo($infoFile, true);
576 576
 		return isset($appData['version']) ? $appData['version'] : '';
577 577
 	}
@@ -594,10 +594,10 @@  discard block
 block discarded – undo
594 594
 				return self::$appInfo[$appId];
595 595
 			}
596 596
 			$appPath = self::getAppPath($appId);
597
-			if($appPath === false) {
597
+			if ($appPath === false) {
598 598
 				return null;
599 599
 			}
600
-			$file = $appPath . '/appinfo/info.xml';
600
+			$file = $appPath.'/appinfo/info.xml';
601 601
 		}
602 602
 
603 603
 		$parser = new InfoParser(\OC::$server->getMemCacheFactory()->create('core.appinfo'));
@@ -606,9 +606,9 @@  discard block
 block discarded – undo
606 606
 		if (is_array($data)) {
607 607
 			$data = OC_App::parseAppInfo($data, $lang);
608 608
 		}
609
-		if(isset($data['ocsid'])) {
609
+		if (isset($data['ocsid'])) {
610 610
 			$storedId = \OC::$server->getConfig()->getAppValue($appId, 'ocsid');
611
-			if($storedId !== '' && $storedId !== $data['ocsid']) {
611
+			if ($storedId !== '' && $storedId !== $data['ocsid']) {
612 612
 				$data['ocsid'] = $storedId;
613 613
 			}
614 614
 		}
@@ -700,7 +700,7 @@  discard block
 block discarded – undo
700 700
 	 * @param string $page
701 701
 	 */
702 702
 	public static function registerAdmin($app, $page) {
703
-		self::$adminForms[] = $app . '/' . $page . '.php';
703
+		self::$adminForms[] = $app.'/'.$page.'.php';
704 704
 	}
705 705
 
706 706
 	/**
@@ -709,7 +709,7 @@  discard block
 block discarded – undo
709 709
 	 * @param string $page
710 710
 	 */
711 711
 	public static function registerPersonal($app, $page) {
712
-		self::$personalForms[] = $app . '/' . $page . '.php';
712
+		self::$personalForms[] = $app.'/'.$page.'.php';
713 713
 	}
714 714
 
715 715
 	/**
@@ -738,7 +738,7 @@  discard block
 block discarded – undo
738 738
 
739 739
 		foreach (OC::$APPSROOTS as $apps_dir) {
740 740
 			if (!is_readable($apps_dir['path'])) {
741
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], \OCP\Util::WARN);
741
+				\OCP\Util::writeLog('core', 'unable to read app folder : '.$apps_dir['path'], \OCP\Util::WARN);
742 742
 				continue;
743 743
 			}
744 744
 			$dh = opendir($apps_dir['path']);
@@ -746,7 +746,7 @@  discard block
 block discarded – undo
746 746
 			if (is_resource($dh)) {
747 747
 				while (($file = readdir($dh)) !== false) {
748 748
 
749
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
749
+					if ($file[0] != '.' and is_dir($apps_dir['path'].'/'.$file) and is_file($apps_dir['path'].'/'.$file.'/appinfo/info.xml')) {
750 750
 
751 751
 						$apps[] = $file;
752 752
 					}
@@ -777,12 +777,12 @@  discard block
 block discarded – undo
777 777
 
778 778
 				$info = OC_App::getAppInfo($app, false, $langCode);
779 779
 				if (!is_array($info)) {
780
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', \OCP\Util::ERROR);
780
+					\OCP\Util::writeLog('core', 'Could not read app info file for app "'.$app.'"', \OCP\Util::ERROR);
781 781
 					continue;
782 782
 				}
783 783
 
784 784
 				if (!isset($info['name'])) {
785
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', \OCP\Util::ERROR);
785
+					\OCP\Util::writeLog('core', 'App id "'.$app.'" has no name in appinfo', \OCP\Util::ERROR);
786 786
 					continue;
787 787
 				}
788 788
 
@@ -809,13 +809,13 @@  discard block
 block discarded – undo
809 809
 				}
810 810
 
811 811
 				$appPath = self::getAppPath($app);
812
-				if($appPath !== false) {
813
-					$appIcon = $appPath . '/img/' . $app . '.svg';
812
+				if ($appPath !== false) {
813
+					$appIcon = $appPath.'/img/'.$app.'.svg';
814 814
 					if (file_exists($appIcon)) {
815
-						$info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
815
+						$info['preview'] = $urlGenerator->imagePath($app, $app.'.svg');
816 816
 						$info['previewAsIcon'] = true;
817 817
 					} else {
818
-						$appIcon = $appPath . '/img/app.svg';
818
+						$appIcon = $appPath.'/img/app.svg';
819 819
 						if (file_exists($appIcon)) {
820 820
 							$info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
821 821
 							$info['previewAsIcon'] = true;
@@ -849,9 +849,9 @@  discard block
 block discarded – undo
849 849
 	 * @return string|false
850 850
 	 */
851 851
 	public static function getInternalAppIdByOcs($ocsID) {
852
-		if(is_numeric($ocsID)) {
852
+		if (is_numeric($ocsID)) {
853 853
 			$idArray = \OC::$server->getAppConfig()->getValues(false, 'ocsid');
854
-			if(array_search($ocsID, $idArray)) {
854
+			if (array_search($ocsID, $idArray)) {
855 855
 				return array_search($ocsID, $idArray);
856 856
 			}
857 857
 		}
@@ -955,7 +955,7 @@  discard block
 block discarded – undo
955 955
 	public static function getAppVersions() {
956 956
 		static $versions;
957 957
 
958
-		if(!$versions) {
958
+		if (!$versions) {
959 959
 			$appConfig = \OC::$server->getAppConfig();
960 960
 			$versions = $appConfig->getValues(false, 'installed_version');
961 961
 		}
@@ -977,7 +977,7 @@  discard block
 block discarded – undo
977 977
 		if ($app !== false) {
978 978
 			// check if the app is compatible with this version of ownCloud
979 979
 			$info = self::getAppInfo($app);
980
-			if(!is_array($info)) {
980
+			if (!is_array($info)) {
981 981
 				throw new \Exception(
982 982
 					$l->t('App "%s" cannot be installed because appinfo file cannot be read.',
983 983
 						[$info['name']]
@@ -1002,7 +1002,7 @@  discard block
 block discarded – undo
1002 1002
 				$config->setAppValue($app, 'ocsid', $appData['id']);
1003 1003
 			}
1004 1004
 
1005
-			if(isset($info['settings']) && is_array($info['settings'])) {
1005
+			if (isset($info['settings']) && is_array($info['settings'])) {
1006 1006
 				$appPath = self::getAppPath($app);
1007 1007
 				self::registerAutoloading($app, $appPath);
1008 1008
 				\OC::$server->getSettingsManager()->setupSettings($info['settings']);
@@ -1010,7 +1010,7 @@  discard block
 block discarded – undo
1010 1010
 
1011 1011
 			\OC_Hook::emit('OC_App', 'post_enable', array('app' => $app));
1012 1012
 		} else {
1013
-			if(empty($appName) ) {
1013
+			if (empty($appName)) {
1014 1014
 				throw new \Exception($l->t("No app name specified"));
1015 1015
 			} else {
1016 1016
 				throw new \Exception($l->t("App '%s' could not be installed!", $appName));
@@ -1028,7 +1028,7 @@  discard block
 block discarded – undo
1028 1028
 	 */
1029 1029
 	public static function updateApp($appId) {
1030 1030
 		$appPath = self::getAppPath($appId);
1031
-		if($appPath === false) {
1031
+		if ($appPath === false) {
1032 1032
 			return false;
1033 1033
 		}
1034 1034
 		self::registerAutoloading($appId, $appPath);
@@ -1036,8 +1036,8 @@  discard block
 block discarded – undo
1036 1036
 		$appData = self::getAppInfo($appId);
1037 1037
 		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
1038 1038
 
1039
-		if (file_exists($appPath . '/appinfo/database.xml')) {
1040
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
1039
+		if (file_exists($appPath.'/appinfo/database.xml')) {
1040
+			OC_DB::updateDbFromStructure($appPath.'/appinfo/database.xml');
1041 1041
 		} else {
1042 1042
 			$ms = new MigrationService($appId, \OC::$server->getDatabaseConnection());
1043 1043
 			$ms->migrate();
@@ -1048,26 +1048,26 @@  discard block
 block discarded – undo
1048 1048
 		unset(self::$appVersion[$appId]);
1049 1049
 
1050 1050
 		// run upgrade code
1051
-		if (file_exists($appPath . '/appinfo/update.php')) {
1051
+		if (file_exists($appPath.'/appinfo/update.php')) {
1052 1052
 			self::loadApp($appId);
1053
-			include $appPath . '/appinfo/update.php';
1053
+			include $appPath.'/appinfo/update.php';
1054 1054
 		}
1055 1055
 		self::setupBackgroundJobs($appData['background-jobs']);
1056
-		if(isset($appData['settings']) && is_array($appData['settings'])) {
1056
+		if (isset($appData['settings']) && is_array($appData['settings'])) {
1057 1057
 			\OC::$server->getSettingsManager()->setupSettings($appData['settings']);
1058 1058
 		}
1059 1059
 
1060 1060
 		//set remote/public handlers
1061 1061
 		if (array_key_exists('ocsid', $appData)) {
1062 1062
 			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1063
-		} elseif(\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1063
+		} elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1064 1064
 			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1065 1065
 		}
1066 1066
 		foreach ($appData['remote'] as $name => $path) {
1067
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1067
+			\OC::$server->getConfig()->setAppValue('core', 'remote_'.$name, $appId.'/'.$path);
1068 1068
 		}
1069 1069
 		foreach ($appData['public'] as $name => $path) {
1070
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1070
+			\OC::$server->getConfig()->setAppValue('core', 'public_'.$name, $appId.'/'.$path);
1071 1071
 		}
1072 1072
 
1073 1073
 		self::setAppTypes($appId);
@@ -1137,17 +1137,17 @@  discard block
 block discarded – undo
1137 1137
 	public static function getStorage($appId) {
1138 1138
 		if (OC_App::isEnabled($appId)) { //sanity check
1139 1139
 			if (\OC::$server->getUserSession()->isLoggedIn()) {
1140
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1140
+				$view = new \OC\Files\View('/'.OC_User::getUser());
1141 1141
 				if (!$view->file_exists($appId)) {
1142 1142
 					$view->mkdir($appId);
1143 1143
 				}
1144
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1144
+				return new \OC\Files\View('/'.OC_User::getUser().'/'.$appId);
1145 1145
 			} else {
1146
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', \OCP\Util::ERROR);
1146
+				\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.', user not logged in', \OCP\Util::ERROR);
1147 1147
 				return false;
1148 1148
 			}
1149 1149
 		} else {
1150
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', \OCP\Util::ERROR);
1150
+			\OCP\Util::writeLog('core', 'Can\'t get app storage, app '.$appId.' not enabled', \OCP\Util::ERROR);
1151 1151
 			return false;
1152 1152
 		}
1153 1153
 	}
@@ -1179,9 +1179,9 @@  discard block
 block discarded – undo
1179 1179
 
1180 1180
 				if ($attributeLang === $similarLang) {
1181 1181
 					$similarLangFallback = $option['@value'];
1182
-				} else if (strpos($attributeLang, $similarLang . '_') === 0) {
1182
+				} else if (strpos($attributeLang, $similarLang.'_') === 0) {
1183 1183
 					if ($similarLangFallback === false) {
1184
-						$similarLangFallback =  $option['@value'];
1184
+						$similarLangFallback = $option['@value'];
1185 1185
 					}
1186 1186
 				}
1187 1187
 			} else {
@@ -1216,7 +1216,7 @@  discard block
 block discarded – undo
1216 1216
 			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1217 1217
 		} else if (isset($data['description']) && is_string($data['description'])) {
1218 1218
 			$data['description'] = trim($data['description']);
1219
-		} else  {
1219
+		} else {
1220 1220
 			$data['description'] = '';
1221 1221
 		}
1222 1222
 
Please login to merge, or discard this patch.
lib/private/Updater.php 2 patches
Indentation   +590 added lines, -590 removed lines patch added patch discarded remove patch
@@ -52,596 +52,596 @@
 block discarded – undo
52 52
  */
53 53
 class Updater extends BasicEmitter {
54 54
 
55
-	/** @var ILogger $log */
56
-	private $log;
57
-
58
-	/** @var IConfig */
59
-	private $config;
60
-
61
-	/** @var Checker */
62
-	private $checker;
63
-
64
-	/** @var bool */
65
-	private $skip3rdPartyAppsDisable;
66
-
67
-	private $logLevelNames = [
68
-		0 => 'Debug',
69
-		1 => 'Info',
70
-		2 => 'Warning',
71
-		3 => 'Error',
72
-		4 => 'Fatal',
73
-	];
74
-
75
-	/**
76
-	 * @param IConfig $config
77
-	 * @param Checker $checker
78
-	 * @param ILogger $log
79
-	 */
80
-	public function __construct(IConfig $config,
81
-								Checker $checker,
82
-								ILogger $log = null) {
83
-		$this->log = $log;
84
-		$this->config = $config;
85
-		$this->checker = $checker;
86
-
87
-		// If at least PHP 7.0.0 is used we don't need to disable apps as we catch
88
-		// fatal errors and exceptions and disable the app just instead.
89
-		if(version_compare(phpversion(), '7.0.0', '>=')) {
90
-			$this->skip3rdPartyAppsDisable = true;
91
-		}
92
-	}
93
-
94
-	/**
95
-	 * Sets whether the update disables 3rd party apps.
96
-	 * This can be set to true to skip the disable.
97
-	 *
98
-	 * @param bool $flag false to not disable, true otherwise
99
-	 */
100
-	public function setSkip3rdPartyAppsDisable($flag) {
101
-		$this->skip3rdPartyAppsDisable = $flag;
102
-	}
103
-
104
-	/**
105
-	 * runs the update actions in maintenance mode, does not upgrade the source files
106
-	 * except the main .htaccess file
107
-	 *
108
-	 * @return bool true if the operation succeeded, false otherwise
109
-	 */
110
-	public function upgrade() {
111
-		$this->emitRepairEvents();
112
-		$this->logAllEvents();
113
-
114
-		$logLevel = $this->config->getSystemValue('loglevel', Util::WARN);
115
-		$this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
116
-		$this->config->setSystemValue('loglevel', Util::DEBUG);
117
-
118
-		$wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false);
119
-
120
-		if(!$wasMaintenanceModeEnabled) {
121
-			$this->config->setSystemValue('maintenance', true);
122
-			$this->emit('\OC\Updater', 'maintenanceEnabled');
123
-		}
124
-
125
-		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
126
-		$currentVersion = implode('.', \OCP\Util::getVersion());
127
-		$this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core'));
128
-
129
-		$success = true;
130
-		try {
131
-			$this->doUpgrade($currentVersion, $installedVersion);
132
-		} catch (HintException $exception) {
133
-			$this->log->logException($exception, ['app' => 'core']);
134
-			$this->emit('\OC\Updater', 'failure', array($exception->getMessage() . ': ' .$exception->getHint()));
135
-			$success = false;
136
-		} catch (\Exception $exception) {
137
-			$this->log->logException($exception, ['app' => 'core']);
138
-			$this->emit('\OC\Updater', 'failure', array(get_class($exception) . ': ' .$exception->getMessage()));
139
-			$success = false;
140
-		}
141
-
142
-		$this->emit('\OC\Updater', 'updateEnd', array($success));
143
-
144
-		if(!$wasMaintenanceModeEnabled && $success) {
145
-			$this->config->setSystemValue('maintenance', false);
146
-			$this->emit('\OC\Updater', 'maintenanceDisabled');
147
-		} else {
148
-			$this->emit('\OC\Updater', 'maintenanceActive');
149
-		}
150
-
151
-		$this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
152
-		$this->config->setSystemValue('loglevel', $logLevel);
153
-		$this->config->setSystemValue('installed', true);
154
-
155
-		return $success;
156
-	}
157
-
158
-	/**
159
-	 * Return version from which this version is allowed to upgrade from
160
-	 *
161
-	 * @return array allowed previous versions per vendor
162
-	 */
163
-	private function getAllowedPreviousVersions() {
164
-		// this should really be a JSON file
165
-		require \OC::$SERVERROOT . '/version.php';
166
-		/** @var array $OC_VersionCanBeUpgradedFrom */
167
-		return $OC_VersionCanBeUpgradedFrom;
168
-	}
169
-
170
-	/**
171
-	 * Return vendor from which this version was published
172
-	 *
173
-	 * @return string Get the vendor
174
-	 */
175
-	private function getVendor() {
176
-		// this should really be a JSON file
177
-		require \OC::$SERVERROOT . '/version.php';
178
-		/** @var string $vendor */
179
-		return (string) $vendor;
180
-	}
181
-
182
-	/**
183
-	 * Whether an upgrade to a specified version is possible
184
-	 * @param string $oldVersion
185
-	 * @param string $newVersion
186
-	 * @param array $allowedPreviousVersions
187
-	 * @return bool
188
-	 */
189
-	public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
190
-		$version = explode('.', $oldVersion);
191
-		$majorMinor = $version[0] . '.' . $version[1];
192
-
193
-		$currentVendor = $this->config->getAppValue('core', 'vendor', '');
194
-
195
-		// Vendor was not set correctly on install, so we have to white-list known versions
196
-		if ($currentVendor === '') {
197
-			if (in_array($oldVersion, [
198
-				'11.0.2.7',
199
-				'11.0.1.2',
200
-				'11.0.0.10',
201
-			], true)) {
202
-				$currentVendor = 'nextcloud';
203
-			} else if (in_array($oldVersion, [
204
-					'10.0.0.12',
205
-				], true)) {
206
-				$currentVendor = 'owncloud';
207
-			}
208
-		}
209
-
210
-		if ($currentVendor === 'nextcloud') {
211
-			return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
212
-				&& (version_compare($oldVersion, $newVersion, '<=') ||
213
-					$this->config->getSystemValue('debug', false));
214
-		}
215
-
216
-		// Check if the instance can be migrated
217
-		return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) ||
218
-			isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
219
-	}
220
-
221
-	/**
222
-	 * runs the update actions in maintenance mode, does not upgrade the source files
223
-	 * except the main .htaccess file
224
-	 *
225
-	 * @param string $currentVersion current version to upgrade to
226
-	 * @param string $installedVersion previous version from which to upgrade from
227
-	 *
228
-	 * @throws \Exception
229
-	 */
230
-	private function doUpgrade($currentVersion, $installedVersion) {
231
-		// Stop update if the update is over several major versions
232
-		$allowedPreviousVersions = $this->getAllowedPreviousVersions();
233
-		if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
234
-			throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
235
-		}
236
-
237
-		// Update .htaccess files
238
-		try {
239
-			Setup::updateHtaccess();
240
-			Setup::protectDataDirectory();
241
-		} catch (\Exception $e) {
242
-			throw new \Exception($e->getMessage());
243
-		}
244
-
245
-		// create empty file in data dir, so we can later find
246
-		// out that this is indeed an ownCloud data directory
247
-		// (in case it didn't exist before)
248
-		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
249
-
250
-		// pre-upgrade repairs
251
-		$repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
252
-		$repair->run();
253
-
254
-		$this->doCoreUpgrade();
255
-
256
-		try {
257
-			// TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
258
-			Setup::installBackgroundJobs();
259
-		} catch (\Exception $e) {
260
-			throw new \Exception($e->getMessage());
261
-		}
262
-
263
-		// update all shipped apps
264
-		$this->checkAppsRequirements();
265
-		$this->doAppUpgrade();
266
-
267
-		// Update the appfetchers version so it downloads the correct list from the appstore
268
-		\OC::$server->getAppFetcher()->setVersion($currentVersion);
269
-
270
-		// upgrade appstore apps
271
-		$this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps());
272
-
273
-		// install new shipped apps on upgrade
274
-		OC_App::loadApps('authentication');
275
-		$errors = Installer::installShippedApps(true);
276
-		foreach ($errors as $appId => $exception) {
277
-			/** @var \Exception $exception */
278
-			$this->log->logException($exception, ['app' => $appId]);
279
-			$this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
280
-		}
281
-
282
-		// post-upgrade repairs
283
-		$repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher());
284
-		$repair->run();
285
-
286
-		//Invalidate update feed
287
-		$this->config->setAppValue('core', 'lastupdatedat', 0);
288
-
289
-		// Check for code integrity if not disabled
290
-		if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
291
-			$this->emit('\OC\Updater', 'startCheckCodeIntegrity');
292
-			$this->checker->runInstanceVerification();
293
-			$this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
294
-		}
295
-
296
-		// only set the final version if everything went well
297
-		$this->config->setSystemValue('version', implode('.', Util::getVersion()));
298
-		$this->config->setAppValue('core', 'vendor', $this->getVendor());
299
-	}
300
-
301
-	protected function doCoreUpgrade() {
302
-		$this->emit('\OC\Updater', 'dbUpgradeBefore');
303
-
304
-		// execute core migrations
305
-		$ms = new MigrationService('core', \OC::$server->getDatabaseConnection());
306
-		$ms->migrate();
307
-
308
-		$this->emit('\OC\Updater', 'dbUpgrade');
309
-	}
310
-
311
-	/**
312
-	 * @param string $version the oc version to check app compatibility with
313
-	 */
314
-	protected function checkAppUpgrade($version) {
315
-		$apps = \OC_App::getEnabledApps();
316
-		$this->emit('\OC\Updater', 'appUpgradeCheckBefore');
317
-
318
-		$appManager = \OC::$server->getAppManager();
319
-		foreach ($apps as $appId) {
320
-			$info = \OC_App::getAppInfo($appId);
321
-			$compatible = \OC_App::isAppCompatible($version, $info);
322
-			$isShipped = $appManager->isShipped($appId);
323
-
324
-			if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) {
325
-				/**
326
-				 * FIXME: The preupdate check is performed before the database migration, otherwise database changes
327
-				 * are not possible anymore within it. - Consider this when touching the code.
328
-				 * @link https://github.com/owncloud/core/issues/10980
329
-				 * @see \OC_App::updateApp
330
-				 */
331
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
332
-					$this->includePreUpdate($appId);
333
-				}
334
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
335
-					$this->emit('\OC\Updater', 'appSimulateUpdate', array($appId));
336
-					\OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml');
337
-				}
338
-			}
339
-		}
340
-
341
-		$this->emit('\OC\Updater', 'appUpgradeCheck');
342
-	}
343
-
344
-	/**
345
-	 * Includes the pre-update file. Done here to prevent namespace mixups.
346
-	 * @param string $appId
347
-	 */
348
-	private function includePreUpdate($appId) {
349
-		include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
350
-	}
351
-
352
-	/**
353
-	 * upgrades all apps within a major ownCloud upgrade. Also loads "priority"
354
-	 * (types authentication, filesystem, logging, in that order) afterwards.
355
-	 *
356
-	 * @throws NeedsUpdateException
357
-	 */
358
-	protected function doAppUpgrade() {
359
-		$apps = \OC_App::getEnabledApps();
360
-		$priorityTypes = array('authentication', 'filesystem', 'logging');
361
-		$pseudoOtherType = 'other';
362
-		$stacks = array($pseudoOtherType => array());
363
-
364
-		foreach ($apps as $appId) {
365
-			$priorityType = false;
366
-			foreach ($priorityTypes as $type) {
367
-				if(!isset($stacks[$type])) {
368
-					$stacks[$type] = array();
369
-				}
370
-				if (\OC_App::isType($appId, $type)) {
371
-					$stacks[$type][] = $appId;
372
-					$priorityType = true;
373
-					break;
374
-				}
375
-			}
376
-			if (!$priorityType) {
377
-				$stacks[$pseudoOtherType][] = $appId;
378
-			}
379
-		}
380
-		foreach ($stacks as $type => $stack) {
381
-			foreach ($stack as $appId) {
382
-				if (\OC_App::shouldUpgrade($appId)) {
383
-					$this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]);
384
-					\OC_App::updateApp($appId);
385
-					$this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
386
-				}
387
-				if($type !== $pseudoOtherType) {
388
-					// load authentication, filesystem and logging apps after
389
-					// upgrading them. Other apps my need to rely on modifying
390
-					// user and/or filesystem aspects.
391
-					\OC_App::loadApp($appId);
392
-				}
393
-			}
394
-		}
395
-	}
396
-
397
-	/**
398
-	 * check if the current enabled apps are compatible with the current
399
-	 * ownCloud version. disable them if not.
400
-	 * This is important if you upgrade ownCloud and have non ported 3rd
401
-	 * party apps installed.
402
-	 *
403
-	 * @return array
404
-	 * @throws \Exception
405
-	 */
406
-	private function checkAppsRequirements() {
407
-		$isCoreUpgrade = $this->isCodeUpgrade();
408
-		$apps = OC_App::getEnabledApps();
409
-		$version = Util::getVersion();
410
-		$disabledApps = [];
411
-		$appManager = \OC::$server->getAppManager();
412
-		foreach ($apps as $app) {
413
-			// check if the app is compatible with this version of ownCloud
414
-			$info = OC_App::getAppInfo($app);
415
-			if(!OC_App::isAppCompatible($version, $info)) {
416
-				if ($appManager->isShipped($app)) {
417
-					throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
418
-				}
419
-				OC_App::disable($app);
420
-				$this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app));
421
-			}
422
-			// no need to disable any app in case this is a non-core upgrade
423
-			if (!$isCoreUpgrade) {
424
-				continue;
425
-			}
426
-			// shipped apps will remain enabled
427
-			if ($appManager->isShipped($app)) {
428
-				continue;
429
-			}
430
-			// authentication and session apps will remain enabled as well
431
-			if (OC_App::isType($app, ['session', 'authentication'])) {
432
-				continue;
433
-			}
434
-
435
-			// disable any other 3rd party apps if not overriden
436
-			if(!$this->skip3rdPartyAppsDisable) {
437
-				\OC_App::disable($app);
438
-				$disabledApps[]= $app;
439
-				$this->emit('\OC\Updater', 'thirdPartyAppDisabled', array($app));
440
-			};
441
-		}
442
-		return $disabledApps;
443
-	}
444
-
445
-	/**
446
-	 * @return bool
447
-	 */
448
-	private function isCodeUpgrade() {
449
-		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
450
-		$currentVersion = implode('.', Util::getVersion());
451
-		if (version_compare($currentVersion, $installedVersion, '>')) {
452
-			return true;
453
-		}
454
-		return false;
455
-	}
456
-
457
-	/**
458
-	 * @param array $disabledApps
459
-	 * @throws \Exception
460
-	 */
461
-	private function upgradeAppStoreApps(array $disabledApps) {
462
-		foreach($disabledApps as $app) {
463
-			try {
464
-				$installer = new Installer(
465
-					\OC::$server->getAppFetcher(),
466
-					\OC::$server->getHTTPClientService(),
467
-					\OC::$server->getTempManager(),
468
-					$this->log,
469
-					\OC::$server->getConfig()
470
-				);
471
-				$this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
472
-				if (Installer::isUpdateAvailable($app, \OC::$server->getAppFetcher())) {
473
-					$this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
474
-					$installer->updateAppstoreApp($app);
475
-				}
476
-				$this->emit('\OC\Updater', 'checkAppStoreApp', [$app]);
477
-			} catch (\Exception $ex) {
478
-				$this->log->logException($ex, ['app' => 'core']);
479
-			}
480
-		}
481
-	}
482
-
483
-	/**
484
-	 * Forward messages emitted by the repair routine
485
-	 */
486
-	private function emitRepairEvents() {
487
-		$dispatcher = \OC::$server->getEventDispatcher();
488
-		$dispatcher->addListener('\OC\Repair::warning', function ($event) {
489
-			if ($event instanceof GenericEvent) {
490
-				$this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
491
-			}
492
-		});
493
-		$dispatcher->addListener('\OC\Repair::error', function ($event) {
494
-			if ($event instanceof GenericEvent) {
495
-				$this->emit('\OC\Updater', 'repairError', $event->getArguments());
496
-			}
497
-		});
498
-		$dispatcher->addListener('\OC\Repair::info', function ($event) {
499
-			if ($event instanceof GenericEvent) {
500
-				$this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
501
-			}
502
-		});
503
-		$dispatcher->addListener('\OC\Repair::step', function ($event) {
504
-			if ($event instanceof GenericEvent) {
505
-				$this->emit('\OC\Updater', 'repairStep', $event->getArguments());
506
-			}
507
-		});
508
-	}
509
-
510
-	private function logAllEvents() {
511
-		$log = $this->log;
512
-
513
-		$dispatcher = \OC::$server->getEventDispatcher();
514
-		$dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($log) {
515
-			if (!$event instanceof GenericEvent) {
516
-				return;
517
-			}
518
-			$log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
519
-		});
520
-		$dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) {
521
-			if (!$event instanceof GenericEvent) {
522
-				return;
523
-			}
524
-			$log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
525
-		});
526
-
527
-		$repairListener = function($event) use ($log) {
528
-			if (!$event instanceof GenericEvent) {
529
-				return;
530
-			}
531
-			switch ($event->getSubject()) {
532
-				case '\OC\Repair::startProgress':
533
-					$log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
534
-					break;
535
-				case '\OC\Repair::advance':
536
-					$desc = $event->getArgument(1);
537
-					if (empty($desc)) {
538
-						$desc = '';
539
-					}
540
-					$log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
541
-
542
-					break;
543
-				case '\OC\Repair::finishProgress':
544
-					$log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
545
-					break;
546
-				case '\OC\Repair::step':
547
-					$log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
548
-					break;
549
-				case '\OC\Repair::info':
550
-					$log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
551
-					break;
552
-				case '\OC\Repair::warning':
553
-					$log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
554
-					break;
555
-				case '\OC\Repair::error':
556
-					$log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
557
-					break;
558
-			}
559
-		};
560
-
561
-		$dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
562
-		$dispatcher->addListener('\OC\Repair::advance', $repairListener);
563
-		$dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
564
-		$dispatcher->addListener('\OC\Repair::step', $repairListener);
565
-		$dispatcher->addListener('\OC\Repair::info', $repairListener);
566
-		$dispatcher->addListener('\OC\Repair::warning', $repairListener);
567
-		$dispatcher->addListener('\OC\Repair::error', $repairListener);
568
-
569
-
570
-		$this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) {
571
-			$log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
572
-		});
573
-		$this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) {
574
-			$log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
575
-		});
576
-		$this->listen('\OC\Updater', 'maintenanceActive', function () use($log) {
577
-			$log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
578
-		});
579
-		$this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) {
580
-			if ($success) {
581
-				$log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
582
-			} else {
583
-				$log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
584
-			}
585
-		});
586
-		$this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) {
587
-			$log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
588
-		});
589
-		$this->listen('\OC\Updater', 'dbUpgrade', function () use($log) {
590
-			$log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
591
-		});
592
-		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) {
593
-			$log->info('\OC\Updater::dbSimulateUpgradeBefore: Checking whether the database schema can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
594
-		});
595
-		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) {
596
-			$log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
597
-		});
598
-		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) {
599
-			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
600
-		});
601
-		$this->listen('\OC\Updater', 'thirdPartyAppDisabled', function ($app) use ($log) {
602
-			$log->info('\OC\Updater::thirdPartyAppDisabled: Disabled 3rd-party app: ' . $app, ['app' => 'updater']);
603
-		});
604
-		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use($log) {
605
-			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
606
-		});
607
-		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) {
608
-			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
609
-		});
610
-		$this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use($log) {
611
-			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
612
-		});
613
-		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
614
-			$log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
615
-		});
616
-		$this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
617
-			$log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
618
-		});
619
-		$this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
620
-			$log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
621
-		});
622
-		$this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
623
-			$log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
624
-		});
625
-		$this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
626
-			$log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
627
-		});
628
-		$this->listen('\OC\Updater', 'failure', function ($message) use($log) {
629
-			$log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
630
-		});
631
-		$this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) {
632
-			$log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
633
-		});
634
-		$this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) {
635
-			$log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
636
-		});
637
-		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) {
638
-			$log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
639
-		});
640
-		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) {
641
-			$log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
642
-		});
643
-
644
-	}
55
+    /** @var ILogger $log */
56
+    private $log;
57
+
58
+    /** @var IConfig */
59
+    private $config;
60
+
61
+    /** @var Checker */
62
+    private $checker;
63
+
64
+    /** @var bool */
65
+    private $skip3rdPartyAppsDisable;
66
+
67
+    private $logLevelNames = [
68
+        0 => 'Debug',
69
+        1 => 'Info',
70
+        2 => 'Warning',
71
+        3 => 'Error',
72
+        4 => 'Fatal',
73
+    ];
74
+
75
+    /**
76
+     * @param IConfig $config
77
+     * @param Checker $checker
78
+     * @param ILogger $log
79
+     */
80
+    public function __construct(IConfig $config,
81
+                                Checker $checker,
82
+                                ILogger $log = null) {
83
+        $this->log = $log;
84
+        $this->config = $config;
85
+        $this->checker = $checker;
86
+
87
+        // If at least PHP 7.0.0 is used we don't need to disable apps as we catch
88
+        // fatal errors and exceptions and disable the app just instead.
89
+        if(version_compare(phpversion(), '7.0.0', '>=')) {
90
+            $this->skip3rdPartyAppsDisable = true;
91
+        }
92
+    }
93
+
94
+    /**
95
+     * Sets whether the update disables 3rd party apps.
96
+     * This can be set to true to skip the disable.
97
+     *
98
+     * @param bool $flag false to not disable, true otherwise
99
+     */
100
+    public function setSkip3rdPartyAppsDisable($flag) {
101
+        $this->skip3rdPartyAppsDisable = $flag;
102
+    }
103
+
104
+    /**
105
+     * runs the update actions in maintenance mode, does not upgrade the source files
106
+     * except the main .htaccess file
107
+     *
108
+     * @return bool true if the operation succeeded, false otherwise
109
+     */
110
+    public function upgrade() {
111
+        $this->emitRepairEvents();
112
+        $this->logAllEvents();
113
+
114
+        $logLevel = $this->config->getSystemValue('loglevel', Util::WARN);
115
+        $this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
116
+        $this->config->setSystemValue('loglevel', Util::DEBUG);
117
+
118
+        $wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false);
119
+
120
+        if(!$wasMaintenanceModeEnabled) {
121
+            $this->config->setSystemValue('maintenance', true);
122
+            $this->emit('\OC\Updater', 'maintenanceEnabled');
123
+        }
124
+
125
+        $installedVersion = $this->config->getSystemValue('version', '0.0.0');
126
+        $currentVersion = implode('.', \OCP\Util::getVersion());
127
+        $this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core'));
128
+
129
+        $success = true;
130
+        try {
131
+            $this->doUpgrade($currentVersion, $installedVersion);
132
+        } catch (HintException $exception) {
133
+            $this->log->logException($exception, ['app' => 'core']);
134
+            $this->emit('\OC\Updater', 'failure', array($exception->getMessage() . ': ' .$exception->getHint()));
135
+            $success = false;
136
+        } catch (\Exception $exception) {
137
+            $this->log->logException($exception, ['app' => 'core']);
138
+            $this->emit('\OC\Updater', 'failure', array(get_class($exception) . ': ' .$exception->getMessage()));
139
+            $success = false;
140
+        }
141
+
142
+        $this->emit('\OC\Updater', 'updateEnd', array($success));
143
+
144
+        if(!$wasMaintenanceModeEnabled && $success) {
145
+            $this->config->setSystemValue('maintenance', false);
146
+            $this->emit('\OC\Updater', 'maintenanceDisabled');
147
+        } else {
148
+            $this->emit('\OC\Updater', 'maintenanceActive');
149
+        }
150
+
151
+        $this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
152
+        $this->config->setSystemValue('loglevel', $logLevel);
153
+        $this->config->setSystemValue('installed', true);
154
+
155
+        return $success;
156
+    }
157
+
158
+    /**
159
+     * Return version from which this version is allowed to upgrade from
160
+     *
161
+     * @return array allowed previous versions per vendor
162
+     */
163
+    private function getAllowedPreviousVersions() {
164
+        // this should really be a JSON file
165
+        require \OC::$SERVERROOT . '/version.php';
166
+        /** @var array $OC_VersionCanBeUpgradedFrom */
167
+        return $OC_VersionCanBeUpgradedFrom;
168
+    }
169
+
170
+    /**
171
+     * Return vendor from which this version was published
172
+     *
173
+     * @return string Get the vendor
174
+     */
175
+    private function getVendor() {
176
+        // this should really be a JSON file
177
+        require \OC::$SERVERROOT . '/version.php';
178
+        /** @var string $vendor */
179
+        return (string) $vendor;
180
+    }
181
+
182
+    /**
183
+     * Whether an upgrade to a specified version is possible
184
+     * @param string $oldVersion
185
+     * @param string $newVersion
186
+     * @param array $allowedPreviousVersions
187
+     * @return bool
188
+     */
189
+    public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
190
+        $version = explode('.', $oldVersion);
191
+        $majorMinor = $version[0] . '.' . $version[1];
192
+
193
+        $currentVendor = $this->config->getAppValue('core', 'vendor', '');
194
+
195
+        // Vendor was not set correctly on install, so we have to white-list known versions
196
+        if ($currentVendor === '') {
197
+            if (in_array($oldVersion, [
198
+                '11.0.2.7',
199
+                '11.0.1.2',
200
+                '11.0.0.10',
201
+            ], true)) {
202
+                $currentVendor = 'nextcloud';
203
+            } else if (in_array($oldVersion, [
204
+                    '10.0.0.12',
205
+                ], true)) {
206
+                $currentVendor = 'owncloud';
207
+            }
208
+        }
209
+
210
+        if ($currentVendor === 'nextcloud') {
211
+            return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
212
+                && (version_compare($oldVersion, $newVersion, '<=') ||
213
+                    $this->config->getSystemValue('debug', false));
214
+        }
215
+
216
+        // Check if the instance can be migrated
217
+        return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) ||
218
+            isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
219
+    }
220
+
221
+    /**
222
+     * runs the update actions in maintenance mode, does not upgrade the source files
223
+     * except the main .htaccess file
224
+     *
225
+     * @param string $currentVersion current version to upgrade to
226
+     * @param string $installedVersion previous version from which to upgrade from
227
+     *
228
+     * @throws \Exception
229
+     */
230
+    private function doUpgrade($currentVersion, $installedVersion) {
231
+        // Stop update if the update is over several major versions
232
+        $allowedPreviousVersions = $this->getAllowedPreviousVersions();
233
+        if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
234
+            throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
235
+        }
236
+
237
+        // Update .htaccess files
238
+        try {
239
+            Setup::updateHtaccess();
240
+            Setup::protectDataDirectory();
241
+        } catch (\Exception $e) {
242
+            throw new \Exception($e->getMessage());
243
+        }
244
+
245
+        // create empty file in data dir, so we can later find
246
+        // out that this is indeed an ownCloud data directory
247
+        // (in case it didn't exist before)
248
+        file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
249
+
250
+        // pre-upgrade repairs
251
+        $repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
252
+        $repair->run();
253
+
254
+        $this->doCoreUpgrade();
255
+
256
+        try {
257
+            // TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
258
+            Setup::installBackgroundJobs();
259
+        } catch (\Exception $e) {
260
+            throw new \Exception($e->getMessage());
261
+        }
262
+
263
+        // update all shipped apps
264
+        $this->checkAppsRequirements();
265
+        $this->doAppUpgrade();
266
+
267
+        // Update the appfetchers version so it downloads the correct list from the appstore
268
+        \OC::$server->getAppFetcher()->setVersion($currentVersion);
269
+
270
+        // upgrade appstore apps
271
+        $this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps());
272
+
273
+        // install new shipped apps on upgrade
274
+        OC_App::loadApps('authentication');
275
+        $errors = Installer::installShippedApps(true);
276
+        foreach ($errors as $appId => $exception) {
277
+            /** @var \Exception $exception */
278
+            $this->log->logException($exception, ['app' => $appId]);
279
+            $this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
280
+        }
281
+
282
+        // post-upgrade repairs
283
+        $repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher());
284
+        $repair->run();
285
+
286
+        //Invalidate update feed
287
+        $this->config->setAppValue('core', 'lastupdatedat', 0);
288
+
289
+        // Check for code integrity if not disabled
290
+        if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
291
+            $this->emit('\OC\Updater', 'startCheckCodeIntegrity');
292
+            $this->checker->runInstanceVerification();
293
+            $this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
294
+        }
295
+
296
+        // only set the final version if everything went well
297
+        $this->config->setSystemValue('version', implode('.', Util::getVersion()));
298
+        $this->config->setAppValue('core', 'vendor', $this->getVendor());
299
+    }
300
+
301
+    protected function doCoreUpgrade() {
302
+        $this->emit('\OC\Updater', 'dbUpgradeBefore');
303
+
304
+        // execute core migrations
305
+        $ms = new MigrationService('core', \OC::$server->getDatabaseConnection());
306
+        $ms->migrate();
307
+
308
+        $this->emit('\OC\Updater', 'dbUpgrade');
309
+    }
310
+
311
+    /**
312
+     * @param string $version the oc version to check app compatibility with
313
+     */
314
+    protected function checkAppUpgrade($version) {
315
+        $apps = \OC_App::getEnabledApps();
316
+        $this->emit('\OC\Updater', 'appUpgradeCheckBefore');
317
+
318
+        $appManager = \OC::$server->getAppManager();
319
+        foreach ($apps as $appId) {
320
+            $info = \OC_App::getAppInfo($appId);
321
+            $compatible = \OC_App::isAppCompatible($version, $info);
322
+            $isShipped = $appManager->isShipped($appId);
323
+
324
+            if ($compatible && $isShipped && \OC_App::shouldUpgrade($appId)) {
325
+                /**
326
+                 * FIXME: The preupdate check is performed before the database migration, otherwise database changes
327
+                 * are not possible anymore within it. - Consider this when touching the code.
328
+                 * @link https://github.com/owncloud/core/issues/10980
329
+                 * @see \OC_App::updateApp
330
+                 */
331
+                if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
332
+                    $this->includePreUpdate($appId);
333
+                }
334
+                if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
335
+                    $this->emit('\OC\Updater', 'appSimulateUpdate', array($appId));
336
+                    \OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml');
337
+                }
338
+            }
339
+        }
340
+
341
+        $this->emit('\OC\Updater', 'appUpgradeCheck');
342
+    }
343
+
344
+    /**
345
+     * Includes the pre-update file. Done here to prevent namespace mixups.
346
+     * @param string $appId
347
+     */
348
+    private function includePreUpdate($appId) {
349
+        include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
350
+    }
351
+
352
+    /**
353
+     * upgrades all apps within a major ownCloud upgrade. Also loads "priority"
354
+     * (types authentication, filesystem, logging, in that order) afterwards.
355
+     *
356
+     * @throws NeedsUpdateException
357
+     */
358
+    protected function doAppUpgrade() {
359
+        $apps = \OC_App::getEnabledApps();
360
+        $priorityTypes = array('authentication', 'filesystem', 'logging');
361
+        $pseudoOtherType = 'other';
362
+        $stacks = array($pseudoOtherType => array());
363
+
364
+        foreach ($apps as $appId) {
365
+            $priorityType = false;
366
+            foreach ($priorityTypes as $type) {
367
+                if(!isset($stacks[$type])) {
368
+                    $stacks[$type] = array();
369
+                }
370
+                if (\OC_App::isType($appId, $type)) {
371
+                    $stacks[$type][] = $appId;
372
+                    $priorityType = true;
373
+                    break;
374
+                }
375
+            }
376
+            if (!$priorityType) {
377
+                $stacks[$pseudoOtherType][] = $appId;
378
+            }
379
+        }
380
+        foreach ($stacks as $type => $stack) {
381
+            foreach ($stack as $appId) {
382
+                if (\OC_App::shouldUpgrade($appId)) {
383
+                    $this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]);
384
+                    \OC_App::updateApp($appId);
385
+                    $this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
386
+                }
387
+                if($type !== $pseudoOtherType) {
388
+                    // load authentication, filesystem and logging apps after
389
+                    // upgrading them. Other apps my need to rely on modifying
390
+                    // user and/or filesystem aspects.
391
+                    \OC_App::loadApp($appId);
392
+                }
393
+            }
394
+        }
395
+    }
396
+
397
+    /**
398
+     * check if the current enabled apps are compatible with the current
399
+     * ownCloud version. disable them if not.
400
+     * This is important if you upgrade ownCloud and have non ported 3rd
401
+     * party apps installed.
402
+     *
403
+     * @return array
404
+     * @throws \Exception
405
+     */
406
+    private function checkAppsRequirements() {
407
+        $isCoreUpgrade = $this->isCodeUpgrade();
408
+        $apps = OC_App::getEnabledApps();
409
+        $version = Util::getVersion();
410
+        $disabledApps = [];
411
+        $appManager = \OC::$server->getAppManager();
412
+        foreach ($apps as $app) {
413
+            // check if the app is compatible with this version of ownCloud
414
+            $info = OC_App::getAppInfo($app);
415
+            if(!OC_App::isAppCompatible($version, $info)) {
416
+                if ($appManager->isShipped($app)) {
417
+                    throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
418
+                }
419
+                OC_App::disable($app);
420
+                $this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app));
421
+            }
422
+            // no need to disable any app in case this is a non-core upgrade
423
+            if (!$isCoreUpgrade) {
424
+                continue;
425
+            }
426
+            // shipped apps will remain enabled
427
+            if ($appManager->isShipped($app)) {
428
+                continue;
429
+            }
430
+            // authentication and session apps will remain enabled as well
431
+            if (OC_App::isType($app, ['session', 'authentication'])) {
432
+                continue;
433
+            }
434
+
435
+            // disable any other 3rd party apps if not overriden
436
+            if(!$this->skip3rdPartyAppsDisable) {
437
+                \OC_App::disable($app);
438
+                $disabledApps[]= $app;
439
+                $this->emit('\OC\Updater', 'thirdPartyAppDisabled', array($app));
440
+            };
441
+        }
442
+        return $disabledApps;
443
+    }
444
+
445
+    /**
446
+     * @return bool
447
+     */
448
+    private function isCodeUpgrade() {
449
+        $installedVersion = $this->config->getSystemValue('version', '0.0.0');
450
+        $currentVersion = implode('.', Util::getVersion());
451
+        if (version_compare($currentVersion, $installedVersion, '>')) {
452
+            return true;
453
+        }
454
+        return false;
455
+    }
456
+
457
+    /**
458
+     * @param array $disabledApps
459
+     * @throws \Exception
460
+     */
461
+    private function upgradeAppStoreApps(array $disabledApps) {
462
+        foreach($disabledApps as $app) {
463
+            try {
464
+                $installer = new Installer(
465
+                    \OC::$server->getAppFetcher(),
466
+                    \OC::$server->getHTTPClientService(),
467
+                    \OC::$server->getTempManager(),
468
+                    $this->log,
469
+                    \OC::$server->getConfig()
470
+                );
471
+                $this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
472
+                if (Installer::isUpdateAvailable($app, \OC::$server->getAppFetcher())) {
473
+                    $this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
474
+                    $installer->updateAppstoreApp($app);
475
+                }
476
+                $this->emit('\OC\Updater', 'checkAppStoreApp', [$app]);
477
+            } catch (\Exception $ex) {
478
+                $this->log->logException($ex, ['app' => 'core']);
479
+            }
480
+        }
481
+    }
482
+
483
+    /**
484
+     * Forward messages emitted by the repair routine
485
+     */
486
+    private function emitRepairEvents() {
487
+        $dispatcher = \OC::$server->getEventDispatcher();
488
+        $dispatcher->addListener('\OC\Repair::warning', function ($event) {
489
+            if ($event instanceof GenericEvent) {
490
+                $this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
491
+            }
492
+        });
493
+        $dispatcher->addListener('\OC\Repair::error', function ($event) {
494
+            if ($event instanceof GenericEvent) {
495
+                $this->emit('\OC\Updater', 'repairError', $event->getArguments());
496
+            }
497
+        });
498
+        $dispatcher->addListener('\OC\Repair::info', function ($event) {
499
+            if ($event instanceof GenericEvent) {
500
+                $this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
501
+            }
502
+        });
503
+        $dispatcher->addListener('\OC\Repair::step', function ($event) {
504
+            if ($event instanceof GenericEvent) {
505
+                $this->emit('\OC\Updater', 'repairStep', $event->getArguments());
506
+            }
507
+        });
508
+    }
509
+
510
+    private function logAllEvents() {
511
+        $log = $this->log;
512
+
513
+        $dispatcher = \OC::$server->getEventDispatcher();
514
+        $dispatcher->addListener('\OC\DB\Migrator::executeSql', function($event) use ($log) {
515
+            if (!$event instanceof GenericEvent) {
516
+                return;
517
+            }
518
+            $log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
519
+        });
520
+        $dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) {
521
+            if (!$event instanceof GenericEvent) {
522
+                return;
523
+            }
524
+            $log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
525
+        });
526
+
527
+        $repairListener = function($event) use ($log) {
528
+            if (!$event instanceof GenericEvent) {
529
+                return;
530
+            }
531
+            switch ($event->getSubject()) {
532
+                case '\OC\Repair::startProgress':
533
+                    $log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
534
+                    break;
535
+                case '\OC\Repair::advance':
536
+                    $desc = $event->getArgument(1);
537
+                    if (empty($desc)) {
538
+                        $desc = '';
539
+                    }
540
+                    $log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
541
+
542
+                    break;
543
+                case '\OC\Repair::finishProgress':
544
+                    $log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
545
+                    break;
546
+                case '\OC\Repair::step':
547
+                    $log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
548
+                    break;
549
+                case '\OC\Repair::info':
550
+                    $log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
551
+                    break;
552
+                case '\OC\Repair::warning':
553
+                    $log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
554
+                    break;
555
+                case '\OC\Repair::error':
556
+                    $log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
557
+                    break;
558
+            }
559
+        };
560
+
561
+        $dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
562
+        $dispatcher->addListener('\OC\Repair::advance', $repairListener);
563
+        $dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
564
+        $dispatcher->addListener('\OC\Repair::step', $repairListener);
565
+        $dispatcher->addListener('\OC\Repair::info', $repairListener);
566
+        $dispatcher->addListener('\OC\Repair::warning', $repairListener);
567
+        $dispatcher->addListener('\OC\Repair::error', $repairListener);
568
+
569
+
570
+        $this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) {
571
+            $log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
572
+        });
573
+        $this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) {
574
+            $log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
575
+        });
576
+        $this->listen('\OC\Updater', 'maintenanceActive', function () use($log) {
577
+            $log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
578
+        });
579
+        $this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) {
580
+            if ($success) {
581
+                $log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
582
+            } else {
583
+                $log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
584
+            }
585
+        });
586
+        $this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) {
587
+            $log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
588
+        });
589
+        $this->listen('\OC\Updater', 'dbUpgrade', function () use($log) {
590
+            $log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
591
+        });
592
+        $this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) {
593
+            $log->info('\OC\Updater::dbSimulateUpgradeBefore: Checking whether the database schema can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
594
+        });
595
+        $this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) {
596
+            $log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
597
+        });
598
+        $this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) {
599
+            $log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
600
+        });
601
+        $this->listen('\OC\Updater', 'thirdPartyAppDisabled', function ($app) use ($log) {
602
+            $log->info('\OC\Updater::thirdPartyAppDisabled: Disabled 3rd-party app: ' . $app, ['app' => 'updater']);
603
+        });
604
+        $this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use($log) {
605
+            $log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
606
+        });
607
+        $this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) {
608
+            $log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
609
+        });
610
+        $this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use($log) {
611
+            $log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
612
+        });
613
+        $this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
614
+            $log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
615
+        });
616
+        $this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
617
+            $log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
618
+        });
619
+        $this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
620
+            $log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
621
+        });
622
+        $this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
623
+            $log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
624
+        });
625
+        $this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
626
+            $log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
627
+        });
628
+        $this->listen('\OC\Updater', 'failure', function ($message) use($log) {
629
+            $log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
630
+        });
631
+        $this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) {
632
+            $log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
633
+        });
634
+        $this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) {
635
+            $log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
636
+        });
637
+        $this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) {
638
+            $log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
639
+        });
640
+        $this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) {
641
+            $log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
642
+        });
643
+
644
+    }
645 645
 
646 646
 }
647 647
 
Please login to merge, or discard this patch.
Spacing   +70 added lines, -70 removed lines patch added patch discarded remove patch
@@ -86,7 +86,7 @@  discard block
 block discarded – undo
86 86
 
87 87
 		// If at least PHP 7.0.0 is used we don't need to disable apps as we catch
88 88
 		// fatal errors and exceptions and disable the app just instead.
89
-		if(version_compare(phpversion(), '7.0.0', '>=')) {
89
+		if (version_compare(phpversion(), '7.0.0', '>=')) {
90 90
 			$this->skip3rdPartyAppsDisable = true;
91 91
 		}
92 92
 	}
@@ -112,43 +112,43 @@  discard block
 block discarded – undo
112 112
 		$this->logAllEvents();
113 113
 
114 114
 		$logLevel = $this->config->getSystemValue('loglevel', Util::WARN);
115
-		$this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
115
+		$this->emit('\OC\Updater', 'setDebugLogLevel', [$logLevel, $this->logLevelNames[$logLevel]]);
116 116
 		$this->config->setSystemValue('loglevel', Util::DEBUG);
117 117
 
118 118
 		$wasMaintenanceModeEnabled = $this->config->getSystemValue('maintenance', false);
119 119
 
120
-		if(!$wasMaintenanceModeEnabled) {
120
+		if (!$wasMaintenanceModeEnabled) {
121 121
 			$this->config->setSystemValue('maintenance', true);
122 122
 			$this->emit('\OC\Updater', 'maintenanceEnabled');
123 123
 		}
124 124
 
125 125
 		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
126 126
 		$currentVersion = implode('.', \OCP\Util::getVersion());
127
-		$this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, array('app' => 'core'));
127
+		$this->log->debug('starting upgrade from '.$installedVersion.' to '.$currentVersion, array('app' => 'core'));
128 128
 
129 129
 		$success = true;
130 130
 		try {
131 131
 			$this->doUpgrade($currentVersion, $installedVersion);
132 132
 		} catch (HintException $exception) {
133 133
 			$this->log->logException($exception, ['app' => 'core']);
134
-			$this->emit('\OC\Updater', 'failure', array($exception->getMessage() . ': ' .$exception->getHint()));
134
+			$this->emit('\OC\Updater', 'failure', array($exception->getMessage().': '.$exception->getHint()));
135 135
 			$success = false;
136 136
 		} catch (\Exception $exception) {
137 137
 			$this->log->logException($exception, ['app' => 'core']);
138
-			$this->emit('\OC\Updater', 'failure', array(get_class($exception) . ': ' .$exception->getMessage()));
138
+			$this->emit('\OC\Updater', 'failure', array(get_class($exception).': '.$exception->getMessage()));
139 139
 			$success = false;
140 140
 		}
141 141
 
142 142
 		$this->emit('\OC\Updater', 'updateEnd', array($success));
143 143
 
144
-		if(!$wasMaintenanceModeEnabled && $success) {
144
+		if (!$wasMaintenanceModeEnabled && $success) {
145 145
 			$this->config->setSystemValue('maintenance', false);
146 146
 			$this->emit('\OC\Updater', 'maintenanceDisabled');
147 147
 		} else {
148 148
 			$this->emit('\OC\Updater', 'maintenanceActive');
149 149
 		}
150 150
 
151
-		$this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
151
+		$this->emit('\OC\Updater', 'resetLogLevel', [$logLevel, $this->logLevelNames[$logLevel]]);
152 152
 		$this->config->setSystemValue('loglevel', $logLevel);
153 153
 		$this->config->setSystemValue('installed', true);
154 154
 
@@ -162,7 +162,7 @@  discard block
 block discarded – undo
162 162
 	 */
163 163
 	private function getAllowedPreviousVersions() {
164 164
 		// this should really be a JSON file
165
-		require \OC::$SERVERROOT . '/version.php';
165
+		require \OC::$SERVERROOT.'/version.php';
166 166
 		/** @var array $OC_VersionCanBeUpgradedFrom */
167 167
 		return $OC_VersionCanBeUpgradedFrom;
168 168
 	}
@@ -174,7 +174,7 @@  discard block
 block discarded – undo
174 174
 	 */
175 175
 	private function getVendor() {
176 176
 		// this should really be a JSON file
177
-		require \OC::$SERVERROOT . '/version.php';
177
+		require \OC::$SERVERROOT.'/version.php';
178 178
 		/** @var string $vendor */
179 179
 		return (string) $vendor;
180 180
 	}
@@ -188,7 +188,7 @@  discard block
 block discarded – undo
188 188
 	 */
189 189
 	public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
190 190
 		$version = explode('.', $oldVersion);
191
-		$majorMinor = $version[0] . '.' . $version[1];
191
+		$majorMinor = $version[0].'.'.$version[1];
192 192
 
193 193
 		$currentVendor = $this->config->getAppValue('core', 'vendor', '');
194 194
 
@@ -245,7 +245,7 @@  discard block
 block discarded – undo
245 245
 		// create empty file in data dir, so we can later find
246 246
 		// out that this is indeed an ownCloud data directory
247 247
 		// (in case it didn't exist before)
248
-		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
248
+		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data').'/.ocdata', '');
249 249
 
250 250
 		// pre-upgrade repairs
251 251
 		$repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
@@ -276,7 +276,7 @@  discard block
 block discarded – undo
276 276
 		foreach ($errors as $appId => $exception) {
277 277
 			/** @var \Exception $exception */
278 278
 			$this->log->logException($exception, ['app' => $appId]);
279
-			$this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
279
+			$this->emit('\OC\Updater', 'failure', [$appId.': '.$exception->getMessage()]);
280 280
 		}
281 281
 
282 282
 		// post-upgrade repairs
@@ -287,7 +287,7 @@  discard block
 block discarded – undo
287 287
 		$this->config->setAppValue('core', 'lastupdatedat', 0);
288 288
 
289 289
 		// Check for code integrity if not disabled
290
-		if(\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
290
+		if (\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
291 291
 			$this->emit('\OC\Updater', 'startCheckCodeIntegrity');
292 292
 			$this->checker->runInstanceVerification();
293 293
 			$this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
@@ -328,12 +328,12 @@  discard block
 block discarded – undo
328 328
 				 * @link https://github.com/owncloud/core/issues/10980
329 329
 				 * @see \OC_App::updateApp
330 330
 				 */
331
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/preupdate.php')) {
331
+				if (file_exists(\OC_App::getAppPath($appId).'/appinfo/preupdate.php')) {
332 332
 					$this->includePreUpdate($appId);
333 333
 				}
334
-				if (file_exists(\OC_App::getAppPath($appId) . '/appinfo/database.xml')) {
334
+				if (file_exists(\OC_App::getAppPath($appId).'/appinfo/database.xml')) {
335 335
 					$this->emit('\OC\Updater', 'appSimulateUpdate', array($appId));
336
-					\OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId) . '/appinfo/database.xml');
336
+					\OC_DB::simulateUpdateDbFromStructure(\OC_App::getAppPath($appId).'/appinfo/database.xml');
337 337
 				}
338 338
 			}
339 339
 		}
@@ -346,7 +346,7 @@  discard block
 block discarded – undo
346 346
 	 * @param string $appId
347 347
 	 */
348 348
 	private function includePreUpdate($appId) {
349
-		include \OC_App::getAppPath($appId) . '/appinfo/preupdate.php';
349
+		include \OC_App::getAppPath($appId).'/appinfo/preupdate.php';
350 350
 	}
351 351
 
352 352
 	/**
@@ -364,7 +364,7 @@  discard block
 block discarded – undo
364 364
 		foreach ($apps as $appId) {
365 365
 			$priorityType = false;
366 366
 			foreach ($priorityTypes as $type) {
367
-				if(!isset($stacks[$type])) {
367
+				if (!isset($stacks[$type])) {
368 368
 					$stacks[$type] = array();
369 369
 				}
370 370
 				if (\OC_App::isType($appId, $type)) {
@@ -384,7 +384,7 @@  discard block
 block discarded – undo
384 384
 					\OC_App::updateApp($appId);
385 385
 					$this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
386 386
 				}
387
-				if($type !== $pseudoOtherType) {
387
+				if ($type !== $pseudoOtherType) {
388 388
 					// load authentication, filesystem and logging apps after
389 389
 					// upgrading them. Other apps my need to rely on modifying
390 390
 					// user and/or filesystem aspects.
@@ -412,9 +412,9 @@  discard block
 block discarded – undo
412 412
 		foreach ($apps as $app) {
413 413
 			// check if the app is compatible with this version of ownCloud
414 414
 			$info = OC_App::getAppInfo($app);
415
-			if(!OC_App::isAppCompatible($version, $info)) {
415
+			if (!OC_App::isAppCompatible($version, $info)) {
416 416
 				if ($appManager->isShipped($app)) {
417
-					throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
417
+					throw new \UnexpectedValueException('The files of the app "'.$app.'" were not correctly replaced before running the update');
418 418
 				}
419 419
 				OC_App::disable($app);
420 420
 				$this->emit('\OC\Updater', 'incompatibleAppDisabled', array($app));
@@ -433,9 +433,9 @@  discard block
 block discarded – undo
433 433
 			}
434 434
 
435 435
 			// disable any other 3rd party apps if not overriden
436
-			if(!$this->skip3rdPartyAppsDisable) {
436
+			if (!$this->skip3rdPartyAppsDisable) {
437 437
 				\OC_App::disable($app);
438
-				$disabledApps[]= $app;
438
+				$disabledApps[] = $app;
439 439
 				$this->emit('\OC\Updater', 'thirdPartyAppDisabled', array($app));
440 440
 			};
441 441
 		}
@@ -459,7 +459,7 @@  discard block
 block discarded – undo
459 459
 	 * @throws \Exception
460 460
 	 */
461 461
 	private function upgradeAppStoreApps(array $disabledApps) {
462
-		foreach($disabledApps as $app) {
462
+		foreach ($disabledApps as $app) {
463 463
 			try {
464 464
 				$installer = new Installer(
465 465
 					\OC::$server->getAppFetcher(),
@@ -485,22 +485,22 @@  discard block
 block discarded – undo
485 485
 	 */
486 486
 	private function emitRepairEvents() {
487 487
 		$dispatcher = \OC::$server->getEventDispatcher();
488
-		$dispatcher->addListener('\OC\Repair::warning', function ($event) {
488
+		$dispatcher->addListener('\OC\Repair::warning', function($event) {
489 489
 			if ($event instanceof GenericEvent) {
490 490
 				$this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
491 491
 			}
492 492
 		});
493
-		$dispatcher->addListener('\OC\Repair::error', function ($event) {
493
+		$dispatcher->addListener('\OC\Repair::error', function($event) {
494 494
 			if ($event instanceof GenericEvent) {
495 495
 				$this->emit('\OC\Updater', 'repairError', $event->getArguments());
496 496
 			}
497 497
 		});
498
-		$dispatcher->addListener('\OC\Repair::info', function ($event) {
498
+		$dispatcher->addListener('\OC\Repair::info', function($event) {
499 499
 			if ($event instanceof GenericEvent) {
500 500
 				$this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
501 501
 			}
502 502
 		});
503
-		$dispatcher->addListener('\OC\Repair::step', function ($event) {
503
+		$dispatcher->addListener('\OC\Repair::step', function($event) {
504 504
 			if ($event instanceof GenericEvent) {
505 505
 				$this->emit('\OC\Updater', 'repairStep', $event->getArguments());
506 506
 			}
@@ -515,13 +515,13 @@  discard block
 block discarded – undo
515 515
 			if (!$event instanceof GenericEvent) {
516 516
 				return;
517 517
 			}
518
-			$log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
518
+			$log->info('\OC\DB\Migrator::executeSql: '.$event->getSubject().' ('.$event->getArgument(0).' of '.$event->getArgument(1).')', ['app' => 'updater']);
519 519
 		});
520 520
 		$dispatcher->addListener('\OC\DB\Migrator::checkTable', function($event) use ($log) {
521 521
 			if (!$event instanceof GenericEvent) {
522 522
 				return;
523 523
 			}
524
-			$log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
524
+			$log->info('\OC\DB\Migrator::checkTable: '.$event->getSubject().' ('.$event->getArgument(0).' of '.$event->getArgument(1).')', ['app' => 'updater']);
525 525
 		});
526 526
 
527 527
 		$repairListener = function($event) use ($log) {
@@ -530,30 +530,30 @@  discard block
 block discarded – undo
530 530
 			}
531 531
 			switch ($event->getSubject()) {
532 532
 				case '\OC\Repair::startProgress':
533
-					$log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
533
+					$log->info('\OC\Repair::startProgress: Starting ... '.$event->getArgument(1).' ('.$event->getArgument(0).')', ['app' => 'updater']);
534 534
 					break;
535 535
 				case '\OC\Repair::advance':
536 536
 					$desc = $event->getArgument(1);
537 537
 					if (empty($desc)) {
538 538
 						$desc = '';
539 539
 					}
540
-					$log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
540
+					$log->info('\OC\Repair::advance: '.$desc.' ('.$event->getArgument(0).')', ['app' => 'updater']);
541 541
 
542 542
 					break;
543 543
 				case '\OC\Repair::finishProgress':
544 544
 					$log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
545 545
 					break;
546 546
 				case '\OC\Repair::step':
547
-					$log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
547
+					$log->info('\OC\Repair::step: Repair step: '.$event->getArgument(0), ['app' => 'updater']);
548 548
 					break;
549 549
 				case '\OC\Repair::info':
550
-					$log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
550
+					$log->info('\OC\Repair::info: Repair info: '.$event->getArgument(0), ['app' => 'updater']);
551 551
 					break;
552 552
 				case '\OC\Repair::warning':
553
-					$log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
553
+					$log->warning('\OC\Repair::warning: Repair warning: '.$event->getArgument(0), ['app' => 'updater']);
554 554
 					break;
555 555
 				case '\OC\Repair::error':
556
-					$log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
556
+					$log->error('\OC\Repair::error: Repair error: '.$event->getArgument(0), ['app' => 'updater']);
557 557
 					break;
558 558
 			}
559 559
 		};
@@ -567,77 +567,77 @@  discard block
 block discarded – undo
567 567
 		$dispatcher->addListener('\OC\Repair::error', $repairListener);
568 568
 
569 569
 
570
-		$this->listen('\OC\Updater', 'maintenanceEnabled', function () use($log) {
570
+		$this->listen('\OC\Updater', 'maintenanceEnabled', function() use($log) {
571 571
 			$log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
572 572
 		});
573
-		$this->listen('\OC\Updater', 'maintenanceDisabled', function () use($log) {
573
+		$this->listen('\OC\Updater', 'maintenanceDisabled', function() use($log) {
574 574
 			$log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
575 575
 		});
576
-		$this->listen('\OC\Updater', 'maintenanceActive', function () use($log) {
576
+		$this->listen('\OC\Updater', 'maintenanceActive', function() use($log) {
577 577
 			$log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
578 578
 		});
579
-		$this->listen('\OC\Updater', 'updateEnd', function ($success) use($log) {
579
+		$this->listen('\OC\Updater', 'updateEnd', function($success) use($log) {
580 580
 			if ($success) {
581 581
 				$log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
582 582
 			} else {
583 583
 				$log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
584 584
 			}
585 585
 		});
586
-		$this->listen('\OC\Updater', 'dbUpgradeBefore', function () use($log) {
586
+		$this->listen('\OC\Updater', 'dbUpgradeBefore', function() use($log) {
587 587
 			$log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
588 588
 		});
589
-		$this->listen('\OC\Updater', 'dbUpgrade', function () use($log) {
589
+		$this->listen('\OC\Updater', 'dbUpgrade', function() use($log) {
590 590
 			$log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
591 591
 		});
592
-		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use($log) {
592
+		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function() use($log) {
593 593
 			$log->info('\OC\Updater::dbSimulateUpgradeBefore: Checking whether the database schema can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
594 594
 		});
595
-		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use($log) {
595
+		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function() use($log) {
596 596
 			$log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
597 597
 		});
598
-		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use($log) {
599
-			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
598
+		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function($app) use($log) {
599
+			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: '.$app, ['app' => 'updater']);
600 600
 		});
601
-		$this->listen('\OC\Updater', 'thirdPartyAppDisabled', function ($app) use ($log) {
602
-			$log->info('\OC\Updater::thirdPartyAppDisabled: Disabled 3rd-party app: ' . $app, ['app' => 'updater']);
601
+		$this->listen('\OC\Updater', 'thirdPartyAppDisabled', function($app) use ($log) {
602
+			$log->info('\OC\Updater::thirdPartyAppDisabled: Disabled 3rd-party app: '.$app, ['app' => 'updater']);
603 603
 		});
604
-		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use($log) {
605
-			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
604
+		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function($app) use($log) {
605
+			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "'.$app.'" in appstore', ['app' => 'updater']);
606 606
 		});
607
-		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use($log) {
608
-			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
607
+		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function($app) use($log) {
608
+			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "'.$app.'" from appstore', ['app' => 'updater']);
609 609
 		});
610
-		$this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use($log) {
611
-			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
610
+		$this->listen('\OC\Updater', 'checkAppStoreApp', function($app) use($log) {
611
+			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "'.$app.'" in appstore', ['app' => 'updater']);
612 612
 		});
613
-		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
613
+		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function() use ($log) {
614 614
 			$log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
615 615
 		});
616
-		$this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
617
-			$log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <' . $app . '> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
616
+		$this->listen('\OC\Updater', 'appSimulateUpdate', function($app) use ($log) {
617
+			$log->info('\OC\Updater::appSimulateUpdate: Checking whether the database schema for <'.$app.'> can be updated (this can take a long time depending on the database size)', ['app' => 'updater']);
618 618
 		});
619
-		$this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
619
+		$this->listen('\OC\Updater', 'appUpgradeCheck', function() use ($log) {
620 620
 			$log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
621 621
 		});
622
-		$this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
623
-			$log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
622
+		$this->listen('\OC\Updater', 'appUpgradeStarted', function($app) use ($log) {
623
+			$log->info('\OC\Updater::appUpgradeStarted: Updating <'.$app.'> ...', ['app' => 'updater']);
624 624
 		});
625
-		$this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
626
-			$log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
625
+		$this->listen('\OC\Updater', 'appUpgrade', function($app, $version) use ($log) {
626
+			$log->info('\OC\Updater::appUpgrade: Updated <'.$app.'> to '.$version, ['app' => 'updater']);
627 627
 		});
628
-		$this->listen('\OC\Updater', 'failure', function ($message) use($log) {
629
-			$log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
628
+		$this->listen('\OC\Updater', 'failure', function($message) use($log) {
629
+			$log->error('\OC\Updater::failure: '.$message, ['app' => 'updater']);
630 630
 		});
631
-		$this->listen('\OC\Updater', 'setDebugLogLevel', function () use($log) {
631
+		$this->listen('\OC\Updater', 'setDebugLogLevel', function() use($log) {
632 632
 			$log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
633 633
 		});
634
-		$this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use($log) {
635
-			$log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
634
+		$this->listen('\OC\Updater', 'resetLogLevel', function($logLevel, $logLevelName) use($log) {
635
+			$log->info('\OC\Updater::resetLogLevel: Reset log level to '.$logLevelName.'('.$logLevel.')', ['app' => 'updater']);
636 636
 		});
637
-		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use($log) {
637
+		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function() use($log) {
638 638
 			$log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
639 639
 		});
640
-		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use($log) {
640
+		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function() use($log) {
641 641
 			$log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
642 642
 		});
643 643
 
Please login to merge, or discard this patch.
core/Command/App/ListApps.php 2 patches
Indentation   +104 added lines, -104 removed lines patch added patch discarded remove patch
@@ -34,109 +34,109 @@
 block discarded – undo
34 34
 
35 35
 class ListApps extends Base {
36 36
 
37
-	/** @var IAppManager */
38
-	protected $manager;
39
-
40
-	/**
41
-	 * @param IAppManager $manager
42
-	 */
43
-	public function __construct(IAppManager $manager) {
44
-		parent::__construct();
45
-		$this->manager = $manager;
46
-	}
47
-
48
-	protected function configure() {
49
-		parent::configure();
50
-
51
-		$this
52
-			->setName('app:list')
53
-			->setDescription('List all available apps')
54
-			->addOption(
55
-				'shipped',
56
-				null,
57
-				InputOption::VALUE_REQUIRED,
58
-				'true - limit to shipped apps only, false - limit to non-shipped apps only'
59
-			)
60
-		;
61
-	}
62
-
63
-	protected function execute(InputInterface $input, OutputInterface $output) {
64
-		if ($input->getOption('shipped') === 'true' || $input->getOption('shipped') === 'false'){
65
-			$shippedFilter = $input->getOption('shipped') === 'true';
66
-		} else {
67
-			$shippedFilter = null;
68
-		}
37
+    /** @var IAppManager */
38
+    protected $manager;
39
+
40
+    /**
41
+     * @param IAppManager $manager
42
+     */
43
+    public function __construct(IAppManager $manager) {
44
+        parent::__construct();
45
+        $this->manager = $manager;
46
+    }
47
+
48
+    protected function configure() {
49
+        parent::configure();
50
+
51
+        $this
52
+            ->setName('app:list')
53
+            ->setDescription('List all available apps')
54
+            ->addOption(
55
+                'shipped',
56
+                null,
57
+                InputOption::VALUE_REQUIRED,
58
+                'true - limit to shipped apps only, false - limit to non-shipped apps only'
59
+            )
60
+        ;
61
+    }
62
+
63
+    protected function execute(InputInterface $input, OutputInterface $output) {
64
+        if ($input->getOption('shipped') === 'true' || $input->getOption('shipped') === 'false'){
65
+            $shippedFilter = $input->getOption('shipped') === 'true';
66
+        } else {
67
+            $shippedFilter = null;
68
+        }
69 69
 		
70
-		$apps = \OC_App::getAllApps();
71
-		$enabledApps = $disabledApps = [];
72
-		$versions = \OC_App::getAppVersions();
73
-
74
-		//sort enabled apps above disabled apps
75
-		foreach ($apps as $app) {
76
-			if ($shippedFilter !== null && $this->manager->isShipped($app) !== $shippedFilter){
77
-				continue;
78
-			}
79
-			if ($this->manager->isInstalled($app)) {
80
-				$enabledApps[] = $app;
81
-			} else {
82
-				$disabledApps[] = $app;
83
-			}
84
-		}
85
-
86
-		$apps = ['enabled' => [], 'disabled' => []];
87
-
88
-		sort($enabledApps);
89
-		foreach ($enabledApps as $app) {
90
-			$apps['enabled'][$app] = (isset($versions[$app])) ? $versions[$app] : true;
91
-		}
92
-
93
-		sort($disabledApps);
94
-		foreach ($disabledApps as $app) {
95
-			$apps['disabled'][$app] = null;
96
-		}
97
-
98
-		$this->writeAppList($input, $output, $apps);
99
-	}
100
-
101
-	/**
102
-	 * @param InputInterface $input
103
-	 * @param OutputInterface $output
104
-	 * @param array $items
105
-	 */
106
-	protected function writeAppList(InputInterface $input, OutputInterface $output, $items) {
107
-		switch ($input->getOption('output')) {
108
-			case self::OUTPUT_FORMAT_PLAIN:
109
-				$output->writeln('Enabled:');
110
-				parent::writeArrayInOutputFormat($input, $output, $items['enabled']);
111
-
112
-				$output->writeln('Disabled:');
113
-				parent::writeArrayInOutputFormat($input, $output, $items['disabled']);
114
-			break;
115
-
116
-			default:
117
-				parent::writeArrayInOutputFormat($input, $output, $items);
118
-			break;
119
-		}
120
-	}
121
-
122
-	/**
123
-	 * @param string $optionName
124
-	 * @param CompletionContext $completionContext
125
-	 * @return array
126
-	 */
127
-	public function completeOptionValues($optionName, CompletionContext $completionContext) {
128
-		if ($optionName === 'shipped') {
129
-			return ['true', 'false'];
130
-		}
131
-		return [];
132
-	}
133
-
134
-	/**
135
-	 * @param string $argumentName
136
-	 * @param CompletionContext $context
137
-	 * @return string[]
138
-	 */
139
-	public function completeArgumentValues($argumentName, CompletionContext $context) {
140
-		return [];
141
-	}
70
+        $apps = \OC_App::getAllApps();
71
+        $enabledApps = $disabledApps = [];
72
+        $versions = \OC_App::getAppVersions();
73
+
74
+        //sort enabled apps above disabled apps
75
+        foreach ($apps as $app) {
76
+            if ($shippedFilter !== null && $this->manager->isShipped($app) !== $shippedFilter){
77
+                continue;
78
+            }
79
+            if ($this->manager->isInstalled($app)) {
80
+                $enabledApps[] = $app;
81
+            } else {
82
+                $disabledApps[] = $app;
83
+            }
84
+        }
85
+
86
+        $apps = ['enabled' => [], 'disabled' => []];
87
+
88
+        sort($enabledApps);
89
+        foreach ($enabledApps as $app) {
90
+            $apps['enabled'][$app] = (isset($versions[$app])) ? $versions[$app] : true;
91
+        }
92
+
93
+        sort($disabledApps);
94
+        foreach ($disabledApps as $app) {
95
+            $apps['disabled'][$app] = null;
96
+        }
97
+
98
+        $this->writeAppList($input, $output, $apps);
99
+    }
100
+
101
+    /**
102
+     * @param InputInterface $input
103
+     * @param OutputInterface $output
104
+     * @param array $items
105
+     */
106
+    protected function writeAppList(InputInterface $input, OutputInterface $output, $items) {
107
+        switch ($input->getOption('output')) {
108
+            case self::OUTPUT_FORMAT_PLAIN:
109
+                $output->writeln('Enabled:');
110
+                parent::writeArrayInOutputFormat($input, $output, $items['enabled']);
111
+
112
+                $output->writeln('Disabled:');
113
+                parent::writeArrayInOutputFormat($input, $output, $items['disabled']);
114
+            break;
115
+
116
+            default:
117
+                parent::writeArrayInOutputFormat($input, $output, $items);
118
+            break;
119
+        }
120
+    }
121
+
122
+    /**
123
+     * @param string $optionName
124
+     * @param CompletionContext $completionContext
125
+     * @return array
126
+     */
127
+    public function completeOptionValues($optionName, CompletionContext $completionContext) {
128
+        if ($optionName === 'shipped') {
129
+            return ['true', 'false'];
130
+        }
131
+        return [];
132
+    }
133
+
134
+    /**
135
+     * @param string $argumentName
136
+     * @param CompletionContext $context
137
+     * @return string[]
138
+     */
139
+    public function completeArgumentValues($argumentName, CompletionContext $context) {
140
+        return [];
141
+    }
142 142
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -61,7 +61,7 @@  discard block
 block discarded – undo
61 61
 	}
62 62
 
63 63
 	protected function execute(InputInterface $input, OutputInterface $output) {
64
-		if ($input->getOption('shipped') === 'true' || $input->getOption('shipped') === 'false'){
64
+		if ($input->getOption('shipped') === 'true' || $input->getOption('shipped') === 'false') {
65 65
 			$shippedFilter = $input->getOption('shipped') === 'true';
66 66
 		} else {
67 67
 			$shippedFilter = null;
@@ -73,7 +73,7 @@  discard block
 block discarded – undo
73 73
 
74 74
 		//sort enabled apps above disabled apps
75 75
 		foreach ($apps as $app) {
76
-			if ($shippedFilter !== null && $this->manager->isShipped($app) !== $shippedFilter){
76
+			if ($shippedFilter !== null && $this->manager->isShipped($app) !== $shippedFilter) {
77 77
 				continue;
78 78
 			}
79 79
 			if ($this->manager->isInstalled($app)) {
Please login to merge, or discard this patch.