Passed
Push — master ( 3c693d...ccd5ca )
by Roeland
28:56 queued 14:09
created
lib/private/Updater.php 1 patch
Indentation   +528 added lines, -528 removed lines patch added patch discarded remove patch
@@ -56,532 +56,532 @@
 block discarded – undo
56 56
  */
57 57
 class Updater extends BasicEmitter {
58 58
 
59
-	/** @var ILogger $log */
60
-	private $log;
61
-
62
-	/** @var IConfig */
63
-	private $config;
64
-
65
-	/** @var Checker */
66
-	private $checker;
67
-
68
-	/** @var Installer */
69
-	private $installer;
70
-
71
-	private $logLevelNames = [
72
-		0 => 'Debug',
73
-		1 => 'Info',
74
-		2 => 'Warning',
75
-		3 => 'Error',
76
-		4 => 'Fatal',
77
-	];
78
-
79
-	/**
80
-	 * @param IConfig $config
81
-	 * @param Checker $checker
82
-	 * @param ILogger $log
83
-	 * @param Installer $installer
84
-	 */
85
-	public function __construct(IConfig $config,
86
-								Checker $checker,
87
-								ILogger $log = null,
88
-								Installer $installer) {
89
-		$this->log = $log;
90
-		$this->config = $config;
91
-		$this->checker = $checker;
92
-		$this->installer = $installer;
93
-	}
94
-
95
-	/**
96
-	 * runs the update actions in maintenance mode, does not upgrade the source files
97
-	 * except the main .htaccess file
98
-	 *
99
-	 * @return bool true if the operation succeeded, false otherwise
100
-	 */
101
-	public function upgrade() {
102
-		$this->emitRepairEvents();
103
-		$this->logAllEvents();
104
-
105
-		$logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN);
106
-		$this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
107
-		$this->config->setSystemValue('loglevel', ILogger::DEBUG);
108
-
109
-		$wasMaintenanceModeEnabled = $this->config->getSystemValueBool('maintenance');
110
-
111
-		if (!$wasMaintenanceModeEnabled) {
112
-			$this->config->setSystemValue('maintenance', true);
113
-			$this->emit('\OC\Updater', 'maintenanceEnabled');
114
-		}
115
-
116
-		// Clear CAN_INSTALL file if not on git
117
-		if (\OC_Util::getChannel() !== 'git' && is_file(\OC::$configDir.'/CAN_INSTALL')) {
118
-			if (!unlink(\OC::$configDir . '/CAN_INSTALL')) {
119
-				$this->log->error('Could not cleanup CAN_INSTALL from your config folder. Please remove this file manually.');
120
-			}
121
-		}
122
-
123
-		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
124
-		$currentVersion = implode('.', \OCP\Util::getVersion());
125
-
126
-		$this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, ['app' => 'core']);
127
-
128
-		$success = true;
129
-		try {
130
-			$this->doUpgrade($currentVersion, $installedVersion);
131
-		} catch (HintException $exception) {
132
-			$this->log->logException($exception, ['app' => 'core']);
133
-			$this->emit('\OC\Updater', 'failure', [$exception->getMessage() . ': ' .$exception->getHint()]);
134
-			$success = false;
135
-		} catch (\Exception $exception) {
136
-			$this->log->logException($exception, ['app' => 'core']);
137
-			$this->emit('\OC\Updater', 'failure', [get_class($exception) . ': ' .$exception->getMessage()]);
138
-			$success = false;
139
-		}
140
-
141
-		$this->emit('\OC\Updater', 'updateEnd', [$success]);
142
-
143
-		if (!$wasMaintenanceModeEnabled && $success) {
144
-			$this->config->setSystemValue('maintenance', false);
145
-			$this->emit('\OC\Updater', 'maintenanceDisabled');
146
-		} else {
147
-			$this->emit('\OC\Updater', 'maintenanceActive');
148
-		}
149
-
150
-		$this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
151
-		$this->config->setSystemValue('loglevel', $logLevel);
152
-		$this->config->setSystemValue('installed', true);
153
-
154
-		return $success;
155
-	}
156
-
157
-	/**
158
-	 * Return version from which this version is allowed to upgrade from
159
-	 *
160
-	 * @return array allowed previous versions per vendor
161
-	 */
162
-	private function getAllowedPreviousVersions() {
163
-		// this should really be a JSON file
164
-		require \OC::$SERVERROOT . '/version.php';
165
-		/** @var array $OC_VersionCanBeUpgradedFrom */
166
-		return $OC_VersionCanBeUpgradedFrom;
167
-	}
168
-
169
-	/**
170
-	 * Return vendor from which this version was published
171
-	 *
172
-	 * @return string Get the vendor
173
-	 */
174
-	private function getVendor() {
175
-		// this should really be a JSON file
176
-		require \OC::$SERVERROOT . '/version.php';
177
-		/** @var string $vendor */
178
-		return (string) $vendor;
179
-	}
180
-
181
-	/**
182
-	 * Whether an upgrade to a specified version is possible
183
-	 * @param string $oldVersion
184
-	 * @param string $newVersion
185
-	 * @param array $allowedPreviousVersions
186
-	 * @return bool
187
-	 */
188
-	public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
189
-		$version = explode('.', $oldVersion);
190
-		$majorMinor = $version[0] . '.' . $version[1];
191
-
192
-		$currentVendor = $this->config->getAppValue('core', 'vendor', '');
193
-
194
-		// Vendor was not set correctly on install, so we have to white-list known versions
195
-		if ($currentVendor === '' && (
196
-			isset($allowedPreviousVersions['owncloud'][$oldVersion]) ||
197
-			isset($allowedPreviousVersions['owncloud'][$majorMinor])
198
-		)) {
199
-			$currentVendor = 'owncloud';
200
-			$this->config->setAppValue('core', 'vendor', $currentVendor);
201
-		}
202
-
203
-		if ($currentVendor === 'nextcloud') {
204
-			return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
205
-				&& (version_compare($oldVersion, $newVersion, '<=') ||
206
-					$this->config->getSystemValue('debug', false));
207
-		}
208
-
209
-		// Check if the instance can be migrated
210
-		return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) ||
211
-			isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
212
-	}
213
-
214
-	/**
215
-	 * runs the update actions in maintenance mode, does not upgrade the source files
216
-	 * except the main .htaccess file
217
-	 *
218
-	 * @param string $currentVersion current version to upgrade to
219
-	 * @param string $installedVersion previous version from which to upgrade from
220
-	 *
221
-	 * @throws \Exception
222
-	 */
223
-	private function doUpgrade($currentVersion, $installedVersion) {
224
-		// Stop update if the update is over several major versions
225
-		$allowedPreviousVersions = $this->getAllowedPreviousVersions();
226
-		if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
227
-			throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
228
-		}
229
-
230
-		// Update .htaccess files
231
-		try {
232
-			Setup::updateHtaccess();
233
-			Setup::protectDataDirectory();
234
-		} catch (\Exception $e) {
235
-			throw new \Exception($e->getMessage());
236
-		}
237
-
238
-		// create empty file in data dir, so we can later find
239
-		// out that this is indeed an ownCloud data directory
240
-		// (in case it didn't exist before)
241
-		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
242
-
243
-		// pre-upgrade repairs
244
-		$repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
245
-		$repair->run();
246
-
247
-		$this->doCoreUpgrade();
248
-
249
-		try {
250
-			// TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
251
-			Setup::installBackgroundJobs();
252
-		} catch (\Exception $e) {
253
-			throw new \Exception($e->getMessage());
254
-		}
255
-
256
-		// update all shipped apps
257
-		$this->checkAppsRequirements();
258
-		$this->doAppUpgrade();
259
-
260
-		// Update the appfetchers version so it downloads the correct list from the appstore
261
-		\OC::$server->getAppFetcher()->setVersion($currentVersion);
262
-
263
-		// upgrade appstore apps
264
-		$this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps());
265
-		$autoDisabledApps = \OC::$server->getAppManager()->getAutoDisabledApps();
266
-		$this->upgradeAppStoreApps($autoDisabledApps, true);
267
-
268
-		// install new shipped apps on upgrade
269
-		OC_App::loadApps(['authentication']);
270
-		$errors = Installer::installShippedApps(true);
271
-		foreach ($errors as $appId => $exception) {
272
-			/** @var \Exception $exception */
273
-			$this->log->logException($exception, ['app' => $appId]);
274
-			$this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
275
-		}
276
-
277
-		// post-upgrade repairs
278
-		$repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher());
279
-		$repair->run();
280
-
281
-		//Invalidate update feed
282
-		$this->config->setAppValue('core', 'lastupdatedat', 0);
283
-
284
-		// Check for code integrity if not disabled
285
-		if (\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
286
-			$this->emit('\OC\Updater', 'startCheckCodeIntegrity');
287
-			$this->checker->runInstanceVerification();
288
-			$this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
289
-		}
290
-
291
-		// only set the final version if everything went well
292
-		$this->config->setSystemValue('version', implode('.', Util::getVersion()));
293
-		$this->config->setAppValue('core', 'vendor', $this->getVendor());
294
-	}
295
-
296
-	protected function doCoreUpgrade() {
297
-		$this->emit('\OC\Updater', 'dbUpgradeBefore');
298
-
299
-		// execute core migrations
300
-		$ms = new MigrationService('core', \OC::$server->getDatabaseConnection());
301
-		$ms->migrate();
302
-
303
-		$this->emit('\OC\Updater', 'dbUpgrade');
304
-	}
305
-
306
-	/**
307
-	 * upgrades all apps within a major ownCloud upgrade. Also loads "priority"
308
-	 * (types authentication, filesystem, logging, in that order) afterwards.
309
-	 *
310
-	 * @throws NeedsUpdateException
311
-	 */
312
-	protected function doAppUpgrade() {
313
-		$apps = \OC_App::getEnabledApps();
314
-		$priorityTypes = ['authentication', 'filesystem', 'logging'];
315
-		$pseudoOtherType = 'other';
316
-		$stacks = [$pseudoOtherType => []];
317
-
318
-		foreach ($apps as $appId) {
319
-			$priorityType = false;
320
-			foreach ($priorityTypes as $type) {
321
-				if (!isset($stacks[$type])) {
322
-					$stacks[$type] = [];
323
-				}
324
-				if (\OC_App::isType($appId, [$type])) {
325
-					$stacks[$type][] = $appId;
326
-					$priorityType = true;
327
-					break;
328
-				}
329
-			}
330
-			if (!$priorityType) {
331
-				$stacks[$pseudoOtherType][] = $appId;
332
-			}
333
-		}
334
-		foreach ($stacks as $type => $stack) {
335
-			foreach ($stack as $appId) {
336
-				if (\OC_App::shouldUpgrade($appId)) {
337
-					$this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]);
338
-					\OC_App::updateApp($appId);
339
-					$this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
340
-				}
341
-				if ($type !== $pseudoOtherType) {
342
-					// load authentication, filesystem and logging apps after
343
-					// upgrading them. Other apps my need to rely on modifying
344
-					// user and/or filesystem aspects.
345
-					\OC_App::loadApp($appId);
346
-				}
347
-			}
348
-		}
349
-	}
350
-
351
-	/**
352
-	 * check if the current enabled apps are compatible with the current
353
-	 * ownCloud version. disable them if not.
354
-	 * This is important if you upgrade ownCloud and have non ported 3rd
355
-	 * party apps installed.
356
-	 *
357
-	 * @return array
358
-	 * @throws \Exception
359
-	 */
360
-	private function checkAppsRequirements() {
361
-		$isCoreUpgrade = $this->isCodeUpgrade();
362
-		$apps = OC_App::getEnabledApps();
363
-		$version = implode('.', Util::getVersion());
364
-		$disabledApps = [];
365
-		$appManager = \OC::$server->getAppManager();
366
-		foreach ($apps as $app) {
367
-			// check if the app is compatible with this version of Nextcloud
368
-			$info = OC_App::getAppInfo($app);
369
-			if ($info === null || !OC_App::isAppCompatible($version, $info)) {
370
-				if ($appManager->isShipped($app)) {
371
-					throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
372
-				}
373
-				\OC::$server->getAppManager()->disableApp($app, true);
374
-				$this->emit('\OC\Updater', 'incompatibleAppDisabled', [$app]);
375
-			}
376
-			// no need to disable any app in case this is a non-core upgrade
377
-			if (!$isCoreUpgrade) {
378
-				continue;
379
-			}
380
-			// shipped apps will remain enabled
381
-			if ($appManager->isShipped($app)) {
382
-				continue;
383
-			}
384
-			// authentication and session apps will remain enabled as well
385
-			if (OC_App::isType($app, ['session', 'authentication'])) {
386
-				continue;
387
-			}
388
-		}
389
-		return $disabledApps;
390
-	}
391
-
392
-	/**
393
-	 * @return bool
394
-	 */
395
-	private function isCodeUpgrade() {
396
-		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
397
-		$currentVersion = implode('.', Util::getVersion());
398
-		if (version_compare($currentVersion, $installedVersion, '>')) {
399
-			return true;
400
-		}
401
-		return false;
402
-	}
403
-
404
-	/**
405
-	 * @param array $disabledApps
406
-	 * @param bool $reenable
407
-	 * @throws \Exception
408
-	 */
409
-	private function upgradeAppStoreApps(array $disabledApps, $reenable = false) {
410
-		foreach ($disabledApps as $app) {
411
-			try {
412
-				$this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
413
-				if ($this->installer->isUpdateAvailable($app)) {
414
-					$this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
415
-					$this->installer->updateAppstoreApp($app);
416
-				}
417
-				$this->emit('\OC\Updater', 'checkAppStoreApp', [$app]);
418
-
419
-				if ($reenable) {
420
-					$ocApp = new \OC_App();
421
-					$ocApp->enable($app);
422
-				}
423
-			} catch (\Exception $ex) {
424
-				$this->log->logException($ex, ['app' => 'core']);
425
-			}
426
-		}
427
-	}
428
-
429
-	/**
430
-	 * Forward messages emitted by the repair routine
431
-	 */
432
-	private function emitRepairEvents() {
433
-		$dispatcher = \OC::$server->getEventDispatcher();
434
-		$dispatcher->addListener('\OC\Repair::warning', function ($event) {
435
-			if ($event instanceof GenericEvent) {
436
-				$this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
437
-			}
438
-		});
439
-		$dispatcher->addListener('\OC\Repair::error', function ($event) {
440
-			if ($event instanceof GenericEvent) {
441
-				$this->emit('\OC\Updater', 'repairError', $event->getArguments());
442
-			}
443
-		});
444
-		$dispatcher->addListener('\OC\Repair::info', function ($event) {
445
-			if ($event instanceof GenericEvent) {
446
-				$this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
447
-			}
448
-		});
449
-		$dispatcher->addListener('\OC\Repair::step', function ($event) {
450
-			if ($event instanceof GenericEvent) {
451
-				$this->emit('\OC\Updater', 'repairStep', $event->getArguments());
452
-			}
453
-		});
454
-	}
455
-
456
-	private function logAllEvents() {
457
-		$log = $this->log;
458
-
459
-		$dispatcher = \OC::$server->getEventDispatcher();
460
-		$dispatcher->addListener('\OC\DB\Migrator::executeSql', function ($event) use ($log) {
461
-			if (!$event instanceof GenericEvent) {
462
-				return;
463
-			}
464
-			$log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
465
-		});
466
-		$dispatcher->addListener('\OC\DB\Migrator::checkTable', function ($event) use ($log) {
467
-			if (!$event instanceof GenericEvent) {
468
-				return;
469
-			}
470
-			$log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
471
-		});
472
-
473
-		$repairListener = function ($event) use ($log) {
474
-			if (!$event instanceof GenericEvent) {
475
-				return;
476
-			}
477
-			switch ($event->getSubject()) {
478
-				case '\OC\Repair::startProgress':
479
-					$log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
480
-					break;
481
-				case '\OC\Repair::advance':
482
-					$desc = $event->getArgument(1);
483
-					if (empty($desc)) {
484
-						$desc = '';
485
-					}
486
-					$log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
487
-
488
-					break;
489
-				case '\OC\Repair::finishProgress':
490
-					$log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
491
-					break;
492
-				case '\OC\Repair::step':
493
-					$log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
494
-					break;
495
-				case '\OC\Repair::info':
496
-					$log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
497
-					break;
498
-				case '\OC\Repair::warning':
499
-					$log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
500
-					break;
501
-				case '\OC\Repair::error':
502
-					$log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
503
-					break;
504
-			}
505
-		};
506
-
507
-		$dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
508
-		$dispatcher->addListener('\OC\Repair::advance', $repairListener);
509
-		$dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
510
-		$dispatcher->addListener('\OC\Repair::step', $repairListener);
511
-		$dispatcher->addListener('\OC\Repair::info', $repairListener);
512
-		$dispatcher->addListener('\OC\Repair::warning', $repairListener);
513
-		$dispatcher->addListener('\OC\Repair::error', $repairListener);
514
-
515
-
516
-		$this->listen('\OC\Updater', 'maintenanceEnabled', function () use ($log) {
517
-			$log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
518
-		});
519
-		$this->listen('\OC\Updater', 'maintenanceDisabled', function () use ($log) {
520
-			$log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
521
-		});
522
-		$this->listen('\OC\Updater', 'maintenanceActive', function () use ($log) {
523
-			$log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
524
-		});
525
-		$this->listen('\OC\Updater', 'updateEnd', function ($success) use ($log) {
526
-			if ($success) {
527
-				$log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
528
-			} else {
529
-				$log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
530
-			}
531
-		});
532
-		$this->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($log) {
533
-			$log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
534
-		});
535
-		$this->listen('\OC\Updater', 'dbUpgrade', function () use ($log) {
536
-			$log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
537
-		});
538
-		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use ($log) {
539
-			$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']);
540
-		});
541
-		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use ($log) {
542
-			$log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
543
-		});
544
-		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($log) {
545
-			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
546
-		});
547
-		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($log) {
548
-			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
549
-		});
550
-		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($log) {
551
-			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
552
-		});
553
-		$this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($log) {
554
-			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
555
-		});
556
-		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
557
-			$log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
558
-		});
559
-		$this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
560
-			$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']);
561
-		});
562
-		$this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
563
-			$log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
564
-		});
565
-		$this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
566
-			$log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
567
-		});
568
-		$this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
569
-			$log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
570
-		});
571
-		$this->listen('\OC\Updater', 'failure', function ($message) use ($log) {
572
-			$log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
573
-		});
574
-		$this->listen('\OC\Updater', 'setDebugLogLevel', function () use ($log) {
575
-			$log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
576
-		});
577
-		$this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($log) {
578
-			$log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
579
-		});
580
-		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($log) {
581
-			$log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
582
-		});
583
-		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($log) {
584
-			$log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
585
-		});
586
-	}
59
+    /** @var ILogger $log */
60
+    private $log;
61
+
62
+    /** @var IConfig */
63
+    private $config;
64
+
65
+    /** @var Checker */
66
+    private $checker;
67
+
68
+    /** @var Installer */
69
+    private $installer;
70
+
71
+    private $logLevelNames = [
72
+        0 => 'Debug',
73
+        1 => 'Info',
74
+        2 => 'Warning',
75
+        3 => 'Error',
76
+        4 => 'Fatal',
77
+    ];
78
+
79
+    /**
80
+     * @param IConfig $config
81
+     * @param Checker $checker
82
+     * @param ILogger $log
83
+     * @param Installer $installer
84
+     */
85
+    public function __construct(IConfig $config,
86
+                                Checker $checker,
87
+                                ILogger $log = null,
88
+                                Installer $installer) {
89
+        $this->log = $log;
90
+        $this->config = $config;
91
+        $this->checker = $checker;
92
+        $this->installer = $installer;
93
+    }
94
+
95
+    /**
96
+     * runs the update actions in maintenance mode, does not upgrade the source files
97
+     * except the main .htaccess file
98
+     *
99
+     * @return bool true if the operation succeeded, false otherwise
100
+     */
101
+    public function upgrade() {
102
+        $this->emitRepairEvents();
103
+        $this->logAllEvents();
104
+
105
+        $logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN);
106
+        $this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
107
+        $this->config->setSystemValue('loglevel', ILogger::DEBUG);
108
+
109
+        $wasMaintenanceModeEnabled = $this->config->getSystemValueBool('maintenance');
110
+
111
+        if (!$wasMaintenanceModeEnabled) {
112
+            $this->config->setSystemValue('maintenance', true);
113
+            $this->emit('\OC\Updater', 'maintenanceEnabled');
114
+        }
115
+
116
+        // Clear CAN_INSTALL file if not on git
117
+        if (\OC_Util::getChannel() !== 'git' && is_file(\OC::$configDir.'/CAN_INSTALL')) {
118
+            if (!unlink(\OC::$configDir . '/CAN_INSTALL')) {
119
+                $this->log->error('Could not cleanup CAN_INSTALL from your config folder. Please remove this file manually.');
120
+            }
121
+        }
122
+
123
+        $installedVersion = $this->config->getSystemValue('version', '0.0.0');
124
+        $currentVersion = implode('.', \OCP\Util::getVersion());
125
+
126
+        $this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, ['app' => 'core']);
127
+
128
+        $success = true;
129
+        try {
130
+            $this->doUpgrade($currentVersion, $installedVersion);
131
+        } catch (HintException $exception) {
132
+            $this->log->logException($exception, ['app' => 'core']);
133
+            $this->emit('\OC\Updater', 'failure', [$exception->getMessage() . ': ' .$exception->getHint()]);
134
+            $success = false;
135
+        } catch (\Exception $exception) {
136
+            $this->log->logException($exception, ['app' => 'core']);
137
+            $this->emit('\OC\Updater', 'failure', [get_class($exception) . ': ' .$exception->getMessage()]);
138
+            $success = false;
139
+        }
140
+
141
+        $this->emit('\OC\Updater', 'updateEnd', [$success]);
142
+
143
+        if (!$wasMaintenanceModeEnabled && $success) {
144
+            $this->config->setSystemValue('maintenance', false);
145
+            $this->emit('\OC\Updater', 'maintenanceDisabled');
146
+        } else {
147
+            $this->emit('\OC\Updater', 'maintenanceActive');
148
+        }
149
+
150
+        $this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
151
+        $this->config->setSystemValue('loglevel', $logLevel);
152
+        $this->config->setSystemValue('installed', true);
153
+
154
+        return $success;
155
+    }
156
+
157
+    /**
158
+     * Return version from which this version is allowed to upgrade from
159
+     *
160
+     * @return array allowed previous versions per vendor
161
+     */
162
+    private function getAllowedPreviousVersions() {
163
+        // this should really be a JSON file
164
+        require \OC::$SERVERROOT . '/version.php';
165
+        /** @var array $OC_VersionCanBeUpgradedFrom */
166
+        return $OC_VersionCanBeUpgradedFrom;
167
+    }
168
+
169
+    /**
170
+     * Return vendor from which this version was published
171
+     *
172
+     * @return string Get the vendor
173
+     */
174
+    private function getVendor() {
175
+        // this should really be a JSON file
176
+        require \OC::$SERVERROOT . '/version.php';
177
+        /** @var string $vendor */
178
+        return (string) $vendor;
179
+    }
180
+
181
+    /**
182
+     * Whether an upgrade to a specified version is possible
183
+     * @param string $oldVersion
184
+     * @param string $newVersion
185
+     * @param array $allowedPreviousVersions
186
+     * @return bool
187
+     */
188
+    public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
189
+        $version = explode('.', $oldVersion);
190
+        $majorMinor = $version[0] . '.' . $version[1];
191
+
192
+        $currentVendor = $this->config->getAppValue('core', 'vendor', '');
193
+
194
+        // Vendor was not set correctly on install, so we have to white-list known versions
195
+        if ($currentVendor === '' && (
196
+            isset($allowedPreviousVersions['owncloud'][$oldVersion]) ||
197
+            isset($allowedPreviousVersions['owncloud'][$majorMinor])
198
+        )) {
199
+            $currentVendor = 'owncloud';
200
+            $this->config->setAppValue('core', 'vendor', $currentVendor);
201
+        }
202
+
203
+        if ($currentVendor === 'nextcloud') {
204
+            return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
205
+                && (version_compare($oldVersion, $newVersion, '<=') ||
206
+                    $this->config->getSystemValue('debug', false));
207
+        }
208
+
209
+        // Check if the instance can be migrated
210
+        return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) ||
211
+            isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
212
+    }
213
+
214
+    /**
215
+     * runs the update actions in maintenance mode, does not upgrade the source files
216
+     * except the main .htaccess file
217
+     *
218
+     * @param string $currentVersion current version to upgrade to
219
+     * @param string $installedVersion previous version from which to upgrade from
220
+     *
221
+     * @throws \Exception
222
+     */
223
+    private function doUpgrade($currentVersion, $installedVersion) {
224
+        // Stop update if the update is over several major versions
225
+        $allowedPreviousVersions = $this->getAllowedPreviousVersions();
226
+        if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
227
+            throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
228
+        }
229
+
230
+        // Update .htaccess files
231
+        try {
232
+            Setup::updateHtaccess();
233
+            Setup::protectDataDirectory();
234
+        } catch (\Exception $e) {
235
+            throw new \Exception($e->getMessage());
236
+        }
237
+
238
+        // create empty file in data dir, so we can later find
239
+        // out that this is indeed an ownCloud data directory
240
+        // (in case it didn't exist before)
241
+        file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
242
+
243
+        // pre-upgrade repairs
244
+        $repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher());
245
+        $repair->run();
246
+
247
+        $this->doCoreUpgrade();
248
+
249
+        try {
250
+            // TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
251
+            Setup::installBackgroundJobs();
252
+        } catch (\Exception $e) {
253
+            throw new \Exception($e->getMessage());
254
+        }
255
+
256
+        // update all shipped apps
257
+        $this->checkAppsRequirements();
258
+        $this->doAppUpgrade();
259
+
260
+        // Update the appfetchers version so it downloads the correct list from the appstore
261
+        \OC::$server->getAppFetcher()->setVersion($currentVersion);
262
+
263
+        // upgrade appstore apps
264
+        $this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps());
265
+        $autoDisabledApps = \OC::$server->getAppManager()->getAutoDisabledApps();
266
+        $this->upgradeAppStoreApps($autoDisabledApps, true);
267
+
268
+        // install new shipped apps on upgrade
269
+        OC_App::loadApps(['authentication']);
270
+        $errors = Installer::installShippedApps(true);
271
+        foreach ($errors as $appId => $exception) {
272
+            /** @var \Exception $exception */
273
+            $this->log->logException($exception, ['app' => $appId]);
274
+            $this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
275
+        }
276
+
277
+        // post-upgrade repairs
278
+        $repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher());
279
+        $repair->run();
280
+
281
+        //Invalidate update feed
282
+        $this->config->setAppValue('core', 'lastupdatedat', 0);
283
+
284
+        // Check for code integrity if not disabled
285
+        if (\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
286
+            $this->emit('\OC\Updater', 'startCheckCodeIntegrity');
287
+            $this->checker->runInstanceVerification();
288
+            $this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
289
+        }
290
+
291
+        // only set the final version if everything went well
292
+        $this->config->setSystemValue('version', implode('.', Util::getVersion()));
293
+        $this->config->setAppValue('core', 'vendor', $this->getVendor());
294
+    }
295
+
296
+    protected function doCoreUpgrade() {
297
+        $this->emit('\OC\Updater', 'dbUpgradeBefore');
298
+
299
+        // execute core migrations
300
+        $ms = new MigrationService('core', \OC::$server->getDatabaseConnection());
301
+        $ms->migrate();
302
+
303
+        $this->emit('\OC\Updater', 'dbUpgrade');
304
+    }
305
+
306
+    /**
307
+     * upgrades all apps within a major ownCloud upgrade. Also loads "priority"
308
+     * (types authentication, filesystem, logging, in that order) afterwards.
309
+     *
310
+     * @throws NeedsUpdateException
311
+     */
312
+    protected function doAppUpgrade() {
313
+        $apps = \OC_App::getEnabledApps();
314
+        $priorityTypes = ['authentication', 'filesystem', 'logging'];
315
+        $pseudoOtherType = 'other';
316
+        $stacks = [$pseudoOtherType => []];
317
+
318
+        foreach ($apps as $appId) {
319
+            $priorityType = false;
320
+            foreach ($priorityTypes as $type) {
321
+                if (!isset($stacks[$type])) {
322
+                    $stacks[$type] = [];
323
+                }
324
+                if (\OC_App::isType($appId, [$type])) {
325
+                    $stacks[$type][] = $appId;
326
+                    $priorityType = true;
327
+                    break;
328
+                }
329
+            }
330
+            if (!$priorityType) {
331
+                $stacks[$pseudoOtherType][] = $appId;
332
+            }
333
+        }
334
+        foreach ($stacks as $type => $stack) {
335
+            foreach ($stack as $appId) {
336
+                if (\OC_App::shouldUpgrade($appId)) {
337
+                    $this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]);
338
+                    \OC_App::updateApp($appId);
339
+                    $this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
340
+                }
341
+                if ($type !== $pseudoOtherType) {
342
+                    // load authentication, filesystem and logging apps after
343
+                    // upgrading them. Other apps my need to rely on modifying
344
+                    // user and/or filesystem aspects.
345
+                    \OC_App::loadApp($appId);
346
+                }
347
+            }
348
+        }
349
+    }
350
+
351
+    /**
352
+     * check if the current enabled apps are compatible with the current
353
+     * ownCloud version. disable them if not.
354
+     * This is important if you upgrade ownCloud and have non ported 3rd
355
+     * party apps installed.
356
+     *
357
+     * @return array
358
+     * @throws \Exception
359
+     */
360
+    private function checkAppsRequirements() {
361
+        $isCoreUpgrade = $this->isCodeUpgrade();
362
+        $apps = OC_App::getEnabledApps();
363
+        $version = implode('.', Util::getVersion());
364
+        $disabledApps = [];
365
+        $appManager = \OC::$server->getAppManager();
366
+        foreach ($apps as $app) {
367
+            // check if the app is compatible with this version of Nextcloud
368
+            $info = OC_App::getAppInfo($app);
369
+            if ($info === null || !OC_App::isAppCompatible($version, $info)) {
370
+                if ($appManager->isShipped($app)) {
371
+                    throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
372
+                }
373
+                \OC::$server->getAppManager()->disableApp($app, true);
374
+                $this->emit('\OC\Updater', 'incompatibleAppDisabled', [$app]);
375
+            }
376
+            // no need to disable any app in case this is a non-core upgrade
377
+            if (!$isCoreUpgrade) {
378
+                continue;
379
+            }
380
+            // shipped apps will remain enabled
381
+            if ($appManager->isShipped($app)) {
382
+                continue;
383
+            }
384
+            // authentication and session apps will remain enabled as well
385
+            if (OC_App::isType($app, ['session', 'authentication'])) {
386
+                continue;
387
+            }
388
+        }
389
+        return $disabledApps;
390
+    }
391
+
392
+    /**
393
+     * @return bool
394
+     */
395
+    private function isCodeUpgrade() {
396
+        $installedVersion = $this->config->getSystemValue('version', '0.0.0');
397
+        $currentVersion = implode('.', Util::getVersion());
398
+        if (version_compare($currentVersion, $installedVersion, '>')) {
399
+            return true;
400
+        }
401
+        return false;
402
+    }
403
+
404
+    /**
405
+     * @param array $disabledApps
406
+     * @param bool $reenable
407
+     * @throws \Exception
408
+     */
409
+    private function upgradeAppStoreApps(array $disabledApps, $reenable = false) {
410
+        foreach ($disabledApps as $app) {
411
+            try {
412
+                $this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
413
+                if ($this->installer->isUpdateAvailable($app)) {
414
+                    $this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
415
+                    $this->installer->updateAppstoreApp($app);
416
+                }
417
+                $this->emit('\OC\Updater', 'checkAppStoreApp', [$app]);
418
+
419
+                if ($reenable) {
420
+                    $ocApp = new \OC_App();
421
+                    $ocApp->enable($app);
422
+                }
423
+            } catch (\Exception $ex) {
424
+                $this->log->logException($ex, ['app' => 'core']);
425
+            }
426
+        }
427
+    }
428
+
429
+    /**
430
+     * Forward messages emitted by the repair routine
431
+     */
432
+    private function emitRepairEvents() {
433
+        $dispatcher = \OC::$server->getEventDispatcher();
434
+        $dispatcher->addListener('\OC\Repair::warning', function ($event) {
435
+            if ($event instanceof GenericEvent) {
436
+                $this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
437
+            }
438
+        });
439
+        $dispatcher->addListener('\OC\Repair::error', function ($event) {
440
+            if ($event instanceof GenericEvent) {
441
+                $this->emit('\OC\Updater', 'repairError', $event->getArguments());
442
+            }
443
+        });
444
+        $dispatcher->addListener('\OC\Repair::info', function ($event) {
445
+            if ($event instanceof GenericEvent) {
446
+                $this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
447
+            }
448
+        });
449
+        $dispatcher->addListener('\OC\Repair::step', function ($event) {
450
+            if ($event instanceof GenericEvent) {
451
+                $this->emit('\OC\Updater', 'repairStep', $event->getArguments());
452
+            }
453
+        });
454
+    }
455
+
456
+    private function logAllEvents() {
457
+        $log = $this->log;
458
+
459
+        $dispatcher = \OC::$server->getEventDispatcher();
460
+        $dispatcher->addListener('\OC\DB\Migrator::executeSql', function ($event) use ($log) {
461
+            if (!$event instanceof GenericEvent) {
462
+                return;
463
+            }
464
+            $log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
465
+        });
466
+        $dispatcher->addListener('\OC\DB\Migrator::checkTable', function ($event) use ($log) {
467
+            if (!$event instanceof GenericEvent) {
468
+                return;
469
+            }
470
+            $log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
471
+        });
472
+
473
+        $repairListener = function ($event) use ($log) {
474
+            if (!$event instanceof GenericEvent) {
475
+                return;
476
+            }
477
+            switch ($event->getSubject()) {
478
+                case '\OC\Repair::startProgress':
479
+                    $log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
480
+                    break;
481
+                case '\OC\Repair::advance':
482
+                    $desc = $event->getArgument(1);
483
+                    if (empty($desc)) {
484
+                        $desc = '';
485
+                    }
486
+                    $log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
487
+
488
+                    break;
489
+                case '\OC\Repair::finishProgress':
490
+                    $log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
491
+                    break;
492
+                case '\OC\Repair::step':
493
+                    $log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
494
+                    break;
495
+                case '\OC\Repair::info':
496
+                    $log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
497
+                    break;
498
+                case '\OC\Repair::warning':
499
+                    $log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
500
+                    break;
501
+                case '\OC\Repair::error':
502
+                    $log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
503
+                    break;
504
+            }
505
+        };
506
+
507
+        $dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
508
+        $dispatcher->addListener('\OC\Repair::advance', $repairListener);
509
+        $dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
510
+        $dispatcher->addListener('\OC\Repair::step', $repairListener);
511
+        $dispatcher->addListener('\OC\Repair::info', $repairListener);
512
+        $dispatcher->addListener('\OC\Repair::warning', $repairListener);
513
+        $dispatcher->addListener('\OC\Repair::error', $repairListener);
514
+
515
+
516
+        $this->listen('\OC\Updater', 'maintenanceEnabled', function () use ($log) {
517
+            $log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
518
+        });
519
+        $this->listen('\OC\Updater', 'maintenanceDisabled', function () use ($log) {
520
+            $log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
521
+        });
522
+        $this->listen('\OC\Updater', 'maintenanceActive', function () use ($log) {
523
+            $log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
524
+        });
525
+        $this->listen('\OC\Updater', 'updateEnd', function ($success) use ($log) {
526
+            if ($success) {
527
+                $log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
528
+            } else {
529
+                $log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
530
+            }
531
+        });
532
+        $this->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($log) {
533
+            $log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
534
+        });
535
+        $this->listen('\OC\Updater', 'dbUpgrade', function () use ($log) {
536
+            $log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
537
+        });
538
+        $this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use ($log) {
539
+            $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']);
540
+        });
541
+        $this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use ($log) {
542
+            $log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
543
+        });
544
+        $this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($log) {
545
+            $log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
546
+        });
547
+        $this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($log) {
548
+            $log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
549
+        });
550
+        $this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($log) {
551
+            $log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
552
+        });
553
+        $this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($log) {
554
+            $log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
555
+        });
556
+        $this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
557
+            $log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
558
+        });
559
+        $this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
560
+            $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']);
561
+        });
562
+        $this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
563
+            $log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
564
+        });
565
+        $this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
566
+            $log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
567
+        });
568
+        $this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
569
+            $log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
570
+        });
571
+        $this->listen('\OC\Updater', 'failure', function ($message) use ($log) {
572
+            $log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
573
+        });
574
+        $this->listen('\OC\Updater', 'setDebugLogLevel', function () use ($log) {
575
+            $log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
576
+        });
577
+        $this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($log) {
578
+            $log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
579
+        });
580
+        $this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($log) {
581
+            $log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
582
+        });
583
+        $this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($log) {
584
+            $log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
585
+        });
586
+    }
587 587
 }
Please login to merge, or discard this patch.
lib/private/Repair/Owncloud/SaveAccountsTableData.php 1 patch
Indentation   +160 added lines, -160 removed lines patch added patch discarded remove patch
@@ -36,164 +36,164 @@
 block discarded – undo
36 36
  * before the data structure is changed and the information is gone
37 37
  */
38 38
 class SaveAccountsTableData implements IRepairStep {
39
-	public const BATCH_SIZE = 75;
40
-
41
-	/** @var IDBConnection */
42
-	protected $db;
43
-
44
-	/** @var IConfig */
45
-	protected $config;
46
-
47
-	protected $hasForeignKeyOnPersistentLocks = false;
48
-
49
-	/**
50
-	 * @param IDBConnection $db
51
-	 * @param IConfig $config
52
-	 */
53
-	public function __construct(IDBConnection $db, IConfig $config) {
54
-		$this->db = $db;
55
-		$this->config = $config;
56
-	}
57
-
58
-	/**
59
-	 * @return string
60
-	 */
61
-	public function getName() {
62
-		return 'Copy data from accounts table when migrating from ownCloud';
63
-	}
64
-
65
-	/**
66
-	 * @param IOutput $output
67
-	 */
68
-	public function run(IOutput $output) {
69
-		if (!$this->shouldRun()) {
70
-			return;
71
-		}
72
-
73
-		$offset = 0;
74
-		$numUsers = $this->runStep($offset);
75
-
76
-		while ($numUsers === self::BATCH_SIZE) {
77
-			$offset += $numUsers;
78
-			$numUsers = $this->runStep($offset);
79
-		}
80
-
81
-		// oc_persistent_locks will be removed later on anyways so we can just drop and ignore any foreign key constraints here
82
-		$tableName = $this->config->getSystemValue('dbtableprefix', 'oc_') . 'persistent_locks';
83
-		$schema = $this->db->createSchema();
84
-		$table = $schema->getTable($tableName);
85
-		foreach ($table->getForeignKeys() as $foreignKey) {
86
-			$table->removeForeignKey($foreignKey->getName());
87
-		}
88
-		$this->db->migrateToSchema($schema);
89
-
90
-		// Remove the table
91
-		if ($this->hasForeignKeyOnPersistentLocks) {
92
-			$this->db->dropTable('persistent_locks');
93
-		}
94
-		$this->db->dropTable('accounts');
95
-	}
96
-
97
-	/**
98
-	 * @return bool
99
-	 */
100
-	protected function shouldRun() {
101
-		$schema = $this->db->createSchema();
102
-		$prefix = $this->config->getSystemValue('dbtableprefix', 'oc_');
103
-
104
-		$tableName = $prefix . 'accounts';
105
-		if (!$schema->hasTable($tableName)) {
106
-			return false;
107
-		}
108
-
109
-		$table = $schema->getTable($tableName);
110
-		if (!$table->hasColumn('user_id')) {
111
-			return false;
112
-		}
113
-
114
-		if ($schema->hasTable($prefix . 'persistent_locks')) {
115
-			$locksTable = $schema->getTable($prefix . 'persistent_locks');
116
-			$foreignKeys = $locksTable->getForeignKeys();
117
-			foreach ($foreignKeys as $foreignKey) {
118
-				if ($tableName === $foreignKey->getForeignTableName()) {
119
-					$this->hasForeignKeyOnPersistentLocks = true;
120
-				}
121
-			}
122
-		}
123
-
124
-		return true;
125
-	}
126
-
127
-	/**
128
-	 * @param int $offset
129
-	 * @return int Number of copied users
130
-	 */
131
-	protected function runStep($offset) {
132
-		$query = $this->db->getQueryBuilder();
133
-		$query->select('*')
134
-			->from('accounts')
135
-			->orderBy('id')
136
-			->setMaxResults(self::BATCH_SIZE);
137
-
138
-		if ($offset > 0) {
139
-			$query->setFirstResult($offset);
140
-		}
141
-
142
-		$result = $query->execute();
143
-
144
-		$update = $this->db->getQueryBuilder();
145
-		$update->update('users')
146
-			->set('displayname', $update->createParameter('displayname'))
147
-			->where($update->expr()->eq('uid', $update->createParameter('userid')));
148
-
149
-		$updatedUsers = 0;
150
-		while ($row = $result->fetch()) {
151
-			try {
152
-				$this->migrateUserInfo($update, $row);
153
-			} catch (PreConditionNotMetException $e) {
154
-				// Ignore and continue
155
-			} catch (\UnexpectedValueException $e) {
156
-				// Ignore and continue
157
-			}
158
-			$updatedUsers++;
159
-		}
160
-		$result->closeCursor();
161
-
162
-		return $updatedUsers;
163
-	}
164
-
165
-	/**
166
-	 * @param IQueryBuilder $update
167
-	 * @param array $userdata
168
-	 * @throws PreConditionNotMetException
169
-	 * @throws \UnexpectedValueException
170
-	 */
171
-	protected function migrateUserInfo(IQueryBuilder $update, $userdata) {
172
-		$state = (int) $userdata['state'];
173
-		if ($state === 3) {
174
-			// Deleted user, ignore
175
-			return;
176
-		}
177
-
178
-		if ($userdata['email'] !== null) {
179
-			$this->config->setUserValue($userdata['user_id'], 'settings', 'email', $userdata['email']);
180
-		}
181
-		if ($userdata['quota'] !== null) {
182
-			$this->config->setUserValue($userdata['user_id'], 'files', 'quota', $userdata['quota']);
183
-		}
184
-		if ($userdata['last_login'] !== null) {
185
-			$this->config->setUserValue($userdata['user_id'], 'login', 'lastLogin', $userdata['last_login']);
186
-		}
187
-		if ($state === 1) {
188
-			$this->config->setUserValue($userdata['user_id'], 'core', 'enabled', 'true');
189
-		} elseif ($state === 2) {
190
-			$this->config->setUserValue($userdata['user_id'], 'core', 'enabled', 'false');
191
-		}
192
-
193
-		if ($userdata['display_name'] !== null) {
194
-			$update->setParameter('displayname', $userdata['display_name'])
195
-				->setParameter('userid', $userdata['user_id']);
196
-			$update->execute();
197
-		}
198
-	}
39
+    public const BATCH_SIZE = 75;
40
+
41
+    /** @var IDBConnection */
42
+    protected $db;
43
+
44
+    /** @var IConfig */
45
+    protected $config;
46
+
47
+    protected $hasForeignKeyOnPersistentLocks = false;
48
+
49
+    /**
50
+     * @param IDBConnection $db
51
+     * @param IConfig $config
52
+     */
53
+    public function __construct(IDBConnection $db, IConfig $config) {
54
+        $this->db = $db;
55
+        $this->config = $config;
56
+    }
57
+
58
+    /**
59
+     * @return string
60
+     */
61
+    public function getName() {
62
+        return 'Copy data from accounts table when migrating from ownCloud';
63
+    }
64
+
65
+    /**
66
+     * @param IOutput $output
67
+     */
68
+    public function run(IOutput $output) {
69
+        if (!$this->shouldRun()) {
70
+            return;
71
+        }
72
+
73
+        $offset = 0;
74
+        $numUsers = $this->runStep($offset);
75
+
76
+        while ($numUsers === self::BATCH_SIZE) {
77
+            $offset += $numUsers;
78
+            $numUsers = $this->runStep($offset);
79
+        }
80
+
81
+        // oc_persistent_locks will be removed later on anyways so we can just drop and ignore any foreign key constraints here
82
+        $tableName = $this->config->getSystemValue('dbtableprefix', 'oc_') . 'persistent_locks';
83
+        $schema = $this->db->createSchema();
84
+        $table = $schema->getTable($tableName);
85
+        foreach ($table->getForeignKeys() as $foreignKey) {
86
+            $table->removeForeignKey($foreignKey->getName());
87
+        }
88
+        $this->db->migrateToSchema($schema);
89
+
90
+        // Remove the table
91
+        if ($this->hasForeignKeyOnPersistentLocks) {
92
+            $this->db->dropTable('persistent_locks');
93
+        }
94
+        $this->db->dropTable('accounts');
95
+    }
96
+
97
+    /**
98
+     * @return bool
99
+     */
100
+    protected function shouldRun() {
101
+        $schema = $this->db->createSchema();
102
+        $prefix = $this->config->getSystemValue('dbtableprefix', 'oc_');
103
+
104
+        $tableName = $prefix . 'accounts';
105
+        if (!$schema->hasTable($tableName)) {
106
+            return false;
107
+        }
108
+
109
+        $table = $schema->getTable($tableName);
110
+        if (!$table->hasColumn('user_id')) {
111
+            return false;
112
+        }
113
+
114
+        if ($schema->hasTable($prefix . 'persistent_locks')) {
115
+            $locksTable = $schema->getTable($prefix . 'persistent_locks');
116
+            $foreignKeys = $locksTable->getForeignKeys();
117
+            foreach ($foreignKeys as $foreignKey) {
118
+                if ($tableName === $foreignKey->getForeignTableName()) {
119
+                    $this->hasForeignKeyOnPersistentLocks = true;
120
+                }
121
+            }
122
+        }
123
+
124
+        return true;
125
+    }
126
+
127
+    /**
128
+     * @param int $offset
129
+     * @return int Number of copied users
130
+     */
131
+    protected function runStep($offset) {
132
+        $query = $this->db->getQueryBuilder();
133
+        $query->select('*')
134
+            ->from('accounts')
135
+            ->orderBy('id')
136
+            ->setMaxResults(self::BATCH_SIZE);
137
+
138
+        if ($offset > 0) {
139
+            $query->setFirstResult($offset);
140
+        }
141
+
142
+        $result = $query->execute();
143
+
144
+        $update = $this->db->getQueryBuilder();
145
+        $update->update('users')
146
+            ->set('displayname', $update->createParameter('displayname'))
147
+            ->where($update->expr()->eq('uid', $update->createParameter('userid')));
148
+
149
+        $updatedUsers = 0;
150
+        while ($row = $result->fetch()) {
151
+            try {
152
+                $this->migrateUserInfo($update, $row);
153
+            } catch (PreConditionNotMetException $e) {
154
+                // Ignore and continue
155
+            } catch (\UnexpectedValueException $e) {
156
+                // Ignore and continue
157
+            }
158
+            $updatedUsers++;
159
+        }
160
+        $result->closeCursor();
161
+
162
+        return $updatedUsers;
163
+    }
164
+
165
+    /**
166
+     * @param IQueryBuilder $update
167
+     * @param array $userdata
168
+     * @throws PreConditionNotMetException
169
+     * @throws \UnexpectedValueException
170
+     */
171
+    protected function migrateUserInfo(IQueryBuilder $update, $userdata) {
172
+        $state = (int) $userdata['state'];
173
+        if ($state === 3) {
174
+            // Deleted user, ignore
175
+            return;
176
+        }
177
+
178
+        if ($userdata['email'] !== null) {
179
+            $this->config->setUserValue($userdata['user_id'], 'settings', 'email', $userdata['email']);
180
+        }
181
+        if ($userdata['quota'] !== null) {
182
+            $this->config->setUserValue($userdata['user_id'], 'files', 'quota', $userdata['quota']);
183
+        }
184
+        if ($userdata['last_login'] !== null) {
185
+            $this->config->setUserValue($userdata['user_id'], 'login', 'lastLogin', $userdata['last_login']);
186
+        }
187
+        if ($state === 1) {
188
+            $this->config->setUserValue($userdata['user_id'], 'core', 'enabled', 'true');
189
+        } elseif ($state === 2) {
190
+            $this->config->setUserValue($userdata['user_id'], 'core', 'enabled', 'false');
191
+        }
192
+
193
+        if ($userdata['display_name'] !== null) {
194
+            $update->setParameter('displayname', $userdata['display_name'])
195
+                ->setParameter('userid', $userdata['user_id']);
196
+            $update->execute();
197
+        }
198
+    }
199 199
 }
Please login to merge, or discard this patch.
lib/private/Repair/Owncloud/CleanPreviews.php 1 patch
Indentation   +34 added lines, -34 removed lines patch added patch discarded remove patch
@@ -31,43 +31,43 @@
 block discarded – undo
31 31
 
32 32
 class CleanPreviews implements IRepairStep {
33 33
 
34
-	/** @var IJobList */
35
-	private $jobList;
34
+    /** @var IJobList */
35
+    private $jobList;
36 36
 
37
-	/** @var IUserManager */
38
-	private $userManager;
37
+    /** @var IUserManager */
38
+    private $userManager;
39 39
 
40
-	/** @var IConfig */
41
-	private $config;
40
+    /** @var IConfig */
41
+    private $config;
42 42
 
43
-	/**
44
-	 * MoveAvatars constructor.
45
-	 *
46
-	 * @param IJobList $jobList
47
-	 * @param IUserManager $userManager
48
-	 * @param IConfig $config
49
-	 */
50
-	public function __construct(IJobList $jobList,
51
-								IUserManager $userManager,
52
-								IConfig $config) {
53
-		$this->jobList = $jobList;
54
-		$this->userManager = $userManager;
55
-		$this->config = $config;
56
-	}
43
+    /**
44
+     * MoveAvatars constructor.
45
+     *
46
+     * @param IJobList $jobList
47
+     * @param IUserManager $userManager
48
+     * @param IConfig $config
49
+     */
50
+    public function __construct(IJobList $jobList,
51
+                                IUserManager $userManager,
52
+                                IConfig $config) {
53
+        $this->jobList = $jobList;
54
+        $this->userManager = $userManager;
55
+        $this->config = $config;
56
+    }
57 57
 
58
-	/**
59
-	 * @return string
60
-	 */
61
-	public function getName() {
62
-		return 'Add preview cleanup background jobs';
63
-	}
58
+    /**
59
+     * @return string
60
+     */
61
+    public function getName() {
62
+        return 'Add preview cleanup background jobs';
63
+    }
64 64
 
65
-	public function run(IOutput $output) {
66
-		if (!$this->config->getAppValue('core', 'previewsCleanedUp', false)) {
67
-			$this->userManager->callForSeenUsers(function (IUser $user) {
68
-				$this->jobList->add(CleanPreviewsBackgroundJob::class, ['uid' => $user->getUID()]);
69
-			});
70
-			$this->config->setAppValue('core', 'previewsCleanedUp', '1');
71
-		}
72
-	}
65
+    public function run(IOutput $output) {
66
+        if (!$this->config->getAppValue('core', 'previewsCleanedUp', false)) {
67
+            $this->userManager->callForSeenUsers(function (IUser $user) {
68
+                $this->jobList->add(CleanPreviewsBackgroundJob::class, ['uid' => $user->getUID()]);
69
+            });
70
+            $this->config->setAppValue('core', 'previewsCleanedUp', '1');
71
+        }
72
+    }
73 73
 }
Please login to merge, or discard this patch.
lib/private/Repair/Owncloud/InstallCoreBundle.php 1 patch
Indentation   +42 added lines, -42 removed lines patch added patch discarded remove patch
@@ -30,51 +30,51 @@
 block discarded – undo
30 30
 use OCP\Migration\IRepairStep;
31 31
 
32 32
 class InstallCoreBundle implements IRepairStep {
33
-	/** @var BundleFetcher */
34
-	private $bundleFetcher;
35
-	/** @var IConfig */
36
-	private $config;
37
-	/** @var Installer */
38
-	private $installer;
33
+    /** @var BundleFetcher */
34
+    private $bundleFetcher;
35
+    /** @var IConfig */
36
+    private $config;
37
+    /** @var Installer */
38
+    private $installer;
39 39
 
40
-	/**
41
-	 * @param BundleFetcher $bundleFetcher
42
-	 * @param IConfig $config
43
-	 * @param Installer $installer
44
-	 */
45
-	public function __construct(BundleFetcher $bundleFetcher,
46
-								IConfig $config,
47
-								Installer $installer) {
48
-		$this->bundleFetcher = $bundleFetcher;
49
-		$this->config = $config;
50
-		$this->installer = $installer;
51
-	}
40
+    /**
41
+     * @param BundleFetcher $bundleFetcher
42
+     * @param IConfig $config
43
+     * @param Installer $installer
44
+     */
45
+    public function __construct(BundleFetcher $bundleFetcher,
46
+                                IConfig $config,
47
+                                Installer $installer) {
48
+        $this->bundleFetcher = $bundleFetcher;
49
+        $this->config = $config;
50
+        $this->installer = $installer;
51
+    }
52 52
 
53
-	/**
54
-	 * {@inheritdoc}
55
-	 */
56
-	public function getName() {
57
-		return 'Install new core bundle components';
58
-	}
53
+    /**
54
+     * {@inheritdoc}
55
+     */
56
+    public function getName() {
57
+        return 'Install new core bundle components';
58
+    }
59 59
 
60
-	/**
61
-	 * {@inheritdoc}
62
-	 */
63
-	public function run(IOutput $output) {
64
-		$versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
60
+    /**
61
+     * {@inheritdoc}
62
+     */
63
+    public function run(IOutput $output) {
64
+        $versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
65 65
 
66
-		if (version_compare($versionFromBeforeUpdate, '12.0.0.14', '>')) {
67
-			return;
68
-		}
66
+        if (version_compare($versionFromBeforeUpdate, '12.0.0.14', '>')) {
67
+            return;
68
+        }
69 69
 
70
-		$defaultBundle = $this->bundleFetcher->getDefaultInstallationBundle();
71
-		foreach ($defaultBundle as $bundle) {
72
-			try {
73
-				$this->installer->installAppBundle($bundle);
74
-				$output->info('Successfully installed core app bundle.');
75
-			} catch (\Exception $e) {
76
-				$output->warning('Could not install core app bundle: ' . $e->getMessage());
77
-			}
78
-		}
79
-	}
70
+        $defaultBundle = $this->bundleFetcher->getDefaultInstallationBundle();
71
+        foreach ($defaultBundle as $bundle) {
72
+            try {
73
+                $this->installer->installAppBundle($bundle);
74
+                $output->info('Successfully installed core app bundle.');
75
+            } catch (\Exception $e) {
76
+                $output->warning('Could not install core app bundle: ' . $e->getMessage());
77
+            }
78
+        }
79
+    }
80 80
 }
Please login to merge, or discard this patch.
lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php 1 patch
Indentation   +96 added lines, -96 removed lines patch added patch discarded remove patch
@@ -33,100 +33,100 @@
 block discarded – undo
33 33
 use OCP\IUserManager;
34 34
 
35 35
 class CleanPreviewsBackgroundJob extends QueuedJob {
36
-	/** @var IRootFolder */
37
-	private $rootFolder;
38
-
39
-	/** @var ILogger */
40
-	private $logger;
41
-
42
-	/** @var IJobList */
43
-	private $jobList;
44
-
45
-	/** @var ITimeFactory */
46
-	private $timeFactory;
47
-
48
-	/** @var IUserManager */
49
-	private $userManager;
50
-
51
-	/**
52
-	 * CleanPreviewsBackgroundJob constructor.
53
-	 *
54
-	 * @param IRootFolder $rootFolder
55
-	 * @param ILogger $logger
56
-	 * @param IJobList $jobList
57
-	 * @param ITimeFactory $timeFactory
58
-	 * @param IUserManager $userManager
59
-	 */
60
-	public function __construct(IRootFolder $rootFolder,
61
-								ILogger $logger,
62
-								IJobList $jobList,
63
-								ITimeFactory $timeFactory,
64
-								IUserManager $userManager) {
65
-		$this->rootFolder = $rootFolder;
66
-		$this->logger = $logger;
67
-		$this->jobList = $jobList;
68
-		$this->timeFactory = $timeFactory;
69
-		$this->userManager = $userManager;
70
-	}
71
-
72
-	public function run($arguments) {
73
-		$uid = $arguments['uid'];
74
-		if (!$this->userManager->userExists($uid)) {
75
-			$this->logger->info('User no longer exists, skip user ' . $uid);
76
-			return;
77
-		}
78
-		$this->logger->info('Started preview cleanup for ' . $uid);
79
-		$empty = $this->cleanupPreviews($uid);
80
-
81
-		if (!$empty) {
82
-			$this->jobList->add(self::class, ['uid' => $uid]);
83
-			$this->logger->info('New preview cleanup scheduled for ' . $uid);
84
-		} else {
85
-			$this->logger->info('Preview cleanup done for ' . $uid);
86
-		}
87
-	}
88
-
89
-	/**
90
-	 * @param $uid
91
-	 * @return bool
92
-	 */
93
-	private function cleanupPreviews($uid) {
94
-		try {
95
-			$userFolder = $this->rootFolder->getUserFolder($uid);
96
-		} catch (NotFoundException $e) {
97
-			return true;
98
-		}
99
-
100
-		$userRoot = $userFolder->getParent();
101
-
102
-		try {
103
-			/** @var Folder $thumbnailFolder */
104
-			$thumbnailFolder = $userRoot->get('thumbnails');
105
-		} catch (NotFoundException $e) {
106
-			return true;
107
-		}
108
-
109
-		$thumbnails = $thumbnailFolder->getDirectoryListing();
110
-
111
-		$start = $this->timeFactory->getTime();
112
-		foreach ($thumbnails as $thumbnail) {
113
-			try {
114
-				$thumbnail->delete();
115
-			} catch (NotPermittedException $e) {
116
-				// Ignore
117
-			}
118
-
119
-			if (($this->timeFactory->getTime() - $start) > 15) {
120
-				return false;
121
-			}
122
-		}
123
-
124
-		try {
125
-			$thumbnailFolder->delete();
126
-		} catch (NotPermittedException $e) {
127
-			// Ignore
128
-		}
129
-
130
-		return true;
131
-	}
36
+    /** @var IRootFolder */
37
+    private $rootFolder;
38
+
39
+    /** @var ILogger */
40
+    private $logger;
41
+
42
+    /** @var IJobList */
43
+    private $jobList;
44
+
45
+    /** @var ITimeFactory */
46
+    private $timeFactory;
47
+
48
+    /** @var IUserManager */
49
+    private $userManager;
50
+
51
+    /**
52
+     * CleanPreviewsBackgroundJob constructor.
53
+     *
54
+     * @param IRootFolder $rootFolder
55
+     * @param ILogger $logger
56
+     * @param IJobList $jobList
57
+     * @param ITimeFactory $timeFactory
58
+     * @param IUserManager $userManager
59
+     */
60
+    public function __construct(IRootFolder $rootFolder,
61
+                                ILogger $logger,
62
+                                IJobList $jobList,
63
+                                ITimeFactory $timeFactory,
64
+                                IUserManager $userManager) {
65
+        $this->rootFolder = $rootFolder;
66
+        $this->logger = $logger;
67
+        $this->jobList = $jobList;
68
+        $this->timeFactory = $timeFactory;
69
+        $this->userManager = $userManager;
70
+    }
71
+
72
+    public function run($arguments) {
73
+        $uid = $arguments['uid'];
74
+        if (!$this->userManager->userExists($uid)) {
75
+            $this->logger->info('User no longer exists, skip user ' . $uid);
76
+            return;
77
+        }
78
+        $this->logger->info('Started preview cleanup for ' . $uid);
79
+        $empty = $this->cleanupPreviews($uid);
80
+
81
+        if (!$empty) {
82
+            $this->jobList->add(self::class, ['uid' => $uid]);
83
+            $this->logger->info('New preview cleanup scheduled for ' . $uid);
84
+        } else {
85
+            $this->logger->info('Preview cleanup done for ' . $uid);
86
+        }
87
+    }
88
+
89
+    /**
90
+     * @param $uid
91
+     * @return bool
92
+     */
93
+    private function cleanupPreviews($uid) {
94
+        try {
95
+            $userFolder = $this->rootFolder->getUserFolder($uid);
96
+        } catch (NotFoundException $e) {
97
+            return true;
98
+        }
99
+
100
+        $userRoot = $userFolder->getParent();
101
+
102
+        try {
103
+            /** @var Folder $thumbnailFolder */
104
+            $thumbnailFolder = $userRoot->get('thumbnails');
105
+        } catch (NotFoundException $e) {
106
+            return true;
107
+        }
108
+
109
+        $thumbnails = $thumbnailFolder->getDirectoryListing();
110
+
111
+        $start = $this->timeFactory->getTime();
112
+        foreach ($thumbnails as $thumbnail) {
113
+            try {
114
+                $thumbnail->delete();
115
+            } catch (NotPermittedException $e) {
116
+                // Ignore
117
+            }
118
+
119
+            if (($this->timeFactory->getTime() - $start) > 15) {
120
+                return false;
121
+            }
122
+        }
123
+
124
+        try {
125
+            $thumbnailFolder->delete();
126
+        } catch (NotPermittedException $e) {
127
+            // Ignore
128
+        }
129
+
130
+        return true;
131
+    }
132 132
 }
Please login to merge, or discard this patch.
lib/private/Repair/Owncloud/MoveAvatars.php 1 patch
Indentation   +36 added lines, -36 removed lines patch added patch discarded remove patch
@@ -29,44 +29,44 @@
 block discarded – undo
29 29
 
30 30
 class MoveAvatars implements IRepairStep {
31 31
 
32
-	/** @var IJobList */
33
-	private $jobList;
32
+    /** @var IJobList */
33
+    private $jobList;
34 34
 
35
-	/** @var IConfig */
36
-	private $config;
35
+    /** @var IConfig */
36
+    private $config;
37 37
 
38
-	/**
39
-	 * MoveAvatars constructor.
40
-	 *
41
-	 * @param IJobList $jobList
42
-	 * @param IConfig $config
43
-	 */
44
-	public function __construct(IJobList $jobList,
45
-								IConfig $config) {
46
-		$this->jobList = $jobList;
47
-		$this->config = $config;
48
-	}
38
+    /**
39
+     * MoveAvatars constructor.
40
+     *
41
+     * @param IJobList $jobList
42
+     * @param IConfig $config
43
+     */
44
+    public function __construct(IJobList $jobList,
45
+                                IConfig $config) {
46
+        $this->jobList = $jobList;
47
+        $this->config = $config;
48
+    }
49 49
 
50
-	/**
51
-	 * @return string
52
-	 */
53
-	public function getName() {
54
-		return 'Add move avatar background job';
55
-	}
50
+    /**
51
+     * @return string
52
+     */
53
+    public function getName() {
54
+        return 'Add move avatar background job';
55
+    }
56 56
 
57
-	public function run(IOutput $output) {
58
-		// only run once
59
-		if ($this->config->getAppValue('core', 'moveavatarsdone') === 'yes') {
60
-			$output->info('Repair step already executed');
61
-			return;
62
-		}
63
-		if ($this->config->getSystemValue('enable_avatars', true) === false) {
64
-			$output->info('Avatars are disabled');
65
-		} else {
66
-			$output->info('Add background job');
67
-			$this->jobList->add(MoveAvatarsBackgroundJob::class);
68
-			// if all were done, no need to redo the repair during next upgrade
69
-			$this->config->setAppValue('core', 'moveavatarsdone', 'yes');
70
-		}
71
-	}
57
+    public function run(IOutput $output) {
58
+        // only run once
59
+        if ($this->config->getAppValue('core', 'moveavatarsdone') === 'yes') {
60
+            $output->info('Repair step already executed');
61
+            return;
62
+        }
63
+        if ($this->config->getSystemValue('enable_avatars', true) === false) {
64
+            $output->info('Avatars are disabled');
65
+        } else {
66
+            $output->info('Add background job');
67
+            $this->jobList->add(MoveAvatarsBackgroundJob::class);
68
+            // if all were done, no need to redo the repair during next upgrade
69
+            $this->config->setAppValue('core', 'moveavatarsdone', 'yes');
70
+        }
71
+    }
72 72
 }
Please login to merge, or discard this patch.
lib/private/Repair/Owncloud/MoveAvatarsBackgroundJob.php 1 patch
Indentation   +67 added lines, -67 removed lines patch added patch discarded remove patch
@@ -35,82 +35,82 @@
 block discarded – undo
35 35
 
36 36
 class MoveAvatarsBackgroundJob extends QueuedJob {
37 37
 
38
-	/** @var IUserManager */
39
-	private $userManager;
38
+    /** @var IUserManager */
39
+    private $userManager;
40 40
 
41
-	/** @var LoggerInterface */
42
-	private $logger;
41
+    /** @var LoggerInterface */
42
+    private $logger;
43 43
 
44
-	/** @var IAvatarManager */
45
-	private $avatarManager;
44
+    /** @var IAvatarManager */
45
+    private $avatarManager;
46 46
 
47
-	/** @var Storage */
48
-	private $owncloudAvatarStorage;
47
+    /** @var Storage */
48
+    private $owncloudAvatarStorage;
49 49
 
50
-	public function __construct(IUserManager $userManager, LoggerInterface $logger, IAvatarManager $avatarManager, IRootFolder $rootFolder) {
51
-		$this->userManager = $userManager;
52
-		$this->logger = $logger;
53
-		$this->avatarManager = $avatarManager;
54
-		try {
55
-			$this->owncloudAvatarStorage = $rootFolder->get('avatars')->getStorage();
56
-		} catch (\Exception $e) {
57
-		}
58
-	}
50
+    public function __construct(IUserManager $userManager, LoggerInterface $logger, IAvatarManager $avatarManager, IRootFolder $rootFolder) {
51
+        $this->userManager = $userManager;
52
+        $this->logger = $logger;
53
+        $this->avatarManager = $avatarManager;
54
+        try {
55
+            $this->owncloudAvatarStorage = $rootFolder->get('avatars')->getStorage();
56
+        } catch (\Exception $e) {
57
+        }
58
+    }
59 59
 
60
-	public function run($arguments) {
61
-		$this->logger->info('Started migrating avatars to AppData folder');
62
-		$this->moveAvatars();
63
-		$this->logger->info('All avatars migrated to AppData folder');
64
-	}
60
+    public function run($arguments) {
61
+        $this->logger->info('Started migrating avatars to AppData folder');
62
+        $this->moveAvatars();
63
+        $this->logger->info('All avatars migrated to AppData folder');
64
+    }
65 65
 
66
-	private function moveAvatars(): void {
67
-		if (!$this->owncloudAvatarStorage) {
68
-			$this->logger->info('No legacy avatars available, skipping migration');
69
-			return;
70
-		}
66
+    private function moveAvatars(): void {
67
+        if (!$this->owncloudAvatarStorage) {
68
+            $this->logger->info('No legacy avatars available, skipping migration');
69
+            return;
70
+        }
71 71
 
72
-		$counter = 0;
73
-		$this->userManager->callForSeenUsers(function (IUser $user) use ($counter) {
74
-			$uid = $user->getUID();
72
+        $counter = 0;
73
+        $this->userManager->callForSeenUsers(function (IUser $user) use ($counter) {
74
+            $uid = $user->getUID();
75 75
 
76
-			$path = 'avatars/' . $this->buildOwnCloudAvatarPath($uid);
77
-			$avatar = $this->avatarManager->getAvatar($uid);
78
-			try {
79
-				$avatarPath = $path . '/avatar.' . $this->getExtension($path);
80
-				$resource = $this->owncloudAvatarStorage->fopen($avatarPath, 'r');
81
-				if ($resource) {
82
-					$avatar->set($resource);
83
-					fclose($resource);
84
-				} else {
85
-					throw new \Exception('Failed to open old avatar file for reading');
86
-				}
87
-			} catch (NotFoundException $e) {
88
-				// In case there is no avatar we can just skip
89
-			} catch (\Throwable $e) {
90
-				$this->logger->error('Failed to migrate avatar for user ' . $uid, ['exception' => $e]);
91
-			}
76
+            $path = 'avatars/' . $this->buildOwnCloudAvatarPath($uid);
77
+            $avatar = $this->avatarManager->getAvatar($uid);
78
+            try {
79
+                $avatarPath = $path . '/avatar.' . $this->getExtension($path);
80
+                $resource = $this->owncloudAvatarStorage->fopen($avatarPath, 'r');
81
+                if ($resource) {
82
+                    $avatar->set($resource);
83
+                    fclose($resource);
84
+                } else {
85
+                    throw new \Exception('Failed to open old avatar file for reading');
86
+                }
87
+            } catch (NotFoundException $e) {
88
+                // In case there is no avatar we can just skip
89
+            } catch (\Throwable $e) {
90
+                $this->logger->error('Failed to migrate avatar for user ' . $uid, ['exception' => $e]);
91
+            }
92 92
 
93
-			$counter++;
94
-			if ($counter % 100 === 0) {
95
-				$this->logger->info('{amount} avatars migrated', ['amount' => $counter]);
96
-			}
97
-		});
98
-	}
93
+            $counter++;
94
+            if ($counter % 100 === 0) {
95
+                $this->logger->info('{amount} avatars migrated', ['amount' => $counter]);
96
+            }
97
+        });
98
+    }
99 99
 
100
-	/**
101
-	 * @throws NotFoundException
102
-	 */
103
-	private function getExtension(string $path): string {
104
-		if ($this->owncloudAvatarStorage->file_exists("{$path}/avatar.jpg")) {
105
-			return 'jpg';
106
-		}
107
-		if ($this->owncloudAvatarStorage->file_exists("{$path}/avatar.png")) {
108
-			return 'png';
109
-		}
110
-		throw new NotFoundException("{$path}/avatar.jpg|png");
111
-	}
100
+    /**
101
+     * @throws NotFoundException
102
+     */
103
+    private function getExtension(string $path): string {
104
+        if ($this->owncloudAvatarStorage->file_exists("{$path}/avatar.jpg")) {
105
+            return 'jpg';
106
+        }
107
+        if ($this->owncloudAvatarStorage->file_exists("{$path}/avatar.png")) {
108
+            return 'png';
109
+        }
110
+        throw new NotFoundException("{$path}/avatar.jpg|png");
111
+    }
112 112
 
113
-	protected function buildOwnCloudAvatarPath(string $userId): string {
114
-		return substr_replace(substr_replace(md5($userId), '/', 4, 0), '/', 2, 0);
115
-	}
113
+    protected function buildOwnCloudAvatarPath(string $userId): string {
114
+        return substr_replace(substr_replace(md5($userId), '/', 4, 0), '/', 2, 0);
115
+    }
116 116
 }
Please login to merge, or discard this patch.
lib/private/Repair/Owncloud/UpdateLanguageCodes.php 1 patch
Indentation   +47 added lines, -47 removed lines patch added patch discarded remove patch
@@ -31,60 +31,60 @@
 block discarded – undo
31 31
 use OCP\Migration\IRepairStep;
32 32
 
33 33
 class UpdateLanguageCodes implements IRepairStep {
34
-	/** @var IDBConnection */
35
-	private $connection;
34
+    /** @var IDBConnection */
35
+    private $connection;
36 36
 
37
-	/** @var IConfig */
38
-	private $config;
37
+    /** @var IConfig */
38
+    private $config;
39 39
 
40
-	/**
41
-	 * @param IDBConnection $connection
42
-	 * @param IConfig $config
43
-	 */
44
-	public function __construct(IDBConnection $connection,
45
-								IConfig $config) {
46
-		$this->connection = $connection;
47
-		$this->config = $config;
48
-	}
40
+    /**
41
+     * @param IDBConnection $connection
42
+     * @param IConfig $config
43
+     */
44
+    public function __construct(IDBConnection $connection,
45
+                                IConfig $config) {
46
+        $this->connection = $connection;
47
+        $this->config = $config;
48
+    }
49 49
 
50
-	/**
51
-	 * {@inheritdoc}
52
-	 */
53
-	public function getName() {
54
-		return 'Repair language codes';
55
-	}
50
+    /**
51
+     * {@inheritdoc}
52
+     */
53
+    public function getName() {
54
+        return 'Repair language codes';
55
+    }
56 56
 
57
-	/**
58
-	 * {@inheritdoc}
59
-	 */
60
-	public function run(IOutput $output) {
61
-		$versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
57
+    /**
58
+     * {@inheritdoc}
59
+     */
60
+    public function run(IOutput $output) {
61
+        $versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
62 62
 
63
-		if (version_compare($versionFromBeforeUpdate, '12.0.0.13', '>')) {
64
-			return;
65
-		}
63
+        if (version_compare($versionFromBeforeUpdate, '12.0.0.13', '>')) {
64
+            return;
65
+        }
66 66
 
67
-		$languages = [
68
-			'bg_BG' => 'bg',
69
-			'cs_CZ' => 'cs',
70
-			'fi_FI' => 'fi',
71
-			'hu_HU' => 'hu',
72
-			'nb_NO' => 'nb',
73
-			'sk_SK' => 'sk',
74
-			'th_TH' => 'th',
75
-		];
67
+        $languages = [
68
+            'bg_BG' => 'bg',
69
+            'cs_CZ' => 'cs',
70
+            'fi_FI' => 'fi',
71
+            'hu_HU' => 'hu',
72
+            'nb_NO' => 'nb',
73
+            'sk_SK' => 'sk',
74
+            'th_TH' => 'th',
75
+        ];
76 76
 
77
-		foreach ($languages as $oldCode => $newCode) {
78
-			$qb = $this->connection->getQueryBuilder();
77
+        foreach ($languages as $oldCode => $newCode) {
78
+            $qb = $this->connection->getQueryBuilder();
79 79
 
80
-			$affectedRows = $qb->update('preferences')
81
-				->set('configvalue', $qb->createNamedParameter($newCode))
82
-				->where($qb->expr()->eq('appid', $qb->createNamedParameter('core')))
83
-				->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter('lang')))
84
-				->andWhere($qb->expr()->eq('configvalue', $qb->createNamedParameter($oldCode), IQueryBuilder::PARAM_STR))
85
-				->execute();
80
+            $affectedRows = $qb->update('preferences')
81
+                ->set('configvalue', $qb->createNamedParameter($newCode))
82
+                ->where($qb->expr()->eq('appid', $qb->createNamedParameter('core')))
83
+                ->andWhere($qb->expr()->eq('configkey', $qb->createNamedParameter('lang')))
84
+                ->andWhere($qb->expr()->eq('configvalue', $qb->createNamedParameter($oldCode), IQueryBuilder::PARAM_STR))
85
+                ->execute();
86 86
 
87
-			$output->info('Changed ' . $affectedRows . ' setting(s) from "' . $oldCode . '" to "' . $newCode . '" in preferences table.');
88
-		}
89
-	}
87
+            $output->info('Changed ' . $affectedRows . ' setting(s) from "' . $oldCode . '" to "' . $newCode . '" in preferences table.');
88
+        }
89
+    }
90 90
 }
Please login to merge, or discard this patch.
lib/private/Security/Bruteforce/Capabilities.php 1 patch
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -27,33 +27,33 @@
 block discarded – undo
27 27
 use OCP\IRequest;
28 28
 
29 29
 class Capabilities implements IPublicCapability {
30
-	/** @var IRequest */
31
-	private $request;
30
+    /** @var IRequest */
31
+    private $request;
32 32
 
33
-	/** @var Throttler */
34
-	private $throttler;
33
+    /** @var Throttler */
34
+    private $throttler;
35 35
 
36
-	/**
37
-	 * Capabilities constructor.
38
-	 *
39
-	 * @param IRequest $request
40
-	 * @param Throttler $throttler
41
-	 */
42
-	public function __construct(IRequest $request,
43
-								Throttler $throttler) {
44
-		$this->request = $request;
45
-		$this->throttler = $throttler;
46
-	}
36
+    /**
37
+     * Capabilities constructor.
38
+     *
39
+     * @param IRequest $request
40
+     * @param Throttler $throttler
41
+     */
42
+    public function __construct(IRequest $request,
43
+                                Throttler $throttler) {
44
+        $this->request = $request;
45
+        $this->throttler = $throttler;
46
+    }
47 47
 
48
-	public function getCapabilities() {
49
-		if (version_compare(\OC::$server->getConfig()->getSystemValue('version', '0.0.0.0'), '12.0.0.0', '<')) {
50
-			return [];
51
-		}
48
+    public function getCapabilities() {
49
+        if (version_compare(\OC::$server->getConfig()->getSystemValue('version', '0.0.0.0'), '12.0.0.0', '<')) {
50
+            return [];
51
+        }
52 52
 
53
-		return [
54
-			'bruteforce' => [
55
-				'delay' => $this->throttler->getDelay($this->request->getRemoteAddress())
56
-			]
57
-		];
58
-	}
53
+        return [
54
+            'bruteforce' => [
55
+                'delay' => $this->throttler->getDelay($this->request->getRemoteAddress())
56
+            ]
57
+        ];
58
+    }
59 59
 }
Please login to merge, or discard this patch.