From 8594fdc493a0bb16bfe37a7cde6c5b8f37a9f4e2 Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Thu, 18 Jan 2018 10:02:08 +0100 Subject: Move to AppFramework Controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl Move app management ajax code to AppSettingsController Signed-off-by: Julius Härtl --- lib/public/App/IAppManager.php | 1 + settings/Controller/AppSettingsController.php | 135 +++++++++++++++++++++++++- settings/ajax/disableapp.php | 44 --------- settings/ajax/enableapp.php | 61 ------------ settings/ajax/uninstallapp.php | 55 ----------- settings/ajax/updateapp.php | 58 ----------- settings/js/apps.js | 12 ++- settings/routes.php | 19 ++-- 8 files changed, 153 insertions(+), 232 deletions(-) delete mode 100644 settings/ajax/disableapp.php delete mode 100644 settings/ajax/enableapp.php delete mode 100644 settings/ajax/uninstallapp.php delete mode 100644 settings/ajax/updateapp.php diff --git a/lib/public/App/IAppManager.php b/lib/public/App/IAppManager.php index 4840d71d756..b0d04500f35 100644 --- a/lib/public/App/IAppManager.php +++ b/lib/public/App/IAppManager.php @@ -100,6 +100,7 @@ interface IAppManager { * * @param string $appId * @param \OCP\IGroup[] $groups + * @throws \Exception * @since 8.0.0 */ public function enableAppForGroups($appId, $groups); diff --git a/settings/Controller/AppSettingsController.php b/settings/Controller/AppSettingsController.php index 325b6a0daf0..234001e1899 100644 --- a/settings/Controller/AppSettingsController.php +++ b/settings/Controller/AppSettingsController.php @@ -38,11 +38,14 @@ use OC\App\AppStore\Version\VersionParser; use OC\App\DependencyAnalyzer; use OC\App\Platform; use OC\Installer; +use OC_App; use OCP\App\IAppManager; use \OCP\AppFramework\Controller; +use OCP\AppFramework\Http; use OCP\AppFramework\Http\ContentSecurityPolicy; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Http\TemplateResponse; +use OCP\ILogger; use OCP\INavigationManager; use OCP\IRequest; use OCP\IL10N; @@ -80,6 +83,8 @@ class AppSettingsController extends Controller { private $installer; /** @var IURLGenerator */ private $urlGenerator; + /** @var ILogger */ + private $logger; /** * @param string $appName @@ -94,6 +99,7 @@ class AppSettingsController extends Controller { * @param BundleFetcher $bundleFetcher * @param Installer $installer * @param IURLGenerator $urlGenerator + * @param ILogger $logger */ public function __construct(string $appName, IRequest $request, @@ -106,7 +112,8 @@ class AppSettingsController extends Controller { IFactory $l10nFactory, BundleFetcher $bundleFetcher, Installer $installer, - IURLGenerator $urlGenerator) { + IURLGenerator $urlGenerator, + ILogger $logger) { parent::__construct($appName, $request); $this->l10n = $l10n; $this->config = $config; @@ -118,6 +125,7 @@ class AppSettingsController extends Controller { $this->bundleFetcher = $bundleFetcher; $this->installer = $installer; $this->urlGenerator = $urlGenerator; + $this->logger = $logger; } /** @@ -280,6 +288,7 @@ class AppSettingsController extends Controller { 'needsDownload' => !$existsLocally, 'groups' => $groups, 'fromAppStore' => true, + 'appstoreData' => $app ]; @@ -295,10 +304,13 @@ class AppSettingsController extends Controller { private function getAppsWithUpdates() { $appClass = new \OC_App(); $apps = $appClass->listAllApps(); + /** @var \OC\App\AppStore\Manager $manager */ + $manager = \OC::$server->query(\OC\App\AppStore\Manager::class); foreach($apps as $key => $app) { $newVersion = $this->installer->isUpdateAvailable($app['id']); if($newVersion !== false) { $apps[$key]['update'] = $newVersion; + $apps[$key]['appstoreData'] = $manager->getApp($app['id']); } else { unset($apps[$key]); } @@ -471,4 +483,125 @@ class AppSettingsController extends Controller { return new JSONResponse(['apps' => $apps, 'status' => 'success']); } + + private function getGroupList(array $groups) { + $groupManager = \OC::$server->getGroupManager(); + $groupsList = []; + foreach ($groups as $group) { + $groupItem = $groupManager->get($group); + if ($groupItem instanceof \OCP\IGroup) { + $groupsList[] = $groupManager->get($group); + } + } + return $groupsList; + } + + /** + * @PasswordConfirmationRequired + * + * @param string $appId + * @return JSONResponse + */ + public function enableApp(string $appId, array $groups): JSONResponse { + return $this->enableApps([$appId], $groups); + } + + /** + * Enable one or more apps + * + * apps will be enabled for specific groups only if $groups is defined + * + * @PasswordConfirmationRequired + * @param array $appIds + * @param array $groups + * @return JSONResponse + */ + public function enableApps(array $appIds, array $groups = []): JSONResponse { + try { + $updateRequired = false; + + foreach ($appIds as $appId) { + $appId = OC_App::cleanAppId($appId); + if (count($groups) > 0) { + $this->appManager->enableAppForGroups($appId, $this->getGroupList($groups)); + } else { + $this->appManager->enableApp($appId); + } + if (\OC_App::shouldUpgrade($appId)) { + $updateRequired = true; + } + } + return new JSONResponse(['data' => ['update_required' => $updateRequired]]); + + } catch (\Exception $e) { + $this->logger->logException($e); + return new JSONResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR); + } + } + + /** + * @PasswordConfirmationRequired + * + * @param string $appId + * @return JSONResponse + */ + public function disableApp(string $appId): JSONResponse { + return $this->disableApps([$appId]); + } + + /** + * @PasswordConfirmationRequired + * + * @param array $appIds + * @return JSONResponse + */ + public function disableApps(array $appIds): JSONResponse { + try { + foreach ($appIds as $appId) { + $appId = OC_App::cleanAppId($appId); + $this->appManager->disableApp($appId); + } + return new JSONResponse([]); + } catch (\Exception $e) { + $this->logger->logException($e); + return new JSONResponse(['data' => ['message' => $e->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR); + } + } + + /** + * @PasswordConfirmationRequired + * + * @param string $appId + * @return JSONResponse + */ + public function uninstallApp(string $appId): JSONResponse { + $appId = OC_App::cleanAppId($appId); + $result = OC_App::removeApp($appId); + if($result !== false) { + // FIXME: Clear the cache - move that into some sane helper method + \OC::$server->getMemCacheFactory()->createDistributed('settings')->remove('listApps-0'); + \OC::$server->getMemCacheFactory()->createDistributed('settings')->remove('listApps-1'); + return new JSONResponse(['data' => ['appid' => $appId]]); + } + return new JSONResponse(['data' => ['message' => $this->l10n->t('Couldn\'t remove app.')]], Http::STATUS_INTERNAL_SERVER_ERROR); + } + + public function updateApp(string $appId) { + $appId = OC_App::cleanAppId($appId); + + $this->config->setSystemValue('maintenance', true); + try { + $installer = \OC::$server->query(\OC\Installer::class); + $result = $installer->updateAppstoreApp($appId); + $this->config->setSystemValue('maintenance', false); + } catch (\Exception $ex) { + $this->config->setSystemValue('maintenance', false); + return new JSONResponse(['data' => ['message' => $ex->getMessage()]], Http::STATUS_INTERNAL_SERVER_ERROR); + } + + if ($result !== false) { + return new JSONResponse(['data' => ['appid' => $appId]]); + } + return new JSONResponse(['data' => ['message' => $this->l10n->t('Couldn\'t update app.')]], Http::STATUS_INTERNAL_SERVER_ERROR); + } } diff --git a/settings/ajax/disableapp.php b/settings/ajax/disableapp.php deleted file mode 100644 index d719c3e9f23..00000000000 --- a/settings/ajax/disableapp.php +++ /dev/null @@ -1,44 +0,0 @@ - - * @author Kamil Domanski - * @author Lukas Reschke - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see - * - */ -\OC_JSON::checkAdminUser(); -\OC_JSON::callCheck(); - -$lastConfirm = (int) \OC::$server->getSession()->get('last-password-confirm'); -if ($lastConfirm < (time() - 30 * 60 + 15)) { // allow 15 seconds delay - $l = \OC::$server->getL10N('core'); - OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required')))); - exit(); -} - -if (!array_key_exists('appid', $_POST)) { - OC_JSON::error(); - exit; -} - -$appIds = (array)$_POST['appid']; -foreach($appIds as $appId) { - $appId = OC_App::cleanAppId($appId); - \OC::$server->getAppManager()->disableApp($appId); -} -OC_JSON::success(); diff --git a/settings/ajax/enableapp.php b/settings/ajax/enableapp.php deleted file mode 100644 index 0ecc001a24c..00000000000 --- a/settings/ajax/enableapp.php +++ /dev/null @@ -1,61 +0,0 @@ - - * @author Christopher Schäpers - * @author Kamil Domanski - * @author Lukas Reschke - * @author Robin Appelman - * @author Thomas Müller - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see - * - */ - -use OCP\ILogger; - -OC_JSON::checkAdminUser(); -\OC_JSON::callCheck(); - -$lastConfirm = (int) \OC::$server->getSession()->get('last-password-confirm'); -if ($lastConfirm < (time() - 30 * 60 + 15)) { // allow 15 seconds delay - $l = \OC::$server->getL10N('core'); - OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required')))); - exit(); -} - -$groups = isset($_POST['groups']) ? (array)$_POST['groups'] : []; -$appIds = isset($_POST['appIds']) ? (array)$_POST['appIds'] : []; - -try { - $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) { - \OC::$server->getLogger()->logException($e, [ - 'level' => ILogger::DEBUG, - 'app' => 'core', - ]); - OC_JSON::error(array("data" => array("message" => $e->getMessage()) )); -} diff --git a/settings/ajax/uninstallapp.php b/settings/ajax/uninstallapp.php deleted file mode 100644 index 26100d3b066..00000000000 --- a/settings/ajax/uninstallapp.php +++ /dev/null @@ -1,55 +0,0 @@ - - * @author Lukas Reschke - * @author Robin Appelman - * @author Roeland Jago Douma - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see - * - */ -\OC_JSON::checkAdminUser(); -\OC_JSON::callCheck(); - -$lastConfirm = (int) \OC::$server->getSession()->get('last-password-confirm'); -if ($lastConfirm < (time() - 30 * 60 + 15)) { // allow 15 seconds delay - $l = \OC::$server->getL10N('core'); - OC_JSON::error(array( 'data' => array( 'message' => $l->t('Password confirmation is required')))); - exit(); -} - -if (!array_key_exists('appid', $_POST)) { - OC_JSON::error(); - exit; -} - -$appId = (string)$_POST['appid']; -$appId = OC_App::cleanAppId($appId); - -// FIXME: move to controller -/** @var \OC\Installer $installer */ -$installer = \OC::$server->query(\OC\Installer::class); -$result = $installer->removeApp($app); -if($result !== false) { - // FIXME: Clear the cache - move that into some sane helper method - \OC::$server->getMemCacheFactory()->createDistributed('settings')->remove('listApps-0'); - \OC::$server->getMemCacheFactory()->createDistributed('settings')->remove('listApps-1'); - OC_JSON::success(array('data' => array('appid' => $appId))); -} else { - $l = \OC::$server->getL10N('settings'); - OC_JSON::error(array('data' => array( 'message' => $l->t("Couldn't remove app.") ))); -} diff --git a/settings/ajax/updateapp.php b/settings/ajax/updateapp.php deleted file mode 100644 index d37e1cfcaed..00000000000 --- a/settings/ajax/updateapp.php +++ /dev/null @@ -1,58 +0,0 @@ - - * @author Frank Karlitschek - * @author Georg Ehrke - * @author Lukas Reschke - * @author Robin Appelman - * @author Roeland Jago Douma - * @author Thomas Müller - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see - * - */ -\OC_JSON::checkAdminUser(); -\OC_JSON::callCheck(); - -if (!array_key_exists('appid', $_POST)) { - \OC_JSON::error(array( - 'message' => 'No AppId given!' - )); - return; -} - -$appId = (string)$_POST['appid']; -$appId = OC_App::cleanAppId($appId); - -$config = \OC::$server->getConfig(); -$config->setSystemValue('maintenance', true); -try { - $installer = \OC::$server->query(\OC\Installer::class); - $result = $installer->updateAppstoreApp($appId); - $config->setSystemValue('maintenance', false); -} catch(Exception $ex) { - $config->setSystemValue('maintenance', false); - OC_JSON::error(array('data' => array( 'message' => $ex->getMessage() ))); - return; -} - -if($result !== false) { - OC_JSON::success(array('data' => array('appid' => $appId))); -} else { - $l = \OC::$server->getL10N('settings'); - OC_JSON::error(array('data' => array( 'message' => $l->t("Couldn't update app.") ))); -} diff --git a/settings/js/apps.js b/settings/js/apps.js index 4fca8539563..9776b6e33c2 100644 --- a/settings/js/apps.js +++ b/settings/js/apps.js @@ -377,7 +377,13 @@ OC.Settings.Apps = OC.Settings.Apps || { elements.forEach(function(element) { element.val(t('settings','Disabling app …')); }); - $.post(OC.filePath('settings','ajax','disableapp.php'),{appid:appId},function(result) { + $.post(OC.generateUrl('/settings/apps/enable/' + appId)) + .done(function(result) { + console.log(result); + }).fail(function(xhr, status, error) { + console.log(error); + }); + /* if(!result || result.status !== 'success') { if (result.data && result.data.message) { OC.Settings.Apps.showErrorMessage(appId, result.data.message); @@ -415,7 +421,7 @@ OC.Settings.Apps = OC.Settings.Apps || { }); OC.Settings.Apps.State.apps[appId].active = false; } - },'json'); + },'json');*/ } else { // TODO: display message to admin to not refresh the page! // TODO: lock UI to prevent further operations @@ -429,7 +435,7 @@ OC.Settings.Apps = OC.Settings.Apps || { } else { appIdArray = appId; } - $.post(OC.filePath('settings','ajax','enableapp.php'),{appIds: appIdArray, groups: groups},function(result) { + $.post(OC.generateUrl('/settings/apps/enable'),{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); diff --git a/settings/routes.php b/settings/routes.php index a3a5812bf4f..a21a0f0789d 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -49,6 +49,14 @@ $application->registerRoutes($this, [ ['name' => 'AppSettings#listCategories', 'url' => '/settings/apps/categories', 'verb' => 'GET'], ['name' => 'AppSettings#viewApps', 'url' => '/settings/apps', 'verb' => 'GET'], ['name' => 'AppSettings#listApps', 'url' => '/settings/apps/list', 'verb' => 'GET'], + ['name' => 'AppSettings#enableApp', 'url' => '/settings/apps/enable/{appId}', 'verb' => 'GET'], + ['name' => 'AppSettings#enableApps', 'url' => '/settings/apps/enable', 'verb' => 'POST'], + ['name' => 'AppSettings#disableApp', 'url' => '/settings/apps/disable/{appId}', 'verb' => 'GET'], + ['name' => 'AppSettings#disableApps', 'url' => '/settings/apps/disable', 'verb' => 'POST'], + ['name' => 'AppSettings#updateApp', 'url' => '/settings/apps/update/{appId}', 'verb' => 'GET'], + ['name' => 'AppSettings#uninstallApp', 'url' => '/settings/apps/uninstall/{appId}', 'verb' => 'GET'], + ['name' => 'Users#setDisplayName', 'url' => '/settings/users/{username}/displayName', 'verb' => 'POST'], + ['name' => 'Users#setEMailAddress', 'url' => '/settings/users/{id}/mailAddress', 'verb' => 'PUT'], ['name' => 'Users#setUserSettings', 'url' => '/settings/users/{username}/settings', 'verb' => 'PUT'], ['name' => 'Users#getVerificationCode', 'url' => '/settings/users/{account}/verify', 'verb' => 'GET'], ['name' => 'Users#usersList', 'url' => '/settings/users', 'verb' => 'GET'], @@ -76,13 +84,4 @@ $application->registerRoutes($this, [ // Settings pages $this->create('settings_help', '/settings/help') ->actionInclude('settings/help.php'); -// Settings ajax actions -// apps -$this->create('settings_ajax_enableapp', '/settings/ajax/enableapp.php') - ->actionInclude('settings/ajax/enableapp.php'); -$this->create('settings_ajax_disableapp', '/settings/ajax/disableapp.php') - ->actionInclude('settings/ajax/disableapp.php'); -$this->create('settings_ajax_updateapp', '/settings/ajax/updateapp.php') - ->actionInclude('settings/ajax/updateapp.php'); -$this->create('settings_ajax_uninstallapp', '/settings/ajax/uninstallapp.php') - ->actionInclude('settings/ajax/uninstallapp.php'); + -- cgit v1.2.3 From 125d1d3d4e7494a0982b1f2adec1e8de2b91b5f7 Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Thu, 10 May 2018 13:26:29 +0200 Subject: Add file skeleton for app settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/Controller/AppSettingsController.php | 2 + settings/src/components/appDetails.vue | 187 ++++++++++++++++++++++++++ settings/src/components/appList.vue | 116 ++++++++++++++++ settings/src/router.js | 21 +++ settings/src/store/apps.js | 99 ++++++++++++++ settings/src/store/index.js | 2 + settings/src/views/Apps.vue | 157 +++++++++++++++++++++ 7 files changed, 584 insertions(+) create mode 100644 settings/src/components/appDetails.vue create mode 100644 settings/src/components/appList.vue create mode 100644 settings/src/store/apps.js create mode 100644 settings/src/views/Apps.vue diff --git a/settings/Controller/AppSettingsController.php b/settings/Controller/AppSettingsController.php index 234001e1899..15b688736fa 100644 --- a/settings/Controller/AppSettingsController.php +++ b/settings/Controller/AppSettingsController.php @@ -150,7 +150,9 @@ class AppSettingsController extends Controller { $policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com'); $templateResponse->setContentSecurityPolicy($policy); + return new TemplateResponse('settings', 'settings', ['serverData' => $params]); return $templateResponse; + } private function getAllCategories() { diff --git a/settings/src/components/appDetails.vue b/settings/src/components/appDetails.vue new file mode 100644 index 00000000000..d007555dd5b --- /dev/null +++ b/settings/src/components/appDetails.vue @@ -0,0 +1,187 @@ + + + + + diff --git a/settings/src/components/appList.vue b/settings/src/components/appList.vue new file mode 100644 index 00000000000..8dc7fede01d --- /dev/null +++ b/settings/src/components/appList.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/settings/src/router.js b/settings/src/router.js index 270949d542c..bfcff91e992 100644 --- a/settings/src/router.js +++ b/settings/src/router.js @@ -1,6 +1,7 @@ import Vue from 'vue'; import Router from 'vue-router'; import Users from './views/Users'; +import Apps from './views/Apps'; Vue.use(Router); @@ -32,6 +33,26 @@ export default new Router({ component: Users } ] + }, + { + path: '/:index(index.php/)?settings/apps', + component: Apps, + props: true, + name: 'apps', + children: [ + { + path: ':category', + name: 'apps-category', + component: Apps, + children: [ + { + path: ':id', + name: 'apps-details', + component: Apps + } + ] + } + ] } ] }); diff --git a/settings/src/store/apps.js b/settings/src/store/apps.js new file mode 100644 index 00000000000..d9888465dd6 --- /dev/null +++ b/settings/src/store/apps.js @@ -0,0 +1,99 @@ +/* + * @copyright Copyright (c) 2018 Julius Härtl + * + * @author Julius Härtl + * + * @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 . + * + */ + +import api from './api'; + +const state = { + apps: [], + categories: [], + updateCount: 0 +}; + +const mutations = { + initCategories(state, {categories, updateCount}) { + state.categories = categories; + state.updateCount = updateCount; + }, + + setUpdateCount(state, updateCount) { + state.updateCount = updateCount; + }, + + addCategory(state, category) { + state.categories.push(category); + }, + + appendCategories(state, categoriesArray) { + // convert obj to array + state.categories = categoriesArray; + }, + + setApps(state, apps) { + state.apps = apps; + }, + + reset(state) { + state.apps = []; + state.categories = []; + state.updateCount = 0; + } +}; + +const getters = { + getCategories(state) { + return state.categories; + }, + getApps(state) { + return state.apps; + }, + getUpdateCount(state) { + return state.updateCount; + } +}; + +const actions = { + + getApps(context, { category }) { + return api.get(OC.generateUrl(`settings/apps/list?category=${category}`)) + .then((response) => { + context.commit('setApps', response.data.apps); + return true; + }) + .catch((error) => context.commit('API_FAILURE', error)) + + }, + + getCategories(context) { + return api.get(OC.generateUrl('settings/apps/categories')) + .then((response) => { + if (response.data.length > 0) { + context.commit('appendCategories', response.data); + return true; + } + return false; + }) + .catch((error) => context.commit('API_FAILURE', error)); + }, + +}; + +export default { state, mutations, getters, actions }; \ No newline at end of file diff --git a/settings/src/store/index.js b/settings/src/store/index.js index 2bd8d76e41b..00f3ad809ad 100644 --- a/settings/src/store/index.js +++ b/settings/src/store/index.js @@ -1,6 +1,7 @@ import Vue from 'vue'; import Vuex from 'vuex'; import users from './users'; +import apps from './apps'; import settings from './settings'; import oc from './oc'; @@ -23,6 +24,7 @@ const mutations = { export default new Vuex.Store({ modules: { users, + apps, settings, oc }, diff --git a/settings/src/views/Apps.vue b/settings/src/views/Apps.vue new file mode 100644 index 00000000000..eac9bec7527 --- /dev/null +++ b/settings/src/views/Apps.vue @@ -0,0 +1,157 @@ + + + + + + -- cgit v1.2.3 From d9d5e975d8f4671341f9c3b5ead85578a86b1c92 Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Thu, 17 May 2018 22:42:16 +0200 Subject: Remove default categories from route endpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/Controller/AppSettingsController.php | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/settings/Controller/AppSettingsController.php b/settings/Controller/AppSettingsController.php index 15b688736fa..413e54d6ce4 100644 --- a/settings/Controller/AppSettingsController.php +++ b/settings/Controller/AppSettingsController.php @@ -143,6 +143,7 @@ class AppSettingsController extends Controller { $params['category'] = $category; $params['appstoreEnabled'] = $this->config->getSystemValue('appstoreenabled', true) === true; $params['urlGenerator'] = $this->urlGenerator; + $params['updateCount'] = count($this->getAppsWithUpdates()); $this->navigationManager->setActiveEntry('core_apps'); $templateResponse = new TemplateResponse($this->appName, 'apps', $params, 'user'); @@ -158,14 +159,7 @@ class AppSettingsController extends Controller { private function getAllCategories() { $currentLanguage = substr($this->l10nFactory->findLanguage(), 0, 2); - $updateCount = count($this->getAppsWithUpdates()); - $formattedCategories = [ - ['id' => self::CAT_ALL_INSTALLED, 'ident' => 'installed', 'displayName' => (string)$this->l10n->t('Your apps')], - ['id' => self::CAT_UPDATES, 'ident' => 'updates', 'displayName' => (string)$this->l10n->t('Updates'), 'counter' => $updateCount], - ['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')], - ]; + $formattedCategories = []; $categories = $this->categoryFetcher->get(); foreach($categories as $category) { $formattedCategories[] = [ -- cgit v1.2.3 From 05b60ee17080b4f9866b82e00e72d52d3ba02338 Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Thu, 17 May 2018 22:42:45 +0200 Subject: Fix category navigation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/routes.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/settings/routes.php b/settings/routes.php index a21a0f0789d..29db7c06d4e 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -49,6 +49,8 @@ $application->registerRoutes($this, [ ['name' => 'AppSettings#listCategories', 'url' => '/settings/apps/categories', 'verb' => 'GET'], ['name' => 'AppSettings#viewApps', 'url' => '/settings/apps', 'verb' => 'GET'], ['name' => 'AppSettings#listApps', 'url' => '/settings/apps/list', 'verb' => 'GET'], + + ['name' => 'AppSettings#viewApps', 'url' => '/settings/apps/{category}', 'verb' => 'GET', 'defaults' => ['category' => '']], ['name' => 'AppSettings#enableApp', 'url' => '/settings/apps/enable/{appId}', 'verb' => 'GET'], ['name' => 'AppSettings#enableApps', 'url' => '/settings/apps/enable', 'verb' => 'POST'], ['name' => 'AppSettings#disableApp', 'url' => '/settings/apps/disable/{appId}', 'verb' => 'GET'], -- cgit v1.2.3 From 23462275ba4c694a43325554afec851071e1a01a Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Thu, 17 May 2018 22:43:05 +0200 Subject: Add AppStore Manager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/private/App/AppStore/Manager.php | 38 ++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 lib/private/App/AppStore/Manager.php diff --git a/lib/private/App/AppStore/Manager.php b/lib/private/App/AppStore/Manager.php new file mode 100644 index 00000000000..1c7f09a817e --- /dev/null +++ b/lib/private/App/AppStore/Manager.php @@ -0,0 +1,38 @@ + + * + * @author Julius Härtl + * + * @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; + + +use OC\App\AppStore\Fetcher\AppFetcher; + +class Manager { + + public function __construct(AppFetcher $appFetcher) { + $this->apps = $appFetcher->get(); + } + + public function getApp(string $appId) { + return $this->apps; + } +} \ No newline at end of file -- cgit v1.2.3 From 3b39e9c97196a3141a3087cce4b24e1784879c6f Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Tue, 22 May 2018 08:57:09 +0200 Subject: More app management implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/src/components/appList.vue | 99 +++++++++------- settings/src/components/appList/appItem.vue | 171 ++++++++++++++++++++++++++++ settings/src/store/api.js | 2 +- settings/src/store/apps.js | 42 ++++++- settings/src/views/Apps.vue | 30 ++++- 5 files changed, 300 insertions(+), 44 deletions(-) create mode 100644 settings/src/components/appList/appItem.vue diff --git a/settings/src/components/appList.vue b/settings/src/components/appList.vue index 8dc7fede01d..b446b9c8a61 100644 --- a/settings/src/components/appList.vue +++ b/settings/src/components/appList.vue @@ -21,7 +21,7 @@ --> diff --git a/settings/src/store/api.js b/settings/src/store/api.js index 7501a7bb4cc..059c9a11ef8 100644 --- a/settings/src/store/api.js +++ b/settings/src/store/api.js @@ -71,7 +71,7 @@ export default { waitForpassword(); }); }, - get(url) { + get(url, data) { return axios.get(sanitize(url), tokenHeaders) .then((response) => Promise.resolve(response)) .catch((error) => Promise.reject(error)); diff --git a/settings/src/store/apps.js b/settings/src/store/apps.js index d9888465dd6..d79540ad525 100644 --- a/settings/src/store/apps.js +++ b/settings/src/store/apps.js @@ -21,6 +21,7 @@ */ import api from './api'; +import axios from 'axios/index'; const state = { apps: [], @@ -51,6 +52,16 @@ const mutations = { state.apps = apps; }, + enableApp(state, {appId, groups}) { + state.apps.find(app => app.id === appId).active = true; + state.apps.find(app => app.id === appId).groups = groups; + console.log(state.apps.find(app => app.id === appId).groups); + }, + + disableApp(state, appId) { + state.apps.find(app => app.id === appId).active = false; + }, + reset(state) { state.apps = []; state.categories = []; @@ -72,6 +83,36 @@ const getters = { const actions = { + enableApp(context, { appId, groups }) { + return api.requireAdmin().then((response) => { + return api.post(OC.generateUrl(`settings/apps/enable/${appId}`), { + groups: groups + }) + .then((response) => { + context.commit('enableApp', {appId: appId, groups: groups}); + return true; + }) + .catch((error) => {throw error;}) + }).catch((error) => context.commit('API_FAILURE', { appId, error })); + + }, + disableApp(context, { appId }) { + return api.requireAdmin().then((response) => { + return api.get(OC.generateUrl(`settings/apps/disable/${appId}`)) + .then((response) => { + context.commit('disableApp', appId); + return true; + }) + .catch((error) => {throw error;}) + }).catch((error) => context.commit('API_FAILURE', { appId, error })); + }, + installApp(appId) { + + }, + uninstallApp(appId) { + + }, + getApps(context, { category }) { return api.get(OC.generateUrl(`settings/apps/list?category=${category}`)) .then((response) => { @@ -79,7 +120,6 @@ const actions = { return true; }) .catch((error) => context.commit('API_FAILURE', error)) - }, getCategories(context) { diff --git a/settings/src/views/Apps.vue b/settings/src/views/Apps.vue index eac9bec7527..17b54415979 100644 --- a/settings/src/views/Apps.vue +++ b/settings/src/views/Apps.vue @@ -23,7 +23,13 @@ @@ -41,13 +47,23 @@ Vue.use(VueLocalStorage) export default { name: 'Apps', - props: ['category'], + props: { + category: { + type: String, + default: 'installed', + }, + id: { + type: String, + default: '', + } + }, components: { appNavigation, appList, }, beforeMount() { this.$store.dispatch('getCategories'); + this.$store.dispatch('getApps', { category: this.category }); this.$store.commit('setUpdateCount', this.$store.getters.getServerData.updateCount) }, data() { @@ -55,7 +71,17 @@ export default { } }, + watch: { + // watch url change and group select + category: function (val, old) { + this.$store.commit('resetApps'); + this.$store.dispatch('getApps', { category: this.category }); + } + }, computed: { + currentApp() { + return this.apps.find(app => app.id === this.id ); + }, categories() { return this.$store.getters.getCategories; }, -- cgit v1.2.3 From bb50ee08e94b9c466b0d73547e326394f1424c9c Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Tue, 22 May 2018 08:58:07 +0200 Subject: Fix app enabling for groups and allow requesting all apps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/Controller/AppSettingsController.php | 21 ++++++++++++--------- settings/routes.php | 3 +++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/settings/Controller/AppSettingsController.php b/settings/Controller/AppSettingsController.php index 413e54d6ce4..98835dc583e 100644 --- a/settings/Controller/AppSettingsController.php +++ b/settings/Controller/AppSettingsController.php @@ -187,7 +187,7 @@ class AppSettingsController extends Controller { * @param string $requestedCategory * @return array */ - private function getAppsForCategory($requestedCategory) { + private function getAppsForCategory($requestedCategory = '') { $versionParser = new VersionParser(); $formattedApps = []; $apps = $this->appFetcher->get(); @@ -197,14 +197,16 @@ class AppSettingsController extends Controller { } // Skip all apps not in the requested category - $isInCategory = false; - foreach($app['categories'] as $category) { - if($category === $requestedCategory) { - $isInCategory = true; + if ($requestedCategory !== '') { + $isInCategory = false; + foreach($app['categories'] as $category) { + if($category === $requestedCategory) { + $isInCategory = true; + } + } + if(!$isInCategory) { + continue; } - } - if(!$isInCategory) { - continue; } $nextCloudVersion = $versionParser->getVersion($app['releases'][0]['rawPlatformVersionSpec']); @@ -496,9 +498,10 @@ class AppSettingsController extends Controller { * @PasswordConfirmationRequired * * @param string $appId + * @param array $groups * @return JSONResponse */ - public function enableApp(string $appId, array $groups): JSONResponse { + public function enableApp(string $appId, array $groups = []): JSONResponse { return $this->enableApps([$appId], $groups); } diff --git a/settings/routes.php b/settings/routes.php index 29db7c06d4e..e0c0eb3d9bf 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -51,7 +51,10 @@ $application->registerRoutes($this, [ ['name' => 'AppSettings#listApps', 'url' => '/settings/apps/list', 'verb' => 'GET'], ['name' => 'AppSettings#viewApps', 'url' => '/settings/apps/{category}', 'verb' => 'GET', 'defaults' => ['category' => '']], + ['name' => 'AppSettings#viewApps', 'url' => '/settings/apps/{category}/{id}', 'verb' => 'GET', 'defaults' => ['category' => '', 'id' => '']], + ['name' => 'AppSettings#enableApp', 'url' => '/settings/apps/enable/{appId}', 'verb' => 'GET'], + ['name' => 'AppSettings#enableApp', 'url' => '/settings/apps/enable/{appId}', 'verb' => 'POST'], ['name' => 'AppSettings#enableApps', 'url' => '/settings/apps/enable', 'verb' => 'POST'], ['name' => 'AppSettings#disableApp', 'url' => '/settings/apps/disable/{appId}', 'verb' => 'GET'], ['name' => 'AppSettings#disableApps', 'url' => '/settings/apps/disable', 'verb' => 'POST'], -- cgit v1.2.3 From a8a655b1c0a393f873bff89e55d8a26697aa9a59 Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Tue, 22 May 2018 08:58:35 +0200 Subject: Add group fetching to vuex group store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/src/store/users.js | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/settings/src/store/users.js b/settings/src/store/users.js index 5fac0c6f327..d3acb2ce553 100644 --- a/settings/src/store/users.js +++ b/settings/src/store/users.js @@ -48,12 +48,12 @@ const mutations = { state.groups = orderGroups(state.groups, state.orderBy); }, - addGroup(state, gid) { + addGroup(state, {gid, displayName}) { try { // extend group to default values let group = Object.assign({}, defaults.group, { id: gid, - name: gid + name: displayName, }); state.groups.push(group); state.groups = orderGroups(state.groups, state.orderBy); @@ -197,6 +197,21 @@ const actions = { .catch((error) => context.commit('API_FAILURE', error)); }, + getGroups(context) { /* { offset, limit, search } */ + //search = typeof search === 'string' ? search : ''; + return api.get(OC.linkToOCS(`cloud/groups`, 2)) /* ?offset=${offset}&limit=${limit}&search=${search}` */ + .then((response) => { + if (Object.keys(response.data.ocs.data.groups).length > 0) { + response.data.ocs.data.groups.forEach(function(group) { + context.commit('addGroup', {gid: group, displayName: group}); + }); + return true; + } + return false; + }) + .catch((error) => context.commit('API_FAILURE', error)); + }, + /** * Get all users with full details * @@ -253,7 +268,7 @@ const actions = { addGroup(context, gid) { return api.requireAdmin().then((response) => { return api.post(OC.linkToOCS(`cloud/groups`, 2), {groupid: gid}) - .then((response) => context.commit('addGroup', gid)) + .then((response) => context.commit('addGroup', {gid: gid, displayName: gid})) .catch((error) => {throw error;}); }).catch((error) => { context.commit('API_FAILURE', { gid, error }); @@ -450,4 +465,4 @@ const actions = { } }; -export default { state, mutations, getters, actions }; \ No newline at end of file +export default { state, mutations, getters, actions }; -- cgit v1.2.3 From eccc391bdac3d900bb95ba3d5304ad9e61af629b Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Wed, 23 May 2018 19:50:42 +0200 Subject: Load marked and return proper Template with CSP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/Controller/AppSettingsController.php | 4 ++-- settings/src/components/appList/appScore.vue | 0 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 settings/src/components/appList/appScore.vue diff --git a/settings/Controller/AppSettingsController.php b/settings/Controller/AppSettingsController.php index 98835dc583e..8e72b5ab2db 100644 --- a/settings/Controller/AppSettingsController.php +++ b/settings/Controller/AppSettingsController.php @@ -139,6 +139,7 @@ class AppSettingsController extends Controller { $category = 'installed'; } + \OC_Util::addVendorScript('core', 'marked/marked.min'); $params = []; $params['category'] = $category; $params['appstoreEnabled'] = $this->config->getSystemValue('appstoreenabled', true) === true; @@ -146,12 +147,11 @@ class AppSettingsController extends Controller { $params['updateCount'] = count($this->getAppsWithUpdates()); $this->navigationManager->setActiveEntry('core_apps'); - $templateResponse = new TemplateResponse($this->appName, 'apps', $params, 'user'); + $templateResponse = new TemplateResponse('settings', 'settings', ['serverData' => $params]); $policy = new ContentSecurityPolicy(); $policy->addAllowedImageDomain('https://usercontent.apps.nextcloud.com'); $templateResponse->setContentSecurityPolicy($policy); - return new TemplateResponse('settings', 'settings', ['serverData' => $params]); return $templateResponse; } diff --git a/settings/src/components/appList/appScore.vue b/settings/src/components/appList/appScore.vue new file mode 100644 index 00000000000..e69de29bb2d -- cgit v1.2.3 From d7b928fd9b688079f175e596f06f16199dfd0309 Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Wed, 23 May 2018 19:51:22 +0200 Subject: Add install/remove to the new controller methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/Controller/AppSettingsController.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/settings/Controller/AppSettingsController.php b/settings/Controller/AppSettingsController.php index 8e72b5ab2db..5aaee1871db 100644 --- a/settings/Controller/AppSettingsController.php +++ b/settings/Controller/AppSettingsController.php @@ -521,6 +521,18 @@ class AppSettingsController extends Controller { foreach ($appIds as $appId) { $appId = OC_App::cleanAppId($appId); + + // Check if app is already downloaded + /** @var Installer $installer */ + $installer = \OC::$server->query(Installer::class); + $isDownloaded = $installer->isDownloaded($appId); + + if(!$isDownloaded) { + $installer->downloadApp($appId); + } + + $installer->installApp($appId); + if (count($groups) > 0) { $this->appManager->enableAppForGroups($appId, $this->getGroupList($groups)); } else { @@ -575,7 +587,9 @@ class AppSettingsController extends Controller { */ public function uninstallApp(string $appId): JSONResponse { $appId = OC_App::cleanAppId($appId); - $result = OC_App::removeApp($appId); + /** @var Installer $installer */ + $installer = \OC::$server->query(\OC\Installer::class); + $result = $installer->removeApp($appId); if($result !== false) { // FIXME: Clear the cache - move that into some sane helper method \OC::$server->getMemCacheFactory()->createDistributed('settings')->remove('listApps-0'); -- cgit v1.2.3 From 7fc2a29c22f8f9ff8688eb9217f2a88e49a28801 Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Wed, 23 May 2018 19:51:57 +0200 Subject: Implement app details in sidebar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/css/settings.scss | 19 ++- settings/src/components/appDetails.vue | 242 +++++++++++---------------- settings/src/components/appList.vue | 68 ++++++-- settings/src/components/appList/appItem.vue | 66 +++++--- settings/src/components/appList/appScore.vue | 38 +++++ settings/src/store/api.js | 2 +- settings/src/store/apps.js | 81 +++++++-- settings/src/views/Apps.vue | 29 +++- 8 files changed, 347 insertions(+), 198 deletions(-) diff --git a/settings/css/settings.scss b/settings/css/settings.scss index b200a4932cb..14e502551f7 100644 --- a/settings/css/settings.scss +++ b/settings/css/settings.scss @@ -756,6 +756,23 @@ span.version { opacity: .5; } +.app-settings-content { + #searchresults { + display: none; + } +} +#apps-list.store { + .app-name { + display: block; + } +} + +#app-sidebar #app-details-view { + .app-description p { + margin-bottom: 10px; + } +} + @media (min-width: 1601px) { #apps-list .section { width: 22%; @@ -946,8 +963,6 @@ span.version { height: 64px; opacity: .1; } - position: relative; - height: 100%; display: flex; flex-wrap: wrap; align-content: flex-start; diff --git a/settings/src/components/appDetails.vue b/settings/src/components/appDetails.vue index d007555dd5b..9192c68a868 100644 --- a/settings/src/components/appDetails.vue +++ b/settings/src/components/appDetails.vue @@ -21,167 +21,123 @@ --> diff --git a/settings/src/components/appList.vue b/settings/src/components/appList.vue index b446b9c8a61..08809cf9b2b 100644 --- a/settings/src/components/appList.vue +++ b/settings/src/components/appList.vue @@ -21,19 +21,43 @@ --> @@ -43,7 +67,7 @@ import Multiselect from 'vue-multiselect'; export default { name: 'appList', - props: ['category', 'app'], + props: ['category', 'app', 'search'], components: { Multiselect, appItem @@ -65,14 +89,28 @@ export default { }, computed: { apps() { - return this.$store.getters.getApps; + return this.$store.getters.getApps + .filter(app => app.name.toLowerCase().search(this.search.toLowerCase()) !== -1) + }, + searchApps() { + return this.$store.getters.getAllApps + .filter(app => app.name.toLowerCase().search(this.search.toLowerCase()) !== -1) }, groups() { console.log(this.$store.getters.getGroups); - return this.$store.getters.getGroups; - /*.filter(group => group.id !== 'disabled') - .sort((a, b) => a.name.localeCompare(b.name));*/ + return this.$store.getters.getGroups + .filter(group => group.id !== 'disabled') + .sort((a, b) => a.name.localeCompare(b.name)); }, + useAppStoreView() { + return !this.useListView && !this.useBundleView; + }, + useListView() { + return (this.category === 'installed' || this.category === 'enabled' || this.category === 'disabled' || this.category === 'updates'); + }, + useBundleView() { + return (this.category === 'app-bundles'); + } }, methods: { prefix(prefix, content) { diff --git a/settings/src/components/appList/appItem.vue b/settings/src/components/appList/appItem.vue index d72f69ff267..4b65aed0ca8 100644 --- a/settings/src/components/appList/appItem.vue +++ b/settings/src/components/appList/appItem.vue @@ -21,23 +21,26 @@ --> \ No newline at end of file diff --git a/settings/src/store/api.js b/settings/src/store/api.js index 059c9a11ef8..7501a7bb4cc 100644 --- a/settings/src/store/api.js +++ b/settings/src/store/api.js @@ -71,7 +71,7 @@ export default { waitForpassword(); }); }, - get(url, data) { + get(url) { return axios.get(sanitize(url), tokenHeaders) .then((response) => Promise.resolve(response)) .catch((error) => Promise.reject(error)); diff --git a/settings/src/store/apps.js b/settings/src/store/apps.js index d79540ad525..cc859c96845 100644 --- a/settings/src/store/apps.js +++ b/settings/src/store/apps.js @@ -25,11 +25,18 @@ import axios from 'axios/index'; const state = { apps: [], + allApps: [], categories: [], updateCount: 0 }; const mutations = { + + APPS_API_FAILURE(state, error) { + OC.Notification.showHtml(t('settings','An error occured during the request. Unable to proceed.')+'
'+error.error.response.data.data.message, {timeout: 7}); + console.log(state, error); + }, + initCategories(state, {categories, updateCount}) { state.categories = categories; state.updateCount = updateCount; @@ -52,16 +59,36 @@ const mutations = { state.apps = apps; }, + setAllApps(state, apps) { + state.allApps = apps; + }, + enableApp(state, {appId, groups}) { - state.apps.find(app => app.id === appId).active = true; - state.apps.find(app => app.id === appId).groups = groups; - console.log(state.apps.find(app => app.id === appId).groups); + let app = state.apps.find(app => app.id === appId); + app.active = true; + app.groups = groups; }, disableApp(state, appId) { + let app = state.apps.find(app => app.id === appId); + app.active = false; + app.groups = []; + if (app.removable) { + app.canUnInstall = true; + } + }, + + uninstallApp(state, appId) { state.apps.find(app => app.id === appId).active = false; + state.apps.find(app => app.id === appId).groups = []; + state.apps.find(app => app.id === appId).needsDownload = true; + state.apps.find(app => app.id === appId).canUnInstall = false; + state.apps.find(app => app.id === appId).canInstall = true; }, + resetApps(state) { + state.apps = []; + }, reset(state) { state.apps = []; state.categories = []; @@ -74,7 +101,18 @@ const getters = { return state.categories; }, getApps(state) { - return state.apps; + return state.apps.concat([]).sort(function (a, b) { + if (a.active !== b.active) { + return (a.active ? -1 : 1) + } + if (a.update !== b.update) { + return (a.update ? -1 : 1) + } + return OC.Util.naturalSortCompare(a.name, b.name); + }); + }, + getAllApps(state) { + return state.allApps; }, getUpdateCount(state) { return state.updateCount; @@ -92,7 +130,7 @@ const actions = { context.commit('enableApp', {appId: appId, groups: groups}); return true; }) - .catch((error) => {throw error;}) + .catch((error) => context.commit('APPS_API_FAILURE', { appId, error })) }).catch((error) => context.commit('API_FAILURE', { appId, error })); }, @@ -103,14 +141,28 @@ const actions = { context.commit('disableApp', appId); return true; }) - .catch((error) => {throw error;}) + .catch((error) => context.commit('APPS_API_FAILURE', { appId, error })) }).catch((error) => context.commit('API_FAILURE', { appId, error })); }, - installApp(appId) { - + installApp(context, { appId }) { + return api.requireAdmin().then((response) => { + return api.get(OC.generateUrl(`settings/apps/enable/${appId}`)) + .then((response) => { + context.commit('enableApp', appId); + return true; + }) + .catch((error) => context.commit('APPS_API_FAILURE', { appId, error })) + }).catch((error) => context.commit('API_FAILURE', { appId, error })); }, - uninstallApp(appId) { - + uninstallApp(context, { appId }) { + return api.requireAdmin().then((response) => { + return api.get(OC.generateUrl(`settings/apps/uninstall/${appId}`)) + .then((response) => { + context.commit('uninstallApp', appId); + return true; + }) + .catch((error) => context.commit('APPS_API_FAILURE', { appId, error })) + }).catch((error) => context.commit('API_FAILURE', { appId, error })); }, getApps(context, { category }) { @@ -122,6 +174,15 @@ const actions = { .catch((error) => context.commit('API_FAILURE', error)) }, + getAllApps(context) { + return api.get(OC.generateUrl(`settings/apps/list`)) + .then((response) => { + context.commit('setAllApps', response.data.apps); + return true; + }) + .catch((error) => context.commit('API_FAILURE', error)) + }, + getCategories(context) { return api.get(OC.generateUrl('settings/apps/categories')) .then((response) => { diff --git a/settings/src/views/Apps.vue b/settings/src/views/Apps.vue index 17b54415979..7dbf9e887d8 100644 --- a/settings/src/views/Apps.vue +++ b/settings/src/views/Apps.vue @@ -23,12 +23,10 @@ @@ -41,6 +39,7 @@ import Vue from 'vue'; import VueLocalStorage from 'vue-localstorage' import Multiselect from 'vue-multiselect'; import api from '../store/api'; +import AppDetails from '../components/appDetails'; Vue.use(VueLocalStorage) Vue.use(VueLocalStorage) @@ -58,17 +57,33 @@ export default { } }, components: { + AppDetails, appNavigation, appList, }, + methods: { + setSearch(search) { + this.search = search; + } + }, beforeMount() { this.$store.dispatch('getCategories'); - this.$store.dispatch('getApps', { category: this.category }); + this.$store.dispatch('getApps', {category: this.category}); + this.$store.dispatch('getAllApps'); this.$store.commit('setUpdateCount', this.$store.getters.getServerData.updateCount) + console.log(this.$store.getters.getServerData.updateCount); + }, + mounted() { + // TODO: remove jQuery once we have a proper standardisation of the search + $('#searchbox').show(); + let self = this; + $('#searchbox').change(function(e) { + self.setSearch($('#searchbox').val()); + }); }, data() { return { - + search: '' } }, watch: { -- cgit v1.2.3 From 0a7ab6f66f46bbae56bad10740bf9960179bf57e Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Wed, 23 May 2018 19:52:19 +0200 Subject: Reorder routes to avoid conflicts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/routes.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/settings/routes.php b/settings/routes.php index e0c0eb3d9bf..bd6713a7c16 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -46,13 +46,10 @@ $application->registerRoutes($this, [ ['name' => 'MailSettings#storeCredentials', 'url' => '/settings/admin/mailsettings/credentials', 'verb' => 'POST'], ['name' => 'MailSettings#sendTestMail', 'url' => '/settings/admin/mailtest', 'verb' => 'POST'], ['name' => 'Encryption#startMigration', 'url' => '/settings/admin/startmigration', 'verb' => 'POST'], + ['name' => 'AppSettings#listCategories', 'url' => '/settings/apps/categories', 'verb' => 'GET'], ['name' => 'AppSettings#viewApps', 'url' => '/settings/apps', 'verb' => 'GET'], ['name' => 'AppSettings#listApps', 'url' => '/settings/apps/list', 'verb' => 'GET'], - - ['name' => 'AppSettings#viewApps', 'url' => '/settings/apps/{category}', 'verb' => 'GET', 'defaults' => ['category' => '']], - ['name' => 'AppSettings#viewApps', 'url' => '/settings/apps/{category}/{id}', 'verb' => 'GET', 'defaults' => ['category' => '', 'id' => '']], - ['name' => 'AppSettings#enableApp', 'url' => '/settings/apps/enable/{appId}', 'verb' => 'GET'], ['name' => 'AppSettings#enableApp', 'url' => '/settings/apps/enable/{appId}', 'verb' => 'POST'], ['name' => 'AppSettings#enableApps', 'url' => '/settings/apps/enable', 'verb' => 'POST'], @@ -60,6 +57,9 @@ $application->registerRoutes($this, [ ['name' => 'AppSettings#disableApps', 'url' => '/settings/apps/disable', 'verb' => 'POST'], ['name' => 'AppSettings#updateApp', 'url' => '/settings/apps/update/{appId}', 'verb' => 'GET'], ['name' => 'AppSettings#uninstallApp', 'url' => '/settings/apps/uninstall/{appId}', 'verb' => 'GET'], + ['name' => 'AppSettings#viewApps', 'url' => '/settings/apps/{category}', 'verb' => 'GET', 'defaults' => ['category' => '']], + ['name' => 'AppSettings#viewApps', 'url' => '/settings/apps/{category}/{id}', 'verb' => 'GET', 'defaults' => ['category' => '', 'id' => '']], + ['name' => 'Users#setDisplayName', 'url' => '/settings/users/{username}/displayName', 'verb' => 'POST'], ['name' => 'Users#setEMailAddress', 'url' => '/settings/users/{id}/mailAddress', 'verb' => 'PUT'], ['name' => 'Users#setUserSettings', 'url' => '/settings/users/{username}/settings', 'verb' => 'PUT'], -- cgit v1.2.3 From c7f145cce125153949a6356e8f5b6cfa997b0c35 Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Wed, 23 May 2018 20:01:30 +0200 Subject: Remove old template code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/templates/apps.php | 213 -------------------------------------------- 1 file changed, 213 deletions(-) delete mode 100644 settings/templates/apps.php diff --git a/settings/templates/apps.php b/settings/templates/apps.php deleted file mode 100644 index 3b22e99a015..00000000000 --- a/settings/templates/apps.php +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - - -
-
    - -
-
-
-
- -
-- cgit v1.2.3 From 492b76935c29b931c991d978b6883eb2d072cf43 Mon Sep 17 00:00:00 2001 From: Julius Härtl Date: Fri, 25 May 2018 13:24:51 +0200 Subject: Add link to developer docs and fix view if appstore is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- settings/Controller/AppSettingsController.php | 2 ++ settings/src/components/appDetails.vue | 6 +++--- settings/src/components/appList/appItem.vue | 5 +++-- settings/src/views/Apps.vue | 15 +++++++++++++++ 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/settings/Controller/AppSettingsController.php b/settings/Controller/AppSettingsController.php index 5aaee1871db..ac6e5d1850d 100644 --- a/settings/Controller/AppSettingsController.php +++ b/settings/Controller/AppSettingsController.php @@ -145,6 +145,7 @@ class AppSettingsController extends Controller { $params['appstoreEnabled'] = $this->config->getSystemValue('appstoreenabled', true) === true; $params['urlGenerator'] = $this->urlGenerator; $params['updateCount'] = count($this->getAppsWithUpdates()); + $params['developerDocumentation'] = $this->urlGenerator->linkToDocs('developer-manual'); $this->navigationManager->setActiveEntry('core_apps'); $templateResponse = new TemplateResponse('settings', 'settings', ['serverData' => $params]); @@ -255,6 +256,7 @@ class AppSettingsController extends Controller { 'id' => $app['id'], 'name' => isset($app['translations'][$currentLanguage]['name']) ? $app['translations'][$currentLanguage]['name'] : $app['translations']['en']['name'], 'description' => isset($app['translations'][$currentLanguage]['description']) ? $app['translations'][$currentLanguage]['description'] : $app['translations']['en']['description'], + 'summary' => isset($app['translations'][$currentLanguage]['summary']) ? $app['translations'][$currentLanguage]['summary'] : $app['translations']['en']['summary'], 'license' => $app['releases'][0]['licenses'], 'author' => $authors, 'shipped' => false, diff --git a/settings/src/components/appDetails.vue b/settings/src/components/appDetails.vue index 9192c68a868..5518fd04860 100644 --- a/settings/src/components/appDetails.vue +++ b/settings/src/components/appDetails.vue @@ -41,9 +41,9 @@ {{ t('settings', 'Visit website') }} ↗ {{ t('settings', 'Report a bug') }} ↗ - {{ t('settings', 'User documentation') }} ↗ - {{ t('settings', 'Admin documentation') }} ↗ - {{ t('settings', 'Developer documentation') }} ↗ + {{ t('settings', 'User documentation') }} ↗ + {{ t('settings', 'Admin documentation') }} ↗ + {{ t('settings', 'Developer documentation') }} ↗

    diff --git a/settings/src/components/appList/appItem.vue b/settings/src/components/appList/appItem.vue index 4b65aed0ca8..13325f6462d 100644 --- a/settings/src/components/appList/appItem.vue +++ b/settings/src/components/appList/appItem.vue @@ -23,8 +23,9 @@