Merge branch 'develop' into milestone/ff-admin-unit
This commit is contained in:
commit
4ebacc5f52
107 changed files with 4980 additions and 1739 deletions
|
@ -11,21 +11,18 @@ export const useAbilityStore = defineStore("ability", {
|
|||
getters: {
|
||||
can:
|
||||
(state) =>
|
||||
(type: PermissionType | "admin", section: PermissionSection, module?: PermissionModule): boolean => {
|
||||
(type: PermissionType | "admin", section: PermissionSection, module: PermissionModule): boolean => {
|
||||
const permissions = state.permissions;
|
||||
if (state.isOwner) return true;
|
||||
if (type == "admin") return permissions?.admin ?? false;
|
||||
if (permissions?.admin) return true;
|
||||
if (type == "admin") return permissions?.admin ?? permissions?.adminByOwner ?? false;
|
||||
if (permissions?.admin || permissions?.adminByOwner) return true;
|
||||
if (
|
||||
(!module &&
|
||||
permissions[section] != undefined &&
|
||||
(permissions[section]?.all == "*" || permissions[section]?.all?.includes(type))) ||
|
||||
permissions[section]?.all == "*" ||
|
||||
permissions[section]?.all?.includes(type)
|
||||
permissions[section]?.all?.includes(type) ||
|
||||
permissions[section]?.[module] == "*" ||
|
||||
permissions[section]?.[module]?.includes(type)
|
||||
)
|
||||
return true;
|
||||
if (module && (permissions[section]?.[module] == "*" || permissions[section]?.[module]?.includes(type)))
|
||||
return true;
|
||||
return false;
|
||||
},
|
||||
canSection:
|
||||
|
@ -33,8 +30,8 @@ export const useAbilityStore = defineStore("ability", {
|
|||
(type: PermissionType | "admin", section: PermissionSection): boolean => {
|
||||
const permissions = state.permissions;
|
||||
if (state.isOwner) return true;
|
||||
if (type == "admin") return permissions?.admin ?? false;
|
||||
if (permissions?.admin) return true;
|
||||
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) ||
|
||||
|
@ -54,20 +51,31 @@ export const useAbilityStore = defineStore("ability", {
|
|||
permissions: PermissionObject,
|
||||
type: PermissionType | "admin",
|
||||
section: PermissionSection,
|
||||
module?: PermissionModule
|
||||
module: PermissionModule
|
||||
): boolean => {
|
||||
// ignores ownership
|
||||
if (type == "admin") return permissions?.admin ?? false;
|
||||
if (permissions?.admin) return true;
|
||||
if (type == "admin") return permissions?.admin ?? permissions?.adminByOwner ?? false;
|
||||
if (permissions?.admin || permissions?.adminByOwner) return true;
|
||||
if (
|
||||
(!module &&
|
||||
permissions[section] != undefined &&
|
||||
(permissions[section]?.all == "*" || permissions[section]?.all?.includes(type))) ||
|
||||
permissions[section]?.all == "*" ||
|
||||
permissions[section]?.all?.includes(type)
|
||||
permissions[section]?.all?.includes(type) ||
|
||||
permissions[section]?.[module] == "*" ||
|
||||
permissions[section]?.[module]?.includes(type)
|
||||
)
|
||||
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 false;
|
||||
},
|
||||
|
|
|
@ -87,6 +87,9 @@ export const useMemberStore = defineStore("member", {
|
|||
})
|
||||
.catch((err) => {});
|
||||
},
|
||||
fetchLastInternalId() {
|
||||
return http.get(`/admin/member/last/internalId`);
|
||||
},
|
||||
async printMemberByActiveId() {
|
||||
return http.get(`/admin/member/${this.activeMember}/print`, {
|
||||
responseType: "blob",
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { http, newEventSource, streamingFetch } from "@/serverCom";
|
||||
import { http, streamingFetch } from "@/serverCom";
|
||||
import { useNewsletterStore } from "./newsletter";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import type { EventSourcePolyfill } from "event-source-polyfill";
|
||||
import { useNotificationStore, type NotificationType } from "../../../notification";
|
||||
import { useNotificationStore, type NotificationType } from "@/stores/notification";
|
||||
|
||||
export const useNewsletterPrintoutStore = defineStore("newsletterPrintout", {
|
||||
state: () => {
|
||||
|
|
|
@ -2,6 +2,7 @@ import { defineStore } from "pinia";
|
|||
import { http } from "@/serverCom";
|
||||
import type { TableMeta } from "@/viewmodels/admin/configuration/query.models";
|
||||
import type { DynamicQueryStructure, FieldType } from "@/types/dynamicQueries";
|
||||
import type { AxiosResponse } from "axios";
|
||||
|
||||
export const useQueryBuilderStore = defineStore("queryBuilder", {
|
||||
state: () => {
|
||||
|
@ -58,6 +59,16 @@ export const useQueryBuilderStore = defineStore("queryBuilder", {
|
|||
this.loadingData = "failed";
|
||||
});
|
||||
},
|
||||
async sendQueryByStoreId(
|
||||
id: string,
|
||||
offset = 0,
|
||||
count = 25,
|
||||
noLimit: boolean = false
|
||||
): Promise<AxiosResponse<any, any>> {
|
||||
return await http.post(
|
||||
`/admin/querybuilder/query/${id}?` + (noLimit ? `noLimit=true` : `offset=${offset}&count=${count}`)
|
||||
);
|
||||
},
|
||||
clearResults() {
|
||||
this.data = [];
|
||||
this.totalLength = 0;
|
||||
|
|
|
@ -6,7 +6,7 @@ import type {
|
|||
import { http } from "@/serverCom";
|
||||
import type { AxiosResponse } from "axios";
|
||||
|
||||
export const useNewsletterConfigStore = defineStore("newsletterConfi", {
|
||||
export const useNewsletterConfigStore = defineStore("newsletterConfig", {
|
||||
state: () => {
|
||||
return {
|
||||
config: [] as Array<NewsletterConfigViewModel>,
|
||||
|
|
|
@ -6,10 +6,10 @@ import type {
|
|||
} from "@/viewmodels/admin/configuration/query.models";
|
||||
import { http } from "@/serverCom";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import { useQueryBuilderStore } from "../club/queryBuilder";
|
||||
import { useModalStore } from "../../modal";
|
||||
import { useQueryBuilderStore } from "@/stores/admin/club/queryBuilder";
|
||||
import { useModalStore } from "@/stores/modal";
|
||||
import { defineAsyncComponent, markRaw } from "vue";
|
||||
import { useAbilityStore } from "../../ability";
|
||||
import { useAbilityStore } from "@/stores/ability";
|
||||
|
||||
export const useQueryStoreStore = defineStore("queryStore", {
|
||||
state: () => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { http } from "@/serverCom";
|
||||
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", {
|
||||
state: () => {
|
||||
|
|
103
src/stores/admin/management/setting.ts
Normal file
103
src/stores/admin/management/setting.ts
Normal file
|
@ -0,0 +1,103 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { http } from "@/serverCom";
|
||||
import type { SettingString, SettingTopic, SettingValueMapping } from "@/types/settingTypes";
|
||||
import type { AxiosResponse } from "axios";
|
||||
|
||||
export const useSettingStore = defineStore("setting", {
|
||||
state: () => {
|
||||
return {
|
||||
settings: {} as { [key in SettingString]: SettingValueMapping[key] },
|
||||
loading: "loading" as "loading" | "fetched" | "failed",
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
readSetting:
|
||||
(state) =>
|
||||
<K extends SettingString>(key: K): SettingValueMapping[K] => {
|
||||
return state.settings[key];
|
||||
},
|
||||
readByTopic:
|
||||
(state) =>
|
||||
<T extends SettingTopic>(
|
||||
topic: T
|
||||
): { [K in SettingString as K extends `${T}.${string}` ? K : never]: SettingValueMapping[K] } => {
|
||||
return Object.entries(state.settings).reduce((acc, [key, value]) => {
|
||||
const typedKey = key as SettingString;
|
||||
if (key.startsWith(topic)) {
|
||||
acc[typedKey] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {} as any);
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
fetchSettings() {
|
||||
this.loading = "loading";
|
||||
http
|
||||
.get("/admin/setting")
|
||||
.then((result) => {
|
||||
this.settings = result.data;
|
||||
this.loading = "fetched";
|
||||
})
|
||||
.catch((err) => {
|
||||
this.loading = "failed";
|
||||
});
|
||||
},
|
||||
async getSetting(key: SettingString): Promise<AxiosResponse<any, any>> {
|
||||
return await http.get(`/admin/setting/${key}`).then((res) => {
|
||||
//@ts-expect-error
|
||||
this.settings[key] = res.data;
|
||||
return res;
|
||||
});
|
||||
},
|
||||
async updateSetting<K extends SettingString>(
|
||||
key: K,
|
||||
value: SettingValueMapping[K]
|
||||
): Promise<AxiosResponse<any, any>> {
|
||||
return await http
|
||||
.put("/admin/setting", {
|
||||
setting: key,
|
||||
value: value,
|
||||
})
|
||||
.then((res) => {
|
||||
this.settings[key] = value;
|
||||
return res;
|
||||
});
|
||||
},
|
||||
async updateSettings<K extends SettingString>(
|
||||
data: { key: K; value: SettingValueMapping[K] }[]
|
||||
): Promise<AxiosResponse<any, any>> {
|
||||
return await http.put("/admin/setting/multi", data).then((res) => {
|
||||
for (const element of data) {
|
||||
this.settings[element.key] = element.value;
|
||||
}
|
||||
return res;
|
||||
});
|
||||
},
|
||||
async uploadImage(
|
||||
data: { key: "club.logo" | "club.icon"; value?: File | "keep" }[]
|
||||
): Promise<AxiosResponse<any, any>> {
|
||||
const formData = new FormData();
|
||||
for (let entry of data) {
|
||||
if (entry.value) {
|
||||
formData.append(typeof entry.value == "string" ? entry.key : entry.key.split(".")[1], entry.value);
|
||||
}
|
||||
}
|
||||
return await http
|
||||
.put("/admin/setting/images", formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
for (const element of data) {
|
||||
this.settings[element.key] = element.value ? "configured" : "";
|
||||
}
|
||||
return res;
|
||||
});
|
||||
},
|
||||
async resetSetting(key: SettingString): Promise<AxiosResponse<any, any>> {
|
||||
return await http.delete(`/admin/setting/${key}`);
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { useAbilityStore } from "@/stores/ability";
|
||||
import router from "@/router";
|
||||
import type { PermissionSection } from "../../types/permissionTypes";
|
||||
import type { PermissionSection } from "@/types/permissionTypes";
|
||||
|
||||
export type navigationModel = {
|
||||
[key in topLevelNavigationType]: navigationSplitModel;
|
||||
|
@ -146,6 +146,7 @@ export const useNavigationStore = defineStore("navigation", {
|
|||
...(abilityStore.can("read", "management", "user") ? [{ key: "user", title: "Benutzer" }] : []),
|
||||
...(abilityStore.can("read", "management", "role") ? [{ key: "role", title: "Rollen" }] : []),
|
||||
...(abilityStore.can("read", "management", "webapi") ? [{ key: "webapi", title: "Webapi-Token" }] : []),
|
||||
...(abilityStore.can("read", "management", "setting") ? [{ key: "setting", title: "Einstellungen" }] : []),
|
||||
...(abilityStore.can("read", "management", "backup") ? [{ key: "backup", title: "Backups" }] : []),
|
||||
...(abilityStore.isAdmin() ? [{ key: "version", title: "Version" }] : []),
|
||||
],
|
||||
|
|
34
src/stores/configuration.ts
Normal file
34
src/stores/configuration.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { http } from "@/serverCom";
|
||||
|
||||
export const useConfigurationStore = defineStore("configuration", {
|
||||
state: () => {
|
||||
return {
|
||||
clubName: "",
|
||||
clubImprint: "",
|
||||
clubPrivacy: "",
|
||||
clubWebsite: "",
|
||||
appCustom_login_message: "",
|
||||
appShow_link_to_calendar: false as boolean,
|
||||
|
||||
serverOffline: false as boolean,
|
||||
};
|
||||
},
|
||||
actions: {
|
||||
configure() {
|
||||
http
|
||||
.get("/public/configuration")
|
||||
.then((res) => {
|
||||
this.clubName = res.data["club.name"];
|
||||
this.clubImprint = res.data["club.imprint"];
|
||||
this.clubPrivacy = res.data["club.privacy"];
|
||||
this.clubWebsite = res.data["club.website"];
|
||||
this.appCustom_login_message = res.data["app.custom_login_message"];
|
||||
this.appShow_link_to_calendar = res.data["app.show_link_to_calendar"];
|
||||
})
|
||||
.catch(() => {
|
||||
this.serverOffline = true;
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
130
src/stores/setup.ts
Normal file
130
src/stores/setup.ts
Normal file
|
@ -0,0 +1,130 @@
|
|||
import { defineStore } from "pinia";
|
||||
import { http } from "@/serverCom";
|
||||
import type { AxiosResponse } from "axios";
|
||||
import { useConfigurationStore } from "./configuration";
|
||||
|
||||
export const useSetupStore = defineStore("setup", {
|
||||
state: () => {
|
||||
return {
|
||||
dictionary: ["club", "clubImages", "app", "mail", "account", "finished"],
|
||||
step: 0 as number,
|
||||
successfull: 0 as number,
|
||||
};
|
||||
},
|
||||
getters: {
|
||||
stepIndex: (state) => (dict: string) => state.dictionary.findIndex((d) => d == dict),
|
||||
},
|
||||
actions: {
|
||||
skip(dict: string) {
|
||||
let myIndex = this.stepIndex(dict);
|
||||
this.step += 1;
|
||||
if (this.successfull <= myIndex) {
|
||||
this.successfull = myIndex + 1;
|
||||
}
|
||||
},
|
||||
async setClub(data: {
|
||||
name?: string;
|
||||
imprint?: string;
|
||||
privacy?: string;
|
||||
website?: string;
|
||||
}): Promise<AxiosResponse<any, any>> {
|
||||
let configStore = useConfigurationStore();
|
||||
|
||||
let myIndex = this.stepIndex("club");
|
||||
const res = await http.post(`/setup/club`, {
|
||||
name: data.name,
|
||||
imprint: data.imprint,
|
||||
privacy: data.privacy,
|
||||
website: data.website,
|
||||
});
|
||||
configStore.configure();
|
||||
|
||||
this.step += 1;
|
||||
if (this.successfull <= myIndex) {
|
||||
this.successfull = myIndex;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
async setClubImages(data: { icon?: File; logo?: File }): Promise<AxiosResponse<any, any>> {
|
||||
let configStore = useConfigurationStore();
|
||||
|
||||
let myIndex = this.stepIndex("clubImages");
|
||||
const formData = new FormData();
|
||||
|
||||
if (data.icon) {
|
||||
formData.append("icon", data.icon);
|
||||
}
|
||||
|
||||
if (data.logo) {
|
||||
formData.append("logo", data.logo);
|
||||
}
|
||||
|
||||
const res = await http.post(`/setup/club/images`, formData, {
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data",
|
||||
},
|
||||
});
|
||||
configStore.configure();
|
||||
|
||||
this.step += 1;
|
||||
if (this.successfull <= myIndex) {
|
||||
this.successfull = myIndex;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
async setApp(data: { login_message: string; show_cal_link: boolean }): Promise<AxiosResponse<any, any>> {
|
||||
let myIndex = this.stepIndex("app");
|
||||
const res = await http.post(`/setup/app`, {
|
||||
custom_login_message: data.login_message,
|
||||
show_link_to_calendar: data.show_cal_link,
|
||||
});
|
||||
this.step += 1;
|
||||
if (this.successfull <= myIndex) {
|
||||
this.successfull = myIndex;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
async setMailConfig(data: {
|
||||
host: string;
|
||||
port: number;
|
||||
secure: boolean;
|
||||
mail: string;
|
||||
username: string;
|
||||
password: string;
|
||||
}): Promise<AxiosResponse<any, any>> {
|
||||
let myIndex = this.stepIndex("mail");
|
||||
const res = await http.post(`/setup/mail`, {
|
||||
host: data.host,
|
||||
port: data.port,
|
||||
secure: data.secure,
|
||||
mail: data.mail,
|
||||
username: data.username,
|
||||
password: data.password,
|
||||
});
|
||||
this.step += 1;
|
||||
if (this.successfull <= myIndex) {
|
||||
this.successfull = myIndex;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
async createAdmin(credentials: {
|
||||
username: string;
|
||||
mail: string;
|
||||
firstname: string;
|
||||
lastname: string;
|
||||
}): Promise<AxiosResponse<any, any>> {
|
||||
let myIndex = this.stepIndex("account");
|
||||
const res = await http.post(`/setup/me`, {
|
||||
username: credentials.username,
|
||||
mail: credentials.mail,
|
||||
firstname: credentials.firstname,
|
||||
lastname: credentials.lastname,
|
||||
});
|
||||
this.step += 1;
|
||||
if (this.successfull < myIndex) {
|
||||
this.successfull = myIndex;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
},
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue