diff options
author | Christoph Wurst <christoph@winzerhof-wurst.at> | 2019-09-17 16:33:27 +0200 |
---|---|---|
committer | npmbuildbot[bot] <npmbuildbot[bot]@users.noreply.github.com> | 2019-09-28 09:39:28 +0000 |
commit | de6940352a2f708376219a89ec84a8e6d25ca59e (patch) | |
tree | 459bacfc183b24d611be1877fbe22bbcd4efb1d6 /apps/settings/src/store | |
parent | c8cd607681ac128228f57114ce14dd67ab05de04 (diff) | |
download | nextcloud-server-de6940352a2f708376219a89ec84a8e6d25ca59e.tar.gz nextcloud-server-de6940352a2f708376219a89ec84a8e6d25ca59e.zip |
Move settings to an app
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
Signed-off-by: npmbuildbot[bot] <npmbuildbot[bot]@users.noreply.github.com>
Diffstat (limited to 'apps/settings/src/store')
-rw-r--r-- | apps/settings/src/store/admin-security.js | 63 | ||||
-rw-r--r-- | apps/settings/src/store/api.js | 81 | ||||
-rw-r--r-- | apps/settings/src/store/apps.js | 327 | ||||
-rw-r--r-- | apps/settings/src/store/index.js | 57 | ||||
-rw-r--r-- | apps/settings/src/store/oc.js | 47 | ||||
-rw-r--r-- | apps/settings/src/store/settings.js | 40 | ||||
-rw-r--r-- | apps/settings/src/store/users.js | 532 |
7 files changed, 1147 insertions, 0 deletions
diff --git a/apps/settings/src/store/admin-security.js b/apps/settings/src/store/admin-security.js new file mode 100644 index 00000000000..997aab2af58 --- /dev/null +++ b/apps/settings/src/store/admin-security.js @@ -0,0 +1,63 @@ +/* + * @copyright 2019 Roeland Jago Douma <roeland@famdouma.nl> + * + * @author 2019 Roeland Jago Douma <roeland@famdouma.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +import Vue from 'vue' +import Vuex from 'vuex' + +Vue.use(Vuex) + +export const mutations = { + setEnforced(state, enabled) { + Vue.set(state, 'enforced', enabled) + }, + setEnforcedGroups(state, total) { + Vue.set(state, 'enforcedGroups', total) + }, + setExcludedGroups(state, used) { + Vue.set(state, 'excludedGroups', used) + } +} + +export const actions = { + save ({commit}, ) { + commit('setEnabled', false); + + return generateCodes() + .then(({codes, state}) => { + commit('setEnabled', state.enabled); + commit('setTotal', state.total); + commit('setUsed', state.used); + commit('setCodes', codes); + return true; + }); + } +} + +export default new Vuex.Store({ + strict: process.env.NODE_ENV !== 'production', + state: { + enforced: false, + enforcedGroups: [], + excludedGroups: [], + }, + mutations, + actions +}) diff --git a/apps/settings/src/store/api.js b/apps/settings/src/store/api.js new file mode 100644 index 00000000000..185e80253a3 --- /dev/null +++ b/apps/settings/src/store/api.js @@ -0,0 +1,81 @@ +/** + * @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +import axios from 'nextcloud-axios' +import confirmPassword from 'nextcloud-password-confirmation' + +const sanitize = function(url) { + return url.replace(/\/$/, ''); // Remove last url slash +}; + +export default { + + /** + * This Promise is used to chain a request that require an admin password confirmation + * Since chaining Promise have a very precise behavior concerning catch and then, + * you'll need to be careful when using it. + * e.g + * // store + * action(context) { + * return api.requireAdmin().then((response) => { + * return api.get('url') + * .then((response) => {API success}) + * .catch((error) => {API failure}); + * }).catch((error) => {requireAdmin failure}); + * } + * // vue + * this.$store.dispatch('action').then(() => {always executed}) + * + * Since Promise.then().catch().then() will always execute the last then + * this.$store.dispatch('action').then will always be executed + * + * If you want requireAdmin failure to also catch the API request failure + * you will need to throw a new error in the api.get.catch() + * + * e.g + * api.requireAdmin().then((response) => { + * api.get('url') + * .then((response) => {API success}) + * .catch((error) => {throw error;}); + * }).catch((error) => {requireAdmin OR API failure}); + * + * @returns {Promise} + */ + requireAdmin() { + return confirmPassword(); + }, + get(url) { + return axios.get(sanitize(url)); + }, + post(url, data) { + return axios.post(sanitize(url), data); + }, + patch(url, data) { + return axios.patch(sanitize(url), data); + }, + put(url, data) { + return axios.put(sanitize(url), data); + }, + delete(url, data) { + return axios.delete(sanitize(url), { data: data }); + } +};
\ No newline at end of file diff --git a/apps/settings/src/store/apps.js b/apps/settings/src/store/apps.js new file mode 100644 index 00000000000..8074eac2e00 --- /dev/null +++ b/apps/settings/src/store/apps.js @@ -0,0 +1,327 @@ +/* + * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net> + * + * @author Julius Härtl <jus@bitgrid.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +import api from './api'; +import Vue from 'vue'; + +const state = { + apps: [], + categories: [], + updateCount: 0, + loading: {}, + loadingList: false, +}; + +const mutations = { + + APPS_API_FAILURE(state, error) { + OC.Notification.showHtml(t('settings','An error occured during the request. Unable to proceed.')+'<br>'+error.error.response.data.data.message, {timeout: 7}); + console.log(state, error); + }, + + 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; + }, + + setAllApps(state, apps) { + state.apps = apps; + }, + + setError(state, {appId, error}) { + if (!Array.isArray(appId)) { + appId = [appId]; + } + appId.forEach((_id) => { + let app = state.apps.find(app => app.id === _id); + app.error = error; + }); + }, + + clearError(state, {appId, error}) { + let app = state.apps.find(app => app.id === appId); + app.error = null; + }, + + enableApp(state, {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).installed = false; + state.apps.find(app => app.id === appId).canUnInstall = false; + state.apps.find(app => app.id === appId).canInstall = true; + }, + + updateApp(state, appId) { + let app = state.apps.find(app => app.id === appId); + let version = app.update; + app.update = null; + app.version = version; + state.updateCount--; + + }, + + resetApps(state) { + state.apps = []; + }, + reset(state) { + state.apps = []; + state.categories = []; + state.updateCount = 0; + }, + startLoading(state, id) { + if (Array.isArray(id)) { + id.forEach((_id) => { + Vue.set(state.loading, _id, true); + }) + } else { + Vue.set(state.loading, id, true); + } + }, + stopLoading(state, id) { + if (Array.isArray(id)) { + id.forEach((_id) => { + Vue.set(state.loading, _id, false); + }) + } else { + Vue.set(state.loading, id, false); + } + }, +}; + +const getters = { + loading(state) { + return function(id) { + return state.loading[id]; + } + }, + getCategories(state) { + return state.categories; + }, + getAllApps(state) { + return state.apps; + }, + getUpdateCount(state) { + return state.updateCount; + } +}; + +const actions = { + + enableApp(context, { appId, groups }) { + let apps; + if (Array.isArray(appId)) { + apps = appId; + } else { + apps = [appId]; + } + return api.requireAdmin().then((response) => { + context.commit('startLoading', apps); + context.commit('startLoading', 'install'); + return api.post(OC.generateUrl(`settings/apps/enable`), {appIds: apps, groups: groups}) + .then((response) => { + context.commit('stopLoading', apps); + context.commit('stopLoading', 'install'); + apps.forEach(_appId => { + context.commit('enableApp', {appId: _appId, groups: groups}); + }); + + // check for server health + return api.get(OC.generateUrl('apps/files')) + .then(() => { + if (response.data.update_required) { + OC.dialogs.info( + t( + 'settings', + 'The app has been enabled but needs to be updated. You will be redirected to the update page in 5 seconds.' + ), + t('settings','App update'), + function () { + window.location.reload(); + }, + true + ); + setTimeout(function() { + location.reload(); + }, 5000); + } + }) + .catch((error) => { + if (!Array.isArray(appId)) { + context.commit('setError', { + appId: apps, + error: t('settings', 'Error: This app can not be enabled because it makes the server unstable') + }); + } + }); + }) + .catch((error) => { + context.commit('stopLoading', apps); + context.commit('stopLoading', 'install'); + context.commit('setError', { + appId: apps, + error: error.response.data.data.message + }); + context.commit('APPS_API_FAILURE', { appId, error}); + }) + }).catch((error) => context.commit('API_FAILURE', { appId, error })); + }, + forceEnableApp(context, { appId, groups }) { + let apps; + if (Array.isArray(appId)) { + apps = appId; + } else { + apps = [appId]; + } + return api.requireAdmin().then(() => { + context.commit('startLoading', apps); + context.commit('startLoading', 'install'); + return api.post(OC.generateUrl(`settings/apps/force`), {appId}) + .then((response) => { + // TODO: find a cleaner solution + location.reload(); + }) + .catch((error) => { + context.commit('stopLoading', apps); + context.commit('stopLoading', 'install'); + context.commit('setError', { + appId: apps, + error: error.response.data.data.message + }); + context.commit('APPS_API_FAILURE', { appId, error}); + }) + }).catch((error) => context.commit('API_FAILURE', { appId, error })); + }, + disableApp(context, { appId }) { + let apps; + if (Array.isArray(appId)) { + apps = appId; + } else { + apps = [appId]; + } + return api.requireAdmin().then((response) => { + context.commit('startLoading', apps); + return api.post(OC.generateUrl(`settings/apps/disable`), {appIds: apps}) + .then((response) => { + context.commit('stopLoading', apps); + apps.forEach(_appId => { + context.commit('disableApp', _appId); + }); + return true; + }) + .catch((error) => { + context.commit('stopLoading', apps); + context.commit('APPS_API_FAILURE', { appId, error }) + }) + }).catch((error) => context.commit('API_FAILURE', { appId, error })); + }, + uninstallApp(context, { appId }) { + return api.requireAdmin().then((response) => { + context.commit('startLoading', appId); + return api.get(OC.generateUrl(`settings/apps/uninstall/${appId}`)) + .then((response) => { + context.commit('stopLoading', appId); + context.commit('uninstallApp', appId); + return true; + }) + .catch((error) => { + context.commit('stopLoading', appId); + context.commit('APPS_API_FAILURE', { appId, error }) + }) + }).catch((error) => context.commit('API_FAILURE', { appId, error })); + }, + + updateApp(context, { appId }) { + return api.requireAdmin().then((response) => { + context.commit('startLoading', appId); + context.commit('startLoading', 'install'); + return api.get(OC.generateUrl(`settings/apps/update/${appId}`)) + .then((response) => { + context.commit('stopLoading', 'install'); + context.commit('stopLoading', appId); + context.commit('updateApp', appId); + return true; + }) + .catch((error) => { + context.commit('stopLoading', appId); + context.commit('stopLoading', 'install'); + context.commit('APPS_API_FAILURE', { appId, error }) + }) + }).catch((error) => context.commit('API_FAILURE', { appId, error })); + }, + + getAllApps(context) { + context.commit('startLoading', 'list'); + return api.get(OC.generateUrl(`settings/apps/list`)) + .then((response) => { + context.commit('setAllApps', response.data.apps); + context.commit('stopLoading', 'list'); + return true; + }) + .catch((error) => context.commit('API_FAILURE', error)) + }, + + getCategories(context) { + context.commit('startLoading', 'categories'); + return api.get(OC.generateUrl('settings/apps/categories')) + .then((response) => { + if (response.data.length > 0) { + context.commit('appendCategories', response.data); + context.commit('stopLoading', 'categories'); + 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/apps/settings/src/store/index.js b/apps/settings/src/store/index.js new file mode 100644 index 00000000000..00bcd67db39 --- /dev/null +++ b/apps/settings/src/store/index.js @@ -0,0 +1,57 @@ +/* + * @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * @author Julius Härtl <jus@bitgrid.net> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +import Vue from 'vue'; +import Vuex from 'vuex'; +import users from './users'; +import apps from './apps'; +import settings from './settings'; +import oc from './oc'; + +Vue.use(Vuex) + +const debug = process.env.NODE_ENV !== 'production'; + +const mutations = { + API_FAILURE(state, error) { + try { + let message = error.error.response.data.ocs.meta.message; + OC.Notification.showHtml(t('settings','An error occured during the request. Unable to proceed.')+'<br>'+message, {timeout: 7}); + } catch(e) { + OC.Notification.showTemporary(t('settings','An error occured during the request. Unable to proceed.')); + } + console.log(state, error); + } +}; + +export default new Vuex.Store({ + modules: { + users, + apps, + settings, + oc + }, + strict: debug, + + mutations +}); diff --git a/apps/settings/src/store/oc.js b/apps/settings/src/store/oc.js new file mode 100644 index 00000000000..afa13fe6b18 --- /dev/null +++ b/apps/settings/src/store/oc.js @@ -0,0 +1,47 @@ +/* + * @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +import api from './api'; + +const state = {}; +const mutations = {}; +const getters = {}; +const actions = { + /** + * Set application config in database + * + * @param {Object} context + * @param {Object} options + * @param {string} options.app Application name + * @param {boolean} options.key Config key + * @param {boolean} options.value Value to set + * @returns{Promise} + */ + setAppConfig(context, {app, key, value}) { + return api.requireAdmin().then((response) => { + return api.post(OC.linkToOCS(`apps/provisioning_api/api/v1/config/apps/${app}/${key}`, 2), {value: value}) + .catch((error) => {throw error;}); + }).catch((error) => context.commit('API_FAILURE', { app, key, value, error }));; + } +}; + +export default {state, mutations, getters, actions}; diff --git a/apps/settings/src/store/settings.js b/apps/settings/src/store/settings.js new file mode 100644 index 00000000000..5f0bcfa60aa --- /dev/null +++ b/apps/settings/src/store/settings.js @@ -0,0 +1,40 @@ +/* + * @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +import api from './api'; + +const state = { + serverData: {} +}; +const mutations = { + setServerData(state, data) { + state.serverData = data; + } +}; +const getters = { + getServerData(state) { + return state.serverData; + } +}; +const actions = {}; + +export default {state, mutations, getters, actions}; diff --git a/apps/settings/src/store/users.js b/apps/settings/src/store/users.js new file mode 100644 index 00000000000..1b174b21bf4 --- /dev/null +++ b/apps/settings/src/store/users.js @@ -0,0 +1,532 @@ +/* + * @copyright Copyright (c) 2018 John Molakvoæ <skjnldsv@protonmail.com> + * + * @author John Molakvoæ <skjnldsv@protonmail.com> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +import api from './api'; + +const orderGroups = function(groups, orderBy) { + /* const SORT_USERCOUNT = 1; + * const SORT_GROUPNAME = 2; + * https://github.com/nextcloud/server/blob/208e38e84e1a07a49699aa90dc5b7272d24489f0/lib/private/Group/MetaData.php#L34 + */ + if (orderBy === 1) { + return groups.sort((a, b) => a.usercount-a.disabled < b.usercount - b.disabled); + } else { + return groups.sort((a, b) => a.name.localeCompare(b.name)); + } +}; + +const defaults = { + group: { + id: '', + name: '', + usercount: 0, + disabled: 0, + canAdd: true, + canRemove: true + } +}; + +const state = { + users: [], + groups: [], + orderBy: 1, + minPasswordLength: 0, + usersOffset: 0, + usersLimit: 25, + userCount: 0 +}; + +const mutations = { + appendUsers(state, usersObj) { + // convert obj to array + let users = state.users.concat(Object.keys(usersObj).map(userid => usersObj[userid])); + state.usersOffset += state.usersLimit; + state.users = users; + }, + setPasswordPolicyMinLength(state, length) { + state.minPasswordLength = length!=='' ? length : 0; + }, + initGroups(state, {groups, orderBy, userCount}) { + state.groups = groups.map(group => Object.assign({}, defaults.group, group)); + state.orderBy = orderBy; + state.userCount = userCount; + state.groups = orderGroups(state.groups, state.orderBy); + + }, + addGroup(state, {gid, displayName}) { + try { + if (typeof state.groups.find((group) => group.id === gid) !== 'undefined') { + return; + } + // extend group to default values + let group = Object.assign({}, defaults.group, { + id: gid, + name: displayName, + }); + state.groups.push(group); + state.groups = orderGroups(state.groups, state.orderBy); + } catch (e) { + console.log('Can\'t create group', e); + } + }, + removeGroup(state, gid) { + let groupIndex = state.groups.findIndex(groupSearch => groupSearch.id == gid); + if (groupIndex >= 0) { + state.groups.splice(groupIndex, 1); + } + }, + addUserGroup(state, { userid, gid }) { + let group = state.groups.find(groupSearch => groupSearch.id == gid); + let user = state.users.find(user => user.id == userid); + // increase count if user is enabled + if (group && user.enabled) { + group.usercount++; + } + let groups = user.groups; + groups.push(gid); + state.groups = orderGroups(state.groups, state.orderBy); + }, + removeUserGroup(state, { userid, gid }) { + let group = state.groups.find(groupSearch => groupSearch.id == gid); + let user = state.users.find(user => user.id == userid); + // lower count if user is enabled + if (group && user.enabled) { + group.usercount--; + } + let groups = user.groups; + groups.splice(groups.indexOf(gid),1); + state.groups = orderGroups(state.groups, state.orderBy); + }, + addUserSubAdmin(state, { userid, gid }) { + let groups = state.users.find(user => user.id == userid).subadmin; + groups.push(gid); + }, + removeUserSubAdmin(state, { userid, gid }) { + let groups = state.users.find(user => user.id == userid).subadmin; + groups.splice(groups.indexOf(gid),1); + }, + deleteUser(state, userid) { + let userIndex = state.users.findIndex(user => user.id == userid); + state.users.splice(userIndex, 1); + }, + addUserData(state, response) { + state.users.push(response.data.ocs.data); + }, + enableDisableUser(state, { userid, enabled }) { + let user = state.users.find(user => user.id == userid); + user.enabled = enabled; + // increment or not + state.groups.find(group => group.id == 'disabled').usercount += enabled ? -1 : 1; + state.userCount += enabled ? 1 : -1; + user.groups.forEach(group => { + // Increment disabled count + state.groups.find(groupSearch => groupSearch.id == group).disabled += enabled ? -1 : 1; + }); + }, + setUserData(state, { userid, key, value }) { + if (key === 'quota') { + let humanValue = OC.Util.computerFileSize(value); + state.users.find(user => user.id == userid)[key][key] = humanValue!==null ? humanValue : value; + } else { + state.users.find(user => user.id == userid)[key] = value; + } + }, + + /** + * Reset users list + */ + resetUsers(state) { + state.users = []; + state.usersOffset = 0; + } +}; + +const getters = { + getUsers(state) { + return state.users; + }, + getGroups(state) { + return state.groups; + }, + getSubadminGroups(state) { + // Can't be subadmin of admin or disabled + return state.groups.filter(group => group.id !== 'admin' && group.id !== 'disabled'); + }, + getPasswordPolicyMinLength(state) { + return state.minPasswordLength; + }, + getUsersOffset(state) { + return state.usersOffset; + }, + getUsersLimit(state) { + return state.usersLimit; + }, + getUserCount(state) { + return state.userCount; + } +}; + +const actions = { + + /** + * Get all users with full details + * + * @param {Object} context + * @param {Object} options + * @param {int} options.offset List offset to request + * @param {int} options.limit List number to return from offset + * @param {string} options.search Search amongst users + * @param {string} options.group Get users from group + * @returns {Promise} + */ + getUsers(context, { offset, limit, search, group }) { + search = typeof search === 'string' ? search : ''; + group = typeof group === 'string' ? group : ''; + if (group !== '') { + return api.get(OC.linkToOCS(`cloud/groups/${group}/users/details?offset=${offset}&limit=${limit}&search=${search}`, 2)) + .then((response) => { + if (Object.keys(response.data.ocs.data.users).length > 0) { + context.commit('appendUsers', response.data.ocs.data.users); + return true; + } + return false; + }) + .catch((error) => context.commit('API_FAILURE', error)); + } + + return api.get(OC.linkToOCS(`cloud/users/details?offset=${offset}&limit=${limit}&search=${search}`, 2)) + .then((response) => { + if (Object.keys(response.data.ocs.data.users).length > 0) { + context.commit('appendUsers', response.data.ocs.data.users); + return true; + } + return false; + }) + .catch((error) => context.commit('API_FAILURE', error)); + }, + + getGroups(context, { offset, limit, search }) { + search = typeof search === 'string' ? search : ''; + let limitParam = limit === -1 ? '' : `&limit=${limit}`; + return api.get(OC.linkToOCS(`cloud/groups?offset=${offset}&search=${search}${limitParam}`, 2)) + .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 + * + * @param {Object} context + * @param {Object} options + * @param {int} options.offset List offset to request + * @param {int} options.limit List number to return from offset + * @returns {Promise} + */ + getUsersFromList(context, { offset, limit, search }) { + search = typeof search === 'string' ? search : ''; + return api.get(OC.linkToOCS(`cloud/users/details?offset=${offset}&limit=${limit}&search=${search}`, 2)) + .then((response) => { + if (Object.keys(response.data.ocs.data.users).length > 0) { + context.commit('appendUsers', response.data.ocs.data.users); + return true; + } + return false; + }) + .catch((error) => context.commit('API_FAILURE', error)); + }, + + /** + * Get all users with full details from a groupid + * + * @param {Object} context + * @param {Object} options + * @param {int} options.offset List offset to request + * @param {int} options.limit List number to return from offset + * @returns {Promise} + */ + getUsersFromGroup(context, { groupid, offset, limit }) { + return api.get(OC.linkToOCS(`cloud/users/${groupid}/details?offset=${offset}&limit=${limit}`, 2)) + .then((response) => context.commit('getUsersFromList', response.data.ocs.data.users)) + .catch((error) => context.commit('API_FAILURE', error)); + }, + + + getPasswordPolicyMinLength(context) { + if(OC.getCapabilities().password_policy && OC.getCapabilities().password_policy.minLength) { + context.commit('setPasswordPolicyMinLength', OC.getCapabilities().password_policy.minLength); + return OC.getCapabilities().password_policy.minLength; + } + return false; + }, + + /** + * Add group + * + * @param {Object} context + * @param {string} gid Group id + * @returns {Promise} + */ + addGroup(context, gid) { + return api.requireAdmin().then((response) => { + return api.post(OC.linkToOCS(`cloud/groups`, 2), {groupid: gid}) + .then((response) => { + context.commit('addGroup', {gid: gid, displayName: gid}) + return {gid: gid, displayName: gid} + }) + .catch((error) => {throw error;}); + }).catch((error) => { + context.commit('API_FAILURE', { gid, error }); + // let's throw one more time to prevent the view + // from adding the user to a group that doesn't exists + throw error; + }); + }, + + /** + * Remove group + * + * @param {Object} context + * @param {string} gid Group id + * @returns {Promise} + */ + removeGroup(context, gid) { + return api.requireAdmin().then((response) => { + return api.delete(OC.linkToOCS(`cloud/groups/${gid}`, 2)) + .then((response) => context.commit('removeGroup', gid)) + .catch((error) => {throw error;}); + }).catch((error) => context.commit('API_FAILURE', { gid, error })); + }, + + /** + * Add user to group + * + * @param {Object} context + * @param {Object} options + * @param {string} options.userid User id + * @param {string} options.gid Group id + * @returns {Promise} + */ + addUserGroup(context, { userid, gid }) { + return api.requireAdmin().then((response) => { + return api.post(OC.linkToOCS(`cloud/users/${userid}/groups`, 2), { groupid: gid }) + .then((response) => context.commit('addUserGroup', { userid, gid })) + .catch((error) => {throw error;}); + }).catch((error) => context.commit('API_FAILURE', { userid, error })); + }, + + /** + * Remove user from group + * + * @param {Object} context + * @param {Object} options + * @param {string} options.userid User id + * @param {string} options.gid Group id + * @returns {Promise} + */ + removeUserGroup(context, { userid, gid }) { + return api.requireAdmin().then((response) => { + return api.delete(OC.linkToOCS(`cloud/users/${userid}/groups`, 2), { groupid: gid }) + .then((response) => context.commit('removeUserGroup', { userid, gid })) + .catch((error) => {throw error;}); + }).catch((error) => { + context.commit('API_FAILURE', { userid, error }); + // let's throw one more time to prevent + // the view from removing the user row on failure + throw error; + }); + }, + + /** + * Add user to group admin + * + * @param {Object} context + * @param {Object} options + * @param {string} options.userid User id + * @param {string} options.gid Group id + * @returns {Promise} + */ + addUserSubAdmin(context, { userid, gid }) { + return api.requireAdmin().then((response) => { + return api.post(OC.linkToOCS(`cloud/users/${userid}/subadmins`, 2), { groupid: gid }) + .then((response) => context.commit('addUserSubAdmin', { userid, gid })) + .catch((error) => {throw error;}); + }).catch((error) => context.commit('API_FAILURE', { userid, error })); + }, + + /** + * Remove user from group admin + * + * @param {Object} context + * @param {Object} options + * @param {string} options.userid User id + * @param {string} options.gid Group id + * @returns {Promise} + */ + removeUserSubAdmin(context, { userid, gid }) { + return api.requireAdmin().then((response) => { + return api.delete(OC.linkToOCS(`cloud/users/${userid}/subadmins`, 2), { groupid: gid }) + .then((response) => context.commit('removeUserSubAdmin', { userid, gid })) + .catch((error) => {throw error;}); + }).catch((error) => context.commit('API_FAILURE', { userid, error })); + }, + + /** + * Mark all user devices for remote wipe + * + * @param {Object} context + * @param {string} userid User id + * @returns {Promise} + */ + wipeUserDevices(context, userid) { + return api.requireAdmin().then((response) => { + return api.post(OC.linkToOCS(`cloud/users/${userid}/wipe`, 2)) + .catch((error) => {throw error;}); + }).catch((error) => context.commit('API_FAILURE', { userid, error })); + }, + + /** + * Delete a user + * + * @param {Object} context + * @param {string} userid User id + * @returns {Promise} + */ + deleteUser(context, userid) { + return api.requireAdmin().then((response) => { + return api.delete(OC.linkToOCS(`cloud/users/${userid}`, 2)) + .then((response) => context.commit('deleteUser', userid)) + .catch((error) => {throw error;}); + }).catch((error) => context.commit('API_FAILURE', { userid, error })); + }, + + /** + * Add a user + * + * @param {Object} context + * @param {Object} options + * @param {string} options.userid User id + * @param {string} options.password User password + * @param {string} options.displayName User display name + * @param {string} options.email User email + * @param {string} options.groups User groups + * @param {string} options.subadmin User subadmin groups + * @param {string} options.quota User email + * @returns {Promise} + */ + addUser({commit, dispatch}, { userid, password, displayName, email, groups, subadmin, quota, language }) { + return api.requireAdmin().then((response) => { + return api.post(OC.linkToOCS(`cloud/users`, 2), { userid, password, displayName, email, groups, subadmin, quota, language }) + .then((response) => dispatch('addUserData', userid || response.data.ocs.data.id)) + .catch((error) => {throw error;}); + }).catch((error) => { + commit('API_FAILURE', { userid, error }); + throw error; + }); + }, + + /** + * Get user data and commit addition + * + * @param {Object} context + * @param {string} userid User id + * @returns {Promise} + */ + addUserData(context, userid) { + return api.requireAdmin().then((response) => { + return api.get(OC.linkToOCS(`cloud/users/${userid}`, 2)) + .then((response) => context.commit('addUserData', response)) + .catch((error) => {throw error;}); + }).catch((error) => context.commit('API_FAILURE', { userid, error })); + }, + + /** Enable or disable user + * + * @param {Object} context + * @param {Object} options + * @param {string} options.userid User id + * @param {boolean} options.enabled User enablement status + * @returns {Promise} + */ + enableDisableUser(context, { userid, enabled = true }) { + let userStatus = enabled ? 'enable' : 'disable'; + return api.requireAdmin().then((response) => { + return api.put(OC.linkToOCS(`cloud/users/${userid}/${userStatus}`, 2)) + .then((response) => context.commit('enableDisableUser', { userid, enabled })) + .catch((error) => {throw error;}); + }).catch((error) => context.commit('API_FAILURE', { userid, error })); + }, + + /** + * Edit user data + * + * @param {Object} context + * @param {Object} options + * @param {string} options.userid User id + * @param {string} options.key User field to edit + * @param {string} options.value Value of the change + * @returns {Promise} + */ + setUserData(context, { userid, key, value }) { + let allowedEmpty = ['email', 'displayname']; + if (['email', 'language', 'quota', 'displayname', 'password'].indexOf(key) !== -1) { + // We allow empty email or displayname + if (typeof value === 'string' && + ( + (allowedEmpty.indexOf(key) === -1 && value.length > 0) || + allowedEmpty.indexOf(key) !== -1 + ) + ) { + return api.requireAdmin().then((response) => { + return api.put(OC.linkToOCS(`cloud/users/${userid}`, 2), { key: key, value: value }) + .then((response) => context.commit('setUserData', { userid, key, value })) + .catch((error) => {throw error;}); + }).catch((error) => context.commit('API_FAILURE', { userid, error })); + } + } + return Promise.reject(new Error('Invalid request data')); + }, + + /** + * Send welcome mail + * + * @param {Object} context + * @param {string} userid User id + * @returns {Promise} + */ + sendWelcomeMail(context, userid) { + return api.requireAdmin().then((response) => { + return api.post(OC.linkToOCS(`cloud/users/${userid}/welcome`, 2)) + .then(response => true) + .catch((error) => {throw error;}); + }).catch((error) => context.commit('API_FAILURE', { userid, error })); + } +}; + +export default { state, mutations, getters, actions }; |