diff --git a/src/command/club/member/communicationCommandHandler.ts b/src/command/club/member/communicationCommandHandler.ts index 3899394..2890485 100644 --- a/src/command/club/member/communicationCommandHandler.ts +++ b/src/command/club/member/communicationCommandHandler.ts @@ -18,6 +18,17 @@ export default abstract class CommunicationCommandHandler { let insertId = -1; return await dataSource .transaction(async (manager) => { + if (createCommunication.isSendNewsletter) { + await manager + .createQueryBuilder() + .update(communication) + .set({ + isSendNewsletter: false, + }) + .where("memberId = :memberId", { memberId: createCommunication.memberId }) + .execute(); + } + await manager .createQueryBuilder() .insert() @@ -40,16 +51,6 @@ export default abstract class CommunicationCommandHandler { .then((result) => { insertId = result.identifiers[0].id; }); - - await manager - .createQueryBuilder() - .update(communication) - .set({ - isSendNewsletter: false, - }) - .where("memberId = :memberId", { memberId: createCommunication.memberId }) - .andWhere("id <> :id", { id: insertId }) - .execute(); }) .then(() => { return insertId; @@ -67,6 +68,17 @@ export default abstract class CommunicationCommandHandler { static async update(updateCommunication: UpdateCommunicationCommand): Promise { return await dataSource .transaction(async (manager) => { + if (updateCommunication.isSendNewsletter) { + await manager + .createQueryBuilder() + .update(communication) + .set({ + isSendNewsletter: false, + }) + .where("memberId = :memberId", { memberId: updateCommunication.memberId }) + .execute(); + } + await manager .createQueryBuilder() .update(communication) @@ -85,16 +97,6 @@ export default abstract class CommunicationCommandHandler { .where("id = :id", { id: updateCommunication.id }) .andWhere("memberId = :memberId", { memberId: updateCommunication.memberId }) .execute(); - - await manager - .createQueryBuilder() - .update(communication) - .set({ - isSendNewsletter: false, - }) - .where("memberId = :memberId", { memberId: updateCommunication.memberId }) - .andWhere("id <> :id", { id: updateCommunication.id }) - .execute(); }) .then(() => {}) .catch((err) => { diff --git a/src/controller/admin/club/newsletterController.ts b/src/controller/admin/club/newsletterController.ts index 294b6e3..5399336 100644 --- a/src/controller/admin/club/newsletterController.ts +++ b/src/controller/admin/club/newsletterController.ts @@ -94,7 +94,7 @@ export async function getNewsletterPrintoutsById(req: Request, res: Response): P let newsletter = await NewsletterService.getById(newsletterId); let filesInFolder = FileSystemHelper.getFilesInDirectory( - `newsletter/${newsletter.id}_${newsletter.title.replace(" ", "")}` + `newsletter/${newsletter.id}_${newsletter.title.replaceAll(" ", "")}` ); res.json(filesInFolder); @@ -114,7 +114,7 @@ export async function getNewsletterPrintoutByIdAndPrint(req: Request, res: Respo let filepath = FileSystemHelper.formatPath( "newsletter", - `${newsletter.id}_${newsletter.title.replace(" ", "")}`, + `${newsletter.id}_${newsletter.title.replaceAll(" ", "")}`, filename ); @@ -164,6 +164,34 @@ export async function createNewsletterPrintoutPreviewById(req: Request, res: Res res.send(pdfbuffer); } +/** + * @description get all members receiving a newsletter printout by id + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getNewsletterPrintReceiversById(req: Request, res: Response): Promise { + let newsletterId = parseInt(req.params.newsletterId); + + let recipients = await NewsletterHelper.getPrintRecipients(newsletterId); + + res.json(recipients); +} + +/** + * @description get all members receiving a newsletter mail by id + * @param req {Request} Express req object + * @param res {Response} Express res object + * @returns {Promise<*>} + */ +export async function getNewsletterMailReceiversById(req: Request, res: Response): Promise { + let newsletterId = parseInt(req.params.newsletterId); + + let recipients = await NewsletterHelper.getMailRecipients(newsletterId); + + res.json(recipients); +} + /** * @description create newsletter * @param req {Request} Express req object diff --git a/src/controller/admin/club/protocolController.ts b/src/controller/admin/club/protocolController.ts index ecae059..98396c8 100644 --- a/src/controller/admin/club/protocolController.ts +++ b/src/controller/admin/club/protocolController.ts @@ -235,7 +235,7 @@ export async function createProtocolPrintoutById(req: Request, res: Response): P year: "numeric", })}`; - let filename = `${new Date().toISOString().split("T")[0]}_${iteration + 1}_Protokoll_${protocol.title.replace( + let filename = `${new Date().toISOString().split("T")[0]}_${iteration + 1}_Protokoll_${protocol.title.replaceAll( /[^a-zA-Z0-9]/g, "" )}`; diff --git a/src/helpers/jwtHelper.ts b/src/helpers/jwtHelper.ts index c16f2a2..5708ab8 100644 --- a/src/helpers/jwtHelper.ts +++ b/src/helpers/jwtHelper.ts @@ -58,7 +58,10 @@ export abstract class JWTHelper { let rolePermissions = userRoles.length != 0 ? await RolePermissionService.getByRoles(userRoles.map((e) => e.id)) : []; let rolePermissionStrings = rolePermissions.map((e) => e.permission); - let permissionObject = PermissionHelper.convertToObject([...userPermissionStrings, ...rolePermissionStrings]); + let permissionObject = PermissionHelper.convertToObject( + [...userPermissionStrings, ...rolePermissionStrings], + isOwner + ); let jwtData: JWTToken = { userId: id, diff --git a/src/helpers/newsletterHelper.ts b/src/helpers/newsletterHelper.ts index 5726dbd..e84427f 100644 --- a/src/helpers/newsletterHelper.ts +++ b/src/helpers/newsletterHelper.ts @@ -1,4 +1,3 @@ -import Mail from "nodemailer/lib/mailer"; import { member } from "../entity/club/member/member"; import { newsletter } from "../entity/club/newsletter/newsletter"; import { newsletterDates } from "../entity/club/newsletter/newsletterDates"; @@ -62,39 +61,41 @@ export abstract class NewsletterHelper { newsletterTitle: newsletter.newsletterTitle, newsletterText: newsletter.newsletterText, newsletterSignatur: newsletter.newsletterSignatur, - dates: dates.map((d) => ({ - title: d.diffTitle || d.calendar.title, - content: d.diffDescription || d.calendar.content, - starttime: d.calendar.starttime, - formattedStarttime: new Date(d.calendar.starttime).toLocaleDateString("de-DE", { - weekday: "long", - day: "2-digit", - month: "long", - }), - formattedFullStarttime: new Date(d.calendar.starttime).toLocaleDateString("de-DE", { - weekday: "long", - day: "2-digit", - month: "long", - year: "numeric", - hour: "2-digit", - minute: "2-digit", - }), - endtime: d.calendar.endtime, - formattedEndtime: new Date(d.calendar.endtime).toLocaleDateString("de-DE", { - weekday: "long", - day: "2-digit", - month: "long", - }), - formattedFullEndtime: new Date(d.calendar.endtime).toLocaleDateString("de-DE", { - weekday: "long", - day: "2-digit", - month: "long", - year: "numeric", - hour: "2-digit", - minute: "2-digit", - }), - location: d.calendar.location, - })), + dates: dates + .map((d) => ({ + title: d.diffTitle || d.calendar.title, + content: d.diffDescription || d.calendar.content, + starttime: d.calendar.starttime, + formattedStarttime: new Date(d.calendar.starttime).toLocaleDateString("de-DE", { + weekday: "long", + day: "2-digit", + month: "long", + }), + formattedFullStarttime: new Date(d.calendar.starttime).toLocaleDateString("de-DE", { + weekday: "long", + day: "2-digit", + month: "long", + year: "numeric", + hour: "2-digit", + minute: "2-digit", + }), + endtime: d.calendar.endtime, + formattedEndtime: new Date(d.calendar.endtime).toLocaleDateString("de-DE", { + weekday: "long", + day: "2-digit", + month: "long", + }), + formattedFullEndtime: new Date(d.calendar.endtime).toLocaleDateString("de-DE", { + weekday: "long", + day: "2-digit", + month: "long", + year: "numeric", + hour: "2-digit", + minute: "2-digit", + }), + location: d.calendar.location, + })) + .sort((a, b) => a.starttime.getTime() - b.starttime.getTime()), ...(recipient ? { recipient: { @@ -140,33 +141,19 @@ export abstract class NewsletterHelper { } } - let members = await MemberService.getAll({ noLimit: true, ids: queryMemberIds }); - - return members[0]; + if (queryMemberIds.length == 0) { + return []; + } else { + let members = await MemberService.getAll({ noLimit: true, ids: queryMemberIds }); + return members[0]; + } } - public static getICSFilePath(newsletter: newsletter) { - return FileSystemHelper.formatPath( - "newsletter", - `${newsletter.id}_${newsletter.title.replace(" ", "")}`, - `events.ics` - ); - } - - public static saveIcsToFile(newsletter: newsletter, ics: string) { - FileSystemHelper.writeFile(`newsletter/${newsletter.id}_${newsletter.title.replace(" ", "")}`, "events.ics", ics); - } - - public static async sendMails(newsletterId: number) { + public static async getMailRecipients(newsletterId: number) { let newsletter = await NewsletterService.getById(newsletterId); - let dates = await NewsletterDatesService.getAll(newsletterId); let recipients = await NewsletterRecipientsService.getAll(newsletterId); let config = await NewsletterConfigService.getAll(); - const { value, error } = CalendarHelper.buildICS(dates.map((r) => r.calendar)); - if (error) throw new InternalException("Failed Building ICS form Mail", error); - this.saveIcsToFile(newsletter, value); - let allowedForMail = config.filter((c) => c.config == NewsletterConfigType.mail).map((c) => c.comTypeId); const members = await this.transformRecipientsToMembers(newsletter, recipients); @@ -177,6 +164,58 @@ export abstract class NewsletterHelper { allowedForMail.includes(m.sendNewsletter?.type?.id) ); + return mailRecipients; + } + + public static async getPrintRecipients(newsletterId: number) { + let newsletter = await NewsletterService.getById(newsletterId); + let recipients = await NewsletterRecipientsService.getAll(newsletterId); + let config = await NewsletterConfigService.getAll(); + + let notAllowedForPdf = config.filter((c) => c.config == NewsletterConfigType.mail).map((c) => c.comTypeId); + + const members = await this.transformRecipientsToMembers(newsletter, recipients); + const pdfRecipients = members.filter( + (m) => !notAllowedForPdf.includes(m.sendNewsletter?.type?.id) || m.sendNewsletter == null + ); + + pdfRecipients.unshift({ + id: "0", + firstname: "Alle Mitglieder", + lastname: CLUB_NAME, + nameaffix: "", + salutation: { salutation: "" }, + } as member); + + return pdfRecipients; + } + + public static getICSFilePath(newsletter: newsletter) { + return FileSystemHelper.formatPath( + "newsletter", + `${newsletter.id}_${newsletter.title.replaceAll(" ", "")}`, + `events.ics` + ); + } + + public static saveIcsToFile(newsletter: newsletter, ics: string) { + FileSystemHelper.writeFile( + `newsletter/${newsletter.id}_${newsletter.title.replaceAll(" ", "")}`, + "events.ics", + ics + ); + } + + public static async sendMails(newsletterId: number) { + let newsletter = await NewsletterService.getById(newsletterId); + let dates = await NewsletterDatesService.getAll(newsletterId); + + const { value, error } = CalendarHelper.buildICS(dates.map((r) => r.calendar)); + if (error) throw new InternalException("Failed Building ICS form Mail", error); + this.saveIcsToFile(newsletter, value); + + const mailRecipients = await this.getMailRecipients(newsletterId); + this.formatJobEmit("progress", "mail", "info", newsletterId, mailRecipients.length, 0, "starting sending"); for (const [index, rec] of mailRecipients.entries()) { @@ -228,11 +267,10 @@ export abstract class NewsletterHelper { public static async printPdfs(newsletterId: number) { let newsletter = await NewsletterService.getById(newsletterId); let dates = await NewsletterDatesService.getAll(newsletterId); - let recipients = await NewsletterRecipientsService.getAll(newsletterId); let config = await NewsletterConfigService.getAll(); FileSystemHelper.clearDirectoryByFiletype( - `newsletter/${newsletter.id}_${newsletter.title.replace(" ", "")}`, + `newsletter/${newsletter.id}_${newsletter.title.replaceAll(" ", "")}`, ".pdf" ); @@ -240,33 +278,20 @@ export abstract class NewsletterHelper { if (error) throw new InternalException("Failed Building ICS form Pdf", error); this.saveIcsToFile(newsletter, value); - let notAllowedForPdf = config.filter((c) => c.config == NewsletterConfigType.mail).map((c) => c.comTypeId); let printWithAdress = config.filter((c) => c.config == NewsletterConfigType.pdf).map((c) => c.comTypeId); - const members = await this.transformRecipientsToMembers(newsletter, recipients); - const pdfRecipients = members.filter( - (m) => !notAllowedForPdf.includes(m.sendNewsletter?.type?.id) || m.sendNewsletter == null - ); + const pdfRecipients = await this.getPrintRecipients(newsletterId); - this.formatJobEmit("progress", "pdf", "info", newsletterId, pdfRecipients.length + 1, 0, "starting sending"); + this.formatJobEmit("progress", "pdf", "info", newsletterId, pdfRecipients.length, 0, "starting printing"); - for (const [index, rec] of [ - ...pdfRecipients, - { - id: "0", - firstname: "Alle Mitglieder", - lastname: CLUB_NAME, - nameaffix: "", - salutation: { salutation: "" }, - } as member, - ].entries()) { + for (const [index, rec] of pdfRecipients.entries()) { let data = this.buildData(newsletter, dates, rec, printWithAdress.includes(rec.sendNewsletter?.type?.id)); await PdfExport.renderFile({ template: "newsletter", title: `Newsletter von ${CLUB_NAME}`, - filename: `${rec.lastname}_${rec.firstname}_${rec.id}`, - folder: `newsletter/${newsletter.id}_${newsletter.title.replace(" ", "")}`, + filename: `${rec.lastname}_${rec.firstname}_${rec.id}`.replaceAll(" ", "-"), + folder: `newsletter/${newsletter.id}_${newsletter.title.replaceAll(" ", "")}`, data: data, }) .then(() => { @@ -294,9 +319,9 @@ export abstract class NewsletterHelper { } await PdfExport.sqashToSingleFile( - `newsletter/${newsletter.id}_${newsletter.title.replace(" ", "")}`, + `newsletter/${newsletter.id}_${newsletter.title.replaceAll(" ", "")}`, "allPdfsTogether", - `newsletter/${newsletter.id}_${newsletter.title.replace(" ", "")}` + `newsletter/${newsletter.id}_${newsletter.title.replaceAll(" ", "")}` ) .then(() => { this.formatJobEmit( diff --git a/src/helpers/pdfExport.ts b/src/helpers/pdfExport.ts index e59ba54..429f551 100644 --- a/src/helpers/pdfExport.ts +++ b/src/helpers/pdfExport.ts @@ -1,10 +1,47 @@ -import puppeteer from "puppeteer"; +import puppeteer, { Browser } from "puppeteer"; import { TemplateHelper } from "./templateHelper"; import { PermissionModule } from "../type/permissionTypes"; import { FileSystemHelper } from "./fileSystemHelper"; import { PDFDocument } from "pdf-lib"; +import { StringHelper } from "./stringHelper"; export abstract class PdfExport { + private static browserInstance: undefined | Browser = undefined; + private static timeout: undefined | NodeJS.Timeout = undefined; + private static printing = new Map(); + + private static async renderTemplate( + template: `${PermissionModule}` | `${PermissionModule}.${string}`, + title: string, + data: any, + customTemplate?: { + headerId?: number; + footerId?: number; + bodyId?: string | number; + headerHeight: number; + footerHeight: number; + } + ): Promise<{ header: string; footer: string; body: string; headerMargin?: number; footerMargin?: number }> { + if (!customTemplate) { + return await TemplateHelper.renderFileForModule({ + module: template, + headerData: data, + bodyData: data, + footerData: data, + title: title, + }); + } else { + return await TemplateHelper.renderFileForCustom({ + module: template, + customTemplate, + headerData: data, + bodyData: data, + footerData: data, + title: title, + }); + } + } + static async renderFile({ template, title = "pdf-export FF Admin", @@ -28,33 +65,25 @@ export abstract class PdfExport { footerHeight: number; }; }) { + try { + clearTimeout(this.timeout); + } catch (err) {} + let id = StringHelper.random(32); + this.printing.set(id, "printing"); + if (folder != "") FileSystemHelper.createFolder(folder); - let header: string, footer: string, body: string, headerMargin: number, footerMargin: number; - if (!customTemplate) { - ({ header, footer, body, headerMargin, footerMargin } = await TemplateHelper.renderFileForModule({ - module: template, - headerData: data, - bodyData: data, - footerData: data, - title: title, - })); - } else { - ({ header, footer, body, headerMargin, footerMargin } = await TemplateHelper.renderFileForCustom({ - module: template, - customTemplate, - headerData: data, - bodyData: data, - footerData: data, - title: title, - })); + const renderedTemplate = await this.renderTemplate(template, title, data, customTemplate); + let { header, footer, body, headerMargin, footerMargin } = renderedTemplate; + + if (!this.browserInstance || !this.browserInstance.connected) { + this.browserInstance = await puppeteer.launch({ + headless: true, + args: ["--no-sandbox", "--disable-gpu", "--disable-setuid-sandbox"], + }); } - const browser = await puppeteer.launch({ - headless: true, - args: ["--no-sandbox", "--disable-gpu", "--disable-setuid-sandbox"], - }); - const page = await browser.newPage(); + const page = await this.browserInstance.newPage(); await page.setContent(body, { waitUntil: "domcontentloaded" }); const exportPath = FileSystemHelper.formatPath(folder, `${filename}.pdf`); @@ -74,7 +103,16 @@ export abstract class PdfExport { footerTemplate: footer, }); - await browser.close(); + await page.close(); + + this.printing.delete(id); + + if (this.printing.size == 0) { + this.timeout = setTimeout(() => { + this.browserInstance.close(); + this.browserInstance = undefined; + }, 5000); + } return pdf; } diff --git a/src/helpers/permissionHelper.ts b/src/helpers/permissionHelper.ts index 86b27e2..6a83f92 100644 --- a/src/helpers/permissionHelper.ts +++ b/src/helpers/permissionHelper.ts @@ -4,9 +4,11 @@ import { permissionModules, PermissionObject, PermissionSection, + permissionSections, PermissionString, PermissionType, permissionTypes, + sectionsAndModules, } from "../type/permissionTypes"; import ForbiddenRequestException from "../exceptions/forbiddenRequestException"; @@ -17,8 +19,8 @@ export default class PermissionHelper { section: PermissionSection, module?: PermissionModule ) { - 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 && @@ -50,8 +52,8 @@ export default class PermissionHelper { type: PermissionType | "admin", section: PermissionSection ): boolean { - 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) || @@ -73,6 +75,11 @@ export default class PermissionHelper { }, false); } + static canValue(permissions: PermissionObject, key: string, emptyIfAdmin: boolean = false): string { + if (emptyIfAdmin && (permissions.admin || permissions.adminByOwner)) return ""; + return permissions?.additional?.[key] ?? ""; + } + static passCheckMiddleware( requiredPermissions: PermissionType | "admin", section: PermissionSection, @@ -159,14 +166,28 @@ export default class PermissionHelper { }; } - static convertToObject(permissions: Array): PermissionObject { - if (permissions.includes("*")) { + static convertToObject(permissions: Array, isOwner: boolean = false): PermissionObject { + let isAdmin = permissions.includes("*"); + + let additional: { [key: string]: string } = {}; + let additionalPermissions = permissions.map((e) => e.split(".")).filter((e) => e[0] == "additional") as Array< + ["additional", string, string] + >; + for (let split of additionalPermissions) { + let module = sectionsAndModules.additional.find((a) => a.key == split[1]); + if (!isAdmin || (isAdmin && !module.emptyIfAdmin)) additional[split[1]] = split[2]; + } + + if (isAdmin) { return { admin: true, + adminByOwner: isOwner, + ...(Object.keys(additional).length > 0 && { additional }), }; } + let output: PermissionObject = {}; - let splitPermissions = permissions.map((e) => e.split(".")) as Array< + let splitPermissions = permissions.map((e) => e.split(".")).filter((e) => e[0] != "additional") as Array< [PermissionSection, PermissionModule | PermissionType | "*", PermissionType | "*"] >; for (let split of splitPermissions) { @@ -208,15 +229,31 @@ export default class PermissionHelper { } } } - return output; + + return { + adminByOwner: isOwner, + ...output, + ...(Object.keys(additional).length > 0 && { additional }), + }; } static convertToStringArray(permissions: PermissionObject): Array { - if (permissions?.admin) { - return ["*"]; + let isAdmin = permissions?.admin; + + let additional: Array = []; + let additionalPermissions = Object.entries(permissions?.additional ?? {}); + for (let add of additionalPermissions) { + additional.push(`additional.${add[0]}.${add[1]}`); } + + if (isAdmin) { + return ["*", ...additional]; + } + let output: Array = []; - let sections = Object.keys(permissions) as Array; + let sections = Object.keys(permissions).filter((m: PermissionSection) => + permissionSections.includes(m) + ) as Array; for (let section of sections) { if (permissions[section].all) { let types = permissions[section].all; @@ -242,7 +279,8 @@ export default class PermissionHelper { } } } - return output; + + return [...output, ...additional]; } static getWhatToAdd(before: Array, after: Array): Array { diff --git a/src/helpers/templateHelper.ts b/src/helpers/templateHelper.ts index b8d97f1..3dc5ad8 100644 --- a/src/helpers/templateHelper.ts +++ b/src/helpers/templateHelper.ts @@ -11,7 +11,9 @@ export abstract class TemplateHelper { try { tmpFile = FileSystemHelper.readTemplateFile(`/src/templates/${template}.template.html`); } catch (err) { - tmpFile = FileSystemHelper.readTemplateFile(`/src/templates/${template.split(".")[1]}.template.html`); + tmpFile = FileSystemHelper.readTemplateFile( + `/src/templates/${template.split(".")[template.split(".").length - 1]}.template.html` + ); } return tmpFile; } @@ -27,9 +29,9 @@ export abstract class TemplateHelper { } static normalizeTemplate(template: string): string { - template = template.replace(/.*?<\/listend>/g, "{{/each}}"); - template = template.replace(/]*>(WDH Start: )?/g, "{{#each "); - template = template.replace(/<\/liststart>/g, "}}"); + template = template.replaceAll(/.*?<\/listend>/g, "{{/each}}"); + template = template.replaceAll(/]*>(WDH Start: )?/g, "{{#each "); + template = template.replaceAll(/<\/liststart>/g, "}}"); return template; } diff --git a/src/routes/admin/club/newsletter.ts b/src/routes/admin/club/newsletter.ts index 9a71bbf..5ec1aba 100644 --- a/src/routes/admin/club/newsletter.ts +++ b/src/routes/admin/club/newsletter.ts @@ -16,6 +16,8 @@ import { createNewsletterPrintoutPreviewById, getNewsletterPrintoutProgressById, getNewsletterSendingProgressById, + getNewsletterMailReceiversById, + getNewsletterPrintReceiversById, } from "../../../controller/admin/club/newsletterController"; import PermissionHelper from "../../../helpers/permissionHelper"; @@ -57,6 +59,14 @@ router.get("/:newsletterId/sendprogress", async (req: Request, res: Response) => await getNewsletterSendingProgressById(req, res); }); +router.get("/:newsletterId/printrecipients", async (req: Request, res: Response) => { + await getNewsletterPrintReceiversById(req, res); +}); + +router.get("/:newsletterId/mailrecipients", async (req: Request, res: Response) => { + await getNewsletterMailReceiversById(req, res); +}); + router.post( "/", PermissionHelper.passCheckMiddleware("create", "club", "protocol"), diff --git a/src/type/permissionTypes.ts b/src/type/permissionTypes.ts index e9ed138..1061d49 100644 --- a/src/type/permissionTypes.ts +++ b/src/type/permissionTypes.ts @@ -30,6 +30,7 @@ export type PermissionString = | `${PermissionSection}.${PermissionModule}.*` // für alle Berechtigungen in einem Modul | `${PermissionSection}.${PermissionType}` // für spezifische Berechtigungen in einem Abschnitt | `${PermissionSection}.*` // für alle Berechtigungen in einem Abschnitt + | `additional.${string}.${string}` // additional | "*"; // für Admin export type PermissionObject = { @@ -38,10 +39,20 @@ export type PermissionObject = { } & { all?: Array | "*" }; } & { admin?: boolean; + adminByOwner?: boolean; +} & { + additional?: { [key: string]: string }; }; export type SectionsAndModulesObject = { [section in PermissionSection]: Array; +} & { + additional?: Array<{ + key: string; + name: string; + type: "number" | "string"; + emptyIfAdmin: boolean; + }>; }; export const permissionSections: Array = ["club", "configuration", "management"]; @@ -85,4 +96,5 @@ export const sectionsAndModules: SectionsAndModulesObject = { "newsletter_config", ], management: ["user", "role", "webapi", "backup"], + additional: [], };