release v2.0.0 #4
|
@ -103,7 +103,7 @@ module.exports = configure(function(ctx) {
|
|||
// directives: [],
|
||||
|
||||
// Quasar plugins
|
||||
plugins: ['LocalStorage', 'Loading']
|
||||
plugins: ['LocalStorage', 'SessionStorage', 'Loading']
|
||||
},
|
||||
|
||||
// animations: 'all', // --- includes all animations
|
||||
|
|
|
@ -7,6 +7,6 @@
|
|||
import { defineComponent } from '@vue/composition-api';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'App',
|
||||
name: 'App'
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -16,9 +16,9 @@ export default boot<Store<StateInterface>>(({ Vue, store }) => {
|
|||
axios.defaults.baseURL = config.baseURL;
|
||||
|
||||
axios.interceptors.request.use(config => {
|
||||
const session = store.state.user.session;
|
||||
if (session.token) {
|
||||
config.headers = {'Authorization': 'Bearer ' + session.token};
|
||||
const session = store.state.session.currentSession;
|
||||
if (session?.token) {
|
||||
config.headers = { Authorization: 'Bearer ' + session.token };
|
||||
}
|
||||
return config;
|
||||
});
|
||||
|
|
|
@ -1,53 +1,49 @@
|
|||
import { boot } from 'quasar/wrappers';
|
||||
import { StateInterface } from 'src/store';
|
||||
import { RouteRecord } from 'vue-router';
|
||||
import { Store } from 'vuex'
|
||||
import { Store } from 'vuex';
|
||||
|
||||
export default boot<Store<StateInterface>>(({ router, store }) => {
|
||||
router.beforeEach((to, from, next) => {
|
||||
store
|
||||
.dispatch('user/loadFromLocalStorage')
|
||||
.then(() => {
|
||||
const user = store.state.user.user;
|
||||
const session = store.state.user.session;
|
||||
const user = store.state.user.currentUser;
|
||||
const session = store.state.session.currentSession;
|
||||
|
||||
let permissions: string[] = [];
|
||||
user.roles.forEach(role => {
|
||||
permissions = permissions.concat(role.permissions);
|
||||
});
|
||||
|
||||
if (to.name != 'login') {
|
||||
if (session.expires >= new Date() || session.token === '') {
|
||||
store.dispatch('user/doLogout').catch(error => {
|
||||
console.warn(error);
|
||||
});
|
||||
return next({ name: 'login', query: { redirect: to.fullPath } });
|
||||
}
|
||||
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 permissions.includes(
|
||||
permission
|
||||
);
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
) {
|
||||
next();
|
||||
} else {
|
||||
next({ name: 'login', query: { redirect: to.fullPath } });
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.exception(error);
|
||||
let permissions: string[] = [];
|
||||
if (user) {
|
||||
user.roles.forEach(role => {
|
||||
permissions = permissions.concat(role.permissions);
|
||||
});
|
||||
}
|
||||
|
||||
if (to.name != 'login') {
|
||||
if (!session || session.expires <= new Date()) {
|
||||
store.dispatch('session/logout').catch(error => {
|
||||
console.warn(error);
|
||||
});
|
||||
return next({ name: 'login', query: { redirect: to.fullPath } });
|
||||
}
|
||||
|
||||
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 permissions.includes(permission);
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
) {
|
||||
next();
|
||||
} else {
|
||||
next({ name: 'login', query: { redirect: to.fullPath } });
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
const config = {
|
||||
baseURL: '/api'
|
||||
baseURL: '/api'
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
|
|
@ -1,57 +1,58 @@
|
|||
declare namespace FG {
|
||||
interface Session {
|
||||
expires: Date;
|
||||
token: string;
|
||||
lifetime: number;
|
||||
browser: string;
|
||||
platform: string;
|
||||
}
|
||||
interface User {
|
||||
userid: string;
|
||||
display_name: string;
|
||||
firstname: string;
|
||||
lastname: string;
|
||||
mail: string;
|
||||
roles: Array<Role>;
|
||||
}
|
||||
type Permission = string;
|
||||
interface Role {
|
||||
name: string;
|
||||
permissions: Array<Permission>;
|
||||
}
|
||||
interface Transaction {
|
||||
id: number;
|
||||
time: Date;
|
||||
amount: number;
|
||||
sender_id: string;
|
||||
receiver_id: string;
|
||||
author_id: string;
|
||||
}
|
||||
interface Event {
|
||||
id: number;
|
||||
start: Date;
|
||||
description?: any;
|
||||
type: EventType;
|
||||
slots: Array<EventSlot>;
|
||||
}
|
||||
interface EventSlot {
|
||||
id: number;
|
||||
start: Date;
|
||||
end?: any;
|
||||
jobs: Array<JobSlot>;
|
||||
}
|
||||
type EventType = string;
|
||||
interface Job {
|
||||
userid: string;
|
||||
value: number;
|
||||
}
|
||||
interface JobSlot {
|
||||
type: JobType;
|
||||
users: Array<Job>;
|
||||
required_jobs: number;
|
||||
}
|
||||
interface JobType {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
interface Session {
|
||||
expires: Date;
|
||||
token: string;
|
||||
lifetime: number;
|
||||
browser: string;
|
||||
platform: string;
|
||||
userid: string;
|
||||
}
|
||||
interface User {
|
||||
userid: string;
|
||||
display_name: string;
|
||||
firstname: string;
|
||||
lastname: string;
|
||||
mail: string;
|
||||
roles: Array<Role>;
|
||||
}
|
||||
type Permission = string;
|
||||
interface Role {
|
||||
name: string;
|
||||
permissions: Array<Permission>;
|
||||
}
|
||||
interface Transaction {
|
||||
id: number;
|
||||
time: Date;
|
||||
amount: number;
|
||||
sender_id: string;
|
||||
receiver_id: string;
|
||||
author_id: string;
|
||||
}
|
||||
interface Event {
|
||||
id: number;
|
||||
start: Date;
|
||||
description?: any;
|
||||
type: EventType;
|
||||
slots: Array<EventSlot>;
|
||||
}
|
||||
interface EventSlot {
|
||||
id: number;
|
||||
start: Date;
|
||||
end?: any;
|
||||
jobs: Array<JobSlot>;
|
||||
}
|
||||
type EventType = string;
|
||||
interface Job {
|
||||
userid: string;
|
||||
value: number;
|
||||
}
|
||||
interface JobSlot {
|
||||
type: JobType;
|
||||
users: Array<Job>;
|
||||
required_jobs: number;
|
||||
}
|
||||
interface JobType {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,24 +1,34 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title><%= productName %></title>
|
||||
|
||||
<head>
|
||||
<title><%= productName %></title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="description" content="<%= productDescription %>" />
|
||||
<meta name="format-detection" content="telephone=no" />
|
||||
<meta name="msapplication-tap-highlight" content="no" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>"
|
||||
/>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="description" content="<%= productDescription %>">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="msapplication-tap-highlight" content="no">
|
||||
<meta name="viewport"
|
||||
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>">
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="128x128"
|
||||
href="icons/favicon-128x128.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
sizes="32x32"
|
||||
href="icons/favicon-32x32.png"
|
||||
/>
|
||||
<link rel="icon" type="image/ico" href="favicon.ico" />
|
||||
</head>
|
||||
|
||||
<link rel="icon" type="image/png" sizes="128x128" href="icons/favicon-128x128.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="icons/favicon-32x32.png">
|
||||
<link rel="icon" type="image/ico" href="favicon.ico">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<!-- DO NOT touch the following DIV -->
|
||||
<div id="q-app"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
<body>
|
||||
<!-- DO NOT touch the following DIV -->
|
||||
<div id="q-app"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
<q-toolbar-title>
|
||||
<q-avatar>
|
||||
<img src="logo.svg"/>
|
||||
<img src="logo.svg" />
|
||||
</q-avatar>
|
||||
<span class="gt-xs">
|
||||
Flaschengeist
|
||||
|
@ -31,7 +31,7 @@
|
|||
:permissions="shortcut.permissions"
|
||||
/>
|
||||
</div>
|
||||
<q-btn flat round dense icon="mdi-exit-to-app" @click="logout()"/>
|
||||
<q-btn flat round dense icon="mdi-exit-to-app" @click="logout()" />
|
||||
</q-toolbar>
|
||||
</q-header>
|
||||
|
||||
|
@ -54,7 +54,7 @@
|
|||
:permissions="link.permissions"
|
||||
/>
|
||||
</q-list>
|
||||
<q-separator/>
|
||||
<q-separator />
|
||||
|
||||
<!-- Plugin functions -->
|
||||
<!-- <router-view name="plugin-nav" /> -->
|
||||
|
@ -81,7 +81,7 @@
|
|||
/>
|
||||
</div>
|
||||
|
||||
<q-separator/>
|
||||
<q-separator />
|
||||
|
||||
<essential-link
|
||||
v-for="(link, index) in links"
|
||||
|
@ -94,7 +94,7 @@
|
|||
</q-drawer>
|
||||
|
||||
<q-page-container>
|
||||
<router-view/>
|
||||
<router-view />
|
||||
</q-page-container>
|
||||
</q-layout>
|
||||
</template>
|
||||
|
@ -102,11 +102,11 @@
|
|||
<script lang="ts">
|
||||
import EssentialLink from 'components/navigation/EssentialLink.vue';
|
||||
import ShortCutLink from 'components/navigation/ShortCutLink.vue';
|
||||
import {Screen} from 'quasar';
|
||||
import {defineComponent, ref, computed} from '@vue/composition-api';
|
||||
import {Store} from 'vuex';
|
||||
import {StateInterface} from 'src/store';
|
||||
import {FG_Plugin} from 'src/plugins';
|
||||
import { Screen } from 'quasar';
|
||||
import { defineComponent, ref, computed } from '@vue/composition-api';
|
||||
import { Store } from 'vuex';
|
||||
import { StateInterface } from 'src/store';
|
||||
import { FG_Plugin } from 'src/plugins';
|
||||
|
||||
const links = [
|
||||
{
|
||||
|
@ -140,7 +140,7 @@ declare module 'vue/types/vue' {
|
|||
|
||||
export default defineComponent({
|
||||
name: 'MainLayout',
|
||||
components: {EssentialLink, ShortCutLink},
|
||||
components: { EssentialLink, ShortCutLink },
|
||||
setup(_, ctx) {
|
||||
const leftDrawer = ref(false);
|
||||
|
||||
|
@ -179,7 +179,7 @@ export default defineComponent({
|
|||
function logout() {
|
||||
const store = <Store<StateInterface>>ctx.root.$store;
|
||||
store
|
||||
.dispatch('user/logout', store.state.user.session.token)
|
||||
.dispatch('session/logout', store.state.session.currentSession?.token)
|
||||
.catch(error => {
|
||||
console.warn(error);
|
||||
});
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<template>
|
||||
<div class="fullscreen bg-blue text-white text-center q-pa-md flex flex-center">
|
||||
<div
|
||||
class="fullscreen bg-blue text-white text-center q-pa-md flex flex-center"
|
||||
>
|
||||
<div>
|
||||
<div style="font-size: 30vh">
|
||||
404
|
||||
|
@ -26,6 +28,6 @@
|
|||
import { defineComponent } from '@vue/composition-api';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'Error404',
|
||||
name: 'Error404'
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -48,7 +48,7 @@ export default defineComponent({
|
|||
function doLogin() {
|
||||
console.log(userid.value, password.value);
|
||||
ctx.root.$store
|
||||
.dispatch('user/login', {
|
||||
.dispatch('session/login', {
|
||||
userid: userid.value,
|
||||
password: password.value
|
||||
})
|
||||
|
|
|
@ -13,7 +13,7 @@ declare namespace FG_Plugin {
|
|||
title: string;
|
||||
icon: string;
|
||||
children?: PluginRouteConfig[];
|
||||
meta?: {permissions?: string[]}
|
||||
meta?: { permissions?: string[] };
|
||||
}
|
||||
|
||||
interface Plugin {
|
||||
|
@ -34,7 +34,7 @@ declare namespace FG_Plugin {
|
|||
title: string;
|
||||
link: string;
|
||||
icon: string;
|
||||
permissions?: string[]
|
||||
permissions?: string[];
|
||||
}
|
||||
|
||||
interface LoadedPlugin {
|
||||
|
|
|
@ -38,7 +38,8 @@ const mutations: MutationTree<BalanceInterface> = {
|
|||
const actions: ActionTree<BalanceInterface, StateInterface> = {
|
||||
getBalance({ commit, rootState }) {
|
||||
axios
|
||||
.get(`/users/${rootState.user.user.userid}/balance`)
|
||||
/* eslint-disable-next-line @typescript-eslint/restrict-template-expressions */
|
||||
.get(`/users/${rootState.user.currentUser?.userid}/balance`)
|
||||
.then(({ data }: AxiosResponse<BalanceResponse>) => {
|
||||
commit('setBalance', data.balance);
|
||||
commit('setCredit', data.credit);
|
||||
|
@ -50,7 +51,8 @@ const actions: ActionTree<BalanceInterface, StateInterface> = {
|
|||
},
|
||||
getLimit({ rootState }) {
|
||||
axios
|
||||
.get(`/users/${rootState.user.user.userid}/balance/limit`)
|
||||
/* eslint-disable-next-line @typescript-eslint/restrict-template-expressions */
|
||||
.get(`/users/${rootState.user.currentUser?.userid}/balance/limit`)
|
||||
.then(({ data }) => {
|
||||
console.log(data);
|
||||
})
|
||||
|
@ -60,7 +62,10 @@ const actions: ActionTree<BalanceInterface, StateInterface> = {
|
|||
},
|
||||
changeBalance({ rootState, dispatch }, amount: number) {
|
||||
axios
|
||||
.put(`/users/${rootState.user.user.userid}/balance`, <{ amount: number }>{
|
||||
/* eslint-disable-next-line @typescript-eslint/restrict-template-expressions */
|
||||
.put(`/users/${rootState.user.currentUser?.userid}/balance`, <
|
||||
{ amount: number }
|
||||
>{
|
||||
amount: amount
|
||||
})
|
||||
.then(() => {
|
||||
|
|
|
@ -100,14 +100,12 @@ export default defineComponent({
|
|||
setup(_, { root }) {
|
||||
const store = <Store<StateInterface>>root.$store;
|
||||
|
||||
const user = computed<FG.User>(() => {
|
||||
return store.state.user.user;
|
||||
});
|
||||
const user = computed(() => <FG.User>store.state.user.currentUser);
|
||||
|
||||
const firstname = ref(user.value.firstname);
|
||||
const lastname = ref(user.value.lastname);
|
||||
const mail = ref(user.value.mail);
|
||||
const display_name = ref(user.value.display_name);
|
||||
const firstname = ref(user.value?.firstname);
|
||||
const lastname = ref(user.value?.lastname);
|
||||
const mail = ref(user.value?.mail);
|
||||
const display_name = ref(user.value?.display_name);
|
||||
|
||||
const password = ref('');
|
||||
const new_password = ref('');
|
||||
|
|
|
@ -76,12 +76,12 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
function deleteSession(token: string) {
|
||||
store.dispatch('sessions/deleteSession', token).catch(error => {
|
||||
store.dispatch('session/deleteSession', token).catch(error => {
|
||||
console.warn(error);
|
||||
});
|
||||
}
|
||||
function isThisSession(token: string) {
|
||||
return store.state.user.session.token == token;
|
||||
return store.state.session.currentSession?.token === token;
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
|
@ -2,3 +2,8 @@ export interface LoginData {
|
|||
userid: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface LoginResponse {
|
||||
user: FG.User;
|
||||
session: FG.Session;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ export default defineComponent({
|
|||
const checkMain = computed(() => {
|
||||
return root.$route.matched.length == 2;
|
||||
});
|
||||
return { checkMain, mainRoutes};
|
||||
return { checkMain, mainRoutes };
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -43,11 +43,11 @@ export default defineComponent({
|
|||
const store = <Store<StateInterface>>root.$store;
|
||||
|
||||
onBeforeMount(() => {
|
||||
store.dispatch('sessions/getSessions').catch(error => {
|
||||
store.dispatch('session/getSessions').catch(error => {
|
||||
console.warn(error);
|
||||
});
|
||||
});
|
||||
const sessions = computed(() => store.state.sessions.sessions);
|
||||
const sessions = computed(() => store.state.session.sessions);
|
||||
|
||||
function showRootGetters() {
|
||||
console.log(sessions.value);
|
||||
|
@ -55,7 +55,7 @@ export default defineComponent({
|
|||
|
||||
const sessionsLoading = computed(
|
||||
() =>
|
||||
store.state.sessions.loading ||
|
||||
store.state.session.loading ||
|
||||
store.state.user.getUserLoading ||
|
||||
store.state.user.updateUserLoading
|
||||
);
|
||||
|
|
|
@ -27,9 +27,9 @@ export default defineComponent({
|
|||
setup(_, { root }) {
|
||||
const store = <Store<StateInterface>>root.$store;
|
||||
|
||||
const userObj = computed(() => store.state.user.user);
|
||||
const userObj = computed(() => store.state.user.currentUser);
|
||||
|
||||
const sessionObj = computed(() => store.state.user.session);
|
||||
const sessionObj = computed(() => store.state.session.currentSession);
|
||||
|
||||
return { userObj, sessionObj };
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ const plugin: FG_Plugin.Plugin = {
|
|||
version: '0.0.1',
|
||||
store: new Map<string, Module<any, StateInterface>>([
|
||||
['user', userStore],
|
||||
['sessions', sessionsStore]
|
||||
['session', sessionsStore]
|
||||
])
|
||||
};
|
||||
|
||||
|
|
|
@ -1,20 +1,33 @@
|
|||
import { Module, MutationTree, ActionTree, GetterTree } from 'vuex';
|
||||
import { LoginData, LoginResponse } from 'src/plugins/user/models';
|
||||
import { StateInterface } from 'src/store';
|
||||
import { axios } from 'src/boot/axios';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { Router } from 'src/router';
|
||||
import { LocalStorage, Loading } from 'quasar';
|
||||
|
||||
export interface SessionInterface {
|
||||
currentSession?: FG.Session;
|
||||
sessions: FG.Session[];
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
const state: SessionInterface = {
|
||||
sessions: [],
|
||||
currentSession:
|
||||
LocalStorage.getItem<FG.Session>('currentSession') || undefined,
|
||||
loading: false
|
||||
};
|
||||
|
||||
const mutations: MutationTree<SessionInterface> = {
|
||||
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;
|
||||
},
|
||||
|
@ -24,40 +37,75 @@ const mutations: MutationTree<SessionInterface> = {
|
|||
};
|
||||
|
||||
const actions: ActionTree<SessionInterface, StateInterface> = {
|
||||
getSessions({ commit, rootState, dispatch }) {
|
||||
commit('setLoading', true);
|
||||
axios
|
||||
.get('/auth')
|
||||
.then((response: AxiosResponse<FG.Session[]>) => {
|
||||
console.log(response.data);
|
||||
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 === rootState.user.session.token;
|
||||
});
|
||||
if (currentSession) {
|
||||
void dispatch('user/setSession', currentSession, { root: true });
|
||||
}
|
||||
login({ commit }, data: LoginData) {
|
||||
Loading.show({
|
||||
message: 'Du wirst angemeldet'
|
||||
});
|
||||
void axios
|
||||
.post('/auth', data)
|
||||
.then((response: AxiosResponse<LoginResponse>) => {
|
||||
response.data.session.expires = new Date(response.data.session.expires);
|
||||
commit('setCurrentSession', response.data.session);
|
||||
commit('user/setCurrentUser', response.data.user, { root: true });
|
||||
void Router.push({ name: 'user-main' });
|
||||
})
|
||||
.catch(error => {
|
||||
console.exception(error);
|
||||
})
|
||||
.finally(() => {
|
||||
commit('setLoading', false);
|
||||
Loading.hide();
|
||||
});
|
||||
},
|
||||
deleteSession({ commit, dispatch, rootState }, token: string) {
|
||||
/**
|
||||
* Logout from current session
|
||||
*/
|
||||
logout({ dispatch, rootState }) {
|
||||
Loading.show({ message: 'Session wird abgemeldet' });
|
||||
dispatch('deleteSession', rootState.session.currentSession?.token).finally(
|
||||
() => {
|
||||
Loading.hide();
|
||||
}
|
||||
);
|
||||
},
|
||||
/**
|
||||
* Delete a given session
|
||||
*/
|
||||
deleteSession({ commit, rootState }, token: string | null) {
|
||||
if (token === null) return;
|
||||
|
||||
commit('setLoading', true);
|
||||
axios
|
||||
.delete(`/auth/${token}`)
|
||||
.then(() => {
|
||||
if (token === rootState.user.session.token) {
|
||||
void dispatch('user/setSession', null, { root: true });
|
||||
Router.go(0);
|
||||
if (token === rootState.session.currentSession?.token) {
|
||||
commit('clearCurrentSession');
|
||||
commit('user/clearCurrentUser', null, { root: true });
|
||||
void Router.push({ name: 'login' });
|
||||
} else {
|
||||
void dispatch('getSessions');
|
||||
commit('getSessions');
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
commit('setLoading', false);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Get all sessions from current User
|
||||
*/
|
||||
getSessions({ commit, state, dispatch }) {
|
||||
commit('setLoading', true);
|
||||
axios
|
||||
.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) {
|
||||
void dispatch('setCurrentSession', currentSession);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
|
@ -70,6 +118,9 @@ const actions: ActionTree<SessionInterface, StateInterface> = {
|
|||
};
|
||||
|
||||
const getters: GetterTree<SessionInterface, StateInterface> = {
|
||||
currentSession(state) {
|
||||
return state.currentSession;
|
||||
},
|
||||
sessions(state) {
|
||||
return state.sessions;
|
||||
},
|
||||
|
|
|
@ -1,131 +1,81 @@
|
|||
import { Module, MutationTree, ActionTree, GetterTree } from 'vuex';
|
||||
import { StateInterface } from 'src/store';
|
||||
import { axios } from 'boot/axios';
|
||||
import { LoginData } from 'src/plugins/user/models';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { LocalStorage, Loading } from 'quasar';
|
||||
import { Router } from 'src/router';
|
||||
import { SessionStorage } from 'quasar';
|
||||
|
||||
export interface UserStateInterface extends LoginResponse {
|
||||
export interface UserStateInterface {
|
||||
updateUserLoading: boolean;
|
||||
getUserLoading: boolean;
|
||||
currentUser?: FG.User;
|
||||
users: FG.User[];
|
||||
}
|
||||
|
||||
export interface LoginResponse {
|
||||
user: FG.User;
|
||||
session: FG.Session;
|
||||
}
|
||||
|
||||
const empty_session: FG.Session = {
|
||||
browser: '',
|
||||
expires: new Date(),
|
||||
lifetime: -1,
|
||||
platform: '',
|
||||
token: ''
|
||||
};
|
||||
|
||||
const empty_user: FG.User = {
|
||||
display_name: '',
|
||||
firstname: '',
|
||||
lastname: '',
|
||||
mail: '',
|
||||
roles: [],
|
||||
userid: ''
|
||||
};
|
||||
|
||||
const state: UserStateInterface = {
|
||||
user: empty_user,
|
||||
session: empty_session,
|
||||
users: [],
|
||||
currentUser: SessionStorage.getItem<FG.User>('currentUser') || undefined,
|
||||
updateUserLoading: false,
|
||||
getUserLoading: false
|
||||
};
|
||||
|
||||
const mutations: MutationTree<UserStateInterface> = {
|
||||
setUser(state, data: FG.User) {
|
||||
state.user = data;
|
||||
setCurrentUser(state, data: FG.User) {
|
||||
SessionStorage.set('currentUser', data);
|
||||
state.currentUser = data;
|
||||
},
|
||||
setSession(state, data: FG.Session) {
|
||||
state.session = data;
|
||||
clearCurrentUser(state) {
|
||||
SessionStorage.remove('currentUser');
|
||||
state.currentUser = undefined;
|
||||
},
|
||||
setUsers(state, data: FG.User[]) {
|
||||
state.users = data;
|
||||
},
|
||||
setLoading(
|
||||
state,
|
||||
data: { key: 'updateUserLoading' | 'getUserLoading'; data: boolean }
|
||||
) {
|
||||
state[data.key] = data.data;
|
||||
},
|
||||
showState(state) {
|
||||
console.log(state);
|
||||
}
|
||||
};
|
||||
|
||||
const actions: ActionTree<UserStateInterface, StateInterface> = {
|
||||
login({ commit }, data: LoginData) {
|
||||
Loading.show({
|
||||
message: 'Du wirst eingeloggt'
|
||||
});
|
||||
void axios
|
||||
.post('/auth', data)
|
||||
.then((response: AxiosResponse<LoginResponse>) => {
|
||||
response.data.session.expires = new Date(response.data.session.expires);
|
||||
commit('setUser', response.data.user);
|
||||
commit('setSession', response.data.session);
|
||||
commit('showState');
|
||||
LocalStorage.set('user', response.data.user);
|
||||
LocalStorage.set('session', response.data.session);
|
||||
|
||||
void Router.push({ name: 'user-main' });
|
||||
})
|
||||
.catch(error => {
|
||||
console.exception(error);
|
||||
})
|
||||
.finally(() => {
|
||||
Loading.hide();
|
||||
});
|
||||
getCurrentUser({ commit, rootState }) {
|
||||
if (rootState.session.currentSession) {
|
||||
commit('setLoading', { key: 'getUserLoading', data: true });
|
||||
axios
|
||||
.get(`/users/${rootState.session.currentSession.userid}`)
|
||||
.then((response: AxiosResponse<FG.User>) => {
|
||||
commit('setCurrentUser', response.data);
|
||||
})
|
||||
.catch(err => {
|
||||
console.warn(err);
|
||||
})
|
||||
.finally(() => {
|
||||
commit('setLoading', { key: 'getUserLoading', data: false });
|
||||
});
|
||||
} else {
|
||||
console.debug('User not logged in, can not get current_user.');
|
||||
}
|
||||
},
|
||||
|
||||
doLogout({ commit }, token: string) {
|
||||
Loading.show({ message: 'Du wirst ausgeloggt' });
|
||||
void axios
|
||||
.delete(`/auth/${token}`)
|
||||
.then(() => {
|
||||
commit('setUser', empty_user);
|
||||
commit('setSession', empty_session);
|
||||
})
|
||||
.finally(() => {
|
||||
LocalStorage.remove('user');
|
||||
LocalStorage.remove('session');
|
||||
Loading.hide();
|
||||
});
|
||||
},
|
||||
|
||||
logout({ dispatch }, token: string) {
|
||||
dispatch('doLogout', token).finally(() => {
|
||||
void Router.push({ name: 'login' });
|
||||
});
|
||||
},
|
||||
|
||||
getUser({ commit, state }) {
|
||||
commit('setLoading', { key: 'getUserLoading', data: true });
|
||||
getUsers({ commit }) {
|
||||
axios
|
||||
.get(`/users/${state.user.userid}`)
|
||||
.then((response: AxiosResponse<FG.User>) => {
|
||||
commit('setUser', response.data);
|
||||
LocalStorage.set('user', response.data);
|
||||
.get(`/users`)
|
||||
.then((response: AxiosResponse<FG.User[]>) => {
|
||||
commit('setUsers', response.data);
|
||||
})
|
||||
.catch(err => {
|
||||
console.warn(err);
|
||||
})
|
||||
.finally(() => {
|
||||
commit('setLoading', { key: 'getUserLoading', data: false });
|
||||
});
|
||||
},
|
||||
|
||||
updateUser({ commit, state, dispatch }, data) {
|
||||
commit('setLoading', { key: 'updateUserLoading', data: true });
|
||||
if (!state.currentUser) throw 'Not logged in';
|
||||
axios
|
||||
.put(`/users/${state.user.userid}`, data)
|
||||
.put(`/users/${state.currentUser.userid}`, data)
|
||||
.then(() => {
|
||||
void dispatch('getUser');
|
||||
void dispatch('getCurrentUser');
|
||||
})
|
||||
.catch(error => {
|
||||
console.log(error);
|
||||
|
@ -133,46 +83,30 @@ const actions: ActionTree<UserStateInterface, StateInterface> = {
|
|||
.finally(() => {
|
||||
commit('setLoading', { key: 'updateUserLoading', data: false });
|
||||
});
|
||||
},
|
||||
|
||||
loadFromLocalStorage({ commit }) {
|
||||
let data = LocalStorage.getItem('user');
|
||||
commit('setUser', data ? data : empty_user);
|
||||
data = LocalStorage.getItem('session');
|
||||
commit('setSession', data ? data : empty_session);
|
||||
commit('showState');
|
||||
},
|
||||
|
||||
setSession({ commit }, session: FG.Session) {
|
||||
if (session) {
|
||||
commit('setSession', session);
|
||||
LocalStorage.set('session', session);
|
||||
} else {
|
||||
commit('setSession', empty_session);
|
||||
LocalStorage.remove('session');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getters: GetterTree<UserStateInterface, StateInterface> = {
|
||||
user({ user }) {
|
||||
return user;
|
||||
currentUser({ currentUser }) {
|
||||
return currentUser;
|
||||
},
|
||||
displayName({ user }) {
|
||||
return user.display_name;
|
||||
},
|
||||
session({ session }) {
|
||||
return session;
|
||||
users({ users }) {
|
||||
return users;
|
||||
},
|
||||
loading({ updateUserLoading, getUserLoading }) {
|
||||
return updateUserLoading || getUserLoading;
|
||||
},
|
||||
permissions({user}) {
|
||||
let permissions: string[] = []
|
||||
user.roles.forEach(role => {
|
||||
permissions = permissions.concat(role.permissions);
|
||||
});
|
||||
return permissions
|
||||
displayName({ currentUser }) {
|
||||
return currentUser?.display_name;
|
||||
},
|
||||
permissions({ currentUser }) {
|
||||
let permissions: string[] = [];
|
||||
if (currentUser) {
|
||||
currentUser.roles.forEach(role => {
|
||||
permissions = permissions.concat(role.permissions);
|
||||
});
|
||||
}
|
||||
return permissions;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ const routes: RouteConfig[] = [
|
|||
{
|
||||
name: 'about',
|
||||
path: 'about',
|
||||
meta: { 'permission': 'user' },
|
||||
meta: { permission: 'user' },
|
||||
component: () => import('pages/about/About.vue')
|
||||
}
|
||||
]
|
||||
|
|
|
@ -9,7 +9,7 @@ import { UserStateInterface } from 'src/plugins/user/store/user';
|
|||
*/
|
||||
export interface StateInterface {
|
||||
user: UserStateInterface;
|
||||
sessions: SessionInterface;
|
||||
session: SessionInterface;
|
||||
}
|
||||
|
||||
export default store(function({ Vue }) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
|
||||
// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
|
||||
import "quasar/dist/types/feature-flag";
|
||||
import 'quasar/dist/types/feature-flag';
|
||||
|
||||
declare module "quasar/dist/types/feature-flag" {
|
||||
declare module 'quasar/dist/types/feature-flag' {
|
||||
interface QuasarFeatureFlags {
|
||||
store: true;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue