Passed
Push — master ( 6401d8...dd39f5 )
by Daniel
15:55 queued 10s
created
core/Command/Maintenance/Repair.php 1 patch
Indentation   +106 added lines, -106 removed lines patch added patch discarded remove patch
@@ -41,121 +41,121 @@
 block discarded – undo
41 41
 use Symfony\Component\EventDispatcher\GenericEvent;
42 42
 
43 43
 class Repair extends Command {
44
-	/** @var \OC\Repair $repair */
45
-	protected $repair;
46
-	/** @var IConfig */
47
-	protected $config;
48
-	/** @var EventDispatcherInterface */
49
-	private $dispatcher;
50
-	/** @var ProgressBar */
51
-	private $progress;
52
-	/** @var OutputInterface */
53
-	private $output;
54
-	/** @var IAppManager */
55
-	private $appManager;
44
+    /** @var \OC\Repair $repair */
45
+    protected $repair;
46
+    /** @var IConfig */
47
+    protected $config;
48
+    /** @var EventDispatcherInterface */
49
+    private $dispatcher;
50
+    /** @var ProgressBar */
51
+    private $progress;
52
+    /** @var OutputInterface */
53
+    private $output;
54
+    /** @var IAppManager */
55
+    private $appManager;
56 56
 
57
-	/**
58
-	 * @param \OC\Repair $repair
59
-	 * @param IConfig $config
60
-	 * @param EventDispatcherInterface $dispatcher
61
-	 * @param IAppManager $appManager
62
-	 */
63
-	public function __construct(\OC\Repair $repair, IConfig $config, EventDispatcherInterface $dispatcher, IAppManager $appManager) {
64
-		$this->repair = $repair;
65
-		$this->config = $config;
66
-		$this->dispatcher = $dispatcher;
67
-		$this->appManager = $appManager;
68
-		parent::__construct();
69
-	}
57
+    /**
58
+     * @param \OC\Repair $repair
59
+     * @param IConfig $config
60
+     * @param EventDispatcherInterface $dispatcher
61
+     * @param IAppManager $appManager
62
+     */
63
+    public function __construct(\OC\Repair $repair, IConfig $config, EventDispatcherInterface $dispatcher, IAppManager $appManager) {
64
+        $this->repair = $repair;
65
+        $this->config = $config;
66
+        $this->dispatcher = $dispatcher;
67
+        $this->appManager = $appManager;
68
+        parent::__construct();
69
+    }
70 70
 
71
-	protected function configure() {
72
-		$this
73
-			->setName('maintenance:repair')
74
-			->setDescription('repair this installation')
75
-			->addOption(
76
-				'include-expensive',
77
-				null,
78
-				InputOption::VALUE_NONE,
79
-				'Use this option when you want to include resource and load expensive tasks');
80
-	}
71
+    protected function configure() {
72
+        $this
73
+            ->setName('maintenance:repair')
74
+            ->setDescription('repair this installation')
75
+            ->addOption(
76
+                'include-expensive',
77
+                null,
78
+                InputOption::VALUE_NONE,
79
+                'Use this option when you want to include resource and load expensive tasks');
80
+    }
81 81
 
82
-	protected function execute(InputInterface $input, OutputInterface $output): int {
83
-		$repairSteps = $this->repair::getRepairSteps();
82
+    protected function execute(InputInterface $input, OutputInterface $output): int {
83
+        $repairSteps = $this->repair::getRepairSteps();
84 84
 
85
-		if ($input->getOption('include-expensive')) {
86
-			$repairSteps = array_merge($repairSteps, $this->repair::getExpensiveRepairSteps());
87
-		}
85
+        if ($input->getOption('include-expensive')) {
86
+            $repairSteps = array_merge($repairSteps, $this->repair::getExpensiveRepairSteps());
87
+        }
88 88
 
89
-		foreach ($repairSteps as $step) {
90
-			$this->repair->addStep($step);
91
-		}
89
+        foreach ($repairSteps as $step) {
90
+            $this->repair->addStep($step);
91
+        }
92 92
 
93
-		$apps = $this->appManager->getInstalledApps();
94
-		foreach ($apps as $app) {
95
-			if (!$this->appManager->isEnabledForUser($app)) {
96
-				continue;
97
-			}
98
-			$info = \OC_App::getAppInfo($app);
99
-			if (!is_array($info)) {
100
-				continue;
101
-			}
102
-			\OC_App::loadApp($app);
103
-			$steps = $info['repair-steps']['post-migration'];
104
-			foreach ($steps as $step) {
105
-				try {
106
-					$this->repair->addStep($step);
107
-				} catch (Exception $ex) {
108
-					$output->writeln("<error>Failed to load repair step for $app: {$ex->getMessage()}</error>");
109
-				}
110
-			}
111
-		}
93
+        $apps = $this->appManager->getInstalledApps();
94
+        foreach ($apps as $app) {
95
+            if (!$this->appManager->isEnabledForUser($app)) {
96
+                continue;
97
+            }
98
+            $info = \OC_App::getAppInfo($app);
99
+            if (!is_array($info)) {
100
+                continue;
101
+            }
102
+            \OC_App::loadApp($app);
103
+            $steps = $info['repair-steps']['post-migration'];
104
+            foreach ($steps as $step) {
105
+                try {
106
+                    $this->repair->addStep($step);
107
+                } catch (Exception $ex) {
108
+                    $output->writeln("<error>Failed to load repair step for $app: {$ex->getMessage()}</error>");
109
+                }
110
+            }
111
+        }
112 112
 
113
-		$maintenanceMode = $this->config->getSystemValueBool('maintenance');
114
-		$this->config->setSystemValue('maintenance', true);
113
+        $maintenanceMode = $this->config->getSystemValueBool('maintenance');
114
+        $this->config->setSystemValue('maintenance', true);
115 115
 
116
-		$this->progress = new ProgressBar($output);
117
-		$this->output = $output;
118
-		$this->dispatcher->addListener('\OC\Repair::startProgress', [$this, 'handleRepairFeedBack']);
119
-		$this->dispatcher->addListener('\OC\Repair::advance', [$this, 'handleRepairFeedBack']);
120
-		$this->dispatcher->addListener('\OC\Repair::finishProgress', [$this, 'handleRepairFeedBack']);
121
-		$this->dispatcher->addListener('\OC\Repair::step', [$this, 'handleRepairFeedBack']);
122
-		$this->dispatcher->addListener('\OC\Repair::info', [$this, 'handleRepairFeedBack']);
123
-		$this->dispatcher->addListener('\OC\Repair::warning', [$this, 'handleRepairFeedBack']);
124
-		$this->dispatcher->addListener('\OC\Repair::error', [$this, 'handleRepairFeedBack']);
116
+        $this->progress = new ProgressBar($output);
117
+        $this->output = $output;
118
+        $this->dispatcher->addListener('\OC\Repair::startProgress', [$this, 'handleRepairFeedBack']);
119
+        $this->dispatcher->addListener('\OC\Repair::advance', [$this, 'handleRepairFeedBack']);
120
+        $this->dispatcher->addListener('\OC\Repair::finishProgress', [$this, 'handleRepairFeedBack']);
121
+        $this->dispatcher->addListener('\OC\Repair::step', [$this, 'handleRepairFeedBack']);
122
+        $this->dispatcher->addListener('\OC\Repair::info', [$this, 'handleRepairFeedBack']);
123
+        $this->dispatcher->addListener('\OC\Repair::warning', [$this, 'handleRepairFeedBack']);
124
+        $this->dispatcher->addListener('\OC\Repair::error', [$this, 'handleRepairFeedBack']);
125 125
 
126
-		$this->repair->run();
126
+        $this->repair->run();
127 127
 
128
-		$this->config->setSystemValue('maintenance', $maintenanceMode);
129
-		return 0;
130
-	}
128
+        $this->config->setSystemValue('maintenance', $maintenanceMode);
129
+        return 0;
130
+    }
131 131
 
132
-	public function handleRepairFeedBack($event) {
133
-		if (!$event instanceof GenericEvent) {
134
-			return;
135
-		}
136
-		switch ($event->getSubject()) {
137
-			case '\OC\Repair::startProgress':
138
-				$this->progress->start($event->getArgument(0));
139
-				break;
140
-			case '\OC\Repair::advance':
141
-				$this->progress->advance($event->getArgument(0));
142
-				break;
143
-			case '\OC\Repair::finishProgress':
144
-				$this->progress->finish();
145
-				$this->output->writeln('');
146
-				break;
147
-			case '\OC\Repair::step':
148
-				$this->output->writeln(' - ' . $event->getArgument(0));
149
-				break;
150
-			case '\OC\Repair::info':
151
-				$this->output->writeln('     - ' . $event->getArgument(0));
152
-				break;
153
-			case '\OC\Repair::warning':
154
-				$this->output->writeln('     - WARNING: ' . $event->getArgument(0));
155
-				break;
156
-			case '\OC\Repair::error':
157
-				$this->output->writeln('<error>     - ERROR: ' . $event->getArgument(0) . '</error>');
158
-				break;
159
-		}
160
-	}
132
+    public function handleRepairFeedBack($event) {
133
+        if (!$event instanceof GenericEvent) {
134
+            return;
135
+        }
136
+        switch ($event->getSubject()) {
137
+            case '\OC\Repair::startProgress':
138
+                $this->progress->start($event->getArgument(0));
139
+                break;
140
+            case '\OC\Repair::advance':
141
+                $this->progress->advance($event->getArgument(0));
142
+                break;
143
+            case '\OC\Repair::finishProgress':
144
+                $this->progress->finish();
145
+                $this->output->writeln('');
146
+                break;
147
+            case '\OC\Repair::step':
148
+                $this->output->writeln(' - ' . $event->getArgument(0));
149
+                break;
150
+            case '\OC\Repair::info':
151
+                $this->output->writeln('     - ' . $event->getArgument(0));
152
+                break;
153
+            case '\OC\Repair::warning':
154
+                $this->output->writeln('     - WARNING: ' . $event->getArgument(0));
155
+                break;
156
+            case '\OC\Repair::error':
157
+                $this->output->writeln('<error>     - ERROR: ' . $event->getArgument(0) . '</error>');
158
+                break;
159
+        }
160
+    }
161 161
 }
Please login to merge, or discard this patch.
core/register_command.php 1 patch
Indentation   +131 added lines, -131 removed lines patch added patch discarded remove patch
@@ -54,146 +54,146 @@
 block discarded – undo
54 54
 $application->add(new OC\Core\Command\App\CheckCode());
55 55
 $application->add(new OC\Core\Command\L10n\CreateJs());
56 56
 $application->add(new \OC\Core\Command\Integrity\SignApp(
57
-		\OC::$server->getIntegrityCodeChecker(),
58
-		new \OC\IntegrityCheck\Helpers\FileAccessHelper(),
59
-		\OC::$server->getURLGenerator()
57
+        \OC::$server->getIntegrityCodeChecker(),
58
+        new \OC\IntegrityCheck\Helpers\FileAccessHelper(),
59
+        \OC::$server->getURLGenerator()
60 60
 ));
61 61
 $application->add(new \OC\Core\Command\Integrity\SignCore(
62
-		\OC::$server->getIntegrityCodeChecker(),
63
-		new \OC\IntegrityCheck\Helpers\FileAccessHelper()
62
+        \OC::$server->getIntegrityCodeChecker(),
63
+        new \OC\IntegrityCheck\Helpers\FileAccessHelper()
64 64
 ));
65 65
 $application->add(new \OC\Core\Command\Integrity\CheckApp(
66
-		\OC::$server->getIntegrityCodeChecker()
66
+        \OC::$server->getIntegrityCodeChecker()
67 67
 ));
68 68
 $application->add(new \OC\Core\Command\Integrity\CheckCore(
69
-		\OC::$server->getIntegrityCodeChecker()
69
+        \OC::$server->getIntegrityCodeChecker()
70 70
 ));
71 71
 
72 72
 
73 73
 if (\OC::$server->getConfig()->getSystemValue('installed', false)) {
74
-	$application->add(new OC\Core\Command\App\Disable(\OC::$server->getAppManager()));
75
-	$application->add(new OC\Core\Command\App\Enable(\OC::$server->getAppManager(), \OC::$server->getGroupManager()));
76
-	$application->add(new OC\Core\Command\App\Install());
77
-	$application->add(new OC\Core\Command\App\GetPath());
78
-	$application->add(new OC\Core\Command\App\ListApps(\OC::$server->getAppManager()));
79
-	$application->add(new OC\Core\Command\App\Remove(\OC::$server->getAppManager(), \OC::$server->query(\OC\Installer::class), \OC::$server->getLogger()));
80
-	$application->add(\OC::$server->query(\OC\Core\Command\App\Update::class));
81
-
82
-	$application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Cleanup::class));
83
-	$application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Enforce::class));
84
-	$application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Enable::class));
85
-	$application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Disable::class));
86
-	$application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\State::class));
87
-
88
-	$application->add(new OC\Core\Command\Background\Cron(\OC::$server->getConfig()));
89
-	$application->add(new OC\Core\Command\Background\WebCron(\OC::$server->getConfig()));
90
-	$application->add(new OC\Core\Command\Background\Ajax(\OC::$server->getConfig()));
91
-
92
-	$application->add(\OC::$server->query(\OC\Core\Command\Broadcast\Test::class));
93
-
94
-	$application->add(new OC\Core\Command\Config\App\DeleteConfig(\OC::$server->getConfig()));
95
-	$application->add(new OC\Core\Command\Config\App\GetConfig(\OC::$server->getConfig()));
96
-	$application->add(new OC\Core\Command\Config\App\SetConfig(\OC::$server->getConfig()));
97
-	$application->add(new OC\Core\Command\Config\Import(\OC::$server->getConfig()));
98
-	$application->add(new OC\Core\Command\Config\ListConfigs(\OC::$server->getSystemConfig(), \OC::$server->getAppConfig()));
99
-	$application->add(new OC\Core\Command\Config\System\DeleteConfig(\OC::$server->getSystemConfig()));
100
-	$application->add(new OC\Core\Command\Config\System\GetConfig(\OC::$server->getSystemConfig()));
101
-	$application->add(new OC\Core\Command\Config\System\SetConfig(\OC::$server->getSystemConfig()));
102
-
103
-	$application->add(new OC\Core\Command\Db\ConvertType(\OC::$server->getConfig(), new \OC\DB\ConnectionFactory(\OC::$server->getSystemConfig())));
104
-	$application->add(new OC\Core\Command\Db\ConvertMysqlToMB4(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection(), \OC::$server->getURLGenerator(), \OC::$server->getLogger()));
105
-	$application->add(new OC\Core\Command\Db\ConvertFilecacheBigInt(\OC::$server->get(\OC\DB\Connection::class)));
106
-	$application->add(new OC\Core\Command\Db\AddMissingIndices(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getEventDispatcher()));
107
-	$application->add(new OC\Core\Command\Db\AddMissingColumns(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getEventDispatcher()));
108
-	$application->add(new OC\Core\Command\Db\AddMissingPrimaryKeys(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getEventDispatcher()));
109
-	$application->add(new OC\Core\Command\Db\Migrations\StatusCommand(\OC::$server->get(\OC\DB\Connection::class)));
110
-	$application->add(new OC\Core\Command\Db\Migrations\MigrateCommand(\OC::$server->get(\OC\DB\Connection::class)));
111
-	$application->add(new OC\Core\Command\Db\Migrations\GenerateCommand(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getAppManager()));
112
-	$application->add(new OC\Core\Command\Db\Migrations\GenerateFromSchemaFileCommand(\OC::$server->getConfig(), \OC::$server->getAppManager(), \OC::$server->get(\OC\DB\Connection::class)));
113
-	$application->add(new OC\Core\Command\Db\Migrations\ExecuteCommand(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getConfig()));
114
-
115
-	$application->add(new OC\Core\Command\Encryption\Disable(\OC::$server->getConfig()));
116
-	$application->add(new OC\Core\Command\Encryption\Enable(\OC::$server->getConfig(), \OC::$server->getEncryptionManager()));
117
-	$application->add(new OC\Core\Command\Encryption\ListModules(\OC::$server->getEncryptionManager(), \OC::$server->getConfig()));
118
-	$application->add(new OC\Core\Command\Encryption\SetDefaultModule(\OC::$server->getEncryptionManager(), \OC::$server->getConfig()));
119
-	$application->add(new OC\Core\Command\Encryption\Status(\OC::$server->getEncryptionManager()));
120
-	$application->add(new OC\Core\Command\Encryption\EncryptAll(\OC::$server->getEncryptionManager(), \OC::$server->getAppManager(), \OC::$server->getConfig(), new \Symfony\Component\Console\Helper\QuestionHelper()));
121
-	$application->add(new OC\Core\Command\Encryption\DecryptAll(
122
-		\OC::$server->getEncryptionManager(),
123
-		\OC::$server->getAppManager(),
124
-		\OC::$server->getConfig(),
125
-		new \OC\Encryption\DecryptAll(\OC::$server->getEncryptionManager(), \OC::$server->getUserManager(), new \OC\Files\View()),
126
-		new \Symfony\Component\Console\Helper\QuestionHelper())
127
-	);
128
-
129
-	$application->add(new OC\Core\Command\Log\Manage(\OC::$server->getConfig()));
130
-	$application->add(new OC\Core\Command\Log\File(\OC::$server->getConfig()));
131
-
132
-	$view = new \OC\Files\View();
133
-	$util = new \OC\Encryption\Util(
134
-		$view,
135
-		\OC::$server->getUserManager(),
136
-		\OC::$server->getGroupManager(),
137
-		\OC::$server->getConfig()
138
-	);
139
-	$application->add(new OC\Core\Command\Encryption\ChangeKeyStorageRoot(
140
-			$view,
141
-			\OC::$server->getUserManager(),
142
-			\OC::$server->getConfig(),
143
-			$util,
144
-			new \Symfony\Component\Console\Helper\QuestionHelper()
145
-		)
146
-	);
147
-	$application->add(new OC\Core\Command\Encryption\ShowKeyStorageRoot($util));
148
-	$application->add(new OC\Core\Command\Encryption\MigrateKeyStorage(
149
-			$view,
150
-			\OC::$server->getUserManager(),
151
-			\OC::$server->getConfig(),
152
-			$util,
153
-			\OC::$server->getCrypto()
154
-		)
155
-	);
156
-
157
-	$application->add(new OC\Core\Command\Maintenance\DataFingerprint(\OC::$server->getConfig(), new \OC\AppFramework\Utility\TimeFactory()));
158
-	$application->add(new OC\Core\Command\Maintenance\Mimetype\UpdateDB(\OC::$server->getMimeTypeDetector(), \OC::$server->getMimeTypeLoader()));
159
-	$application->add(new OC\Core\Command\Maintenance\Mimetype\UpdateJS(\OC::$server->getMimeTypeDetector()));
160
-	$application->add(new OC\Core\Command\Maintenance\Mode(\OC::$server->getConfig()));
161
-	$application->add(new OC\Core\Command\Maintenance\UpdateHtaccess());
162
-	$application->add(new OC\Core\Command\Maintenance\UpdateTheme(\OC::$server->getMimeTypeDetector(), \OC::$server->getMemCacheFactory()));
163
-
164
-	$application->add(new OC\Core\Command\Upgrade(\OC::$server->getConfig(), \OC::$server->getLogger(), \OC::$server->query(\OC\Installer::class)));
165
-	$application->add(new OC\Core\Command\Maintenance\Repair(
166
-		new \OC\Repair([], \OC::$server->getEventDispatcher(), \OC::$server->get(LoggerInterface::class)),
167
-		\OC::$server->getConfig(),
168
-		\OC::$server->getEventDispatcher(),
169
-		\OC::$server->getAppManager()
170
-	));
171
-
172
-	$application->add(\OC::$server->query(\OC\Core\Command\Preview\Repair::class));
173
-
174
-	$application->add(new OC\Core\Command\User\Add(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
175
-	$application->add(new OC\Core\Command\User\Delete(\OC::$server->getUserManager()));
176
-	$application->add(new OC\Core\Command\User\Disable(\OC::$server->getUserManager()));
177
-	$application->add(new OC\Core\Command\User\Enable(\OC::$server->getUserManager()));
178
-	$application->add(new OC\Core\Command\User\LastSeen(\OC::$server->getUserManager()));
179
-	$application->add(\OC::$server->get(\OC\Core\Command\User\Report::class));
180
-	$application->add(new OC\Core\Command\User\ResetPassword(\OC::$server->getUserManager()));
181
-	$application->add(new OC\Core\Command\User\Setting(\OC::$server->getUserManager(), \OC::$server->getConfig(), \OC::$server->getDatabaseConnection()));
182
-	$application->add(new OC\Core\Command\User\ListCommand(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
183
-	$application->add(new OC\Core\Command\User\Info(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
184
-	$application->add(new OC\Core\Command\User\AddAppPassword(\OC::$server->get(\OCP\IUserManager::class), \OC::$server->get(\OC\Authentication\Token\IProvider::class), \OC::$server->get(\OCP\Security\ISecureRandom::class), \OC::$server->get(\OCP\Security\ICrypto::class)));
185
-
186
-	$application->add(new OC\Core\Command\Group\Add(\OC::$server->getGroupManager()));
187
-	$application->add(new OC\Core\Command\Group\Delete(\OC::$server->getGroupManager()));
188
-	$application->add(new OC\Core\Command\Group\ListCommand(\OC::$server->getGroupManager()));
189
-	$application->add(new OC\Core\Command\Group\AddUser(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
190
-	$application->add(new OC\Core\Command\Group\RemoveUser(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
191
-	$application->add(new OC\Core\Command\Group\Info(\OC::$server->get(\OCP\IGroupManager::class)));
192
-
193
-	$application->add(new OC\Core\Command\Security\ListCertificates(\OC::$server->getCertificateManager(), \OC::$server->getL10N('core')));
194
-	$application->add(new OC\Core\Command\Security\ImportCertificate(\OC::$server->getCertificateManager()));
195
-	$application->add(new OC\Core\Command\Security\RemoveCertificate(\OC::$server->getCertificateManager()));
196
-	$application->add(new OC\Core\Command\Security\ResetBruteforceAttempts(\OC::$server->getBruteForceThrottler()));
74
+    $application->add(new OC\Core\Command\App\Disable(\OC::$server->getAppManager()));
75
+    $application->add(new OC\Core\Command\App\Enable(\OC::$server->getAppManager(), \OC::$server->getGroupManager()));
76
+    $application->add(new OC\Core\Command\App\Install());
77
+    $application->add(new OC\Core\Command\App\GetPath());
78
+    $application->add(new OC\Core\Command\App\ListApps(\OC::$server->getAppManager()));
79
+    $application->add(new OC\Core\Command\App\Remove(\OC::$server->getAppManager(), \OC::$server->query(\OC\Installer::class), \OC::$server->getLogger()));
80
+    $application->add(\OC::$server->query(\OC\Core\Command\App\Update::class));
81
+
82
+    $application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Cleanup::class));
83
+    $application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Enforce::class));
84
+    $application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Enable::class));
85
+    $application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Disable::class));
86
+    $application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\State::class));
87
+
88
+    $application->add(new OC\Core\Command\Background\Cron(\OC::$server->getConfig()));
89
+    $application->add(new OC\Core\Command\Background\WebCron(\OC::$server->getConfig()));
90
+    $application->add(new OC\Core\Command\Background\Ajax(\OC::$server->getConfig()));
91
+
92
+    $application->add(\OC::$server->query(\OC\Core\Command\Broadcast\Test::class));
93
+
94
+    $application->add(new OC\Core\Command\Config\App\DeleteConfig(\OC::$server->getConfig()));
95
+    $application->add(new OC\Core\Command\Config\App\GetConfig(\OC::$server->getConfig()));
96
+    $application->add(new OC\Core\Command\Config\App\SetConfig(\OC::$server->getConfig()));
97
+    $application->add(new OC\Core\Command\Config\Import(\OC::$server->getConfig()));
98
+    $application->add(new OC\Core\Command\Config\ListConfigs(\OC::$server->getSystemConfig(), \OC::$server->getAppConfig()));
99
+    $application->add(new OC\Core\Command\Config\System\DeleteConfig(\OC::$server->getSystemConfig()));
100
+    $application->add(new OC\Core\Command\Config\System\GetConfig(\OC::$server->getSystemConfig()));
101
+    $application->add(new OC\Core\Command\Config\System\SetConfig(\OC::$server->getSystemConfig()));
102
+
103
+    $application->add(new OC\Core\Command\Db\ConvertType(\OC::$server->getConfig(), new \OC\DB\ConnectionFactory(\OC::$server->getSystemConfig())));
104
+    $application->add(new OC\Core\Command\Db\ConvertMysqlToMB4(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection(), \OC::$server->getURLGenerator(), \OC::$server->getLogger()));
105
+    $application->add(new OC\Core\Command\Db\ConvertFilecacheBigInt(\OC::$server->get(\OC\DB\Connection::class)));
106
+    $application->add(new OC\Core\Command\Db\AddMissingIndices(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getEventDispatcher()));
107
+    $application->add(new OC\Core\Command\Db\AddMissingColumns(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getEventDispatcher()));
108
+    $application->add(new OC\Core\Command\Db\AddMissingPrimaryKeys(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getEventDispatcher()));
109
+    $application->add(new OC\Core\Command\Db\Migrations\StatusCommand(\OC::$server->get(\OC\DB\Connection::class)));
110
+    $application->add(new OC\Core\Command\Db\Migrations\MigrateCommand(\OC::$server->get(\OC\DB\Connection::class)));
111
+    $application->add(new OC\Core\Command\Db\Migrations\GenerateCommand(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getAppManager()));
112
+    $application->add(new OC\Core\Command\Db\Migrations\GenerateFromSchemaFileCommand(\OC::$server->getConfig(), \OC::$server->getAppManager(), \OC::$server->get(\OC\DB\Connection::class)));
113
+    $application->add(new OC\Core\Command\Db\Migrations\ExecuteCommand(\OC::$server->get(\OC\DB\Connection::class), \OC::$server->getConfig()));
114
+
115
+    $application->add(new OC\Core\Command\Encryption\Disable(\OC::$server->getConfig()));
116
+    $application->add(new OC\Core\Command\Encryption\Enable(\OC::$server->getConfig(), \OC::$server->getEncryptionManager()));
117
+    $application->add(new OC\Core\Command\Encryption\ListModules(\OC::$server->getEncryptionManager(), \OC::$server->getConfig()));
118
+    $application->add(new OC\Core\Command\Encryption\SetDefaultModule(\OC::$server->getEncryptionManager(), \OC::$server->getConfig()));
119
+    $application->add(new OC\Core\Command\Encryption\Status(\OC::$server->getEncryptionManager()));
120
+    $application->add(new OC\Core\Command\Encryption\EncryptAll(\OC::$server->getEncryptionManager(), \OC::$server->getAppManager(), \OC::$server->getConfig(), new \Symfony\Component\Console\Helper\QuestionHelper()));
121
+    $application->add(new OC\Core\Command\Encryption\DecryptAll(
122
+        \OC::$server->getEncryptionManager(),
123
+        \OC::$server->getAppManager(),
124
+        \OC::$server->getConfig(),
125
+        new \OC\Encryption\DecryptAll(\OC::$server->getEncryptionManager(), \OC::$server->getUserManager(), new \OC\Files\View()),
126
+        new \Symfony\Component\Console\Helper\QuestionHelper())
127
+    );
128
+
129
+    $application->add(new OC\Core\Command\Log\Manage(\OC::$server->getConfig()));
130
+    $application->add(new OC\Core\Command\Log\File(\OC::$server->getConfig()));
131
+
132
+    $view = new \OC\Files\View();
133
+    $util = new \OC\Encryption\Util(
134
+        $view,
135
+        \OC::$server->getUserManager(),
136
+        \OC::$server->getGroupManager(),
137
+        \OC::$server->getConfig()
138
+    );
139
+    $application->add(new OC\Core\Command\Encryption\ChangeKeyStorageRoot(
140
+            $view,
141
+            \OC::$server->getUserManager(),
142
+            \OC::$server->getConfig(),
143
+            $util,
144
+            new \Symfony\Component\Console\Helper\QuestionHelper()
145
+        )
146
+    );
147
+    $application->add(new OC\Core\Command\Encryption\ShowKeyStorageRoot($util));
148
+    $application->add(new OC\Core\Command\Encryption\MigrateKeyStorage(
149
+            $view,
150
+            \OC::$server->getUserManager(),
151
+            \OC::$server->getConfig(),
152
+            $util,
153
+            \OC::$server->getCrypto()
154
+        )
155
+    );
156
+
157
+    $application->add(new OC\Core\Command\Maintenance\DataFingerprint(\OC::$server->getConfig(), new \OC\AppFramework\Utility\TimeFactory()));
158
+    $application->add(new OC\Core\Command\Maintenance\Mimetype\UpdateDB(\OC::$server->getMimeTypeDetector(), \OC::$server->getMimeTypeLoader()));
159
+    $application->add(new OC\Core\Command\Maintenance\Mimetype\UpdateJS(\OC::$server->getMimeTypeDetector()));
160
+    $application->add(new OC\Core\Command\Maintenance\Mode(\OC::$server->getConfig()));
161
+    $application->add(new OC\Core\Command\Maintenance\UpdateHtaccess());
162
+    $application->add(new OC\Core\Command\Maintenance\UpdateTheme(\OC::$server->getMimeTypeDetector(), \OC::$server->getMemCacheFactory()));
163
+
164
+    $application->add(new OC\Core\Command\Upgrade(\OC::$server->getConfig(), \OC::$server->getLogger(), \OC::$server->query(\OC\Installer::class)));
165
+    $application->add(new OC\Core\Command\Maintenance\Repair(
166
+        new \OC\Repair([], \OC::$server->getEventDispatcher(), \OC::$server->get(LoggerInterface::class)),
167
+        \OC::$server->getConfig(),
168
+        \OC::$server->getEventDispatcher(),
169
+        \OC::$server->getAppManager()
170
+    ));
171
+
172
+    $application->add(\OC::$server->query(\OC\Core\Command\Preview\Repair::class));
173
+
174
+    $application->add(new OC\Core\Command\User\Add(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
175
+    $application->add(new OC\Core\Command\User\Delete(\OC::$server->getUserManager()));
176
+    $application->add(new OC\Core\Command\User\Disable(\OC::$server->getUserManager()));
177
+    $application->add(new OC\Core\Command\User\Enable(\OC::$server->getUserManager()));
178
+    $application->add(new OC\Core\Command\User\LastSeen(\OC::$server->getUserManager()));
179
+    $application->add(\OC::$server->get(\OC\Core\Command\User\Report::class));
180
+    $application->add(new OC\Core\Command\User\ResetPassword(\OC::$server->getUserManager()));
181
+    $application->add(new OC\Core\Command\User\Setting(\OC::$server->getUserManager(), \OC::$server->getConfig(), \OC::$server->getDatabaseConnection()));
182
+    $application->add(new OC\Core\Command\User\ListCommand(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
183
+    $application->add(new OC\Core\Command\User\Info(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
184
+    $application->add(new OC\Core\Command\User\AddAppPassword(\OC::$server->get(\OCP\IUserManager::class), \OC::$server->get(\OC\Authentication\Token\IProvider::class), \OC::$server->get(\OCP\Security\ISecureRandom::class), \OC::$server->get(\OCP\Security\ICrypto::class)));
185
+
186
+    $application->add(new OC\Core\Command\Group\Add(\OC::$server->getGroupManager()));
187
+    $application->add(new OC\Core\Command\Group\Delete(\OC::$server->getGroupManager()));
188
+    $application->add(new OC\Core\Command\Group\ListCommand(\OC::$server->getGroupManager()));
189
+    $application->add(new OC\Core\Command\Group\AddUser(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
190
+    $application->add(new OC\Core\Command\Group\RemoveUser(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
191
+    $application->add(new OC\Core\Command\Group\Info(\OC::$server->get(\OCP\IGroupManager::class)));
192
+
193
+    $application->add(new OC\Core\Command\Security\ListCertificates(\OC::$server->getCertificateManager(), \OC::$server->getL10N('core')));
194
+    $application->add(new OC\Core\Command\Security\ImportCertificate(\OC::$server->getCertificateManager()));
195
+    $application->add(new OC\Core\Command\Security\RemoveCertificate(\OC::$server->getCertificateManager()));
196
+    $application->add(new OC\Core\Command\Security\ResetBruteforceAttempts(\OC::$server->getBruteForceThrottler()));
197 197
 } else {
198
-	$application->add(\OC::$server->get(\OC\Core\Command\Maintenance\Install::class));
198
+    $application->add(\OC::$server->get(\OC\Core\Command\Maintenance\Install::class));
199 199
 }
Please login to merge, or discard this patch.
lib/private/Repair.php 1 patch
Indentation   +187 added lines, -187 removed lines patch added patch discarded remove patch
@@ -82,209 +82,209 @@
 block discarded – undo
82 82
 
83 83
 class Repair implements IOutput {
84 84
 
85
-	/** @var IRepairStep[] */
86
-	private $repairSteps;
85
+    /** @var IRepairStep[] */
86
+    private $repairSteps;
87 87
 
88
-	/** @var EventDispatcherInterface */
89
-	private $dispatcher;
88
+    /** @var EventDispatcherInterface */
89
+    private $dispatcher;
90 90
 
91
-	/** @var string */
92
-	private $currentStep;
91
+    /** @var string */
92
+    private $currentStep;
93 93
 
94
-	private $logger;
94
+    private $logger;
95 95
 
96
-	/**
97
-	 * Creates a new repair step runner
98
-	 *
99
-	 * @param IRepairStep[] $repairSteps array of RepairStep instances
100
-	 * @param EventDispatcherInterface $dispatcher
101
-	 */
102
-	public function __construct(array $repairSteps, EventDispatcherInterface $dispatcher, LoggerInterface $logger) {
103
-		$this->repairSteps = $repairSteps;
104
-		$this->dispatcher = $dispatcher;
105
-		$this->logger = $logger;
106
-	}
96
+    /**
97
+     * Creates a new repair step runner
98
+     *
99
+     * @param IRepairStep[] $repairSteps array of RepairStep instances
100
+     * @param EventDispatcherInterface $dispatcher
101
+     */
102
+    public function __construct(array $repairSteps, EventDispatcherInterface $dispatcher, LoggerInterface $logger) {
103
+        $this->repairSteps = $repairSteps;
104
+        $this->dispatcher = $dispatcher;
105
+        $this->logger = $logger;
106
+    }
107 107
 
108
-	/**
109
-	 * Run a series of repair steps for common problems
110
-	 */
111
-	public function run() {
112
-		if (count($this->repairSteps) === 0) {
113
-			$this->emit('\OC\Repair', 'info', ['No repair steps available']);
108
+    /**
109
+     * Run a series of repair steps for common problems
110
+     */
111
+    public function run() {
112
+        if (count($this->repairSteps) === 0) {
113
+            $this->emit('\OC\Repair', 'info', ['No repair steps available']);
114 114
 
115
-			return;
116
-		}
117
-		// run each repair step
118
-		foreach ($this->repairSteps as $step) {
119
-			$this->currentStep = $step->getName();
120
-			$this->emit('\OC\Repair', 'step', [$this->currentStep]);
121
-			try {
122
-				$step->run($this);
123
-			} catch (\Exception $e) {
124
-				$this->logger->error("Exception while executing repair step " . $step->getName(), ['exception' => $e]);
125
-				$this->emit('\OC\Repair', 'error', [$e->getMessage()]);
126
-			}
127
-		}
128
-	}
115
+            return;
116
+        }
117
+        // run each repair step
118
+        foreach ($this->repairSteps as $step) {
119
+            $this->currentStep = $step->getName();
120
+            $this->emit('\OC\Repair', 'step', [$this->currentStep]);
121
+            try {
122
+                $step->run($this);
123
+            } catch (\Exception $e) {
124
+                $this->logger->error("Exception while executing repair step " . $step->getName(), ['exception' => $e]);
125
+                $this->emit('\OC\Repair', 'error', [$e->getMessage()]);
126
+            }
127
+        }
128
+    }
129 129
 
130
-	/**
131
-	 * Add repair step
132
-	 *
133
-	 * @param IRepairStep|string $repairStep repair step
134
-	 * @throws \Exception
135
-	 */
136
-	public function addStep($repairStep) {
137
-		if (is_string($repairStep)) {
138
-			try {
139
-				$s = \OC::$server->query($repairStep);
140
-			} catch (QueryException $e) {
141
-				if (class_exists($repairStep)) {
142
-					$s = new $repairStep();
143
-				} else {
144
-					throw new \Exception("Repair step '$repairStep' is unknown");
145
-				}
146
-			}
130
+    /**
131
+     * Add repair step
132
+     *
133
+     * @param IRepairStep|string $repairStep repair step
134
+     * @throws \Exception
135
+     */
136
+    public function addStep($repairStep) {
137
+        if (is_string($repairStep)) {
138
+            try {
139
+                $s = \OC::$server->query($repairStep);
140
+            } catch (QueryException $e) {
141
+                if (class_exists($repairStep)) {
142
+                    $s = new $repairStep();
143
+                } else {
144
+                    throw new \Exception("Repair step '$repairStep' is unknown");
145
+                }
146
+            }
147 147
 
148
-			if ($s instanceof IRepairStep) {
149
-				$this->repairSteps[] = $s;
150
-			} else {
151
-				throw new \Exception("Repair step '$repairStep' is not of type \\OCP\\Migration\\IRepairStep");
152
-			}
153
-		} else {
154
-			$this->repairSteps[] = $repairStep;
155
-		}
156
-	}
148
+            if ($s instanceof IRepairStep) {
149
+                $this->repairSteps[] = $s;
150
+            } else {
151
+                throw new \Exception("Repair step '$repairStep' is not of type \\OCP\\Migration\\IRepairStep");
152
+            }
153
+        } else {
154
+            $this->repairSteps[] = $repairStep;
155
+        }
156
+    }
157 157
 
158
-	/**
159
-	 * Returns the default repair steps to be run on the
160
-	 * command line or after an upgrade.
161
-	 *
162
-	 * @return IRepairStep[]
163
-	 */
164
-	public static function getRepairSteps() {
165
-		return [
166
-			new Collation(\OC::$server->getConfig(), \OC::$server->getLogger(), \OC::$server->getDatabaseConnection(), false),
167
-			new RepairMimeTypes(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()),
168
-			new CleanTags(\OC::$server->getDatabaseConnection(), \OC::$server->getUserManager()),
169
-			new RepairInvalidShares(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()),
170
-			new MoveUpdaterStepFile(\OC::$server->getConfig()),
171
-			new MoveAvatars(
172
-				\OC::$server->getJobList(),
173
-				\OC::$server->getConfig()
174
-			),
175
-			new CleanPreviews(
176
-				\OC::$server->getJobList(),
177
-				\OC::$server->getUserManager(),
178
-				\OC::$server->getConfig()
179
-			),
180
-			new FixMountStorages(\OC::$server->getDatabaseConnection()),
181
-			new UpdateLanguageCodes(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig()),
182
-			new InstallCoreBundle(
183
-				\OC::$server->query(BundleFetcher::class),
184
-				\OC::$server->getConfig(),
185
-				\OC::$server->query(Installer::class)
186
-			),
187
-			new AddLogRotateJob(\OC::$server->getJobList()),
188
-			new ClearFrontendCaches(\OC::$server->getMemCacheFactory(), \OC::$server->query(SCSSCacher::class), \OC::$server->query(JSCombiner::class)),
189
-			new ClearGeneratedAvatarCache(\OC::$server->getConfig(), \OC::$server->query(AvatarManager::class)),
190
-			new AddPreviewBackgroundCleanupJob(\OC::$server->getJobList()),
191
-			new AddCleanupUpdaterBackupsJob(\OC::$server->getJobList()),
192
-			new CleanupCardDAVPhotoCache(\OC::$server->getConfig(), \OC::$server->getAppDataDir('dav-photocache'), \OC::$server->getLogger()),
193
-			new AddClenupLoginFlowV2BackgroundJob(\OC::$server->getJobList()),
194
-			new RemoveLinkShares(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig(), \OC::$server->getGroupManager(), \OC::$server->getNotificationManager(), \OC::$server->query(ITimeFactory::class)),
195
-			new ClearCollectionsAccessCache(\OC::$server->getConfig(), \OC::$server->query(IManager::class)),
196
-			\OC::$server->query(ResetGeneratedAvatarFlag::class),
197
-			\OC::$server->query(EncryptionLegacyCipher::class),
198
-			\OC::$server->query(EncryptionMigration::class),
199
-			\OC::$server->get(ShippedDashboardEnable::class),
200
-			\OC::$server->get(AddBruteForceCleanupJob::class),
201
-			\OC::$server->get(AddCheckForUserCertificatesJob::class),
202
-			\OC::$server->get(RepairDavShares::class)
203
-		];
204
-	}
158
+    /**
159
+     * Returns the default repair steps to be run on the
160
+     * command line or after an upgrade.
161
+     *
162
+     * @return IRepairStep[]
163
+     */
164
+    public static function getRepairSteps() {
165
+        return [
166
+            new Collation(\OC::$server->getConfig(), \OC::$server->getLogger(), \OC::$server->getDatabaseConnection(), false),
167
+            new RepairMimeTypes(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()),
168
+            new CleanTags(\OC::$server->getDatabaseConnection(), \OC::$server->getUserManager()),
169
+            new RepairInvalidShares(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()),
170
+            new MoveUpdaterStepFile(\OC::$server->getConfig()),
171
+            new MoveAvatars(
172
+                \OC::$server->getJobList(),
173
+                \OC::$server->getConfig()
174
+            ),
175
+            new CleanPreviews(
176
+                \OC::$server->getJobList(),
177
+                \OC::$server->getUserManager(),
178
+                \OC::$server->getConfig()
179
+            ),
180
+            new FixMountStorages(\OC::$server->getDatabaseConnection()),
181
+            new UpdateLanguageCodes(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig()),
182
+            new InstallCoreBundle(
183
+                \OC::$server->query(BundleFetcher::class),
184
+                \OC::$server->getConfig(),
185
+                \OC::$server->query(Installer::class)
186
+            ),
187
+            new AddLogRotateJob(\OC::$server->getJobList()),
188
+            new ClearFrontendCaches(\OC::$server->getMemCacheFactory(), \OC::$server->query(SCSSCacher::class), \OC::$server->query(JSCombiner::class)),
189
+            new ClearGeneratedAvatarCache(\OC::$server->getConfig(), \OC::$server->query(AvatarManager::class)),
190
+            new AddPreviewBackgroundCleanupJob(\OC::$server->getJobList()),
191
+            new AddCleanupUpdaterBackupsJob(\OC::$server->getJobList()),
192
+            new CleanupCardDAVPhotoCache(\OC::$server->getConfig(), \OC::$server->getAppDataDir('dav-photocache'), \OC::$server->getLogger()),
193
+            new AddClenupLoginFlowV2BackgroundJob(\OC::$server->getJobList()),
194
+            new RemoveLinkShares(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig(), \OC::$server->getGroupManager(), \OC::$server->getNotificationManager(), \OC::$server->query(ITimeFactory::class)),
195
+            new ClearCollectionsAccessCache(\OC::$server->getConfig(), \OC::$server->query(IManager::class)),
196
+            \OC::$server->query(ResetGeneratedAvatarFlag::class),
197
+            \OC::$server->query(EncryptionLegacyCipher::class),
198
+            \OC::$server->query(EncryptionMigration::class),
199
+            \OC::$server->get(ShippedDashboardEnable::class),
200
+            \OC::$server->get(AddBruteForceCleanupJob::class),
201
+            \OC::$server->get(AddCheckForUserCertificatesJob::class),
202
+            \OC::$server->get(RepairDavShares::class)
203
+        ];
204
+    }
205 205
 
206
-	/**
207
-	 * Returns expensive repair steps to be run on the
208
-	 * command line with a special option.
209
-	 *
210
-	 * @return IRepairStep[]
211
-	 */
212
-	public static function getExpensiveRepairSteps() {
213
-		return [
214
-			new OldGroupMembershipShares(\OC::$server->getDatabaseConnection(), \OC::$server->getGroupManager()),
215
-			\OC::$server->get(ValidatePhoneNumber::class),
216
-		];
217
-	}
206
+    /**
207
+     * Returns expensive repair steps to be run on the
208
+     * command line with a special option.
209
+     *
210
+     * @return IRepairStep[]
211
+     */
212
+    public static function getExpensiveRepairSteps() {
213
+        return [
214
+            new OldGroupMembershipShares(\OC::$server->getDatabaseConnection(), \OC::$server->getGroupManager()),
215
+            \OC::$server->get(ValidatePhoneNumber::class),
216
+        ];
217
+    }
218 218
 
219
-	/**
220
-	 * Returns the repair steps to be run before an
221
-	 * upgrade.
222
-	 *
223
-	 * @return IRepairStep[]
224
-	 */
225
-	public static function getBeforeUpgradeRepairSteps() {
226
-		/** @var Connection $connection */
227
-		$connection = \OC::$server->get(Connection::class);
228
-		/** @var ConnectionAdapter $connectionAdapter */
229
-		$connectionAdapter = \OC::$server->get(ConnectionAdapter::class);
230
-		$config = \OC::$server->getConfig();
231
-		$steps = [
232
-			new Collation(\OC::$server->getConfig(), \OC::$server->getLogger(), $connectionAdapter, true),
233
-			new SqliteAutoincrement($connection),
234
-			new SaveAccountsTableData($connectionAdapter, $config),
235
-			new DropAccountTermsTable($connectionAdapter),
236
-		];
219
+    /**
220
+     * Returns the repair steps to be run before an
221
+     * upgrade.
222
+     *
223
+     * @return IRepairStep[]
224
+     */
225
+    public static function getBeforeUpgradeRepairSteps() {
226
+        /** @var Connection $connection */
227
+        $connection = \OC::$server->get(Connection::class);
228
+        /** @var ConnectionAdapter $connectionAdapter */
229
+        $connectionAdapter = \OC::$server->get(ConnectionAdapter::class);
230
+        $config = \OC::$server->getConfig();
231
+        $steps = [
232
+            new Collation(\OC::$server->getConfig(), \OC::$server->getLogger(), $connectionAdapter, true),
233
+            new SqliteAutoincrement($connection),
234
+            new SaveAccountsTableData($connectionAdapter, $config),
235
+            new DropAccountTermsTable($connectionAdapter),
236
+        ];
237 237
 
238
-		return $steps;
239
-	}
238
+        return $steps;
239
+    }
240 240
 
241
-	/**
242
-	 * @param string $scope
243
-	 * @param string $method
244
-	 * @param array $arguments
245
-	 */
246
-	public function emit($scope, $method, array $arguments = []) {
247
-		if (!is_null($this->dispatcher)) {
248
-			$this->dispatcher->dispatch("$scope::$method",
249
-				new GenericEvent("$scope::$method", $arguments));
250
-		}
251
-	}
241
+    /**
242
+     * @param string $scope
243
+     * @param string $method
244
+     * @param array $arguments
245
+     */
246
+    public function emit($scope, $method, array $arguments = []) {
247
+        if (!is_null($this->dispatcher)) {
248
+            $this->dispatcher->dispatch("$scope::$method",
249
+                new GenericEvent("$scope::$method", $arguments));
250
+        }
251
+    }
252 252
 
253
-	public function info($string) {
254
-		// for now just emit as we did in the past
255
-		$this->emit('\OC\Repair', 'info', [$string]);
256
-	}
253
+    public function info($string) {
254
+        // for now just emit as we did in the past
255
+        $this->emit('\OC\Repair', 'info', [$string]);
256
+    }
257 257
 
258
-	/**
259
-	 * @param string $message
260
-	 */
261
-	public function warning($message) {
262
-		// for now just emit as we did in the past
263
-		$this->emit('\OC\Repair', 'warning', [$message]);
264
-	}
258
+    /**
259
+     * @param string $message
260
+     */
261
+    public function warning($message) {
262
+        // for now just emit as we did in the past
263
+        $this->emit('\OC\Repair', 'warning', [$message]);
264
+    }
265 265
 
266
-	/**
267
-	 * @param int $max
268
-	 */
269
-	public function startProgress($max = 0) {
270
-		// for now just emit as we did in the past
271
-		$this->emit('\OC\Repair', 'startProgress', [$max, $this->currentStep]);
272
-	}
266
+    /**
267
+     * @param int $max
268
+     */
269
+    public function startProgress($max = 0) {
270
+        // for now just emit as we did in the past
271
+        $this->emit('\OC\Repair', 'startProgress', [$max, $this->currentStep]);
272
+    }
273 273
 
274
-	/**
275
-	 * @param int $step
276
-	 * @param string $description
277
-	 */
278
-	public function advance($step = 1, $description = '') {
279
-		// for now just emit as we did in the past
280
-		$this->emit('\OC\Repair', 'advance', [$step, $description]);
281
-	}
274
+    /**
275
+     * @param int $step
276
+     * @param string $description
277
+     */
278
+    public function advance($step = 1, $description = '') {
279
+        // for now just emit as we did in the past
280
+        $this->emit('\OC\Repair', 'advance', [$step, $description]);
281
+    }
282 282
 
283
-	/**
284
-	 * @param int $max
285
-	 */
286
-	public function finishProgress() {
287
-		// for now just emit as we did in the past
288
-		$this->emit('\OC\Repair', 'finishProgress', []);
289
-	}
283
+    /**
284
+     * @param int $max
285
+     */
286
+    public function finishProgress() {
287
+        // for now just emit as we did in the past
288
+        $this->emit('\OC\Repair', 'finishProgress', []);
289
+    }
290 290
 }
Please login to merge, or discard this patch.
lib/private/legacy/OC_App.php 1 patch
Indentation   +1121 added lines, -1121 removed lines patch added patch discarded remove patch
@@ -69,1125 +69,1125 @@
 block discarded – undo
69 69
  * upgrading and removing apps.
70 70
  */
71 71
 class OC_App {
72
-	private static $adminForms = [];
73
-	private static $personalForms = [];
74
-	private static $appTypes = [];
75
-	private static $loadedApps = [];
76
-	private static $altLogin = [];
77
-	private static $alreadyRegistered = [];
78
-	public const supportedApp = 300;
79
-	public const officialApp = 200;
80
-
81
-	/**
82
-	 * clean the appId
83
-	 *
84
-	 * @psalm-taint-escape file
85
-	 * @psalm-taint-escape include
86
-	 *
87
-	 * @param string $app AppId that needs to be cleaned
88
-	 * @return string
89
-	 */
90
-	public static function cleanAppId(string $app): string {
91
-		return str_replace(['\0', '/', '\\', '..'], '', $app);
92
-	}
93
-
94
-	/**
95
-	 * Check if an app is loaded
96
-	 *
97
-	 * @param string $app
98
-	 * @return bool
99
-	 */
100
-	public static function isAppLoaded(string $app): bool {
101
-		return isset(self::$loadedApps[$app]);
102
-	}
103
-
104
-	/**
105
-	 * loads all apps
106
-	 *
107
-	 * @param string[] $types
108
-	 * @return bool
109
-	 *
110
-	 * This function walks through the ownCloud directory and loads all apps
111
-	 * it can find. A directory contains an app if the file /appinfo/info.xml
112
-	 * exists.
113
-	 *
114
-	 * if $types is set to non-empty array, only apps of those types will be loaded
115
-	 */
116
-	public static function loadApps(array $types = []): bool {
117
-		if ((bool) \OC::$server->getSystemConfig()->getValue('maintenance', false)) {
118
-			return false;
119
-		}
120
-		// Load the enabled apps here
121
-		$apps = self::getEnabledApps();
122
-
123
-		// Add each apps' folder as allowed class path
124
-		foreach ($apps as $app) {
125
-			// If the app is already loaded then autoloading it makes no sense
126
-			if (!isset(self::$loadedApps[$app])) {
127
-				$path = self::getAppPath($app);
128
-				if ($path !== false) {
129
-					self::registerAutoloading($app, $path);
130
-				}
131
-			}
132
-		}
133
-
134
-		// prevent app.php from printing output
135
-		ob_start();
136
-		foreach ($apps as $app) {
137
-			if (!isset(self::$loadedApps[$app]) && ($types === [] || self::isType($app, $types))) {
138
-				self::loadApp($app);
139
-			}
140
-		}
141
-		ob_end_clean();
142
-
143
-		return true;
144
-	}
145
-
146
-	/**
147
-	 * load a single app
148
-	 *
149
-	 * @param string $app
150
-	 * @throws Exception
151
-	 */
152
-	public static function loadApp(string $app) {
153
-		self::$loadedApps[$app] = true;
154
-		$appPath = self::getAppPath($app);
155
-		if ($appPath === false) {
156
-			return;
157
-		}
158
-
159
-		// in case someone calls loadApp() directly
160
-		self::registerAutoloading($app, $appPath);
161
-
162
-		/** @var Coordinator $coordinator */
163
-		$coordinator = \OC::$server->query(Coordinator::class);
164
-		$isBootable = $coordinator->isBootable($app);
165
-
166
-		$hasAppPhpFile = is_file($appPath . '/appinfo/app.php');
167
-
168
-		if ($isBootable && $hasAppPhpFile) {
169
-			\OC::$server->getLogger()->error('/appinfo/app.php is not loaded when \OCP\AppFramework\Bootstrap\IBootstrap on the application class is used. Migrate everything from app.php to the Application class.', [
170
-				'app' => $app,
171
-			]);
172
-		} elseif ($hasAppPhpFile) {
173
-			\OC::$server->getLogger()->debug('/appinfo/app.php is deprecated, use \OCP\AppFramework\Bootstrap\IBootstrap on the application class instead.', [
174
-				'app' => $app,
175
-			]);
176
-			\OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
177
-			try {
178
-				self::requireAppFile($app);
179
-			} catch (Throwable $ex) {
180
-				if ($ex instanceof ServerNotAvailableException) {
181
-					throw $ex;
182
-				}
183
-				if (!\OC::$server->getAppManager()->isShipped($app) && !self::isType($app, ['authentication'])) {
184
-					\OC::$server->getLogger()->logException($ex, [
185
-						'message' => "App $app threw an error during app.php load and will be disabled: " . $ex->getMessage(),
186
-					]);
187
-
188
-					// Only disable apps which are not shipped and that are not authentication apps
189
-					\OC::$server->getAppManager()->disableApp($app, true);
190
-				} else {
191
-					\OC::$server->getLogger()->logException($ex, [
192
-						'message' => "App $app threw an error during app.php load: " . $ex->getMessage(),
193
-					]);
194
-				}
195
-			}
196
-			\OC::$server->getEventLogger()->end('load_app_' . $app);
197
-		}
198
-		$coordinator->bootApp($app);
199
-
200
-		$info = self::getAppInfo($app);
201
-		if (!empty($info['activity']['filters'])) {
202
-			foreach ($info['activity']['filters'] as $filter) {
203
-				\OC::$server->getActivityManager()->registerFilter($filter);
204
-			}
205
-		}
206
-		if (!empty($info['activity']['settings'])) {
207
-			foreach ($info['activity']['settings'] as $setting) {
208
-				\OC::$server->getActivityManager()->registerSetting($setting);
209
-			}
210
-		}
211
-		if (!empty($info['activity']['providers'])) {
212
-			foreach ($info['activity']['providers'] as $provider) {
213
-				\OC::$server->getActivityManager()->registerProvider($provider);
214
-			}
215
-		}
216
-
217
-		if (!empty($info['settings']['admin'])) {
218
-			foreach ($info['settings']['admin'] as $setting) {
219
-				\OC::$server->getSettingsManager()->registerSetting('admin', $setting);
220
-			}
221
-		}
222
-		if (!empty($info['settings']['admin-section'])) {
223
-			foreach ($info['settings']['admin-section'] as $section) {
224
-				\OC::$server->getSettingsManager()->registerSection('admin', $section);
225
-			}
226
-		}
227
-		if (!empty($info['settings']['personal'])) {
228
-			foreach ($info['settings']['personal'] as $setting) {
229
-				\OC::$server->getSettingsManager()->registerSetting('personal', $setting);
230
-			}
231
-		}
232
-		if (!empty($info['settings']['personal-section'])) {
233
-			foreach ($info['settings']['personal-section'] as $section) {
234
-				\OC::$server->getSettingsManager()->registerSection('personal', $section);
235
-			}
236
-		}
237
-
238
-		if (!empty($info['collaboration']['plugins'])) {
239
-			// deal with one or many plugin entries
240
-			$plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
241
-				[$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
242
-			foreach ($plugins as $plugin) {
243
-				if ($plugin['@attributes']['type'] === 'collaborator-search') {
244
-					$pluginInfo = [
245
-						'shareType' => $plugin['@attributes']['share-type'],
246
-						'class' => $plugin['@value'],
247
-					];
248
-					\OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo);
249
-				} elseif ($plugin['@attributes']['type'] === 'autocomplete-sort') {
250
-					\OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']);
251
-				}
252
-			}
253
-		}
254
-	}
255
-
256
-	/**
257
-	 * @internal
258
-	 * @param string $app
259
-	 * @param string $path
260
-	 * @param bool $force
261
-	 */
262
-	public static function registerAutoloading(string $app, string $path, bool $force = false) {
263
-		$key = $app . '-' . $path;
264
-		if (!$force && isset(self::$alreadyRegistered[$key])) {
265
-			return;
266
-		}
267
-
268
-		self::$alreadyRegistered[$key] = true;
269
-
270
-		// Register on PSR-4 composer autoloader
271
-		$appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
272
-		\OC::$server->registerNamespace($app, $appNamespace);
273
-
274
-		if (file_exists($path . '/composer/autoload.php')) {
275
-			require_once $path . '/composer/autoload.php';
276
-		} else {
277
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
278
-			// Register on legacy autoloader
279
-			\OC::$loader->addValidRoot($path);
280
-		}
281
-
282
-		// Register Test namespace only when testing
283
-		if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
284
-			\OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
285
-		}
286
-	}
287
-
288
-	/**
289
-	 * Load app.php from the given app
290
-	 *
291
-	 * @param string $app app name
292
-	 * @throws Error
293
-	 */
294
-	private static function requireAppFile(string $app) {
295
-		// encapsulated here to avoid variable scope conflicts
296
-		require_once $app . '/appinfo/app.php';
297
-	}
298
-
299
-	/**
300
-	 * check if an app is of a specific type
301
-	 *
302
-	 * @param string $app
303
-	 * @param array $types
304
-	 * @return bool
305
-	 */
306
-	public static function isType(string $app, array $types): bool {
307
-		$appTypes = self::getAppTypes($app);
308
-		foreach ($types as $type) {
309
-			if (array_search($type, $appTypes) !== false) {
310
-				return true;
311
-			}
312
-		}
313
-		return false;
314
-	}
315
-
316
-	/**
317
-	 * get the types of an app
318
-	 *
319
-	 * @param string $app
320
-	 * @return array
321
-	 */
322
-	private static function getAppTypes(string $app): array {
323
-		//load the cache
324
-		if (count(self::$appTypes) == 0) {
325
-			self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
326
-		}
327
-
328
-		if (isset(self::$appTypes[$app])) {
329
-			return explode(',', self::$appTypes[$app]);
330
-		}
331
-
332
-		return [];
333
-	}
334
-
335
-	/**
336
-	 * read app types from info.xml and cache them in the database
337
-	 */
338
-	public static function setAppTypes(string $app) {
339
-		$appManager = \OC::$server->getAppManager();
340
-		$appData = $appManager->getAppInfo($app);
341
-		if (!is_array($appData)) {
342
-			return;
343
-		}
344
-
345
-		if (isset($appData['types'])) {
346
-			$appTypes = implode(',', $appData['types']);
347
-		} else {
348
-			$appTypes = '';
349
-			$appData['types'] = [];
350
-		}
351
-
352
-		$config = \OC::$server->getConfig();
353
-		$config->setAppValue($app, 'types', $appTypes);
354
-
355
-		if ($appManager->hasProtectedAppType($appData['types'])) {
356
-			$enabled = $config->getAppValue($app, 'enabled', 'yes');
357
-			if ($enabled !== 'yes' && $enabled !== 'no') {
358
-				$config->setAppValue($app, 'enabled', 'yes');
359
-			}
360
-		}
361
-	}
362
-
363
-	/**
364
-	 * Returns apps enabled for the current user.
365
-	 *
366
-	 * @param bool $forceRefresh whether to refresh the cache
367
-	 * @param bool $all whether to return apps for all users, not only the
368
-	 * currently logged in one
369
-	 * @return string[]
370
-	 */
371
-	public static function getEnabledApps(bool $forceRefresh = false, bool $all = false): array {
372
-		if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
373
-			return [];
374
-		}
375
-		// in incognito mode or when logged out, $user will be false,
376
-		// which is also the case during an upgrade
377
-		$appManager = \OC::$server->getAppManager();
378
-		if ($all) {
379
-			$user = null;
380
-		} else {
381
-			$user = \OC::$server->getUserSession()->getUser();
382
-		}
383
-
384
-		if (is_null($user)) {
385
-			$apps = $appManager->getInstalledApps();
386
-		} else {
387
-			$apps = $appManager->getEnabledAppsForUser($user);
388
-		}
389
-		$apps = array_filter($apps, function ($app) {
390
-			return $app !== 'files';//we add this manually
391
-		});
392
-		sort($apps);
393
-		array_unshift($apps, 'files');
394
-		return $apps;
395
-	}
396
-
397
-	/**
398
-	 * checks whether or not an app is enabled
399
-	 *
400
-	 * @param string $app app
401
-	 * @return bool
402
-	 * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId)
403
-	 *
404
-	 * This function checks whether or not an app is enabled.
405
-	 */
406
-	public static function isEnabled(string $app): bool {
407
-		return \OC::$server->getAppManager()->isEnabledForUser($app);
408
-	}
409
-
410
-	/**
411
-	 * enables an app
412
-	 *
413
-	 * @param string $appId
414
-	 * @param array $groups (optional) when set, only these groups will have access to the app
415
-	 * @throws \Exception
416
-	 * @return void
417
-	 *
418
-	 * This function set an app as enabled in appconfig.
419
-	 */
420
-	public function enable(string $appId,
421
-						   array $groups = []) {
422
-
423
-		// Check if app is already downloaded
424
-		/** @var Installer $installer */
425
-		$installer = \OC::$server->query(Installer::class);
426
-		$isDownloaded = $installer->isDownloaded($appId);
427
-
428
-		if (!$isDownloaded) {
429
-			$installer->downloadApp($appId);
430
-		}
431
-
432
-		$installer->installApp($appId);
433
-
434
-		$appManager = \OC::$server->getAppManager();
435
-		if ($groups !== []) {
436
-			$groupManager = \OC::$server->getGroupManager();
437
-			$groupsList = [];
438
-			foreach ($groups as $group) {
439
-				$groupItem = $groupManager->get($group);
440
-				if ($groupItem instanceof \OCP\IGroup) {
441
-					$groupsList[] = $groupManager->get($group);
442
-				}
443
-			}
444
-			$appManager->enableAppForGroups($appId, $groupsList);
445
-		} else {
446
-			$appManager->enableApp($appId);
447
-		}
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.', ILogger::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(string $appId) {
478
-		$sanitizedAppId = self::cleanAppId($appId);
479
-		if ($sanitizedAppId !== $appId) {
480
-			return false;
481
-		}
482
-		static $app_dir = [];
483
-
484
-		if (isset($app_dir[$appId])) {
485
-			return $app_dir[$appId];
486
-		}
487
-
488
-		$possibleApps = [];
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 = [];
503
-			foreach ($possibleApps as $possibleApp) {
504
-				$version = self::getAppVersionByPath($possibleApp['path'] . '/' . $appId);
505
-				if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
506
-					$versionToLoad = [
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
-	 * @psalm-taint-specialize
523
-	 *
524
-	 * @param string $appId
525
-	 * @return string|false
526
-	 * @deprecated 11.0.0 use \OC::$server->getAppManager()->getAppPath()
527
-	 */
528
-	public static function getAppPath(string $appId) {
529
-		if ($appId === null || trim($appId) === '') {
530
-			return false;
531
-		}
532
-
533
-		if (($dir = self::findAppInDirectories($appId)) != false) {
534
-			return $dir['path'] . '/' . $appId;
535
-		}
536
-		return false;
537
-	}
538
-
539
-	/**
540
-	 * Get the path for the given app on the access
541
-	 * If the app is defined in multiple directories, the first one is taken. (false if not found)
542
-	 *
543
-	 * @param string $appId
544
-	 * @return string|false
545
-	 * @deprecated 18.0.0 use \OC::$server->getAppManager()->getAppWebPath()
546
-	 */
547
-	public static function getAppWebPath(string $appId) {
548
-		if (($dir = self::findAppInDirectories($appId)) != false) {
549
-			return OC::$WEBROOT . $dir['url'] . '/' . $appId;
550
-		}
551
-		return false;
552
-	}
553
-
554
-	/**
555
-	 * get the last version of the app from appinfo/info.xml
556
-	 *
557
-	 * @param string $appId
558
-	 * @param bool $useCache
559
-	 * @return string
560
-	 * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion()
561
-	 */
562
-	public static function getAppVersion(string $appId, bool $useCache = true): string {
563
-		return \OC::$server->getAppManager()->getAppVersion($appId, $useCache);
564
-	}
565
-
566
-	/**
567
-	 * get app's version based on it's path
568
-	 *
569
-	 * @param string $path
570
-	 * @return string
571
-	 */
572
-	public static function getAppVersionByPath(string $path): string {
573
-		$infoFile = $path . '/appinfo/info.xml';
574
-		$appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
575
-		return isset($appData['version']) ? $appData['version'] : '';
576
-	}
577
-
578
-
579
-	/**
580
-	 * Read all app metadata from the info.xml file
581
-	 *
582
-	 * @param string $appId id of the app or the path of the info.xml file
583
-	 * @param bool $path
584
-	 * @param string $lang
585
-	 * @return array|null
586
-	 * @note all data is read from info.xml, not just pre-defined fields
587
-	 * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppInfo()
588
-	 */
589
-	public static function getAppInfo(string $appId, bool $path = false, string $lang = null) {
590
-		return \OC::$server->getAppManager()->getAppInfo($appId, $path, $lang);
591
-	}
592
-
593
-	/**
594
-	 * Returns the navigation
595
-	 *
596
-	 * @return array
597
-	 * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll()
598
-	 *
599
-	 * This function returns an array containing all entries added. The
600
-	 * entries are sorted by the key 'order' ascending. Additional to the keys
601
-	 * given for each app the following keys exist:
602
-	 *   - active: boolean, signals if the user is on this navigation entry
603
-	 */
604
-	public static function getNavigation(): array {
605
-		return OC::$server->getNavigationManager()->getAll();
606
-	}
607
-
608
-	/**
609
-	 * Returns the Settings Navigation
610
-	 *
611
-	 * @return string[]
612
-	 * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll('settings')
613
-	 *
614
-	 * This function returns an array containing all settings pages added. The
615
-	 * entries are sorted by the key 'order' ascending.
616
-	 */
617
-	public static function getSettingsNavigation(): array {
618
-		return OC::$server->getNavigationManager()->getAll('settings');
619
-	}
620
-
621
-	/**
622
-	 * get the id of loaded app
623
-	 *
624
-	 * @return string
625
-	 */
626
-	public static function getCurrentApp(): string {
627
-		$request = \OC::$server->getRequest();
628
-		$script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
629
-		$topFolder = substr($script, 0, strpos($script, '/') ?: 0);
630
-		if (empty($topFolder)) {
631
-			$path_info = $request->getPathInfo();
632
-			if ($path_info) {
633
-				$topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
634
-			}
635
-		}
636
-		if ($topFolder == 'apps') {
637
-			$length = strlen($topFolder);
638
-			return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1) ?: '';
639
-		} else {
640
-			return $topFolder;
641
-		}
642
-	}
643
-
644
-	/**
645
-	 * @param string $type
646
-	 * @return array
647
-	 */
648
-	public static function getForms(string $type): array {
649
-		$forms = [];
650
-		switch ($type) {
651
-			case 'admin':
652
-				$source = self::$adminForms;
653
-				break;
654
-			case 'personal':
655
-				$source = self::$personalForms;
656
-				break;
657
-			default:
658
-				return [];
659
-		}
660
-		foreach ($source as $form) {
661
-			$forms[] = include $form;
662
-		}
663
-		return $forms;
664
-	}
665
-
666
-	/**
667
-	 * register an admin form to be shown
668
-	 *
669
-	 * @param string $app
670
-	 * @param string $page
671
-	 */
672
-	public static function registerAdmin(string $app, string $page) {
673
-		self::$adminForms[] = $app . '/' . $page . '.php';
674
-	}
675
-
676
-	/**
677
-	 * register a personal form to be shown
678
-	 * @param string $app
679
-	 * @param string $page
680
-	 */
681
-	public static function registerPersonal(string $app, string $page) {
682
-		self::$personalForms[] = $app . '/' . $page . '.php';
683
-	}
684
-
685
-	/**
686
-	 * @param array $entry
687
-	 * @deprecated 20.0.0 Please register your alternative login option using the registerAlternativeLogin() on the RegistrationContext in your Application class implementing the OCP\Authentication\IAlternativeLogin interface
688
-	 */
689
-	public static function registerLogIn(array $entry) {
690
-		\OC::$server->getLogger()->debug('OC_App::registerLogIn() is deprecated, please register your alternative login option using the registerAlternativeLogin() on the RegistrationContext in your Application class implementing the OCP\Authentication\IAlternativeLogin interface');
691
-		self::$altLogin[] = $entry;
692
-	}
693
-
694
-	/**
695
-	 * @return array
696
-	 */
697
-	public static function getAlternativeLogIns(): array {
698
-		/** @var Coordinator $bootstrapCoordinator */
699
-		$bootstrapCoordinator = \OC::$server->query(Coordinator::class);
700
-
701
-		foreach ($bootstrapCoordinator->getRegistrationContext()->getAlternativeLogins() as $registration) {
702
-			if (!in_array(IAlternativeLogin::class, class_implements($registration->getService()), true)) {
703
-				\OC::$server->getLogger()->error('Alternative login option {option} does not implement {interface} and is therefore ignored.', [
704
-					'option' => $registration->getService(),
705
-					'interface' => IAlternativeLogin::class,
706
-					'app' => $registration->getAppId(),
707
-				]);
708
-				continue;
709
-			}
710
-
711
-			try {
712
-				/** @var IAlternativeLogin $provider */
713
-				$provider = \OC::$server->query($registration->getService());
714
-			} catch (QueryException $e) {
715
-				\OC::$server->getLogger()->logException($e, [
716
-					'message' => 'Alternative login option {option} can not be initialised.',
717
-					'option' => $registration->getService(),
718
-					'app' => $registration->getAppId(),
719
-				]);
720
-			}
721
-
722
-			try {
723
-				$provider->load();
724
-
725
-				self::$altLogin[] = [
726
-					'name' => $provider->getLabel(),
727
-					'href' => $provider->getLink(),
728
-					'style' => $provider->getClass(),
729
-				];
730
-			} catch (Throwable $e) {
731
-				\OC::$server->getLogger()->logException($e, [
732
-					'message' => 'Alternative login option {option} had an error while loading.',
733
-					'option' => $registration->getService(),
734
-					'app' => $registration->getAppId(),
735
-				]);
736
-			}
737
-		}
738
-
739
-		return self::$altLogin;
740
-	}
741
-
742
-	/**
743
-	 * get a list of all apps in the apps folder
744
-	 *
745
-	 * @return string[] an array of app names (string IDs)
746
-	 * @todo: change the name of this method to getInstalledApps, which is more accurate
747
-	 */
748
-	public static function getAllApps(): array {
749
-		$apps = [];
750
-
751
-		foreach (OC::$APPSROOTS as $apps_dir) {
752
-			if (!is_readable($apps_dir['path'])) {
753
-				\OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], ILogger::WARN);
754
-				continue;
755
-			}
756
-			$dh = opendir($apps_dir['path']);
757
-
758
-			if (is_resource($dh)) {
759
-				while (($file = readdir($dh)) !== false) {
760
-					if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
761
-						$apps[] = $file;
762
-					}
763
-				}
764
-			}
765
-		}
766
-
767
-		$apps = array_unique($apps);
768
-
769
-		return $apps;
770
-	}
771
-
772
-	/**
773
-	 * List all apps, this is used in apps.php
774
-	 *
775
-	 * @return array
776
-	 */
777
-	public function listAllApps(): array {
778
-		$installedApps = OC_App::getAllApps();
779
-
780
-		$appManager = \OC::$server->getAppManager();
781
-		//we don't want to show configuration for these
782
-		$blacklist = $appManager->getAlwaysEnabledApps();
783
-		$appList = [];
784
-		$langCode = \OC::$server->getL10N('core')->getLanguageCode();
785
-		$urlGenerator = \OC::$server->getURLGenerator();
786
-		/** @var \OCP\Support\Subscription\IRegistry $subscriptionRegistry */
787
-		$subscriptionRegistry = \OC::$server->query(\OCP\Support\Subscription\IRegistry::class);
788
-		$supportedApps = $subscriptionRegistry->delegateGetSupportedApps();
789
-
790
-		foreach ($installedApps as $app) {
791
-			if (array_search($app, $blacklist) === false) {
792
-				$info = OC_App::getAppInfo($app, false, $langCode);
793
-				if (!is_array($info)) {
794
-					\OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', ILogger::ERROR);
795
-					continue;
796
-				}
797
-
798
-				if (!isset($info['name'])) {
799
-					\OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', ILogger::ERROR);
800
-					continue;
801
-				}
802
-
803
-				$enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'no');
804
-				$info['groups'] = null;
805
-				if ($enabled === 'yes') {
806
-					$active = true;
807
-				} elseif ($enabled === 'no') {
808
-					$active = false;
809
-				} else {
810
-					$active = true;
811
-					$info['groups'] = $enabled;
812
-				}
813
-
814
-				$info['active'] = $active;
815
-
816
-				if ($appManager->isShipped($app)) {
817
-					$info['internal'] = true;
818
-					$info['level'] = self::officialApp;
819
-					$info['removable'] = false;
820
-				} else {
821
-					$info['internal'] = false;
822
-					$info['removable'] = true;
823
-				}
824
-
825
-				if (in_array($app, $supportedApps)) {
826
-					$info['level'] = self::supportedApp;
827
-				}
828
-
829
-				$appPath = self::getAppPath($app);
830
-				if ($appPath !== false) {
831
-					$appIcon = $appPath . '/img/' . $app . '.svg';
832
-					if (file_exists($appIcon)) {
833
-						$info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
834
-						$info['previewAsIcon'] = true;
835
-					} else {
836
-						$appIcon = $appPath . '/img/app.svg';
837
-						if (file_exists($appIcon)) {
838
-							$info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
839
-							$info['previewAsIcon'] = true;
840
-						}
841
-					}
842
-				}
843
-				// fix documentation
844
-				if (isset($info['documentation']) && is_array($info['documentation'])) {
845
-					foreach ($info['documentation'] as $key => $url) {
846
-						// If it is not an absolute URL we assume it is a key
847
-						// i.e. admin-ldap will get converted to go.php?to=admin-ldap
848
-						if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
849
-							$url = $urlGenerator->linkToDocs($url);
850
-						}
851
-
852
-						$info['documentation'][$key] = $url;
853
-					}
854
-				}
855
-
856
-				$info['version'] = OC_App::getAppVersion($app);
857
-				$appList[] = $info;
858
-			}
859
-		}
860
-
861
-		return $appList;
862
-	}
863
-
864
-	public static function shouldUpgrade(string $app): bool {
865
-		$versions = self::getAppVersions();
866
-		$currentVersion = OC_App::getAppVersion($app);
867
-		if ($currentVersion && isset($versions[$app])) {
868
-			$installedVersion = $versions[$app];
869
-			if (!version_compare($currentVersion, $installedVersion, '=')) {
870
-				return true;
871
-			}
872
-		}
873
-		return false;
874
-	}
875
-
876
-	/**
877
-	 * Adjust the number of version parts of $version1 to match
878
-	 * the number of version parts of $version2.
879
-	 *
880
-	 * @param string $version1 version to adjust
881
-	 * @param string $version2 version to take the number of parts from
882
-	 * @return string shortened $version1
883
-	 */
884
-	private static function adjustVersionParts(string $version1, string $version2): string {
885
-		$version1 = explode('.', $version1);
886
-		$version2 = explode('.', $version2);
887
-		// reduce $version1 to match the number of parts in $version2
888
-		while (count($version1) > count($version2)) {
889
-			array_pop($version1);
890
-		}
891
-		// if $version1 does not have enough parts, add some
892
-		while (count($version1) < count($version2)) {
893
-			$version1[] = '0';
894
-		}
895
-		return implode('.', $version1);
896
-	}
897
-
898
-	/**
899
-	 * Check whether the current ownCloud version matches the given
900
-	 * application's version requirements.
901
-	 *
902
-	 * The comparison is made based on the number of parts that the
903
-	 * app info version has. For example for ownCloud 6.0.3 if the
904
-	 * app info version is expecting version 6.0, the comparison is
905
-	 * made on the first two parts of the ownCloud version.
906
-	 * This means that it's possible to specify "requiremin" => 6
907
-	 * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
908
-	 *
909
-	 * @param string $ocVersion ownCloud version to check against
910
-	 * @param array $appInfo app info (from xml)
911
-	 *
912
-	 * @return boolean true if compatible, otherwise false
913
-	 */
914
-	public static function isAppCompatible(string $ocVersion, array $appInfo, bool $ignoreMax = false): bool {
915
-		$requireMin = '';
916
-		$requireMax = '';
917
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
918
-			$requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
919
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
920
-			$requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
921
-		} elseif (isset($appInfo['requiremin'])) {
922
-			$requireMin = $appInfo['requiremin'];
923
-		} elseif (isset($appInfo['require'])) {
924
-			$requireMin = $appInfo['require'];
925
-		}
926
-
927
-		if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
928
-			$requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
929
-		} elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
930
-			$requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
931
-		} elseif (isset($appInfo['requiremax'])) {
932
-			$requireMax = $appInfo['requiremax'];
933
-		}
934
-
935
-		if (!empty($requireMin)
936
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
937
-		) {
938
-			return false;
939
-		}
940
-
941
-		if (!$ignoreMax && !empty($requireMax)
942
-			&& version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
943
-		) {
944
-			return false;
945
-		}
946
-
947
-		return true;
948
-	}
949
-
950
-	/**
951
-	 * get the installed version of all apps
952
-	 */
953
-	public static function getAppVersions() {
954
-		static $versions;
955
-
956
-		if (!$versions) {
957
-			$appConfig = \OC::$server->getAppConfig();
958
-			$versions = $appConfig->getValues(false, 'installed_version');
959
-		}
960
-		return $versions;
961
-	}
962
-
963
-	/**
964
-	 * update the database for the app and call the update script
965
-	 *
966
-	 * @param string $appId
967
-	 * @return bool
968
-	 */
969
-	public static function updateApp(string $appId): bool {
970
-		$appPath = self::getAppPath($appId);
971
-		if ($appPath === false) {
972
-			return false;
973
-		}
974
-
975
-		\OC::$server->getAppManager()->clearAppsCache();
976
-		$appData = self::getAppInfo($appId);
977
-
978
-		$ignoreMaxApps = \OC::$server->getConfig()->getSystemValue('app_install_overwrite', []);
979
-		$ignoreMax = in_array($appId, $ignoreMaxApps, true);
980
-		\OC_App::checkAppDependencies(
981
-			\OC::$server->getConfig(),
982
-			\OC::$server->getL10N('core'),
983
-			$appData,
984
-			$ignoreMax
985
-		);
986
-
987
-		self::registerAutoloading($appId, $appPath, true);
988
-		self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
989
-
990
-		if (file_exists($appPath . '/appinfo/database.xml')) {
991
-			OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
992
-		} else {
993
-			$ms = new MigrationService($appId, \OC::$server->get(\OC\DB\Connection::class));
994
-			$ms->migrate();
995
-		}
996
-
997
-		self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
998
-		self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
999
-		// update appversion in app manager
1000
-		\OC::$server->getAppManager()->clearAppsCache();
1001
-		\OC::$server->getAppManager()->getAppVersion($appId, false);
1002
-
1003
-		self::setupBackgroundJobs($appData['background-jobs']);
1004
-
1005
-		//set remote/public handlers
1006
-		if (array_key_exists('ocsid', $appData)) {
1007
-			\OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1008
-		} elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1009
-			\OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1010
-		}
1011
-		foreach ($appData['remote'] as $name => $path) {
1012
-			\OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1013
-		}
1014
-		foreach ($appData['public'] as $name => $path) {
1015
-			\OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1016
-		}
1017
-
1018
-		self::setAppTypes($appId);
1019
-
1020
-		$version = \OC_App::getAppVersion($appId);
1021
-		\OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
1022
-
1023
-		\OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
1024
-			ManagerEvent::EVENT_APP_UPDATE, $appId
1025
-		));
1026
-
1027
-		return true;
1028
-	}
1029
-
1030
-	/**
1031
-	 * @param string $appId
1032
-	 * @param string[] $steps
1033
-	 * @throws \OC\NeedsUpdateException
1034
-	 */
1035
-	public static function executeRepairSteps(string $appId, array $steps) {
1036
-		if (empty($steps)) {
1037
-			return;
1038
-		}
1039
-		// load the app
1040
-		self::loadApp($appId);
1041
-
1042
-		$dispatcher = OC::$server->getEventDispatcher();
1043
-
1044
-		// load the steps
1045
-		$r = new Repair([], $dispatcher, \OC::$server->get(LoggerInterface::class));
1046
-		foreach ($steps as $step) {
1047
-			try {
1048
-				$r->addStep($step);
1049
-			} catch (Exception $ex) {
1050
-				$r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1051
-				\OC::$server->getLogger()->logException($ex);
1052
-			}
1053
-		}
1054
-		// run the steps
1055
-		$r->run();
1056
-	}
1057
-
1058
-	public static function setupBackgroundJobs(array $jobs) {
1059
-		$queue = \OC::$server->getJobList();
1060
-		foreach ($jobs as $job) {
1061
-			$queue->add($job);
1062
-		}
1063
-	}
1064
-
1065
-	/**
1066
-	 * @param string $appId
1067
-	 * @param string[] $steps
1068
-	 */
1069
-	private static function setupLiveMigrations(string $appId, array $steps) {
1070
-		$queue = \OC::$server->getJobList();
1071
-		foreach ($steps as $step) {
1072
-			$queue->add('OC\Migration\BackgroundRepair', [
1073
-				'app' => $appId,
1074
-				'step' => $step]);
1075
-		}
1076
-	}
1077
-
1078
-	/**
1079
-	 * @param string $appId
1080
-	 * @return \OC\Files\View|false
1081
-	 */
1082
-	public static function getStorage(string $appId) {
1083
-		if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
1084
-			if (\OC::$server->getUserSession()->isLoggedIn()) {
1085
-				$view = new \OC\Files\View('/' . OC_User::getUser());
1086
-				if (!$view->file_exists($appId)) {
1087
-					$view->mkdir($appId);
1088
-				}
1089
-				return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1090
-			} else {
1091
-				\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', ILogger::ERROR);
1092
-				return false;
1093
-			}
1094
-		} else {
1095
-			\OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', ILogger::ERROR);
1096
-			return false;
1097
-		}
1098
-	}
1099
-
1100
-	protected static function findBestL10NOption(array $options, string $lang): string {
1101
-		// only a single option
1102
-		if (isset($options['@value'])) {
1103
-			return $options['@value'];
1104
-		}
1105
-
1106
-		$fallback = $similarLangFallback = $englishFallback = false;
1107
-
1108
-		$lang = strtolower($lang);
1109
-		$similarLang = $lang;
1110
-		if (strpos($similarLang, '_')) {
1111
-			// For "de_DE" we want to find "de" and the other way around
1112
-			$similarLang = substr($lang, 0, strpos($lang, '_'));
1113
-		}
1114
-
1115
-		foreach ($options as $option) {
1116
-			if (is_array($option)) {
1117
-				if ($fallback === false) {
1118
-					$fallback = $option['@value'];
1119
-				}
1120
-
1121
-				if (!isset($option['@attributes']['lang'])) {
1122
-					continue;
1123
-				}
1124
-
1125
-				$attributeLang = strtolower($option['@attributes']['lang']);
1126
-				if ($attributeLang === $lang) {
1127
-					return $option['@value'];
1128
-				}
1129
-
1130
-				if ($attributeLang === $similarLang) {
1131
-					$similarLangFallback = $option['@value'];
1132
-				} elseif (strpos($attributeLang, $similarLang . '_') === 0) {
1133
-					if ($similarLangFallback === false) {
1134
-						$similarLangFallback = $option['@value'];
1135
-					}
1136
-				}
1137
-			} else {
1138
-				$englishFallback = $option;
1139
-			}
1140
-		}
1141
-
1142
-		if ($similarLangFallback !== false) {
1143
-			return $similarLangFallback;
1144
-		} elseif ($englishFallback !== false) {
1145
-			return $englishFallback;
1146
-		}
1147
-		return (string) $fallback;
1148
-	}
1149
-
1150
-	/**
1151
-	 * parses the app data array and enhanced the 'description' value
1152
-	 *
1153
-	 * @param array $data the app data
1154
-	 * @param string $lang
1155
-	 * @return array improved app data
1156
-	 */
1157
-	public static function parseAppInfo(array $data, $lang = null): array {
1158
-		if ($lang && isset($data['name']) && is_array($data['name'])) {
1159
-			$data['name'] = self::findBestL10NOption($data['name'], $lang);
1160
-		}
1161
-		if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1162
-			$data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1163
-		}
1164
-		if ($lang && isset($data['description']) && is_array($data['description'])) {
1165
-			$data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1166
-		} elseif (isset($data['description']) && is_string($data['description'])) {
1167
-			$data['description'] = trim($data['description']);
1168
-		} else {
1169
-			$data['description'] = '';
1170
-		}
1171
-
1172
-		return $data;
1173
-	}
1174
-
1175
-	/**
1176
-	 * @param \OCP\IConfig $config
1177
-	 * @param \OCP\IL10N $l
1178
-	 * @param array $info
1179
-	 * @throws \Exception
1180
-	 */
1181
-	public static function checkAppDependencies(\OCP\IConfig $config, \OCP\IL10N $l, array $info, bool $ignoreMax) {
1182
-		$dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1183
-		$missing = $dependencyAnalyzer->analyze($info, $ignoreMax);
1184
-		if (!empty($missing)) {
1185
-			$missingMsg = implode(PHP_EOL, $missing);
1186
-			throw new \Exception(
1187
-				$l->t('App "%1$s" cannot be installed because the following dependencies are not fulfilled: %2$s',
1188
-					[$info['name'], $missingMsg]
1189
-				)
1190
-			);
1191
-		}
1192
-	}
72
+    private static $adminForms = [];
73
+    private static $personalForms = [];
74
+    private static $appTypes = [];
75
+    private static $loadedApps = [];
76
+    private static $altLogin = [];
77
+    private static $alreadyRegistered = [];
78
+    public const supportedApp = 300;
79
+    public const officialApp = 200;
80
+
81
+    /**
82
+     * clean the appId
83
+     *
84
+     * @psalm-taint-escape file
85
+     * @psalm-taint-escape include
86
+     *
87
+     * @param string $app AppId that needs to be cleaned
88
+     * @return string
89
+     */
90
+    public static function cleanAppId(string $app): string {
91
+        return str_replace(['\0', '/', '\\', '..'], '', $app);
92
+    }
93
+
94
+    /**
95
+     * Check if an app is loaded
96
+     *
97
+     * @param string $app
98
+     * @return bool
99
+     */
100
+    public static function isAppLoaded(string $app): bool {
101
+        return isset(self::$loadedApps[$app]);
102
+    }
103
+
104
+    /**
105
+     * loads all apps
106
+     *
107
+     * @param string[] $types
108
+     * @return bool
109
+     *
110
+     * This function walks through the ownCloud directory and loads all apps
111
+     * it can find. A directory contains an app if the file /appinfo/info.xml
112
+     * exists.
113
+     *
114
+     * if $types is set to non-empty array, only apps of those types will be loaded
115
+     */
116
+    public static function loadApps(array $types = []): bool {
117
+        if ((bool) \OC::$server->getSystemConfig()->getValue('maintenance', false)) {
118
+            return false;
119
+        }
120
+        // Load the enabled apps here
121
+        $apps = self::getEnabledApps();
122
+
123
+        // Add each apps' folder as allowed class path
124
+        foreach ($apps as $app) {
125
+            // If the app is already loaded then autoloading it makes no sense
126
+            if (!isset(self::$loadedApps[$app])) {
127
+                $path = self::getAppPath($app);
128
+                if ($path !== false) {
129
+                    self::registerAutoloading($app, $path);
130
+                }
131
+            }
132
+        }
133
+
134
+        // prevent app.php from printing output
135
+        ob_start();
136
+        foreach ($apps as $app) {
137
+            if (!isset(self::$loadedApps[$app]) && ($types === [] || self::isType($app, $types))) {
138
+                self::loadApp($app);
139
+            }
140
+        }
141
+        ob_end_clean();
142
+
143
+        return true;
144
+    }
145
+
146
+    /**
147
+     * load a single app
148
+     *
149
+     * @param string $app
150
+     * @throws Exception
151
+     */
152
+    public static function loadApp(string $app) {
153
+        self::$loadedApps[$app] = true;
154
+        $appPath = self::getAppPath($app);
155
+        if ($appPath === false) {
156
+            return;
157
+        }
158
+
159
+        // in case someone calls loadApp() directly
160
+        self::registerAutoloading($app, $appPath);
161
+
162
+        /** @var Coordinator $coordinator */
163
+        $coordinator = \OC::$server->query(Coordinator::class);
164
+        $isBootable = $coordinator->isBootable($app);
165
+
166
+        $hasAppPhpFile = is_file($appPath . '/appinfo/app.php');
167
+
168
+        if ($isBootable && $hasAppPhpFile) {
169
+            \OC::$server->getLogger()->error('/appinfo/app.php is not loaded when \OCP\AppFramework\Bootstrap\IBootstrap on the application class is used. Migrate everything from app.php to the Application class.', [
170
+                'app' => $app,
171
+            ]);
172
+        } elseif ($hasAppPhpFile) {
173
+            \OC::$server->getLogger()->debug('/appinfo/app.php is deprecated, use \OCP\AppFramework\Bootstrap\IBootstrap on the application class instead.', [
174
+                'app' => $app,
175
+            ]);
176
+            \OC::$server->getEventLogger()->start('load_app_' . $app, 'Load app: ' . $app);
177
+            try {
178
+                self::requireAppFile($app);
179
+            } catch (Throwable $ex) {
180
+                if ($ex instanceof ServerNotAvailableException) {
181
+                    throw $ex;
182
+                }
183
+                if (!\OC::$server->getAppManager()->isShipped($app) && !self::isType($app, ['authentication'])) {
184
+                    \OC::$server->getLogger()->logException($ex, [
185
+                        'message' => "App $app threw an error during app.php load and will be disabled: " . $ex->getMessage(),
186
+                    ]);
187
+
188
+                    // Only disable apps which are not shipped and that are not authentication apps
189
+                    \OC::$server->getAppManager()->disableApp($app, true);
190
+                } else {
191
+                    \OC::$server->getLogger()->logException($ex, [
192
+                        'message' => "App $app threw an error during app.php load: " . $ex->getMessage(),
193
+                    ]);
194
+                }
195
+            }
196
+            \OC::$server->getEventLogger()->end('load_app_' . $app);
197
+        }
198
+        $coordinator->bootApp($app);
199
+
200
+        $info = self::getAppInfo($app);
201
+        if (!empty($info['activity']['filters'])) {
202
+            foreach ($info['activity']['filters'] as $filter) {
203
+                \OC::$server->getActivityManager()->registerFilter($filter);
204
+            }
205
+        }
206
+        if (!empty($info['activity']['settings'])) {
207
+            foreach ($info['activity']['settings'] as $setting) {
208
+                \OC::$server->getActivityManager()->registerSetting($setting);
209
+            }
210
+        }
211
+        if (!empty($info['activity']['providers'])) {
212
+            foreach ($info['activity']['providers'] as $provider) {
213
+                \OC::$server->getActivityManager()->registerProvider($provider);
214
+            }
215
+        }
216
+
217
+        if (!empty($info['settings']['admin'])) {
218
+            foreach ($info['settings']['admin'] as $setting) {
219
+                \OC::$server->getSettingsManager()->registerSetting('admin', $setting);
220
+            }
221
+        }
222
+        if (!empty($info['settings']['admin-section'])) {
223
+            foreach ($info['settings']['admin-section'] as $section) {
224
+                \OC::$server->getSettingsManager()->registerSection('admin', $section);
225
+            }
226
+        }
227
+        if (!empty($info['settings']['personal'])) {
228
+            foreach ($info['settings']['personal'] as $setting) {
229
+                \OC::$server->getSettingsManager()->registerSetting('personal', $setting);
230
+            }
231
+        }
232
+        if (!empty($info['settings']['personal-section'])) {
233
+            foreach ($info['settings']['personal-section'] as $section) {
234
+                \OC::$server->getSettingsManager()->registerSection('personal', $section);
235
+            }
236
+        }
237
+
238
+        if (!empty($info['collaboration']['plugins'])) {
239
+            // deal with one or many plugin entries
240
+            $plugins = isset($info['collaboration']['plugins']['plugin']['@value']) ?
241
+                [$info['collaboration']['plugins']['plugin']] : $info['collaboration']['plugins']['plugin'];
242
+            foreach ($plugins as $plugin) {
243
+                if ($plugin['@attributes']['type'] === 'collaborator-search') {
244
+                    $pluginInfo = [
245
+                        'shareType' => $plugin['@attributes']['share-type'],
246
+                        'class' => $plugin['@value'],
247
+                    ];
248
+                    \OC::$server->getCollaboratorSearch()->registerPlugin($pluginInfo);
249
+                } elseif ($plugin['@attributes']['type'] === 'autocomplete-sort') {
250
+                    \OC::$server->getAutoCompleteManager()->registerSorter($plugin['@value']);
251
+                }
252
+            }
253
+        }
254
+    }
255
+
256
+    /**
257
+     * @internal
258
+     * @param string $app
259
+     * @param string $path
260
+     * @param bool $force
261
+     */
262
+    public static function registerAutoloading(string $app, string $path, bool $force = false) {
263
+        $key = $app . '-' . $path;
264
+        if (!$force && isset(self::$alreadyRegistered[$key])) {
265
+            return;
266
+        }
267
+
268
+        self::$alreadyRegistered[$key] = true;
269
+
270
+        // Register on PSR-4 composer autoloader
271
+        $appNamespace = \OC\AppFramework\App::buildAppNamespace($app);
272
+        \OC::$server->registerNamespace($app, $appNamespace);
273
+
274
+        if (file_exists($path . '/composer/autoload.php')) {
275
+            require_once $path . '/composer/autoload.php';
276
+        } else {
277
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\', $path . '/lib/', true);
278
+            // Register on legacy autoloader
279
+            \OC::$loader->addValidRoot($path);
280
+        }
281
+
282
+        // Register Test namespace only when testing
283
+        if (defined('PHPUNIT_RUN') || defined('CLI_TEST_RUN')) {
284
+            \OC::$composerAutoloader->addPsr4($appNamespace . '\\Tests\\', $path . '/tests/', true);
285
+        }
286
+    }
287
+
288
+    /**
289
+     * Load app.php from the given app
290
+     *
291
+     * @param string $app app name
292
+     * @throws Error
293
+     */
294
+    private static function requireAppFile(string $app) {
295
+        // encapsulated here to avoid variable scope conflicts
296
+        require_once $app . '/appinfo/app.php';
297
+    }
298
+
299
+    /**
300
+     * check if an app is of a specific type
301
+     *
302
+     * @param string $app
303
+     * @param array $types
304
+     * @return bool
305
+     */
306
+    public static function isType(string $app, array $types): bool {
307
+        $appTypes = self::getAppTypes($app);
308
+        foreach ($types as $type) {
309
+            if (array_search($type, $appTypes) !== false) {
310
+                return true;
311
+            }
312
+        }
313
+        return false;
314
+    }
315
+
316
+    /**
317
+     * get the types of an app
318
+     *
319
+     * @param string $app
320
+     * @return array
321
+     */
322
+    private static function getAppTypes(string $app): array {
323
+        //load the cache
324
+        if (count(self::$appTypes) == 0) {
325
+            self::$appTypes = \OC::$server->getAppConfig()->getValues(false, 'types');
326
+        }
327
+
328
+        if (isset(self::$appTypes[$app])) {
329
+            return explode(',', self::$appTypes[$app]);
330
+        }
331
+
332
+        return [];
333
+    }
334
+
335
+    /**
336
+     * read app types from info.xml and cache them in the database
337
+     */
338
+    public static function setAppTypes(string $app) {
339
+        $appManager = \OC::$server->getAppManager();
340
+        $appData = $appManager->getAppInfo($app);
341
+        if (!is_array($appData)) {
342
+            return;
343
+        }
344
+
345
+        if (isset($appData['types'])) {
346
+            $appTypes = implode(',', $appData['types']);
347
+        } else {
348
+            $appTypes = '';
349
+            $appData['types'] = [];
350
+        }
351
+
352
+        $config = \OC::$server->getConfig();
353
+        $config->setAppValue($app, 'types', $appTypes);
354
+
355
+        if ($appManager->hasProtectedAppType($appData['types'])) {
356
+            $enabled = $config->getAppValue($app, 'enabled', 'yes');
357
+            if ($enabled !== 'yes' && $enabled !== 'no') {
358
+                $config->setAppValue($app, 'enabled', 'yes');
359
+            }
360
+        }
361
+    }
362
+
363
+    /**
364
+     * Returns apps enabled for the current user.
365
+     *
366
+     * @param bool $forceRefresh whether to refresh the cache
367
+     * @param bool $all whether to return apps for all users, not only the
368
+     * currently logged in one
369
+     * @return string[]
370
+     */
371
+    public static function getEnabledApps(bool $forceRefresh = false, bool $all = false): array {
372
+        if (!\OC::$server->getSystemConfig()->getValue('installed', false)) {
373
+            return [];
374
+        }
375
+        // in incognito mode or when logged out, $user will be false,
376
+        // which is also the case during an upgrade
377
+        $appManager = \OC::$server->getAppManager();
378
+        if ($all) {
379
+            $user = null;
380
+        } else {
381
+            $user = \OC::$server->getUserSession()->getUser();
382
+        }
383
+
384
+        if (is_null($user)) {
385
+            $apps = $appManager->getInstalledApps();
386
+        } else {
387
+            $apps = $appManager->getEnabledAppsForUser($user);
388
+        }
389
+        $apps = array_filter($apps, function ($app) {
390
+            return $app !== 'files';//we add this manually
391
+        });
392
+        sort($apps);
393
+        array_unshift($apps, 'files');
394
+        return $apps;
395
+    }
396
+
397
+    /**
398
+     * checks whether or not an app is enabled
399
+     *
400
+     * @param string $app app
401
+     * @return bool
402
+     * @deprecated 13.0.0 use \OC::$server->getAppManager()->isEnabledForUser($appId)
403
+     *
404
+     * This function checks whether or not an app is enabled.
405
+     */
406
+    public static function isEnabled(string $app): bool {
407
+        return \OC::$server->getAppManager()->isEnabledForUser($app);
408
+    }
409
+
410
+    /**
411
+     * enables an app
412
+     *
413
+     * @param string $appId
414
+     * @param array $groups (optional) when set, only these groups will have access to the app
415
+     * @throws \Exception
416
+     * @return void
417
+     *
418
+     * This function set an app as enabled in appconfig.
419
+     */
420
+    public function enable(string $appId,
421
+                            array $groups = []) {
422
+
423
+        // Check if app is already downloaded
424
+        /** @var Installer $installer */
425
+        $installer = \OC::$server->query(Installer::class);
426
+        $isDownloaded = $installer->isDownloaded($appId);
427
+
428
+        if (!$isDownloaded) {
429
+            $installer->downloadApp($appId);
430
+        }
431
+
432
+        $installer->installApp($appId);
433
+
434
+        $appManager = \OC::$server->getAppManager();
435
+        if ($groups !== []) {
436
+            $groupManager = \OC::$server->getGroupManager();
437
+            $groupsList = [];
438
+            foreach ($groups as $group) {
439
+                $groupItem = $groupManager->get($group);
440
+                if ($groupItem instanceof \OCP\IGroup) {
441
+                    $groupsList[] = $groupManager->get($group);
442
+                }
443
+            }
444
+            $appManager->enableAppForGroups($appId, $groupsList);
445
+        } else {
446
+            $appManager->enableApp($appId);
447
+        }
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.', ILogger::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(string $appId) {
478
+        $sanitizedAppId = self::cleanAppId($appId);
479
+        if ($sanitizedAppId !== $appId) {
480
+            return false;
481
+        }
482
+        static $app_dir = [];
483
+
484
+        if (isset($app_dir[$appId])) {
485
+            return $app_dir[$appId];
486
+        }
487
+
488
+        $possibleApps = [];
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 = [];
503
+            foreach ($possibleApps as $possibleApp) {
504
+                $version = self::getAppVersionByPath($possibleApp['path'] . '/' . $appId);
505
+                if (empty($versionToLoad) || version_compare($version, $versionToLoad['version'], '>')) {
506
+                    $versionToLoad = [
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
+     * @psalm-taint-specialize
523
+     *
524
+     * @param string $appId
525
+     * @return string|false
526
+     * @deprecated 11.0.0 use \OC::$server->getAppManager()->getAppPath()
527
+     */
528
+    public static function getAppPath(string $appId) {
529
+        if ($appId === null || trim($appId) === '') {
530
+            return false;
531
+        }
532
+
533
+        if (($dir = self::findAppInDirectories($appId)) != false) {
534
+            return $dir['path'] . '/' . $appId;
535
+        }
536
+        return false;
537
+    }
538
+
539
+    /**
540
+     * Get the path for the given app on the access
541
+     * If the app is defined in multiple directories, the first one is taken. (false if not found)
542
+     *
543
+     * @param string $appId
544
+     * @return string|false
545
+     * @deprecated 18.0.0 use \OC::$server->getAppManager()->getAppWebPath()
546
+     */
547
+    public static function getAppWebPath(string $appId) {
548
+        if (($dir = self::findAppInDirectories($appId)) != false) {
549
+            return OC::$WEBROOT . $dir['url'] . '/' . $appId;
550
+        }
551
+        return false;
552
+    }
553
+
554
+    /**
555
+     * get the last version of the app from appinfo/info.xml
556
+     *
557
+     * @param string $appId
558
+     * @param bool $useCache
559
+     * @return string
560
+     * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppVersion()
561
+     */
562
+    public static function getAppVersion(string $appId, bool $useCache = true): string {
563
+        return \OC::$server->getAppManager()->getAppVersion($appId, $useCache);
564
+    }
565
+
566
+    /**
567
+     * get app's version based on it's path
568
+     *
569
+     * @param string $path
570
+     * @return string
571
+     */
572
+    public static function getAppVersionByPath(string $path): string {
573
+        $infoFile = $path . '/appinfo/info.xml';
574
+        $appData = \OC::$server->getAppManager()->getAppInfo($infoFile, true);
575
+        return isset($appData['version']) ? $appData['version'] : '';
576
+    }
577
+
578
+
579
+    /**
580
+     * Read all app metadata from the info.xml file
581
+     *
582
+     * @param string $appId id of the app or the path of the info.xml file
583
+     * @param bool $path
584
+     * @param string $lang
585
+     * @return array|null
586
+     * @note all data is read from info.xml, not just pre-defined fields
587
+     * @deprecated 14.0.0 use \OC::$server->getAppManager()->getAppInfo()
588
+     */
589
+    public static function getAppInfo(string $appId, bool $path = false, string $lang = null) {
590
+        return \OC::$server->getAppManager()->getAppInfo($appId, $path, $lang);
591
+    }
592
+
593
+    /**
594
+     * Returns the navigation
595
+     *
596
+     * @return array
597
+     * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll()
598
+     *
599
+     * This function returns an array containing all entries added. The
600
+     * entries are sorted by the key 'order' ascending. Additional to the keys
601
+     * given for each app the following keys exist:
602
+     *   - active: boolean, signals if the user is on this navigation entry
603
+     */
604
+    public static function getNavigation(): array {
605
+        return OC::$server->getNavigationManager()->getAll();
606
+    }
607
+
608
+    /**
609
+     * Returns the Settings Navigation
610
+     *
611
+     * @return string[]
612
+     * @deprecated 14.0.0 use \OC::$server->getNavigationManager()->getAll('settings')
613
+     *
614
+     * This function returns an array containing all settings pages added. The
615
+     * entries are sorted by the key 'order' ascending.
616
+     */
617
+    public static function getSettingsNavigation(): array {
618
+        return OC::$server->getNavigationManager()->getAll('settings');
619
+    }
620
+
621
+    /**
622
+     * get the id of loaded app
623
+     *
624
+     * @return string
625
+     */
626
+    public static function getCurrentApp(): string {
627
+        $request = \OC::$server->getRequest();
628
+        $script = substr($request->getScriptName(), strlen(OC::$WEBROOT) + 1);
629
+        $topFolder = substr($script, 0, strpos($script, '/') ?: 0);
630
+        if (empty($topFolder)) {
631
+            $path_info = $request->getPathInfo();
632
+            if ($path_info) {
633
+                $topFolder = substr($path_info, 1, strpos($path_info, '/', 1) - 1);
634
+            }
635
+        }
636
+        if ($topFolder == 'apps') {
637
+            $length = strlen($topFolder);
638
+            return substr($script, $length + 1, strpos($script, '/', $length + 1) - $length - 1) ?: '';
639
+        } else {
640
+            return $topFolder;
641
+        }
642
+    }
643
+
644
+    /**
645
+     * @param string $type
646
+     * @return array
647
+     */
648
+    public static function getForms(string $type): array {
649
+        $forms = [];
650
+        switch ($type) {
651
+            case 'admin':
652
+                $source = self::$adminForms;
653
+                break;
654
+            case 'personal':
655
+                $source = self::$personalForms;
656
+                break;
657
+            default:
658
+                return [];
659
+        }
660
+        foreach ($source as $form) {
661
+            $forms[] = include $form;
662
+        }
663
+        return $forms;
664
+    }
665
+
666
+    /**
667
+     * register an admin form to be shown
668
+     *
669
+     * @param string $app
670
+     * @param string $page
671
+     */
672
+    public static function registerAdmin(string $app, string $page) {
673
+        self::$adminForms[] = $app . '/' . $page . '.php';
674
+    }
675
+
676
+    /**
677
+     * register a personal form to be shown
678
+     * @param string $app
679
+     * @param string $page
680
+     */
681
+    public static function registerPersonal(string $app, string $page) {
682
+        self::$personalForms[] = $app . '/' . $page . '.php';
683
+    }
684
+
685
+    /**
686
+     * @param array $entry
687
+     * @deprecated 20.0.0 Please register your alternative login option using the registerAlternativeLogin() on the RegistrationContext in your Application class implementing the OCP\Authentication\IAlternativeLogin interface
688
+     */
689
+    public static function registerLogIn(array $entry) {
690
+        \OC::$server->getLogger()->debug('OC_App::registerLogIn() is deprecated, please register your alternative login option using the registerAlternativeLogin() on the RegistrationContext in your Application class implementing the OCP\Authentication\IAlternativeLogin interface');
691
+        self::$altLogin[] = $entry;
692
+    }
693
+
694
+    /**
695
+     * @return array
696
+     */
697
+    public static function getAlternativeLogIns(): array {
698
+        /** @var Coordinator $bootstrapCoordinator */
699
+        $bootstrapCoordinator = \OC::$server->query(Coordinator::class);
700
+
701
+        foreach ($bootstrapCoordinator->getRegistrationContext()->getAlternativeLogins() as $registration) {
702
+            if (!in_array(IAlternativeLogin::class, class_implements($registration->getService()), true)) {
703
+                \OC::$server->getLogger()->error('Alternative login option {option} does not implement {interface} and is therefore ignored.', [
704
+                    'option' => $registration->getService(),
705
+                    'interface' => IAlternativeLogin::class,
706
+                    'app' => $registration->getAppId(),
707
+                ]);
708
+                continue;
709
+            }
710
+
711
+            try {
712
+                /** @var IAlternativeLogin $provider */
713
+                $provider = \OC::$server->query($registration->getService());
714
+            } catch (QueryException $e) {
715
+                \OC::$server->getLogger()->logException($e, [
716
+                    'message' => 'Alternative login option {option} can not be initialised.',
717
+                    'option' => $registration->getService(),
718
+                    'app' => $registration->getAppId(),
719
+                ]);
720
+            }
721
+
722
+            try {
723
+                $provider->load();
724
+
725
+                self::$altLogin[] = [
726
+                    'name' => $provider->getLabel(),
727
+                    'href' => $provider->getLink(),
728
+                    'style' => $provider->getClass(),
729
+                ];
730
+            } catch (Throwable $e) {
731
+                \OC::$server->getLogger()->logException($e, [
732
+                    'message' => 'Alternative login option {option} had an error while loading.',
733
+                    'option' => $registration->getService(),
734
+                    'app' => $registration->getAppId(),
735
+                ]);
736
+            }
737
+        }
738
+
739
+        return self::$altLogin;
740
+    }
741
+
742
+    /**
743
+     * get a list of all apps in the apps folder
744
+     *
745
+     * @return string[] an array of app names (string IDs)
746
+     * @todo: change the name of this method to getInstalledApps, which is more accurate
747
+     */
748
+    public static function getAllApps(): array {
749
+        $apps = [];
750
+
751
+        foreach (OC::$APPSROOTS as $apps_dir) {
752
+            if (!is_readable($apps_dir['path'])) {
753
+                \OCP\Util::writeLog('core', 'unable to read app folder : ' . $apps_dir['path'], ILogger::WARN);
754
+                continue;
755
+            }
756
+            $dh = opendir($apps_dir['path']);
757
+
758
+            if (is_resource($dh)) {
759
+                while (($file = readdir($dh)) !== false) {
760
+                    if ($file[0] != '.' and is_dir($apps_dir['path'] . '/' . $file) and is_file($apps_dir['path'] . '/' . $file . '/appinfo/info.xml')) {
761
+                        $apps[] = $file;
762
+                    }
763
+                }
764
+            }
765
+        }
766
+
767
+        $apps = array_unique($apps);
768
+
769
+        return $apps;
770
+    }
771
+
772
+    /**
773
+     * List all apps, this is used in apps.php
774
+     *
775
+     * @return array
776
+     */
777
+    public function listAllApps(): array {
778
+        $installedApps = OC_App::getAllApps();
779
+
780
+        $appManager = \OC::$server->getAppManager();
781
+        //we don't want to show configuration for these
782
+        $blacklist = $appManager->getAlwaysEnabledApps();
783
+        $appList = [];
784
+        $langCode = \OC::$server->getL10N('core')->getLanguageCode();
785
+        $urlGenerator = \OC::$server->getURLGenerator();
786
+        /** @var \OCP\Support\Subscription\IRegistry $subscriptionRegistry */
787
+        $subscriptionRegistry = \OC::$server->query(\OCP\Support\Subscription\IRegistry::class);
788
+        $supportedApps = $subscriptionRegistry->delegateGetSupportedApps();
789
+
790
+        foreach ($installedApps as $app) {
791
+            if (array_search($app, $blacklist) === false) {
792
+                $info = OC_App::getAppInfo($app, false, $langCode);
793
+                if (!is_array($info)) {
794
+                    \OCP\Util::writeLog('core', 'Could not read app info file for app "' . $app . '"', ILogger::ERROR);
795
+                    continue;
796
+                }
797
+
798
+                if (!isset($info['name'])) {
799
+                    \OCP\Util::writeLog('core', 'App id "' . $app . '" has no name in appinfo', ILogger::ERROR);
800
+                    continue;
801
+                }
802
+
803
+                $enabled = \OC::$server->getConfig()->getAppValue($app, 'enabled', 'no');
804
+                $info['groups'] = null;
805
+                if ($enabled === 'yes') {
806
+                    $active = true;
807
+                } elseif ($enabled === 'no') {
808
+                    $active = false;
809
+                } else {
810
+                    $active = true;
811
+                    $info['groups'] = $enabled;
812
+                }
813
+
814
+                $info['active'] = $active;
815
+
816
+                if ($appManager->isShipped($app)) {
817
+                    $info['internal'] = true;
818
+                    $info['level'] = self::officialApp;
819
+                    $info['removable'] = false;
820
+                } else {
821
+                    $info['internal'] = false;
822
+                    $info['removable'] = true;
823
+                }
824
+
825
+                if (in_array($app, $supportedApps)) {
826
+                    $info['level'] = self::supportedApp;
827
+                }
828
+
829
+                $appPath = self::getAppPath($app);
830
+                if ($appPath !== false) {
831
+                    $appIcon = $appPath . '/img/' . $app . '.svg';
832
+                    if (file_exists($appIcon)) {
833
+                        $info['preview'] = $urlGenerator->imagePath($app, $app . '.svg');
834
+                        $info['previewAsIcon'] = true;
835
+                    } else {
836
+                        $appIcon = $appPath . '/img/app.svg';
837
+                        if (file_exists($appIcon)) {
838
+                            $info['preview'] = $urlGenerator->imagePath($app, 'app.svg');
839
+                            $info['previewAsIcon'] = true;
840
+                        }
841
+                    }
842
+                }
843
+                // fix documentation
844
+                if (isset($info['documentation']) && is_array($info['documentation'])) {
845
+                    foreach ($info['documentation'] as $key => $url) {
846
+                        // If it is not an absolute URL we assume it is a key
847
+                        // i.e. admin-ldap will get converted to go.php?to=admin-ldap
848
+                        if (stripos($url, 'https://') !== 0 && stripos($url, 'http://') !== 0) {
849
+                            $url = $urlGenerator->linkToDocs($url);
850
+                        }
851
+
852
+                        $info['documentation'][$key] = $url;
853
+                    }
854
+                }
855
+
856
+                $info['version'] = OC_App::getAppVersion($app);
857
+                $appList[] = $info;
858
+            }
859
+        }
860
+
861
+        return $appList;
862
+    }
863
+
864
+    public static function shouldUpgrade(string $app): bool {
865
+        $versions = self::getAppVersions();
866
+        $currentVersion = OC_App::getAppVersion($app);
867
+        if ($currentVersion && isset($versions[$app])) {
868
+            $installedVersion = $versions[$app];
869
+            if (!version_compare($currentVersion, $installedVersion, '=')) {
870
+                return true;
871
+            }
872
+        }
873
+        return false;
874
+    }
875
+
876
+    /**
877
+     * Adjust the number of version parts of $version1 to match
878
+     * the number of version parts of $version2.
879
+     *
880
+     * @param string $version1 version to adjust
881
+     * @param string $version2 version to take the number of parts from
882
+     * @return string shortened $version1
883
+     */
884
+    private static function adjustVersionParts(string $version1, string $version2): string {
885
+        $version1 = explode('.', $version1);
886
+        $version2 = explode('.', $version2);
887
+        // reduce $version1 to match the number of parts in $version2
888
+        while (count($version1) > count($version2)) {
889
+            array_pop($version1);
890
+        }
891
+        // if $version1 does not have enough parts, add some
892
+        while (count($version1) < count($version2)) {
893
+            $version1[] = '0';
894
+        }
895
+        return implode('.', $version1);
896
+    }
897
+
898
+    /**
899
+     * Check whether the current ownCloud version matches the given
900
+     * application's version requirements.
901
+     *
902
+     * The comparison is made based on the number of parts that the
903
+     * app info version has. For example for ownCloud 6.0.3 if the
904
+     * app info version is expecting version 6.0, the comparison is
905
+     * made on the first two parts of the ownCloud version.
906
+     * This means that it's possible to specify "requiremin" => 6
907
+     * and "requiremax" => 6 and it will still match ownCloud 6.0.3.
908
+     *
909
+     * @param string $ocVersion ownCloud version to check against
910
+     * @param array $appInfo app info (from xml)
911
+     *
912
+     * @return boolean true if compatible, otherwise false
913
+     */
914
+    public static function isAppCompatible(string $ocVersion, array $appInfo, bool $ignoreMax = false): bool {
915
+        $requireMin = '';
916
+        $requireMax = '';
917
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['min-version'])) {
918
+            $requireMin = $appInfo['dependencies']['nextcloud']['@attributes']['min-version'];
919
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['min-version'])) {
920
+            $requireMin = $appInfo['dependencies']['owncloud']['@attributes']['min-version'];
921
+        } elseif (isset($appInfo['requiremin'])) {
922
+            $requireMin = $appInfo['requiremin'];
923
+        } elseif (isset($appInfo['require'])) {
924
+            $requireMin = $appInfo['require'];
925
+        }
926
+
927
+        if (isset($appInfo['dependencies']['nextcloud']['@attributes']['max-version'])) {
928
+            $requireMax = $appInfo['dependencies']['nextcloud']['@attributes']['max-version'];
929
+        } elseif (isset($appInfo['dependencies']['owncloud']['@attributes']['max-version'])) {
930
+            $requireMax = $appInfo['dependencies']['owncloud']['@attributes']['max-version'];
931
+        } elseif (isset($appInfo['requiremax'])) {
932
+            $requireMax = $appInfo['requiremax'];
933
+        }
934
+
935
+        if (!empty($requireMin)
936
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMin), $requireMin, '<')
937
+        ) {
938
+            return false;
939
+        }
940
+
941
+        if (!$ignoreMax && !empty($requireMax)
942
+            && version_compare(self::adjustVersionParts($ocVersion, $requireMax), $requireMax, '>')
943
+        ) {
944
+            return false;
945
+        }
946
+
947
+        return true;
948
+    }
949
+
950
+    /**
951
+     * get the installed version of all apps
952
+     */
953
+    public static function getAppVersions() {
954
+        static $versions;
955
+
956
+        if (!$versions) {
957
+            $appConfig = \OC::$server->getAppConfig();
958
+            $versions = $appConfig->getValues(false, 'installed_version');
959
+        }
960
+        return $versions;
961
+    }
962
+
963
+    /**
964
+     * update the database for the app and call the update script
965
+     *
966
+     * @param string $appId
967
+     * @return bool
968
+     */
969
+    public static function updateApp(string $appId): bool {
970
+        $appPath = self::getAppPath($appId);
971
+        if ($appPath === false) {
972
+            return false;
973
+        }
974
+
975
+        \OC::$server->getAppManager()->clearAppsCache();
976
+        $appData = self::getAppInfo($appId);
977
+
978
+        $ignoreMaxApps = \OC::$server->getConfig()->getSystemValue('app_install_overwrite', []);
979
+        $ignoreMax = in_array($appId, $ignoreMaxApps, true);
980
+        \OC_App::checkAppDependencies(
981
+            \OC::$server->getConfig(),
982
+            \OC::$server->getL10N('core'),
983
+            $appData,
984
+            $ignoreMax
985
+        );
986
+
987
+        self::registerAutoloading($appId, $appPath, true);
988
+        self::executeRepairSteps($appId, $appData['repair-steps']['pre-migration']);
989
+
990
+        if (file_exists($appPath . '/appinfo/database.xml')) {
991
+            OC_DB::updateDbFromStructure($appPath . '/appinfo/database.xml');
992
+        } else {
993
+            $ms = new MigrationService($appId, \OC::$server->get(\OC\DB\Connection::class));
994
+            $ms->migrate();
995
+        }
996
+
997
+        self::executeRepairSteps($appId, $appData['repair-steps']['post-migration']);
998
+        self::setupLiveMigrations($appId, $appData['repair-steps']['live-migration']);
999
+        // update appversion in app manager
1000
+        \OC::$server->getAppManager()->clearAppsCache();
1001
+        \OC::$server->getAppManager()->getAppVersion($appId, false);
1002
+
1003
+        self::setupBackgroundJobs($appData['background-jobs']);
1004
+
1005
+        //set remote/public handlers
1006
+        if (array_key_exists('ocsid', $appData)) {
1007
+            \OC::$server->getConfig()->setAppValue($appId, 'ocsid', $appData['ocsid']);
1008
+        } elseif (\OC::$server->getConfig()->getAppValue($appId, 'ocsid', null) !== null) {
1009
+            \OC::$server->getConfig()->deleteAppValue($appId, 'ocsid');
1010
+        }
1011
+        foreach ($appData['remote'] as $name => $path) {
1012
+            \OC::$server->getConfig()->setAppValue('core', 'remote_' . $name, $appId . '/' . $path);
1013
+        }
1014
+        foreach ($appData['public'] as $name => $path) {
1015
+            \OC::$server->getConfig()->setAppValue('core', 'public_' . $name, $appId . '/' . $path);
1016
+        }
1017
+
1018
+        self::setAppTypes($appId);
1019
+
1020
+        $version = \OC_App::getAppVersion($appId);
1021
+        \OC::$server->getConfig()->setAppValue($appId, 'installed_version', $version);
1022
+
1023
+        \OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
1024
+            ManagerEvent::EVENT_APP_UPDATE, $appId
1025
+        ));
1026
+
1027
+        return true;
1028
+    }
1029
+
1030
+    /**
1031
+     * @param string $appId
1032
+     * @param string[] $steps
1033
+     * @throws \OC\NeedsUpdateException
1034
+     */
1035
+    public static function executeRepairSteps(string $appId, array $steps) {
1036
+        if (empty($steps)) {
1037
+            return;
1038
+        }
1039
+        // load the app
1040
+        self::loadApp($appId);
1041
+
1042
+        $dispatcher = OC::$server->getEventDispatcher();
1043
+
1044
+        // load the steps
1045
+        $r = new Repair([], $dispatcher, \OC::$server->get(LoggerInterface::class));
1046
+        foreach ($steps as $step) {
1047
+            try {
1048
+                $r->addStep($step);
1049
+            } catch (Exception $ex) {
1050
+                $r->emit('\OC\Repair', 'error', [$ex->getMessage()]);
1051
+                \OC::$server->getLogger()->logException($ex);
1052
+            }
1053
+        }
1054
+        // run the steps
1055
+        $r->run();
1056
+    }
1057
+
1058
+    public static function setupBackgroundJobs(array $jobs) {
1059
+        $queue = \OC::$server->getJobList();
1060
+        foreach ($jobs as $job) {
1061
+            $queue->add($job);
1062
+        }
1063
+    }
1064
+
1065
+    /**
1066
+     * @param string $appId
1067
+     * @param string[] $steps
1068
+     */
1069
+    private static function setupLiveMigrations(string $appId, array $steps) {
1070
+        $queue = \OC::$server->getJobList();
1071
+        foreach ($steps as $step) {
1072
+            $queue->add('OC\Migration\BackgroundRepair', [
1073
+                'app' => $appId,
1074
+                'step' => $step]);
1075
+        }
1076
+    }
1077
+
1078
+    /**
1079
+     * @param string $appId
1080
+     * @return \OC\Files\View|false
1081
+     */
1082
+    public static function getStorage(string $appId) {
1083
+        if (\OC::$server->getAppManager()->isEnabledForUser($appId)) { //sanity check
1084
+            if (\OC::$server->getUserSession()->isLoggedIn()) {
1085
+                $view = new \OC\Files\View('/' . OC_User::getUser());
1086
+                if (!$view->file_exists($appId)) {
1087
+                    $view->mkdir($appId);
1088
+                }
1089
+                return new \OC\Files\View('/' . OC_User::getUser() . '/' . $appId);
1090
+            } else {
1091
+                \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ', user not logged in', ILogger::ERROR);
1092
+                return false;
1093
+            }
1094
+        } else {
1095
+            \OCP\Util::writeLog('core', 'Can\'t get app storage, app ' . $appId . ' not enabled', ILogger::ERROR);
1096
+            return false;
1097
+        }
1098
+    }
1099
+
1100
+    protected static function findBestL10NOption(array $options, string $lang): string {
1101
+        // only a single option
1102
+        if (isset($options['@value'])) {
1103
+            return $options['@value'];
1104
+        }
1105
+
1106
+        $fallback = $similarLangFallback = $englishFallback = false;
1107
+
1108
+        $lang = strtolower($lang);
1109
+        $similarLang = $lang;
1110
+        if (strpos($similarLang, '_')) {
1111
+            // For "de_DE" we want to find "de" and the other way around
1112
+            $similarLang = substr($lang, 0, strpos($lang, '_'));
1113
+        }
1114
+
1115
+        foreach ($options as $option) {
1116
+            if (is_array($option)) {
1117
+                if ($fallback === false) {
1118
+                    $fallback = $option['@value'];
1119
+                }
1120
+
1121
+                if (!isset($option['@attributes']['lang'])) {
1122
+                    continue;
1123
+                }
1124
+
1125
+                $attributeLang = strtolower($option['@attributes']['lang']);
1126
+                if ($attributeLang === $lang) {
1127
+                    return $option['@value'];
1128
+                }
1129
+
1130
+                if ($attributeLang === $similarLang) {
1131
+                    $similarLangFallback = $option['@value'];
1132
+                } elseif (strpos($attributeLang, $similarLang . '_') === 0) {
1133
+                    if ($similarLangFallback === false) {
1134
+                        $similarLangFallback = $option['@value'];
1135
+                    }
1136
+                }
1137
+            } else {
1138
+                $englishFallback = $option;
1139
+            }
1140
+        }
1141
+
1142
+        if ($similarLangFallback !== false) {
1143
+            return $similarLangFallback;
1144
+        } elseif ($englishFallback !== false) {
1145
+            return $englishFallback;
1146
+        }
1147
+        return (string) $fallback;
1148
+    }
1149
+
1150
+    /**
1151
+     * parses the app data array and enhanced the 'description' value
1152
+     *
1153
+     * @param array $data the app data
1154
+     * @param string $lang
1155
+     * @return array improved app data
1156
+     */
1157
+    public static function parseAppInfo(array $data, $lang = null): array {
1158
+        if ($lang && isset($data['name']) && is_array($data['name'])) {
1159
+            $data['name'] = self::findBestL10NOption($data['name'], $lang);
1160
+        }
1161
+        if ($lang && isset($data['summary']) && is_array($data['summary'])) {
1162
+            $data['summary'] = self::findBestL10NOption($data['summary'], $lang);
1163
+        }
1164
+        if ($lang && isset($data['description']) && is_array($data['description'])) {
1165
+            $data['description'] = trim(self::findBestL10NOption($data['description'], $lang));
1166
+        } elseif (isset($data['description']) && is_string($data['description'])) {
1167
+            $data['description'] = trim($data['description']);
1168
+        } else {
1169
+            $data['description'] = '';
1170
+        }
1171
+
1172
+        return $data;
1173
+    }
1174
+
1175
+    /**
1176
+     * @param \OCP\IConfig $config
1177
+     * @param \OCP\IL10N $l
1178
+     * @param array $info
1179
+     * @throws \Exception
1180
+     */
1181
+    public static function checkAppDependencies(\OCP\IConfig $config, \OCP\IL10N $l, array $info, bool $ignoreMax) {
1182
+        $dependencyAnalyzer = new DependencyAnalyzer(new Platform($config), $l);
1183
+        $missing = $dependencyAnalyzer->analyze($info, $ignoreMax);
1184
+        if (!empty($missing)) {
1185
+            $missingMsg = implode(PHP_EOL, $missing);
1186
+            throw new \Exception(
1187
+                $l->t('App "%1$s" cannot be installed because the following dependencies are not fulfilled: %2$s',
1188
+                    [$info['name'], $missingMsg]
1189
+                )
1190
+            );
1191
+        }
1192
+    }
1193 1193
 }
Please login to merge, or discard this patch.
lib/private/Updater.php 1 patch
Indentation   +528 added lines, -528 removed lines patch added patch discarded remove patch
@@ -59,532 +59,532 @@
 block discarded – undo
59 59
  */
60 60
 class Updater extends BasicEmitter {
61 61
 
62
-	/** @var ILogger $log */
63
-	private $log;
64
-
65
-	/** @var IConfig */
66
-	private $config;
67
-
68
-	/** @var Checker */
69
-	private $checker;
70
-
71
-	/** @var Installer */
72
-	private $installer;
73
-
74
-	private $logLevelNames = [
75
-		0 => 'Debug',
76
-		1 => 'Info',
77
-		2 => 'Warning',
78
-		3 => 'Error',
79
-		4 => 'Fatal',
80
-	];
81
-
82
-	/**
83
-	 * @param IConfig $config
84
-	 * @param Checker $checker
85
-	 * @param ILogger $log
86
-	 * @param Installer $installer
87
-	 */
88
-	public function __construct(IConfig $config,
89
-								Checker $checker,
90
-								ILogger $log = null,
91
-								Installer $installer) {
92
-		$this->log = $log;
93
-		$this->config = $config;
94
-		$this->checker = $checker;
95
-		$this->installer = $installer;
96
-	}
97
-
98
-	/**
99
-	 * runs the update actions in maintenance mode, does not upgrade the source files
100
-	 * except the main .htaccess file
101
-	 *
102
-	 * @return bool true if the operation succeeded, false otherwise
103
-	 */
104
-	public function upgrade() {
105
-		$this->emitRepairEvents();
106
-		$this->logAllEvents();
107
-
108
-		$logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN);
109
-		$this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
110
-		$this->config->setSystemValue('loglevel', ILogger::DEBUG);
111
-
112
-		$wasMaintenanceModeEnabled = $this->config->getSystemValueBool('maintenance');
113
-
114
-		if (!$wasMaintenanceModeEnabled) {
115
-			$this->config->setSystemValue('maintenance', true);
116
-			$this->emit('\OC\Updater', 'maintenanceEnabled');
117
-		}
118
-
119
-		// Clear CAN_INSTALL file if not on git
120
-		if (\OC_Util::getChannel() !== 'git' && is_file(\OC::$configDir.'/CAN_INSTALL')) {
121
-			if (!unlink(\OC::$configDir . '/CAN_INSTALL')) {
122
-				$this->log->error('Could not cleanup CAN_INSTALL from your config folder. Please remove this file manually.');
123
-			}
124
-		}
125
-
126
-		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
127
-		$currentVersion = implode('.', \OCP\Util::getVersion());
128
-
129
-		$this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, ['app' => 'core']);
130
-
131
-		$success = true;
132
-		try {
133
-			$this->doUpgrade($currentVersion, $installedVersion);
134
-		} catch (HintException $exception) {
135
-			$this->log->logException($exception, ['app' => 'core']);
136
-			$this->emit('\OC\Updater', 'failure', [$exception->getMessage() . ': ' .$exception->getHint()]);
137
-			$success = false;
138
-		} catch (\Exception $exception) {
139
-			$this->log->logException($exception, ['app' => 'core']);
140
-			$this->emit('\OC\Updater', 'failure', [get_class($exception) . ': ' .$exception->getMessage()]);
141
-			$success = false;
142
-		}
143
-
144
-		$this->emit('\OC\Updater', 'updateEnd', [$success]);
145
-
146
-		if (!$wasMaintenanceModeEnabled && $success) {
147
-			$this->config->setSystemValue('maintenance', false);
148
-			$this->emit('\OC\Updater', 'maintenanceDisabled');
149
-		} else {
150
-			$this->emit('\OC\Updater', 'maintenanceActive');
151
-		}
152
-
153
-		$this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
154
-		$this->config->setSystemValue('loglevel', $logLevel);
155
-		$this->config->setSystemValue('installed', true);
156
-
157
-		return $success;
158
-	}
159
-
160
-	/**
161
-	 * Return version from which this version is allowed to upgrade from
162
-	 *
163
-	 * @return array allowed previous versions per vendor
164
-	 */
165
-	private function getAllowedPreviousVersions() {
166
-		// this should really be a JSON file
167
-		require \OC::$SERVERROOT . '/version.php';
168
-		/** @var array $OC_VersionCanBeUpgradedFrom */
169
-		return $OC_VersionCanBeUpgradedFrom;
170
-	}
171
-
172
-	/**
173
-	 * Return vendor from which this version was published
174
-	 *
175
-	 * @return string Get the vendor
176
-	 */
177
-	private function getVendor() {
178
-		// this should really be a JSON file
179
-		require \OC::$SERVERROOT . '/version.php';
180
-		/** @var string $vendor */
181
-		return (string) $vendor;
182
-	}
183
-
184
-	/**
185
-	 * Whether an upgrade to a specified version is possible
186
-	 * @param string $oldVersion
187
-	 * @param string $newVersion
188
-	 * @param array $allowedPreviousVersions
189
-	 * @return bool
190
-	 */
191
-	public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
192
-		$version = explode('.', $oldVersion);
193
-		$majorMinor = $version[0] . '.' . $version[1];
194
-
195
-		$currentVendor = $this->config->getAppValue('core', 'vendor', '');
196
-
197
-		// Vendor was not set correctly on install, so we have to white-list known versions
198
-		if ($currentVendor === '' && (
199
-			isset($allowedPreviousVersions['owncloud'][$oldVersion]) ||
200
-			isset($allowedPreviousVersions['owncloud'][$majorMinor])
201
-		)) {
202
-			$currentVendor = 'owncloud';
203
-			$this->config->setAppValue('core', 'vendor', $currentVendor);
204
-		}
205
-
206
-		if ($currentVendor === 'nextcloud') {
207
-			return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
208
-				&& (version_compare($oldVersion, $newVersion, '<=') ||
209
-					$this->config->getSystemValue('debug', false));
210
-		}
211
-
212
-		// Check if the instance can be migrated
213
-		return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) ||
214
-			isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
215
-	}
216
-
217
-	/**
218
-	 * runs the update actions in maintenance mode, does not upgrade the source files
219
-	 * except the main .htaccess file
220
-	 *
221
-	 * @param string $currentVersion current version to upgrade to
222
-	 * @param string $installedVersion previous version from which to upgrade from
223
-	 *
224
-	 * @throws \Exception
225
-	 */
226
-	private function doUpgrade($currentVersion, $installedVersion) {
227
-		// Stop update if the update is over several major versions
228
-		$allowedPreviousVersions = $this->getAllowedPreviousVersions();
229
-		if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
230
-			throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
231
-		}
232
-
233
-		// Update .htaccess files
234
-		try {
235
-			Setup::updateHtaccess();
236
-			Setup::protectDataDirectory();
237
-		} catch (\Exception $e) {
238
-			throw new \Exception($e->getMessage());
239
-		}
240
-
241
-		// create empty file in data dir, so we can later find
242
-		// out that this is indeed an ownCloud data directory
243
-		// (in case it didn't exist before)
244
-		file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
245
-
246
-		// pre-upgrade repairs
247
-		$repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher(), \OC::$server->get(LoggerInterface::class));
248
-		$repair->run();
249
-
250
-		$this->doCoreUpgrade();
251
-
252
-		try {
253
-			// TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
254
-			Setup::installBackgroundJobs();
255
-		} catch (\Exception $e) {
256
-			throw new \Exception($e->getMessage());
257
-		}
258
-
259
-		// update all shipped apps
260
-		$this->checkAppsRequirements();
261
-		$this->doAppUpgrade();
262
-
263
-		// Update the appfetchers version so it downloads the correct list from the appstore
264
-		\OC::$server->getAppFetcher()->setVersion($currentVersion);
265
-
266
-		// upgrade appstore apps
267
-		$this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps());
268
-		$autoDisabledApps = \OC::$server->getAppManager()->getAutoDisabledApps();
269
-		$this->upgradeAppStoreApps($autoDisabledApps, true);
270
-
271
-		// install new shipped apps on upgrade
272
-		$errors = Installer::installShippedApps(true);
273
-		foreach ($errors as $appId => $exception) {
274
-			/** @var \Exception $exception */
275
-			$this->log->logException($exception, ['app' => $appId]);
276
-			$this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
277
-		}
278
-
279
-		// post-upgrade repairs
280
-		$repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher(), \OC::$server->get(LoggerInterface::class));
281
-		$repair->run();
282
-
283
-		//Invalidate update feed
284
-		$this->config->setAppValue('core', 'lastupdatedat', 0);
285
-
286
-		// Check for code integrity if not disabled
287
-		if (\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
288
-			$this->emit('\OC\Updater', 'startCheckCodeIntegrity');
289
-			$this->checker->runInstanceVerification();
290
-			$this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
291
-		}
292
-
293
-		// only set the final version if everything went well
294
-		$this->config->setSystemValue('version', implode('.', Util::getVersion()));
295
-		$this->config->setAppValue('core', 'vendor', $this->getVendor());
296
-	}
297
-
298
-	protected function doCoreUpgrade() {
299
-		$this->emit('\OC\Updater', 'dbUpgradeBefore');
300
-
301
-		// execute core migrations
302
-		$ms = new MigrationService('core', \OC::$server->get(Connection::class));
303
-		$ms->migrate();
304
-
305
-		$this->emit('\OC\Updater', 'dbUpgrade');
306
-	}
307
-
308
-	/**
309
-	 * upgrades all apps within a major ownCloud upgrade. Also loads "priority"
310
-	 * (types authentication, filesystem, logging, in that order) afterwards.
311
-	 *
312
-	 * @throws NeedsUpdateException
313
-	 */
314
-	protected function doAppUpgrade() {
315
-		$apps = \OC_App::getEnabledApps();
316
-		$priorityTypes = ['authentication', 'filesystem', 'logging'];
317
-		$pseudoOtherType = 'other';
318
-		$stacks = [$pseudoOtherType => []];
319
-
320
-		foreach ($apps as $appId) {
321
-			$priorityType = false;
322
-			foreach ($priorityTypes as $type) {
323
-				if (!isset($stacks[$type])) {
324
-					$stacks[$type] = [];
325
-				}
326
-				if (\OC_App::isType($appId, [$type])) {
327
-					$stacks[$type][] = $appId;
328
-					$priorityType = true;
329
-					break;
330
-				}
331
-			}
332
-			if (!$priorityType) {
333
-				$stacks[$pseudoOtherType][] = $appId;
334
-			}
335
-		}
336
-		foreach (array_merge($priorityTypes, [$pseudoOtherType]) as $type) {
337
-			$stack = $stacks[$type];
338
-			foreach ($stack as $appId) {
339
-				if (\OC_App::shouldUpgrade($appId)) {
340
-					$this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]);
341
-					\OC_App::updateApp($appId);
342
-					$this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
343
-				}
344
-				if ($type !== $pseudoOtherType) {
345
-					// load authentication, filesystem and logging apps after
346
-					// upgrading them. Other apps my need to rely on modifying
347
-					// user and/or filesystem aspects.
348
-					\OC_App::loadApp($appId);
349
-				}
350
-			}
351
-		}
352
-	}
353
-
354
-	/**
355
-	 * check if the current enabled apps are compatible with the current
356
-	 * ownCloud version. disable them if not.
357
-	 * This is important if you upgrade ownCloud and have non ported 3rd
358
-	 * party apps installed.
359
-	 *
360
-	 * @return array
361
-	 * @throws \Exception
362
-	 */
363
-	private function checkAppsRequirements() {
364
-		$isCoreUpgrade = $this->isCodeUpgrade();
365
-		$apps = OC_App::getEnabledApps();
366
-		$version = implode('.', Util::getVersion());
367
-		$disabledApps = [];
368
-		$appManager = \OC::$server->getAppManager();
369
-		foreach ($apps as $app) {
370
-			// check if the app is compatible with this version of Nextcloud
371
-			$info = OC_App::getAppInfo($app);
372
-			if ($info === null || !OC_App::isAppCompatible($version, $info)) {
373
-				if ($appManager->isShipped($app)) {
374
-					throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
375
-				}
376
-				\OC::$server->getAppManager()->disableApp($app, true);
377
-				$this->emit('\OC\Updater', 'incompatibleAppDisabled', [$app]);
378
-			}
379
-			// no need to disable any app in case this is a non-core upgrade
380
-			if (!$isCoreUpgrade) {
381
-				continue;
382
-			}
383
-			// shipped apps will remain enabled
384
-			if ($appManager->isShipped($app)) {
385
-				continue;
386
-			}
387
-			// authentication and session apps will remain enabled as well
388
-			if (OC_App::isType($app, ['session', 'authentication'])) {
389
-				continue;
390
-			}
391
-		}
392
-		return $disabledApps;
393
-	}
394
-
395
-	/**
396
-	 * @return bool
397
-	 */
398
-	private function isCodeUpgrade() {
399
-		$installedVersion = $this->config->getSystemValue('version', '0.0.0');
400
-		$currentVersion = implode('.', Util::getVersion());
401
-		if (version_compare($currentVersion, $installedVersion, '>')) {
402
-			return true;
403
-		}
404
-		return false;
405
-	}
406
-
407
-	/**
408
-	 * @param array $disabledApps
409
-	 * @param bool $reenable
410
-	 * @throws \Exception
411
-	 */
412
-	private function upgradeAppStoreApps(array $disabledApps, $reenable = false) {
413
-		foreach ($disabledApps as $app) {
414
-			try {
415
-				$this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
416
-				if ($this->installer->isUpdateAvailable($app)) {
417
-					$this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
418
-					$this->installer->updateAppstoreApp($app);
419
-				}
420
-				$this->emit('\OC\Updater', 'checkAppStoreApp', [$app]);
421
-
422
-				if ($reenable) {
423
-					$ocApp = new \OC_App();
424
-					$ocApp->enable($app);
425
-				}
426
-			} catch (\Exception $ex) {
427
-				$this->log->logException($ex, ['app' => 'core']);
428
-			}
429
-		}
430
-	}
431
-
432
-	/**
433
-	 * Forward messages emitted by the repair routine
434
-	 */
435
-	private function emitRepairEvents() {
436
-		$dispatcher = \OC::$server->getEventDispatcher();
437
-		$dispatcher->addListener('\OC\Repair::warning', function ($event) {
438
-			if ($event instanceof GenericEvent) {
439
-				$this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
440
-			}
441
-		});
442
-		$dispatcher->addListener('\OC\Repair::error', function ($event) {
443
-			if ($event instanceof GenericEvent) {
444
-				$this->emit('\OC\Updater', 'repairError', $event->getArguments());
445
-			}
446
-		});
447
-		$dispatcher->addListener('\OC\Repair::info', function ($event) {
448
-			if ($event instanceof GenericEvent) {
449
-				$this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
450
-			}
451
-		});
452
-		$dispatcher->addListener('\OC\Repair::step', function ($event) {
453
-			if ($event instanceof GenericEvent) {
454
-				$this->emit('\OC\Updater', 'repairStep', $event->getArguments());
455
-			}
456
-		});
457
-	}
458
-
459
-	private function logAllEvents() {
460
-		$log = $this->log;
461
-
462
-		$dispatcher = \OC::$server->getEventDispatcher();
463
-		$dispatcher->addListener('\OC\DB\Migrator::executeSql', function ($event) use ($log) {
464
-			if (!$event instanceof GenericEvent) {
465
-				return;
466
-			}
467
-			$log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
468
-		});
469
-		$dispatcher->addListener('\OC\DB\Migrator::checkTable', function ($event) use ($log) {
470
-			if (!$event instanceof GenericEvent) {
471
-				return;
472
-			}
473
-			$log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
474
-		});
475
-
476
-		$repairListener = function ($event) use ($log) {
477
-			if (!$event instanceof GenericEvent) {
478
-				return;
479
-			}
480
-			switch ($event->getSubject()) {
481
-				case '\OC\Repair::startProgress':
482
-					$log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
483
-					break;
484
-				case '\OC\Repair::advance':
485
-					$desc = $event->getArgument(1);
486
-					if (empty($desc)) {
487
-						$desc = '';
488
-					}
489
-					$log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
490
-
491
-					break;
492
-				case '\OC\Repair::finishProgress':
493
-					$log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
494
-					break;
495
-				case '\OC\Repair::step':
496
-					$log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
497
-					break;
498
-				case '\OC\Repair::info':
499
-					$log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
500
-					break;
501
-				case '\OC\Repair::warning':
502
-					$log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
503
-					break;
504
-				case '\OC\Repair::error':
505
-					$log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
506
-					break;
507
-			}
508
-		};
509
-
510
-		$dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
511
-		$dispatcher->addListener('\OC\Repair::advance', $repairListener);
512
-		$dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
513
-		$dispatcher->addListener('\OC\Repair::step', $repairListener);
514
-		$dispatcher->addListener('\OC\Repair::info', $repairListener);
515
-		$dispatcher->addListener('\OC\Repair::warning', $repairListener);
516
-		$dispatcher->addListener('\OC\Repair::error', $repairListener);
517
-
518
-
519
-		$this->listen('\OC\Updater', 'maintenanceEnabled', function () use ($log) {
520
-			$log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
521
-		});
522
-		$this->listen('\OC\Updater', 'maintenanceDisabled', function () use ($log) {
523
-			$log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
524
-		});
525
-		$this->listen('\OC\Updater', 'maintenanceActive', function () use ($log) {
526
-			$log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
527
-		});
528
-		$this->listen('\OC\Updater', 'updateEnd', function ($success) use ($log) {
529
-			if ($success) {
530
-				$log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
531
-			} else {
532
-				$log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
533
-			}
534
-		});
535
-		$this->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($log) {
536
-			$log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
537
-		});
538
-		$this->listen('\OC\Updater', 'dbUpgrade', function () use ($log) {
539
-			$log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
540
-		});
541
-		$this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use ($log) {
542
-			$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']);
543
-		});
544
-		$this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use ($log) {
545
-			$log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
546
-		});
547
-		$this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($log) {
548
-			$log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
549
-		});
550
-		$this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($log) {
551
-			$log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
552
-		});
553
-		$this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($log) {
554
-			$log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
555
-		});
556
-		$this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($log) {
557
-			$log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
558
-		});
559
-		$this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
560
-			$log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
561
-		});
562
-		$this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
563
-			$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']);
564
-		});
565
-		$this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
566
-			$log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
567
-		});
568
-		$this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
569
-			$log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
570
-		});
571
-		$this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
572
-			$log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
573
-		});
574
-		$this->listen('\OC\Updater', 'failure', function ($message) use ($log) {
575
-			$log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
576
-		});
577
-		$this->listen('\OC\Updater', 'setDebugLogLevel', function () use ($log) {
578
-			$log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
579
-		});
580
-		$this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($log) {
581
-			$log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
582
-		});
583
-		$this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($log) {
584
-			$log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
585
-		});
586
-		$this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($log) {
587
-			$log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
588
-		});
589
-	}
62
+    /** @var ILogger $log */
63
+    private $log;
64
+
65
+    /** @var IConfig */
66
+    private $config;
67
+
68
+    /** @var Checker */
69
+    private $checker;
70
+
71
+    /** @var Installer */
72
+    private $installer;
73
+
74
+    private $logLevelNames = [
75
+        0 => 'Debug',
76
+        1 => 'Info',
77
+        2 => 'Warning',
78
+        3 => 'Error',
79
+        4 => 'Fatal',
80
+    ];
81
+
82
+    /**
83
+     * @param IConfig $config
84
+     * @param Checker $checker
85
+     * @param ILogger $log
86
+     * @param Installer $installer
87
+     */
88
+    public function __construct(IConfig $config,
89
+                                Checker $checker,
90
+                                ILogger $log = null,
91
+                                Installer $installer) {
92
+        $this->log = $log;
93
+        $this->config = $config;
94
+        $this->checker = $checker;
95
+        $this->installer = $installer;
96
+    }
97
+
98
+    /**
99
+     * runs the update actions in maintenance mode, does not upgrade the source files
100
+     * except the main .htaccess file
101
+     *
102
+     * @return bool true if the operation succeeded, false otherwise
103
+     */
104
+    public function upgrade() {
105
+        $this->emitRepairEvents();
106
+        $this->logAllEvents();
107
+
108
+        $logLevel = $this->config->getSystemValue('loglevel', ILogger::WARN);
109
+        $this->emit('\OC\Updater', 'setDebugLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
110
+        $this->config->setSystemValue('loglevel', ILogger::DEBUG);
111
+
112
+        $wasMaintenanceModeEnabled = $this->config->getSystemValueBool('maintenance');
113
+
114
+        if (!$wasMaintenanceModeEnabled) {
115
+            $this->config->setSystemValue('maintenance', true);
116
+            $this->emit('\OC\Updater', 'maintenanceEnabled');
117
+        }
118
+
119
+        // Clear CAN_INSTALL file if not on git
120
+        if (\OC_Util::getChannel() !== 'git' && is_file(\OC::$configDir.'/CAN_INSTALL')) {
121
+            if (!unlink(\OC::$configDir . '/CAN_INSTALL')) {
122
+                $this->log->error('Could not cleanup CAN_INSTALL from your config folder. Please remove this file manually.');
123
+            }
124
+        }
125
+
126
+        $installedVersion = $this->config->getSystemValue('version', '0.0.0');
127
+        $currentVersion = implode('.', \OCP\Util::getVersion());
128
+
129
+        $this->log->debug('starting upgrade from ' . $installedVersion . ' to ' . $currentVersion, ['app' => 'core']);
130
+
131
+        $success = true;
132
+        try {
133
+            $this->doUpgrade($currentVersion, $installedVersion);
134
+        } catch (HintException $exception) {
135
+            $this->log->logException($exception, ['app' => 'core']);
136
+            $this->emit('\OC\Updater', 'failure', [$exception->getMessage() . ': ' .$exception->getHint()]);
137
+            $success = false;
138
+        } catch (\Exception $exception) {
139
+            $this->log->logException($exception, ['app' => 'core']);
140
+            $this->emit('\OC\Updater', 'failure', [get_class($exception) . ': ' .$exception->getMessage()]);
141
+            $success = false;
142
+        }
143
+
144
+        $this->emit('\OC\Updater', 'updateEnd', [$success]);
145
+
146
+        if (!$wasMaintenanceModeEnabled && $success) {
147
+            $this->config->setSystemValue('maintenance', false);
148
+            $this->emit('\OC\Updater', 'maintenanceDisabled');
149
+        } else {
150
+            $this->emit('\OC\Updater', 'maintenanceActive');
151
+        }
152
+
153
+        $this->emit('\OC\Updater', 'resetLogLevel', [ $logLevel, $this->logLevelNames[$logLevel] ]);
154
+        $this->config->setSystemValue('loglevel', $logLevel);
155
+        $this->config->setSystemValue('installed', true);
156
+
157
+        return $success;
158
+    }
159
+
160
+    /**
161
+     * Return version from which this version is allowed to upgrade from
162
+     *
163
+     * @return array allowed previous versions per vendor
164
+     */
165
+    private function getAllowedPreviousVersions() {
166
+        // this should really be a JSON file
167
+        require \OC::$SERVERROOT . '/version.php';
168
+        /** @var array $OC_VersionCanBeUpgradedFrom */
169
+        return $OC_VersionCanBeUpgradedFrom;
170
+    }
171
+
172
+    /**
173
+     * Return vendor from which this version was published
174
+     *
175
+     * @return string Get the vendor
176
+     */
177
+    private function getVendor() {
178
+        // this should really be a JSON file
179
+        require \OC::$SERVERROOT . '/version.php';
180
+        /** @var string $vendor */
181
+        return (string) $vendor;
182
+    }
183
+
184
+    /**
185
+     * Whether an upgrade to a specified version is possible
186
+     * @param string $oldVersion
187
+     * @param string $newVersion
188
+     * @param array $allowedPreviousVersions
189
+     * @return bool
190
+     */
191
+    public function isUpgradePossible($oldVersion, $newVersion, array $allowedPreviousVersions) {
192
+        $version = explode('.', $oldVersion);
193
+        $majorMinor = $version[0] . '.' . $version[1];
194
+
195
+        $currentVendor = $this->config->getAppValue('core', 'vendor', '');
196
+
197
+        // Vendor was not set correctly on install, so we have to white-list known versions
198
+        if ($currentVendor === '' && (
199
+            isset($allowedPreviousVersions['owncloud'][$oldVersion]) ||
200
+            isset($allowedPreviousVersions['owncloud'][$majorMinor])
201
+        )) {
202
+            $currentVendor = 'owncloud';
203
+            $this->config->setAppValue('core', 'vendor', $currentVendor);
204
+        }
205
+
206
+        if ($currentVendor === 'nextcloud') {
207
+            return isset($allowedPreviousVersions[$currentVendor][$majorMinor])
208
+                && (version_compare($oldVersion, $newVersion, '<=') ||
209
+                    $this->config->getSystemValue('debug', false));
210
+        }
211
+
212
+        // Check if the instance can be migrated
213
+        return isset($allowedPreviousVersions[$currentVendor][$majorMinor]) ||
214
+            isset($allowedPreviousVersions[$currentVendor][$oldVersion]);
215
+    }
216
+
217
+    /**
218
+     * runs the update actions in maintenance mode, does not upgrade the source files
219
+     * except the main .htaccess file
220
+     *
221
+     * @param string $currentVersion current version to upgrade to
222
+     * @param string $installedVersion previous version from which to upgrade from
223
+     *
224
+     * @throws \Exception
225
+     */
226
+    private function doUpgrade($currentVersion, $installedVersion) {
227
+        // Stop update if the update is over several major versions
228
+        $allowedPreviousVersions = $this->getAllowedPreviousVersions();
229
+        if (!$this->isUpgradePossible($installedVersion, $currentVersion, $allowedPreviousVersions)) {
230
+            throw new \Exception('Updates between multiple major versions and downgrades are unsupported.');
231
+        }
232
+
233
+        // Update .htaccess files
234
+        try {
235
+            Setup::updateHtaccess();
236
+            Setup::protectDataDirectory();
237
+        } catch (\Exception $e) {
238
+            throw new \Exception($e->getMessage());
239
+        }
240
+
241
+        // create empty file in data dir, so we can later find
242
+        // out that this is indeed an ownCloud data directory
243
+        // (in case it didn't exist before)
244
+        file_put_contents($this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/.ocdata', '');
245
+
246
+        // pre-upgrade repairs
247
+        $repair = new Repair(Repair::getBeforeUpgradeRepairSteps(), \OC::$server->getEventDispatcher(), \OC::$server->get(LoggerInterface::class));
248
+        $repair->run();
249
+
250
+        $this->doCoreUpgrade();
251
+
252
+        try {
253
+            // TODO: replace with the new repair step mechanism https://github.com/owncloud/core/pull/24378
254
+            Setup::installBackgroundJobs();
255
+        } catch (\Exception $e) {
256
+            throw new \Exception($e->getMessage());
257
+        }
258
+
259
+        // update all shipped apps
260
+        $this->checkAppsRequirements();
261
+        $this->doAppUpgrade();
262
+
263
+        // Update the appfetchers version so it downloads the correct list from the appstore
264
+        \OC::$server->getAppFetcher()->setVersion($currentVersion);
265
+
266
+        // upgrade appstore apps
267
+        $this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps());
268
+        $autoDisabledApps = \OC::$server->getAppManager()->getAutoDisabledApps();
269
+        $this->upgradeAppStoreApps($autoDisabledApps, true);
270
+
271
+        // install new shipped apps on upgrade
272
+        $errors = Installer::installShippedApps(true);
273
+        foreach ($errors as $appId => $exception) {
274
+            /** @var \Exception $exception */
275
+            $this->log->logException($exception, ['app' => $appId]);
276
+            $this->emit('\OC\Updater', 'failure', [$appId . ': ' . $exception->getMessage()]);
277
+        }
278
+
279
+        // post-upgrade repairs
280
+        $repair = new Repair(Repair::getRepairSteps(), \OC::$server->getEventDispatcher(), \OC::$server->get(LoggerInterface::class));
281
+        $repair->run();
282
+
283
+        //Invalidate update feed
284
+        $this->config->setAppValue('core', 'lastupdatedat', 0);
285
+
286
+        // Check for code integrity if not disabled
287
+        if (\OC::$server->getIntegrityCodeChecker()->isCodeCheckEnforced()) {
288
+            $this->emit('\OC\Updater', 'startCheckCodeIntegrity');
289
+            $this->checker->runInstanceVerification();
290
+            $this->emit('\OC\Updater', 'finishedCheckCodeIntegrity');
291
+        }
292
+
293
+        // only set the final version if everything went well
294
+        $this->config->setSystemValue('version', implode('.', Util::getVersion()));
295
+        $this->config->setAppValue('core', 'vendor', $this->getVendor());
296
+    }
297
+
298
+    protected function doCoreUpgrade() {
299
+        $this->emit('\OC\Updater', 'dbUpgradeBefore');
300
+
301
+        // execute core migrations
302
+        $ms = new MigrationService('core', \OC::$server->get(Connection::class));
303
+        $ms->migrate();
304
+
305
+        $this->emit('\OC\Updater', 'dbUpgrade');
306
+    }
307
+
308
+    /**
309
+     * upgrades all apps within a major ownCloud upgrade. Also loads "priority"
310
+     * (types authentication, filesystem, logging, in that order) afterwards.
311
+     *
312
+     * @throws NeedsUpdateException
313
+     */
314
+    protected function doAppUpgrade() {
315
+        $apps = \OC_App::getEnabledApps();
316
+        $priorityTypes = ['authentication', 'filesystem', 'logging'];
317
+        $pseudoOtherType = 'other';
318
+        $stacks = [$pseudoOtherType => []];
319
+
320
+        foreach ($apps as $appId) {
321
+            $priorityType = false;
322
+            foreach ($priorityTypes as $type) {
323
+                if (!isset($stacks[$type])) {
324
+                    $stacks[$type] = [];
325
+                }
326
+                if (\OC_App::isType($appId, [$type])) {
327
+                    $stacks[$type][] = $appId;
328
+                    $priorityType = true;
329
+                    break;
330
+                }
331
+            }
332
+            if (!$priorityType) {
333
+                $stacks[$pseudoOtherType][] = $appId;
334
+            }
335
+        }
336
+        foreach (array_merge($priorityTypes, [$pseudoOtherType]) as $type) {
337
+            $stack = $stacks[$type];
338
+            foreach ($stack as $appId) {
339
+                if (\OC_App::shouldUpgrade($appId)) {
340
+                    $this->emit('\OC\Updater', 'appUpgradeStarted', [$appId, \OC_App::getAppVersion($appId)]);
341
+                    \OC_App::updateApp($appId);
342
+                    $this->emit('\OC\Updater', 'appUpgrade', [$appId, \OC_App::getAppVersion($appId)]);
343
+                }
344
+                if ($type !== $pseudoOtherType) {
345
+                    // load authentication, filesystem and logging apps after
346
+                    // upgrading them. Other apps my need to rely on modifying
347
+                    // user and/or filesystem aspects.
348
+                    \OC_App::loadApp($appId);
349
+                }
350
+            }
351
+        }
352
+    }
353
+
354
+    /**
355
+     * check if the current enabled apps are compatible with the current
356
+     * ownCloud version. disable them if not.
357
+     * This is important if you upgrade ownCloud and have non ported 3rd
358
+     * party apps installed.
359
+     *
360
+     * @return array
361
+     * @throws \Exception
362
+     */
363
+    private function checkAppsRequirements() {
364
+        $isCoreUpgrade = $this->isCodeUpgrade();
365
+        $apps = OC_App::getEnabledApps();
366
+        $version = implode('.', Util::getVersion());
367
+        $disabledApps = [];
368
+        $appManager = \OC::$server->getAppManager();
369
+        foreach ($apps as $app) {
370
+            // check if the app is compatible with this version of Nextcloud
371
+            $info = OC_App::getAppInfo($app);
372
+            if ($info === null || !OC_App::isAppCompatible($version, $info)) {
373
+                if ($appManager->isShipped($app)) {
374
+                    throw new \UnexpectedValueException('The files of the app "' . $app . '" were not correctly replaced before running the update');
375
+                }
376
+                \OC::$server->getAppManager()->disableApp($app, true);
377
+                $this->emit('\OC\Updater', 'incompatibleAppDisabled', [$app]);
378
+            }
379
+            // no need to disable any app in case this is a non-core upgrade
380
+            if (!$isCoreUpgrade) {
381
+                continue;
382
+            }
383
+            // shipped apps will remain enabled
384
+            if ($appManager->isShipped($app)) {
385
+                continue;
386
+            }
387
+            // authentication and session apps will remain enabled as well
388
+            if (OC_App::isType($app, ['session', 'authentication'])) {
389
+                continue;
390
+            }
391
+        }
392
+        return $disabledApps;
393
+    }
394
+
395
+    /**
396
+     * @return bool
397
+     */
398
+    private function isCodeUpgrade() {
399
+        $installedVersion = $this->config->getSystemValue('version', '0.0.0');
400
+        $currentVersion = implode('.', Util::getVersion());
401
+        if (version_compare($currentVersion, $installedVersion, '>')) {
402
+            return true;
403
+        }
404
+        return false;
405
+    }
406
+
407
+    /**
408
+     * @param array $disabledApps
409
+     * @param bool $reenable
410
+     * @throws \Exception
411
+     */
412
+    private function upgradeAppStoreApps(array $disabledApps, $reenable = false) {
413
+        foreach ($disabledApps as $app) {
414
+            try {
415
+                $this->emit('\OC\Updater', 'checkAppStoreAppBefore', [$app]);
416
+                if ($this->installer->isUpdateAvailable($app)) {
417
+                    $this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
418
+                    $this->installer->updateAppstoreApp($app);
419
+                }
420
+                $this->emit('\OC\Updater', 'checkAppStoreApp', [$app]);
421
+
422
+                if ($reenable) {
423
+                    $ocApp = new \OC_App();
424
+                    $ocApp->enable($app);
425
+                }
426
+            } catch (\Exception $ex) {
427
+                $this->log->logException($ex, ['app' => 'core']);
428
+            }
429
+        }
430
+    }
431
+
432
+    /**
433
+     * Forward messages emitted by the repair routine
434
+     */
435
+    private function emitRepairEvents() {
436
+        $dispatcher = \OC::$server->getEventDispatcher();
437
+        $dispatcher->addListener('\OC\Repair::warning', function ($event) {
438
+            if ($event instanceof GenericEvent) {
439
+                $this->emit('\OC\Updater', 'repairWarning', $event->getArguments());
440
+            }
441
+        });
442
+        $dispatcher->addListener('\OC\Repair::error', function ($event) {
443
+            if ($event instanceof GenericEvent) {
444
+                $this->emit('\OC\Updater', 'repairError', $event->getArguments());
445
+            }
446
+        });
447
+        $dispatcher->addListener('\OC\Repair::info', function ($event) {
448
+            if ($event instanceof GenericEvent) {
449
+                $this->emit('\OC\Updater', 'repairInfo', $event->getArguments());
450
+            }
451
+        });
452
+        $dispatcher->addListener('\OC\Repair::step', function ($event) {
453
+            if ($event instanceof GenericEvent) {
454
+                $this->emit('\OC\Updater', 'repairStep', $event->getArguments());
455
+            }
456
+        });
457
+    }
458
+
459
+    private function logAllEvents() {
460
+        $log = $this->log;
461
+
462
+        $dispatcher = \OC::$server->getEventDispatcher();
463
+        $dispatcher->addListener('\OC\DB\Migrator::executeSql', function ($event) use ($log) {
464
+            if (!$event instanceof GenericEvent) {
465
+                return;
466
+            }
467
+            $log->info('\OC\DB\Migrator::executeSql: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
468
+        });
469
+        $dispatcher->addListener('\OC\DB\Migrator::checkTable', function ($event) use ($log) {
470
+            if (!$event instanceof GenericEvent) {
471
+                return;
472
+            }
473
+            $log->info('\OC\DB\Migrator::checkTable: ' . $event->getSubject() . ' (' . $event->getArgument(0) . ' of ' . $event->getArgument(1) . ')', ['app' => 'updater']);
474
+        });
475
+
476
+        $repairListener = function ($event) use ($log) {
477
+            if (!$event instanceof GenericEvent) {
478
+                return;
479
+            }
480
+            switch ($event->getSubject()) {
481
+                case '\OC\Repair::startProgress':
482
+                    $log->info('\OC\Repair::startProgress: Starting ... ' . $event->getArgument(1) .  ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
483
+                    break;
484
+                case '\OC\Repair::advance':
485
+                    $desc = $event->getArgument(1);
486
+                    if (empty($desc)) {
487
+                        $desc = '';
488
+                    }
489
+                    $log->info('\OC\Repair::advance: ' . $desc . ' (' . $event->getArgument(0) . ')', ['app' => 'updater']);
490
+
491
+                    break;
492
+                case '\OC\Repair::finishProgress':
493
+                    $log->info('\OC\Repair::finishProgress', ['app' => 'updater']);
494
+                    break;
495
+                case '\OC\Repair::step':
496
+                    $log->info('\OC\Repair::step: Repair step: ' . $event->getArgument(0), ['app' => 'updater']);
497
+                    break;
498
+                case '\OC\Repair::info':
499
+                    $log->info('\OC\Repair::info: Repair info: ' . $event->getArgument(0), ['app' => 'updater']);
500
+                    break;
501
+                case '\OC\Repair::warning':
502
+                    $log->warning('\OC\Repair::warning: Repair warning: ' . $event->getArgument(0), ['app' => 'updater']);
503
+                    break;
504
+                case '\OC\Repair::error':
505
+                    $log->error('\OC\Repair::error: Repair error: ' . $event->getArgument(0), ['app' => 'updater']);
506
+                    break;
507
+            }
508
+        };
509
+
510
+        $dispatcher->addListener('\OC\Repair::startProgress', $repairListener);
511
+        $dispatcher->addListener('\OC\Repair::advance', $repairListener);
512
+        $dispatcher->addListener('\OC\Repair::finishProgress', $repairListener);
513
+        $dispatcher->addListener('\OC\Repair::step', $repairListener);
514
+        $dispatcher->addListener('\OC\Repair::info', $repairListener);
515
+        $dispatcher->addListener('\OC\Repair::warning', $repairListener);
516
+        $dispatcher->addListener('\OC\Repair::error', $repairListener);
517
+
518
+
519
+        $this->listen('\OC\Updater', 'maintenanceEnabled', function () use ($log) {
520
+            $log->info('\OC\Updater::maintenanceEnabled: Turned on maintenance mode', ['app' => 'updater']);
521
+        });
522
+        $this->listen('\OC\Updater', 'maintenanceDisabled', function () use ($log) {
523
+            $log->info('\OC\Updater::maintenanceDisabled: Turned off maintenance mode', ['app' => 'updater']);
524
+        });
525
+        $this->listen('\OC\Updater', 'maintenanceActive', function () use ($log) {
526
+            $log->info('\OC\Updater::maintenanceActive: Maintenance mode is kept active', ['app' => 'updater']);
527
+        });
528
+        $this->listen('\OC\Updater', 'updateEnd', function ($success) use ($log) {
529
+            if ($success) {
530
+                $log->info('\OC\Updater::updateEnd: Update successful', ['app' => 'updater']);
531
+            } else {
532
+                $log->error('\OC\Updater::updateEnd: Update failed', ['app' => 'updater']);
533
+            }
534
+        });
535
+        $this->listen('\OC\Updater', 'dbUpgradeBefore', function () use ($log) {
536
+            $log->info('\OC\Updater::dbUpgradeBefore: Updating database schema', ['app' => 'updater']);
537
+        });
538
+        $this->listen('\OC\Updater', 'dbUpgrade', function () use ($log) {
539
+            $log->info('\OC\Updater::dbUpgrade: Updated database', ['app' => 'updater']);
540
+        });
541
+        $this->listen('\OC\Updater', 'dbSimulateUpgradeBefore', function () use ($log) {
542
+            $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']);
543
+        });
544
+        $this->listen('\OC\Updater', 'dbSimulateUpgrade', function () use ($log) {
545
+            $log->info('\OC\Updater::dbSimulateUpgrade: Checked database schema update', ['app' => 'updater']);
546
+        });
547
+        $this->listen('\OC\Updater', 'incompatibleAppDisabled', function ($app) use ($log) {
548
+            $log->info('\OC\Updater::incompatibleAppDisabled: Disabled incompatible app: ' . $app, ['app' => 'updater']);
549
+        });
550
+        $this->listen('\OC\Updater', 'checkAppStoreAppBefore', function ($app) use ($log) {
551
+            $log->info('\OC\Updater::checkAppStoreAppBefore: Checking for update of app "' . $app . '" in appstore', ['app' => 'updater']);
552
+        });
553
+        $this->listen('\OC\Updater', 'upgradeAppStoreApp', function ($app) use ($log) {
554
+            $log->info('\OC\Updater::upgradeAppStoreApp: Update app "' . $app . '" from appstore', ['app' => 'updater']);
555
+        });
556
+        $this->listen('\OC\Updater', 'checkAppStoreApp', function ($app) use ($log) {
557
+            $log->info('\OC\Updater::checkAppStoreApp: Checked for update of app "' . $app . '" in appstore', ['app' => 'updater']);
558
+        });
559
+        $this->listen('\OC\Updater', 'appUpgradeCheckBefore', function () use ($log) {
560
+            $log->info('\OC\Updater::appUpgradeCheckBefore: Checking updates of apps', ['app' => 'updater']);
561
+        });
562
+        $this->listen('\OC\Updater', 'appSimulateUpdate', function ($app) use ($log) {
563
+            $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']);
564
+        });
565
+        $this->listen('\OC\Updater', 'appUpgradeCheck', function () use ($log) {
566
+            $log->info('\OC\Updater::appUpgradeCheck: Checked database schema update for apps', ['app' => 'updater']);
567
+        });
568
+        $this->listen('\OC\Updater', 'appUpgradeStarted', function ($app) use ($log) {
569
+            $log->info('\OC\Updater::appUpgradeStarted: Updating <' . $app . '> ...', ['app' => 'updater']);
570
+        });
571
+        $this->listen('\OC\Updater', 'appUpgrade', function ($app, $version) use ($log) {
572
+            $log->info('\OC\Updater::appUpgrade: Updated <' . $app . '> to ' . $version, ['app' => 'updater']);
573
+        });
574
+        $this->listen('\OC\Updater', 'failure', function ($message) use ($log) {
575
+            $log->error('\OC\Updater::failure: ' . $message, ['app' => 'updater']);
576
+        });
577
+        $this->listen('\OC\Updater', 'setDebugLogLevel', function () use ($log) {
578
+            $log->info('\OC\Updater::setDebugLogLevel: Set log level to debug', ['app' => 'updater']);
579
+        });
580
+        $this->listen('\OC\Updater', 'resetLogLevel', function ($logLevel, $logLevelName) use ($log) {
581
+            $log->info('\OC\Updater::resetLogLevel: Reset log level to ' . $logLevelName . '(' . $logLevel . ')', ['app' => 'updater']);
582
+        });
583
+        $this->listen('\OC\Updater', 'startCheckCodeIntegrity', function () use ($log) {
584
+            $log->info('\OC\Updater::startCheckCodeIntegrity: Starting code integrity check...', ['app' => 'updater']);
585
+        });
586
+        $this->listen('\OC\Updater', 'finishedCheckCodeIntegrity', function () use ($log) {
587
+            $log->info('\OC\Updater::finishedCheckCodeIntegrity: Finished code integrity check', ['app' => 'updater']);
588
+        });
589
+    }
590 590
 }
Please login to merge, or discard this patch.
lib/private/Migration/BackgroundRepair.php 1 patch
Indentation   +78 added lines, -78 removed lines patch added patch discarded remove patch
@@ -43,82 +43,82 @@
 block discarded – undo
43 43
  */
44 44
 class BackgroundRepair extends TimedJob {
45 45
 
46
-	/** @var IJobList */
47
-	private $jobList;
48
-
49
-	/** @var ILogger */
50
-	private $logger;
51
-
52
-	/** @var EventDispatcherInterface */
53
-	private $dispatcher;
54
-
55
-	public function __construct(EventDispatcherInterface $dispatcher) {
56
-		$this->dispatcher = $dispatcher;
57
-	}
58
-
59
-	/**
60
-	 * run the job, then remove it from the job list
61
-	 *
62
-	 * @param JobList $jobList
63
-	 * @param ILogger|null $logger
64
-	 */
65
-	public function execute($jobList, ILogger $logger = null) {
66
-		// add an interval of 15 mins
67
-		$this->setInterval(15 * 60);
68
-
69
-		$this->jobList = $jobList;
70
-		$this->logger = $logger;
71
-		parent::execute($jobList, $logger);
72
-	}
73
-
74
-	/**
75
-	 * @param array $argument
76
-	 * @throws \Exception
77
-	 * @throws \OC\NeedsUpdateException
78
-	 */
79
-	protected function run($argument) {
80
-		if (!isset($argument['app']) || !isset($argument['step'])) {
81
-			// remove the job - we can never execute it
82
-			$this->jobList->remove($this, $this->argument);
83
-			return;
84
-		}
85
-		$app = $argument['app'];
86
-
87
-		try {
88
-			$this->loadApp($app);
89
-		} catch (NeedsUpdateException $ex) {
90
-			// as long as the app is not yet done with it's offline migration
91
-			// we better not start with the live migration
92
-			return;
93
-		}
94
-
95
-		$step = $argument['step'];
96
-		$repair = new Repair([], $this->dispatcher, \OC::$server->get(LoggerInterface::class));
97
-		try {
98
-			$repair->addStep($step);
99
-		} catch (\Exception $ex) {
100
-			$this->logger->logException($ex,[
101
-				'app' => 'migration'
102
-			]);
103
-
104
-			// remove the job - we can never execute it
105
-			$this->jobList->remove($this, $this->argument);
106
-			return;
107
-		}
108
-
109
-		// execute the repair step
110
-		$repair->run();
111
-
112
-		// remove the job once executed successfully
113
-		$this->jobList->remove($this, $this->argument);
114
-	}
115
-
116
-	/**
117
-	 * @codeCoverageIgnore
118
-	 * @param $app
119
-	 * @throws NeedsUpdateException
120
-	 */
121
-	protected function loadApp($app) {
122
-		OC_App::loadApp($app);
123
-	}
46
+    /** @var IJobList */
47
+    private $jobList;
48
+
49
+    /** @var ILogger */
50
+    private $logger;
51
+
52
+    /** @var EventDispatcherInterface */
53
+    private $dispatcher;
54
+
55
+    public function __construct(EventDispatcherInterface $dispatcher) {
56
+        $this->dispatcher = $dispatcher;
57
+    }
58
+
59
+    /**
60
+     * run the job, then remove it from the job list
61
+     *
62
+     * @param JobList $jobList
63
+     * @param ILogger|null $logger
64
+     */
65
+    public function execute($jobList, ILogger $logger = null) {
66
+        // add an interval of 15 mins
67
+        $this->setInterval(15 * 60);
68
+
69
+        $this->jobList = $jobList;
70
+        $this->logger = $logger;
71
+        parent::execute($jobList, $logger);
72
+    }
73
+
74
+    /**
75
+     * @param array $argument
76
+     * @throws \Exception
77
+     * @throws \OC\NeedsUpdateException
78
+     */
79
+    protected function run($argument) {
80
+        if (!isset($argument['app']) || !isset($argument['step'])) {
81
+            // remove the job - we can never execute it
82
+            $this->jobList->remove($this, $this->argument);
83
+            return;
84
+        }
85
+        $app = $argument['app'];
86
+
87
+        try {
88
+            $this->loadApp($app);
89
+        } catch (NeedsUpdateException $ex) {
90
+            // as long as the app is not yet done with it's offline migration
91
+            // we better not start with the live migration
92
+            return;
93
+        }
94
+
95
+        $step = $argument['step'];
96
+        $repair = new Repair([], $this->dispatcher, \OC::$server->get(LoggerInterface::class));
97
+        try {
98
+            $repair->addStep($step);
99
+        } catch (\Exception $ex) {
100
+            $this->logger->logException($ex,[
101
+                'app' => 'migration'
102
+            ]);
103
+
104
+            // remove the job - we can never execute it
105
+            $this->jobList->remove($this, $this->argument);
106
+            return;
107
+        }
108
+
109
+        // execute the repair step
110
+        $repair->run();
111
+
112
+        // remove the job once executed successfully
113
+        $this->jobList->remove($this, $this->argument);
114
+    }
115
+
116
+    /**
117
+     * @codeCoverageIgnore
118
+     * @param $app
119
+     * @throws NeedsUpdateException
120
+     */
121
+    protected function loadApp($app) {
122
+        OC_App::loadApp($app);
123
+    }
124 124
 }
Please login to merge, or discard this patch.