Reworked user and session store, added Admin function for user.
* Sync Login with backend * Split Main into MainUserSettins and Settings * Added AdminSetting to change other users, added UserSelector Component for selecting users (can be reused for other stuff ;-) ). * Split hasPermission into helper file for code reuse
This commit is contained in:
		
							parent
							
								
									5c11e02b2c
								
							
						
					
					
						commit
						8689e84d47
					
				| 
						 | 
					@ -5,16 +5,8 @@ import { Store } from 'vuex';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default boot<Store<StateInterface>>(({ router, store }) => {
 | 
					export default boot<Store<StateInterface>>(({ router, store }) => {
 | 
				
			||||||
  router.beforeEach((to, from, next) => {
 | 
					  router.beforeEach((to, from, next) => {
 | 
				
			||||||
    const user = store.state.user.currentUser;
 | 
					 | 
				
			||||||
    const session = store.state.session.currentSession;
 | 
					    const session = store.state.session.currentSession;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let permissions: string[] = [];
 | 
					 | 
				
			||||||
    if (user) {
 | 
					 | 
				
			||||||
      user.roles.forEach(role => {
 | 
					 | 
				
			||||||
        permissions = permissions.concat(role.permissions);
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (to.name != 'login') {
 | 
					    if (to.name != 'login') {
 | 
				
			||||||
      if (!session || session.expires <= new Date()) {
 | 
					      if (!session || session.expires <= new Date()) {
 | 
				
			||||||
        store.dispatch('session/logout').catch(error => {
 | 
					        store.dispatch('session/logout').catch(error => {
 | 
				
			||||||
| 
						 | 
					@ -32,7 +24,7 @@ export default boot<Store<StateInterface>>(({ router, store }) => {
 | 
				
			||||||
              return (<{ permissions: FG.Permission[] }>(
 | 
					              return (<{ permissions: FG.Permission[] }>(
 | 
				
			||||||
                record.meta
 | 
					                record.meta
 | 
				
			||||||
              )).permissions.every((permission: string) => {
 | 
					              )).permissions.every((permission: string) => {
 | 
				
			||||||
                return permissions.includes(permission);
 | 
					                return store.state.user.currentPermissions.includes(permission);
 | 
				
			||||||
              });
 | 
					              });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,7 @@
 | 
				
			||||||
import { computed, defineComponent } from '@vue/composition-api';
 | 
					import { computed, defineComponent } from '@vue/composition-api';
 | 
				
			||||||
import { Store } from 'vuex';
 | 
					import { Store } from 'vuex';
 | 
				
			||||||
import { StateInterface } from 'src/store';
 | 
					import { StateInterface } from 'src/store';
 | 
				
			||||||
 | 
					import { hasPermissions } from 'src/components/permission';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default defineComponent({
 | 
					export default defineComponent({
 | 
				
			||||||
  name: 'EssentialLink',
 | 
					  name: 'EssentialLink',
 | 
				
			||||||
| 
						 | 
					@ -65,17 +66,9 @@ export default defineComponent({
 | 
				
			||||||
      return props.title;
 | 
					      return props.title;
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const hasPermissions = computed(() => {
 | 
					    const isGranted = computed(() =>
 | 
				
			||||||
      let permissions = props.permissions;
 | 
					      hasPermissions(props.permissions || [], root.$store)
 | 
				
			||||||
      if (permissions) {
 | 
					    );
 | 
				
			||||||
        return (<string[]>permissions).every(permission => {
 | 
					 | 
				
			||||||
          return (<{ 'user/permissions': string[] }>(
 | 
					 | 
				
			||||||
            (<Store<StateInterface>>root.$store).getters
 | 
					 | 
				
			||||||
          ))['user/permissions'].includes(permission);
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return true;
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return { realTitle: title, hasPermissions };
 | 
					    return { realTitle: title, hasPermissions };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,12 @@
 | 
				
			||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <q-btn flat dense :icon="icon" :to="{ name: link }" v-if="hasPermissions" />
 | 
					  <q-btn flat dense :icon="icon" :to="{ name: link }" v-if="isGranted" />
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
import { computed, defineComponent } from '@vue/composition-api';
 | 
					import { computed, defineComponent } from '@vue/composition-api';
 | 
				
			||||||
import { Store } from 'vuex';
 | 
					import { Store } from 'vuex';
 | 
				
			||||||
import { StateInterface } from 'src/store';
 | 
					import { StateInterface } from 'src/store';
 | 
				
			||||||
 | 
					import { hasPermissions } from 'src/components/permission';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default defineComponent({
 | 
					export default defineComponent({
 | 
				
			||||||
  name: 'ShortCutLink',
 | 
					  name: 'ShortCutLink',
 | 
				
			||||||
| 
						 | 
					@ -23,18 +24,10 @@ export default defineComponent({
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  setup(props, { root }) {
 | 
					  setup(props, { root }) {
 | 
				
			||||||
    const hasPermissions = computed(() => {
 | 
					    const isGranted = computed(() =>
 | 
				
			||||||
      let permissions = props.permissions;
 | 
					      hasPermissions(props.permissions || [], root.$store)
 | 
				
			||||||
      if (permissions) {
 | 
					    );
 | 
				
			||||||
        return (<string[]>permissions).every(permission => {
 | 
					    return { isGranted };
 | 
				
			||||||
          return (<{ 'user/permissions': string[] }>(
 | 
					 | 
				
			||||||
            (<Store<StateInterface>>root.$store).getters
 | 
					 | 
				
			||||||
          ))['user/permissions'].includes(permission);
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return true;
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
    return { hasPermissions };
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					import { Store } from 'vuex';
 | 
				
			||||||
 | 
					import { StateInterface } from 'src/store';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function hasPermission(
 | 
				
			||||||
 | 
					  permission: string,
 | 
				
			||||||
 | 
					  store: Store<StateInterface>
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					  return store.state.user.currentPermissions.includes(permission);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function hasPermissions(needed: string[], store: Store<StateInterface>) {
 | 
				
			||||||
 | 
					  const permissions = store.state.user.currentPermissions;
 | 
				
			||||||
 | 
					  return needed.every(value => permissions.includes(value));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,41 @@
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <q-select
 | 
				
			||||||
 | 
					    filled
 | 
				
			||||||
 | 
					    label="Benutzer"
 | 
				
			||||||
 | 
					    @input="updated"
 | 
				
			||||||
 | 
					    v-model="user"
 | 
				
			||||||
 | 
					    :options="users"
 | 
				
			||||||
 | 
					    option-label="display_name"
 | 
				
			||||||
 | 
					    option-value="userid"
 | 
				
			||||||
 | 
					    map-options
 | 
				
			||||||
 | 
					  />
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					import { computed, defineComponent, ref } from '@vue/composition-api';
 | 
				
			||||||
 | 
					import { Store } from 'vuex';
 | 
				
			||||||
 | 
					import { StateInterface } from 'src/store';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface Props {
 | 
				
			||||||
 | 
					  user: FG.User;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default defineComponent({
 | 
				
			||||||
 | 
					  name: 'UserSelector',
 | 
				
			||||||
 | 
					  props: ['user'],
 | 
				
			||||||
 | 
					  setup(props: Props, { root, emit }) {
 | 
				
			||||||
 | 
					    const store = <Store<StateInterface>>root.$store;
 | 
				
			||||||
 | 
					    const users = computed(() => store.state.user.users);
 | 
				
			||||||
 | 
					    const user = ref(props.user);
 | 
				
			||||||
 | 
					    const updated = (value: FG.User) => {
 | 
				
			||||||
 | 
					      emit('update:user', value);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      user,
 | 
				
			||||||
 | 
					      updated,
 | 
				
			||||||
 | 
					      users
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
| 
						 | 
					@ -1,191 +0,0 @@
 | 
				
			||||||
<template>
 | 
					 | 
				
			||||||
  <q-card class="col-12">
 | 
					 | 
				
			||||||
    <q-linear-progress indeterminate rounded color="primary" v-if="loading" />
 | 
					 | 
				
			||||||
    <q-form @submit="save" @reset="reset">
 | 
					 | 
				
			||||||
      <q-card-section class="fit row justify-start content-center items-center">
 | 
					 | 
				
			||||||
        <q-input
 | 
					 | 
				
			||||||
          class="col-xs-12 col-sm-6 q-pa-sm"
 | 
					 | 
				
			||||||
          label="Vorname"
 | 
					 | 
				
			||||||
          :rules="[notEmpty]"
 | 
					 | 
				
			||||||
          v-model="firstname"
 | 
					 | 
				
			||||||
          filled
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        <q-input
 | 
					 | 
				
			||||||
          class="col-xs-12 col-sm-6 q-pa-sm"
 | 
					 | 
				
			||||||
          label="Nachname"
 | 
					 | 
				
			||||||
          :rules="[notEmpty]"
 | 
					 | 
				
			||||||
          v-model="lastname"
 | 
					 | 
				
			||||||
          filled
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        <q-input
 | 
					 | 
				
			||||||
          class="col-xs-12 col-sm-6 q-pa-sm"
 | 
					 | 
				
			||||||
          label="Benutzername"
 | 
					 | 
				
			||||||
          readonly
 | 
					 | 
				
			||||||
          :value="user.userid"
 | 
					 | 
				
			||||||
          filled
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        <q-input
 | 
					 | 
				
			||||||
          class="col-xs-12 col-sm-6 q-pa-sm"
 | 
					 | 
				
			||||||
          label="E-Mail"
 | 
					 | 
				
			||||||
          :rules="[isEmail, notEmpty]"
 | 
					 | 
				
			||||||
          v-model="mail"
 | 
					 | 
				
			||||||
          filled
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        <q-input
 | 
					 | 
				
			||||||
          class="col-xs-12 col-sm-6 q-pa-sm"
 | 
					 | 
				
			||||||
          label="Display Name"
 | 
					 | 
				
			||||||
          :rules="[notEmpty]"
 | 
					 | 
				
			||||||
          v-model="display_name"
 | 
					 | 
				
			||||||
          filled
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        <q-select
 | 
					 | 
				
			||||||
          class="col-xs-12 col-sm-6 q-pa-sm"
 | 
					 | 
				
			||||||
          label="Rollen"
 | 
					 | 
				
			||||||
          readonly
 | 
					 | 
				
			||||||
          v-model="user.roles"
 | 
					 | 
				
			||||||
          :options="user.roles"
 | 
					 | 
				
			||||||
          filled
 | 
					 | 
				
			||||||
        >
 | 
					 | 
				
			||||||
          <template v-slot:selected-item="scope">
 | 
					 | 
				
			||||||
            <q-chip v-for="(item, index) in scope.opt" :key="'item' + index">
 | 
					 | 
				
			||||||
              {{ item.name }}
 | 
					 | 
				
			||||||
            </q-chip>
 | 
					 | 
				
			||||||
          </template>
 | 
					 | 
				
			||||||
        </q-select>
 | 
					 | 
				
			||||||
      </q-card-section>
 | 
					 | 
				
			||||||
      <q-separator />
 | 
					 | 
				
			||||||
      <q-card-section class="fit row justify-start content-center items-center">
 | 
					 | 
				
			||||||
        <q-input
 | 
					 | 
				
			||||||
          class="col-xs-12 col-sm-6 col-md-4 q-pa-sm"
 | 
					 | 
				
			||||||
          label="Password"
 | 
					 | 
				
			||||||
          type="password"
 | 
					 | 
				
			||||||
          hint="Password muss immer eingetragen werden"
 | 
					 | 
				
			||||||
          :rules="[notEmpty]"
 | 
					 | 
				
			||||||
          v-model="password"
 | 
					 | 
				
			||||||
          filled
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        <q-input
 | 
					 | 
				
			||||||
          class="col-xs-12 col-sm-6 col-md-4 q-pa-sm"
 | 
					 | 
				
			||||||
          label="Neues Password"
 | 
					 | 
				
			||||||
          type="password"
 | 
					 | 
				
			||||||
          v-model="new_password"
 | 
					 | 
				
			||||||
          filled
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
        <q-input
 | 
					 | 
				
			||||||
          class="col-xs-12 col-sm-6 col-md-4 q-pa-sm"
 | 
					 | 
				
			||||||
          label="Wiederhole neues Password"
 | 
					 | 
				
			||||||
          type="password"
 | 
					 | 
				
			||||||
          :disable="new_password.length == 0"
 | 
					 | 
				
			||||||
          :rules="[samePassword]"
 | 
					 | 
				
			||||||
          v-model="new_password2"
 | 
					 | 
				
			||||||
          filled
 | 
					 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      </q-card-section>
 | 
					 | 
				
			||||||
      <q-card-actions align="right">
 | 
					 | 
				
			||||||
        <q-btn label="test" @click="$store.dispatch('user/getUser')" />
 | 
					 | 
				
			||||||
        <q-btn label="Reset" type="reset" />
 | 
					 | 
				
			||||||
        <q-btn color="primary" type="submit" label="Speichern" />
 | 
					 | 
				
			||||||
      </q-card-actions>
 | 
					 | 
				
			||||||
    </q-form>
 | 
					 | 
				
			||||||
  </q-card>
 | 
					 | 
				
			||||||
</template>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
<script lang="ts">
 | 
					 | 
				
			||||||
import { computed, defineComponent, ref } from '@vue/composition-api';
 | 
					 | 
				
			||||||
import { Store } from 'vuex';
 | 
					 | 
				
			||||||
import { StateInterface } from 'src/store';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default defineComponent({
 | 
					 | 
				
			||||||
  name: 'Main',
 | 
					 | 
				
			||||||
  setup(_, { root }) {
 | 
					 | 
				
			||||||
    const store = <Store<StateInterface>>root.$store;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    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 password = ref('');
 | 
					 | 
				
			||||||
    const new_password = ref('');
 | 
					 | 
				
			||||||
    const new_password2 = ref('');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function save() {
 | 
					 | 
				
			||||||
      let change_values: { [index: string]: string } = {
 | 
					 | 
				
			||||||
        firstname: firstname.value,
 | 
					 | 
				
			||||||
        lastname: lastname.value,
 | 
					 | 
				
			||||||
        mail: mail.value,
 | 
					 | 
				
			||||||
        display_name: display_name.value
 | 
					 | 
				
			||||||
      };
 | 
					 | 
				
			||||||
      Object.keys(change_values).forEach(key => {
 | 
					 | 
				
			||||||
        if (
 | 
					 | 
				
			||||||
          change_values[key] === (<{ [index: string]: any }>user.value)[key]
 | 
					 | 
				
			||||||
        ) {
 | 
					 | 
				
			||||||
          delete change_values[key];
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
      change_values = Object.assign(change_values, {
 | 
					 | 
				
			||||||
        password: password.value
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
      if (new_password.value != '') {
 | 
					 | 
				
			||||||
        change_values = Object.assign(change_values, {
 | 
					 | 
				
			||||||
          new_password: new_password.value
 | 
					 | 
				
			||||||
        });
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      store.dispatch('user/updateUser', change_values).catch(error => {
 | 
					 | 
				
			||||||
        console.warn(error);
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function reset() {
 | 
					 | 
				
			||||||
      firstname.value = user.value.firstname;
 | 
					 | 
				
			||||||
      lastname.value = user.value.lastname;
 | 
					 | 
				
			||||||
      mail.value = user.value.mail;
 | 
					 | 
				
			||||||
      display_name.value = user.value.display_name;
 | 
					 | 
				
			||||||
      password.value = '';
 | 
					 | 
				
			||||||
      new_password.value = '';
 | 
					 | 
				
			||||||
      new_password2.value = '';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function samePassword(val: string) {
 | 
					 | 
				
			||||||
      return val == new_password.value || 'Passwörter sind nicht identisch!';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function notEmpty(val: string) {
 | 
					 | 
				
			||||||
      return !!val || 'Feld darf nicht leer sein!';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    function isEmail(val: string | null) {
 | 
					 | 
				
			||||||
      return (
 | 
					 | 
				
			||||||
        !val ||
 | 
					 | 
				
			||||||
        /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w\w+)+$/.test(val) ||
 | 
					 | 
				
			||||||
        'E-Mail ist nicht valide.'
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const loading = computed(() => {
 | 
					 | 
				
			||||||
      return (
 | 
					 | 
				
			||||||
        store.state.user.getUserLoading || store.state.user.updateUserLoading
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
      user,
 | 
					 | 
				
			||||||
      firstname,
 | 
					 | 
				
			||||||
      lastname,
 | 
					 | 
				
			||||||
      mail,
 | 
					 | 
				
			||||||
      display_name,
 | 
					 | 
				
			||||||
      password,
 | 
					 | 
				
			||||||
      new_password,
 | 
					 | 
				
			||||||
      new_password2,
 | 
					 | 
				
			||||||
      samePassword,
 | 
					 | 
				
			||||||
      isEmail,
 | 
					 | 
				
			||||||
      notEmpty,
 | 
					 | 
				
			||||||
      save,
 | 
					 | 
				
			||||||
      reset,
 | 
					 | 
				
			||||||
      loading
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
</script>
 | 
					 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,194 @@
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <q-form @submit="save" @reset="reset">
 | 
				
			||||||
 | 
					    <q-linear-progress indeterminate rounded color="primary" v-if="loading" />
 | 
				
			||||||
 | 
					    <q-card-section class="fit row justify-start content-center items-center">
 | 
				
			||||||
 | 
					      <q-input
 | 
				
			||||||
 | 
					        class="col-xs-12 col-sm-6 q-pa-sm"
 | 
				
			||||||
 | 
					        label="Vorname"
 | 
				
			||||||
 | 
					        :rules="[notEmpty]"
 | 
				
			||||||
 | 
					        v-model="props.user.firstname"
 | 
				
			||||||
 | 
					        filled
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <q-input
 | 
				
			||||||
 | 
					        class="col-xs-12 col-sm-6 q-pa-sm"
 | 
				
			||||||
 | 
					        label="Nachname"
 | 
				
			||||||
 | 
					        :rules="[notEmpty]"
 | 
				
			||||||
 | 
					        v-model="props.user.lastname"
 | 
				
			||||||
 | 
					        filled
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <q-input
 | 
				
			||||||
 | 
					        class="col-xs-12 col-sm-6 q-pa-sm"
 | 
				
			||||||
 | 
					        label="Benutzername"
 | 
				
			||||||
 | 
					        readonly
 | 
				
			||||||
 | 
					        :value="props.user.userid"
 | 
				
			||||||
 | 
					        filled
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <q-input
 | 
				
			||||||
 | 
					        class="col-xs-12 col-sm-6 q-pa-sm"
 | 
				
			||||||
 | 
					        label="E-Mail"
 | 
				
			||||||
 | 
					        :rules="[isEmail, notEmpty]"
 | 
				
			||||||
 | 
					        v-model="props.user.mail"
 | 
				
			||||||
 | 
					        filled
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <q-input
 | 
				
			||||||
 | 
					        class="col-xs-12 col-sm-6 q-pa-sm"
 | 
				
			||||||
 | 
					        label="Display Name"
 | 
				
			||||||
 | 
					        :rules="[notEmpty]"
 | 
				
			||||||
 | 
					        v-model="props.user.display_name"
 | 
				
			||||||
 | 
					        filled
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <q-select
 | 
				
			||||||
 | 
					        class="col-xs-12 col-sm-6 q-pa-sm"
 | 
				
			||||||
 | 
					        label="Rollen"
 | 
				
			||||||
 | 
					        filled
 | 
				
			||||||
 | 
					        multiple
 | 
				
			||||||
 | 
					        use-chips
 | 
				
			||||||
 | 
					        v-model="props.user.roles"
 | 
				
			||||||
 | 
					        :readonly="() => canSetRoles()"
 | 
				
			||||||
 | 
					        :options="allRoles"
 | 
				
			||||||
 | 
					        option-label="name"
 | 
				
			||||||
 | 
					        option-value="name"
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </q-card-section>
 | 
				
			||||||
 | 
					    <q-separator />
 | 
				
			||||||
 | 
					    <q-card-section class="fit row justify-start content-center items-center">
 | 
				
			||||||
 | 
					      <q-input
 | 
				
			||||||
 | 
					        v-if="isCurrentUser"
 | 
				
			||||||
 | 
					        class="col-xs-12 col-sm-6 col-md-4 q-pa-sm"
 | 
				
			||||||
 | 
					        label="Password"
 | 
				
			||||||
 | 
					        type="password"
 | 
				
			||||||
 | 
					        hint="Password muss immer eingetragen werden"
 | 
				
			||||||
 | 
					        :rules="[notEmpty]"
 | 
				
			||||||
 | 
					        v-model="password"
 | 
				
			||||||
 | 
					        filled
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <q-input
 | 
				
			||||||
 | 
					        class="col-xs-12 col-sm-6 col-md-4 q-pa-sm"
 | 
				
			||||||
 | 
					        label="Neues Password"
 | 
				
			||||||
 | 
					        type="password"
 | 
				
			||||||
 | 
					        v-model="new_password"
 | 
				
			||||||
 | 
					        filled
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					      <q-input
 | 
				
			||||||
 | 
					        class="col-xs-12 col-sm-6 col-md-4 q-pa-sm"
 | 
				
			||||||
 | 
					        label="Wiederhole neues Password"
 | 
				
			||||||
 | 
					        type="password"
 | 
				
			||||||
 | 
					        :disable="new_password.length == 0"
 | 
				
			||||||
 | 
					        :rules="[samePassword]"
 | 
				
			||||||
 | 
					        v-model="new_password2"
 | 
				
			||||||
 | 
					        filled
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </q-card-section>
 | 
				
			||||||
 | 
					    <q-card-actions align="right">
 | 
				
			||||||
 | 
					      <q-btn label="Reset" type="reset" />
 | 
				
			||||||
 | 
					      <q-btn color="primary" type="submit" label="Speichern" />
 | 
				
			||||||
 | 
					    </q-card-actions>
 | 
				
			||||||
 | 
					  </q-form>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					  computed,
 | 
				
			||||||
 | 
					  defineComponent,
 | 
				
			||||||
 | 
					  ref,
 | 
				
			||||||
 | 
					  onBeforeMount
 | 
				
			||||||
 | 
					} from '@vue/composition-api';
 | 
				
			||||||
 | 
					import { Store } from 'vuex';
 | 
				
			||||||
 | 
					import { StateInterface } from 'src/store';
 | 
				
			||||||
 | 
					import { hasPermission } from 'src/components/permission';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface Props {
 | 
				
			||||||
 | 
					  user?: FG.User;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default defineComponent({
 | 
				
			||||||
 | 
					  name: 'MainUserSettings',
 | 
				
			||||||
 | 
					  props: ['user'],
 | 
				
			||||||
 | 
					  setup(props: Props, { root }) {
 | 
				
			||||||
 | 
					    const store = <Store<StateInterface>>root.$store;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    onBeforeMount(() => {
 | 
				
			||||||
 | 
					      store.dispatch('user/getRoles', false).catch(error => {
 | 
				
			||||||
 | 
					        console.warn(error);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const isCurrentUser = computed(
 | 
				
			||||||
 | 
					      () => props.user?.userid === store.state.user.currentUser?.userid
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const canSetRoles = computed(() => hasPermission('users_set_roles', store));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const oldUser = computed(() => {
 | 
				
			||||||
 | 
					      if (isCurrentUser.value) return <FG.User>store.state.user.currentUser;
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        return store.state.user.users.filter(user => {
 | 
				
			||||||
 | 
					          user.userid === props.user?.userid;
 | 
				
			||||||
 | 
					        })[0];
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const allRoles = computed(() =>
 | 
				
			||||||
 | 
					      store.state.user.roles.map(role => role.name)
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const password = ref('');
 | 
				
			||||||
 | 
					    const new_password = ref('');
 | 
				
			||||||
 | 
					    const new_password2 = ref('');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function save() {
 | 
				
			||||||
 | 
					      let changed = <FG.User>props.user;
 | 
				
			||||||
 | 
					      changed = Object.assign(changed, {
 | 
				
			||||||
 | 
					        password: password.value
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					      if (new_password.value != '') {
 | 
				
			||||||
 | 
					        changed = Object.assign(changed, {
 | 
				
			||||||
 | 
					          new_password: new_password.value
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      store.dispatch('user/updateUser', changed).catch(error => {
 | 
				
			||||||
 | 
					        console.warn(error);
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function reset() {
 | 
				
			||||||
 | 
					      props.user = oldUser.value;
 | 
				
			||||||
 | 
					      password.value = '';
 | 
				
			||||||
 | 
					      new_password.value = '';
 | 
				
			||||||
 | 
					      new_password2.value = '';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function samePassword(val: string) {
 | 
				
			||||||
 | 
					      return val == new_password.value || 'Passwörter sind nicht identisch!';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function notEmpty(val: string) {
 | 
				
			||||||
 | 
					      return !!val || 'Feld darf nicht leer sein!';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function isEmail(val: string | null) {
 | 
				
			||||||
 | 
					      return (
 | 
				
			||||||
 | 
					        !val ||
 | 
				
			||||||
 | 
					        /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w\w+)+$/.test(val) ||
 | 
				
			||||||
 | 
					        'E-Mail ist nicht valide.'
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const loading = computed(() => store.state.user.loading > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      props,
 | 
				
			||||||
 | 
					      allRoles,
 | 
				
			||||||
 | 
					      canSetRoles,
 | 
				
			||||||
 | 
					      password,
 | 
				
			||||||
 | 
					      new_password,
 | 
				
			||||||
 | 
					      new_password2,
 | 
				
			||||||
 | 
					      samePassword,
 | 
				
			||||||
 | 
					      isCurrentUser,
 | 
				
			||||||
 | 
					      isEmail,
 | 
				
			||||||
 | 
					      notEmpty,
 | 
				
			||||||
 | 
					      save,
 | 
				
			||||||
 | 
					      reset,
 | 
				
			||||||
 | 
					      loading
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,55 @@
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div>
 | 
				
			||||||
 | 
					    <q-page
 | 
				
			||||||
 | 
					      padding
 | 
				
			||||||
 | 
					      class="fit row justify-center content-center items-center q-gutter-sm"
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					      <q-card class="col-12">
 | 
				
			||||||
 | 
					        <q-card-section
 | 
				
			||||||
 | 
					          class="fit row justify-start content-center items-center"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <div class="col-xs-12 col-sm-6 text-center text-h6">
 | 
				
			||||||
 | 
					            Benutzereinstellungen
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					          <div class="col-xs-12 col-sm-6 q-pa-sm">
 | 
				
			||||||
 | 
					            <UserSelector :user="user" @update:user="userUpdated" />
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </q-card-section>
 | 
				
			||||||
 | 
					        <MainUserSettings :user="user" />
 | 
				
			||||||
 | 
					      </q-card>
 | 
				
			||||||
 | 
					    </q-page>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script lang="ts">
 | 
				
			||||||
 | 
					import { defineComponent, onBeforeMount, ref } from '@vue/composition-api';
 | 
				
			||||||
 | 
					import UserSelector from '../components/UserSelector.vue';
 | 
				
			||||||
 | 
					import MainUserSettings from '../components/settings/MainUserSettings.vue';
 | 
				
			||||||
 | 
					import { Store } from 'vuex';
 | 
				
			||||||
 | 
					import { StateInterface } from 'src/store';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default defineComponent({
 | 
				
			||||||
 | 
					  name: 'AdminSettings',
 | 
				
			||||||
 | 
					  components: { UserSelector, MainUserSettings },
 | 
				
			||||||
 | 
					  setup(_, { root }) {
 | 
				
			||||||
 | 
					    const store = <Store<StateInterface>>root.$store;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    onBeforeMount(() => {
 | 
				
			||||||
 | 
					      store.dispatch('user/getUsers').catch(error => console.warn(error));
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const user = ref(<FG.User>store.state.user.currentUser);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // can be dropped with VUE3
 | 
				
			||||||
 | 
					    const userUpdated = (value: FG.User) => {
 | 
				
			||||||
 | 
					      user.value = value;
 | 
				
			||||||
 | 
					      console.log(value);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      user,
 | 
				
			||||||
 | 
					      userUpdated
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
| 
						 | 
					@ -4,41 +4,41 @@
 | 
				
			||||||
      padding
 | 
					      padding
 | 
				
			||||||
      class="fit row justify-center content-center items-center q-gutter-sm"
 | 
					      class="fit row justify-center content-center items-center q-gutter-sm"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <div
 | 
					      <circular-progress v-if="sessionsLoading" />
 | 
				
			||||||
        class="fit row justify-center content-center items-center q-gutter-sm"
 | 
					      <q-card class="col-12">
 | 
				
			||||||
      >
 | 
					        <q-card-section
 | 
				
			||||||
        <circular-progress v-if="sessionsLoading" />
 | 
					          class="fit row justify-start content-center items-center"
 | 
				
			||||||
        <div class="col-12 text-left text-h6">
 | 
					        >
 | 
				
			||||||
          Allgemeine Einstellungen:
 | 
					          <div class="col-12 text-center text-h6">Benutzereinstellungen</div>
 | 
				
			||||||
        </div>
 | 
					        </q-card-section>
 | 
				
			||||||
        <Main />
 | 
					        <MainUserSettings :user="currentUser" />
 | 
				
			||||||
        <div class="col-12 text-left text-h6">
 | 
					      </q-card>
 | 
				
			||||||
          Aktive Sessions:
 | 
					      <div class="col-12 text-left text-h6">Aktive Sessions:</div>
 | 
				
			||||||
        </div>
 | 
					      <sessions
 | 
				
			||||||
        <sessions
 | 
					        v-for="(session, index) in sessions"
 | 
				
			||||||
          v-for="(session, index) in sessions"
 | 
					        :key="'session' + index"
 | 
				
			||||||
          :key="'session' + index"
 | 
					        :session="session"
 | 
				
			||||||
          :session="session"
 | 
					      />
 | 
				
			||||||
        />
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
      <div class="row">
 | 
					 | 
				
			||||||
        <q-btn label="show sessions" @click="showRootGetters" />
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </q-page>
 | 
					    </q-page>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
import { computed, defineComponent, onBeforeMount } from '@vue/composition-api';
 | 
					import {
 | 
				
			||||||
 | 
					  computed,
 | 
				
			||||||
 | 
					  defineComponent,
 | 
				
			||||||
 | 
					  onBeforeMount,
 | 
				
			||||||
 | 
					  ref
 | 
				
			||||||
 | 
					} from '@vue/composition-api';
 | 
				
			||||||
import CircularProgress from 'components/loading/CircularProgress.vue';
 | 
					import CircularProgress from 'components/loading/CircularProgress.vue';
 | 
				
			||||||
import Sessions from '../components/settings/Sessions.vue';
 | 
					import Sessions from '../components/settings/Sessions.vue';
 | 
				
			||||||
import Main from '../components/settings/Main.vue';
 | 
					import MainUserSettings from '../components/settings/MainUserSettings.vue';
 | 
				
			||||||
import { Store } from 'vuex';
 | 
					import { Store } from 'vuex';
 | 
				
			||||||
import { StateInterface } from 'src/store';
 | 
					import { StateInterface } from 'src/store';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default defineComponent({
 | 
					export default defineComponent({
 | 
				
			||||||
  // name: 'PageName'
 | 
					  // name: 'PageName'
 | 
				
			||||||
  components: { CircularProgress, Sessions, Main },
 | 
					  components: { CircularProgress, Sessions, MainUserSettings },
 | 
				
			||||||
  setup(_, { root }) {
 | 
					  setup(_, { root }) {
 | 
				
			||||||
    const store = <Store<StateInterface>>root.$store;
 | 
					    const store = <Store<StateInterface>>root.$store;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,21 +47,13 @@ export default defineComponent({
 | 
				
			||||||
        console.warn(error);
 | 
					        console.warn(error);
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const currentUser = ref(<FG.User>store.state.user.currentUser);
 | 
				
			||||||
    const sessions = computed(() => store.state.session.sessions);
 | 
					    const sessions = computed(() => store.state.session.sessions);
 | 
				
			||||||
 | 
					    const sessionsLoading = computed(() => store.state.session.loading);
 | 
				
			||||||
    function showRootGetters() {
 | 
					 | 
				
			||||||
      console.log(sessions.value);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const sessionsLoading = computed(
 | 
					 | 
				
			||||||
      () =>
 | 
					 | 
				
			||||||
        store.state.session.loading ||
 | 
					 | 
				
			||||||
        store.state.user.getUserLoading ||
 | 
					 | 
				
			||||||
        store.state.user.updateUserLoading
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      showRootGetters,
 | 
					      currentUser,
 | 
				
			||||||
      sessionsLoading,
 | 
					      sessionsLoading,
 | 
				
			||||||
      sessions
 | 
					      sessions
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,15 @@ const mainRoutes: FG_Plugin.PluginRouteConfig[] = [
 | 
				
			||||||
        shortcut: true,
 | 
					        shortcut: true,
 | 
				
			||||||
        meta: { permissions: ['user'] },
 | 
					        meta: { permissions: ['user'] },
 | 
				
			||||||
        component: () => import('../pages/Settings.vue')
 | 
					        component: () => import('../pages/Settings.vue')
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        title: 'Admin',
 | 
				
			||||||
 | 
					        icon: 'mdi-cog',
 | 
				
			||||||
 | 
					        path: 'admin',
 | 
				
			||||||
 | 
					        name: 'admin-settings',
 | 
				
			||||||
 | 
					        shortcut: false,
 | 
				
			||||||
 | 
					        meta: { permissions: ['users_edit_other'] },
 | 
				
			||||||
 | 
					        component: () => import('../pages/AdminSettings.vue')
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@ import { Module, MutationTree, ActionTree, GetterTree } from 'vuex';
 | 
				
			||||||
import { LoginData, LoginResponse } from 'src/plugins/user/models';
 | 
					import { LoginData, LoginResponse } from 'src/plugins/user/models';
 | 
				
			||||||
import { StateInterface } from 'src/store';
 | 
					import { StateInterface } from 'src/store';
 | 
				
			||||||
import { axios } from 'src/boot/axios';
 | 
					import { axios } from 'src/boot/axios';
 | 
				
			||||||
import { AxiosResponse } from 'axios';
 | 
					import { AxiosError, AxiosResponse } from 'axios';
 | 
				
			||||||
import { Router } from 'src/router';
 | 
					import { Router } from 'src/router';
 | 
				
			||||||
import { LocalStorage, Loading } from 'quasar';
 | 
					import { LocalStorage, Loading } from 'quasar';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,10 +12,15 @@ export interface SessionInterface {
 | 
				
			||||||
  loading: boolean;
 | 
					  loading: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function loadFromLocal() {
 | 
				
			||||||
 | 
					  const session = LocalStorage.getItem<FG.Session>('currentSession');
 | 
				
			||||||
 | 
					  if (session) session.expires = new Date(session.expires);
 | 
				
			||||||
 | 
					  return session;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const state: SessionInterface = {
 | 
					const state: SessionInterface = {
 | 
				
			||||||
  sessions: [],
 | 
					  sessions: [],
 | 
				
			||||||
  currentSession:
 | 
					  currentSession: loadFromLocal() || undefined,
 | 
				
			||||||
    LocalStorage.getItem<FG.Session>('currentSession') || undefined,
 | 
					 | 
				
			||||||
  loading: false
 | 
					  loading: false
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,12 +52,13 @@ const actions: ActionTree<SessionInterface, StateInterface> = {
 | 
				
			||||||
        response.data.session.expires = new Date(response.data.session.expires);
 | 
					        response.data.session.expires = new Date(response.data.session.expires);
 | 
				
			||||||
        commit('setCurrentSession', response.data.session);
 | 
					        commit('setCurrentSession', response.data.session);
 | 
				
			||||||
        commit('user/setCurrentUser', response.data.user, { root: true });
 | 
					        commit('user/setCurrentUser', response.data.user, { root: true });
 | 
				
			||||||
        void Router.push({ name: 'user-main' });
 | 
					        commit('user/setCurrentPermissions', response.data.permissions, {
 | 
				
			||||||
      })
 | 
					          root: true
 | 
				
			||||||
      .catch(error => {
 | 
					        });
 | 
				
			||||||
        console.exception(error);
 | 
					 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
 | 
					      .catch(error => console.warn(error))
 | 
				
			||||||
      .finally(() => {
 | 
					      .finally(() => {
 | 
				
			||||||
 | 
					        void Router.push({ name: 'user-main' });
 | 
				
			||||||
        Loading.hide();
 | 
					        Loading.hide();
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
| 
						 | 
					@ -70,7 +76,7 @@ const actions: ActionTree<SessionInterface, StateInterface> = {
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Delete a given session
 | 
					   * Delete a given session
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  deleteSession({ commit, rootState }, token: string | null) {
 | 
					  deleteSession({ commit, dispatch, rootState }, token: string | null) {
 | 
				
			||||||
    if (token === null) return;
 | 
					    if (token === null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    commit('setLoading', true);
 | 
					    commit('setLoading', true);
 | 
				
			||||||
| 
						 | 
					@ -78,17 +84,23 @@ const actions: ActionTree<SessionInterface, StateInterface> = {
 | 
				
			||||||
      .delete(`/auth/${token}`)
 | 
					      .delete(`/auth/${token}`)
 | 
				
			||||||
      .then(() => {
 | 
					      .then(() => {
 | 
				
			||||||
        if (token === rootState.session.currentSession?.token) {
 | 
					        if (token === rootState.session.currentSession?.token) {
 | 
				
			||||||
          commit('clearCurrentSession');
 | 
					          void dispatch('clearup');
 | 
				
			||||||
          commit('user/clearCurrentUser', null, { root: true });
 | 
					 | 
				
			||||||
          void Router.push({ name: 'login' });
 | 
					 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          commit('getSessions');
 | 
					          commit('getSessions');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
 | 
					      .catch((error: AxiosError) => {
 | 
				
			||||||
 | 
					        if (!error.response || error.response.status != 401) throw error;
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
      .finally(() => {
 | 
					      .finally(() => {
 | 
				
			||||||
        commit('setLoading', false);
 | 
					        commit('setLoading', false);
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  clearup({ commit }) {
 | 
				
			||||||
 | 
					    commit('clearCurrentSession');
 | 
				
			||||||
 | 
					    commit('user/clearCurrentUser', null, { root: true });
 | 
				
			||||||
 | 
					    void Router.push({ name: 'login' });
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Get all sessions from current User
 | 
					   * Get all sessions from current User
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,19 +3,25 @@ import { StateInterface } from 'src/store';
 | 
				
			||||||
import { axios } from 'boot/axios';
 | 
					import { axios } from 'boot/axios';
 | 
				
			||||||
import { AxiosResponse } from 'axios';
 | 
					import { AxiosResponse } from 'axios';
 | 
				
			||||||
import { SessionStorage } from 'quasar';
 | 
					import { SessionStorage } from 'quasar';
 | 
				
			||||||
 | 
					import { CurrentUserResponse } from 'src/plugins/user/models';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface UserStateInterface {
 | 
					export interface UserStateInterface {
 | 
				
			||||||
  updateUserLoading: boolean;
 | 
					 | 
				
			||||||
  getUserLoading: boolean;
 | 
					 | 
				
			||||||
  currentUser?: FG.User;
 | 
					  currentUser?: FG.User;
 | 
				
			||||||
 | 
					  currentPermissions: FG.Permission[];
 | 
				
			||||||
  users: FG.User[];
 | 
					  users: FG.User[];
 | 
				
			||||||
 | 
					  roles: FG.Role[];
 | 
				
			||||||
 | 
					  permissions: FG.Permission[];
 | 
				
			||||||
 | 
					  loading: number;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const state: UserStateInterface = {
 | 
					const state: UserStateInterface = {
 | 
				
			||||||
  users: [],
 | 
					  users: [],
 | 
				
			||||||
 | 
					  roles: [],
 | 
				
			||||||
 | 
					  permissions: [],
 | 
				
			||||||
  currentUser: SessionStorage.getItem<FG.User>('currentUser') || undefined,
 | 
					  currentUser: SessionStorage.getItem<FG.User>('currentUser') || undefined,
 | 
				
			||||||
  updateUserLoading: false,
 | 
					  currentPermissions:
 | 
				
			||||||
  getUserLoading: false
 | 
					    SessionStorage.getItem<FG.Permission[]>('currentPermissions') || [],
 | 
				
			||||||
 | 
					  loading: 0
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mutations: MutationTree<UserStateInterface> = {
 | 
					const mutations: MutationTree<UserStateInterface> = {
 | 
				
			||||||
| 
						 | 
					@ -23,35 +29,46 @@ const mutations: MutationTree<UserStateInterface> = {
 | 
				
			||||||
    SessionStorage.set('currentUser', data);
 | 
					    SessionStorage.set('currentUser', data);
 | 
				
			||||||
    state.currentUser = data;
 | 
					    state.currentUser = data;
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  setCurrentPermissions(state, data: FG.Permission[]) {
 | 
				
			||||||
 | 
					    SessionStorage.set('currentPermissions', data);
 | 
				
			||||||
 | 
					    state.currentPermissions = data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  clearCurrentUser(state) {
 | 
					  clearCurrentUser(state) {
 | 
				
			||||||
    SessionStorage.remove('currentUser');
 | 
					    SessionStorage.remove('currentUser');
 | 
				
			||||||
 | 
					    SessionStorage.remove('currentPermissions');
 | 
				
			||||||
    state.currentUser = undefined;
 | 
					    state.currentUser = undefined;
 | 
				
			||||||
 | 
					    state.currentPermissions = [];
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  setUsers(state, data: FG.User[]) {
 | 
					  setUsers(state, data: FG.User[]) {
 | 
				
			||||||
    state.users = data;
 | 
					    state.users = data;
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  setLoading(
 | 
					  setRoles(state, data: FG.Role[]) {
 | 
				
			||||||
    state,
 | 
					    state.roles = data;
 | 
				
			||||||
    data: { key: 'updateUserLoading' | 'getUserLoading'; data: boolean }
 | 
					  },
 | 
				
			||||||
  ) {
 | 
					  setPermissions(state, data: FG.Permission[]) {
 | 
				
			||||||
    state[data.key] = data.data;
 | 
					    state.permissions = data;
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  setLoading(state, data = true) {
 | 
				
			||||||
 | 
					    if (data) state.loading += 1;
 | 
				
			||||||
 | 
					    else state.loading -= 1;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const actions: ActionTree<UserStateInterface, StateInterface> = {
 | 
					const actions: ActionTree<UserStateInterface, StateInterface> = {
 | 
				
			||||||
  getCurrentUser({ commit, rootState }) {
 | 
					  getCurrentUser({ commit, rootState }) {
 | 
				
			||||||
    if (rootState.session.currentSession) {
 | 
					    if (rootState.session.currentSession) {
 | 
				
			||||||
      commit('setLoading', { key: 'getUserLoading', data: true });
 | 
					      commit('setLoading');
 | 
				
			||||||
      axios
 | 
					      axios
 | 
				
			||||||
        .get(`/users/${rootState.session.currentSession.userid}`)
 | 
					        .get(`/users/${rootState.session.currentSession.userid}`)
 | 
				
			||||||
        .then((response: AxiosResponse<FG.User>) => {
 | 
					        .then((response: AxiosResponse<CurrentUserResponse>) => {
 | 
				
			||||||
          commit('setCurrentUser', response.data);
 | 
					          commit('setCurrentUser', response.data);
 | 
				
			||||||
 | 
					          commit('setCurrentPermissions', response.data.permissions);
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .catch(err => {
 | 
					        .catch(err => {
 | 
				
			||||||
          console.warn(err);
 | 
					          console.warn(err);
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .finally(() => {
 | 
					        .finally(() => {
 | 
				
			||||||
          commit('setLoading', { key: 'getUserLoading', data: false });
 | 
					          commit('setLoading', false);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      console.debug('User not logged in, can not get current_user.');
 | 
					      console.debug('User not logged in, can not get current_user.');
 | 
				
			||||||
| 
						 | 
					@ -60,7 +77,7 @@ const actions: ActionTree<UserStateInterface, StateInterface> = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  getUsers({ commit }) {
 | 
					  getUsers({ commit }) {
 | 
				
			||||||
    axios
 | 
					    axios
 | 
				
			||||||
      .get(`/users`)
 | 
					      .get('/users')
 | 
				
			||||||
      .then((response: AxiosResponse<FG.User[]>) => {
 | 
					      .then((response: AxiosResponse<FG.User[]>) => {
 | 
				
			||||||
        commit('setUsers', response.data);
 | 
					        commit('setUsers', response.data);
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
| 
						 | 
					@ -69,20 +86,43 @@ const actions: ActionTree<UserStateInterface, StateInterface> = {
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  updateUser({ commit, state, dispatch }, data) {
 | 
					  updateUser({ commit, state, dispatch }, data: FG.User) {
 | 
				
			||||||
    commit('setLoading', { key: 'updateUserLoading', data: true });
 | 
					    commit('setLoading');
 | 
				
			||||||
    if (!state.currentUser) throw 'Not logged in';
 | 
					 | 
				
			||||||
    axios
 | 
					    axios
 | 
				
			||||||
      .put(`/users/${state.currentUser.userid}`, data)
 | 
					      .put(`/users/${data.userid}`, data)
 | 
				
			||||||
      .then(() => {
 | 
					      .then(() => {
 | 
				
			||||||
        void dispatch('getCurrentUser');
 | 
					        if (state.currentUser && state.currentUser.userid === data.userid)
 | 
				
			||||||
 | 
					          void dispatch('getCurrentUser');
 | 
				
			||||||
 | 
					        else void dispatch('getUsers');
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      .catch(error => {
 | 
					      .catch(error => {
 | 
				
			||||||
        console.log(error);
 | 
					        console.log(error);
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      .finally(() => {
 | 
					      .finally(() => {
 | 
				
			||||||
        commit('setLoading', { key: 'updateUserLoading', data: false });
 | 
					        commit('setLoading', false);
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getRoles({ commit, state }, force = true) {
 | 
				
			||||||
 | 
					    if (!force && state.roles.length > 0) return;
 | 
				
			||||||
 | 
					    commit('setLoading');
 | 
				
			||||||
 | 
					    axios
 | 
				
			||||||
 | 
					      .get('/roles')
 | 
				
			||||||
 | 
					      .then((response: AxiosResponse<FG.Role[]>) => {
 | 
				
			||||||
 | 
					        commit('setRoles', response.data);
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .finally(() => commit('setLoading', false));
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  getPermissions({ commit, state }, force = true) {
 | 
				
			||||||
 | 
					    if (!force && state.permissions.length > 0) return;
 | 
				
			||||||
 | 
					    commit('setLoading');
 | 
				
			||||||
 | 
					    axios
 | 
				
			||||||
 | 
					      .get('/roles')
 | 
				
			||||||
 | 
					      .then((response: AxiosResponse<FG.Permission[]>) => {
 | 
				
			||||||
 | 
					        commit('setPermissions', response.data);
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .finally(() => commit('setLoading', false));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -93,20 +133,11 @@ const getters: GetterTree<UserStateInterface, StateInterface> = {
 | 
				
			||||||
  users({ users }) {
 | 
					  users({ users }) {
 | 
				
			||||||
    return users;
 | 
					    return users;
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  loading({ updateUserLoading, getUserLoading }) {
 | 
					  loading({ loading }) {
 | 
				
			||||||
    return updateUserLoading || getUserLoading;
 | 
					    return loading > 0;
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  displayName({ currentUser }) {
 | 
					  displayName({ currentUser }) {
 | 
				
			||||||
    return currentUser?.display_name;
 | 
					    return currentUser?.display_name;
 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  permissions({ currentUser }) {
 | 
					 | 
				
			||||||
    let permissions: string[] = [];
 | 
					 | 
				
			||||||
    if (currentUser) {
 | 
					 | 
				
			||||||
      currentUser.roles.forEach(role => {
 | 
					 | 
				
			||||||
        permissions = permissions.concat(role.permissions);
 | 
					 | 
				
			||||||
      });
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return permissions;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue