diff --git a/lib/base.php b/lib/base.php
index 1db6b84c5fb05..3ca4775dbe2aa 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -935,14 +935,15 @@ public static function handleRequest() {
// emergency app disabling
if ($requestPath === '/disableapp'
&& $request->getMethod() === 'POST'
- && ((string)$request->getParam('appid')) !== ''
+ && ((array)$request->getParam('appid')) !== ''
) {
\OCP\JSON::callCheck();
\OCP\JSON::checkAdminUser();
- $appId = (string)$request->getParam('appid');
- $appId = \OC_App::cleanAppId($appId);
-
- \OC_App::disable($appId);
+ $appIds = (array)$request->getParam('appid');
+ foreach($appIds as $appId) {
+ $appId = \OC_App::cleanAppId($appId);
+ \OC_App::disable($appId);
+ }
\OC_JSON::success();
exit();
}
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 9dea4d10fb225..23aff9df87083 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -318,6 +318,12 @@
'OC\\AppFramework\\Utility\\TimeFactory' => $baseDir . '/lib/private/AppFramework/Utility/TimeFactory.php',
'OC\\AppHelper' => $baseDir . '/lib/private/AppHelper.php',
'OC\\App\\AppManager' => $baseDir . '/lib/private/App/AppManager.php',
+ 'OC\\App\\AppStore\\Bundles\\Bundle' => $baseDir . '/lib/private/App/AppStore/Bundles/Bundle.php',
+ 'OC\\App\\AppStore\\Bundles\\BundleFetcher' => $baseDir . '/lib/private/App/AppStore/Bundles/BundleFetcher.php',
+ 'OC\\App\\AppStore\\Bundles\\CoreBundle' => $baseDir . '/lib/private/App/AppStore/Bundles/CoreBundle.php',
+ 'OC\\App\\AppStore\\Bundles\\EnterpriseBundle' => $baseDir . '/lib/private/App/AppStore/Bundles/EnterpriseBundle.php',
+ 'OC\\App\\AppStore\\Bundles\\GroupwareBundle' => $baseDir . '/lib/private/App/AppStore/Bundles/GroupwareBundle.php',
+ 'OC\\App\\AppStore\\Bundles\\SocialSharingBundle' => $baseDir . '/lib/private/App/AppStore/Bundles/SocialSharingBundle.php',
'OC\\App\\AppStore\\Fetcher\\AppFetcher' => $baseDir . '/lib/private/App/AppStore/Fetcher/AppFetcher.php',
'OC\\App\\AppStore\\Fetcher\\CategoryFetcher' => $baseDir . '/lib/private/App/AppStore/Fetcher/CategoryFetcher.php',
'OC\\App\\AppStore\\Fetcher\\Fetcher' => $baseDir . '/lib/private/App/AppStore/Fetcher/Fetcher.php',
@@ -727,6 +733,7 @@
'OC\\Repair\\NC11\\FixMountStorages' => $baseDir . '/lib/private/Repair/NC11/FixMountStorages.php',
'OC\\Repair\\NC11\\MoveAvatars' => $baseDir . '/lib/private/Repair/NC11/MoveAvatars.php',
'OC\\Repair\\NC11\\MoveAvatarsBackgroundJob' => $baseDir . '/lib/private/Repair/NC11/MoveAvatarsBackgroundJob.php',
+ 'OC\\Repair\\NC12\\InstallCoreBundle' => $baseDir . '/lib/private/Repair/NC12/InstallCoreBundle.php',
'OC\\Repair\\NC12\\UpdateLanguageCodes' => $baseDir . '/lib/private/Repair/NC12/UpdateLanguageCodes.php',
'OC\\Repair\\OldGroupMembershipShares' => $baseDir . '/lib/private/Repair/OldGroupMembershipShares.php',
'OC\\Repair\\RemoveRootShares' => $baseDir . '/lib/private/Repair/RemoveRootShares.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 11d949de34a1e..709d59ff3d081 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -348,6 +348,12 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\AppFramework\\Utility\\TimeFactory' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Utility/TimeFactory.php',
'OC\\AppHelper' => __DIR__ . '/../../..' . '/lib/private/AppHelper.php',
'OC\\App\\AppManager' => __DIR__ . '/../../..' . '/lib/private/App/AppManager.php',
+ 'OC\\App\\AppStore\\Bundles\\Bundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/Bundle.php',
+ 'OC\\App\\AppStore\\Bundles\\BundleFetcher' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/BundleFetcher.php',
+ 'OC\\App\\AppStore\\Bundles\\CoreBundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/CoreBundle.php',
+ 'OC\\App\\AppStore\\Bundles\\EnterpriseBundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/EnterpriseBundle.php',
+ 'OC\\App\\AppStore\\Bundles\\GroupwareBundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/GroupwareBundle.php',
+ 'OC\\App\\AppStore\\Bundles\\SocialSharingBundle' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Bundles/SocialSharingBundle.php',
'OC\\App\\AppStore\\Fetcher\\AppFetcher' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Fetcher/AppFetcher.php',
'OC\\App\\AppStore\\Fetcher\\CategoryFetcher' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Fetcher/CategoryFetcher.php',
'OC\\App\\AppStore\\Fetcher\\Fetcher' => __DIR__ . '/../../..' . '/lib/private/App/AppStore/Fetcher/Fetcher.php',
@@ -757,6 +763,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Repair\\NC11\\FixMountStorages' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/FixMountStorages.php',
'OC\\Repair\\NC11\\MoveAvatars' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/MoveAvatars.php',
'OC\\Repair\\NC11\\MoveAvatarsBackgroundJob' => __DIR__ . '/../../..' . '/lib/private/Repair/NC11/MoveAvatarsBackgroundJob.php',
+ 'OC\\Repair\\NC12\\InstallCoreBundle' => __DIR__ . '/../../..' . '/lib/private/Repair/NC12/InstallCoreBundle.php',
'OC\\Repair\\NC12\\UpdateLanguageCodes' => __DIR__ . '/../../..' . '/lib/private/Repair/NC12/UpdateLanguageCodes.php',
'OC\\Repair\\OldGroupMembershipShares' => __DIR__ . '/../../..' . '/lib/private/Repair/OldGroupMembershipShares.php',
'OC\\Repair\\RemoveRootShares' => __DIR__ . '/../../..' . '/lib/private/Repair/RemoveRootShares.php',
diff --git a/lib/private/App/AppStore/Bundles/Bundle.php b/lib/private/App/AppStore/Bundles/Bundle.php
new file mode 100644
index 0000000000000..47efc4e0cce41
--- /dev/null
+++ b/lib/private/App/AppStore/Bundles/Bundle.php
@@ -0,0 +1,59 @@
+
+ *
+ * @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 .
+ *
+ */
+
+namespace OC\App\AppStore\Bundles;
+
+use OCP\IL10N;
+
+abstract class Bundle {
+ /** @var IL10N */
+ protected $l10n;
+
+ /**
+ * @param IL10N $l10n
+ */
+ public function __construct(IL10N $l10n) {
+ $this->l10n = $l10n;
+ }
+
+ /**
+ * Get the identifier of the bundle
+ *
+ * @return string
+ */
+ public final function getIdentifier() {
+ return substr(strrchr(get_class($this), '\\'), 1);
+ }
+
+ /**
+ * Get the name of the bundle
+ *
+ * @return string
+ */
+ public abstract function getName();
+
+ /**
+ * Get the list of app identifiers in the bundle
+ *
+ * @return array
+ */
+ public abstract function getAppIdentifiers();
+}
diff --git a/lib/private/App/AppStore/Bundles/BundleFetcher.php b/lib/private/App/AppStore/Bundles/BundleFetcher.php
new file mode 100644
index 0000000000000..01cd4d6a5182c
--- /dev/null
+++ b/lib/private/App/AppStore/Bundles/BundleFetcher.php
@@ -0,0 +1,80 @@
+
+ *
+ * @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 .
+ *
+ */
+
+namespace OC\App\AppStore\Bundles;
+
+use OCP\IL10N;
+
+class BundleFetcher {
+ /** @var IL10N */
+ private $l10n;
+
+ /**
+ * @param IL10N $l10n
+ */
+ public function __construct(IL10N $l10n) {
+ $this->l10n = $l10n;
+ }
+
+ /**
+ * @return Bundle[]
+ */
+ public function getBundles() {
+ return [
+ new EnterpriseBundle($this->l10n),
+ new GroupwareBundle($this->l10n),
+ new SocialSharingBundle($this->l10n),
+ ];
+ }
+
+ /**
+ * Bundles that should be installed by default after installation
+ *
+ * @return Bundle[]
+ */
+ public function getDefaultInstallationBundle() {
+ return [
+ new CoreBundle($this->l10n),
+ ];
+ }
+
+ /**
+ * Get the bundle with the specified identifier
+ *
+ * @param string $identifier
+ * @return Bundle
+ * @throws \BadMethodCallException If the bundle does not exist
+ */
+ public function getBundleByIdentifier($identifier) {
+ /** @var Bundle[] $bundles */
+ $bundles = array_merge(
+ $this->getBundles(),
+ $this->getDefaultInstallationBundle()
+ );
+ foreach($bundles as $bundle) {
+ if($bundle->getIdentifier() === $identifier) {
+ return $bundle;
+ }
+ }
+
+ throw new \BadMethodCallException('Bundle with specified identifier does not exist');
+ }
+}
diff --git a/lib/private/App/AppStore/Bundles/CoreBundle.php b/lib/private/App/AppStore/Bundles/CoreBundle.php
new file mode 100644
index 0000000000000..a87292b9ec948
--- /dev/null
+++ b/lib/private/App/AppStore/Bundles/CoreBundle.php
@@ -0,0 +1,42 @@
+
+ *
+ * @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 .
+ *
+ */
+
+namespace OC\App\AppStore\Bundles;
+
+class CoreBundle extends Bundle {
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getName() {
+ return 'Core bundle';
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getAppIdentifiers() {
+ return [
+ 'bruteforcesettings',
+ ];
+ }
+
+}
diff --git a/lib/private/App/AppStore/Bundles/EnterpriseBundle.php b/lib/private/App/AppStore/Bundles/EnterpriseBundle.php
new file mode 100644
index 0000000000000..6d43a6210fa76
--- /dev/null
+++ b/lib/private/App/AppStore/Bundles/EnterpriseBundle.php
@@ -0,0 +1,47 @@
+
+ *
+ * @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 .
+ *
+ */
+
+namespace OC\App\AppStore\Bundles;
+
+class EnterpriseBundle extends Bundle {
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getName() {
+ return (string)$this->l10n->t('Enterprise bundle');
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getAppIdentifiers() {
+ return [
+ 'admin_audit',
+ 'user_ldap',
+ 'files_retention',
+ 'files_automatedtagging',
+ 'user_saml',
+ 'files_accesscontrol',
+ ];
+ }
+
+}
diff --git a/lib/private/App/AppStore/Bundles/GroupwareBundle.php b/lib/private/App/AppStore/Bundles/GroupwareBundle.php
new file mode 100644
index 0000000000000..7e7414f69c7c5
--- /dev/null
+++ b/lib/private/App/AppStore/Bundles/GroupwareBundle.php
@@ -0,0 +1,44 @@
+
+ *
+ * @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 .
+ *
+ */
+
+namespace OC\App\AppStore\Bundles;
+
+class GroupwareBundle extends Bundle {
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getName() {
+ return (string)$this->l10n->t('Groupware bundle');
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getAppIdentifiers() {
+ return [
+ 'calendar',
+ 'contacts',
+ 'spreed',
+ ];
+ }
+
+}
diff --git a/lib/private/App/AppStore/Bundles/SocialSharingBundle.php b/lib/private/App/AppStore/Bundles/SocialSharingBundle.php
new file mode 100644
index 0000000000000..8da84e8d1ef65
--- /dev/null
+++ b/lib/private/App/AppStore/Bundles/SocialSharingBundle.php
@@ -0,0 +1,46 @@
+
+ *
+ * @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 .
+ *
+ */
+
+namespace OC\App\AppStore\Bundles;
+
+class SocialSharingBundle extends Bundle {
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getName() {
+ return (string)$this->l10n->t('Social sharing bundle');
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function getAppIdentifiers() {
+ return [
+ 'socialsharing_twitter',
+ 'socialsharing_googleplus',
+ 'socialsharing_facebook',
+ 'socialsharing_email',
+ 'socialsharing_diaspora',
+ ];
+ }
+
+}
diff --git a/lib/private/Installer.php b/lib/private/Installer.php
index 0d6030d574461..8702f264e5449 100644
--- a/lib/private/Installer.php
+++ b/lib/private/Installer.php
@@ -42,6 +42,8 @@
namespace OC;
use Doctrine\DBAL\Exception\TableExistsException;
+use OC\App\AppManager;
+use OC\App\AppStore\Bundles\Bundle;
use OC\App\AppStore\Fetcher\AppFetcher;
use OC\App\CodeChecker\CodeChecker;
use OC\App\CodeChecker\EmptyCheck;
@@ -50,7 +52,9 @@
use OC_App;
use OC_DB;
use OC_Helper;
+use OCP\App\IAppManager;
use OCP\Http\Client\IClientService;
+use OCP\IConfig;
use OCP\ILogger;
use OCP\ITempManager;
use phpseclib\File\X509;
@@ -67,21 +71,26 @@ class Installer {
private $tempManager;
/** @var ILogger */
private $logger;
+ /** @var IConfig */
+ private $config;
/**
* @param AppFetcher $appFetcher
* @param IClientService $clientService
* @param ITempManager $tempManager
* @param ILogger $logger
+ * @param IConfig $config
*/
public function __construct(AppFetcher $appFetcher,
IClientService $clientService,
ITempManager $tempManager,
- ILogger $logger) {
+ ILogger $logger,
+ IConfig $config) {
$this->appFetcher = $appFetcher;
$this->clientService = $clientService;
$this->tempManager = $tempManager;
$this->logger = $logger;
+ $this->config = $config;
}
/**
@@ -109,6 +118,7 @@ public function installApp($appId) {
}
}
+ \OC_App::registerAutoloading($appId, $basedir);
\OC_App::setupBackgroundJobs($info['background-jobs']);
//run appinfo/install.php
@@ -419,6 +429,27 @@ public function removeApp($appId) {
}
+ /**
+ * Installs the app within the bundle and marks the bundle as installed
+ *
+ * @param Bundle $bundle
+ * @throws \Exception If app could not get installed
+ */
+ public function installAppBundle(Bundle $bundle) {
+ $appIds = $bundle->getAppIdentifiers();
+ foreach($appIds as $appId) {
+ if(!$this->isDownloaded($appId)) {
+ $this->downloadApp($appId);
+ }
+ $this->installApp($appId);
+ $app = new OC_App();
+ $app->enable($appId);
+ }
+ $bundles = json_decode($this->config->getAppValue('core', 'installed.bundles', json_encode([])), true);
+ $bundles[] = $bundle->getIdentifier();
+ $this->config->setAppValue('core', 'installed.bundles', json_encode($bundles));
+ }
+
/**
* Installs shipped apps
*
diff --git a/lib/private/Repair.php b/lib/private/Repair.php
index e808774ec935d..65e0342905ac3 100644
--- a/lib/private/Repair.php
+++ b/lib/private/Repair.php
@@ -30,12 +30,14 @@
namespace OC;
+use OC\App\AppStore\Bundles\BundleFetcher;
use OC\Repair\CleanTags;
use OC\Repair\Collation;
use OC\Repair\MoveUpdaterStepFile;
use OC\Repair\NC11\CleanPreviews;
use OC\Repair\NC11\FixMountStorages;
use OC\Repair\NC11\MoveAvatars;
+use OC\Repair\NC12\InstallCoreBundle;
use OC\Repair\NC12\UpdateLanguageCodes;
use OC\Repair\OldGroupMembershipShares;
use OC\Repair\RemoveRootShares;
@@ -136,6 +138,11 @@ public static function getRepairSteps() {
),
new FixMountStorages(\OC::$server->getDatabaseConnection()),
new UpdateLanguageCodes(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig()),
+ new InstallCoreBundle(
+ \OC::$server->query(BundleFetcher::class),
+ \OC::$server->getConfig(),
+ \OC::$server->query(Installer::class)
+ )
];
}
diff --git a/lib/private/Repair/NC12/InstallCoreBundle.php b/lib/private/Repair/NC12/InstallCoreBundle.php
new file mode 100644
index 0000000000000..38583b09a8936
--- /dev/null
+++ b/lib/private/Repair/NC12/InstallCoreBundle.php
@@ -0,0 +1,78 @@
+
+ *
+ * @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 .
+ *
+ */
+
+namespace OC\Repair\NC12;
+
+use OC\App\AppStore\Bundles\BundleFetcher;
+use OC\Installer;
+use OCP\IConfig;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+class InstallCoreBundle implements IRepairStep {
+ /** @var BundleFetcher */
+ private $bundleFetcher;
+ /** @var IConfig */
+ private $config;
+ /** @var Installer */
+ private $installer;
+
+ /**
+ * @param BundleFetcher $bundleFetcher
+ * @param IConfig $config
+ * @param Installer $installer
+ */
+ public function __construct(BundleFetcher $bundleFetcher,
+ IConfig $config,
+ Installer $installer) {
+ $this->bundleFetcher = $bundleFetcher;
+ $this->config = $config;
+ $this->installer = $installer;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName() {
+ return 'Install new core bundle components';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function run(IOutput $output) {
+ $versionFromBeforeUpdate = $this->config->getSystemValue('version', '0.0.0');
+
+ if (version_compare($versionFromBeforeUpdate, '12.0.0.14', '>')) {
+ return;
+ }
+
+ $defaultBundle = $this->bundleFetcher->getDefaultInstallationBundle();
+ foreach($defaultBundle as $bundle) {
+ try {
+ $this->installer->installAppBundle($bundle);
+ $output->info('Successfully installed core app bundle.');
+ } catch (\Exception $e) {
+ $output->warning('Could not install core app bundle: ' . $e->getMessage());
+ }
+ }
+ }
+}
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 7724feb551b03..b05e05660b035 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -43,6 +43,7 @@
use bantu\IniGetWrapper\IniGetWrapper;
use OC\App\AppManager;
+use OC\App\AppStore\Bundles\BundleFetcher;
use OC\App\AppStore\Fetcher\AppFetcher;
use OC\App\AppStore\Fetcher\CategoryFetcher;
use OC\AppFramework\Http\Request;
@@ -816,7 +817,12 @@ public function __construct($webRoot, \OC\Config $config) {
);
});
$this->registerAlias('MimeTypeLoader', \OCP\Files\IMimeTypeLoader::class);
-
+ $this->registerService(BundleFetcher::class, function () {
+ return new BundleFetcher($this->getL10N('lib'));
+ });
+ $this->registerService(AppFetcher::class, function() {
+ return $this->getAppFetcher();
+ });
$this->registerService(\OCP\Notification\IManager::class, function (Server $c) {
return new Manager(
$c->query(IValidator::class)
diff --git a/lib/private/Setup.php b/lib/private/Setup.php
index e2806efad4838..b1cf289d9aa7c 100644
--- a/lib/private/Setup.php
+++ b/lib/private/Setup.php
@@ -41,6 +41,7 @@
use bantu\IniGetWrapper\IniGetWrapper;
use Exception;
+use OC\App\AppStore\Bundles\BundleFetcher;
use OCP\Defaults;
use OCP\IL10N;
use OCP\ILogger;
@@ -63,11 +64,12 @@ class Setup {
/**
* @param SystemConfig $config
* @param IniGetWrapper $iniWrapper
+ * @param IL10N $l10n
* @param Defaults $defaults
* @param ILogger $logger
* @param ISecureRandom $random
*/
- function __construct(SystemConfig $config,
+ public function __construct(SystemConfig $config,
IniGetWrapper $iniWrapper,
IL10N $l10n,
Defaults $defaults,
@@ -364,8 +366,22 @@ public function install($options) {
$group =\OC::$server->getGroupManager()->createGroup('admin');
$group->addUser($user);
- //guess what this does
+ // Install shipped apps and specified app bundles
Installer::installShippedApps();
+ $installer = new Installer(
+ \OC::$server->getAppFetcher(),
+ \OC::$server->getHTTPClientService(),
+ \OC::$server->getTempManager(),
+ \OC::$server->getLogger(),
+ \OC::$server->getConfig()
+ );
+ $bundleFetcher = new BundleFetcher(\OC::$server->getL10N('lib'));
+ $defaultInstallationBundles = $bundleFetcher->getDefaultInstallationBundle();
+ foreach($defaultInstallationBundles as $bundle) {
+ try {
+ $installer->installAppBundle($bundle);
+ } catch (Exception $e) {}
+ }
// create empty file in data dir, so we can later find
// out that this is indeed an ownCloud data directory
diff --git a/lib/private/Updater.php b/lib/private/Updater.php
index 4427e4c48dc3b..c080ee0eb43d7 100644
--- a/lib/private/Updater.php
+++ b/lib/private/Updater.php
@@ -243,11 +243,11 @@ private function doUpgrade($currentVersion, $installedVersion) {
}
// update all shipped apps
- $disabledApps = $this->checkAppsRequirements();
+ $this->checkAppsRequirements();
$this->doAppUpgrade();
// upgrade appstore apps
- $this->upgradeAppStoreApps($disabledApps);
+ $this->upgradeAppStoreApps(\OC::$server->getAppManager()->getInstalledApps());
// install new shipped apps on upgrade
OC_App::loadApps('authentication');
@@ -441,7 +441,8 @@ private function upgradeAppStoreApps(array $disabledApps) {
\OC::$server->getAppFetcher(),
\OC::$server->getHTTPClientService(),
\OC::$server->getTempManager(),
- $this->log
+ $this->log,
+ \OC::$server->getConfig()
);
if (Installer::isUpdateAvailable($app, \OC::$server->getAppFetcher())) {
$this->emit('\OC\Updater', 'upgradeAppStoreApp', [$app]);
diff --git a/lib/private/legacy/app.php b/lib/private/legacy/app.php
index 3800b8b770e83..111da7d0d401e 100644
--- a/lib/private/legacy/app.php
+++ b/lib/private/legacy/app.php
@@ -365,7 +365,8 @@ public function enable($appId,
\OC::$server->getAppFetcher(),
\OC::$server->getHTTPClientService(),
\OC::$server->getTempManager(),
- \OC::$server->getLogger()
+ \OC::$server->getLogger(),
+ \OC::$server->getConfig()
);
$isDownloaded = $installer->isDownloaded($appId);
@@ -427,7 +428,8 @@ public static function removeApp($app) {
\OC::$server->getAppFetcher(),
\OC::$server->getHTTPClientService(),
\OC::$server->getTempManager(),
- \OC::$server->getLogger()
+ \OC::$server->getLogger(),
+ \OC::$server->getConfig()
);
return $installer->removeApp($app);
}
diff --git a/settings/Controller/AppSettingsController.php b/settings/Controller/AppSettingsController.php
index 7be6c2bf56217..ac77b2e7dd6ef 100644
--- a/settings/Controller/AppSettingsController.php
+++ b/settings/Controller/AppSettingsController.php
@@ -27,6 +27,7 @@
namespace OC\Settings\Controller;
+use OC\App\AppStore\Bundles\BundleFetcher;
use OC\App\AppStore\Fetcher\AppFetcher;
use OC\App\AppStore\Fetcher\CategoryFetcher;
use OC\App\AppStore\Version\VersionParser;
@@ -50,6 +51,7 @@ class AppSettingsController extends Controller {
const CAT_ENABLED = 0;
const CAT_DISABLED = 1;
const CAT_ALL_INSTALLED = 2;
+ const CAT_APP_BUNDLES = 3;
/** @var \OCP\IL10N */
private $l10n;
@@ -65,6 +67,8 @@ class AppSettingsController extends Controller {
private $appFetcher;
/** @var IFactory */
private $l10nFactory;
+ /** @var BundleFetcher */
+ private $bundleFetcher;
/**
* @param string $appName
@@ -76,6 +80,7 @@ class AppSettingsController extends Controller {
* @param CategoryFetcher $categoryFetcher
* @param AppFetcher $appFetcher
* @param IFactory $l10nFactory
+ * @param BundleFetcher $bundleFetcher
*/
public function __construct($appName,
IRequest $request,
@@ -85,7 +90,8 @@ public function __construct($appName,
IAppManager $appManager,
CategoryFetcher $categoryFetcher,
AppFetcher $appFetcher,
- IFactory $l10nFactory) {
+ IFactory $l10nFactory,
+ BundleFetcher $bundleFetcher) {
parent::__construct($appName, $request);
$this->l10n = $l10n;
$this->config = $config;
@@ -94,6 +100,7 @@ public function __construct($appName,
$this->categoryFetcher = $categoryFetcher;
$this->appFetcher = $appFetcher;
$this->l10nFactory = $l10nFactory;
+ $this->bundleFetcher = $bundleFetcher;
}
/**
@@ -120,18 +127,14 @@ public function viewApps($category = '') {
return $templateResponse;
}
- /**
- * Get all available categories
- *
- * @return JSONResponse
- */
- public function listCategories() {
+ private function getAllCategories() {
$currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2);
$formattedCategories = [
['id' => self::CAT_ALL_INSTALLED, 'ident' => 'installed', 'displayName' => (string)$this->l10n->t('Your apps')],
['id' => self::CAT_ENABLED, 'ident' => 'enabled', 'displayName' => (string)$this->l10n->t('Enabled apps')],
['id' => self::CAT_DISABLED, 'ident' => 'disabled', 'displayName' => (string)$this->l10n->t('Disabled apps')],
+ ['id' => self::CAT_APP_BUNDLES, 'ident' => 'app-bundles', 'displayName' => (string)$this->l10n->t('App bundles')],
];
$categories = $this->categoryFetcher->get();
foreach($categories as $category) {
@@ -142,7 +145,16 @@ public function listCategories() {
];
}
- return new JSONResponse($formattedCategories);
+ return $formattedCategories;
+ }
+
+ /**
+ * Get all available categories
+ *
+ * @return JSONResponse
+ */
+ public function listCategories() {
+ return new JSONResponse($this->getAllCategories());
}
/**
@@ -334,6 +346,41 @@ public function listApps($category = '') {
return ($a < $b) ? -1 : 1;
});
break;
+ case 'app-bundles':
+ $bundles = $this->bundleFetcher->getBundles();
+ $apps = [];
+ foreach($bundles as $bundle) {
+ $newCategory = true;
+ $allApps = $appClass->listAllApps();
+ $categories = $this->getAllCategories();
+ foreach($categories as $singleCategory) {
+ $newApps = $this->getAppsForCategory($singleCategory['id']);
+ foreach($allApps as $app) {
+ foreach($newApps as $key => $newApp) {
+ if($app['id'] === $newApp['id']) {
+ unset($newApps[$key]);
+ }
+ }
+ }
+ $allApps = array_merge($allApps, $newApps);
+ }
+
+ foreach($bundle->getAppIdentifiers() as $identifier) {
+ foreach($allApps as $app) {
+ if($app['id'] === $identifier) {
+ if($newCategory) {
+ $app['newCategory'] = true;
+ $app['categoryName'] = $bundle->getName();
+ }
+ $app['bundleId'] = $bundle->getIdentifier();
+ $newCategory = false;
+ $apps[] = $app;
+ continue;
+ }
+ }
+ }
+ }
+ break;
default:
$apps = $this->getAppsForCategory($category);
diff --git a/settings/ajax/disableapp.php b/settings/ajax/disableapp.php
index 8edd1c1453e60..9b76236a15bcf 100644
--- a/settings/ajax/disableapp.php
+++ b/settings/ajax/disableapp.php
@@ -36,8 +36,9 @@
exit;
}
-$appId = (string)$_POST['appid'];
-$appId = OC_App::cleanAppId($appId);
-
-OC_App::disable($appId);
+$appIds = (array)$_POST['appid'];
+foreach($appIds as $appId) {
+ $appId = OC_App::cleanAppId($appId);
+ OC_App::disable($appId);
+}
OC_JSON::success();
diff --git a/settings/ajax/enableapp.php b/settings/ajax/enableapp.php
index b6d62671a63cb..4c4fa0be66647 100644
--- a/settings/ajax/enableapp.php
+++ b/settings/ajax/enableapp.php
@@ -36,13 +36,20 @@
}
$groups = isset($_POST['groups']) ? (array)$_POST['groups'] : null;
+$appIds = isset($_POST['appIds']) ? (array)$_POST['appIds'] : [];
try {
- $app = new OC_App();
- $appId = (string)$_POST['appid'];
- $appId = OC_App::cleanAppId($appId);
- $app->enable($appId, $groups);
- OC_JSON::success(['data' => ['update_required' => \OC_App::shouldUpgrade($appId)]]);
+ $updateRequired = false;
+ foreach($appIds as $appId) {
+ $app = new OC_App();
+ $appId = OC_App::cleanAppId($appId);
+ $app->enable($appId, $groups);
+ if(\OC_App::shouldUpgrade($appId)) {
+ $updateRequired = true;
+ }
+ }
+
+ OC_JSON::success(['data' => ['update_required' => $updateRequired]]);
} catch (Exception $e) {
\OCP\Util::writeLog('core', $e->getMessage(), \OCP\Util::ERROR);
OC_JSON::error(array("data" => array("message" => $e->getMessage()) ));
diff --git a/settings/ajax/updateapp.php b/settings/ajax/updateapp.php
index 3020f82857742..bcf8e14914030 100644
--- a/settings/ajax/updateapp.php
+++ b/settings/ajax/updateapp.php
@@ -44,7 +44,8 @@
\OC::$server->getAppFetcher(),
\OC::$server->getHTTPClientService(),
\OC::$server->getTempManager(),
- \OC::$server->getLogger()
+ \OC::$server->getLogger(),
+ \OC::$server->getConfig()
);
$result = $installer->updateAppstoreApp($appId);
$config->setSystemValue('maintenance', false);
diff --git a/settings/css/settings.css b/settings/css/settings.css
index 7e91877773e51..0a1d4e046feb1 100644
--- a/settings/css/settings.css
+++ b/settings/css/settings.css
@@ -519,13 +519,37 @@ input.userFilter {width: 200px;}
/* APPS */
+/* Bundle header */
+#apps-list .apps-header {
+ display: table-row;
+ position: relative;
+}
+#apps-list .apps-header div {
+ display: table-cell;
+ height: 70px;
+}
+#apps-list .apps-header h2 {
+ display: table-cell;
+ position: absolute;
+ padding-left: 6px;
+ padding-top: 15px;
+}
+#apps-list .apps-header h2 .enable {
+ position: relative;
+ top: -1px;
+ margin-left: 12px;
+}
+#apps-list .apps-header h2 + .section {
+ margin-top: 50px;
+}
+
#app-content > svg.app-filter {
float: left;
height: 0;
width: 0;
}
-#app-category-disabled {
+#app-category-app-bundles {
margin-bottom: 20px;
}
@@ -558,6 +582,10 @@ span.version {
border-radius: 3px;
padding: 3px 6px;
}
+.app-level a {
+ padding: 10px;
+ white-space: nowrap;
+}
.app-level .official {
border-color: #37ce02;
background-position: left center;
@@ -737,6 +765,7 @@ form.section {
display: table;
width: 100%;
height: auto;
+ margin-bottom: 100px;
}
#apps-list.installed .section {
diff --git a/settings/js/apps.js b/settings/js/apps.js
index 3326886951fe5..6bad2cc842c33 100644
--- a/settings/js/apps.js
+++ b/settings/js/apps.js
@@ -29,6 +29,7 @@ OC.Settings.Apps = OC.Settings.Apps || {
State: {
currentCategory: null,
+ currentCategoryElements: null,
apps: null,
$updateNotification: null,
availableUpdates: 0
@@ -90,14 +91,15 @@ OC.Settings.Apps = OC.Settings.Apps || {
}), {
type:'GET',
success: function (apps) {
+ OC.Settings.Apps.State.currentCategoryElements = apps.apps;
var appListWithIndex = _.indexBy(apps.apps, 'id');
OC.Settings.Apps.State.apps = appListWithIndex;
var appList = _.map(appListWithIndex, function(app) {
// default values for missing fields
return _.extend({level: 0}, app);
});
- var source
- if (categoryId === 'enabled' || categoryId === 'disabled' || categoryId === 'installed') {
+ var source;
+ if (categoryId === 'enabled' || categoryId === 'disabled' || categoryId === 'installed' || categoryId === 'app-bundles') {
source = $("#app-template-installed").html();
$('#apps-list').addClass('installed');
} else {
@@ -107,17 +109,19 @@ OC.Settings.Apps = OC.Settings.Apps || {
var template = Handlebars.compile(source);
if (appList.length) {
- appList.sort(function(a,b) {
- if (a.active !== b.active) {
- return (a.active ? -1 : 1)
- } else {
- var levelDiff = b.level - a.level;
- if (levelDiff === 0) {
- return OC.Util.naturalSortCompare(a.name, b.name);
+ if(categoryId !== 'app-bundles') {
+ appList.sort(function (a, b) {
+ if (a.active !== b.active) {
+ return (a.active ? -1 : 1)
+ } else {
+ var levelDiff = b.level - a.level;
+ if (levelDiff === 0) {
+ return OC.Util.naturalSortCompare(a.name, b.name);
+ }
+ return levelDiff;
}
- return levelDiff;
- }
- });
+ });
+ }
var firstExperimental = false;
_.each(appList, function(app) {
@@ -303,56 +307,126 @@ OC.Settings.Apps = OC.Settings.Apps || {
return $.get(OC.generateUrl('apps/files'));
},
- enableApp:function(appId, active, element, groups) {
+ enableAppBundle:function(bundleId, active, element, groups) {
+ if (OC.PasswordConfirmation.requiresPasswordConfirmation()) {
+ OC.PasswordConfirmation.requirePasswordConfirmation(_.bind(this.enableAppBundle, this, bundleId, active, element, groups));
+ return;
+ }
+
+ var apps = OC.Settings.Apps.State.currentCategoryElements;
+ var appsToEnable = [];
+ apps.forEach(function(app) {
+ if(app['bundleId'] === bundleId) {
+ if(app['active'] === false) {
+ appsToEnable.push(app['id']);
+ }
+ }
+ });
+
+ OC.Settings.Apps.enableApp(appsToEnable, false, groups);
+ },
+
+ /**
+ * @param {string[]} appId
+ * @param {boolean} active
+ * @param {array} groups
+ */
+ enableApp:function(appId, active, groups) {
if (OC.PasswordConfirmation.requiresPasswordConfirmation()) {
- OC.PasswordConfirmation.requirePasswordConfirmation(_.bind(this.enableApp, this, appId, active, element, groups));
+ OC.PasswordConfirmation.requirePasswordConfirmation(_.bind(this.enableApp, this, appId, active, groups));
return;
}
+ var elements = [];
+ appId.forEach(function(appId) {
+ elements.push($('#app-'+appId+' .enable'));
+ });
+
var self = this;
- OC.Settings.Apps.hideErrorMessage(appId);
+ appId.forEach(function(appId) {
+ OC.Settings.Apps.hideErrorMessage(appId);
+ });
groups = groups || [];
- var appItem = $('div#app-'+appId+'');
+ var appItems = [];
+ appId.forEach(function(appId) {
+ appItems.push($('div#app-'+appId+''));
+ });
+
if(active && !groups.length) {
- element.val(t('settings','Disabling app …'));
+ elements.forEach(function(element) {
+ element.val(t('settings','Disabling app …'));
+ });
$.post(OC.filePath('settings','ajax','disableapp.php'),{appid:appId},function(result) {
if(!result || result.status !== 'success') {
if (result.data && result.data.message) {
OC.Settings.Apps.showErrorMessage(appId, result.data.message);
- appItem.data('errormsg', result.data.message);
+ appItems.forEach(function(appItem) {
+ appItem.data('errormsg', result.data.message);
+ })
} else {
OC.Settings.Apps.showErrorMessage(appId, t('settings', 'Error while disabling app'));
- appItem.data('errormsg', t('settings', 'Error while disabling app'));
+ appItems.forEach(function(appItem) {
+ appItem.data('errormsg', t('settings', 'Error while disabling app'));
+ });
}
- element.val(t('settings','Disable'));
- appItem.addClass('appwarning');
+ elements.forEach(function(element) {
+ element.val(t('settings','Disable'));
+ });
+ appItems.forEach(function(appItem) {
+ appItem.addClass('appwarning');
+ });
} else {
OC.Settings.Apps.rebuildNavigation();
- appItem.data('active',false);
- appItem.data('groups', '');
- element.data('active',false);
- appItem.removeClass('active');
- element.val(t('settings','Enable'));
- element.parent().find(".groups-enable").hide();
- element.parent().find('#group_select').hide().val(null);
+ appItems.forEach(function(appItem) {
+ appItem.data('active', false);
+ appItem.data('groups', '');
+ });
+ elements.forEach(function(element) {
+ element.data('active', false);
+ });
+ appItems.forEach(function(appItem) {
+ appItem.removeClass('active');
+ });
+ elements.forEach(function(element) {
+ element.val(t('settings', 'Enable'));
+ element.parent().find(".groups-enable").hide();
+ element.parent().find('#group_select').hide().val(null);
+ });
OC.Settings.Apps.State.apps[appId].active = false;
}
},'json');
} else {
// TODO: display message to admin to not refresh the page!
// TODO: lock UI to prevent further operations
- element.val(t('settings','Enabling app …'));
- $.post(OC.filePath('settings','ajax','enableapp.php'),{appid: appId, groups: groups},function(result) {
+ elements.forEach(function(element) {
+ element.val(t('settings', 'Enabling app …'));
+ });
+
+ var appIdArray = [];
+ if( typeof appId === 'string' ) {
+ appIdArray = [appId];
+ } else {
+ appIdArray = appId;
+ }
+ $.post(OC.filePath('settings','ajax','enableapp.php'),{appIds: appIdArray, groups: groups},function(result) {
if(!result || result.status !== 'success') {
if (result.data && result.data.message) {
OC.Settings.Apps.showErrorMessage(appId, result.data.message);
- appItem.data('errormsg', result.data.message);
+ appItems.forEach(function(appItem) {
+ appItem.data('errormsg', result.data.message);
+ });
} else {
OC.Settings.Apps.showErrorMessage(appId, t('settings', 'Error while enabling app'));
- appItem.data('errormsg', t('settings', 'Error while disabling app'));
+ appItems.forEach(function(appItem) {
+ appItem.data('errormsg', t('settings', 'Error while disabling app'));
+ });
}
- element.val(t('settings','Enable'));
- appItem.addClass('appwarning');
+ elements.forEach(function(element) {
+ element.val(t('settings', 'Enable'));
+ });
+ appItems.forEach(function(appItem) {
+ appItem.addClass('appwarning');
+ });
} else {
self._checkServerHealth().done(function() {
if (result.data.update_required) {
@@ -364,24 +438,40 @@ OC.Settings.Apps = OC.Settings.Apps || {
}
OC.Settings.Apps.rebuildNavigation();
- appItem.data('active',true);
- element.data('active',true);
- appItem.addClass('active');
- element.val(t('settings','Disable'));
+ appItems.forEach(function(appItem) {
+ appItem.data('active', true);
+ });
+ elements.forEach(function(element) {
+ element.data('active', true);
+ });
+ appItems.forEach(function(appItem) {
+ appItem.addClass('active');
+ });
+ elements.forEach(function(element) {
+ element.val(t('settings', 'Disable'));
+ });
var app = OC.Settings.Apps.State.apps[appId];
app.active = true;
if (OC.Settings.Apps.isType(app, 'filesystem') || OC.Settings.Apps.isType(app, 'prelogin') ||
OC.Settings.Apps.isType(app, 'authentication') || OC.Settings.Apps.isType(app, 'logging')) {
- element.parent().find(".groups-enable").prop('checked', true);
- element.parent().find(".groups-enable").hide();
- element.parent().find('#group_select').hide().val(null);
+ elements.forEach(function(element) {
+ element.parent().find(".groups-enable").prop('checked', true);
+ element.parent().find(".groups-enable").hide();
+ element.parent().find('#group_select').hide().val(null);
+ });
} else {
- element.parent().find("#groups-enable").show();
+ elements.forEach(function(element) {
+ element.parent().find("#groups-enable").show();
+ });
if (groups) {
- appItem.data('groups', JSON.stringify(groups));
+ appItems.forEach(function(appItem) {
+ appItem.data('groups', JSON.stringify(groups));
+ });
} else {
- appItem.data('groups', '');
+ appItems.forEach(function(appItem) {
+ appItem.data('groups', '');
+ });
}
}
}).fail(function() {
@@ -391,26 +481,40 @@ OC.Settings.Apps = OC.Settings.Apps || {
appId,
t('settings', 'Error: this app cannot be enabled because it makes the server unstable')
);
- appItem.data('errormsg', t('settings', 'Error while enabling app'));
- element.val(t('settings','Enable'));
- appItem.addClass('appwarning');
+ appItems.forEach(function(appItem) {
+ appItem.data('errormsg', t('settings', 'Error while enabling app'));
+ });
+ elements.forEach(function(element) {
+ element.val(t('settings', 'Enable'));
+ });
+ appItems.forEach(function(appItem) {
+ appItem.addClass('appwarning');
+ });
}).fail(function() {
OC.Settings.Apps.showErrorMessage(
appId,
t('settings', 'Error: could not disable broken app')
);
- appItem.data('errormsg', t('settings', 'Error while disabling broken app'));
- element.val(t('settings','Enable'));
+ appItems.forEach(function(appItem) {
+ appItem.data('errormsg', t('settings', 'Error while disabling broken app'));
+ });
+ elements.forEach(function(element) {
+ element.val(t('settings', 'Enable'));
+ });
});
});
}
},'json')
.fail(function() {
OC.Settings.Apps.showErrorMessage(appId, t('settings', 'Error while enabling app'));
- appItem.data('errormsg', t('settings', 'Error while enabling app'));
- appItem.data('active',false);
- appItem.addClass('appwarning');
- element.val(t('settings','Enable'));
+ appItems.forEach(function(appItem) {
+ appItem.data('errormsg', t('settings', 'Error while enabling app'));
+ appItem.data('active', false);
+ appItem.addClass('appwarning');
+ });
+ elements.forEach(function(element) {
+ element.val(t('settings', 'Enable'));
+ });
});
}
},
@@ -774,10 +878,17 @@ OC.Settings.Apps = OC.Settings.Apps || {
$(document).on('click', '#apps-list input.enable', function () {
var appId = $(this).data('appid');
+ var bundleId = $(this).data('bundleid');
var element = $(this);
var active = $(this).data('active');
- OC.Settings.Apps.enableApp(appId, active, element);
+ var category = $('#app-navigation').attr('data-category');
+ if(bundleId) {
+ OC.Settings.Apps.enableAppBundle(bundleId, active, element);
+ element.val(t('settings', 'Enable all'));
+ } else {
+ OC.Settings.Apps.enableApp([appId], active);
+ }
});
$(document).on('click', '#apps-list input.uninstall', function () {
@@ -805,7 +916,7 @@ OC.Settings.Apps = OC.Settings.Apps || {
var appId = element.data('appid');
if (appId) {
- OC.Settings.Apps.enableApp(appId, false, element, groups);
+ OC.Settings.Apps.enableApp([appId], false, groups);
OC.Settings.Apps.State.apps[appId].groups = groups;
}
});
diff --git a/settings/templates/apps.php b/settings/templates/apps.php
index 310513722cfb1..260b042c078d8 100644
--- a/settings/templates/apps.php
+++ b/settings/templates/apps.php
@@ -29,8 +29,17 @@
-