441 lines
12 KiB
Vue
441 lines
12 KiB
Vue
<!--
|
|
- @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/>.
|
|
-
|
|
-->
|
|
|
|
<template>
|
|
<AppContent app-name="settings" :navigation-class="{ 'icon-loading': loadingAddGroup }">
|
|
<template #navigation>
|
|
<AppNavigationNew button-id="new-user-button" :text="t('settings','New user')" button-class="icon-add" @click="toggleNewUserMenu" />
|
|
<ul id="usergrouplist">
|
|
<AppNavigationItem v-for="item in menu" :key="item.key" :item="item" />
|
|
</ul>
|
|
<AppNavigationSettings>
|
|
<div>
|
|
<p>{{t('settings', 'Default quota:')}}</p>
|
|
<multiselect :value="defaultQuota" :options="quotaOptions"
|
|
tag-placeholder="create" :placeholder="t('settings', 'Select default quota')"
|
|
label="label" track-by="id" class="multiselect-vue"
|
|
:allowEmpty="false" :taggable="true"
|
|
@tag="validateQuota" @input="setDefaultQuota">
|
|
</multiselect>
|
|
|
|
</div>
|
|
<div>
|
|
<input type="checkbox" id="showLanguages" class="checkbox" v-model="showLanguages">
|
|
<label for="showLanguages">{{t('settings', 'Show Languages')}}</label>
|
|
</div>
|
|
<div>
|
|
<input type="checkbox" id="showLastLogin" class="checkbox" v-model="showLastLogin">
|
|
<label for="showLastLogin">{{t('settings', 'Show last login')}}</label>
|
|
</div>
|
|
<div>
|
|
<input type="checkbox" id="showUserBackend" class="checkbox" v-model="showUserBackend">
|
|
<label for="showUserBackend">{{t('settings', 'Show user backend')}}</label>
|
|
</div>
|
|
<div>
|
|
<input type="checkbox" id="showStoragePath" class="checkbox" v-model="showStoragePath">
|
|
<label for="showStoragePath">{{t('settings', 'Show storage path')}}</label>
|
|
</div>
|
|
</AppNavigationSettings>
|
|
</template>
|
|
<template #content>
|
|
<user-list :users="users" :showConfig="showConfig" :selectedGroup="selectedGroup" :externalActions="externalActions" />
|
|
</template>
|
|
</AppContent>
|
|
</template>
|
|
|
|
<script>
|
|
import {
|
|
AppContent,
|
|
AppNavigationItem,
|
|
AppNavigationNew,
|
|
AppNavigationSettings,
|
|
} from 'nextcloud-vue';
|
|
import userList from '../components/userList';
|
|
import Vue from 'vue';
|
|
import VueLocalStorage from 'vue-localstorage'
|
|
import Multiselect from 'vue-multiselect';
|
|
import api from '../store/api';
|
|
|
|
Vue.use(VueLocalStorage)
|
|
|
|
export default {
|
|
name: 'Users',
|
|
props: ['selectedGroup'],
|
|
components: {
|
|
AppContent,
|
|
AppNavigationItem,
|
|
AppNavigationNew,
|
|
AppNavigationSettings,
|
|
userList,
|
|
Multiselect,
|
|
},
|
|
beforeMount() {
|
|
this.$store.commit('initGroups', {
|
|
groups: this.$store.getters.getServerData.groups,
|
|
orderBy: this.$store.getters.getServerData.sortGroups,
|
|
userCount: this.$store.getters.getServerData.userCount
|
|
});
|
|
this.$store.dispatch('getPasswordPolicyMinLength');
|
|
},
|
|
created() {
|
|
// init the OCA.Settings.UserList object
|
|
// and add the registerAction method
|
|
Object.assign(OCA, {
|
|
Settings: {
|
|
UserList: {
|
|
registerAction: this.registerAction
|
|
}
|
|
}
|
|
});
|
|
},
|
|
data() {
|
|
return {
|
|
// default quota is set to unlimited
|
|
unlimitedQuota: {id: 'none', label: t('settings', 'Unlimited')},
|
|
// temporary value used for multiselect change
|
|
selectedQuota: false,
|
|
externalActions: [],
|
|
showAddGroupEntry: false,
|
|
loadingAddGroup: false,
|
|
showConfig: {
|
|
showStoragePath: false,
|
|
showUserBackend: false,
|
|
showLastLogin: false,
|
|
showNewUserForm: false,
|
|
showLanguages: false
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
toggleNewUserMenu() {
|
|
this.showConfig.showNewUserForm = !this.showConfig.showNewUserForm;
|
|
if (this.showConfig.showNewUserForm) {
|
|
Vue.nextTick(() => {
|
|
window.newusername.focus();
|
|
});
|
|
}
|
|
},
|
|
getLocalstorage(key) {
|
|
// force initialization
|
|
let localConfig = this.$localStorage.get(key);
|
|
// if localstorage is null, fallback to original values
|
|
this.showConfig[key] = localConfig !== null ? localConfig === 'true' : this.showConfig[key];
|
|
return this.showConfig[key];
|
|
},
|
|
setLocalStorage(key, status) {
|
|
this.showConfig[key] = status;
|
|
this.$localStorage.set(key, status);
|
|
return status;
|
|
},
|
|
removeGroup(groupid) {
|
|
let self = this;
|
|
// TODO migrate to a vue js confirm dialog component
|
|
OC.dialogs.confirm(
|
|
t('settings', 'You are about to remove the group {group}. The users will NOT be deleted.', {group: groupid}),
|
|
t('settings','Please confirm the group removal '),
|
|
function (success) {
|
|
if (success) {
|
|
self.$store.dispatch('removeGroup', groupid);
|
|
}
|
|
}
|
|
);
|
|
},
|
|
|
|
/**
|
|
* Dispatch default quota set request
|
|
*
|
|
* @param {string|Object} quota Quota in readable format '5 GB' or Object {id: '5 GB', label: '5GB'}
|
|
* @returns {string}
|
|
*/
|
|
setDefaultQuota(quota = 'none') {
|
|
this.$store.dispatch('setAppConfig', {
|
|
app: 'files',
|
|
key: 'default_quota',
|
|
// ensure we only send the preset id
|
|
value: quota.id ? quota.id : quota
|
|
}).then(() => {
|
|
if (typeof quota !== 'object') {
|
|
quota = {id: quota, label: quota};
|
|
}
|
|
this.defaultQuota = quota;
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Validate quota string to make sure it's a valid human file size
|
|
*
|
|
* @param {string} quota Quota in readable format '5 GB'
|
|
* @returns {Promise|boolean}
|
|
*/
|
|
validateQuota(quota) {
|
|
// only used for new presets sent through @Tag
|
|
let validQuota = OC.Util.computerFileSize(quota);
|
|
if (validQuota === 0) {
|
|
return this.setDefaultQuota('none');
|
|
} else if (validQuota !== null) {
|
|
// unify format output
|
|
return this.setDefaultQuota(OC.Util.humanFileSize(OC.Util.computerFileSize(quota)));
|
|
}
|
|
// if no valid do not change
|
|
return false;
|
|
},
|
|
|
|
/**
|
|
* Register a new action for the user menu
|
|
*
|
|
* @param {string} icon the icon class
|
|
* @param {string} text the text to display
|
|
* @param {function} action the function to run
|
|
*/
|
|
registerAction(icon, text, action) {
|
|
this.externalActions.push({
|
|
icon: icon,
|
|
text: text,
|
|
action: action
|
|
});
|
|
return this.externalActions;
|
|
},
|
|
|
|
/**
|
|
* Create a new group
|
|
*
|
|
* @param {Object} event The form submit event
|
|
*/
|
|
createGroup(event) {
|
|
let gid = event.target[0].value;
|
|
this.loadingAddGroup = true;
|
|
this.$store.dispatch('addGroup', gid)
|
|
.then(() => {
|
|
this.showAddGroupEntry = false;
|
|
this.loadingAddGroup = false;
|
|
this.$router.push({
|
|
name: 'group',
|
|
params: {
|
|
selectedGroup: gid
|
|
}
|
|
})
|
|
})
|
|
.catch(() => {
|
|
this.loadingAddGroup = false;
|
|
});
|
|
}
|
|
},
|
|
computed: {
|
|
users() {
|
|
return this.$store.getters.getUsers;
|
|
},
|
|
usersOffset() {
|
|
return this.$store.getters.getUsersOffset;
|
|
},
|
|
usersLimit() {
|
|
return this.$store.getters.getUsersLimit;
|
|
},
|
|
|
|
// Local settings
|
|
showLanguages: {
|
|
get: function() {return this.getLocalstorage('showLanguages')},
|
|
set: function(status) {
|
|
this.setLocalStorage('showLanguages', status);
|
|
}
|
|
},
|
|
showLastLogin: {
|
|
get: function() {return this.getLocalstorage('showLastLogin')},
|
|
set: function(status) {
|
|
this.setLocalStorage('showLastLogin', status);
|
|
}
|
|
},
|
|
showUserBackend: {
|
|
get: function() {return this.getLocalstorage('showUserBackend')},
|
|
set: function(status) {
|
|
this.setLocalStorage('showUserBackend', status);
|
|
}
|
|
},
|
|
showStoragePath: {
|
|
get: function() {return this.getLocalstorage('showStoragePath')},
|
|
set: function(status) {
|
|
this.setLocalStorage('showStoragePath', status);
|
|
}
|
|
},
|
|
|
|
userCount() {
|
|
return this.$store.getters.getUserCount;
|
|
},
|
|
settings() {
|
|
return this.$store.getters.getServerData;
|
|
},
|
|
|
|
// default quota
|
|
quotaOptions() {
|
|
// convert the preset array into objects
|
|
let quotaPreset = this.settings.quotaPreset.reduce((acc, cur) => acc.concat({id:cur, label:cur}), []);
|
|
// add default presets
|
|
quotaPreset.unshift(this.unlimitedQuota);
|
|
return quotaPreset;
|
|
},
|
|
// mapping saved values to objects
|
|
defaultQuota: {
|
|
get: function() {
|
|
if (this.selectedQuota !== false) {
|
|
return this.selectedQuota;
|
|
}
|
|
if (OC.Util.computerFileSize(this.settings.defaultQuota) > 0) {
|
|
// if value is valid, let's map the quotaOptions or return custom quota
|
|
return {id:this.settings.defaultQuota, label:this.settings.defaultQuota};
|
|
}
|
|
return this.unlimitedQuota; // unlimited
|
|
},
|
|
set: function(quota) {
|
|
this.selectedQuota = quota;
|
|
}
|
|
|
|
},
|
|
|
|
// BUILD APP NAVIGATION MENU OBJECT
|
|
menu() {
|
|
// Data provided php side
|
|
let self = this;
|
|
let groups = this.$store.getters.getGroups;
|
|
groups = Array.isArray(groups) ? groups : [];
|
|
|
|
// Map groups
|
|
groups = groups.map(group => {
|
|
let item = {};
|
|
item.id = group.id.replace(' ', '_');
|
|
item.key = item.id;
|
|
item.utils = {}
|
|
|
|
// router link to
|
|
item.router = {
|
|
name: 'group',
|
|
params: {selectedGroup: group.id}
|
|
};
|
|
|
|
// group name
|
|
item.text = group.name;
|
|
item.title = group.name;
|
|
|
|
// users count for all groups
|
|
if (group.usercount - group.disabled > 0 || group.usercount === -1) {
|
|
item.utils.counter = group.usercount - group.disabled;
|
|
}
|
|
|
|
if (item.id !== 'admin' && item.id !== 'disabled' && this.settings.isAdmin) {
|
|
// add delete button on real groups
|
|
item.utils.actions = [{
|
|
icon: 'icon-delete',
|
|
text: t('settings', 'Remove group'),
|
|
action: function() {
|
|
self.removeGroup(group.id)
|
|
}
|
|
}];
|
|
};
|
|
return item;
|
|
});
|
|
|
|
// Every item is added on top of the array, so we're going backward
|
|
// Groups, separator, disabled, admin, everyone
|
|
|
|
// Add separator
|
|
let realGroups = groups.find((group) => {return group.id !== 'disabled' && group.id !== 'admin'});
|
|
realGroups = typeof realGroups === 'undefined' ? [] : realGroups;
|
|
realGroups = Array.isArray(realGroups) ? realGroups : [realGroups];
|
|
if (realGroups.length > 0) {
|
|
let separator = {
|
|
caption: true,
|
|
text: t('settings', 'Groups')
|
|
};
|
|
groups.unshift(separator);
|
|
}
|
|
|
|
// Adjust admin and disabled groups
|
|
let adminGroup = groups.find(group => group.id == 'admin');
|
|
let disabledGroup = groups.find(group => group.id == 'disabled');
|
|
|
|
// filter out admin and disabled
|
|
groups = groups.filter(group => ['admin', 'disabled'].indexOf(group.id) === -1);
|
|
|
|
if (adminGroup && adminGroup.text) {
|
|
adminGroup.text = t('settings', 'Admins'); // rename admin group
|
|
adminGroup.icon = 'icon-user-admin'; // set icon
|
|
groups.unshift(adminGroup); // add admin group if present
|
|
}
|
|
if (disabledGroup && disabledGroup.text) {
|
|
disabledGroup.text = t('settings', 'Disabled users'); // rename disabled group
|
|
disabledGroup.icon = 'icon-disabled-users'; // set icon
|
|
if (disabledGroup.utils && (
|
|
disabledGroup.utils.counter > 0 // add disabled if not empty
|
|
|| disabledGroup.utils.counter === -1) // add disabled if ldap enabled
|
|
) {
|
|
groups.unshift(disabledGroup);
|
|
}
|
|
}
|
|
|
|
|
|
// Add everyone group
|
|
let everyoneGroup = {
|
|
id: 'everyone',
|
|
key: 'everyone',
|
|
icon: 'icon-contacts-dark',
|
|
router: {name:'users'},
|
|
text: t('settings', 'Everyone'),
|
|
};
|
|
// users count
|
|
if (this.userCount > 0) {
|
|
Vue.set(everyoneGroup, 'utils', {
|
|
counter: this.userCount
|
|
});
|
|
}
|
|
groups.unshift(everyoneGroup);
|
|
|
|
let addGroup = {
|
|
id: 'addgroup',
|
|
key: 'addgroup',
|
|
icon: 'icon-add',
|
|
text: t('settings', 'Add group'),
|
|
classes: this.loadingAddGroup ? 'icon-loading-small' : ''
|
|
};
|
|
if (this.showAddGroupEntry) {
|
|
Vue.set(addGroup, 'edit', {
|
|
text: t('settings', 'Add group'),
|
|
action: this.createGroup,
|
|
reset: function() {
|
|
self.showAddGroupEntry = false
|
|
}
|
|
});
|
|
addGroup.classes = 'editing';
|
|
} else {
|
|
Vue.set(addGroup, 'action', function() {
|
|
self.showAddGroupEntry = true
|
|
// focus input
|
|
Vue.nextTick(() => {
|
|
window.addgroup.querySelector('form > input[type="text"]').focus()
|
|
})
|
|
})
|
|
}
|
|
groups.unshift(addGroup);
|
|
|
|
return groups;
|
|
},
|
|
}
|
|
}
|
|
</script>
|