release v2.0.0 #4

Merged
crimsen merged 481 commits from develop into master 2024-01-18 15:15:08 +00:00
14 changed files with 152 additions and 76 deletions
Showing only changes of commit 82d4b52e24 - Show all commits

View File

@ -1,20 +1,25 @@
import { boot } from 'quasar/wrappers';
import { StateInterface } from '../store';
export default boot(({ Vue, router, store }) => {
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!store.getters.isLoggedIn()) {
let user = (<StateInterface>store.state).user;
if (to.matched.some(record => {
// permissions is set AND has NO matching permission
return record.meta.permissions !== undefined &&
!(record.meta.permissions.filter(
(value: string) =>
user.permissions.includes(value)
).length > 0);
})
) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
});
} else {
next()
}
} else {
next() // make sure to always call next()!
next();
}
})
});

View File

@ -1,8 +1,9 @@
<template>
<q-page padding class="fit row justify-center items-center content-center">
<q-card
class="col-xs-11 col-sm-8 col-md-6 col-lg-4 justify-center items-center content-center"
<q-page
padding
class="fit row justify-center items-center content-center"
>
<q-card class="col-xs-11 col-sm-8 col-md-6 col-lg-4 justify-center items-center content-center">
<q-toolbar class="bg-primary text-white">
<q-toolbar-title>
Login
@ -10,10 +11,14 @@
</q-toolbar>
<q-card-section>
<q-form ref="LoginForm" @submit="doLogin" class="q-gutter-md">
<q-form
ref="LoginForm"
@submit="doLogin"
class="q-gutter-md"
>
<q-input
filled
v-model="username"
v-model="userid"
label="Benutzername oder E-Mail"
:rules="rules"
/>
@ -25,7 +30,11 @@
:rules="rules"
/>
<div class="row justify-end">
<q-btn label="Login" type="submit" color="primary" />
<q-btn
label="Login"
type="submit"
color="primary"
/>
</div>
</q-form>
</q-card-section>
@ -39,18 +48,22 @@ import { defineComponent, ref } from '@vue/composition-api';
export default defineComponent({
// name: 'PageName'
setup(_, ctx) {
const username = ref('');
const userid = ref('');
const password = ref('');
const rules = [
(val: string) => (val && val.length > 0) || 'Feld darf nicht leer sein!'
(val: string) => (val && val.length > 0) || 'Feld darf nicht leer sein!',
];
function doLogin() {
console.log(username.value, password.value);
void ctx.root.$router.push({ name: 'main' });
ctx.root.$store.dispatch('user/login', {
userid: userid.value,
password: password.value,
});
void ctx.root.$router.push({ name: 'user' });
}
return { username, password, doLogin, rules };
}
return { userid, password, doLogin, rules };
},
});
</script>

View File

@ -10,6 +10,7 @@ const routes: RouteConfig[] = [
{
path: 'plugin1',
name: 'plugin1',
meta: { permissions: ['user'] },
components: {
default: () => import('../pages/Plugin.vue'),
'plugin-nav': () => import('../components/navigation/PluginLinks.vue')
@ -18,11 +19,13 @@ const routes: RouteConfig[] = [
{
path: 'plugin1_1',
name: 'plugin1_1',
meta: { permissions: ['user'] },
component: () => import('../pages/NewPlugin.vue')
},
{
path: 'plugin1_2',
name: 'plugin1_2',
meta: { permissions: ['user'] },
component: () => import('../pages/OldPlugin.vue')
}
]

View File

@ -3,11 +3,22 @@
<q-page
padding
class="fit row justify-center content-center items-center"
v-if="$route.name == mainLink.link"
v-if="true"
>
<q-card
class="col-4"
height=""
>
<q-card class="col-4" height="">
<q-card-section>
{{ mainLink.title }}
Name: {{ userState.user.firstname }} {{ userState.user.lastname }}<br />
E-Mail: {{ userState.user.mail }}<br />
Roles: <ul
v-for="role in userState.user.roles"
v-bind:key="role"
>
<li>{{ role }}</li>
</ul><br />
Token expires: {{ userState.token.expires }}
</q-card-section>
</q-card>
</q-page>
@ -16,13 +27,17 @@
</template>
<script lang="ts">
import { defineComponent } from '@vue/composition-api';
import { mainLink } from '../plugin';
import { defineComponent, computed } from '@vue/composition-api';
import { UserStateInterface } from '../../../store/module-user/state';
export default defineComponent({
// name: 'PageName'
setup(_, ctx) {
const a = ctx.root.$flaschengeistPluginsMainLinks;
return { a, mainLink };
}
setup(_, { root }) {
const userState = computed(
() => <UserStateInterface>root.$store.state.user
);
const a = root.$flaschengeistPluginsMainLinks;
return { a, userState };
},
});
</script>

View File

@ -20,12 +20,13 @@ const routes: RouteConfig[] = [
},
{
path: '/main',
name: 'main',
redirect: 'user',
component: () => import('layouts/MainLayout.vue'),
children: [
{
name: 'about',
path: 'about',
meta: { 'permissions': ['user'] },
component: () => import('pages/about/About.vue')
}
]

View File

@ -1,8 +1,8 @@
import { store } from 'quasar/wrappers';
import Vuex from 'vuex';
// import example from './module-example';
// import { ExampleStateInterface } from './module-example/state';
import user from './module-user';
import { UserStateInterface } from './module-user/state';
/*
* If not building with SSR mode, you can
@ -11,17 +11,15 @@ import Vuex from 'vuex';
export interface StateInterface {
// Define your own store structure, using submodules if needed
// example: ExampleStateInterface;
// Declared as unknown to avoid linting issue. Best to strongly type as per the line above.
example: unknown;
user: UserStateInterface;
}
export default store(function({ Vue }) {
export default store(function ({ Vue }) {
Vue.use(Vuex);
const Store = new Vuex.Store<StateInterface>({
modules: {
// example
user
},
// enable strict mode (adds overhead!)

View File

@ -1,11 +0,0 @@
import { ActionTree } from 'vuex';
import { StateInterface } from '../index';
import { ExampleStateInterface } from './state';
const actions: ActionTree<ExampleStateInterface, StateInterface> = {
someAction (/* context */) {
// your code
}
};
export default actions;

View File

@ -1,10 +0,0 @@
import { MutationTree } from 'vuex';
import { ExampleStateInterface } from './state';
const mutation: MutationTree<ExampleStateInterface> = {
someMutation (/* state: ExampleStateInterface */) {
// your code
}
};
export default mutation;

View File

@ -1,9 +0,0 @@
export interface ExampleStateInterface {
prop: boolean;
}
const state: ExampleStateInterface = {
prop: false
};
export default state;

View File

@ -0,0 +1,25 @@
import axios from 'axios';
import { ActionTree } from 'vuex';
import { StateInterface } from '../index';
import { UserStateInterface } from './state';
const actions: ActionTree<UserStateInterface, StateInterface> = {
login ({ commit }, payload): any {
axios.post("/auth", {
userid: payload.userid,
password: payload.password
}).then(function (response) {
let token = (<UserStateInterface>response.data).token;
console.log(token);
if (token)
token.expires = new Date(token.expires);
commit('setUser', (<UserStateInterface>response.data).user);
commit('setToken', token);
commit('setPermissions', (<UserStateInterface>response.data).permissions);
}).catch(function (error) {
console.error(error);
});
}
};
export default actions;

View File

@ -1,9 +1,10 @@
import { GetterTree } from 'vuex';
import { StateInterface } from '../index';
import { ExampleStateInterface } from './state';
import { UserStateInterface } from './state';
const getters: GetterTree<ExampleStateInterface, StateInterface> = {
const getters: GetterTree<UserStateInterface, StateInterface> = {
someAction (/* context */) {
console.log("GOOOOOOOOOOOOOOOOOOO");
// your code
}
};

View File

@ -1,11 +1,11 @@
import { Module } from 'vuex';
import { StateInterface } from '../index';
import state, { ExampleStateInterface } from './state';
import state, { UserStateInterface } from './state';
import actions from './actions';
import getters from './getters';
import mutations from './mutations';
const exampleModule: Module<ExampleStateInterface, StateInterface> = {
const exampleModule: Module<UserStateInterface, StateInterface> = {
namespaced: true,
actions,
getters,

View File

@ -0,0 +1,16 @@
import { MutationTree } from 'vuex';
import { TokenInterface, UserInterface, UserStateInterface } from './state';
const mutation: MutationTree<UserStateInterface> = {
setToken (state: UserStateInterface, token: TokenInterface) {
state.token = token
},
setUser (state: UserStateInterface, user: UserInterface) {
state.user = user
},
setPermissions (state: UserStateInterface, permissions: Array<string>) {
state.permissions = permissions
}
};
export default mutation;

View File

@ -0,0 +1,29 @@
export interface TokenInterface {
token: string,
expires: Date,
lifetime: number,
browser: string,
platform: string
}
export interface UserInterface {
display_name: string | null,
firstname: string,
lastname: string,
mail: string | null,
roles: Array<string>
}
export interface UserStateInterface {
token: TokenInterface | null,
user: UserInterface | null,
permissions: Array<string>
};
const state: UserStateInterface = {
token: null,
user: null,
permissions: []
};
export default state;