release v2.0.0 #4
|
@ -14,6 +14,7 @@
|
|||
"axios": "^0.21.1",
|
||||
"cordova": "^10.0.0",
|
||||
"core-js": "^3.7.0",
|
||||
"pinia": "^2.0.0-alpha.7",
|
||||
"quasar": "^2.0.0-beta.9"
|
||||
},
|
||||
"prettier": {
|
||||
|
|
|
@ -30,7 +30,7 @@ module.exports = configure(function (/* ctx */) {
|
|||
// app boot file (/src/boot)
|
||||
// --> boot files are part of "main.js"
|
||||
// https://quasar.dev/quasar-cli/boot-files
|
||||
boot: ['axios', 'plugins', 'loading', 'login'],
|
||||
boot: ['axios', 'store', 'plugins', 'loading', 'login'],
|
||||
|
||||
// https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css
|
||||
css: ['app.scss'],
|
||||
|
|
|
@ -1,27 +1,21 @@
|
|||
import config from 'src/config';
|
||||
import { boot } from 'quasar/wrappers';
|
||||
import { LocalStorage, Notify } from 'quasar';
|
||||
import axios, { AxiosError, AxiosInstance } from 'axios';
|
||||
import { UserSessionState } from 'src/plugins/user/store';
|
||||
import axios, { AxiosError } from 'axios';
|
||||
import { useMainStore } from 'src/store';
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
interface ComponentCustomProperties {
|
||||
$axios: AxiosInstance;
|
||||
}
|
||||
}
|
||||
const api = axios.create();
|
||||
|
||||
const api = axios.create({
|
||||
baseURL: <string | undefined>LocalStorage.getItem('baseURL') || config.baseURL,
|
||||
});
|
||||
export default boot(({ store, router }) => {
|
||||
api.defaults.baseURL = LocalStorage.getItem<string>('baseURL') || config.baseURL;
|
||||
|
||||
export default boot<UserSessionState>(({ app, store, router }) => {
|
||||
/***
|
||||
* Intercept requests and insert Token if available
|
||||
*/
|
||||
api.interceptors.request.use((config) => {
|
||||
const session = store.state.sessions.currentSession;
|
||||
if (session?.token) {
|
||||
config.headers = { Authorization: 'Bearer ' + session.token };
|
||||
const store = useMainStore();
|
||||
if (store.session?.token) {
|
||||
config.headers = { Authorization: 'Bearer ' + store.session.token };
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
@ -31,7 +25,7 @@ export default boot<UserSessionState>(({ app, store, router }) => {
|
|||
* - filter 401 --> logout
|
||||
* - filter timeout or 502-504 --> backendOffline
|
||||
*/
|
||||
axios.interceptors.response.use(
|
||||
api.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error) => {
|
||||
if (error) {
|
||||
|
@ -56,22 +50,13 @@ export default boot<UserSessionState>(({ app, store, router }) => {
|
|||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
// for use inside Vue files (Options API) through this.$axios and this.$api
|
||||
|
||||
app.config.globalProperties.$axios = axios;
|
||||
// ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
|
||||
// so you won't necessarily have to import axios in each vue file
|
||||
|
||||
app.config.globalProperties.$api = api;
|
||||
// ^ ^ ^ this will allow you to use this.$api (for Vue Options API form)
|
||||
// so you can easily perform requests against your app's API
|
||||
});
|
||||
|
||||
export { axios, api };
|
||||
export { api };
|
||||
|
||||
export const setBaseUrl = (url: string) => {
|
||||
export const setBaseURL = (url: string) => {
|
||||
LocalStorage.set('baseURL', url);
|
||||
axios.defaults.baseURL = url;
|
||||
api.defaults.baseURL = url;
|
||||
Notify.create({
|
||||
message: 'Serveraddresse gespeichert',
|
||||
position: 'bottom',
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { boot } from 'quasar/wrappers';
|
||||
import { UserSessionState } from 'src/plugins/user/store';
|
||||
import { useMainStore } from 'src/store';
|
||||
import { hasPermissions } from 'src/utils/permission';
|
||||
import { RouteRecord } from 'vue-router';
|
||||
|
||||
export default boot<UserSessionState>(({ router, store }) => {
|
||||
export default boot(({ router }) => {
|
||||
router.beforeEach((to, from, next) => {
|
||||
const session = store.state.sessions.currentSession;
|
||||
console.log(`from ${from.fullPath} to ${to.fullPath}`);
|
||||
const store = useMainStore();
|
||||
|
||||
if (to.path == from.path) {
|
||||
return;
|
||||
|
@ -13,10 +15,9 @@ export default boot<UserSessionState>(({ router, store }) => {
|
|||
if (to.path.startsWith('/main')) {
|
||||
// Secured area (LOGIN REQUIRED)
|
||||
// Check login is ok
|
||||
if (!session || session.expires <= new Date()) {
|
||||
store.dispatch('sessions/logout').catch((error) => {
|
||||
console.warn(error);
|
||||
});
|
||||
if (!store.session || store.session.expires <= new Date()) {
|
||||
console.log('Nope, logout');
|
||||
void store.logout();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -24,27 +25,28 @@ export default boot<UserSessionState>(({ router, store }) => {
|
|||
if (
|
||||
to.matched.every((record: RouteRecord) => {
|
||||
if (!('meta' in record) || !('permissions' in record.meta)) return true;
|
||||
if (record.meta) {
|
||||
if ((<{ permissions: FG.Permission[] }>record.meta).permissions) {
|
||||
return (<{ permissions: FG.Permission[] }>record.meta).permissions.every(
|
||||
(permission: string) => {
|
||||
return store.state.users.currentPermissions.includes(permission);
|
||||
}
|
||||
);
|
||||
}
|
||||
console.log(record.meta);
|
||||
const h = hasPermissions((<{ permissions: FG.Permission[] }>record.meta).permissions);
|
||||
console.log(h);
|
||||
return h;
|
||||
}
|
||||
})
|
||||
) {
|
||||
console.log('ok next');
|
||||
next();
|
||||
} else {
|
||||
console.log('Back loggin');
|
||||
next({ name: 'login', query: { redirect: to.fullPath } });
|
||||
}
|
||||
} else {
|
||||
if (to.name == 'login' && store.state.users.currentUser && !to.params['logout']) {
|
||||
if (to.name == 'login' && store.user && !to.params['logout']) {
|
||||
// Called login while already logged in
|
||||
console.log('Ok next');
|
||||
void next({ name: 'dashboard' });
|
||||
} else {
|
||||
// We are on the non secured area
|
||||
console.log('Ok non sec');
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
import { boot } from 'quasar/wrappers';
|
||||
import { Notify } from 'quasar';
|
||||
|
||||
// "async" is optional;
|
||||
// more info on params: https://quasar.dev/quasar-cli/boot-files
|
||||
export default boot(() => {
|
||||
Notify.registerType('error', {
|
||||
color: 'negative',
|
||||
icon: 'mdi-alert-circle',
|
||||
progress: true,
|
||||
position: 'bottom',
|
||||
actions: [{ icon: 'mdi-close', color: 'white' }],
|
||||
});
|
||||
});
|
|
@ -5,7 +5,6 @@ import routes from 'src/router/routes';
|
|||
import { api } from 'boot/axios';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { Router, RouteRecordRaw } from 'vue-router';
|
||||
import { UserSessionState } from 'src/plugins/user/store';
|
||||
|
||||
const config: { [key: string]: Array<string> } = {
|
||||
// Do not change required Modules !!
|
||||
|
@ -160,7 +159,7 @@ function loadPlugin(
|
|||
modules: string[],
|
||||
backendpromise: Promise<Backend | null>,
|
||||
plugins: FG_Plugin.Plugin[],
|
||||
store: Store<UserSessionState>,
|
||||
store: Store<unknown>,
|
||||
router: Router
|
||||
): FG_Plugin.Flaschengeist {
|
||||
modules.forEach((requiredModule) => {
|
||||
|
@ -218,7 +217,7 @@ async function getBackend(): Promise<Backend | null> {
|
|||
|
||||
// "async" is optional;
|
||||
// more info on params: https://quasar.dev/quasar-cli/cli-documentation/boot-files#Anatomy-of-a-boot-file
|
||||
export default boot<UserSessionState>(({ router, store, app }) => {
|
||||
export default boot(({ router, app, store }) => {
|
||||
const plugins: FG_Plugin.Plugin[] = [];
|
||||
|
||||
const backendPromise = getBackend();
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import { createPinia } from 'pinia';
|
||||
import { boot } from 'quasar/wrappers';
|
||||
import { useMainStore } from 'src/store';
|
||||
|
||||
export default boot(({ app }) => {
|
||||
app.use(createPinia());
|
||||
|
||||
const store = useMainStore();
|
||||
void store.init();
|
||||
});
|
|
@ -5,7 +5,7 @@
|
|||
</q-item-section>
|
||||
|
||||
<q-item-section>
|
||||
<q-item-label>{{ realTitle }}</q-item-label>
|
||||
<q-item-label>{{ title }}</q-item-label>
|
||||
<!--<q-item-label caption>
|
||||
{{ caption }}
|
||||
</q-item-label>-->
|
||||
|
@ -14,7 +14,6 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useStore } from 'vuex';
|
||||
import { computed, defineComponent } from 'vue';
|
||||
import { hasPermissions } from 'src/utils/permission';
|
||||
|
||||
|
@ -44,22 +43,8 @@ export default defineComponent({
|
|||
},
|
||||
|
||||
setup(props) {
|
||||
let title = computed<string>(() => {
|
||||
if (props.title.includes('loadFromStore')) {
|
||||
const store = useStore();
|
||||
|
||||
const startIndex = props.title.indexOf('(') + 1;
|
||||
const endIndex = props.title.indexOf(')');
|
||||
const substring = props.title.substring(startIndex, endIndex).replace(/"/g, '');
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
return <string>store.getters[substring];
|
||||
}
|
||||
return props.title;
|
||||
});
|
||||
|
||||
const isGranted = computed(() => hasPermissions(props.permissions));
|
||||
|
||||
return { realTitle: title, isGranted };
|
||||
return { isGranted };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -13,10 +13,10 @@ declare namespace FG {
|
|||
firstname: string;
|
||||
lastname: string;
|
||||
mail: string;
|
||||
birthday?: any;
|
||||
birthday?: Date;
|
||||
roles: Array<string>;
|
||||
permissions?: any;
|
||||
avatar_url?: any;
|
||||
permissions?: Array<Permission>;
|
||||
avatar_url?: string;
|
||||
}
|
||||
type Permission = string;
|
||||
interface Role {
|
||||
|
@ -29,51 +29,16 @@ declare namespace FG {
|
|||
time: Date;
|
||||
amount: number;
|
||||
reversal_id: number;
|
||||
sender_id?: any;
|
||||
receiver_id?: any;
|
||||
author_id?: any;
|
||||
original_id?: any;
|
||||
}
|
||||
interface Drink {
|
||||
id: number;
|
||||
name: string;
|
||||
volume: number;
|
||||
cost_price: number;
|
||||
discount: number;
|
||||
extra_charge?: any;
|
||||
prices: Array<DrinkPrice>;
|
||||
ingredients: Array<Ingredient>;
|
||||
tags: Array<any>;
|
||||
}
|
||||
interface DrinkPrice {
|
||||
id: number;
|
||||
volume: number;
|
||||
price: number;
|
||||
no_auto: boolean;
|
||||
public: boolean;
|
||||
description?: any;
|
||||
round_step: number;
|
||||
}
|
||||
interface DrinkType {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
interface Ingredient {
|
||||
id: number;
|
||||
volume: number;
|
||||
drink_parent_id: number;
|
||||
drink_ingredient_id: number;
|
||||
drink_ingredient?: any;
|
||||
}
|
||||
interface Tag {
|
||||
id: number;
|
||||
name: string;
|
||||
sender_id?: string;
|
||||
receiver_id?: string;
|
||||
author_id?: string;
|
||||
original_id?: number;
|
||||
}
|
||||
interface Event {
|
||||
id: number;
|
||||
start: Date;
|
||||
end: Date;
|
||||
description?: any;
|
||||
description?: string;
|
||||
type: EventType;
|
||||
jobs: Array<Job>;
|
||||
}
|
||||
|
@ -84,7 +49,7 @@ declare namespace FG {
|
|||
interface Job {
|
||||
id: number;
|
||||
start: Date;
|
||||
end?: any;
|
||||
end?: Date;
|
||||
comment: string;
|
||||
type: JobType;
|
||||
services: Array<Service>;
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
<essential-link
|
||||
v-for="(link, index) in flaschengeist.mainLinks"
|
||||
:key="'plugin' + index"
|
||||
:title="link.title"
|
||||
:title="typeof link.title === 'object' ? link.title.value : link.title"
|
||||
:link="link.link"
|
||||
:icon="link.icon"
|
||||
:permissions="link.permissions"
|
||||
|
@ -101,11 +101,11 @@
|
|||
<script lang="ts">
|
||||
import EssentialLink from 'components/navigation/EssentialLink.vue';
|
||||
import ShortCutLink from 'components/navigation/ShortCutLink.vue';
|
||||
import { Screen, Loading } from 'quasar';
|
||||
import { Screen } from 'quasar';
|
||||
import { defineComponent, ref, inject, computed } from 'vue';
|
||||
import { useMainStore } from 'src/store';
|
||||
import { FG_Plugin } from 'src/plugins';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useStore } from 'vuex';
|
||||
|
||||
const links = [
|
||||
{
|
||||
|
@ -136,7 +136,7 @@ export default defineComponent({
|
|||
components: { EssentialLink, ShortCutLink },
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const store = useStore();
|
||||
const mainStore = useMainStore();
|
||||
const flaschengeist = inject<FG_Plugin.Flaschengeist>('flaschengeist');
|
||||
const leftDrawer = ref(false);
|
||||
|
||||
|
@ -171,10 +171,7 @@ export default defineComponent({
|
|||
});
|
||||
|
||||
function logout() {
|
||||
Loading.show({ message: 'Session wird abgemeldet' });
|
||||
store.dispatch('sessions/logout').finally(() => {
|
||||
Loading.hide();
|
||||
});
|
||||
void mainStore.logout();
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -54,19 +54,19 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useStore } from 'vuex';
|
||||
import { useMainStore } from 'src/store';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { Loading, Notify } from 'quasar';
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { setBaseUrl, api } from 'boot/axios';
|
||||
import { UserSessionState } from 'src/plugins/user/store';
|
||||
import { setBaseURL, api } from 'boot/axios';
|
||||
import { useUserStore } from 'src/plugins/user/store';
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'PageName'
|
||||
name: 'Login',
|
||||
setup() {
|
||||
const store = useStore<UserSessionState>();
|
||||
const router = useRouter();
|
||||
const mainStore = useMainStore();
|
||||
const mainRoute = { name: 'dashboard' };
|
||||
const router = useRouter();
|
||||
|
||||
/* Stuff for the real login page */
|
||||
const userid = ref('');
|
||||
|
@ -81,26 +81,21 @@ export default defineComponent({
|
|||
|
||||
function changeUrl() {
|
||||
if (server.value) {
|
||||
setBaseUrl(server.value);
|
||||
setBaseURL(server.value);
|
||||
}
|
||||
}
|
||||
|
||||
function doLogin() {
|
||||
Loading.show({
|
||||
message: 'Du wirst angemeldet',
|
||||
});
|
||||
store
|
||||
.dispatch('sessions/login', {
|
||||
userid: userid.value,
|
||||
password: password.value,
|
||||
})
|
||||
.then(() => {
|
||||
async function doLogin() {
|
||||
Loading.show({ message: 'Du wirst angemeldet' });
|
||||
const status = await mainStore.login(userid.value, password.value);
|
||||
|
||||
if (status === true) {
|
||||
mainStore.user = (await useUserStore().getUser(userid.value)) || undefined;
|
||||
const x = router.currentRoute.value.query['redirect'];
|
||||
void router.push(typeof x === 'string' ? { path: x } : mainRoute);
|
||||
})
|
||||
.catch((error: { status: number } | undefined) => {
|
||||
if (error && error.status === 401) {
|
||||
} else {
|
||||
password.value = '';
|
||||
if (status === 401) {
|
||||
Notify.create({
|
||||
group: false,
|
||||
type: 'negative',
|
||||
|
@ -110,13 +105,11 @@ export default defineComponent({
|
|||
actions: [{ icon: 'mdi-close', color: 'white' }],
|
||||
});
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
}
|
||||
Loading.hide();
|
||||
});
|
||||
}
|
||||
|
||||
function doReset() {
|
||||
async function doReset() {
|
||||
if (userid.value == '') {
|
||||
Notify.create({
|
||||
group: false,
|
||||
|
@ -128,11 +121,8 @@ export default defineComponent({
|
|||
});
|
||||
return;
|
||||
}
|
||||
void store
|
||||
.dispatch('sessions/requestPasswordReset', {
|
||||
userid: userid.value,
|
||||
})
|
||||
.then(() => {
|
||||
|
||||
if (await mainStore.requestReset(userid.value)) {
|
||||
userid.value = '';
|
||||
password.value = '';
|
||||
Notify.create({
|
||||
|
@ -144,7 +134,7 @@ export default defineComponent({
|
|||
progress: true,
|
||||
actions: [{ icon: 'mdi-close', color: 'white' }],
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -47,8 +47,6 @@ export default defineComponent({
|
|||
reload.value -= 1;
|
||||
if (reload.value === 0) {
|
||||
const path = router.currentRoute.value.query.redirect;
|
||||
console.log('Offline: ');
|
||||
console.log(path);
|
||||
void router.replace(path ? { path: <string>path } : { name: 'login' });
|
||||
}
|
||||
}, 1000);
|
||||
|
|
|
@ -34,17 +34,15 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useStore } from 'vuex';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { Loading, Notify } from 'quasar';
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { UserSessionState } from 'src/plugins/user/store';
|
||||
import { useMainStore } from 'src/store';
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'PageName'
|
||||
setup() {
|
||||
const store = useStore<UserSessionState>();
|
||||
const mainStore = useMainStore();
|
||||
const router = useRouter();
|
||||
const password = ref('');
|
||||
const password2 = ref('');
|
||||
|
@ -68,16 +66,27 @@ export default defineComponent({
|
|||
return;
|
||||
}
|
||||
|
||||
const token = router.currentRoute.value.query.token;
|
||||
if (token === null)
|
||||
if (password.value !== password2.value) {
|
||||
Notify.create({
|
||||
group: false,
|
||||
type: 'negative',
|
||||
message: 'Der Link wurde nicht richtig geöffnet, Token nicht gefunden.',
|
||||
timeout: 10000,
|
||||
progress: true,
|
||||
actions: [{ icon: 'mdi-close', color: 'white' }],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Loading.show({
|
||||
message: 'Das Passwort wird zurückgesetzt',
|
||||
});
|
||||
store
|
||||
.dispatch('sessions/resetPassword', {
|
||||
password: password.value,
|
||||
token: router.currentRoute.value.query.token,
|
||||
})
|
||||
.catch((error: AxiosResponse) => {
|
||||
if (error.status == 403) {
|
||||
mainStore
|
||||
.resetPassword(<string>token, password.value)
|
||||
.catch((status) => {
|
||||
if (status == 403) {
|
||||
Notify.create({
|
||||
group: false,
|
||||
type: 'negative',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { RouteRecordRaw } from 'vue-router';
|
||||
import { Module } from 'vuex';
|
||||
import { Component } from 'vue';
|
||||
import { Component, ComputedRef } from 'vue';
|
||||
|
||||
declare namespace FG_Plugin {
|
||||
interface ShortCutLink {
|
||||
|
@ -10,7 +10,7 @@ declare namespace FG_Plugin {
|
|||
}
|
||||
|
||||
interface PluginRouteConfig {
|
||||
title: string;
|
||||
title: string | ComputedRef<string>;
|
||||
icon: string;
|
||||
route: RouteRecordRaw;
|
||||
shortcut?: boolean;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Module, MutationTree, ActionTree, GetterTree } from 'vuex';
|
||||
import { StateInterface } from 'src/store';
|
||||
import { StateInterface, useMainStore } from 'src/store';
|
||||
import { api } from 'src/boot/axios';
|
||||
import { AxiosResponse } from 'axios';
|
||||
|
||||
|
@ -90,27 +90,28 @@ const mutations: MutationTree<BalanceInterface> = {
|
|||
|
||||
const actions: ActionTree<BalanceInterface, StateInterface> = {
|
||||
//const actions: ActionTree<BalanceInterface, any> = {
|
||||
addShortcut({ commit, state, rootState }, shortcut) {
|
||||
addShortcut({ commit, state }, shortcut) {
|
||||
const sc = [...state.shortcuts, shortcut];
|
||||
sc.sort();
|
||||
|
||||
const user = <FG.User>rootState.users.currentUser;
|
||||
const mainStore = useMainStore();
|
||||
const user = mainStore.currentUser;
|
||||
return api.put(`/users/${user.userid}/balance/shortcuts`, sc).then(() => {
|
||||
commit('setShortcuts', sc);
|
||||
});
|
||||
},
|
||||
removeShortcut({ commit, state, rootState }, shortcut) {
|
||||
removeShortcut({ commit, state }, shortcut) {
|
||||
const sc = state.shortcuts.filter((value: number) => value != shortcut);
|
||||
|
||||
const user = <FG.User>rootState.users.currentUser;
|
||||
const mainStore = useMainStore();
|
||||
const user = mainStore.currentUser;
|
||||
return api.put(`/users/${user.userid}/balance/shortcuts`, sc).then(() => {
|
||||
commit('setShortcuts', sc);
|
||||
});
|
||||
},
|
||||
getShortcuts({ commit, state, rootState }, force = false) {
|
||||
getShortcuts({ commit, state }, force = false) {
|
||||
if (force || state.shortcuts.length == 0) {
|
||||
const mainStore = useMainStore();
|
||||
commit('setLoading');
|
||||
const user = <FG.User>rootState.users.currentUser;
|
||||
const user = mainStore.currentUser;
|
||||
return api
|
||||
.get(`/users/${user.userid}/balance/shortcuts`)
|
||||
.then(({ data }: AxiosResponse<BalanceResponse>) => {
|
||||
|
@ -120,9 +121,10 @@ const actions: ActionTree<BalanceInterface, StateInterface> = {
|
|||
.finally(() => commit('setLoading', false));
|
||||
}
|
||||
},
|
||||
getBalance({ commit, rootState }, user: FG.User | undefined = undefined) {
|
||||
getBalance({ commit }, user: FG.User | undefined = undefined) {
|
||||
commit('setLoading');
|
||||
if (!user) user = <FG.User>rootState.users.currentUser;
|
||||
const mainStore = useMainStore();
|
||||
if (!user) user = mainStore.currentUser;
|
||||
return api
|
||||
.get(`/users/${user.userid}/balance`)
|
||||
.then(({ data }: AxiosResponse<BalanceResponse>) => {
|
||||
|
@ -137,7 +139,7 @@ const actions: ActionTree<BalanceInterface, StateInterface> = {
|
|||
});
|
||||
},
|
||||
getTransactions(
|
||||
{ commit, rootState },
|
||||
{ commit },
|
||||
payload: {
|
||||
userid?: string;
|
||||
filter?: {
|
||||
|
@ -151,7 +153,8 @@ const actions: ActionTree<BalanceInterface, StateInterface> = {
|
|||
}
|
||||
) {
|
||||
commit('setLoading');
|
||||
if (!payload.userid) payload.userid = (<FG.User>rootState.users.currentUser).userid;
|
||||
const mainStore = useMainStore();
|
||||
if (!payload.userid) payload.userid = mainStore.currentUser.userid;
|
||||
if (!payload.filter) payload.filter = { limit: 10 };
|
||||
return api
|
||||
.get(`/users/${payload.userid}/balance/transactions`, { params: payload.filter || {} })
|
||||
|
@ -162,11 +165,12 @@ const actions: ActionTree<BalanceInterface, StateInterface> = {
|
|||
})
|
||||
.finally(() => commit('setLoading', false));
|
||||
},
|
||||
getLimit({ rootState, commit }) {
|
||||
getLimit({ commit }) {
|
||||
const mainStore = useMainStore();
|
||||
commit('setLoading');
|
||||
api
|
||||
/* eslint-disable-next-line @typescript-eslint/restrict-template-expressions */
|
||||
.get(`/users/${rootState.users.currentUser?.userid}/balance/limit`)
|
||||
.get(`/users/${mainStore.currentUser.userid}/balance/limit`)
|
||||
.then(({ data }) => {
|
||||
console.log(data);
|
||||
})
|
||||
|
@ -184,19 +188,17 @@ const actions: ActionTree<BalanceInterface, StateInterface> = {
|
|||
dispatch('getBalance').catch((err) => console.warn(err));
|
||||
});
|
||||
},
|
||||
changeBalance(
|
||||
{ dispatch, commit, rootState },
|
||||
data: { amount: number; user: string; sender?: string }
|
||||
) {
|
||||
changeBalance({ dispatch, commit }, data: { amount: number; user: string; sender?: string }) {
|
||||
commit('setLoading');
|
||||
return api
|
||||
.put(`/users/${data.user}/balance`, data)
|
||||
.then((response: AxiosResponse<FG.Transaction>) => {
|
||||
const mainStore = useMainStore();
|
||||
const transaction = response.data;
|
||||
fixTransaction(transaction);
|
||||
if (
|
||||
data.user == rootState.users.currentUser?.userid ||
|
||||
data.sender === rootState.users.currentUser?.userid
|
||||
data.user == mainStore.currentUser.userid ||
|
||||
data.sender === mainStore.currentUser.userid
|
||||
)
|
||||
commit('addTransaction', transaction);
|
||||
commit(state.balances.has(data.user) ? 'changeBalance' : 'setBalance', {
|
||||
|
|
|
@ -12,14 +12,13 @@
|
|||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import MainUserSettings from 'src/plugins/user/components/settings/MainUserSettings.vue';
|
||||
import { useStore } from 'vuex';
|
||||
import { UserSessionState } from '../store';
|
||||
import { useUserStore } from '../store';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NewUser',
|
||||
components: { MainUserSettings },
|
||||
setup() {
|
||||
const store = useStore<UserSessionState>();
|
||||
const userStore = useUserStore();
|
||||
const user = ref<FG.User>({
|
||||
userid: '',
|
||||
display_name: '',
|
||||
|
@ -28,10 +27,9 @@ export default defineComponent({
|
|||
mail: '',
|
||||
roles: [],
|
||||
});
|
||||
function setUser(value: FG.User) {
|
||||
store.dispatch('users/setUser', value).catch((error) => {
|
||||
console.warn(error);
|
||||
});
|
||||
|
||||
async function setUser(value: FG.User) {
|
||||
await userStore.createUser(value);
|
||||
}
|
||||
return { user, setUser };
|
||||
},
|
||||
|
|
|
@ -11,23 +11,22 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useStore } from 'vuex';
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { UserSessionState } from '../store';
|
||||
import UserSelector from '../components/UserSelector.vue';
|
||||
import MainUserSettings from '../components/settings/MainUserSettings.vue';
|
||||
import { useMainStore } from 'src/store';
|
||||
import { useUserStore } from '../store';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'UpdateUser',
|
||||
components: { UserSelector, MainUserSettings },
|
||||
setup() {
|
||||
const store = useStore<UserSessionState>();
|
||||
const user = ref(<FG.User>store.state.users.currentUser);
|
||||
const mainStore = useMainStore();
|
||||
const userStore = useUserStore();
|
||||
const user = ref(mainStore.currentUser);
|
||||
|
||||
function updateUser(value: FG.User) {
|
||||
store.dispatch('users/updateUser', value).catch((error) => {
|
||||
console.warn(error);
|
||||
});
|
||||
async function updateUser(value: FG.User) {
|
||||
await userStore.updateUser(value);
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -12,8 +12,7 @@
|
|||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType, onBeforeMount } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
import { UserSessionState } from '../store';
|
||||
import { useUserStore } from '../store';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'UserSelector',
|
||||
|
@ -23,15 +22,13 @@ export default defineComponent({
|
|||
},
|
||||
emits: { 'update:modelValue': (user: FG.User) => !!user },
|
||||
setup(props, { emit }) {
|
||||
const store = useStore<UserSessionState>();
|
||||
const userStore = useUserStore();
|
||||
|
||||
onBeforeMount(() => {
|
||||
store.dispatch('users/getUsers').catch((error) => {
|
||||
console.error(error);
|
||||
});
|
||||
void userStore.getUsers(false);
|
||||
});
|
||||
|
||||
const users = computed(() => store.state.users.users);
|
||||
const users = computed(() => userStore.users);
|
||||
const selected = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (value: FG.User | undefined) => (value ? emit('update:modelValue', value) : undefined),
|
||||
|
|
|
@ -26,19 +26,21 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useMainStore } from 'src/store';
|
||||
import { computed, defineComponent, onMounted, ref } from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
import { UserSessionState } from '../store';
|
||||
import { useUserStore } from '../store';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Greeting',
|
||||
setup() {
|
||||
const store = useStore<UserSessionState>();
|
||||
onMounted(() => store.dispatch('users/getUsers', false));
|
||||
const mainStore = useMainStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const name = ref(store.state.users.currentUser?.display_name);
|
||||
// Ensure users are loaded,so we can query birthdays
|
||||
onMounted(() => userStore.getUsers(false));
|
||||
|
||||
const avatarLink = ref(store.state.users.currentUser?.avatar_url);
|
||||
const name = ref(mainStore.currentUser.display_name);
|
||||
const avatarLink = ref(mainStore.currentUser.avatar_url);
|
||||
|
||||
function userHasBirthday(user: FG.User) {
|
||||
const today = new Date();
|
||||
|
@ -50,13 +52,13 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
const hasBirthday = computed(() => {
|
||||
return userHasBirthday(<FG.User>store.state.users.currentUser);
|
||||
return userHasBirthday(mainStore.currentUser);
|
||||
});
|
||||
|
||||
const birthday = computed(() =>
|
||||
store.state.users.users
|
||||
userStore.users
|
||||
.filter(userHasBirthday)
|
||||
.filter((user) => user.userid !== store.state.users.currentUser?.userid)
|
||||
.filter((user) => user.userid !== mainStore.currentUser.userid)
|
||||
);
|
||||
|
||||
return { avatarLink, name, hasBirthday, birthday };
|
||||
|
|
|
@ -107,12 +107,12 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useStore } from 'vuex';
|
||||
import { Notify } from 'quasar';
|
||||
import { UserSessionState } from '../../store';
|
||||
import { hasPermission } from 'src/utils/permission';
|
||||
import IsoDateInput from 'src/components/utils/IsoDateInput.vue';
|
||||
import { defineComponent, computed, ref, onBeforeMount, PropType } from 'vue';
|
||||
import { useUserStore } from '../../store';
|
||||
import { useMainStore } from 'src/store';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'MainUserSettings',
|
||||
|
@ -128,22 +128,20 @@ export default defineComponent({
|
|||
'update:user': (payload: FG.User) => !!payload,
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const store = useStore<UserSessionState>();
|
||||
const userStore = useUserStore();
|
||||
const mainStore = useMainStore();
|
||||
|
||||
const user_model = ref(props.user);
|
||||
|
||||
onBeforeMount(() => {
|
||||
store.dispatch('users/getRoles', false).catch((error) => {
|
||||
console.warn(error);
|
||||
});
|
||||
void userStore.getRoles(false);
|
||||
});
|
||||
|
||||
const isCurrentUser = computed(
|
||||
() => user_model.value.userid === store.state.users.currentUser?.userid
|
||||
);
|
||||
const isCurrentUser = computed(() => user_model.value.userid === mainStore.currentUser.userid);
|
||||
|
||||
const canSetRoles = computed(() => hasPermission('users_set_roles'));
|
||||
|
||||
const avatar = ref([]);
|
||||
const avatar = ref([] as string[]);
|
||||
function onAvatarRejected() {
|
||||
Notify.create({
|
||||
group: false,
|
||||
|
@ -156,7 +154,7 @@ export default defineComponent({
|
|||
avatar.value = [];
|
||||
}
|
||||
|
||||
const allRoles = computed(() => store.state.users.roles.map((role) => role.name));
|
||||
const allRoles = computed(() => userStore.roles.map((role) => role.name));
|
||||
const password = ref('');
|
||||
const new_password = ref('');
|
||||
const new_password2 = ref('');
|
||||
|
@ -176,12 +174,7 @@ export default defineComponent({
|
|||
emit('update:user', changed);
|
||||
|
||||
if (avatar.value && (avatar.value.length > 0 || avatar.value instanceof File))
|
||||
store
|
||||
.dispatch('users/uploadAvatar', {
|
||||
user: changed,
|
||||
file: avatar.value,
|
||||
})
|
||||
.catch((response: Response) => {
|
||||
userStore.uploadAvatar(changed, avatar.value[0]).catch((response: Response) => {
|
||||
if (response && response.status == 400) {
|
||||
onAvatarRejected();
|
||||
}
|
||||
|
@ -212,7 +205,7 @@ export default defineComponent({
|
|||
|
||||
function isUseridUsed(val: string) {
|
||||
return (
|
||||
!store.state.users.users.find((user: FG.User) => {
|
||||
!userStore.users.find((user: FG.User) => {
|
||||
return user.userid == val;
|
||||
}) ||
|
||||
!props.newUser ||
|
||||
|
|
|
@ -45,28 +45,23 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useStore } from 'vuex';
|
||||
import { UserSessionState } from '../../store';
|
||||
import { computed, defineComponent, ref, onBeforeMount } from 'vue';
|
||||
import { useUserStore } from '../../store';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'RoleSettings',
|
||||
setup() {
|
||||
const store = useStore<UserSessionState>();
|
||||
const userStore = useUserStore();
|
||||
|
||||
onBeforeMount(() => {
|
||||
store.dispatch('users/getRoles').catch((error) => {
|
||||
console.warn(error);
|
||||
});
|
||||
store.dispatch('users/getPermissions').catch((error) => {
|
||||
console.warn(error);
|
||||
});
|
||||
void userStore.getRoles();
|
||||
void userStore.getPermissions();
|
||||
});
|
||||
|
||||
const role = ref<FG.Role | null>(null);
|
||||
const roles = computed(() => store.state.users.roles);
|
||||
const roles = computed(() => userStore.roles);
|
||||
const permissions = computed(() =>
|
||||
store.state.users.permissions.map((perm) => {
|
||||
userStore.permissions.map((perm) => {
|
||||
return {
|
||||
value: perm,
|
||||
label: perm,
|
||||
|
@ -103,14 +98,14 @@ export default defineComponent({
|
|||
function save() {
|
||||
if (role.value) {
|
||||
if (role.value.id === -1)
|
||||
void store.dispatch('users/newRole', role.value).then((createdRole: FG.Role) => {
|
||||
void userStore.newRole(role.value).then((createdRole: FG.Role) => {
|
||||
console.log(createdRole);
|
||||
role.value = createdRole;
|
||||
});
|
||||
else {
|
||||
if (newRoleName.value !== '') role.value.name = newRoleName.value;
|
||||
console.log(role.value);
|
||||
void store.dispatch('users/updateRole', role.value);
|
||||
void userStore.updateRole(role.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,10 +124,7 @@ export default defineComponent({
|
|||
if (role.value.id === -1) {
|
||||
role.value = null;
|
||||
} else {
|
||||
store
|
||||
.dispatch('users/deleteRole', role.value)
|
||||
.then(() => (role.value = null))
|
||||
.catch((error) => console.warn(error));
|
||||
void userStore.deleteRole(role.value).then(() => (role.value = null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,21 +46,22 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { useStore } from 'vuex';
|
||||
import { defineComponent, ref, computed } from 'vue';
|
||||
import { UserSessionState } from '../../store';
|
||||
import { defineComponent, ref, computed, PropType } from 'vue';
|
||||
import { formatDateTime } from 'src/utils/datetime';
|
||||
import { useMainStore } from 'src/store';
|
||||
import { useSessionStore } from '../../store';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Sessions',
|
||||
props: {
|
||||
session: {
|
||||
required: true,
|
||||
type: Object,
|
||||
type: Object as PropType<FG.Session>,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore<UserSessionState>();
|
||||
const sessionStore = useSessionStore();
|
||||
const mainStore = useMainStore();
|
||||
|
||||
const dateTime = (date: Date) => formatDateTime(date, true);
|
||||
|
||||
|
@ -91,13 +92,11 @@ export default defineComponent({
|
|||
: 'mdi-help';
|
||||
}
|
||||
|
||||
function deleteSession(token: string) {
|
||||
store.dispatch('sessions/deleteSession', token).catch((error) => {
|
||||
console.warn(error);
|
||||
});
|
||||
async function deleteSession(token: string) {
|
||||
await sessionStore.deleteSession(token);
|
||||
}
|
||||
function isThisSession(token: string) {
|
||||
return store.state.sessions.currentSession?.token === token;
|
||||
return mainStore.session?.token === token;
|
||||
}
|
||||
|
||||
const isEdit = ref(false);
|
||||
|
@ -132,21 +131,14 @@ export default defineComponent({
|
|||
});
|
||||
|
||||
function edit(value: boolean) {
|
||||
lifetime.value = (<FG.Session>props.session).lifetime;
|
||||
lifetime.value = props.session.lifetime;
|
||||
isEdit.value = value;
|
||||
}
|
||||
|
||||
function save() {
|
||||
async function save() {
|
||||
console.log(lifetime.value);
|
||||
isEdit.value = false;
|
||||
void store
|
||||
.dispatch('sessions/updateSession', {
|
||||
lifetime: lifetime.value,
|
||||
token: (<FG.Session>props.session).token,
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
await sessionStore.updateSession(lifetime.value, props.session.token);
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -14,36 +14,29 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onBeforeMount, ref } from 'vue';
|
||||
import { defineComponent, onBeforeMount, ref } from 'vue';
|
||||
import Sessions from '../components/settings/Sessions.vue';
|
||||
import MainUserSettings from '../components/settings/MainUserSettings.vue';
|
||||
import { useStore } from 'vuex';
|
||||
import setLoadingBar from 'src/utils/loading';
|
||||
import { UserSessionState } from '../store';
|
||||
import { useMainStore } from 'src/store';
|
||||
import { useSessionStore } from '../store';
|
||||
import { useUserStore } from '../store';
|
||||
|
||||
export default defineComponent({
|
||||
// name: 'PageName'
|
||||
components: { Sessions, MainUserSettings },
|
||||
setup() {
|
||||
const store = useStore<UserSessionState>();
|
||||
const mainStore = useMainStore();
|
||||
const sessionStore = useSessionStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
onBeforeMount(() => {
|
||||
store.dispatch('sessions/getSessions').catch((error) => {
|
||||
console.warn(error);
|
||||
});
|
||||
});
|
||||
onBeforeMount(() => sessionStore.getSessions().then((s) => (sessions.value = s)));
|
||||
const currentUser = ref(mainStore.currentUser);
|
||||
const sessions = ref([] as FG.Session[]);
|
||||
|
||||
const currentUser = ref(<FG.User>store.state.users.currentUser);
|
||||
const sessions = computed(() => store.state.sessions.sessions);
|
||||
const loading = computed(() => store.state.sessions.loading || store.state.users.loading > 0);
|
||||
function updateUser(value: FG.User) {
|
||||
store.dispatch('users/updateUser', value).catch((error) => {
|
||||
console.warn(error);
|
||||
});
|
||||
async function updateUser(value: FG.User) {
|
||||
await userStore.updateUser(value);
|
||||
}
|
||||
|
||||
setLoadingBar(loading);
|
||||
|
||||
return {
|
||||
currentUser,
|
||||
sessions,
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import { Module } from 'vuex';
|
||||
import routes from './routes';
|
||||
import { FG_Plugin } from 'src/plugins';
|
||||
import { defineAsyncComponent } from 'vue';
|
||||
import { UserSessionState } from './store';
|
||||
import usersStore, { UserStateInterface } from './store/user';
|
||||
import sessionsStorage, { SessionStateInterface } from './store/session';
|
||||
|
||||
const plugin: FG_Plugin.Plugin = {
|
||||
name: 'User',
|
||||
|
@ -12,13 +8,6 @@ const plugin: FG_Plugin.Plugin = {
|
|||
requiredModules: [],
|
||||
requiredBackendModules: ['auth'],
|
||||
version: '0.0.1',
|
||||
store: new Map<
|
||||
string,
|
||||
Module<UserStateInterface, UserSessionState> | Module<SessionStateInterface, UserSessionState>
|
||||
>([
|
||||
['users', usersStore],
|
||||
['sessions', sessionsStorage],
|
||||
]),
|
||||
widgets: [
|
||||
{
|
||||
priority: 1,
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
import { FG_Plugin } from 'src/plugins';
|
||||
import { useMainStore } from 'src/store';
|
||||
import { computed } from 'vue';
|
||||
|
||||
const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
|
||||
{
|
||||
title: 'loadFromStore("users/displayName")',
|
||||
get title() {
|
||||
return computed(() => useMainStore().user?.display_name || 'Not loaded');
|
||||
},
|
||||
icon: 'mdi-account',
|
||||
permissions: ['user'],
|
||||
route: { path: 'user', name: 'user', component: () => import('../pages/MainPage.vue') },
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
import { defineStore } from 'pinia';
|
||||
import { api } from 'src/boot/axios';
|
||||
import { AxiosError, AxiosResponse } from 'axios';
|
||||
import { useMainStore } from 'src/store';
|
||||
|
||||
export const useUserStore = defineStore({
|
||||
id: 'users',
|
||||
|
||||
state: () => ({
|
||||
roles: [] as FG.Role[],
|
||||
users: [] as FG.User[],
|
||||
permissions: [] as FG.Permission[],
|
||||
_dirty_users: 0,
|
||||
_dirty_roles: 0,
|
||||
}),
|
||||
|
||||
getters: {
|
||||
isDirty() {
|
||||
return new Date().getTime() - this._dirty_users > 60000;
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
async getUser(userid: string, force = true) {
|
||||
const idx = this.users.findIndex((user) => user.userid === userid);
|
||||
if (force || idx == -1 || this.isDirty) {
|
||||
try {
|
||||
const { data } = await api.get<FG.User>(`/users/${userid}`);
|
||||
if (data.birthday) data.birthday = new Date(data.birthday);
|
||||
if (idx === -1) this.users.push(data);
|
||||
else this.users[idx] = data;
|
||||
return data;
|
||||
} catch (error) {
|
||||
if (!error || !('response' in error) || (<AxiosError>error).response?.status !== 404)
|
||||
throw error;
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
return this.users[idx];
|
||||
}
|
||||
},
|
||||
|
||||
async getUsers(force = true) {
|
||||
if (force || this.isDirty) {
|
||||
const { data } = await api.get<FG.User[]>('/users');
|
||||
data.forEach((user) => {
|
||||
if (user.birthday) user.birthday = new Date(user.birthday);
|
||||
});
|
||||
this.users = data;
|
||||
this._dirty_users = new Date().getTime();
|
||||
} else {
|
||||
return this.users;
|
||||
}
|
||||
},
|
||||
|
||||
async updateUser(user: FG.User) {
|
||||
await api.put(`/users/${user.userid}`, user);
|
||||
|
||||
const mainStore = useMainStore();
|
||||
if (user.userid === mainStore.user?.userid) mainStore.user = user;
|
||||
this._dirty_users = 0;
|
||||
},
|
||||
|
||||
async createUser(user: FG.User) {
|
||||
const { data } = await api.post<FG.User>('/users', user);
|
||||
this.users.push(data);
|
||||
return data;
|
||||
},
|
||||
|
||||
async uploadAvatar(user: FG.User, file: string) {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
await api.post(`/users/${user.userid}/avatar`, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
async getPermissions(force = false) {
|
||||
if (force || this.permissions.length === 0) {
|
||||
const { data } = await api.get<FG.Permission[]>('/roles/permissions');
|
||||
this.permissions = data;
|
||||
}
|
||||
return this.permissions;
|
||||
},
|
||||
|
||||
async getRoles(force = false) {
|
||||
if (force || new Date().getTime() - this._dirty_roles > 60000) {
|
||||
const { data } = await api.get<FG.Role[]>('/roles');
|
||||
this.roles = data;
|
||||
this._dirty_roles = new Date().getTime();
|
||||
}
|
||||
return this.roles;
|
||||
},
|
||||
|
||||
async updateRole(role: FG.Role) {
|
||||
await api.put(`/roles/${role.id}`, role);
|
||||
const idx = this.roles.findIndex((r) => r.id === role.id);
|
||||
if (idx != -1) this.roles[idx] = role;
|
||||
this._dirty_roles = 0;
|
||||
},
|
||||
|
||||
async newRole(role: FG.Role) {
|
||||
const { data } = await api.post<FG.Role>('/roles', role);
|
||||
this.roles.push(data);
|
||||
this._dirty_roles = 0;
|
||||
return data;
|
||||
},
|
||||
|
||||
async deleteRole(role: FG.Role | number) {
|
||||
await api.delete(`/roles/${typeof role === 'number' ? role : role.id}`);
|
||||
this.roles = this.roles.filter((r) => r.id !== (typeof role == 'number' ? role : role.id));
|
||||
this._dirty_roles = 0;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const useSessionStore = defineStore({
|
||||
id: 'sessions',
|
||||
|
||||
state: () => ({}),
|
||||
|
||||
getters: {},
|
||||
|
||||
actions: {
|
||||
async getSession(token: string) {
|
||||
return await api
|
||||
.get(`/auth/${token}`)
|
||||
.then(({ data }: AxiosResponse<FG.Session>) => data)
|
||||
.catch(() => null);
|
||||
},
|
||||
|
||||
async getSessions() {
|
||||
try {
|
||||
const { data } = await api.get<FG.Session[]>('/auth');
|
||||
data.forEach((session) => {
|
||||
session.expires = new Date(session.expires);
|
||||
});
|
||||
|
||||
const mainStore = useMainStore();
|
||||
const currentSession = data.find((session) => {
|
||||
return session.token === mainStore.session?.token;
|
||||
});
|
||||
if (currentSession) {
|
||||
mainStore.session = currentSession;
|
||||
}
|
||||
return data;
|
||||
} catch (error) {
|
||||
return [] as FG.Session[];
|
||||
}
|
||||
},
|
||||
|
||||
async deleteSession(token: string) {
|
||||
const mainStore = useMainStore();
|
||||
if (token === mainStore.session?.token) return mainStore.logout();
|
||||
|
||||
try {
|
||||
await api.delete(`/auth/${token}`);
|
||||
return true;
|
||||
} catch (error) {
|
||||
if (!error || !('response' in error) || (<AxiosError>error).response?.status != 401)
|
||||
throw error;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
async updateSession(lifetime: number, token: string) {
|
||||
try {
|
||||
const { data } = await api.put<FG.Session>(`auth/${token}`, { value: lifetime });
|
||||
data.expires = new Date(data.expires);
|
||||
|
||||
const mainStore = useMainStore();
|
||||
if (mainStore.session?.token == data.token) mainStore.session = data;
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,7 +0,0 @@
|
|||
import { SessionStateInterface } from './session';
|
||||
import { UserStateInterface } from './user';
|
||||
|
||||
export interface UserSessionState {
|
||||
sessions: SessionStateInterface;
|
||||
users: UserStateInterface;
|
||||
}
|
|
@ -1,199 +0,0 @@
|
|||
import { Module, MutationTree, ActionTree, GetterTree } from 'vuex';
|
||||
import { LoginData, LoginResponse } from 'src/plugins/user/models';
|
||||
import { api } from 'src/boot/axios';
|
||||
import { AxiosError, AxiosResponse } from 'axios';
|
||||
import { LocalStorage } from 'quasar';
|
||||
import { UserSessionState } from '.';
|
||||
import { Router } from 'src/router';
|
||||
|
||||
export interface SessionStateInterface {
|
||||
currentSession?: FG.Session;
|
||||
sessions: FG.Session[];
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load current session from LocalStorage
|
||||
* Used when we were already authenticated using this browser
|
||||
*/
|
||||
function loadCurrentSession() {
|
||||
const session = LocalStorage.getItem<FG.Session>('currentSession');
|
||||
if (session) session.expires = new Date(session.expires);
|
||||
return session;
|
||||
}
|
||||
|
||||
const state: SessionStateInterface = {
|
||||
sessions: [],
|
||||
currentSession: loadCurrentSession() || undefined,
|
||||
loading: false,
|
||||
};
|
||||
|
||||
const mutations: MutationTree<SessionStateInterface> = {
|
||||
setCurrentSession(state, session: FG.Session) {
|
||||
LocalStorage.set('currentSession', session);
|
||||
state.currentSession = session;
|
||||
},
|
||||
clearCurrentSession(state) {
|
||||
LocalStorage.remove('currentSession');
|
||||
state.currentSession = undefined;
|
||||
},
|
||||
setSessions(state, sessions: FG.Session[]) {
|
||||
state.sessions = sessions;
|
||||
},
|
||||
setLoading(state, value: boolean) {
|
||||
state.loading = value;
|
||||
},
|
||||
updateSession(state, session: FG.Session) {
|
||||
const index = state.sessions.findIndex((x) => x.token == session.token);
|
||||
if (index > -1) {
|
||||
state.sessions[index] = session;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const actions: ActionTree<SessionStateInterface, UserSessionState> = {
|
||||
/** Used to authenticate the user
|
||||
* Setting current Session, User and Permissions.
|
||||
* @param param0 Context
|
||||
* @param data Credentitals
|
||||
*/
|
||||
login({ commit }, data: LoginData) {
|
||||
return api
|
||||
.post('/auth', data)
|
||||
.then((response: AxiosResponse<LoginResponse>) => {
|
||||
response.data.session.expires = new Date(response.data.session.expires);
|
||||
commit('setCurrentSession', response.data.session);
|
||||
commit('users/setCurrentUser', response.data.user, { root: true });
|
||||
commit('users/setCurrentPermissions', response.data.permissions, {
|
||||
root: true,
|
||||
});
|
||||
})
|
||||
.catch((error: AxiosError) => {
|
||||
return Promise.reject(error.response);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Logout from current session
|
||||
* Alias of deleteSession with current session as target
|
||||
*/
|
||||
logout({ dispatch, rootState }) {
|
||||
if (rootState.sessions.currentSession) {
|
||||
dispatch('deleteSession', rootState.sessions.currentSession.token).catch((error) => {
|
||||
console.log(error);
|
||||
void dispatch('clearCurrent', false);
|
||||
});
|
||||
} else {
|
||||
void dispatch('clearCurrent', false);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Delete a given session
|
||||
*/
|
||||
deleteSession({ commit, dispatch, rootState }, token: string) {
|
||||
commit('setLoading', true);
|
||||
api
|
||||
.delete(`/auth/${token}`)
|
||||
.then(() => {
|
||||
if (token === rootState.sessions.currentSession?.token) {
|
||||
void dispatch('clearCurrent', false);
|
||||
} else {
|
||||
dispatch('getSessions').catch((error) => {
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((error: AxiosError) => {
|
||||
if (!error.response || error.response.status != 401) throw error;
|
||||
})
|
||||
.finally(() => {
|
||||
commit('setLoading', false);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Clear current session and logged in user
|
||||
*/
|
||||
clearCurrent({ commit }, redirect = true) {
|
||||
void Router.push({
|
||||
name: 'login',
|
||||
query: redirect ? { redirect: Router.currentRoute.value.fullPath } : {},
|
||||
params: { logout: 'true' },
|
||||
}).then(() => {
|
||||
commit('clearCurrentSession');
|
||||
commit('users/clearCurrentUser', null, { root: true });
|
||||
// ensure also volatile store gets cleared by refreshing the site
|
||||
Router.go(0);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Get all sessions from current User
|
||||
*/
|
||||
getSessions({ commit, state }) {
|
||||
commit('setLoading', true);
|
||||
api
|
||||
.get('/auth')
|
||||
.then((response: AxiosResponse<FG.Session[]>) => {
|
||||
response.data.forEach((session) => {
|
||||
session.expires = new Date(session.expires);
|
||||
});
|
||||
commit('setSessions', response.data);
|
||||
const currentSession = response.data.find((session: FG.Session) => {
|
||||
return session.token === state.currentSession?.token;
|
||||
});
|
||||
if (currentSession) {
|
||||
commit('setCurrentSession', currentSession);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
throw error;
|
||||
})
|
||||
.finally(() => {
|
||||
commit('setLoading', false);
|
||||
});
|
||||
},
|
||||
updateSession({ commit, state }, data: { lifetime: number; token: string }) {
|
||||
commit('setLoading', true);
|
||||
api
|
||||
.put(`auth/${data.token}`, { value: data.lifetime })
|
||||
.then((response: AxiosResponse<FG.Session>) => {
|
||||
response.data.expires = new Date(response.data.expires);
|
||||
if (state.currentSession?.token == response.data.token) {
|
||||
commit('setCurrentSession', response.data);
|
||||
}
|
||||
})
|
||||
.catch((err) => console.log(err))
|
||||
.finally(() => {
|
||||
commit('setLoading', false);
|
||||
});
|
||||
console.log('updateSession', data);
|
||||
},
|
||||
requestPasswordReset({}, data) {
|
||||
return api.post('/auth/reset', data);
|
||||
},
|
||||
resetPassword({}, data) {
|
||||
return api.post('/auth/reset', data).catch((error: AxiosError) => {
|
||||
return Promise.reject(error.response);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
const getters: GetterTree<SessionStateInterface, UserSessionState> = {
|
||||
currentSession(state) {
|
||||
return state.currentSession;
|
||||
},
|
||||
sessions(state) {
|
||||
return state.sessions;
|
||||
},
|
||||
loading(state) {
|
||||
return state.loading;
|
||||
},
|
||||
};
|
||||
|
||||
const sessionsStore: Module<SessionStateInterface, UserSessionState> = {
|
||||
namespaced: true,
|
||||
state,
|
||||
mutations,
|
||||
actions,
|
||||
getters,
|
||||
};
|
||||
|
||||
export default sessionsStore;
|
|
@ -1,275 +0,0 @@
|
|||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
import { Module, MutationTree, ActionTree, GetterTree } from 'vuex';
|
||||
import { api } from 'boot/axios';
|
||||
import { AxiosError, AxiosResponse } from 'axios';
|
||||
import { SessionStorage } from 'quasar';
|
||||
import { CurrentUserResponse } from 'src/plugins/user/models';
|
||||
import { UserSessionState } from '.';
|
||||
|
||||
export interface UserStateInterface {
|
||||
currentUser?: FG.User;
|
||||
currentPermissions: FG.Permission[];
|
||||
users: FG.User[];
|
||||
roles: FG.Role[];
|
||||
permissions: FG.Permission[];
|
||||
loading: number;
|
||||
}
|
||||
|
||||
function loadUserFromLocalStorage() {
|
||||
const user = SessionStorage.getItem<FG.User>('currentUser') || undefined;
|
||||
if (user && user.birthday && typeof user.birthday === 'string')
|
||||
user.birthday = new Date(user.birthday);
|
||||
return user;
|
||||
}
|
||||
const state: UserStateInterface = {
|
||||
users: [],
|
||||
roles: [],
|
||||
permissions: [],
|
||||
currentUser: loadUserFromLocalStorage(),
|
||||
currentPermissions: SessionStorage.getItem<FG.Permission[]>('currentPermissions') || [],
|
||||
loading: 0,
|
||||
};
|
||||
|
||||
const mutations: MutationTree<UserStateInterface> = {
|
||||
setCurrentUser(state, data: FG.User) {
|
||||
if (typeof data.birthday === 'string') data.birthday = new Date(data.birthday);
|
||||
SessionStorage.set('currentUser', data);
|
||||
state.currentUser = data;
|
||||
},
|
||||
setCurrentPermissions(state, data: FG.Permission[]) {
|
||||
SessionStorage.set('currentPermissions', data);
|
||||
state.currentPermissions = data;
|
||||
},
|
||||
clearCurrentUser(state) {
|
||||
SessionStorage.remove('currentUser');
|
||||
SessionStorage.remove('currentPermissions');
|
||||
state.currentUser = undefined;
|
||||
state.currentPermissions = [];
|
||||
},
|
||||
setUsers(state, data: FG.User[]) {
|
||||
state.users = data;
|
||||
},
|
||||
setUser(state, data: FG.User) {
|
||||
const index = state.users.findIndex((x) => x.userid === data.userid);
|
||||
if (index > -1) state.users[index] = data;
|
||||
else state.users.push(data);
|
||||
},
|
||||
setRoles(state, data: FG.Role[]) {
|
||||
state.roles = data;
|
||||
},
|
||||
addRole(state, data: FG.Role) {
|
||||
state.roles.push(data);
|
||||
},
|
||||
updateRole(state, data: FG.Role) {
|
||||
const idx = state.roles.findIndex((role) => role.id === data.id);
|
||||
if (idx >= 0) {
|
||||
state.roles[idx].name = data.name;
|
||||
state.roles[idx].permissions = data.permissions;
|
||||
}
|
||||
},
|
||||
setPermissions(state, data: FG.Permission[]) {
|
||||
state.permissions = data;
|
||||
},
|
||||
setLoading(state, data = true) {
|
||||
if (data) state.loading += 1;
|
||||
else state.loading -= 1;
|
||||
},
|
||||
};
|
||||
|
||||
const actions: ActionTree<UserStateInterface, UserSessionState> = {
|
||||
getCurrentUser({ commit, rootState }) {
|
||||
if (rootState.sessions.currentSession) {
|
||||
commit('setLoading');
|
||||
api
|
||||
.get(`/users/${rootState.sessions.currentSession.userid}`)
|
||||
.then((response: AxiosResponse<CurrentUserResponse>) => {
|
||||
commit('setCurrentUser', response.data);
|
||||
commit('setCurrentPermissions', response.data.permissions);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn(err);
|
||||
})
|
||||
.finally(() => {
|
||||
commit('setLoading', false);
|
||||
});
|
||||
} else {
|
||||
console.debug('User not logged in, can not get current_user.');
|
||||
}
|
||||
},
|
||||
|
||||
getUsers({ commit }) {
|
||||
commit('setLoading');
|
||||
api
|
||||
.get('/users')
|
||||
.then((response: AxiosResponse<FG.User[]>) => {
|
||||
response.data.forEach((user) => {
|
||||
if (user.birthday) user.birthday = new Date(user.birthday);
|
||||
});
|
||||
commit('setUsers', response.data);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn(err);
|
||||
})
|
||||
.finally(() => {
|
||||
commit('setLoading', false);
|
||||
});
|
||||
},
|
||||
|
||||
updateUser({ commit, state, dispatch }, data: FG.User) {
|
||||
commit('setLoading');
|
||||
api
|
||||
.put(`/users/${data.userid}`, data)
|
||||
.then(() => {
|
||||
if (state.currentUser && state.currentUser.userid === data.userid)
|
||||
void dispatch('getCurrentUser');
|
||||
else void dispatch('getUsers');
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
})
|
||||
.finally(() => {
|
||||
commit('setLoading', false);
|
||||
});
|
||||
},
|
||||
|
||||
uploadAvatar({ commit }, payload: { user: FG.User; file: string }) {
|
||||
commit('setLoading');
|
||||
const formData = new FormData();
|
||||
formData.append('file', payload.file);
|
||||
return api
|
||||
.post(`/users/${payload.user.userid}/avatar`, formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
})
|
||||
.catch((error: AxiosError) => {
|
||||
return Promise.reject(error.response);
|
||||
})
|
||||
.finally(() => {
|
||||
commit('setLoading', false);
|
||||
});
|
||||
},
|
||||
|
||||
setUser({ commit, state, dispatch }, data: FG.User) {
|
||||
commit('setLoading');
|
||||
api
|
||||
.post('users', data)
|
||||
.then(() => {
|
||||
if (state.currentUser && state.currentUser.userid === data.userid)
|
||||
void dispatch('getCurrentUser');
|
||||
else void dispatch('getUsers');
|
||||
})
|
||||
.catch((error) => {
|
||||
console.warn(error);
|
||||
})
|
||||
.finally(() => {
|
||||
commit('setLoading', false);
|
||||
});
|
||||
},
|
||||
|
||||
getRoles({ commit, state }, force = false) {
|
||||
if (!force && state.roles.length > 0) return;
|
||||
commit('setLoading');
|
||||
api
|
||||
.get('/roles')
|
||||
.then((response: AxiosResponse<FG.Role[]>) => {
|
||||
commit('setRoles', response.data);
|
||||
})
|
||||
.finally(() => commit('setLoading', false));
|
||||
},
|
||||
|
||||
updateRole({ commit }, data: FG.Role) {
|
||||
commit('setLoading');
|
||||
api
|
||||
.put(`/roles/${data.id}`, data)
|
||||
.then(() => {
|
||||
commit('updateRole', data);
|
||||
})
|
||||
.finally(() => {
|
||||
commit('setLoading', false);
|
||||
});
|
||||
},
|
||||
|
||||
newRole({ commit }, data: FG.Role) {
|
||||
commit('setLoading');
|
||||
return api
|
||||
.post('/roles', data)
|
||||
.then((response: AxiosResponse<FG.Role>) => {
|
||||
commit('addRole', response.data);
|
||||
return Promise.resolve(response.data);
|
||||
})
|
||||
.finally(() => {
|
||||
commit('setLoading', false);
|
||||
});
|
||||
},
|
||||
|
||||
deleteRole({ commit, state }, data: FG.Role) {
|
||||
commit('setLoading');
|
||||
api
|
||||
.delete(`/roles/${data.id}`)
|
||||
.then(() => {
|
||||
commit(
|
||||
'setRoles',
|
||||
state.roles.filter((value) => value.id !== data.id)
|
||||
);
|
||||
})
|
||||
.finally(() => {
|
||||
commit('setLoading', false);
|
||||
});
|
||||
},
|
||||
|
||||
getPermissions({ commit, state }, force = false) {
|
||||
if (!force && state.permissions.length > 0) return;
|
||||
commit('setLoading');
|
||||
api
|
||||
.get('/roles/permissions')
|
||||
.then((response: AxiosResponse<FG.Role[]>) => {
|
||||
commit('setPermissions', response.data);
|
||||
})
|
||||
.finally(() => commit('setLoading', false));
|
||||
},
|
||||
getUser({ commit, getters }, data: { userid: string; force?: boolean }) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
const user = <FG.User | undefined>getters['getUser'](data.userid);
|
||||
if (user === undefined || data.force === true) {
|
||||
return api.get(`/users/${data.userid}`).then((response: AxiosResponse<FG.User>) => {
|
||||
commit('setUser', response.data);
|
||||
return response.data;
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve(user);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const getters: GetterTree<UserStateInterface, UserSessionState> = {
|
||||
getUser: (state) => (userid: string) => {
|
||||
const user = state.users.filter((usr) => usr.userid === userid);
|
||||
return user.length > 0 ? user[0] : undefined;
|
||||
},
|
||||
currentUser({ currentUser }) {
|
||||
return currentUser;
|
||||
},
|
||||
users({ users }) {
|
||||
return users;
|
||||
},
|
||||
loading({ loading }) {
|
||||
return loading > 0;
|
||||
},
|
||||
displayName({ currentUser }) {
|
||||
return currentUser?.display_name;
|
||||
},
|
||||
roles({ roles }): string[] {
|
||||
return roles.map((role) => role.name).flat();
|
||||
},
|
||||
};
|
||||
|
||||
const usersStore: Module<UserStateInterface, UserSessionState> = {
|
||||
namespaced: true,
|
||||
actions,
|
||||
getters,
|
||||
mutations,
|
||||
state,
|
||||
};
|
||||
|
||||
export default usersStore;
|
|
@ -1,11 +1,7 @@
|
|||
import { store } from 'quasar/wrappers';
|
||||
import { createStore } from 'vuex';
|
||||
import { UserStateInterface } from 'src/plugins/user/store/user';
|
||||
import { SessionStateInterface } from 'src/plugins/user/store/session';
|
||||
|
||||
export interface StateInterface {
|
||||
users: UserStateInterface;
|
||||
sessions: SessionStateInterface;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
|
@ -20,3 +16,95 @@ export default store(function (/* { ssrContext } */) {
|
|||
|
||||
return Store;
|
||||
});
|
||||
|
||||
import { defineStore } from 'pinia';
|
||||
import { api } from 'src/boot/axios';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { LocalStorage } from 'quasar';
|
||||
import { useUserStore, useSessionStore } from 'src/plugins/user/store';
|
||||
|
||||
function loadCurrentSession() {
|
||||
const session = LocalStorage.getItem<FG.Session>('session');
|
||||
if (session) session.expires = new Date(session.expires);
|
||||
return session || undefined;
|
||||
}
|
||||
|
||||
export const useMainStore = defineStore({
|
||||
id: 'main',
|
||||
|
||||
state: () => ({
|
||||
session: loadCurrentSession(),
|
||||
user: undefined as FG.User | undefined,
|
||||
}),
|
||||
|
||||
getters: {
|
||||
loggedIn() {
|
||||
return this.session !== undefined;
|
||||
},
|
||||
currentUser() {
|
||||
if (this.user === undefined) throw 'Not logged in, this should not be called';
|
||||
return this.user;
|
||||
},
|
||||
permissions() {
|
||||
return this.user?.permissions || [];
|
||||
},
|
||||
},
|
||||
|
||||
actions: {
|
||||
/** Ininitalize store from saved session
|
||||
* Updates session and loads current user
|
||||
*/
|
||||
async init() {
|
||||
if (this.session) {
|
||||
const sessionStore = useSessionStore();
|
||||
const session = await sessionStore.getSession(this.session.token);
|
||||
if (session) {
|
||||
this.session = this.session;
|
||||
const userStore = useUserStore();
|
||||
const user = await userStore.getUser(this.session.userid);
|
||||
if (user) this.user = user;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async login(userid: string, password: string) {
|
||||
try {
|
||||
const { data } = await api.post<FG.Session>('/auth', { userid, password });
|
||||
this.session = data;
|
||||
this.session.expires = new Date(this.session.expires);
|
||||
LocalStorage.set('session', this.session);
|
||||
return true;
|
||||
} catch ({ response }) {
|
||||
return (<AxiosResponse | undefined>response)?.status || false;
|
||||
}
|
||||
},
|
||||
|
||||
logout() {
|
||||
if (!this.session) return false;
|
||||
|
||||
void api.delete(`/auth/${this.session.token}`);
|
||||
this.$patch({
|
||||
session: undefined,
|
||||
user: undefined,
|
||||
});
|
||||
LocalStorage.remove('session');
|
||||
return true;
|
||||
},
|
||||
|
||||
async requestReset(userid: string) {
|
||||
return await api
|
||||
.post('/auth/reset', { userid })
|
||||
.then(() => true)
|
||||
.catch(() => false);
|
||||
},
|
||||
|
||||
async resetPassword(token: string, password: string) {
|
||||
return await api
|
||||
.post('/auth/reset', { token, password })
|
||||
.then(() => true)
|
||||
.catch(({ response }) =>
|
||||
response && 'status' in response ? (<AxiosResponse>response).status : false
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,19 +1,16 @@
|
|||
import { useStore } from 'vuex';
|
||||
import { UserSessionState } from 'src/plugins/user/store';
|
||||
import { useMainStore } from 'src/store';
|
||||
|
||||
export function hasPermission(permission: string) {
|
||||
const store = useStore<UserSessionState>();
|
||||
return store.state.users.currentPermissions.includes(permission);
|
||||
const store = useMainStore();
|
||||
return store.permissions.includes(permission);
|
||||
}
|
||||
|
||||
export function hasPermissions(needed: string[]) {
|
||||
const store = useStore<UserSessionState>();
|
||||
const permissions = store.state.users.currentPermissions;
|
||||
return needed.every((value) => permissions.includes(value));
|
||||
const store = useMainStore();
|
||||
return needed.every((value) => store.permissions.includes(value));
|
||||
}
|
||||
|
||||
export function hasSomePermissions(needed: string[]) {
|
||||
const store = useStore<UserSessionState>();
|
||||
const permissions = store.state.users.currentPermissions;
|
||||
return needed.some((value) => permissions.includes(value));
|
||||
const store = useMainStore();
|
||||
return needed.some((value) => store.permissions.includes(value));
|
||||
}
|
||||
|
|
|
@ -7497,6 +7497,11 @@ pify@^5.0.0:
|
|||
resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f"
|
||||
integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==
|
||||
|
||||
pinia@^2.0.0-alpha.7:
|
||||
version "2.0.0-alpha.7"
|
||||
resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.0.0-alpha.7.tgz#3b55af0185a45e6e1a75ba90f6da3e1a61623767"
|
||||
integrity sha512-IXPG+4elwC+0h5r3FZUhcH+XwywMN+f9uxoMxzapz5ywBfo7BeE48wpC1o+81qnil5m3FhBOjMKZeS7t0t6ljw==
|
||||
|
||||
pinkie-promise@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
|
||||
|
|
Loading…
Reference in New Issue