Merge pull request 'patches v1.5.1' (#93) from develop into main
Reviewed-on: #93
This commit is contained in:
commit
9bac6e2f97
44 changed files with 100 additions and 90 deletions
17
README.md
17
README.md
|
@ -8,12 +8,9 @@ Dieses Repository dient hauptsächlich zur Verwaltung der Mitgliederdaten, aber
|
||||||
|
|
||||||
Eine Demo dieser Seite finden Sie unter [https://admin-demo.ff-admin.de](https://admin-demo.ff-admin.de).
|
Eine Demo dieser Seite finden Sie unter [https://admin-demo.ff-admin.de](https://admin-demo.ff-admin.de).
|
||||||
|
|
||||||
Für die Verwendung muss ein TOTP-Code eingegeben werden.
|
Die Zugangsdaten (Lesebeschränkt) sind unterhalb dem Login angegeben.
|
||||||
|
|
||||||
Die Zugangsdaten (Lesebeschränkt) sind:\
|
Das Handbuch zur Anwendung finden sie unter [https://ff-admin.de/ff-admin-handbook](https://ff-admin.de/ff-admin-handbook).
|
||||||
EMAIL: demo-besucher\
|
|
||||||
TOTP: \
|
|
||||||
TOTP-Code: FBMDAJKFOYQXM2DNH47GWWBGJ5KWOUCW
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
@ -29,17 +26,9 @@ services:
|
||||||
image: docker.registry.jk-effects.cloud/ehrenamt/ff-admin/app:latest
|
image: docker.registry.jk-effects.cloud/ehrenamt/ff-admin/app:latest
|
||||||
container_name: ff_admin
|
container_name: ff_admin
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
#environment:
|
#environment:
|
||||||
# - SERVERADDRESS=<backend_url (https://... | http://...)> # wichtig: ohne Pfad
|
# - SERVERADDRESS=<backend_url (https://... | http://...)> # wichtig: ohne Pfad
|
||||||
# - APPNAMEOVERWRITE=<appname> # ersetzt den Namen FF-Admin auf der Login-Seite und sonstigen Positionen in der Oberfläche
|
|
||||||
# - IMPRINTLINK=<imprint link>
|
|
||||||
# - PRIVACYLINK=<privacy link>
|
|
||||||
# - CUSTOMLOGINMESSAGE=betrieben von xy
|
|
||||||
#volumes:
|
|
||||||
# - <volume|local path>/favicon.ico:/usr/share/nginx/html/favicon.ico # 48x48 px Auflösung
|
|
||||||
# - <volume|local path>/favicon.png:/usr/share/nginx/html/favicon.png # 512x512 px Auflösung - wird als pwa Icon genutzt
|
|
||||||
# - <volume|local path>/Logo.png:/usr/share/nginx/html/Logo.png
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Wenn keine Server-Adresse angegeben wird, wird versucht das Backend unter der URL des Frontends zu erreichen. Dazu muss das Backend auf der gleichen URL wie das Frontend laufen. Zur Unterscheidung von Frontend und Backend bei gleicher URL müssen alle Anfragen mit dem PathPrefix `/api` an das Backend weitergeleitet werden.
|
Wenn keine Server-Adresse angegeben wird, wird versucht das Backend unter der URL des Frontends zu erreichen. Dazu muss das Backend auf der gleichen URL wie das Frontend laufen. Zur Unterscheidung von Frontend und Backend bei gleicher URL müssen alle Anfragen mit dem PathPrefix `/api` an das Backend weitergeleitet werden.
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.9 KiB |
|
@ -42,7 +42,7 @@ import UserMenu from "./UserMenu.vue";
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from "vue";
|
import { defineComponent } from "vue";
|
||||||
import AppLogo from "./AppLogo.vue";
|
import AppLogo from "./AppLogo.vue";
|
||||||
import { useConfigurationStore } from "../stores/configuration";
|
import { useConfigurationStore } from "@/stores/configuration";
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(useAuthStore, ["authCheck"]),
|
...mapState(useAuthStore, ["authCheck"]),
|
||||||
|
|
|
@ -48,7 +48,7 @@ import Spinner from "@/components/Spinner.vue";
|
||||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||||
import FailureXMark from "@/components/FailureXMark.vue";
|
import FailureXMark from "@/components/FailureXMark.vue";
|
||||||
import TextCopy from "@/components/TextCopy.vue";
|
import TextCopy from "@/components/TextCopy.vue";
|
||||||
import { hashString } from "../../helpers/crypto";
|
import { hashString } from "@/helpers/crypto";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -84,7 +84,7 @@ export default defineComponent({
|
||||||
this.changeStatus = "loading";
|
this.changeStatus = "loading";
|
||||||
this.changeError = "";
|
this.changeError = "";
|
||||||
this.$http
|
this.$http
|
||||||
.post(`/user/changeToPW`, {
|
.patch(`/user/changeToPW`, {
|
||||||
newpassword: await hashString(formData.new.value),
|
newpassword: await hashString(formData.new.value),
|
||||||
})
|
})
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
|
|
|
@ -69,7 +69,7 @@ export default defineComponent({
|
||||||
this.verifyStatus = "loading";
|
this.verifyStatus = "loading";
|
||||||
this.verifyError = "";
|
this.verifyError = "";
|
||||||
this.$http
|
this.$http
|
||||||
.post(`/user/changeToTOTP`, {
|
.patch(`/user/changeToTOTP`, {
|
||||||
otp: this.otp,
|
otp: this.otp,
|
||||||
totp: formData.totp.value,
|
totp: formData.totp.value,
|
||||||
})
|
})
|
||||||
|
|
|
@ -58,7 +58,7 @@ import MainTemplate from "@/templates/Main.vue";
|
||||||
import Spinner from "@/components/Spinner.vue";
|
import Spinner from "@/components/Spinner.vue";
|
||||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||||
import FailureXMark from "@/components/FailureXMark.vue";
|
import FailureXMark from "@/components/FailureXMark.vue";
|
||||||
import { hashString } from "../../helpers/crypto";
|
import { hashString } from "@/helpers/crypto";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -87,7 +87,7 @@ export default defineComponent({
|
||||||
this.changeStatus = "loading";
|
this.changeStatus = "loading";
|
||||||
this.changeError = "";
|
this.changeError = "";
|
||||||
this.$http
|
this.$http
|
||||||
.post(`/user/changepw`, {
|
.patch(`/user/changepw`, {
|
||||||
current: await hashString(formData.current.value),
|
current: await hashString(formData.current.value),
|
||||||
newpassword: await hashString(formData.new.value),
|
newpassword: await hashString(formData.new.value),
|
||||||
})
|
})
|
||||||
|
|
|
@ -87,7 +87,7 @@ import { CheckIcon, ChevronUpDownIcon } from "@heroicons/vue/20/solid";
|
||||||
import { useMemberStore } from "@/stores/admin/club/member/member";
|
import { useMemberStore } from "@/stores/admin/club/member/member";
|
||||||
import type { MemberViewModel } from "@/viewmodels/admin/club/member/member.models";
|
import type { MemberViewModel } from "@/viewmodels/admin/club/member/member.models";
|
||||||
import difference from "lodash.difference";
|
import difference from "lodash.difference";
|
||||||
import Spinner from "../Spinner.vue";
|
import Spinner from "@/components/Spinner.vue";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -18,22 +18,22 @@
|
||||||
<div class="flex flex-row border border-white rounded-md overflow-hidden">
|
<div class="flex flex-row border border-white rounded-md overflow-hidden">
|
||||||
<EyeIcon
|
<EyeIcon
|
||||||
class="w-5 h-5 p-1 box-content cursor-pointer"
|
class="w-5 h-5 p-1 box-content cursor-pointer"
|
||||||
:class="_can(permissionUpdate, 'read', section) ? 'bg-success' : ''"
|
:class="_canSection(permissionUpdate, 'read', section) ? 'bg-success' : ''"
|
||||||
@click="togglePermission('read', section)"
|
@click="togglePermission('read', section)"
|
||||||
/>
|
/>
|
||||||
<PlusIcon
|
<PlusIcon
|
||||||
class="w-5 h-5 p-1 box-content cursor-pointer"
|
class="w-5 h-5 p-1 box-content cursor-pointer"
|
||||||
:class="_can(permissionUpdate, 'create', section) ? 'bg-success' : ''"
|
:class="_canSection(permissionUpdate, 'create', section) ? 'bg-success' : ''"
|
||||||
@click="togglePermission('create', section)"
|
@click="togglePermission('create', section)"
|
||||||
/>
|
/>
|
||||||
<PencilIcon
|
<PencilIcon
|
||||||
class="w-5 h-5 p-1 box-content cursor-pointer"
|
class="w-5 h-5 p-1 box-content cursor-pointer"
|
||||||
:class="_can(permissionUpdate, 'update', section) ? 'bg-success' : ''"
|
:class="_canSection(permissionUpdate, 'update', section) ? 'bg-success' : ''"
|
||||||
@click="togglePermission('update', section)"
|
@click="togglePermission('update', section)"
|
||||||
/>
|
/>
|
||||||
<TrashIcon
|
<TrashIcon
|
||||||
class="w-5 h-5 p-1 box-content cursor-pointer"
|
class="w-5 h-5 p-1 box-content cursor-pointer"
|
||||||
:class="_can(permissionUpdate, 'delete', section) ? 'bg-success' : ''"
|
:class="_canSection(permissionUpdate, 'delete', section) ? 'bg-success' : ''"
|
||||||
@click="togglePermission('delete', section)"
|
@click="togglePermission('delete', section)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -132,7 +132,7 @@ export default defineComponent({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(useAbilityStore, ["_can"]),
|
...mapState(useAbilityStore, ["_can", "_canSection"]),
|
||||||
canSaveOrReset(): boolean {
|
canSaveOrReset(): boolean {
|
||||||
return isEqual(this.permissions, this.permissionUpdate);
|
return isEqual(this.permissions, this.permissionUpdate);
|
||||||
},
|
},
|
||||||
|
|
|
@ -109,8 +109,8 @@ import { Listbox, ListboxButton, ListboxOptions, ListboxOption, ListboxLabel } f
|
||||||
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/vue/20/solid";
|
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/vue/20/solid";
|
||||||
import { useMemberStore } from "@/stores/admin/club/member/member";
|
import { useMemberStore } from "@/stores/admin/club/member/member";
|
||||||
import type { CreateMemberViewModel } from "@/viewmodels/admin/club/member/member.models";
|
import type { CreateMemberViewModel } from "@/viewmodels/admin/club/member/member.models";
|
||||||
import { useSalutationStore } from "../../../../stores/admin/configuration/salutation";
|
import { useSalutationStore } from "@/stores/admin/configuration/salutation";
|
||||||
import type { SalutationViewModel } from "../../../../viewmodels/admin/configuration/salutation.models";
|
import type { SalutationViewModel } from "@/viewmodels/admin/configuration/salutation.models";
|
||||||
import { InformationCircleIcon } from "@heroicons/vue/24/outline";
|
import { InformationCircleIcon } from "@heroicons/vue/24/outline";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,8 @@ import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||||
import FailureXMark from "@/components/FailureXMark.vue";
|
import FailureXMark from "@/components/FailureXMark.vue";
|
||||||
import { useProtocolStore } from "@/stores/admin/club/protocol/protocol";
|
import { useProtocolStore } from "@/stores/admin/club/protocol/protocol";
|
||||||
import type { CreateProtocolViewModel } from "@/viewmodels/admin/club/protocol/protocol.models";
|
import type { CreateProtocolViewModel } from "@/viewmodels/admin/club/protocol/protocol.models";
|
||||||
import { useNewsletterStore } from "../../../../stores/admin/club/newsletter/newsletter";
|
import { useNewsletterStore } from "@/stores/admin/club/newsletter/newsletter";
|
||||||
import type { CreateNewsletterViewModel } from "../../../../viewmodels/admin/club/newsletter/newsletter.models";
|
import type { CreateNewsletterViewModel } from "@/viewmodels/admin/club/newsletter/newsletter.models";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { mapState, mapActions } from "pinia";
|
||||||
import { ArchiveBoxArrowDownIcon, ArrowDownTrayIcon, BarsArrowUpIcon } from "@heroicons/vue/24/outline";
|
import { ArchiveBoxArrowDownIcon, ArrowDownTrayIcon, BarsArrowUpIcon } from "@heroicons/vue/24/outline";
|
||||||
import { useAbilityStore } from "@/stores/ability";
|
import { useAbilityStore } from "@/stores/ability";
|
||||||
import { useModalStore } from "@/stores/modal";
|
import { useModalStore } from "@/stores/modal";
|
||||||
import { useBackupStore } from "../../../../stores/admin/management/backup";
|
import { useBackupStore } from "@/stores/admin/management/backup";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -57,9 +57,9 @@ import Spinner from "@/components/Spinner.vue";
|
||||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||||
import FailureXMark from "@/components/FailureXMark.vue";
|
import FailureXMark from "@/components/FailureXMark.vue";
|
||||||
import { useBackupStore } from "@/stores/admin/management/backup";
|
import { useBackupStore } from "@/stores/admin/management/backup";
|
||||||
import type { BackupRestoreViewModel } from "../../../../viewmodels/admin/management/backup.models";
|
import type { BackupRestoreViewModel } from "@/viewmodels/admin/management/backup.models";
|
||||||
import { InformationCircleIcon } from "@heroicons/vue/24/outline";
|
import { InformationCircleIcon } from "@heroicons/vue/24/outline";
|
||||||
import { backupSections, type BackupSection } from "../../../../types/backupTypes";
|
import { backupSections, type BackupSection } from "@/types/backupTypes";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -39,7 +39,7 @@ import Spinner from "@/components/Spinner.vue";
|
||||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||||
import FailureXMark from "@/components/FailureXMark.vue";
|
import FailureXMark from "@/components/FailureXMark.vue";
|
||||||
import { useWebapiStore } from "@/stores/admin/management/webapi";
|
import { useWebapiStore } from "@/stores/admin/management/webapi";
|
||||||
import type { CreateWebapiViewModel } from "../../../../viewmodels/admin/management/webapi.models";
|
import type { CreateWebapiViewModel } from "@/viewmodels/admin/management/webapi.models";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -28,7 +28,7 @@ import { CheckIcon, ChevronUpDownIcon } from "@heroicons/vue/20/solid";
|
||||||
import TextCopy from "@/components/TextCopy.vue";
|
import TextCopy from "@/components/TextCopy.vue";
|
||||||
import { CalendarDaysIcon, InformationCircleIcon } from "@heroicons/vue/24/outline";
|
import { CalendarDaysIcon, InformationCircleIcon } from "@heroicons/vue/24/outline";
|
||||||
import { host } from "@/serverCom";
|
import { host } from "@/serverCom";
|
||||||
import { useWebapiStore } from "../../../../stores/admin/management/webapi";
|
import { useWebapiStore } from "@/stores/admin/management/webapi";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -34,7 +34,7 @@ import Spinner from "@/components/Spinner.vue";
|
||||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||||
import FailureXMark from "@/components/FailureXMark.vue";
|
import FailureXMark from "@/components/FailureXMark.vue";
|
||||||
import { mapActions } from "pinia";
|
import { mapActions } from "pinia";
|
||||||
import { useSetupStore } from "../../stores/setup";
|
import { useSetupStore } from "@/stores/setup";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -32,7 +32,7 @@ import Spinner from "@/components/Spinner.vue";
|
||||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||||
import FailureXMark from "@/components/FailureXMark.vue";
|
import FailureXMark from "@/components/FailureXMark.vue";
|
||||||
import { mapActions } from "pinia";
|
import { mapActions } from "pinia";
|
||||||
import { useSetupStore } from "../../stores/setup";
|
import { useSetupStore } from "@/stores/setup";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -63,7 +63,7 @@ import Spinner from "@/components/Spinner.vue";
|
||||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||||
import FailureXMark from "@/components/FailureXMark.vue";
|
import FailureXMark from "@/components/FailureXMark.vue";
|
||||||
import { mapActions } from "pinia";
|
import { mapActions } from "pinia";
|
||||||
import { useSetupStore } from "../../stores/setup";
|
import { useSetupStore } from "@/stores/setup";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -37,7 +37,7 @@ import Spinner from "@/components/Spinner.vue";
|
||||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||||
import FailureXMark from "@/components/FailureXMark.vue";
|
import FailureXMark from "@/components/FailureXMark.vue";
|
||||||
import { mapActions } from "pinia";
|
import { mapActions } from "pinia";
|
||||||
import { useSetupStore } from "../../stores/setup";
|
import { useSetupStore } from "@/stores/setup";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -57,7 +57,7 @@ import Spinner from "@/components/Spinner.vue";
|
||||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||||
import FailureXMark from "@/components/FailureXMark.vue";
|
import FailureXMark from "@/components/FailureXMark.vue";
|
||||||
import { mapActions } from "pinia";
|
import { mapActions } from "pinia";
|
||||||
import { useSetupStore } from "../../stores/setup";
|
import { useSetupStore } from "@/stores/setup";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { joinTableFormatter, type FieldType, type QueryResult } from "../types/dynamicQueries";
|
import { joinTableFormatter, type FieldType, type QueryResult } from "@/types/dynamicQueries";
|
||||||
|
|
||||||
export function joinTableName(name: string): string {
|
export function joinTableName(name: string): string {
|
||||||
let normalized = joinTableFormatter[name];
|
let normalized = joinTableFormatter[name];
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useBackupStore } from "../stores/admin/management/backup";
|
import { useBackupStore } from "@/stores/admin/management/backup";
|
||||||
|
|
||||||
export async function setBackupPage(to: any, from: any, next: any) {
|
export async function setBackupPage(to: any, from: any, next: any) {
|
||||||
const backup = useBackupStore();
|
const backup = useBackupStore();
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useNewsletterStore } from "@/stores/admin/club/newsletter/newsletter";
|
import { useNewsletterStore } from "@/stores/admin/club/newsletter/newsletter";
|
||||||
import { useNewsletterDatesStore } from "@/stores/admin/club/newsletter/newsletterDates";
|
import { useNewsletterDatesStore } from "@/stores/admin/club/newsletter/newsletterDates";
|
||||||
import { useNewsletterRecipientsStore } from "@/stores/admin/club/newsletter/newsletterRecipients";
|
import { useNewsletterRecipientsStore } from "@/stores/admin/club/newsletter/newsletterRecipients";
|
||||||
import { useNewsletterPrintoutStore } from "../stores/admin/club/newsletter/newsletterPrintout";
|
import { useNewsletterPrintoutStore } from "@/stores/admin/club/newsletter/newsletterPrintout";
|
||||||
|
|
||||||
export async function setNewsletterId(to: any, from: any, next: any) {
|
export async function setNewsletterId(to: any, from: any, next: any) {
|
||||||
const newsletter = useNewsletterStore();
|
const newsletter = useNewsletterStore();
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useProtocolAgendaStore } from "@/stores/admin/club/protocol/protocolAge
|
||||||
import { useProtocolDecisionStore } from "@/stores/admin/club/protocol/protocolDecision";
|
import { useProtocolDecisionStore } from "@/stores/admin/club/protocol/protocolDecision";
|
||||||
import { useProtocolPresenceStore } from "@/stores/admin/club/protocol/protocolPresence";
|
import { useProtocolPresenceStore } from "@/stores/admin/club/protocol/protocolPresence";
|
||||||
import { useProtocolVotingStore } from "@/stores/admin/club/protocol/protocolVoting";
|
import { useProtocolVotingStore } from "@/stores/admin/club/protocol/protocolVoting";
|
||||||
import { useProtocolPrintoutStore } from "../stores/admin/club/protocol/protocolPrintout";
|
import { useProtocolPrintoutStore } from "@/stores/admin/club/protocol/protocolPrintout";
|
||||||
|
|
||||||
export async function setProtocolId(to: any, from: any, next: any) {
|
export async function setProtocolId(to: any, from: any, next: any) {
|
||||||
const protocol = useProtocolStore();
|
const protocol = useProtocolStore();
|
||||||
|
|
|
@ -11,21 +11,18 @@ export const useAbilityStore = defineStore("ability", {
|
||||||
getters: {
|
getters: {
|
||||||
can:
|
can:
|
||||||
(state) =>
|
(state) =>
|
||||||
(type: PermissionType | "admin", section: PermissionSection, module?: PermissionModule): boolean => {
|
(type: PermissionType | "admin", section: PermissionSection, module: PermissionModule): boolean => {
|
||||||
const permissions = state.permissions;
|
const permissions = state.permissions;
|
||||||
if (state.isOwner) return true;
|
if (state.isOwner) return true;
|
||||||
if (type == "admin") return permissions?.admin ?? false;
|
if (type == "admin") return permissions?.admin ?? permissions?.adminByOwner ?? false;
|
||||||
if (permissions?.admin) return true;
|
if (permissions?.admin || permissions?.adminByOwner) return true;
|
||||||
if (
|
if (
|
||||||
(!module &&
|
|
||||||
permissions[section] != undefined &&
|
|
||||||
(permissions[section]?.all == "*" || permissions[section]?.all?.includes(type))) ||
|
|
||||||
permissions[section]?.all == "*" ||
|
permissions[section]?.all == "*" ||
|
||||||
permissions[section]?.all?.includes(type)
|
permissions[section]?.all?.includes(type) ||
|
||||||
|
permissions[section]?.[module] == "*" ||
|
||||||
|
permissions[section]?.[module]?.includes(type)
|
||||||
)
|
)
|
||||||
return true;
|
return true;
|
||||||
if (module && (permissions[section]?.[module] == "*" || permissions[section]?.[module]?.includes(type)))
|
|
||||||
return true;
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
canSection:
|
canSection:
|
||||||
|
@ -33,8 +30,8 @@ export const useAbilityStore = defineStore("ability", {
|
||||||
(type: PermissionType | "admin", section: PermissionSection): boolean => {
|
(type: PermissionType | "admin", section: PermissionSection): boolean => {
|
||||||
const permissions = state.permissions;
|
const permissions = state.permissions;
|
||||||
if (state.isOwner) return true;
|
if (state.isOwner) return true;
|
||||||
if (type == "admin") return permissions?.admin ?? false;
|
if (type == "admin") return permissions?.admin ?? permissions?.adminByOwner ?? false;
|
||||||
if (permissions?.admin) return true;
|
if (permissions?.admin || permissions?.adminByOwner) return true;
|
||||||
if (
|
if (
|
||||||
permissions[section]?.all == "*" ||
|
permissions[section]?.all == "*" ||
|
||||||
permissions[section]?.all?.includes(type) ||
|
permissions[section]?.all?.includes(type) ||
|
||||||
|
@ -54,20 +51,31 @@ export const useAbilityStore = defineStore("ability", {
|
||||||
permissions: PermissionObject,
|
permissions: PermissionObject,
|
||||||
type: PermissionType | "admin",
|
type: PermissionType | "admin",
|
||||||
section: PermissionSection,
|
section: PermissionSection,
|
||||||
module?: PermissionModule
|
module: PermissionModule
|
||||||
): boolean => {
|
): boolean => {
|
||||||
// ignores ownership
|
// ignores ownership
|
||||||
if (type == "admin") return permissions?.admin ?? false;
|
if (type == "admin") return permissions?.admin ?? permissions?.adminByOwner ?? false;
|
||||||
if (permissions?.admin) return true;
|
if (permissions?.admin || permissions?.adminByOwner) return true;
|
||||||
if (
|
if (
|
||||||
(!module &&
|
|
||||||
permissions[section] != undefined &&
|
|
||||||
(permissions[section]?.all == "*" || permissions[section]?.all?.includes(type))) ||
|
|
||||||
permissions[section]?.all == "*" ||
|
permissions[section]?.all == "*" ||
|
||||||
permissions[section]?.all?.includes(type)
|
permissions[section]?.all?.includes(type) ||
|
||||||
|
permissions[section]?.[module] == "*" ||
|
||||||
|
permissions[section]?.[module]?.includes(type)
|
||||||
)
|
)
|
||||||
return true;
|
return true;
|
||||||
if (module && (permissions[section]?.[module] == "*" || permissions[section]?.[module]?.includes(type)))
|
return false;
|
||||||
|
},
|
||||||
|
_canSection:
|
||||||
|
() =>
|
||||||
|
(permissions: PermissionObject, type: PermissionType | "admin", section: PermissionSection): boolean => {
|
||||||
|
// ignores ownership
|
||||||
|
if (type == "admin") return permissions?.admin ?? permissions?.adminByOwner ?? false;
|
||||||
|
if (permissions?.admin || permissions?.adminByOwner) return true;
|
||||||
|
if (
|
||||||
|
permissions[section]?.all == "*" ||
|
||||||
|
permissions[section]?.all?.includes(type) ||
|
||||||
|
permissions[section] != undefined
|
||||||
|
)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { http, newEventSource, streamingFetch } from "@/serverCom";
|
import { http, streamingFetch } from "@/serverCom";
|
||||||
import { useNewsletterStore } from "./newsletter";
|
import { useNewsletterStore } from "./newsletter";
|
||||||
import type { AxiosResponse } from "axios";
|
import type { AxiosResponse } from "axios";
|
||||||
import type { EventSourcePolyfill } from "event-source-polyfill";
|
import { useNotificationStore, type NotificationType } from "@/stores/notification";
|
||||||
import { useNotificationStore, type NotificationType } from "../../../notification";
|
|
||||||
|
|
||||||
export const useNewsletterPrintoutStore = defineStore("newsletterPrintout", {
|
export const useNewsletterPrintoutStore = defineStore("newsletterPrintout", {
|
||||||
state: () => {
|
state: () => {
|
||||||
|
|
|
@ -6,10 +6,10 @@ import type {
|
||||||
} from "@/viewmodels/admin/configuration/query.models";
|
} from "@/viewmodels/admin/configuration/query.models";
|
||||||
import { http } from "@/serverCom";
|
import { http } from "@/serverCom";
|
||||||
import type { AxiosResponse } from "axios";
|
import type { AxiosResponse } from "axios";
|
||||||
import { useQueryBuilderStore } from "../club/queryBuilder";
|
import { useQueryBuilderStore } from "@/stores/admin/club/queryBuilder";
|
||||||
import { useModalStore } from "../../modal";
|
import { useModalStore } from "@/stores/modal";
|
||||||
import { defineAsyncComponent, markRaw } from "vue";
|
import { defineAsyncComponent, markRaw } from "vue";
|
||||||
import { useAbilityStore } from "../../ability";
|
import { useAbilityStore } from "@/stores/ability";
|
||||||
|
|
||||||
export const useQueryStoreStore = defineStore("queryStore", {
|
export const useQueryStoreStore = defineStore("queryStore", {
|
||||||
state: () => {
|
state: () => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { http } from "@/serverCom";
|
import { http } from "@/serverCom";
|
||||||
import type { AxiosResponse, AxiosProgressEvent } from "axios";
|
import type { AxiosResponse, AxiosProgressEvent } from "axios";
|
||||||
import type { BackupRestoreViewModel } from "../../../viewmodels/admin/management/backup.models";
|
import type { BackupRestoreViewModel } from "@/viewmodels/admin/management/backup.models";
|
||||||
|
|
||||||
export const useBackupStore = defineStore("backup", {
|
export const useBackupStore = defineStore("backup", {
|
||||||
state: () => {
|
state: () => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { useAbilityStore } from "@/stores/ability";
|
import { useAbilityStore } from "@/stores/ability";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import type { PermissionSection } from "../../types/permissionTypes";
|
import type { PermissionSection } from "@/types/permissionTypes";
|
||||||
|
|
||||||
export type navigationModel = {
|
export type navigationModel = {
|
||||||
[key in topLevelNavigationType]: navigationSplitModel;
|
[key in topLevelNavigationType]: navigationSplitModel;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { http } from "../serverCom";
|
import { http } from "@/serverCom";
|
||||||
|
|
||||||
export const useConfigurationStore = defineStore("configuration", {
|
export const useConfigurationStore = defineStore("configuration", {
|
||||||
state: () => {
|
state: () => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { http } from "../serverCom";
|
import { http } from "@/serverCom";
|
||||||
import type { AxiosResponse } from "axios";
|
import type { AxiosResponse } from "axios";
|
||||||
import { useConfigurationStore } from "./configuration";
|
import { useConfigurationStore } from "./configuration";
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ export type PermissionString =
|
||||||
| `${PermissionSection}.${PermissionModule}.*` // für alle Berechtigungen in einem Modul
|
| `${PermissionSection}.${PermissionModule}.*` // für alle Berechtigungen in einem Modul
|
||||||
| `${PermissionSection}.${PermissionType}` // für spezifische Berechtigungen in einem Abschnitt
|
| `${PermissionSection}.${PermissionType}` // für spezifische Berechtigungen in einem Abschnitt
|
||||||
| `${PermissionSection}.*` // für alle Berechtigungen in einem Abschnitt
|
| `${PermissionSection}.*` // für alle Berechtigungen in einem Abschnitt
|
||||||
|
| `additional.${string}.${string}` // additional
|
||||||
| "*"; // für Admin
|
| "*"; // für Admin
|
||||||
|
|
||||||
export type PermissionObject = {
|
export type PermissionObject = {
|
||||||
|
@ -39,10 +40,20 @@ export type PermissionObject = {
|
||||||
} & { all?: Array<PermissionType> | "*" };
|
} & { all?: Array<PermissionType> | "*" };
|
||||||
} & {
|
} & {
|
||||||
admin?: boolean;
|
admin?: boolean;
|
||||||
|
adminByOwner?: boolean;
|
||||||
|
} & {
|
||||||
|
additional?: { [key: string]: string };
|
||||||
};
|
};
|
||||||
|
|
||||||
export type SectionsAndModulesObject = {
|
export type SectionsAndModulesObject = {
|
||||||
[section in PermissionSection]: Array<PermissionModule>;
|
[section in PermissionSection]: Array<PermissionModule>;
|
||||||
|
} & {
|
||||||
|
additional?: Array<{
|
||||||
|
key: string;
|
||||||
|
name: string;
|
||||||
|
type: "number" | "string";
|
||||||
|
emptyIfAdmin: boolean;
|
||||||
|
}>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const permissionSections: Array<PermissionSection> = ["club", "configuration", "management"];
|
export const permissionSections: Array<PermissionSection> = ["club", "configuration", "management"];
|
||||||
|
@ -87,4 +98,7 @@ export const sectionsAndModules: SectionsAndModulesObject = {
|
||||||
"newsletter_config",
|
"newsletter_config",
|
||||||
],
|
],
|
||||||
management: ["user", "role", "webapi", "backup", "setting"],
|
management: ["user", "role", "webapi", "backup", "setting"],
|
||||||
|
additional: [
|
||||||
|
//{ key: "val", name: "name", type: "number", emptyIfAdmin: true },
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { CalendarTypeViewModel } from "../configuration/calendarType.models";
|
import type { CalendarTypeViewModel } from "@/viewmodels/admin/configuration/calendarType.models";
|
||||||
|
|
||||||
export interface CalendarViewModel {
|
export interface CalendarViewModel {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { CommunicationTypeViewModel } from "../../configuration/communicationType.models";
|
import type { CommunicationTypeViewModel } from "@/viewmodels/admin/configuration/communicationType.models";
|
||||||
|
|
||||||
export interface CommunicationViewModel {
|
export interface CommunicationViewModel {
|
||||||
id: number;
|
id: number;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { CommunicationViewModel } from "./communication.models";
|
import type { CommunicationViewModel } from "./communication.models";
|
||||||
import type { MembershipViewModel } from "./membership.models";
|
import type { MembershipViewModel } from "./membership.models";
|
||||||
import type { SalutationViewModel } from "../../configuration/salutation.models";
|
import type { SalutationViewModel } from "@/viewmodels/admin/configuration/salutation.models";
|
||||||
|
|
||||||
export interface MemberViewModel {
|
export interface MemberViewModel {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { CalendarViewModel } from "../calendar.models";
|
import type { CalendarViewModel } from "@/viewmodels/admin/club/calendar.models";
|
||||||
|
|
||||||
export interface NewsletterDatesViewModel {
|
export interface NewsletterDatesViewModel {
|
||||||
newsletterId: number;
|
newsletterId: number;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { MemberViewModel } from "../member/member.models";
|
import type { MemberViewModel } from "@/viewmodels/admin/club/member/member.models";
|
||||||
|
|
||||||
export interface NewsletterRecipientsViewModel {
|
export interface NewsletterRecipientsViewModel {
|
||||||
newsletterId: number;
|
newsletterId: number;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import type { BackupSection } from "../../../types/backupTypes";
|
import type { BackupSection } from "@/types/backupTypes";
|
||||||
|
|
||||||
export interface BackupRestoreViewModel {
|
export interface BackupRestoreViewModel {
|
||||||
filename: string;
|
filename: string;
|
||||||
|
|
|
@ -81,7 +81,7 @@ import FormBottomBar from "@/components/FormBottomBar.vue";
|
||||||
import AppLogo from "@/components/AppLogo.vue";
|
import AppLogo from "@/components/AppLogo.vue";
|
||||||
import { mapState } from "pinia";
|
import { mapState } from "pinia";
|
||||||
import { useConfigurationStore } from "@/stores/configuration";
|
import { useConfigurationStore } from "@/stores/configuration";
|
||||||
import { hashString } from "../helpers/crypto";
|
import { hashString } from "@/helpers/crypto";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -54,10 +54,10 @@ import Spinner from "@/components/Spinner.vue";
|
||||||
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
import SuccessCheckmark from "@/components/SuccessCheckmark.vue";
|
||||||
import FailureXMark from "@/components/FailureXMark.vue";
|
import FailureXMark from "@/components/FailureXMark.vue";
|
||||||
import TextCopy from "@/components/TextCopy.vue";
|
import TextCopy from "@/components/TextCopy.vue";
|
||||||
import TotpCheckAndScan from "../../components/account/TotpCheckAndScan.vue";
|
import TotpCheckAndScan from "@/components/account/TotpCheckAndScan.vue";
|
||||||
import PasswordChange from "../../components/account/PasswordChange.vue";
|
import PasswordChange from "@/components/account/PasswordChange.vue";
|
||||||
import ChangeToPassword from "../../components/account/ChangeToPassword.vue";
|
import ChangeToPassword from "@/components/account/ChangeToPassword.vue";
|
||||||
import ChangeToTOTP from "../../components/account/ChangeToTOTP.vue";
|
import ChangeToTOTP from "@/components/account/ChangeToTOTP.vue";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -103,7 +103,7 @@ import { Listbox, ListboxButton, ListboxOptions, ListboxOption, ListboxLabel } f
|
||||||
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/vue/20/solid";
|
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/vue/20/solid";
|
||||||
import cloneDeep from "lodash.clonedeep";
|
import cloneDeep from "lodash.clonedeep";
|
||||||
import isEqual from "lodash.isequal";
|
import isEqual from "lodash.isequal";
|
||||||
import { useSalutationStore } from "../../../../stores/admin/configuration/salutation";
|
import { useSalutationStore } from "@/stores/admin/configuration/salutation";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -38,7 +38,7 @@ import Pagination from "@/components/Pagination.vue";
|
||||||
import { useAbilityStore } from "@/stores/ability";
|
import { useAbilityStore } from "@/stores/ability";
|
||||||
import { useNewsletterStore } from "@/stores/admin/club/newsletter/newsletter";
|
import { useNewsletterStore } from "@/stores/admin/club/newsletter/newsletter";
|
||||||
import type { NewsletterViewModel } from "@/viewmodels/admin/club/newsletter/newsletter.models";
|
import type { NewsletterViewModel } from "@/viewmodels/admin/club/newsletter/newsletter.models";
|
||||||
import NewsletterListItem from "../../../../components/admin/club/newsletter/NewsletterListItem.vue";
|
import NewsletterListItem from "@/components/admin/club/newsletter/NewsletterListItem.vue";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -81,7 +81,7 @@ import FailureXMark from "@/components/FailureXMark.vue";
|
||||||
import { ArrowDownTrayIcon, ViewfinderCircleIcon } from "@heroicons/vue/24/outline";
|
import { ArrowDownTrayIcon, ViewfinderCircleIcon } from "@heroicons/vue/24/outline";
|
||||||
import { useModalStore } from "@/stores/modal";
|
import { useModalStore } from "@/stores/modal";
|
||||||
import { useAbilityStore } from "@/stores/ability";
|
import { useAbilityStore } from "@/stores/ability";
|
||||||
import { useNewsletterPrintoutStore } from "../../../../stores/admin/club/newsletter/newsletterPrintout";
|
import { useNewsletterPrintoutStore } from "@/stores/admin/club/newsletter/newsletterPrintout";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -53,8 +53,8 @@ import { useNewsletterStore } from "@/stores/admin/club/newsletter/newsletter";
|
||||||
import { useModalStore } from "@/stores/modal";
|
import { useModalStore } from "@/stores/modal";
|
||||||
import NewsletterSyncing from "@/components/admin/club/newsletter/NewsletterSyncing.vue";
|
import NewsletterSyncing from "@/components/admin/club/newsletter/NewsletterSyncing.vue";
|
||||||
import { PrinterIcon } from "@heroicons/vue/24/outline";
|
import { PrinterIcon } from "@heroicons/vue/24/outline";
|
||||||
import { useNewsletterDatesStore } from "../../../../stores/admin/club/newsletter/newsletterDates";
|
import { useNewsletterDatesStore } from "@/stores/admin/club/newsletter/newsletterDates";
|
||||||
import { useNewsletterRecipientsStore } from "../../../../stores/admin/club/newsletter/newsletterRecipients";
|
import { useNewsletterRecipientsStore } from "@/stores/admin/club/newsletter/newsletterRecipients";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
|
@ -32,7 +32,7 @@ import { useSetupStore } from "@/stores/setup";
|
||||||
import Club from "@/components/setup/Club.vue";
|
import Club from "@/components/setup/Club.vue";
|
||||||
import Images from "@/components/setup/Images.vue";
|
import Images from "@/components/setup/Images.vue";
|
||||||
import Finished from "@/components/setup/Finished.vue";
|
import Finished from "@/components/setup/Finished.vue";
|
||||||
import Mail from "../../components/setup/Mail.vue";
|
import Mail from "@/components/setup/Mail.vue";
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
Loading…
Add table
Reference in a new issue