change whole backend and tables for gorm table references

simplify tables with table components close #31
This commit is contained in:
Adrian Zürcher
2025-11-29 15:59:18 +01:00
parent 62549c9039
commit bdcceb53e0
29 changed files with 646 additions and 514 deletions

View File

@@ -77,7 +77,7 @@
filled
:options="props.responsibles"
:option-label="(opt) => opt.firstName + ' ' + opt.lastName"
v-model="localMember.responsiblePerson"
v-model="localMember.responsible"
></q-select>
<q-input
v-if="!newMember"
@@ -105,9 +105,10 @@
import DialogFrame from 'src/vueLib/dialog/DialogFrame.vue';
import { type PropType, ref } from 'vue';
import { appApi } from 'src/boot/axios';
import type { Member, Members } from 'src/vueLib/models/member';
import type { Member } from 'src/vueLib/models/member';
import { useNotify } from 'src/vueLib/general/useNotify';
import { i18n } from 'src/boot/lang';
import type { Responsibles } from 'src/vueLib/models/responsible';
const { NotifyResponse } = useNotify();
const dialog = ref();
@@ -121,7 +122,7 @@ const localMember = ref<Member>({
const props = defineProps({
responsibles: {
type: Object as PropType<Members>,
type: Object as PropType<Responsibles>,
},
group: {
type: Array,

View File

@@ -24,63 +24,7 @@
:rules="[(val) => !!val || $t('emailIsRequired')]"
v-model="localUser.email"
></q-input>
<div class="col-5">
<q-input
class="col-5 required"
:label="$t('password')"
filled
:lazy-rules="false"
:rules="[validatePassword]"
v-model="localUser.password"
@update:model-value="checkStrength"
:type="showPassword1 ? 'text' : 'password'"
>
<template v-slot:append>
<q-btn
flat
dense
:icon="showPassword1 ? 'visibility_off' : 'visibility'"
@mousedown.prevent="showPassword1 = true"
@mouseup.prevent="showPassword1 = false"
@mouseleave.prevent="showPassword1 = false"
@touchstart.prevent="showPassword1 = true"
@touchend.prevent="showPassword1 = false"
@touchcancel.prevent="showPassword1 = false"
></q-btn>
<q-icon :name="strengthIcon" :color="strengthColor"></q-icon>
</template>
</q-input>
<div class="q-mt-md q-px-xl">
<q-linear-progress :value="strengthValue" :color="strengthColor" size="8px" rounded />
<div class="text-caption text-center q-mt-xs">
{{ strengthLabel }}
</div>
</div>
<q-input
class="col-5 required"
:label="$t('password')"
filled
:type="showPassword2 ? 'text' : 'password'"
:rules="[checkSamePassword]"
v-model="passwordCheck"
>
<template v-slot:append>
<q-btn
flat
dense
:icon="showPassword2 ? 'visibility_off' : 'visibility'"
@mousedown.prevent="showPassword2 = true"
@mouseup.prevent="showPassword2 = false"
@mouseleave.prevent="showPassword2 = false"
@touchstart.prevent="showPassword2 = true"
@touchend.prevent="showPassword2 = false"
@touchcancel.prevent="showPassword2 = false"
></q-btn>
</template>
</q-input>
</div>
<EnterNewPassword class="col-5 required" v-model:password="localUser.password!" />
<div class="col-5">
<q-select
class="col-5 required"
@@ -88,7 +32,7 @@
filled
:options="props.roles"
:rules="[(val) => !!val || $t('roleIsRequired')]"
v-model="localUser.role"
v-model="role"
></q-select>
<q-input
class="col-5 q-mt-xl"
@@ -109,29 +53,22 @@
<script setup lang="ts">
import DialogFrame from 'src/vueLib/dialog/DialogFrame.vue';
import { ref } from 'vue';
import zxcvbn from 'zxcvbn';
import { appApi } from 'src/boot/axios';
import type { User } from 'src/vueLib/models/users';
import { useNotify } from 'src/vueLib/general/useNotify';
import { validateQForm } from 'src/vueLib/utils/validation';
import { i18n } from 'src/boot/lang';
import { DefaultSettings } from 'src/vueLib/models/settings';
import EnterNewPassword from 'src/vueLib/login/EnterNewPassword.vue';
const { NotifyResponse } = useNotify();
const dialog = ref();
const form = ref();
const newUser = ref(false);
const showPassword1 = ref(false);
const showPassword2 = ref(false);
const passwordCheck = ref('');
const strengthValue = ref(0);
const strengthLabel = ref('Enter a password');
const strengthColor = ref('grey');
const strengthIcon = ref('lock');
const role = ref('');
const localUser = ref<User>({
user: '',
email: '',
role: '',
});
const props = defineProps({
@@ -155,7 +92,6 @@ async function open(user: User | null) {
localUser.value = {
user: '',
email: '',
role: '',
};
newUser.value = true;
}
@@ -164,47 +100,6 @@ async function open(user: User | null) {
await validateQForm(form.value);
}
function checkStrength() {
const result = zxcvbn(localUser.value.password || '');
strengthValue.value = (result.score + 1) / 5;
const levels = [
i18n.global.t('veryWeak'),
i18n.global.t('weak'),
i18n.global.t('fair'),
i18n.global.t('good'),
i18n.global.t('strong'),
];
const colors = ['red', 'orange', 'yellow', 'light-green', 'green'];
const icon = ['lock', 'warning', 'error_outline', 'check_circle_outline', 'verified_user'];
strengthLabel.value = levels[result.score] || i18n.global.t('veryWeak');
strengthColor.value = colors[result.score] || 'grey';
strengthIcon.value = icon[result.score] || 'lock';
}
function validatePassword(): string | boolean {
if (!localUser.value.password) return i18n.global.t('passwordIsRequired');
if (localUser.value.password.length < 8) {
return i18n.global.t('passwordTooShort');
} else if (!/[A-Z]/.test(localUser.value.password)) {
return i18n.global.t('passwordNeedsUppercase');
} else if (!/[a-z]/.test(localUser.value.password)) {
return i18n.global.t('passwordNeedsLowercase');
} else if (!/[0-9]/.test(localUser.value.password)) {
return i18n.global.t('passwordNeedsNumber');
} else if (!/[!@#$%^&*(),.?":{}|<>]/.test(localUser.value.password)) {
return i18n.global.t('passwordNeedsSpecial');
}
return true;
}
function checkSamePassword(): string | boolean {
if (localUser.value.password === passwordCheck.value) return true;
return i18n.global.t('passwordDoNotMatch');
}
async function save() {
if (!(await validateQForm(form.value))) {
NotifyResponse(i18n.global.t('notAllRequiredFieldsFilled'), 'error');
@@ -216,6 +111,7 @@ async function save() {
localUser.value.settings = DefaultSettings();
}
localUser.value.role = { role: role.value || '', permissions: [] };
appApi
.post(query, JSON.stringify(localUser.value))
.then(() => {