#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,
} from "../../command/communicationCommand";
import CommunicationCommandHandler from "../../command/communicationCommandHandler";
import {PdfExport} from "../../helpers/pdfExport";
import {PermissionModule} from "../../type/permissionTypes";
/**
* @description get all members
@ -218,6 +220,33 @@ export async function getCommunicationByMemberAndRecord(req: Request, res: Respo
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
* @param req {Request} Express req object

View file

@ -21,8 +21,8 @@ export async function getAllTemplateUsages(req: Request, res: Response): Promise
if (!req.isOwner) {
templateUsages = templateUsages.filter((tu) => {
return (
PermissionHelper.can(req.permissions, "update", "settings", tu.scope) ||
PermissionHelper.can(req.permissions, "update", "club", tu.scope)
PermissionHelper.can(req.permissions, "update", "settings", tu.scope.split(".")[0] as PermissionModule) ||
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 { PostalCode1735927918979 } from "./migrations/1735927918979-postalCode";
import { ProtocolAbsent1736072179716 } from "./migrations/1736072179716-protocolAbsent";
import {Memberlist1736079005086} from "./migrations/1736079005086-memberlist";
const dataSource = new DataSource({
type: DB_TYPE as any,
@ -140,6 +141,7 @@ const dataSource = new DataSource({
InternalId1735822722235,
PostalCode1735927918979,
ProtocolAbsent1736072179716,
Memberlist1736079005086
],
migrationsRun: true,
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()
export class templateUsage {
@PrimaryColumn({ type: "varchar", length: 255 })
scope: PermissionModule;
scope: `${PermissionModule}`|`${PermissionModule}.${string}`;
@Column({ type: "int", nullable: true })
headerId: number | null;

View file

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

View file

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

View file

@ -34,7 +34,7 @@ export abstract class TemplateHelper {
bodyData = {},
footerData = {},
}: {
module: PermissionModule;
module: `${PermissionModule}`|`${PermissionModule}.${string}`;
title?: string;
headerData?: 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,
addQualificationToMember,
createMember,
createMemberPrintoutList,
deleteAwardOfMember,
deleteCommunicationOfMember,
deleteExecutivePositionOfMember,
@ -43,6 +44,10 @@ router.get("/:id", async (req: Request, res: Response) => {
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) => {
await getMembershipsByMember(req, res);
});

View file

@ -9,7 +9,7 @@ export default abstract class MemberService {
* @returns {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)
.createQueryBuilder("member")
.leftJoinAndMapOne(
@ -54,7 +54,7 @@ export default abstract class MemberService {
});
}
return query
return await query
.offset(offset)
.limit(count)
.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
* @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";
export interface TemplateUsageViewModel {
scope: PermissionModule;
scope: `${PermissionModule}`|`${PermissionModule}.${string}`;
header: { id: number; template: string } | null;
body: { id: number; template: string } | null;
footer: { id: number; template: string } | null;