]> source.dussan.org Git - nextcloud-server.git/commitdiff
check registered sections and settings after an app got updated to garbage collect...
authorArthur Schiwon <blizzz@arthur-schiwon.de>
Mon, 15 Aug 2016 22:52:41 +0000 (00:52 +0200)
committerLukas Reschke <lukas@statuscode.ch>
Tue, 16 Aug 2016 19:10:57 +0000 (21:10 +0200)
lib/base.php
lib/private/Settings/Manager.php
lib/private/Settings/RemoveOrphaned.php [new file with mode: 0644]
lib/private/legacy/app.php
lib/public/App/ManagerEvent.php
lib/public/Settings/IManager.php

index 1b53282fb9115e09c9f5a31bf5c0ec52f2ce5c1d..99ba21f86aa6bc4f701142381bc1e0b96dbb3cf2 100644 (file)
@@ -808,6 +808,14 @@ class OC {
                        /** @var \OCP\App\ManagerEvent $event */
                        \OC::$server->getSettingsManager()->onAppDisabled($event->getAppID());
                });
+               $dispatcher->addListener(OCP\App\ManagerEvent::EVENT_APP_UPDATE, function($event) {
+                       /** @var \OCP\App\ManagerEvent $event */
+                       $jobList = \OC::$server->getJobList();
+                       $job = 'OC\\Settings\\RemoveOrphaned';
+                       if(!($jobList->has($job, null))) {
+                               $jobList->add($job);
+                       }
+               });
        }
 
        private static function registerEncryptionWrapper() {
index 8fdc7fefbb3acc63e4aa3cb63de047990c788203..7574695d709fded3f81c0871cb3f5063010bb195 100644 (file)
@@ -112,6 +112,37 @@ class Manager implements IManager {
                }
        }
 
+       public function checkForOrphanedClassNames() {
+               $tables = [ self::TABLE_ADMIN_SECTIONS, self::TABLE_ADMIN_SETTINGS ];
+               foreach ($tables as $table) {
+                       $classes = $this->getClasses($table);
+                       foreach($classes as $className) {
+                               try {
+                                       \OC::$server->query($className);
+                               } catch (QueryException $e) {
+                                       $this->remove($table, $className);
+                               }
+                       }
+               }
+       }
+
+       /**
+        * returns the registerd classes in the given table
+        *
+        * @param $table
+        * @return string[]
+        */
+       private function getClasses($table) {
+               $q = $this->dbc->getQueryBuilder();
+               $resultStatement = $q->select('class')
+                       ->from($table)
+                       ->execute();
+               $data = $resultStatement->fetchAll();
+               $resultStatement->closeCursor();
+
+               return array_map(function($row) { return $row['class']; }, $data);
+       }
+
        /**
         * @param string $sectionClassName
         */
diff --git a/lib/private/Settings/RemoveOrphaned.php b/lib/private/Settings/RemoveOrphaned.php
new file mode 100644 (file)
index 0000000..fbee95c
--- /dev/null
@@ -0,0 +1,91 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016 Arthur Schiwon <blizzz@arthur-schiwon.de>
+ *
+ * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\Settings;
+
+use OC\BackgroundJob\JobList;
+use OC\BackgroundJob\TimedJob;
+use OC\NeedsUpdateException;
+use OCP\BackgroundJob\IJobList;
+use OCP\ILogger;
+
+/**
+ * Class RemoveOrphaned
+ *
+ * @package OC\Settings
+ */
+class RemoveOrphaned extends TimedJob {
+
+       /** @var IJobList */
+       private $jobList;
+
+       /** @var ILogger */
+       private $logger;
+
+       /** @var Manager */
+       private $manager;
+
+       public function __construct(Manager $manager = null) {
+               if($manager !== null) {
+                       $this->manager = $manager;
+               } else {
+                       // fix DI for Jobs
+                       $this->manager = \OC::$server->getSettingsManager();
+               }
+       }
+
+       /**
+        * run the job, then remove it from the job list
+        *
+        * @param JobList $jobList
+        * @param ILogger $logger
+        */
+       public function execute($jobList, ILogger $logger = null) {
+               // add an interval of 15 mins
+               $this->setInterval(15*60);
+
+               $this->jobList = $jobList;
+               $this->logger = $logger;
+               parent::execute($jobList, $logger);
+       }
+
+       /**
+        * @param array $argument
+        * @throws \Exception
+        * @throws \OC\NeedsUpdateException
+        */
+       protected function run($argument) {
+               try {
+                       \OC_App::loadApps();
+               } catch (NeedsUpdateException $ex) {
+                       // only run when apps are up to date
+                       return;
+               }
+
+               $this->manager->checkForOrphanedClassNames();
+
+               // remove the job once executed successfully
+               $this->jobList->remove($this);
+       }
+
+}
index b39f5fa789049d0749e8bd24272684da782fbd30..ac0bcf11f364f1079f465d1b922e2729539c0351 100644 (file)
@@ -51,6 +51,7 @@ use OC\App\Platform;
 use OC\Installer;
 use OC\OCSClient;
 use OC\Repair;
+use OCP\App\ManagerEvent;
 
 /**
  * This class manages the apps. It allows them to register and integrate in the
@@ -1237,6 +1238,10 @@ class OC_App {
                $version = \OC_App::getAppVersion($appId);
                \OC::$server->getAppConfig()->setValue($appId, 'installed_version', $version);
 
+               \OC::$server->getEventDispatcher()->dispatch(ManagerEvent::EVENT_APP_UPDATE, new ManagerEvent(
+                       ManagerEvent::EVENT_APP_UPDATE, $appId
+               ));
+
                return true;
        }
 
index a70345b62fd15eda5df4689d4e58acc295429ed1..b25ea55aee6f4e3225e151e56d37807a6dcd4698 100644 (file)
@@ -36,6 +36,11 @@ class ManagerEvent extends Event {
        const EVENT_APP_ENABLE_FOR_GROUPS = 'OCP\App\IAppManager::enableAppForGroups';
        const EVENT_APP_DISABLE = 'OCP\App\IAppManager::disableApp';
 
+       /**
+        * @since 9.1.0
+        */
+       const EVENT_APP_UPDATE = 'OCP\App\IAppManager::updateApp';
+
        /** @var string */
        protected $event;
        /** @var string */
index cba4efbd0370955e2b8a46f59c30a138cd98ca23..a406915ad0900db490654995a346e0bcb75f16f1 100644 (file)
@@ -64,6 +64,21 @@ interface IManager {
         */
        public function onAppDisabled($appId);
 
+       /**
+        * The method should check all registered classes whether they are still
+        * instantiable and remove them, if not. This method is called by a
+        * background job once, after one or more apps were updated.
+        *
+        * An app`s info.xml can change during an update and make it unknown whether
+        * a registered class name was changed or not. An old one would just stay
+        * registered. Another case is if an admin takes a radical approach and
+        * simply removes an app from the app folder. These unregular checks will
+        * take care of such situations.
+        *
+        * @since 9.1.0
+        */
+       public function checkForOrphanedClassNames();
+
        /**
         * returns a list of the admin sections
         *