#25-cleanup-&-enhancements #31

Merged
jkeffects merged 7 commits from #25-cleanup-&-enhancements into main 2025-01-05 15:12:11 +00:00
14 changed files with 185 additions and 39 deletions
Showing only changes of commit 5d3f8ea46a - Show all commits

View file

@ -48,6 +48,8 @@ import {
UpdateCommunicationCommand, UpdateCommunicationCommand,
} from "../../command/communicationCommand"; } from "../../command/communicationCommand";
import CommunicationCommandHandler from "../../command/communicationCommandHandler"; import CommunicationCommandHandler from "../../command/communicationCommandHandler";
import {PdfExport} from "../../helpers/pdfExport";
import {PermissionModule} from "../../type/permissionTypes";
/** /**
* @description get all members * @description get all members
@ -218,6 +220,33 @@ export async function getCommunicationByMemberAndRecord(req: Request, res: Respo
res.json(CommunicationFactory.mapToSingle(communication)); res.json(CommunicationFactory.mapToSingle(communication));
} }
/**
* @description create member printout list
* @param req {Request} Express req object
* @param res {Response} Express res object
* @returns {Promise<*>}
*/
export async function createMemberPrintoutList(req: Request, res: Response): Promise<any> {
let members = await MemberService.getByRunningMembership()
let pdf = await PdfExport.renderFile({
title: "Mitgliederliste",
template: "member.list",
saveToDisk: false,
data: {
member: members
},
});
let pdfbuffer = Buffer.from(pdf);
res.setHeader("Content-Type", "application/pdf");
res.setHeader("Content-Length", pdfbuffer.byteLength);
res.setHeader("Content-Disposition", "inline; filename=preview.pdf");
res.send(pdfbuffer);
}
/** /**
* @description create member * @description create member
* @param req {Request} Express req object * @param req {Request} Express req object

View file

@ -21,8 +21,8 @@ export async function getAllTemplateUsages(req: Request, res: Response): Promise
if (!req.isOwner) { if (!req.isOwner) {
templateUsages = templateUsages.filter((tu) => { templateUsages = templateUsages.filter((tu) => {
return ( return (
PermissionHelper.can(req.permissions, "update", "settings", tu.scope) || PermissionHelper.can(req.permissions, "update", "settings", tu.scope.split(".")[0] as PermissionModule) ||
PermissionHelper.can(req.permissions, "update", "club", tu.scope) PermissionHelper.can(req.permissions, "update", "club", tu.scope.split(".")[0] as PermissionModule)
); );
}); });
} }

View file

@ -65,6 +65,7 @@ import { TemplateMargins1735733514043 } from "./migrations/1735733514043-templat
import { InternalId1735822722235 } from "./migrations/1735822722235-internalId"; import { InternalId1735822722235 } from "./migrations/1735822722235-internalId";
import { PostalCode1735927918979 } from "./migrations/1735927918979-postalCode"; import { PostalCode1735927918979 } from "./migrations/1735927918979-postalCode";
import { ProtocolAbsent1736072179716 } from "./migrations/1736072179716-protocolAbsent"; import { ProtocolAbsent1736072179716 } from "./migrations/1736072179716-protocolAbsent";
import {Memberlist1736079005086} from "./migrations/1736079005086-memberlist";
const dataSource = new DataSource({ const dataSource = new DataSource({
type: DB_TYPE as any, type: DB_TYPE as any,
@ -140,6 +141,7 @@ const dataSource = new DataSource({
InternalId1735822722235, InternalId1735822722235,
PostalCode1735927918979, PostalCode1735927918979,
ProtocolAbsent1736072179716, ProtocolAbsent1736072179716,
Memberlist1736079005086
], ],
migrationsRun: true, migrationsRun: true,
migrationsTransactionMode: "each", migrationsTransactionMode: "each",

View file

@ -0,0 +1,13 @@
import { member } from "../entity/member";
import { protocolAgenda } from "../entity/protocolAgenda";
import { protocolDecision } from "../entity/protocolDecision";
import { protocolVoting } from "../entity/protocolVoting";
export const memberlistDemoData: { member: Array<Partial<member>> } = {
member: [
{
firstname: "Julian",
lastname: "Krauser",
},
]
}

View file

@ -5,7 +5,7 @@ import { PermissionModule } from "../type/permissionTypes";
@Entity() @Entity()
export class templateUsage { export class templateUsage {
@PrimaryColumn({ type: "varchar", length: 255 }) @PrimaryColumn({ type: "varchar", length: 255 })
scope: PermissionModule; scope: `${PermissionModule}`|`${PermissionModule}.${string}`;
@Column({ type: "int", nullable: true }) @Column({ type: "int", nullable: true })
headerId: number | null; headerId: number | null;

View file

@ -1,14 +1,17 @@
import { newsletterDemoData } from "../demodata/newsletter.data"; import { newsletterDemoData } from "../demodata/newsletter.data";
import { protocolDemoData } from "../demodata/protocol.data"; import { protocolDemoData } from "../demodata/protocol.data";
import { PermissionModule } from "../type/permissionTypes"; import { PermissionModule } from "../type/permissionTypes";
import {memberlistDemoData} from "../demodata/member.list.data";
export abstract class DemoDataHelper { export abstract class DemoDataHelper {
static getData(scope: PermissionModule) { static getData(scope: `${PermissionModule}`|`${PermissionModule}.${string}`) {
switch (scope) { switch (scope) {
case "protocol": case "protocol":
return protocolDemoData; return protocolDemoData;
case "newsletter": case "newsletter":
return newsletterDemoData; return newsletterDemoData;
case "member.list":
return memberlistDemoData;
default: default:
return {}; return {};
} }

View file

@ -13,7 +13,7 @@ export abstract class PdfExport {
saveToDisk = true, saveToDisk = true,
folder = "", folder = "",
}: { }: {
template: PermissionModule; template: `${PermissionModule}`|`${PermissionModule}.${string}`;
title?: string; title?: string;
filename?: string; filename?: string;
data?: any; data?: any;

View file

@ -34,7 +34,7 @@ export abstract class TemplateHelper {
bodyData = {}, bodyData = {},
footerData = {}, footerData = {},
}: { }: {
module: PermissionModule; module: `${PermissionModule}`|`${PermissionModule}.${string}`;
title?: string; title?: string;
headerData?: any; headerData?: any;
bodyData?: any; bodyData?: any;

View file

@ -0,0 +1,26 @@
import { MigrationInterface, QueryRunner } from "typeorm";
import { templateUsage } from "../entity/templateUsage";
import {PermissionModule} from "../type/permissionTypes";
export class Memberlist1736079005086 implements MigrationInterface {
name = "Memberlist1736079005086";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.manager
.createQueryBuilder()
.insert()
.into(templateUsage)
.values({ scope: "member.list" })
.orIgnore()
.execute();
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.manager
.createQueryBuilder()
.delete()
.from(templateUsage)
.where({ scope: "member.list" })
.execute();
}
}

View file

@ -6,6 +6,7 @@ import {
addMembershipToMember, addMembershipToMember,
addQualificationToMember, addQualificationToMember,
createMember, createMember,
createMemberPrintoutList,
deleteAwardOfMember, deleteAwardOfMember,
deleteCommunicationOfMember, deleteCommunicationOfMember,
deleteExecutivePositionOfMember, deleteExecutivePositionOfMember,
@ -43,6 +44,10 @@ router.get("/:id", async (req: Request, res: Response) => {
await getMemberById(req, res); await getMemberById(req, res);
}); });
router.get("/print/namelist", async (req: Request, res: Response) => {
await createMemberPrintoutList(req, res);
});
router.get("/:memberId/memberships", async (req: Request, res: Response) => { router.get("/:memberId/memberships", async (req: Request, res: Response) => {
await getMembershipsByMember(req, res); await getMembershipsByMember(req, res);
}); });

View file

@ -9,7 +9,7 @@ export default abstract class MemberService {
* @returns {Promise<[Array<member>, number]>} * @returns {Promise<[Array<member>, number]>}
*/ */
static async getAll(offset: number = 0, count: number = 25, search: string = ""): Promise<[Array<member>, number]> { static async getAll(offset: number = 0, count: number = 25, search: string = ""): Promise<[Array<member>, number]> {
let query = await dataSource let query = dataSource
.getRepository(member) .getRepository(member)
.createQueryBuilder("member") .createQueryBuilder("member")
.leftJoinAndMapOne( .leftJoinAndMapOne(
@ -54,7 +54,7 @@ export default abstract class MemberService {
}); });
} }
return query return await query
.offset(offset) .offset(offset)
.limit(count) .limit(count)
.orderBy("member.lastname") .orderBy("member.lastname")
@ -114,6 +114,25 @@ export default abstract class MemberService {
}); });
} }
/**
* @description get members where membership is setz
* @returns {Promise<member>}
*/
static async getByRunningMembership(): Promise<Array<member>> {
return await dataSource
.getRepository(member)
.createQueryBuilder("member")
.leftJoinAndSelect("member.memberships", "membership")
.where("membership.end IS NULL")
.getMany()
.then((res) => {
return res;
})
.catch((err) => {
throw new InternalException("member not found by id", err);
});
}
/** /**
* @description get newsletter by member by id * @description get newsletter by member by id
* @param {number} id * @param {number} id

View file

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Mitgliederliste</title>
</head>
<body>
<h1>Mitgliederliste</h1>
<br />
<table style="width:100%">
{{#each member}}
<tr>
<th style="width: 35%;padding: 10px 5px">{{this.firstname}} {{this.lastname}} {{this.nameaffix}}</th>
<th style="width: 65%;padding: 10px 0"></th>
</tr>
{{/each}}
</table>
</body>
<style>
h2,
h3,
p,
span,
ul,
li {
padding: 0;
margin: 0;
}
h1,
h2 {
color: #990b00;
}
h2 {
margin-bottom: 5px;
}
table, th, td {
border: 1px solid black;
border-collapse: collapse;
text-align: start;
}
</style>
</html>

View file

@ -0,0 +1,3 @@
<div style="font-size: 10px; text-align: center; width: 100%; color: #888">
Seite <span class="pageNumber"></span> von <span class="totalPages"></span>
</div>

View file

@ -1,7 +1,7 @@
import { PermissionModule } from "../../type/permissionTypes"; import { PermissionModule } from "../../type/permissionTypes";
export interface TemplateUsageViewModel { export interface TemplateUsageViewModel {
scope: PermissionModule; scope: `${PermissionModule}`|`${PermissionModule}.${string}`;
header: { id: number; template: string } | null; header: { id: number; template: string } | null;
body: { id: number; template: string } | null; body: { id: number; template: string } | null;
footer: { id: number; template: string } | null; footer: { id: number; template: string } | null;