From b1e949dce27b991ea360e0de3fa73a90abd910e6 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Sat, 11 Jan 2025 14:45:37 +0100 Subject: [PATCH 1/9] enhance: detect requests of pwa --- src/index.ts | 1 + src/middleware/detectPWA.ts | 11 +++++++++++ src/routes/index.ts | 2 ++ 3 files changed, 14 insertions(+) create mode 100644 src/middleware/detectPWA.ts diff --git a/src/index.ts b/src/index.ts index a1d7178..f5a73e6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,6 +12,7 @@ declare global { username: string; isOwner: boolean; permissions: PermissionObject; + isPWA: boolean; } } } diff --git a/src/middleware/detectPWA.ts b/src/middleware/detectPWA.ts new file mode 100644 index 0000000..d30df95 --- /dev/null +++ b/src/middleware/detectPWA.ts @@ -0,0 +1,11 @@ +import { Request, Response } from "express"; + +export default async function detectPWA(req: Request, res: Response, next: Function) { + const userAgent = req.headers["user-agent"] || ""; + if ((userAgent.includes("Mobile") && userAgent.includes("Standalone")) || req.headers["x-pwa-client"] === "true") { + req.isPWA = true; + } else { + req.isPWA = false; + } + next(); +} diff --git a/src/routes/index.ts b/src/routes/index.ts index 72cb526..b939d52 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -13,6 +13,7 @@ import reset from "./reset"; import auth from "./auth"; import admin from "./admin/index"; import user from "./user"; +import detectPWA from "../middleware/detectPWA"; export default (app: Express) => { app.set("query parser", "extended"); @@ -25,6 +26,7 @@ export default (app: Express) => { app.use(cors()); app.options("*", cors()); + app.use(detectPWA); app.use("/api/public", publicAvailable); app.use("/api/setup", allowSetup, setup); app.use("/api/reset", reset); From 916a6da4a034a10b24eb60caef89608bd6607228 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Sun, 12 Jan 2025 11:41:02 +0100 Subject: [PATCH 2/9] enhance: allow extended refresh duration to PWAs --- .env.example | 1 + README.md | 13 +++++++------ src/command/refreshCommand.ts | 1 + src/command/refreshCommandHandler.ts | 12 ++++-------- src/controller/authController.ts | 5 ++--- src/env.defaults.ts | 2 ++ 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.env.example b/.env.example index 7d63ce3..28b487d 100644 --- a/.env.example +++ b/.env.example @@ -10,6 +10,7 @@ SERVER_PORT = portnumber JWT_SECRET = ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 JWT_EXPIRATION = [0-9]*(y|d|h|m|s) REFRESH_EXPIRATION = [0-9]*(y|d|h|m|s) +PWA_REFRESH_EXPIRATION = [0-9]*(y|d|h|m|s) MAIL_USERNAME = mail_username MAIL_PASSWORD = mail_password diff --git a/README.md b/README.md index 713f57a..4896a21 100644 --- a/README.md +++ b/README.md @@ -25,20 +25,21 @@ services: container_name: ff_member_administration_server restart: unless-stopped environment: - - DB_TYPE=mysql + - DB_TYPE= # default ist auf mysql gesetzt - DB_HOST=ffm-db - - DB_PORT= # fallback ist auf 3306 gesetzt + - DB_PORT= # default ist auf 3306 gesetzt - DB_NAME=ffadmin - DB_USERNAME=administration_backend - DB_PASSWORD= - JWT_SECRET= - - JWT_EXPIRATION= - - REFRESH_EXPIRATION= + - JWT_EXPIRATION= # default ist auf 15m gesetzt + - REFRESH_EXPIRATION= # default ist auf 1d gesetzt + - PWA_REFRESH_EXPIRATION= # default ist auf 5d gesetzt - MAIL_USERNAME= - MAIL_PASSWORD= - MAIL_HOST= - - MAIL_PORT= - - MAIL_SECURE= + - MAIL_PORT= # default ist auf 578 gesetzt + - MAIL_SECURE= # default ist auf false gesetzt - CLUB_NAME= - CLUB_WEBSITE= volumes: diff --git a/src/command/refreshCommand.ts b/src/command/refreshCommand.ts index e0404c8..80b14cc 100644 --- a/src/command/refreshCommand.ts +++ b/src/command/refreshCommand.ts @@ -1,5 +1,6 @@ export interface CreateRefreshCommand { userId: number; + isFromPwa?: boolean; } export interface DeleteRefreshCommand { diff --git a/src/command/refreshCommandHandler.ts b/src/command/refreshCommandHandler.ts index 86841ad..709f51b 100644 --- a/src/command/refreshCommandHandler.ts +++ b/src/command/refreshCommandHandler.ts @@ -1,11 +1,9 @@ import { dataSource } from "../data-source"; import { refresh } from "../entity/refresh"; -import { REFRESH_EXPIRATION } from "../env.defaults"; +import { PWA_REFRESH_EXPIRATION, REFRESH_EXPIRATION } from "../env.defaults"; import InternalException from "../exceptions/internalException"; -import { JWTHelper } from "../helpers/jwtHelper"; import { StringHelper } from "../helpers/stringHelper"; import UserService from "../service/user/userService"; -import { JWTRefresh } from "../type/jwtTypes"; import { CreateRefreshCommand, DeleteRefreshCommand } from "./refreshCommand"; import ms from "ms"; @@ -16,10 +14,6 @@ export default abstract class RefreshCommandHandler { * @returns {Promise} */ static async create(createRefresh: CreateRefreshCommand): Promise { - // let createRefreshToken: JWTRefresh = { - // userId: createRefresh.userId, - // }; - // const refreshToken = await JWTHelper.create(createRefreshToken); const refreshToken = StringHelper.random(32); return await dataSource @@ -29,7 +23,9 @@ export default abstract class RefreshCommandHandler { .values({ token: refreshToken, user: await UserService.getById(createRefresh.userId), - expiry: new Date(Date.now() + ms(REFRESH_EXPIRATION)), + expiry: createRefresh.isFromPwa + ? new Date(Date.now() + ms(PWA_REFRESH_EXPIRATION)) + : new Date(Date.now() + ms(REFRESH_EXPIRATION)), }) .execute() .then((result) => { diff --git a/src/controller/authController.ts b/src/controller/authController.ts index dd4fee7..e3f5af2 100644 --- a/src/controller/authController.ts +++ b/src/controller/authController.ts @@ -8,9 +8,6 @@ import UserService from "../service/user/userService"; import speakeasy from "speakeasy"; import UnauthorizedRequestException from "../exceptions/unauthorizedRequestException"; import RefreshService from "../service/refreshService"; -import UserPermissionService from "../service/user/userPermissionService"; -import PermissionHelper from "../helpers/permissionHelper"; -import RolePermissionService from "../service/user/rolePermissionService"; /** * @description Check authentication status by token @@ -39,6 +36,7 @@ export async function login(req: Request, res: Response): Promise { let refreshCommand: CreateRefreshCommand = { userId: id, + isFromPwa: req.isPWA, }; let refreshToken = await RefreshCommandHandler.create(refreshCommand); @@ -83,6 +81,7 @@ export async function refresh(req: Request, res: Response): Promise { let refreshCommand: CreateRefreshCommand = { userId: tokenUserId, + isFromPwa: req.isPWA, }; let refreshToken = await RefreshCommandHandler.create(refreshCommand); diff --git a/src/env.defaults.ts b/src/env.defaults.ts index a662555..159845b 100644 --- a/src/env.defaults.ts +++ b/src/env.defaults.ts @@ -13,6 +13,7 @@ export const SERVER_PORT = Number(process.env.SERVER_PORT ?? 5000); export const JWT_SECRET = process.env.JWT_SECRET ?? "my_jwt_secret_string_ilughfnadiuhgq§$IUZGFVRweiouarbt1oub3h5q4a"; export const JWT_EXPIRATION = process.env.JWT_EXPIRATION ?? "15m"; export const REFRESH_EXPIRATION = process.env.REFRESH_EXPIRATION ?? "1d"; +export const PWA_REFRESH_EXPIRATION = process.env.PWA_REFRESH_EXPIRATION ?? "5d"; export const MAIL_USERNAME = process.env.MAIL_USERNAME ?? ""; export const MAIL_PASSWORD = process.env.MAIL_PASSWORD ?? ""; @@ -35,6 +36,7 @@ export function configCheck() { if (JWT_SECRET == "" || typeof JWT_SECRET != "string") throw new Error("set valid value to JWT_SECRET"); checkMS(JWT_EXPIRATION, "JWT_EXPIRATION"); checkMS(REFRESH_EXPIRATION, "REFRESH_EXPIRATION"); + checkMS(PWA_REFRESH_EXPIRATION, "PWA_REFRESH_EXPIRATION"); if (MAIL_USERNAME == "" || typeof MAIL_USERNAME != "string") throw new Error("set valid value to MAIL_USERNAME"); if (MAIL_PASSWORD == "" || typeof MAIL_PASSWORD != "string") throw new Error("set valid value to MAIL_PASSWORD"); From e1f6b363368e0f78195e063a6edef3d5785c65d9 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Sun, 12 Jan 2025 11:41:22 +0100 Subject: [PATCH 3/9] change: removed dev logging --- src/command/club/member/memberCommandHandler.ts | 1 - src/env.defaults.ts | 1 - src/helpers/newsletterHelper.ts | 5 ----- src/migrations/1735822722235-internalId.ts | 2 -- 4 files changed, 9 deletions(-) diff --git a/src/command/club/member/memberCommandHandler.ts b/src/command/club/member/memberCommandHandler.ts index 8d8e65b..d0fd59a 100644 --- a/src/command/club/member/memberCommandHandler.ts +++ b/src/command/club/member/memberCommandHandler.ts @@ -43,7 +43,6 @@ export default abstract class MemberCommandHandler { * @returns {Promise} */ static async update(updateMember: UpdateMemberCommand): Promise { - console.log(updateMember); return await dataSource .createQueryBuilder() .update(member) diff --git a/src/env.defaults.ts b/src/env.defaults.ts index 159845b..33fe53a 100644 --- a/src/env.defaults.ts +++ b/src/env.defaults.ts @@ -44,7 +44,6 @@ export function configCheck() { if (typeof MAIL_PORT != "number") throw new Error("set valid numeric value to MAIL_PORT"); if (MAIL_SECURE != "true" && MAIL_SECURE != "false") throw new Error("set 'true' or 'false' to MAIL_SECURE"); - console.log(CLUB_WEBSITE); if ( CLUB_WEBSITE != "" && !/^(http(s):\/\/.)[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/.test(CLUB_WEBSITE) diff --git a/src/helpers/newsletterHelper.ts b/src/helpers/newsletterHelper.ts index 458f854..b9215c7 100644 --- a/src/helpers/newsletterHelper.ts +++ b/src/helpers/newsletterHelper.ts @@ -132,8 +132,6 @@ export abstract class NewsletterHelper { } } - console.log(queryMemberIds); - let members = await MemberService.getAll(0, 1000); return members[0].filter((m) => queryMemberIds.includes(m.id)); @@ -212,7 +210,6 @@ export abstract class NewsletterHelper { index, `failed to send to ${rec.sendNewsletter.email}` ); - console.log("mail send", err); }); } @@ -292,7 +289,6 @@ export abstract class NewsletterHelper { index, `failed print for ${rec.lastname}, ${rec.firstname}` ); - console.log("pdf print", err); }); } @@ -329,7 +325,6 @@ export abstract class NewsletterHelper { pdfRecipients.length, "failed combining pdf" ); - console.log("pdf squash", err); }); this.formatJobEmit( diff --git a/src/migrations/1735822722235-internalId.ts b/src/migrations/1735822722235-internalId.ts index 9468b61..40aacca 100644 --- a/src/migrations/1735822722235-internalId.ts +++ b/src/migrations/1735822722235-internalId.ts @@ -19,7 +19,6 @@ export class InternalId1735822722235 implements MigrationInterface { ); // let memberships = await queryRunner.manager.getRepository(membership).find(); - // console.log(memberships); // let internalIds = memberships.reduce<{ [key: number]: Array }>((acc, cur) => { // let memberId = cur.memberId; // let setIds = acc[memberId] ?? []; @@ -30,7 +29,6 @@ export class InternalId1735822722235 implements MigrationInterface { // return acc; // }, {}); - // console.log(internalIds); // for (const [id, value] of Object.entries(internalIds)) { // const ids = value.filter((v) => v != null).join(", "); // if (ids) { From 1c6c123142ece31a26b11965f93b0217c62e80ee Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Sun, 12 Jan 2025 13:21:34 +0100 Subject: [PATCH 4/9] fix: stream newsletter progress to client --- .../admin/club/newsletterController.ts | 27 +++---- src/helpers/newsletterHelper.ts | 74 ++++++++----------- 2 files changed, 46 insertions(+), 55 deletions(-) diff --git a/src/controller/admin/club/newsletterController.ts b/src/controller/admin/club/newsletterController.ts index 7c322e9..10699a0 100644 --- a/src/controller/admin/club/newsletterController.ts +++ b/src/controller/admin/club/newsletterController.ts @@ -6,7 +6,10 @@ import NewsletterDatesFactory from "../../../factory/admin/club/newsletter/newsl import NewsletterRecipientsService from "../../../service/club/newsletter/newsletterRecipientsService"; import NewsletterRecipientsFactory from "../../../factory/admin/club/newsletter/newsletterRecipients"; import { FileSystemHelper } from "../../../helpers/fileSystemHelper"; -import { CreateNewsletterCommand, SynchronizeNewsletterCommand } from "../../../command/club/newsletter/newsletterCommand"; +import { + CreateNewsletterCommand, + SynchronizeNewsletterCommand, +} from "../../../command/club/newsletter/newsletterCommand"; import NewsletterCommandHandler from "../../../command/club/newsletter/newsletterCommandHandler"; import { SynchronizeNewsletterDatesCommand } from "../../../command/club/newsletter/newsletterDatesCommand"; import NewsletterDatesCommandHandler from "../../../command/club/newsletter/newsletterDatesCommandHandler"; @@ -188,15 +191,14 @@ export async function createNewsletter(req: Request, res: Response): Promise { let newsletterId = parseInt(req.params.newsletterId); - res.setHeader("Content-Type", "text/event-stream"); - res.setHeader("Cache-Control", "no-cache"); - res.setHeader("Connection", "keep-alive"); - - res.flushHeaders(); + res.writeHead(200, { + "Content-Type": "text/plain", + "Transfer-Encoding": "chunked", + }); const progressHandler = (data: NewsletterEventType) => { if (data.newsletterId == newsletterId && data.kind == "pdf") { - res.write(JSON.stringify(data)); + res.write(JSON.stringify(data) + "//"); } }; @@ -287,15 +289,14 @@ export async function sendNewsletterById(req: Request, res: Response): Promise { let newsletterId = parseInt(req.params.newsletterId); - res.setHeader("Content-Type", "text/event-stream"); - res.setHeader("Cache-Control", "no-cache"); - res.setHeader("Connection", "keep-alive"); - - res.flushHeaders(); + res.writeHead(200, { + "Content-Type": "text/plain", + "Transfer-Encoding": "chunked", + }); const progressHandler = (data: NewsletterEventType) => { if (data.newsletterId == newsletterId && data.kind == "mail") { - res.write(JSON.stringify(data)); + res.write(JSON.stringify(data) + "//"); } }; diff --git a/src/helpers/newsletterHelper.ts b/src/helpers/newsletterHelper.ts index b9215c7..eed0fc5 100644 --- a/src/helpers/newsletterHelper.ts +++ b/src/helpers/newsletterHelper.ts @@ -33,12 +33,21 @@ export abstract class NewsletterHelper { private static formatJobEmit( event: "progress" | "complete", kind: "pdf" | "mail", + factor: "success" | "failed" | "info", newsletterId: number, total: number, iteration: number, msg: string ) { - this.jobStatus.emit(event, { kind, newsletterId, total, iteration, msg, date: new Date() }); + this.jobStatus.emit(event, { + kind, + newsletterId, + factor, + total, + iteration, + msg, + date: new Date(), + }); } public static buildData( @@ -169,18 +178,9 @@ export abstract class NewsletterHelper { allowedForMail.includes(m.sendNewsletter?.type?.id) ); - this.formatJobEmit("progress", "mail", newsletterId, mailRecipients.length, 0, "starting sending"); + this.formatJobEmit("progress", "mail", "info", newsletterId, mailRecipients.length, 0, "starting sending"); for (const [index, rec] of mailRecipients.entries()) { - this.formatJobEmit( - "progress", - "mail", - newsletterId, - mailRecipients.length, - index, - `start sending to ${rec.sendNewsletter.email}` - ); - let data = this.buildData(newsletter, dates, rec); const { body } = await TemplateHelper.renderFileForModule({ @@ -195,9 +195,10 @@ export abstract class NewsletterHelper { this.formatJobEmit( "progress", "mail", + "success", newsletterId, mailRecipients.length, - index, + index + 1, `successfully sent to ${rec.sendNewsletter.email}` ); }) @@ -205,9 +206,10 @@ export abstract class NewsletterHelper { this.formatJobEmit( "progress", "mail", + "failed", newsletterId, mailRecipients.length, - index, + index + 1, `failed to send to ${rec.sendNewsletter.email}` ); }); @@ -216,6 +218,7 @@ export abstract class NewsletterHelper { this.formatJobEmit( "complete", "mail", + "info", newsletterId, mailRecipients.length, mailRecipients.length, @@ -246,21 +249,12 @@ export abstract class NewsletterHelper { (m) => !notAllowedForPdf.includes(m.sendNewsletter?.type?.id) || m.sendNewsletter == null ); - this.formatJobEmit("progress", "pdf", newsletterId, pdfRecipients.length, 0, "starting sending"); + this.formatJobEmit("progress", "pdf", "info", newsletterId, pdfRecipients.length + 1, 0, "starting sending"); for (const [index, rec] of [ ...pdfRecipients, { id: 0, firstname: "Alle Mitglieder", lastname: CLUB_NAME } as member, ].entries()) { - this.formatJobEmit( - "progress", - "pdf", - newsletterId, - pdfRecipients.length, - index, - `start print for ${rec.lastname}, ${rec.firstname}` - ); - let data = this.buildData(newsletter, dates, rec, printWithAdress.includes(rec.sendNewsletter?.type?.id)); await PdfExport.renderFile({ @@ -274,9 +268,10 @@ export abstract class NewsletterHelper { this.formatJobEmit( "progress", "pdf", + "success", newsletterId, - pdfRecipients.length, - index, + pdfRecipients.length + 1, + index + 1, `successfully printed for ${rec.lastname}, ${rec.firstname}` ); }) @@ -284,23 +279,15 @@ export abstract class NewsletterHelper { this.formatJobEmit( "progress", "pdf", + "failed", newsletterId, - pdfRecipients.length, - index, + pdfRecipients.length + 1, + index + 1, `failed print for ${rec.lastname}, ${rec.firstname}` ); }); } - this.formatJobEmit( - "progress", - "pdf", - newsletterId, - pdfRecipients.length, - pdfRecipients.length, - "starting pdf combine" - ); - await PdfExport.sqashToSingleFile( `newsletter/${newsletter.id}_${newsletter.title.replace(" ", "")}`, "allPdfsTogether", @@ -310,9 +297,10 @@ export abstract class NewsletterHelper { this.formatJobEmit( "progress", "pdf", + "success", newsletterId, - pdfRecipients.length, - pdfRecipients.length, + pdfRecipients.length + 1, + pdfRecipients.length + 1, "sucessfully combined pdf" ); }) @@ -320,9 +308,10 @@ export abstract class NewsletterHelper { this.formatJobEmit( "progress", "pdf", + "failed", newsletterId, - pdfRecipients.length, - pdfRecipients.length, + pdfRecipients.length + 1, + pdfRecipients.length + 1, "failed combining pdf" ); }); @@ -330,9 +319,10 @@ export abstract class NewsletterHelper { this.formatJobEmit( "complete", "pdf", + "info", newsletterId, - pdfRecipients.length, - pdfRecipients.length, + pdfRecipients.length + 1, + pdfRecipients.length + 1, `completed printing process` ); } From 03036c8b77cc82e3dc90009adead1726a5421f31 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Sun, 12 Jan 2025 18:17:54 +0100 Subject: [PATCH 5/9] add: sort data --- src/service/club/calendarService.ts | 1 + src/service/club/member/communicationService.ts | 1 + src/service/club/member/memberAwardService.ts | 1 + src/service/club/member/memberExecutivePositionService.ts | 2 ++ src/service/club/member/memberQualificationService.ts | 1 + src/service/settings/awardService.ts | 1 + src/service/settings/calendarTypeService.ts | 1 + src/service/settings/communicationTypeService.ts | 1 + src/service/settings/executivePositionService.ts | 1 + src/service/settings/membershipStatusService.ts | 1 + src/service/settings/newsletterConfigService.ts | 1 + src/service/settings/qualification.ts | 1 + src/service/settings/queryStoreService.ts | 1 + src/service/settings/templateService.ts | 1 + src/service/settings/templateUsageService.ts | 1 + src/service/user/roleService.ts | 1 + src/service/user/userService.ts | 2 ++ 17 files changed, 19 insertions(+) diff --git a/src/service/club/calendarService.ts b/src/service/club/calendarService.ts index 0714cd3..e1186a1 100644 --- a/src/service/club/calendarService.ts +++ b/src/service/club/calendarService.ts @@ -12,6 +12,7 @@ export default abstract class CalendarService { .getRepository(calendar) .createQueryBuilder("calendar") .leftJoinAndSelect("calendar.type", "type") + .orderBy("starttime", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/club/member/communicationService.ts b/src/service/club/member/communicationService.ts index f0c2f04..5ca7bdd 100644 --- a/src/service/club/member/communicationService.ts +++ b/src/service/club/member/communicationService.ts @@ -16,6 +16,7 @@ export default abstract class CommunicationService { .leftJoinAndSelect("communication.member", "member") .leftJoinAndSelect("member.sendNewsletter", "sendNewsletter") .where("communication.memberId = :memberId", { memberId: memberId }) + .orderBy("communicationType.type", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/club/member/memberAwardService.ts b/src/service/club/member/memberAwardService.ts index 16ed55c..db69f06 100644 --- a/src/service/club/member/memberAwardService.ts +++ b/src/service/club/member/memberAwardService.ts @@ -14,6 +14,7 @@ export default abstract class MemberAwardService { .createQueryBuilder("memberAwards") .leftJoinAndSelect("memberAwards.award", "award") .where("memberAwards.memberId = :memberId", { memberId: memberId }) + .orderBy("award.award", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/club/member/memberExecutivePositionService.ts b/src/service/club/member/memberExecutivePositionService.ts index 89cf23c..ff15ba0 100644 --- a/src/service/club/member/memberExecutivePositionService.ts +++ b/src/service/club/member/memberExecutivePositionService.ts @@ -14,6 +14,8 @@ export default abstract class MemberExecutivePositionService { .createQueryBuilder("memberExecutivePositions") .leftJoinAndSelect("memberExecutivePositions.executivePosition", "executivePosition") .where("memberExecutivePositions.memberId = :memberId", { memberId: memberId }) + .orderBy("executivePosition.position", "ASC") + .addOrderBy("memberExecutivePositions.start", "DESC") .getMany() .then((res) => { return res; diff --git a/src/service/club/member/memberQualificationService.ts b/src/service/club/member/memberQualificationService.ts index 9685c19..84c6a5f 100644 --- a/src/service/club/member/memberQualificationService.ts +++ b/src/service/club/member/memberQualificationService.ts @@ -14,6 +14,7 @@ export default abstract class MemberQualificationService { .createQueryBuilder("memberQualifications") .leftJoinAndSelect("memberQualifications.qualification", "qualification") .where("memberQualifications.memberId = :memberId", { memberId: memberId }) + .orderBy("qualification.qualification", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/settings/awardService.ts b/src/service/settings/awardService.ts index 414ea01..57872da 100644 --- a/src/service/settings/awardService.ts +++ b/src/service/settings/awardService.ts @@ -12,6 +12,7 @@ export default abstract class AwardService { return await dataSource .getRepository(award) .createQueryBuilder("award") + .orderBy("award", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/settings/calendarTypeService.ts b/src/service/settings/calendarTypeService.ts index 0bbc5bb..1fb3f34 100644 --- a/src/service/settings/calendarTypeService.ts +++ b/src/service/settings/calendarTypeService.ts @@ -11,6 +11,7 @@ export default abstract class CalendarTypeService { return await dataSource .getRepository(calendarType) .createQueryBuilder("calendarType") + .orderBy("type", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/settings/communicationTypeService.ts b/src/service/settings/communicationTypeService.ts index cecc1fc..74494b1 100644 --- a/src/service/settings/communicationTypeService.ts +++ b/src/service/settings/communicationTypeService.ts @@ -11,6 +11,7 @@ export default abstract class CommunicationTypeService { return await dataSource .getRepository(communicationType) .createQueryBuilder("communicationType") + .orderBy("type", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/settings/executivePositionService.ts b/src/service/settings/executivePositionService.ts index e69e96f..cf2b105 100644 --- a/src/service/settings/executivePositionService.ts +++ b/src/service/settings/executivePositionService.ts @@ -12,6 +12,7 @@ export default abstract class ExecutivePositionService { return await dataSource .getRepository(executivePosition) .createQueryBuilder("executivePosition") + .orderBy("position", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/settings/membershipStatusService.ts b/src/service/settings/membershipStatusService.ts index 23269f1..b1e94f1 100644 --- a/src/service/settings/membershipStatusService.ts +++ b/src/service/settings/membershipStatusService.ts @@ -12,6 +12,7 @@ export default abstract class MembershipStatusService { return await dataSource .getRepository(membershipStatus) .createQueryBuilder("membershipStatus") + .orderBy("status", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/settings/newsletterConfigService.ts b/src/service/settings/newsletterConfigService.ts index 5ef66a3..984fbb2 100644 --- a/src/service/settings/newsletterConfigService.ts +++ b/src/service/settings/newsletterConfigService.ts @@ -13,6 +13,7 @@ export default abstract class NewsletterConfigService { .getRepository(newsletterConfig) .createQueryBuilder("newsletterConfig") .leftJoinAndSelect("newsletterConfig.comType", "comType") + .orderBy("comType.type", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/settings/qualification.ts b/src/service/settings/qualification.ts index 585d1ae..f400576 100644 --- a/src/service/settings/qualification.ts +++ b/src/service/settings/qualification.ts @@ -13,6 +13,7 @@ export default abstract class QualificationService { return await dataSource .getRepository(qualification) .createQueryBuilder("qualification") + .orderBy("qualification", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/settings/queryStoreService.ts b/src/service/settings/queryStoreService.ts index 8dfbcf8..8ad5a52 100644 --- a/src/service/settings/queryStoreService.ts +++ b/src/service/settings/queryStoreService.ts @@ -11,6 +11,7 @@ export default abstract class QueryStoreService { return await dataSource .getRepository(query) .createQueryBuilder("queryStore") + .orderBy("title", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/settings/templateService.ts b/src/service/settings/templateService.ts index 4ace459..fb073f8 100644 --- a/src/service/settings/templateService.ts +++ b/src/service/settings/templateService.ts @@ -12,6 +12,7 @@ export default abstract class TemplateService { return await dataSource .getRepository(template) .createQueryBuilder("template") + .orderBy("template", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/settings/templateUsageService.ts b/src/service/settings/templateUsageService.ts index e944edc..a782d7b 100644 --- a/src/service/settings/templateUsageService.ts +++ b/src/service/settings/templateUsageService.ts @@ -14,6 +14,7 @@ export default abstract class TemplateUsageService { .leftJoinAndSelect("templateUsage.header", "headerTemplate") .leftJoinAndSelect("templateUsage.body", "bodyTemplate") .leftJoinAndSelect("templateUsage.footer", "footerTemplate") + .orderBy("scope", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/user/roleService.ts b/src/service/user/roleService.ts index 82cdaae..042c001 100644 --- a/src/service/user/roleService.ts +++ b/src/service/user/roleService.ts @@ -12,6 +12,7 @@ export default abstract class RoleService { .getRepository(role) .createQueryBuilder("role") .leftJoinAndSelect("role.permissions", "role_permissions") + .orderBy("role", "ASC") .getMany() .then((res) => { return res; diff --git a/src/service/user/userService.ts b/src/service/user/userService.ts index 2ff9ed1..45102a5 100644 --- a/src/service/user/userService.ts +++ b/src/service/user/userService.ts @@ -15,6 +15,8 @@ export default abstract class UserService { .leftJoinAndSelect("user.roles", "roles") .leftJoinAndSelect("user.permissions", "permissions") .leftJoinAndSelect("roles.permissions", "role_permissions") + .orderBy("firstname", "ASC") + .addOrderBy("lastname", "ASC") .getMany() .then((res) => { return res; From d206d7a77ca9ba38ef53ab2db8f98deff3fd81b9 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Mon, 13 Jan 2025 10:37:53 +0100 Subject: [PATCH 6/9] enhance: provide more details to command delete error --- src/command/settings/award/awardCommandHandler.ts | 5 ++++- .../settings/calendarType/calendarTypeCommandHandler.ts | 5 ++++- .../communicationType/communicationTypeCommandHandler.ts | 7 ++++++- .../executivePosition/executivePositionCommandHandler.ts | 7 ++++++- .../membershipStatus/membershipStatusCommandHandler.ts | 7 ++++++- .../settings/qualification/qualificationCommandHandler.ts | 5 ++++- .../settings/queryStore/queryStoreCommandHandler.ts | 5 ++++- src/command/settings/template/templateCommandHandler.ts | 5 ++++- 8 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/command/settings/award/awardCommandHandler.ts b/src/command/settings/award/awardCommandHandler.ts index af0000f..2a525a9 100644 --- a/src/command/settings/award/awardCommandHandler.ts +++ b/src/command/settings/award/awardCommandHandler.ts @@ -60,7 +60,10 @@ export default abstract class AwardCommandHandler { .execute() .then(() => {}) .catch((err) => { - throw new InternalException("Failed deleting award", err); + throw new InternalException( + `Failed deleting award ${err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : ""}`, + err + ); }); } } diff --git a/src/command/settings/calendarType/calendarTypeCommandHandler.ts b/src/command/settings/calendarType/calendarTypeCommandHandler.ts index bc20d6a..702728d 100644 --- a/src/command/settings/calendarType/calendarTypeCommandHandler.ts +++ b/src/command/settings/calendarType/calendarTypeCommandHandler.ts @@ -66,7 +66,10 @@ export default abstract class CalendarTypeCommandHandler { .execute() .then(() => {}) .catch((err) => { - throw new InternalException("Failed deleting calendarType", err); + throw new InternalException( + `Failed deleting calendarType${err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : ""}`, + err + ); }); } } diff --git a/src/command/settings/communicationType/communicationTypeCommandHandler.ts b/src/command/settings/communicationType/communicationTypeCommandHandler.ts index 04c7f10..df11e20 100644 --- a/src/command/settings/communicationType/communicationTypeCommandHandler.ts +++ b/src/command/settings/communicationType/communicationTypeCommandHandler.ts @@ -66,7 +66,12 @@ export default abstract class CommunicationTypeCommandHandler { .execute() .then(() => {}) .catch((err) => { - throw new InternalException("Failed deleting communicationType", err); + throw new InternalException( + `Failed deleting communicationType${ + err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : "" + }`, + err + ); }); } } diff --git a/src/command/settings/executivePosition/executivePositionCommandHandler.ts b/src/command/settings/executivePosition/executivePositionCommandHandler.ts index d1be38d..14a31a5 100644 --- a/src/command/settings/executivePosition/executivePositionCommandHandler.ts +++ b/src/command/settings/executivePosition/executivePositionCommandHandler.ts @@ -64,7 +64,12 @@ export default abstract class ExecutivePositionCommandHandler { .execute() .then(() => {}) .catch((err) => { - throw new InternalException("Failed deleting executivePosition", err); + throw new InternalException( + `Failed deleting executivePosition${ + err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : "" + }`, + err + ); }); } } diff --git a/src/command/settings/membershipStatus/membershipStatusCommandHandler.ts b/src/command/settings/membershipStatus/membershipStatusCommandHandler.ts index bc9f30f..7e5e953 100644 --- a/src/command/settings/membershipStatus/membershipStatusCommandHandler.ts +++ b/src/command/settings/membershipStatus/membershipStatusCommandHandler.ts @@ -64,7 +64,12 @@ export default abstract class MembershipStatusCommandHandler { .execute() .then(() => {}) .catch((err) => { - throw new InternalException("Failed deleting membershipStatus", err); + throw new InternalException( + `Failed deleting membershipStatus${ + err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : "" + }`, + err + ); }); } } diff --git a/src/command/settings/qualification/qualificationCommandHandler.ts b/src/command/settings/qualification/qualificationCommandHandler.ts index 0abd401..b0b9f22 100644 --- a/src/command/settings/qualification/qualificationCommandHandler.ts +++ b/src/command/settings/qualification/qualificationCommandHandler.ts @@ -66,7 +66,10 @@ export default abstract class QualificationCommandHandler { .execute() .then(() => {}) .catch((err) => { - throw new InternalException("Failed deleting qualification", err); + throw new InternalException( + `Failed deleting qualification${err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : ""}`, + err + ); }); } } diff --git a/src/command/settings/queryStore/queryStoreCommandHandler.ts b/src/command/settings/queryStore/queryStoreCommandHandler.ts index 3776b5e..e8c6917 100644 --- a/src/command/settings/queryStore/queryStoreCommandHandler.ts +++ b/src/command/settings/queryStore/queryStoreCommandHandler.ts @@ -63,7 +63,10 @@ export default abstract class QueryStoreCommandHandler { .execute() .then(() => {}) .catch((err) => { - throw new InternalException("Failed deleting queryStore", err); + throw new InternalException( + `Failed deleting queryStore${err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : ""}`, + err + ); }); } } diff --git a/src/command/settings/template/templateCommandHandler.ts b/src/command/settings/template/templateCommandHandler.ts index 54ea6f7..6a88353 100644 --- a/src/command/settings/template/templateCommandHandler.ts +++ b/src/command/settings/template/templateCommandHandler.ts @@ -64,7 +64,10 @@ export default abstract class TemplateCommandHandler { .execute() .then(() => {}) .catch((err) => { - throw new InternalException("Failed deleting template", err); + throw new InternalException( + `Failed deleting template${err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : ""}`, + err + ); }); } } From a2cc408e85bbf5259bbbbe1db5931f2274bcb848 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Mon, 13 Jan 2025 10:38:25 +0100 Subject: [PATCH 7/9] change: remove unused command --- .../newsletterConfigCommand.ts | 4 ---- .../newsletterConfigCommandHandler.ts | 19 +------------------ .../settings/newsletterConfigController.ts | 19 +------------------ src/routes/admin/settings/newsletterConfig.ts | 9 --------- 4 files changed, 2 insertions(+), 49 deletions(-) diff --git a/src/command/settings/newsletterConfig/newsletterConfigCommand.ts b/src/command/settings/newsletterConfig/newsletterConfigCommand.ts index f07de54..be28649 100644 --- a/src/command/settings/newsletterConfig/newsletterConfigCommand.ts +++ b/src/command/settings/newsletterConfig/newsletterConfigCommand.ts @@ -4,7 +4,3 @@ export interface SetNewsletterConfigCommand { comTypeId: number; config: NewsletterConfigType; } - -export interface DeleteNewsletterConfigCommand { - comTypeId: number; -} diff --git a/src/command/settings/newsletterConfig/newsletterConfigCommandHandler.ts b/src/command/settings/newsletterConfig/newsletterConfigCommandHandler.ts index 56b41bd..4f26df4 100644 --- a/src/command/settings/newsletterConfig/newsletterConfigCommandHandler.ts +++ b/src/command/settings/newsletterConfig/newsletterConfigCommandHandler.ts @@ -1,7 +1,7 @@ import { dataSource } from "../../../data-source"; import { newsletterConfig } from "../../../entity/settings/newsletterConfig"; import InternalException from "../../../exceptions/internalException"; -import { DeleteNewsletterConfigCommand, SetNewsletterConfigCommand } from "./newsletterConfigCommand"; +import { SetNewsletterConfigCommand } from "./newsletterConfigCommand"; export default abstract class NewsletterConfigCommandHandler { /** @@ -27,21 +27,4 @@ export default abstract class NewsletterConfigCommandHandler { throw new InternalException("Failed setting newsletterConfig", err); }); } - /** - * @description delete newsletterConfig - * @param {DeleteNewsletterConfigCommand} deleteNewsletterConfig - * @returns {Promise} - */ - static async delete(deleteNewsletterConfig: DeleteNewsletterConfigCommand): Promise { - return await dataSource - .createQueryBuilder() - .delete() - .from(newsletterConfig) - .where("comTypeId = :comTypeId", { comTypeId: deleteNewsletterConfig.comTypeId }) - .execute() - .then(() => {}) - .catch((err) => { - throw new InternalException("Failed setting newsletterConfig", err); - }); - } } diff --git a/src/controller/admin/settings/newsletterConfigController.ts b/src/controller/admin/settings/newsletterConfigController.ts index f047816..7d0ff95 100644 --- a/src/controller/admin/settings/newsletterConfigController.ts +++ b/src/controller/admin/settings/newsletterConfigController.ts @@ -2,7 +2,7 @@ import { Request, Response } from "express"; import NewsletterConfigService from "../../../service/settings/newsletterConfigService"; import NewsletterConfigFactory from "../../../factory/admin/settings/newsletterConfig"; import NewsletterConfigCommandHandler from "../../../command/settings/newsletterConfig/newsletterConfigCommandHandler"; -import { DeleteNewsletterConfigCommand, SetNewsletterConfigCommand } from "../../../command/settings/newsletterConfig/newsletterConfigCommand"; +import { SetNewsletterConfigCommand } from "../../../command/settings/newsletterConfig/newsletterConfigCommand"; /** * @description get all newsletterConfigs @@ -47,20 +47,3 @@ export async function setNewsletterConfig(req: Request, res: Response): Promise< res.send(id); } - -/** - * @description delete award - * @param req {Request} Express req object - * @param res {Response} Express res object - * @returns {Promise<*>} - */ -export async function deleteNewsletterConfig(req: Request, res: Response): Promise { - const comTypeId = parseInt(req.params.comTypeId); - - let deleteNewsletterConfig: DeleteNewsletterConfigCommand = { - comTypeId: comTypeId, - }; - await NewsletterConfigCommandHandler.delete(deleteNewsletterConfig); - - res.sendStatus(204); -} diff --git a/src/routes/admin/settings/newsletterConfig.ts b/src/routes/admin/settings/newsletterConfig.ts index a874cc7..94fe205 100644 --- a/src/routes/admin/settings/newsletterConfig.ts +++ b/src/routes/admin/settings/newsletterConfig.ts @@ -1,6 +1,5 @@ import express, { Request, Response } from "express"; import { - deleteNewsletterConfig, getAllNewsletterConfigs, getNewsletterConfigById, setNewsletterConfig, @@ -25,12 +24,4 @@ router.put( } ); -router.delete( - "/:comTypeId", - PermissionHelper.passCheckMiddleware("create", "settings", "newsletter_config"), - async (req: Request, res: Response) => { - await deleteNewsletterConfig(req, res); - } -); - export default router; From c9b8c3090d0addca459b0d3d49fb5b499c02ddba Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Mon, 13 Jan 2025 10:38:44 +0100 Subject: [PATCH 8/9] fix: end date update date error --- src/command/club/member/membershipCommandHandler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/command/club/member/membershipCommandHandler.ts b/src/command/club/member/membershipCommandHandler.ts index 602d6d7..0cd0e5a 100644 --- a/src/command/club/member/membershipCommandHandler.ts +++ b/src/command/club/member/membershipCommandHandler.ts @@ -31,7 +31,7 @@ export default abstract class MembershipCommandHandler { .createQueryBuilder() .update(membership) .set({ - end: new Date(createMembership.start).setDate(new Date(createMembership.start).getDate() - 1), + end: new Date(new Date(createMembership.start).setDate(new Date(createMembership.start).getDate() - 1)), terminationReason: "beendet durch neuen Eintrag.", }) .where("end IS NULL") From e738be4e13f7e35a4c3d306737d1ab4e74301c11 Mon Sep 17 00:00:00 2001 From: Julian Krauser Date: Mon, 13 Jan 2025 11:16:35 +0100 Subject: [PATCH 9/9] change: update entity files --- src/entity/club/member/communication.ts | 14 +++++++------- src/entity/club/protocol/protocolPrintout.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/entity/club/member/communication.ts b/src/entity/club/member/communication.ts index 42b1bd7..f50d1a9 100644 --- a/src/entity/club/member/communication.ts +++ b/src/entity/club/member/communication.ts @@ -40,17 +40,17 @@ export class communication { @Column() typeId: number; - @ManyToOne(() => communicationType, (communicationType) => communicationType.communications, { - nullable: false, - onDelete: "RESTRICT", - onUpdate: "RESTRICT", - }) - type: communicationType; - @ManyToOne(() => member, (member) => member.awards, { nullable: false, onDelete: "CASCADE", onUpdate: "RESTRICT", }) member: member; + + @ManyToOne(() => communicationType, (communicationType) => communicationType.communications, { + nullable: false, + onDelete: "RESTRICT", + onUpdate: "RESTRICT", + }) + type: communicationType; } diff --git a/src/entity/club/protocol/protocolPrintout.ts b/src/entity/club/protocol/protocolPrintout.ts index 311b407..a369ccb 100644 --- a/src/entity/club/protocol/protocolPrintout.ts +++ b/src/entity/club/protocol/protocolPrintout.ts @@ -9,7 +9,7 @@ export class protocolPrintout { @Column({ type: "varchar", length: 255 }) title: string; - @Column({ type: "int" }) + @Column({ type: "int", default: "1" }) iteration: number; @Column({ type: "varchar", length: 255 })