Compare commits

...

24 commits

Author SHA1 Message Date
542a77fbef fix backup await 2025-02-02 16:37:55 +01:00
6330ebd01d backup serving, storing and restoring 2025-02-02 16:23:44 +01:00
fc01263c4e enhance views to display exact year, month, day values
sqlite displays negative days and months
2025-02-01 18:09:58 +01:00
a73c712626 transform migrations to work with mysql, postgres and sqlite
sqlite currently fails syntax of views
2025-02-01 13:11:10 +01:00
2cee8b5119 calendar externa prefix 2025-01-31 17:48:20 +01:00
ee60f497fa improved backup restore 2025-01-31 13:58:07 +01:00
0f621ac46d Merge branch 'develop' into feature/#34-backup-&-import
# Conflicts:
#	src/command/club/member/memberCommandHandler.ts
#	src/data-source.ts
#	src/entity/club/member/member.ts
#	src/service/club/member/memberService.ts
2025-01-31 11:51:38 +01:00
0468a4f331 Merge branch 'main' into develop 2025-01-31 11:50:39 +01:00
0994274c0c update prevention message 2025-01-31 11:25:00 +01:00
9a1f4a2985 extend backup file with file details 2025-01-31 11:10:08 +01:00
e17eb30aed change: allow read to related data from allowed modules 2025-01-31 11:07:58 +01:00
668d8448da fix: newsletter recipients with type 2025-01-31 11:07:10 +01:00
0b7de992c8 extend base schema for future features 2025-01-31 11:06:02 +01:00
b7b6694407 backup and base schema creation 2025-01-30 15:58:34 +01:00
a91b723f04 default arrays and none existant data inserts 2025-01-30 14:02:42 +01:00
5701313228 restart schema with clean database 2025-01-29 18:10:41 +01:00
f78097b616 create and restore backups 2025-01-29 16:49:34 +01:00
6ae463a784 fix: member update internal id default 2025-01-29 10:05:55 +01:00
f245ff74a8 update database error messages 2025-01-29 09:42:22 +01:00
f89483f878 change user to uuid 2025-01-29 08:53:49 +01:00
07f8e2dbcb Merge branch 'develop' into feature/#34-backup-&-import 2025-01-28 11:10:12 +01:00
4378c02d17 unique fields for tables 2025-01-28 11:09:42 +01:00
684c24e4fd extend ENVs 2025-01-25 16:54:01 +01:00
46ad96c470 move sendNewsletter flag to communication table 2025-01-25 16:37:52 +01:00
179 changed files with 4498 additions and 3205 deletions

View file

@ -1,10 +1,22 @@
DB_TYPE = (mysql|sqlite|...)
DB_PORT = number
DB_TYPE = (mysql|sqlite|postgres)
## BSP für mysql
DB_PORT = 3306
DB_HOST = database_host
DB_NAME = database_name
DB_USERNAME = database_username
DB_PASSWORD = database_password
## BSP für postgres
DB_PORT = 5432
DB_HOST = database_host
DB_NAME = database_name
DB_USERNAME = database_username
DB_PASSWORD = database_password
## BSP für sqlite
DB_HOST = filename.db
SERVER_PORT = portnumber
JWT_SECRET = ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890
@ -16,7 +28,11 @@ MAIL_USERNAME = mail_username
MAIL_PASSWORD = mail_password
MAIL_HOST = mail_hoststring
MAIL_PORT = mail_portnumber
MAIL_SECURE (true|false) // true for port 465, fals for other ports
MAIL_SECURE = (true|false) // true for port 465, fals for other ports
CLUB_NAME = clubname #default FF Admin
CLUB_WEBSITE = https://my-club-website-url
CLUB_WEBSITE = https://my-club-website-url
BACKUP_INTERVAL = number of days (min 1)
BACKUP_COPIES = number of parallel copies
BACKUP_AUTO_RESTORE = (true|false) # default false

3
.gitignore vendored
View file

@ -132,4 +132,5 @@ dist
files
.idea
.idea
*.db

View file

@ -25,7 +25,7 @@ services:
container_name: ff_member_administration_server
restart: unless-stopped
environment:
- DB_TYPE=<mysql|sqlite> # default ist auf mysql gesetzt
- DB_TYPE=<mysql|sqlite|postgres> # default ist auf mysql gesetzt
- DB_HOST=ff-db
- DB_PORT=<number> # default ist auf 3306 gesetzt
- DB_NAME=ffadmin
@ -42,6 +42,9 @@ services:
- MAIL_SECURE=<boolean> # default ist auf false gesetzt
- CLUB_NAME=<tobemodified> # default ist auf FF Admin gesetzt
- CLUB_WEBSITE=<tobemodified>
- BACKUP_INTERVAL=<number of days (min. 1)> # alle x Tage, sonst keine
- BACKUP_COPIES=<number of parallel copies> # Anzahl parallel bestehender Backups
- BACKUP_AUTO_RESTORE=<boolean> # default ist auf true gesetzt
volumes:
- <volume|local path>:/app/files
networks:
@ -62,11 +65,27 @@ services:
- <volume|local path>:/var/lib/mysql
networks:
- ff_internal
# OR
image: postgres:16
container_name: ff_db
restart: unless-stopped
environment:
- POSTGRES_DB=ffadmin
- POSTGRES_USER=administration_backend
- POSTGRES_PASSWORD=<dbuserpasswd>
volumes:
- <volume|local path>:/var/lib/postgresql/data
networks:
- ff_internal
networks:
ff_internal:
```
Die Verwendung von postgres wird aufgrund des Verhaltens bei Datenbank-Update-Fehlern empfohlen.
Die Verwendung von SQLite wird nur für die Entwicklung oder lokale Tests empfohlen.
Führen Sie dann den folgenden Befehl im Verzeichnis der compose-Datei aus, um den Container zu starten:
```sh

1298
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -30,8 +30,10 @@
"handlebars": "^4.7.8",
"ics": "^3.8.1",
"jsonwebtoken": "^9.0.2",
"lodash.uniqby": "^4.7.0",
"moment": "^2.30.1",
"ms": "^2.1.3",
"multer": "^1.4.5-lts.1",
"mysql": "^2.18.1",
"node-schedule": "^2.1.1",
"nodemailer": "^6.9.14",
@ -42,6 +44,7 @@
"rss-parser": "^3.13.0",
"socket.io": "^4.7.5",
"speakeasy": "^2.0.0",
"sqlite3": "^5.1.7",
"typeorm": "^0.3.20",
"uuid": "^10.0.0"
},
@ -49,7 +52,9 @@
"@types/cors": "^2.8.14",
"@types/express": "^4.17.17",
"@types/jsonwebtoken": "^9.0.6",
"@types/lodash.uniqby": "^4.7.9",
"@types/ms": "^0.7.34",
"@types/multer": "^1.4.12",
"@types/mysql": "^2.15.21",
"@types/node": "^16.18.41",
"@types/node-schedule": "^2.1.6",

View file

@ -1,6 +1,7 @@
import { dataSource } from "../../../data-source";
import { calendar } from "../../../entity/club/calendar";
import { calendarType } from "../../../entity/settings/calendarType";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { CreateCalendarCommand, DeleteCalendarCommand, UpdateCalendarCommand } from "./calendarCommand";
@ -33,7 +34,7 @@ export default abstract class CalendarCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating calendar", err);
throw new DatabaseActionException("CREATE", "calendar", err);
});
}
@ -72,7 +73,7 @@ export default abstract class CalendarCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating award", err);
throw new DatabaseActionException("UPDATE", "calendar", err);
});
}
@ -90,7 +91,7 @@ export default abstract class CalendarCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed deleting calendar", err);
throw new DatabaseActionException("DELETE", "calendar", err);
});
}
}

View file

@ -9,7 +9,7 @@ export interface CreateCommunicationCommand {
street: string;
streetNumber: number;
streetNumberAddition: string;
memberId: number;
memberId: string;
typeId: number;
}
@ -25,10 +25,10 @@ export interface UpdateCommunicationCommand {
street: string;
streetNumber: number;
streetNumberAddition: string;
memberId: number;
memberId: string;
}
export interface DeleteCommunicationCommand {
id: number;
memberId: number;
memberId: string;
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { communication } from "../../../entity/club/member/communication";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import {
CreateCommunicationCommand,
@ -54,7 +55,7 @@ export default abstract class CommunicationCommandHandler {
return insertId;
})
.catch((err) => {
throw new InternalException("Failed creating communication", err);
throw new DatabaseActionException("CREATE", "communication", err);
});
}
@ -97,7 +98,7 @@ export default abstract class CommunicationCommandHandler {
})
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating communication", err);
throw new DatabaseActionException("UPDATE", "communication", err);
});
}
@ -116,7 +117,7 @@ export default abstract class CommunicationCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed deleting communication", err);
throw new DatabaseActionException("DELETE", "communication", err);
});
}
}

View file

@ -2,7 +2,7 @@ export interface CreateMemberAwardCommand {
given: boolean;
note?: string;
date: Date;
memberId: number;
memberId: string;
awardId: number;
}
@ -11,11 +11,11 @@ export interface UpdateMemberAwardCommand {
given: boolean;
note?: string;
date: Date;
memberId: number;
memberId: string;
awardId: number;
}
export interface DeleteMemberAwardCommand {
id: number;
memberId: number;
memberId: string;
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { memberAwards } from "../../../entity/club/member/memberAwards";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { CreateMemberAwardCommand, DeleteMemberAwardCommand, UpdateMemberAwardCommand } from "./memberAwardCommand";
@ -26,7 +27,7 @@ export default abstract class MemberAwardCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating memberAward", err);
throw new DatabaseActionException("CREATE", "memberAward", err);
});
}
@ -50,7 +51,7 @@ export default abstract class MemberAwardCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating memberAward", err);
throw new DatabaseActionException("UPDATE", "memberAward", err);
});
}
@ -69,7 +70,7 @@ export default abstract class MemberAwardCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed deleting memberAward", err);
throw new DatabaseActionException("DELETE", "memberAward", err);
});
}
}

View file

@ -8,7 +8,7 @@ export interface CreateMemberCommand {
}
export interface UpdateMemberCommand {
id: number;
id: string;
salutationId: number;
firstname: string;
lastname: string;
@ -18,5 +18,5 @@ export interface UpdateMemberCommand {
}
export interface DeleteMemberCommand {
id: number;
id: string;
}

View file

@ -1,6 +1,7 @@
import { dataSource } from "../../../data-source";
import { communication } from "../../../entity/club/member/communication";
import { member } from "../../../entity/club/member/member";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { CreateMemberCommand, DeleteMemberCommand, UpdateMemberCommand } from "./memberCommand";
@ -28,10 +29,7 @@ export default abstract class MemberCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException(
`Failed creating member${err.code.includes("ER_DUP_ENTRY") ? " due to duplicate entry for column" : ""}`,
err
);
throw new DatabaseActionException("CREATE", "member", err);
});
}
@ -56,10 +54,7 @@ export default abstract class MemberCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException(
`Failed updating member${err.code.includes("ER_DUP_ENTRY") ? " due to duplicate entry for column" : ""}`,
err
);
throw new DatabaseActionException("UPDATE", "member", err);
});
}
@ -77,7 +72,7 @@ export default abstract class MemberCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed deleting member", err);
throw new DatabaseActionException("DELETE", "member", err);
});
}
}

View file

@ -2,7 +2,7 @@ export interface CreateMemberExecutivePositionCommand {
note?: string;
start: Date;
end?: Date;
memberId: number;
memberId: string;
executivePositionId: number;
}
@ -11,11 +11,11 @@ export interface UpdateMemberExecutivePositionCommand {
note?: string;
start: Date;
end?: Date;
memberId: number;
memberId: string;
executivePositionId: number;
}
export interface DeleteMemberExecutivePositionCommand {
id: number;
memberId: number;
memberId: string;
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { memberExecutivePositions } from "../../../entity/club/member/memberExecutivePositions";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import {
CreateMemberExecutivePositionCommand,
@ -30,7 +31,7 @@ export default abstract class MemberExecutivePositionCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating memberExecutivePosition", err);
throw new DatabaseActionException("CREATE", "memberExecutivePosition", err);
});
}
@ -54,7 +55,7 @@ export default abstract class MemberExecutivePositionCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating memberExecutivePosition", err);
throw new DatabaseActionException("UPDATE", "memberExecutivePosition", err);
});
}
@ -73,7 +74,7 @@ export default abstract class MemberExecutivePositionCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed deleting memberExecutivePosition", err);
throw new DatabaseActionException("DELETE", "memberExecutivePosition", err);
});
}
}

View file

@ -1,7 +1,7 @@
export interface CreateMemberQualificationCommand {
note?: string;
start: Date;
memberId: number;
memberId: string;
qualificationId: number;
}
@ -11,11 +11,11 @@ export interface UpdateMemberQualificationCommand {
start: Date;
end?: Date;
terminationReason?: string;
memberId: number;
memberId: string;
qualificationId: number;
}
export interface DeleteMemberQualificationCommand {
id: number;
memberId: number;
memberId: string;
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { memberQualifications } from "../../../entity/club/member/memberQualifications";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import {
CreateMemberQualificationCommand,
@ -29,7 +30,7 @@ export default abstract class MemberQualificationCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating memberQualification", err);
throw new DatabaseActionException("CREATE", "memberQualification", err);
});
}
@ -54,7 +55,7 @@ export default abstract class MemberQualificationCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating memberQualification", err);
throw new DatabaseActionException("UPDATE", "memberQualification", err);
});
}
@ -73,7 +74,7 @@ export default abstract class MemberQualificationCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed deleting memberQualification", err);
throw new DatabaseActionException("DELETE", "memberQualification", err);
});
}
}

View file

@ -1,6 +1,6 @@
export interface CreateMembershipCommand {
start: Date;
memberId: number;
memberId: string;
statusId: number;
}
@ -9,11 +9,11 @@ export interface UpdateMembershipCommand {
start: Date;
end?: Date;
terminationReason?: string;
memberId: number;
memberId: string;
statusId: number;
}
export interface DeleteMembershipCommand {
id: number;
memberId: number;
memberId: string;
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { membership } from "../../../entity/club/member/membership";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { CreateMembershipCommand, DeleteMembershipCommand, UpdateMembershipCommand } from "./membershipCommand";
@ -43,7 +44,7 @@ export default abstract class MembershipCommandHandler {
return insertId;
})
.catch((err) => {
throw new InternalException("Failed creating membership", err);
throw new DatabaseActionException("CREATE", "membership", err);
});
}
@ -67,7 +68,7 @@ export default abstract class MembershipCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating membership", err);
throw new DatabaseActionException("UPDATE", "membership", err);
});
}
@ -86,7 +87,7 @@ export default abstract class MembershipCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed deleting membership", err);
throw new DatabaseActionException("DELETE", "membership", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { newsletter } from "../../../entity/club/newsletter/newsletter";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { CreateNewsletterCommand, SendNewsletterCommand, SynchronizeNewsletterCommand } from "./newsletterCommand";
@ -22,7 +23,7 @@ export default abstract class NewsletterCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating newsletter", err);
throw new DatabaseActionException("CREATE", "newsletter", err);
});
}
@ -47,7 +48,7 @@ export default abstract class NewsletterCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed synching newsletter", err);
throw new DatabaseActionException("SYNC", "newsletter", err);
});
}
@ -67,7 +68,7 @@ export default abstract class NewsletterCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed setting newsletter send state", err);
throw new DatabaseActionException("SET SEND STATE", "newsletter", err);
});
}
}

View file

@ -4,6 +4,7 @@ import InternalException from "../../../exceptions/internalException";
import NewsletterDatesService from "../../../service/club/newsletter/newsletterDatesService";
import { NewsletterDateCommand, SynchronizeNewsletterDatesCommand } from "./newsletterDatesCommand";
import { newsletterDates } from "../../../entity/club/newsletter/newsletterDates";
import DatabaseActionException from "../../../exceptions/databaseActionException";
export default abstract class NewsletterDatesCommandHandler {
/**
@ -42,7 +43,7 @@ export default abstract class NewsletterDatesCommandHandler {
})
.then(() => {})
.catch((err) => {
throw new InternalException("Failed syncing newsletter dates", err);
throw new DatabaseActionException("SYNC", "newsletterDates", err);
});
}

View file

@ -1,4 +1,4 @@
export interface SynchronizeNewsletterRecipientsCommand {
newsletterId: number;
recipients: Array<number>;
recipients: Array<string>;
}

View file

@ -4,6 +4,7 @@ import InternalException from "../../../exceptions/internalException";
import NewsletterRecipientsService from "../../../service/club/newsletter/newsletterRecipientsService";
import { SynchronizeNewsletterRecipientsCommand } from "./newsletterRecipientsCommand";
import { newsletterRecipients } from "../../../entity/club/newsletter/newsletterRecipients";
import DatabaseActionException from "../../../exceptions/databaseActionException";
export default abstract class NewsletterRecipientsCommandHandler {
/**
@ -35,14 +36,14 @@ export default abstract class NewsletterRecipientsCommandHandler {
})
.then(() => {})
.catch((err) => {
throw new InternalException("Failed syncing newsletter recipients", err);
throw new DatabaseActionException("SYNC", "newsletterRecipients", err);
});
}
private static async syncPresenceAdd(
manager: EntityManager,
newsletterId: number,
recipients: Array<number>
recipients: Array<string>
): Promise<InsertResult> {
return await manager
.createQueryBuilder()
@ -60,7 +61,7 @@ export default abstract class NewsletterRecipientsCommandHandler {
private static async syncPresenceRemove(
manager: EntityManager,
newsletterId: number,
recipients: Array<number>
recipients: Array<string>
): Promise<DeleteResult> {
return await manager
.createQueryBuilder()

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { protocolAgenda } from "../../../entity/club/protocol/protocolAgenda";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { SynchronizeProtocolAgendaCommand } from "./protocolAgendaCommand";
@ -24,7 +25,7 @@ export default abstract class ProtocolAgendaCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating protocol", err);
throw new DatabaseActionException("CREATE", "protocolAgenda", err);
});
}
@ -43,7 +44,7 @@ export default abstract class ProtocolAgendaCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed creating protocol", err);
throw new DatabaseActionException("SYNC", "protocolAgenda", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { protocol } from "../../../entity/club/protocol/protocol";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { CreateProtocolCommand, SynchronizeProtocolCommand } from "./protocolCommand";
@ -23,7 +24,7 @@ export default abstract class ProtocolCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating protocol", err);
throw new DatabaseActionException("CREATE", "protocol", err);
});
}
@ -47,7 +48,7 @@ export default abstract class ProtocolCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed creating protocol", err);
throw new DatabaseActionException("SYNC", "protocol", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { protocolDecision } from "../../../entity/club/protocol/protocolDecision";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { SynchronizeProtocolDecisionCommand } from "./protocolDecisionCommand";
@ -24,7 +25,7 @@ export default abstract class ProtocolDecisionCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating protocol", err);
throw new DatabaseActionException("CREATE", "protocolDecision", err);
});
}
/**
@ -42,7 +43,7 @@ export default abstract class ProtocolDecisionCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed creating protocol", err);
throw new DatabaseActionException("SYNC", "protocolDecision", err);
});
}
}

View file

@ -4,7 +4,7 @@ export interface SynchronizeProtocolPresenceCommand {
}
export interface ProtocolPresenceCommand {
memberId: number;
memberId: string;
absent: boolean;
excused: boolean;
}

View file

@ -4,6 +4,7 @@ import { protocolPresence } from "../../../entity/club/protocol/protocolPresence
import InternalException from "../../../exceptions/internalException";
import ProtocolPresenceService from "../../../service/club/protocol/protocolPrecenseService";
import { ProtocolPresenceCommand, SynchronizeProtocolPresenceCommand } from "./protocolPresenceCommand";
import DatabaseActionException from "../../../exceptions/databaseActionException";
export default abstract class ProtocolPresenceCommandHandler {
/**
@ -42,7 +43,7 @@ export default abstract class ProtocolPresenceCommandHandler {
})
.then(() => {})
.catch((err) => {
throw new InternalException("Failed saving protocol presence", err);
throw new DatabaseActionException("SYNC", "protocolSresence", err);
});
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { protocolPrintout } from "../../../entity/club/protocol/protocolPrintout";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { CreateProtocolPrintoutCommand } from "./protocolPrintoutCommand";
@ -25,7 +26,7 @@ export default abstract class ProtocolPrintoutCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating protocol", err);
throw new DatabaseActionException("CREATE", "protocolPrintout", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { protocolVoting } from "../../../entity/club/protocol/protocolVoting";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { SynchronizeProtocolVotingCommand } from "./protocolVotingCommand";
@ -24,7 +25,7 @@ export default abstract class ProtocolVotingCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating protocol", err);
throw new DatabaseActionException("CREATE", "protocolVoting", err);
});
}
/**
@ -42,7 +43,7 @@ export default abstract class ProtocolVotingCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed creating protocol", err);
throw new DatabaseActionException("SYNC", "protocolVoting", err);
});
}
}

View file

@ -1,9 +1,9 @@
export interface CreateRefreshCommand {
userId: number;
userId: string;
isFromPwa?: boolean;
}
export interface DeleteRefreshCommand {
token: string;
userId: number;
userId: string;
}

View file

@ -1,6 +1,7 @@
import { dataSource } from "../data-source";
import { refresh } from "../entity/refresh";
import { PWA_REFRESH_EXPIRATION, REFRESH_EXPIRATION } from "../env.defaults";
import DatabaseActionException from "../exceptions/databaseActionException";
import InternalException from "../exceptions/internalException";
import { StringHelper } from "../helpers/stringHelper";
import UserService from "../service/user/userService";
@ -32,7 +33,7 @@ export default abstract class RefreshCommandHandler {
return refreshToken;
})
.catch((err) => {
throw new InternalException("Failed saving refresh token", err);
throw new DatabaseActionException("CREATE", "refresh", err);
});
}
@ -51,7 +52,7 @@ export default abstract class RefreshCommandHandler {
.execute()
.then((res) => {})
.catch((err) => {
throw new InternalException("failed refresh removal", err);
throw new DatabaseActionException("DELETE", "refresh", err);
});
}
@ -68,7 +69,7 @@ export default abstract class RefreshCommandHandler {
.execute()
.then((res) => {})
.catch((err) => {
throw new InternalException("failed expired refresh removal", err);
throw new DatabaseActionException("DELETE", "refresh", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../data-source";
import { reset } from "../entity/reset";
import DatabaseActionException from "../exceptions/databaseActionException";
import InternalException from "../exceptions/internalException";
import { StringHelper } from "../helpers/stringHelper";
import { CreateResetCommand, DeleteResetCommand } from "./resetCommand";
@ -29,7 +30,7 @@ export default abstract class ResetCommandHandler {
return token;
})
.catch((err) => {
throw new InternalException("Failed saving reset", err);
throw new DatabaseActionException("CREATE", "reset", err);
});
}
@ -48,7 +49,7 @@ export default abstract class ResetCommandHandler {
.execute()
.then((res) => {})
.catch((err) => {
throw new InternalException("failed reset removal", err);
throw new DatabaseActionException("DELETE", "reset", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { award } from "../../../entity/settings/award";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { CreateAwardCommand, DeleteAwardCommand, UpdateAwardCommand } from "./awardCommand";
@ -22,7 +23,7 @@ export default abstract class AwardCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating award", err);
throw new DatabaseActionException("CREATE", "award", err);
});
}
@ -42,7 +43,7 @@ export default abstract class AwardCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating award", err);
throw new DatabaseActionException("UPDATE", "award", err);
});
}
@ -60,10 +61,7 @@ export default abstract class AwardCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException(
`Failed deleting award ${err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : ""}`,
err
);
throw new DatabaseActionException("DELETE", "award", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { calendarType } from "../../../entity/settings/calendarType";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { CreateCalendarTypeCommand, DeleteCalendarTypeCommand, UpdateCalendarTypeCommand } from "./calendarTypeCommand";
@ -25,7 +26,7 @@ export default abstract class CalendarTypeCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating calendarType", err);
throw new DatabaseActionException("CREATE", "calendarType", err);
});
}
@ -48,7 +49,7 @@ export default abstract class CalendarTypeCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating award", err);
throw new DatabaseActionException("UPDATE", "calenarType", err);
});
}
@ -66,10 +67,7 @@ export default abstract class CalendarTypeCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException(
`Failed deleting calendarType${err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : ""}`,
err
);
throw new DatabaseActionException("DELETE", "calendarType", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { communicationType } from "../../../entity/settings/communicationType";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import {
CreateCommunicationTypeCommand,
@ -27,7 +28,7 @@ export default abstract class CommunicationTypeCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating communicationType", err);
throw new DatabaseActionException("CREATE", "communicationType", err);
});
}
@ -48,7 +49,7 @@ export default abstract class CommunicationTypeCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating communicationType", err);
throw new DatabaseActionException("UPDATE", "communicationType", err);
});
}
@ -66,12 +67,7 @@ export default abstract class CommunicationTypeCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException(
`Failed deleting communicationType${
err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : ""
}`,
err
);
throw new DatabaseActionException("DELETE", "communicationType", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { executivePosition } from "../../../entity/settings/executivePosition";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import {
CreateExecutivePositionCommand,
@ -26,7 +27,7 @@ export default abstract class ExecutivePositionCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating executivePosition", err);
throw new DatabaseActionException("DELETE", "executivePosition", err);
});
}
@ -46,7 +47,7 @@ export default abstract class ExecutivePositionCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating executivePosition", err);
throw new DatabaseActionException("UPDATE", "executivePosition", err);
});
}
@ -64,12 +65,7 @@ export default abstract class ExecutivePositionCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException(
`Failed deleting executivePosition${
err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : ""
}`,
err
);
throw new DatabaseActionException("DELETE", "executivePosition", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { membershipStatus } from "../../../entity/settings/membershipStatus";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import {
CreateMembershipStatusCommand,
@ -26,7 +27,7 @@ export default abstract class MembershipStatusCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating membershipStatus", err);
throw new DatabaseActionException("CREATING", "membershipStatus", err);
});
}
@ -46,7 +47,7 @@ export default abstract class MembershipStatusCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating membershipStatus", err);
throw new DatabaseActionException("UPDATE", "membershipStatus", err);
});
}
@ -64,12 +65,7 @@ export default abstract class MembershipStatusCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException(
`Failed deleting membershipStatus${
err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : ""
}`,
err
);
throw new DatabaseActionException("DELETE", "membershipStatus", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { newsletterConfig } from "../../../entity/settings/newsletterConfig";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { SetNewsletterConfigCommand } from "./newsletterConfigCommand";
@ -24,7 +25,7 @@ export default abstract class NewsletterConfigCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed setting newsletterConfig", err);
throw new DatabaseActionException("SET", "newsletterConfig", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { qualification } from "../../../entity/settings/qualification";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import {
CreateQualificationCommand,
@ -27,7 +28,7 @@ export default abstract class QualificationCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating qualification", err);
throw new DatabaseActionException("CREATE", "qualification", err);
});
}
@ -48,7 +49,7 @@ export default abstract class QualificationCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating qualification", err);
throw new DatabaseActionException("UPDATE", "qualification", err);
});
}
@ -66,10 +67,7 @@ export default abstract class QualificationCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException(
`Failed deleting qualification${err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : ""}`,
err
);
throw new DatabaseActionException("DELETE", "qualification", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { query } from "../../../entity/settings/query";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { CreateQueryStoreCommand, DeleteQueryStoreCommand, UpdateQueryStoreCommand } from "./queryStoreCommand";
@ -24,7 +25,7 @@ export default abstract class QueryStoreCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating queryStore", err);
throw new DatabaseActionException("CREATE", "queryStore", err);
});
}
@ -45,7 +46,7 @@ export default abstract class QueryStoreCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating queryStore", err);
throw new DatabaseActionException("UPDATE", "queryStore", err);
});
}
@ -63,10 +64,7 @@ export default abstract class QueryStoreCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException(
`Failed deleting queryStore${err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : ""}`,
err
);
throw new DatabaseActionException("DELETE", "queryStore", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { salutation } from "../../../entity/settings/salutation";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { CreateSalutationCommand, DeleteSalutationCommand, UpdateSalutationCommand } from "./salutationCommand";
@ -22,7 +23,7 @@ export default abstract class SalutationCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating salutation", err);
throw new DatabaseActionException("CREATE", "salutation", err);
});
}
@ -42,7 +43,7 @@ export default abstract class SalutationCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating salutation", err);
throw new DatabaseActionException("UPDATE", "salutation", err);
});
}
@ -60,10 +61,7 @@ export default abstract class SalutationCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException(
`Failed deleting salutation ${err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : ""}`,
err
);
throw new DatabaseActionException("DELETE", "salutation", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { template } from "../../../entity/settings/template";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { CreateTemplateCommand, DeleteTemplateCommand, UpdateTemplateCommand } from "./templateCommand";
@ -23,7 +24,7 @@ export default abstract class TemplateCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating template", err);
throw new DatabaseActionException("CREATE", "template", err);
});
}
@ -46,7 +47,7 @@ export default abstract class TemplateCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating template", err);
throw new DatabaseActionException("UPDATE", "template", err);
});
}
@ -64,10 +65,7 @@ export default abstract class TemplateCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException(
`Failed deleting template${err.code.includes("ER_ROW_IS_REFERENCED") ? " due to referenced data" : ""}`,
err
);
throw new DatabaseActionException("DELETE", "template", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { templateUsage } from "../../../entity/settings/templateUsage";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { UpdateTemplateUsageCommand } from "./templateUsageCommand";
@ -24,7 +25,7 @@ export default abstract class TemplateUsageCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating templateUsage", err);
throw new DatabaseActionException("SET", "templateUsage", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { role } from "../../../entity/user/role";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { CreateRoleCommand, DeleteRoleCommand, UpdateRoleCommand } from "./roleCommand";
@ -22,7 +23,7 @@ export default abstract class RoleCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed creating role", err);
throw new DatabaseActionException("CREATE", "role", err);
});
}
@ -42,7 +43,7 @@ export default abstract class RoleCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating role", err);
throw new DatabaseActionException("UPDATE", "role", err);
});
}
@ -60,7 +61,7 @@ export default abstract class RoleCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed deleting role", err);
throw new DatabaseActionException("DELETE", "role", err);
});
}
}

View file

@ -11,6 +11,7 @@ import {
import PermissionHelper from "../../../helpers/permissionHelper";
import RolePermissionService from "../../../service/user/rolePermissionService";
import { PermissionString } from "../../../type/permissionTypes";
import DatabaseActionException from "../../../exceptions/databaseActionException";
export default abstract class RolePermissionCommandHandler {
/**
@ -35,7 +36,7 @@ export default abstract class RolePermissionCommandHandler {
})
.then(() => {})
.catch((err) => {
throw new InternalException("Failed saving role permissions", err);
throw new DatabaseActionException("UPDATE", "rolePermissions", err);
});
}
@ -71,46 +72,4 @@ export default abstract class RolePermissionCommandHandler {
.andWhere("permission IN (:...permission)", { permission: permissions })
.execute();
}
/**
* @description grant permission to user
* @param {CreateRolePermissionCommand} createPermission
* @returns {Promise<number>}
*/
static async create(createPermission: CreateRolePermissionCommand): Promise<number> {
return await dataSource
.createQueryBuilder()
.insert()
.into(rolePermission)
.values({
permission: createPermission.permission,
role: await RoleService.getById(createPermission.roleId),
})
.execute()
.then((result) => {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed saving role permission", err);
});
}
/**
* @description remove permission from role
* @param {DeleteRolePermissionCommand} deletePermission
* @returns {Promise<any>}
*/
static async delete(deletePermission: DeleteRolePermissionCommand): Promise<any> {
return await dataSource
.createQueryBuilder()
.delete()
.from(rolePermission)
.where("roleId = :id", { id: deletePermission.roleId })
.andWhere("permission = :permission", { permission: deletePermission.permission })
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("failed role permission removal", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { invite } from "../../../entity/user/invite";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import { StringHelper } from "../../../helpers/stringHelper";
import { CreateInviteCommand, DeleteInviteCommand } from "./inviteCommand";
@ -31,7 +32,7 @@ export default abstract class InviteCommandHandler {
return token;
})
.catch((err) => {
throw new InternalException("Failed saving invite", err);
throw new DatabaseActionException("CREATE", "invite", err);
});
}
@ -50,7 +51,7 @@ export default abstract class InviteCommandHandler {
.execute()
.then((res) => {})
.catch((err) => {
throw new InternalException("failed invite removal", err);
throw new DatabaseActionException("DELETE", "invite", err);
});
}
@ -68,7 +69,7 @@ export default abstract class InviteCommandHandler {
.execute()
.then((res) => {})
.catch((err) => {
throw new InternalException("failed invite removal", err);
throw new DatabaseActionException("DELETE", "invite", err);
});
}
}

View file

@ -8,7 +8,7 @@ export interface CreateUserCommand {
}
export interface UpdateUserCommand {
id: number;
id: string;
mail: string;
username: string;
firstname: string;
@ -16,20 +16,20 @@ export interface UpdateUserCommand {
}
export interface UpdateUserSecretCommand {
id: number;
id: string;
secret: string;
}
export interface TransferUserOwnerCommand {
fromId: number;
toId: number;
fromId: string;
toId: string;
}
export interface UpdateUserRolesCommand {
id: number;
id: string;
roleIds: Array<number>;
}
export interface DeleteUserCommand {
id: number;
id: string;
}

View file

@ -11,14 +11,15 @@ import {
UpdateUserSecretCommand,
} from "./userCommand";
import UserService from "../../../service/user/userService";
import DatabaseActionException from "../../../exceptions/databaseActionException";
export default abstract class UserCommandHandler {
/**
* @description create user
* @param {CreateUserCommand} createUser
* @returns {Promise<number>}
* @returns {Promise<string>}
*/
static async create(createUser: CreateUserCommand): Promise<number> {
static async create(createUser: CreateUserCommand): Promise<string> {
return await dataSource
.createQueryBuilder()
.insert()
@ -36,7 +37,7 @@ export default abstract class UserCommandHandler {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed saving user", err);
throw new DatabaseActionException("CREATE", "user", err);
});
}
@ -59,7 +60,7 @@ export default abstract class UserCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating user", err);
throw new DatabaseActionException("UPDATE", "user", err);
});
}
@ -79,7 +80,7 @@ export default abstract class UserCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed updating user secret", err);
throw new DatabaseActionException("UPDATE", "user", err);
});
}
@ -105,15 +106,15 @@ export default abstract class UserCommandHandler {
})
.then(() => {})
.catch((err) => {
throw new InternalException("Failed saving user roles", err);
throw new DatabaseActionException("UPDATE", "userRoles", err);
});
}
private static async updateRolesAdd(manager: EntityManager, userId: number, roleId: number): Promise<void> {
private static async updateRolesAdd(manager: EntityManager, userId: string, roleId: number): Promise<void> {
return await manager.createQueryBuilder().relation(user, "roles").of(userId).add(roleId);
}
private static async updateRolesRemove(manager: EntityManager, userId: number, roleId: number): Promise<void> {
private static async updateRolesRemove(manager: EntityManager, userId: string, roleId: number): Promise<void> {
return await manager.createQueryBuilder().relation(user, "roles").of(userId).remove(roleId);
}
@ -145,7 +146,7 @@ export default abstract class UserCommandHandler {
})
.then(() => {})
.catch((err) => {
throw new InternalException("Failed transfering ownership", err);
throw new DatabaseActionException("ABORT", "transfer owner", err);
});
}
@ -163,7 +164,7 @@ export default abstract class UserCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed deleting user", err);
throw new DatabaseActionException("DELETE", "user", err);
});
}
}

View file

@ -2,15 +2,15 @@ import { PermissionString } from "../../../type/permissionTypes";
export interface CreateUserPermissionCommand {
permission: PermissionString;
userId: number;
userId: string;
}
export interface DeleteUserPermissionCommand {
permission: PermissionString;
userId: number;
userId: string;
}
export interface UpdateUserPermissionsCommand {
userId: number;
userId: string;
permissions: Array<PermissionString>;
}

View file

@ -11,6 +11,7 @@ import {
import UserPermissionService from "../../../service/user/userPermissionService";
import PermissionHelper from "../../../helpers/permissionHelper";
import { PermissionString } from "../../../type/permissionTypes";
import DatabaseActionException from "../../../exceptions/databaseActionException";
export default abstract class UserPermissionCommandHandler {
/**
@ -36,13 +37,13 @@ export default abstract class UserPermissionCommandHandler {
})
.then(() => {})
.catch((err) => {
throw new InternalException("Failed saving user permissions", err);
throw new DatabaseActionException("UPDATE", "userPermissions", err);
});
}
private static async updatePermissionsAdd(
manager: EntityManager,
userId: number,
userId: string,
permissions: Array<PermissionString>
): Promise<InsertResult> {
return await manager
@ -61,7 +62,7 @@ export default abstract class UserPermissionCommandHandler {
private static async updatePermissionsRemove(
manager: EntityManager,
userId: number,
userId: string,
permissions: Array<PermissionString>
): Promise<DeleteResult> {
return await manager
@ -72,46 +73,4 @@ export default abstract class UserPermissionCommandHandler {
.andWhere("permission IN (:...permission)", { permission: permissions })
.execute();
}
/**
* @description grant permission to user
* @param {CreateUserPermissionCommand} createPermission
* @returns {Promise<number>}
*/
static async create(createPermission: CreateUserPermissionCommand): Promise<number> {
return await dataSource
.createQueryBuilder()
.insert()
.into(userPermission)
.values({
permission: createPermission.permission,
userId: createPermission.userId,
})
.execute()
.then((result) => {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed saving user permission", err);
});
}
/**
* @description remove permission to user
* @param {DeleteUserPermissionCommand} deletePermission
* @returns {Promise<any>}
*/
static async delete(deletePermission: DeleteUserPermissionCommand): Promise<any> {
return await dataSource
.createQueryBuilder()
.delete()
.from(userPermission)
.where("userId = :id", { id: deletePermission.userId })
.andWhere("permission = :permission", { permission: deletePermission.permission })
.execute()
.then((res) => {})
.catch((err) => {
throw new InternalException("failed user permission removal", err);
});
}
}

View file

@ -1,5 +1,6 @@
import { dataSource } from "../../../data-source";
import { webapi } from "../../../entity/user/webapi";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import InternalException from "../../../exceptions/internalException";
import {
CreateWebapiCommand,
@ -29,10 +30,7 @@ export default abstract class WebapiCommandHandler {
return result.identifiers[0].token;
})
.catch((err) => {
throw new InternalException(
`Failed creating api${err.code.includes("ER_DUP_ENTRY") ? " due to duplicate entry for column" : ""}`,
err
);
throw new DatabaseActionException("CREATE", "webapi", err);
});
}
@ -53,10 +51,7 @@ export default abstract class WebapiCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException(
`Failed updating api${err.code.includes("ER_DUP_ENTRY") ? " due to duplicate entry for column" : ""}`,
err
);
throw new DatabaseActionException("UPDATE", "webapi", err);
});
}
@ -76,7 +71,7 @@ export default abstract class WebapiCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException(`Failed updating api last usage`, err);
throw new DatabaseActionException("UPDATE", "webapi", err);
});
}
@ -94,7 +89,7 @@ export default abstract class WebapiCommandHandler {
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("Failed deleting api", err);
throw new DatabaseActionException("DELETE", "webapi", err);
});
}
}

View file

@ -11,6 +11,7 @@ import {
import PermissionHelper from "../../../helpers/permissionHelper";
import WebapiPermissionService from "../../../service/user/webapiPermissionService";
import { PermissionString } from "../../../type/permissionTypes";
import DatabaseActionException from "../../../exceptions/databaseActionException";
export default abstract class WebapiPermissionCommandHandler {
/**
@ -38,7 +39,7 @@ export default abstract class WebapiPermissionCommandHandler {
})
.then(() => {})
.catch((err) => {
throw new InternalException("Failed saving api permissions", err);
throw new DatabaseActionException("UPDATE", "webapiPermission", err);
});
}
@ -74,46 +75,4 @@ export default abstract class WebapiPermissionCommandHandler {
.andWhere("permission IN (:...permission)", { permission: permissions })
.execute();
}
/**
* @description grant permission to user
* @param {CreateWebapiPermissionCommand} createPermission
* @returns {Promise<number>}
*/
static async create(createPermission: CreateWebapiPermissionCommand): Promise<number> {
return await dataSource
.createQueryBuilder()
.insert()
.into(webapiPermission)
.values({
permission: createPermission.permission,
webapiId: createPermission.webapiId,
})
.execute()
.then((result) => {
return result.identifiers[0].id;
})
.catch((err) => {
throw new InternalException("Failed saving api permission", err);
});
}
/**
* @description remove permission from api
* @param {DeleteWebapiPermissionCommand} deletePermission
* @returns {Promise<any>}
*/
static async delete(deletePermission: DeleteWebapiPermissionCommand): Promise<any> {
return await dataSource
.createQueryBuilder()
.delete()
.from(webapiPermission)
.where("webapiId = :id", { id: deletePermission.webapiId })
.andWhere("permission = :permission", { permission: deletePermission.permission })
.execute()
.then(() => {})
.catch((err) => {
throw new InternalException("failed api permission removal", err);
});
}
}

View file

@ -61,10 +61,7 @@ export async function getAllMembers(req: Request, res: Response): Promise<any> {
let count = parseInt((req.query.count as string) ?? "25");
let search = (req.query.search as string) ?? "";
let noLimit = req.query.noLimit === "true";
let ids = ((req.query.ids ?? "") as string)
.split(",")
.filter((i) => i)
.map((i) => parseInt(i));
let ids = ((req.query.ids ?? "") as string).split(",").filter((i) => i);
let [members, total] = await MemberService.getAll({ offset, count, search, noLimit, ids });
@ -83,7 +80,7 @@ export async function getAllMembers(req: Request, res: Response): Promise<any> {
* @returns {Promise<*>}
*/
export async function getMemberById(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.id);
const memberId = req.params.id;
let member = await MemberService.getById(memberId);
res.json(MemberFactory.mapToSingle(member));
@ -96,7 +93,7 @@ export async function getMemberById(req: Request, res: Response): Promise<any> {
* @returns {Promise<*>}
*/
export async function getMemberStatisticsById(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.id);
const memberId = req.params.id;
let member = await MemberService.getStatisticsById(memberId);
res.json(MemberFactory.mapToMemberStatistic(member));
@ -109,7 +106,7 @@ export async function getMemberStatisticsById(req: Request, res: Response): Prom
* @returns {Promise<*>}
*/
export async function getMembershipsByMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
let memberships = await MembershipService.getAll(memberId);
res.json(MembershipFactory.mapToBase(memberships));
@ -122,7 +119,7 @@ export async function getMembershipsByMember(req: Request, res: Response): Promi
* @returns {Promise<*>}
*/
export async function getMembershipStatisticsById(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
let member = await MembershipService.getStatisticsById(memberId);
res.json(MembershipFactory.mapToBaseStatistics(member));
@ -135,7 +132,7 @@ export async function getMembershipStatisticsById(req: Request, res: Response):
* @returns {Promise<*>}
*/
export async function getMembershipByMemberAndRecord(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.id);
let membership = await MembershipService.getById(memberId, recordId);
@ -149,7 +146,7 @@ export async function getMembershipByMemberAndRecord(req: Request, res: Response
* @returns {Promise<*>}
*/
export async function getAwardsByMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
let awards = await MemberAwardService.getAll(memberId);
res.json(MemberAwardFactory.mapToBase(awards));
@ -162,7 +159,7 @@ export async function getAwardsByMember(req: Request, res: Response): Promise<an
* @returns {Promise<*>}
*/
export async function getAwardByMemberAndRecord(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.id);
let award = await MemberAwardService.getById(memberId, recordId);
@ -176,7 +173,7 @@ export async function getAwardByMemberAndRecord(req: Request, res: Response): Pr
* @returns {Promise<*>}
*/
export async function getQualificationsByMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
let qualifications = await MemberQualificationService.getAll(memberId);
res.json(MemberQualificationFactory.mapToBase(qualifications));
@ -189,7 +186,7 @@ export async function getQualificationsByMember(req: Request, res: Response): Pr
* @returns {Promise<*>}
*/
export async function getQualificationByMemberAndRecord(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.id);
let qualification = await MemberQualificationService.getById(memberId, recordId);
@ -203,7 +200,7 @@ export async function getQualificationByMemberAndRecord(req: Request, res: Respo
* @returns {Promise<*>}
*/
export async function getExecutivePositionsByMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
let positions = await MemberExecutivePositionService.getAll(memberId);
res.json(MemberExecutivePositionFactory.mapToBase(positions));
@ -216,7 +213,7 @@ export async function getExecutivePositionsByMember(req: Request, res: Response)
* @returns {Promise<*>}
*/
export async function getExecutivePositionByMemberAndRecord(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.id);
let position = await MemberExecutivePositionService.getById(memberId, recordId);
@ -230,7 +227,7 @@ export async function getExecutivePositionByMemberAndRecord(req: Request, res: R
* @returns {Promise<*>}
*/
export async function getCommunicationsByMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
let communications = await CommunicationService.getAll(memberId);
res.json(CommunicationFactory.mapToBase(communications));
@ -243,7 +240,7 @@ export async function getCommunicationsByMember(req: Request, res: Response): Pr
* @returns {Promise<*>}
*/
export async function getCommunicationByMemberAndRecord(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.id);
let communication = await CommunicationService.getById(memberId, recordId);
@ -289,7 +286,7 @@ export async function createMember(req: Request, res: Response): Promise<any> {
const lastname = req.body.lastname;
const nameaffix = req.body.nameaffix;
const birthdate = req.body.birthdate;
const internalId = req.body.internalId;
const internalId = req.body.internalId || null;
let createMember: CreateMemberCommand = {
salutationId,
@ -311,7 +308,7 @@ export async function createMember(req: Request, res: Response): Promise<any> {
* @returns {Promise<*>}
*/
export async function addMembershipToMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const start = req.body.start;
const statusId = req.body.statusId;
@ -332,7 +329,7 @@ export async function addMembershipToMember(req: Request, res: Response): Promis
* @returns {Promise<*>}
*/
export async function addAwardToMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const given = req.body.given;
const note = req.body.note;
const date = req.body.date;
@ -357,7 +354,7 @@ export async function addAwardToMember(req: Request, res: Response): Promise<any
* @returns {Promise<*>}
*/
export async function addQualificationToMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const note = req.body.note;
const start = req.body.start;
const qualificationId = req.body.qualificationId;
@ -380,7 +377,7 @@ export async function addQualificationToMember(req: Request, res: Response): Pro
* @returns {Promise<*>}
*/
export async function addExecutivePositionToMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const note = req.body.note;
const start = req.body.start;
const end = req.body.end || null;
@ -405,7 +402,7 @@ export async function addExecutivePositionToMember(req: Request, res: Response):
* @returns {Promise<*>}
*/
export async function addCommunicationToMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const preferred = req.body.preferred;
const isSMSAlarming = req.body.isSMSAlarming;
const isSendNewsletter = req.body.isNewsletterMain;
@ -444,13 +441,13 @@ export async function addCommunicationToMember(req: Request, res: Response): Pro
* @returns {Promise<*>}
*/
export async function updateMemberById(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.id);
const memberId = req.params.id;
const salutationId = parseInt(req.body.salutationId);
const firstname = req.body.firstname;
const lastname = req.body.lastname;
const nameaffix = req.body.nameaffix;
const birthdate = req.body.birthdate;
const internalId = req.body.internalId;
const internalId = req.body.internalId || null;
let updateMember: UpdateMemberCommand = {
id: memberId,
@ -473,7 +470,7 @@ export async function updateMemberById(req: Request, res: Response): Promise<any
* @returns {Promise<*>}
*/
export async function updateMembershipOfMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.recordId);
const start = req.body.start;
const end = req.body.end || null;
@ -500,7 +497,7 @@ export async function updateMembershipOfMember(req: Request, res: Response): Pro
* @returns {Promise<*>}
*/
export async function updateAwardOfMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.recordId);
const given = req.body.given;
const note = req.body.note;
@ -527,7 +524,7 @@ export async function updateAwardOfMember(req: Request, res: Response): Promise<
* @returns {Promise<*>}
*/
export async function updateQualificationOfMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.recordId);
const note = req.body.note;
const start = req.body.start;
@ -556,7 +553,7 @@ export async function updateQualificationOfMember(req: Request, res: Response):
* @returns {Promise<*>}
*/
export async function updateExecutivePositionOfMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.recordId);
const note = req.body.note;
const start = req.body.start;
@ -583,7 +580,7 @@ export async function updateExecutivePositionOfMember(req: Request, res: Respons
* @returns {Promise<*>}
*/
export async function updateCommunicationOfMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.recordId);
const preferred = req.body.preferred;
const isSMSAlarming = req.body.isSMSAlarming;
@ -622,7 +619,7 @@ export async function updateCommunicationOfMember(req: Request, res: Response):
* @returns {Promise<*>}
*/
export async function deleteMemberById(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.id);
const memberId = req.params.id;
let deleteMember: DeleteMemberCommand = {
id: memberId,
@ -639,7 +636,7 @@ export async function deleteMemberById(req: Request, res: Response): Promise<any
* @returns {Promise<*>}
*/
export async function deleteMembershipOfMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.recordId);
let deleteMembership: DeleteMembershipCommand = {
@ -658,7 +655,7 @@ export async function deleteMembershipOfMember(req: Request, res: Response): Pro
* @returns {Promise<*>}
*/
export async function deleteAwardOfMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.recordId);
let deleteMemberAward: DeleteMemberAwardCommand = {
@ -677,7 +674,7 @@ export async function deleteAwardOfMember(req: Request, res: Response): Promise<
* @returns {Promise<*>}
*/
export async function deleteQualificationOfMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.recordId);
let deleteMemberQualification: DeleteMemberQualificationCommand = {
@ -696,7 +693,7 @@ export async function deleteQualificationOfMember(req: Request, res: Response):
* @returns {Promise<*>}
*/
export async function deleteExecutivePositionOfMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.recordId);
let deleteMemberExecutivePosition: DeleteMemberExecutivePositionCommand = {
@ -715,7 +712,7 @@ export async function deleteExecutivePositionOfMember(req: Request, res: Respons
* @returns {Promise<*>}
*/
export async function deleteCommunicationOfMember(req: Request, res: Response): Promise<any> {
const memberId = parseInt(req.params.memberId);
const memberId = req.params.memberId;
const recordId = parseInt(req.params.recordId);
let deleteCommunication: DeleteCommunicationCommand = {

View file

@ -135,7 +135,7 @@ export async function createNewsletterPrintoutPreviewById(req: Request, res: Res
let newsletterId = parseInt(req.params.newsletterId);
let newsletter = await NewsletterService.getById(newsletterId);
let dates = await NewsletterDatesService.getAll(newsletterId);
let recipient = await UserService.getById(parseInt(req.userId));
let recipient = await UserService.getById(req.userId);
let data = NewsletterHelper.buildData(newsletter, dates);
data.recipient = {
@ -241,7 +241,7 @@ export async function createNewsletterMailPreviewById(req: Request, res: Respons
let newsletterId = parseInt(req.params.newsletterId);
let newsletter = await NewsletterService.getById(newsletterId);
let dates = await NewsletterDatesService.getAll(newsletterId);
let recipient = await UserService.getById(parseInt(req.userId));
let recipient = await UserService.getById(req.userId);
let data = NewsletterHelper.buildData(newsletter, dates);
data.recipient = {
@ -375,7 +375,7 @@ export async function synchronizeNewsletterDatesById(req: Request, res: Response
*/
export async function synchronizeNewsletterRecipientsById(req: Request, res: Response): Promise<any> {
let newsletterId = parseInt(req.params.newsletterId);
let recipients = req.body.recipients as Array<number>;
let recipients = req.body.recipients as Array<string>;
let syncRecipients: SynchronizeNewsletterRecipientsCommand = {
newsletterId,

View file

@ -0,0 +1,75 @@
import { Request, Response } from "express";
import { FileSystemHelper } from "../../../helpers/fileSystemHelper";
import BackupHelper from "../../../helpers/backupHelper";
import InternalException from "../../../exceptions/internalException";
/**
* @description get generated backups
* @param req {Request} Express req object
* @param res {Response} Express res object
* @returns {Promise<*>}
*/
export async function getGeneratedBackups(req: Request, res: Response): Promise<any> {
let filesInFolder = FileSystemHelper.getFilesInDirectory(`backup`);
res.json(filesInFolder);
}
/**
* @description download backup file
* @param req {Request} Express req object
* @param res {Response} Express res object
* @returns {Promise<*>}
*/
export async function downloadBackupFile(req: Request, res: Response): Promise<any> {
let filename = req.params.filename;
let filepath = FileSystemHelper.formatPath("backup", filename);
res.sendFile(filepath, {
headers: {
"Content-Type": "application/json",
},
});
}
/**
* @description create backup manually
* @param req {Request} Express req object
* @param res {Response} Express res object
* @returns {Promise<*>}
*/
export async function createManualBackup(req: Request, res: Response): Promise<any> {
await BackupHelper.createBackup({});
res.sendStatus(204);
}
/**
* @description restore backup by selected
* @param req {Request} Express req object
* @param res {Response} Express res object
* @returns {Promise<*>}
*/
export async function restoreBackupByLocalFile(req: Request, res: Response): Promise<any> {
let filename = req.body.filename;
let partial = req.body.partial;
let include = req.body.include;
await BackupHelper.loadBackup({ filename, include, partial });
res.sendStatus(204);
}
/**
* @description upload backup
* @param req {Request} Express req object
* @param res {Response} Express res object
* @returns {Promise<*>}
*/
export async function uploadBackupFile(req: Request, res: Response): Promise<any> {
if (!req.file) {
throw new InternalException("File upload failed");
}
res.sendStatus(204);
}

View file

@ -31,7 +31,7 @@ export async function getAllUsers(req: Request, res: Response): Promise<any> {
* @returns {Promise<*>}
*/
export async function getUserById(req: Request, res: Response): Promise<any> {
const id = parseInt(req.params.id);
const id = req.params.id;
let user = await UserService.getById(id);
res.json(UserFactory.mapToSingle(user));
@ -44,7 +44,7 @@ export async function getUserById(req: Request, res: Response): Promise<any> {
* @returns {Promise<*>}
*/
export async function getUserPermissions(req: Request, res: Response): Promise<any> {
const id = parseInt(req.params.id);
const id = req.params.id;
let permissions = await UserPermissionService.getByUser(id);
res.json(PermissionHelper.convertToObject(permissions.map((p) => p.permission)));
@ -57,7 +57,7 @@ export async function getUserPermissions(req: Request, res: Response): Promise<a
* @returns {Promise<*>}
*/
export async function getUserRoles(req: Request, res: Response): Promise<any> {
const id = parseInt(req.params.id);
const id = req.params.id;
let roles = await UserService.getAssignedRolesByUserId(id);
@ -71,7 +71,7 @@ export async function getUserRoles(req: Request, res: Response): Promise<any> {
* @returns {Promise<*>}
*/
export async function updateUser(req: Request, res: Response): Promise<any> {
const id = parseInt(req.params.id);
const id = req.params.id;
let mail = req.body.mail;
let firstname = req.body.firstname;
let lastname = req.body.lastname;
@ -96,7 +96,7 @@ export async function updateUser(req: Request, res: Response): Promise<any> {
* @returns {Promise<*>}
*/
export async function updateUserPermissions(req: Request, res: Response): Promise<any> {
const id = parseInt(req.params.id);
const id = req.params.id;
let permissions = req.body.permissions;
let permissionStrings = PermissionHelper.convertToStringArray(permissions);
@ -117,7 +117,7 @@ export async function updateUserPermissions(req: Request, res: Response): Promis
* @returns {Promise<*>}
*/
export async function updateUserRoles(req: Request, res: Response): Promise<any> {
const id = parseInt(req.params.id);
const id = req.params.id;
let roleIds = req.body.roleIds as Array<number>;
let updateRoles: UpdateUserRolesCommand = {
@ -136,7 +136,7 @@ export async function updateUserRoles(req: Request, res: Response): Promise<any>
* @returns {Promise<*>}
*/
export async function deleteUser(req: Request, res: Response): Promise<any> {
const id = parseInt(req.params.id);
const id = req.params.id;
let { mail, isOwner } = await UserService.getById(id);

View file

@ -16,7 +16,7 @@ import ForbiddenRequestException from "../exceptions/forbiddenRequestException";
* @returns {Promise<*>}
*/
export async function getMeById(req: Request, res: Response): Promise<any> {
const id = parseInt(req.userId);
const id = req.userId;
let user = await UserService.getById(id);
res.json(UserFactory.mapToSingle(user));
@ -29,7 +29,7 @@ export async function getMeById(req: Request, res: Response): Promise<any> {
* @returns {Promise<*>}
*/
export async function getMyTotp(req: Request, res: Response): Promise<any> {
const userId = parseInt(req.userId);
const userId = req.userId;
let { secret } = await UserService.getById(userId);
@ -54,7 +54,7 @@ export async function getMyTotp(req: Request, res: Response): Promise<any> {
* @returns {Promise<*>}
*/
export async function verifyMyTotp(req: Request, res: Response): Promise<any> {
const userId = parseInt(req.userId);
const userId = req.userId;
let totp = req.body.totp;
let { secret } = await UserService.getById(userId);
@ -78,7 +78,7 @@ export async function verifyMyTotp(req: Request, res: Response): Promise<any> {
* @returns {Promise<*>}
*/
export async function transferOwnership(req: Request, res: Response): Promise<any> {
const userId = parseInt(req.userId);
const userId = req.userId;
let toId = req.body.toId;
let { isOwner } = await UserService.getById(userId);
@ -102,7 +102,7 @@ export async function transferOwnership(req: Request, res: Response): Promise<an
* @returns {Promise<*>}
*/
export async function updateMe(req: Request, res: Response): Promise<any> {
const id = parseInt(req.userId);
const id = req.userId;
let mail = req.body.mail;
let firstname = req.body.firstname;
let lastname = req.body.lastname;

View file

@ -16,69 +16,41 @@ import { executivePosition } from "./entity/settings/executivePosition";
import { membershipStatus } from "./entity/settings/membershipStatus";
import { qualification } from "./entity/settings/qualification";
import { Initial1724317398939 } from "./migrations/1724317398939-initial";
import { RefreshPrimaryChange1724573307851 } from "./migrations/1724573307851-refreshPrimaryChange";
import { Invite1724579024939 } from "./migrations/1724579024939-invite";
import { Permissions1724661484664 } from "./migrations/1724661484664-permissions";
import { RolePermission1724771491085 } from "./migrations/1724771491085-role_permission";
import { MemberBaseData1725435669492 } from "./migrations/1725435669492-member_base_data";
import { member } from "./entity/club/member/member";
import { memberAwards } from "./entity/club/member/memberAwards";
import { memberExecutivePositions } from "./entity/club/member/memberExecutivePositions";
import { memberQualifications } from "./entity/club/member/memberQualifications";
import { membership } from "./entity/club/member/membership";
import { Memberdata1726301836849 } from "./migrations/1726301836849-memberdata";
import { CommunicationFields1727439800630 } from "./migrations/1727439800630-communicationFields";
import { Ownership1728313041449 } from "./migrations/1728313041449-ownership";
import { protocol } from "./entity/club/protocol/protocol";
import { protocolAgenda } from "./entity/club/protocol/protocolAgenda";
import { protocolDecision } from "./entity/club/protocol/protocolDecision";
import { protocolPresence } from "./entity/club/protocol/protocolPresence";
import { protocolVoting } from "./entity/club/protocol/protocolVoting";
import { protocolPrintout } from "./entity/club/protocol/protocolPrintout";
import { Protocol1729347911107 } from "./migrations/1729347911107-protocol";
import { calendar } from "./entity/club/calendar";
import { calendarType } from "./entity/settings/calendarType";
import { Calendar1729947763295 } from "./migrations/1729947763295-calendar";
import { reset } from "./entity/reset";
import { ResetToken1732358596823 } from "./migrations/1732358596823-resetToken";
import { SMSAlarming1732696919191 } from "./migrations/1732696919191-SMSAlarming";
import { SecuringCalendarType1733249553766 } from "./migrations/1733249553766-securingCalendarType";
import { query } from "./entity/settings/query";
import { QueryStore1734187754677 } from "./migrations/1734187754677-queryStore";
import { memberView } from "./views/memberView";
import { memberExecutivePositionsView } from "./views/memberExecutivePositionView";
import { memberQualificationsView } from "./views/memberQualificationsView";
import { membershipView } from "./views/membershipsView";
import { MemberDataViews1734520998539 } from "./migrations/1734520998539-memberDataViews";
import { template } from "./entity/settings/template";
import { Template1734854680201 } from "./migrations/1734854680201-template";
import { templateUsage } from "./entity/settings/templateUsage";
import { TemplateUsage1734949173739 } from "./migrations/1734949173739-templateUsage";
import { newsletter } from "./entity/club/newsletter/newsletter";
import { newsletterDates } from "./entity/club/newsletter/newsletterDates";
import { newsletterRecipients } from "./entity/club/newsletter/newsletterRecipients";
import { Newsletter1735118780511 } from "./migrations/1735118780511-newsletter";
import { newsletterConfig } from "./entity/settings/newsletterConfig";
import { NewsletterConfig1735207446910 } from "./migrations/1735207446910-newsletterConfig";
import { InternalId1735822722235 } from "./migrations/1735822722235-internalId";
import { PostalCode1735927918979 } from "./migrations/1735927918979-postalCode";
import { ProtocolAbsent1736072179716 } from "./migrations/1736072179716-protocolAbsent";
import { Memberlist1736079005086 } from "./migrations/1736079005086-memberlist";
import { ExtendViewValues1736084198860 } from "./migrations/1736084198860-extendViewValues";
import { FinishInternalIdTransfer1736505324488 } from "./migrations/1736505324488-finishInternalIdTransfer";
import { ProtocolPresenceExcuse1737287798828 } from "./migrations/1737287798828-protocolPresenceExcuse";
import { webapi } from "./entity/user/webapi";
import { webapiPermission } from "./entity/user/webapi_permission";
import { AddWebapiTokens1737453096674 } from "./migrations/1737453096674-addwebapiTokens";
import { salutation } from "./entity/settings/salutation";
import { SalutationAsTable1737796878058 } from "./migrations/1737796878058-salutationAsTable";
import { UpdateViews1737800468938 } from "./migrations/1737800468938-updateViews";
import { MoveSendNewsletterFlag1737816852011 } from "./migrations/1737816852011-moveSendNewsletterFlag";
import { BackupAndResetDatabase1738166124200 } from "./migrations/1738166124200-BackupAndResetDatabase";
import { CreateSchema1738166167472 } from "./migrations/1738166167472-CreateSchema";
const dataSource = new DataSource({
type: DB_TYPE as any,
host: process.env.NODE_ENV || process.env.DBMODE ? "localhost" : DB_HOST,
host: DB_HOST,
port: DB_PORT,
username: DB_USERNAME,
password: DB_PASSWORD,
@ -128,39 +100,7 @@ const dataSource = new DataSource({
webapi,
webapiPermission,
],
migrations: [
Initial1724317398939,
RefreshPrimaryChange1724573307851,
Invite1724579024939,
Permissions1724661484664,
RolePermission1724771491085,
MemberBaseData1725435669492,
Memberdata1726301836849,
CommunicationFields1727439800630,
Ownership1728313041449,
Protocol1729347911107,
Calendar1729947763295,
ResetToken1732358596823,
SMSAlarming1732696919191,
SecuringCalendarType1733249553766,
QueryStore1734187754677,
MemberDataViews1734520998539,
Template1734854680201,
TemplateUsage1734949173739,
Newsletter1735118780511,
NewsletterConfig1735207446910,
InternalId1735822722235,
PostalCode1735927918979,
ProtocolAbsent1736072179716,
Memberlist1736079005086,
ExtendViewValues1736084198860,
FinishInternalIdTransfer1736505324488,
ProtocolPresenceExcuse1737287798828,
AddWebapiTokens1737453096674,
SalutationAsTable1737796878058,
UpdateViews1737800468938,
MoveSendNewsletterFlag1737816852011,
],
migrations: [BackupAndResetDatabase1738166124200, CreateSchema1738166167472],
migrationsRun: true,
migrationsTransactionMode: "each",
subscribers: [],

View file

@ -8,18 +8,20 @@ import {
UpdateDateColumn,
AfterUpdate,
BeforeUpdate,
ColumnType,
} from "typeorm";
import { calendarType } from "../settings/calendarType";
import { getTypeByORM } from "../../migrations/ormHelper";
@Entity()
export class calendar {
@PrimaryGeneratedColumn("uuid")
id: string;
@Column({ type: "datetime", nullable: false })
@Column({ type: getTypeByORM("datetime").type as ColumnType })
starttime: Date;
@Column({ type: "datetime", nullable: false })
@Column({ type: getTypeByORM("datetime").type as ColumnType })
endtime: Date;
@Column({ type: "varchar", length: 255, nullable: false })
@ -43,10 +45,14 @@ export class calendar {
@UpdateDateColumn()
updatedAt: Date;
@Column({ type: "varchar", nullable: true, default: null, unique: true })
webpageId: string;
@ManyToOne(() => calendarType, (t) => t.calendar, {
nullable: false,
onDelete: "RESTRICT",
onUpdate: "RESTRICT",
cascade: ["insert"],
})
type: calendarType;
}

View file

@ -38,7 +38,7 @@ export class communication {
streetNumberAddition: string;
@Column()
memberId: number;
memberId: string;
@Column()
typeId: number;
@ -54,6 +54,7 @@ export class communication {
nullable: false,
onDelete: "RESTRICT",
onUpdate: "RESTRICT",
cascade: ["insert"],
})
type: communicationType;
}

View file

@ -1,15 +1,16 @@
import { Column, Entity, JoinColumn, ManyToOne, OneToMany, OneToOne, PrimaryColumn } from "typeorm";
import { Column, ColumnType, Entity, JoinColumn, ManyToOne, OneToMany, OneToOne, PrimaryColumn } from "typeorm";
import { membership } from "./membership";
import { memberAwards } from "./memberAwards";
import { memberQualifications } from "./memberQualifications";
import { memberExecutivePositions } from "./memberExecutivePositions";
import { communication } from "./communication";
import { salutation } from "../../settings/salutation";
import { getTypeByORM } from "../../../migrations/ormHelper";
@Entity()
export class member {
@PrimaryColumn({ generated: "increment", type: "int" })
id: number;
@PrimaryColumn({ generated: "uuid", type: "varchar" })
id: string;
@Column({ type: "varchar", length: 255 })
firstname: string;
@ -20,7 +21,7 @@ export class member {
@Column({ type: "varchar", length: 255 })
nameaffix: string;
@Column({ type: "date" })
@Column({ type: getTypeByORM("date").type as ColumnType })
birthdate: Date;
@Column({ type: "varchar", length: 255, unique: true, nullable: true })
@ -29,22 +30,27 @@ export class member {
@Column()
salutationId: number;
@OneToMany(() => communication, (communications) => communications.member)
communications: communication[];
@ManyToOne(() => salutation, (salutation) => salutation.members)
@ManyToOne(() => salutation, (salutation) => salutation.members, {
nullable: false,
onDelete: "RESTRICT",
onUpdate: "RESTRICT",
cascade: ["insert"],
})
salutation: salutation;
@OneToMany(() => membership, (membership) => membership.member)
@OneToMany(() => communication, (communications) => communications.member, { cascade: ["insert"] })
communications: communication[];
@OneToMany(() => membership, (membership) => membership.member, { cascade: ["insert"] })
memberships: membership[];
@OneToMany(() => memberAwards, (awards) => awards.member)
@OneToMany(() => memberAwards, (awards) => awards.member, { cascade: ["insert"] })
awards: memberAwards[];
@OneToMany(() => memberExecutivePositions, (executivePositions) => executivePositions.member)
@OneToMany(() => memberExecutivePositions, (executivePositions) => executivePositions.member, { cascade: ["insert"] })
positions: memberExecutivePositions[];
@OneToMany(() => memberQualifications, (qualifications) => qualifications.member)
@OneToMany(() => memberQualifications, (qualifications) => qualifications.member, { cascade: ["insert"] })
qualifications: memberQualifications[];
firstMembershipEntry?: membership;

View file

@ -1,6 +1,7 @@
import { Column, Entity, ManyToOne, PrimaryColumn } from "typeorm";
import { Column, ColumnType, Entity, ManyToOne, PrimaryColumn } from "typeorm";
import { member } from "./member";
import { award } from "../../settings/award";
import { getTypeByORM } from "../../../migrations/ormHelper";
@Entity()
export class memberAwards {
@ -13,11 +14,11 @@ export class memberAwards {
@Column({ type: "varchar", length: 255, nullable: true })
note?: string;
@Column({ type: "date" })
@Column({ type: getTypeByORM("date").type as ColumnType })
date: Date;
@Column()
memberId: number;
memberId: string;
@Column()
awardId: number;
@ -33,6 +34,7 @@ export class memberAwards {
nullable: false,
onDelete: "RESTRICT",
onUpdate: "RESTRICT",
cascade: ["insert"],
})
award: award;
}

View file

@ -1,6 +1,7 @@
import { Column, Entity, ManyToOne, PrimaryColumn } from "typeorm";
import { Column, ColumnType, Entity, ManyToOne, PrimaryColumn } from "typeorm";
import { member } from "./member";
import { executivePosition } from "../../settings/executivePosition";
import { getTypeByORM } from "../../../migrations/ormHelper";
@Entity()
export class memberExecutivePositions {
@ -10,14 +11,14 @@ export class memberExecutivePositions {
@Column({ type: "varchar", length: 255, nullable: true })
note?: string;
@Column({ type: "date" })
@Column({ type: getTypeByORM("date").type as ColumnType })
start: Date;
@Column({ type: "date", nullable: true })
@Column({ type: getTypeByORM("date").type as ColumnType, nullable: true })
end?: Date;
@Column()
memberId: number;
memberId: string;
@Column()
executivePositionId: number;
@ -33,6 +34,7 @@ export class memberExecutivePositions {
nullable: false,
onDelete: "RESTRICT",
onUpdate: "RESTRICT",
cascade: ["insert"],
})
executivePosition: executivePosition;
}

View file

@ -1,6 +1,7 @@
import { Column, Entity, ManyToOne, PrimaryColumn } from "typeorm";
import { Column, ColumnType, Entity, ManyToOne, PrimaryColumn } from "typeorm";
import { member } from "./member";
import { qualification } from "../../settings/qualification";
import { getTypeByORM } from "../../../migrations/ormHelper";
@Entity()
export class memberQualifications {
@ -10,17 +11,17 @@ export class memberQualifications {
@Column({ type: "varchar", length: 255, nullable: true })
note?: string;
@Column({ type: "date" })
@Column({ type: getTypeByORM("date").type as ColumnType })
start: Date;
@Column({ type: "date", nullable: true })
@Column({ type: getTypeByORM("date").type as ColumnType, nullable: true })
end?: Date;
@Column({ type: "varchar", length: 255, nullable: true })
terminationReason?: string;
@Column()
memberId: number;
memberId: string;
@Column()
qualificationId: number;
@ -36,6 +37,7 @@ export class memberQualifications {
nullable: false,
onDelete: "RESTRICT",
onUpdate: "RESTRICT",
cascade: ["insert"],
})
qualification: qualification;
}

View file

@ -1,23 +1,24 @@
import { Column, Entity, JoinColumn, ManyToOne, PrimaryColumn } from "typeorm";
import { Column, ColumnType, Entity, JoinColumn, ManyToOne, PrimaryColumn } from "typeorm";
import { member } from "./member";
import { membershipStatus } from "../../settings/membershipStatus";
import { getTypeByORM } from "../../../migrations/ormHelper";
@Entity()
export class membership {
@PrimaryColumn({ generated: "increment", type: "int" })
id: number;
@Column({ type: "date" })
@Column({ type: getTypeByORM("date").type as ColumnType })
start: Date;
@Column({ type: "date", nullable: true })
@Column({ type: getTypeByORM("date").type as ColumnType, nullable: true })
end?: Date;
@Column({ type: "varchar", length: 255, nullable: true })
terminationReason?: string;
@Column()
memberId: number;
memberId: string;
@Column()
statusId: number;
@ -34,6 +35,7 @@ export class membership {
nullable: false,
onDelete: "RESTRICT",
onUpdate: "RESTRICT",
cascade: ["insert"],
})
@JoinColumn()
status: membershipStatus;

View file

@ -9,7 +9,7 @@ export class newsletter {
@PrimaryColumn({ generated: "increment", type: "int" })
id: number;
@Column({ type: "varchar", length: 255 })
@Column({ type: "varchar", length: 255, unique: true })
title: string;
@Column({ type: "varchar", length: 255, default: "" })
@ -30,16 +30,17 @@ export class newsletter {
@Column({ type: "int", nullable: true })
recipientsByQueryId?: number;
@OneToMany(() => newsletterDates, (dates) => dates.newsletter)
@OneToMany(() => newsletterDates, (dates) => dates.newsletter, { cascade: ["insert"] })
dates: newsletterDates[];
@OneToMany(() => newsletterRecipients, (recipient) => recipient.newsletter)
@OneToMany(() => newsletterRecipients, (recipient) => recipient.newsletter, { cascade: ["insert"] })
recipients: newsletterRecipients[];
@ManyToOne(() => query, {
nullable: true,
onDelete: "CASCADE",
onUpdate: "RESTRICT",
cascade: ["insert"],
})
recipientsByQuery?: query;
}

View file

@ -4,11 +4,11 @@ import { member } from "../member/member";
@Entity()
export class newsletterRecipients {
@PrimaryColumn({ type: "int" })
@PrimaryColumn()
newsletterId: number;
@PrimaryColumn({ type: "int" })
memberId: number;
@PrimaryColumn()
memberId: string;
@ManyToOne(() => newsletter, (newsletter) => newsletter.recipients, {
nullable: false,

View file

@ -1,22 +1,43 @@
import { Column, Entity, PrimaryColumn } from "typeorm";
import { Column, ColumnType, Entity, OneToMany, PrimaryColumn } from "typeorm";
import { protocolAgenda } from "./protocolAgenda";
import { protocolDecision } from "./protocolDecision";
import { protocolPresence } from "./protocolPresence";
import { protocolPrintout } from "./protocolPrintout";
import { protocolVoting } from "./protocolVoting";
import { getTypeByORM } from "../../../migrations/ormHelper";
@Entity()
export class protocol {
@PrimaryColumn({ generated: "increment", type: "int" })
id: number;
@Column({ type: "varchar", length: 255 })
@Column({ type: "varchar", length: 255, unique: true })
title: string;
@Column({ type: "date" })
@Column({ type: getTypeByORM("date").type as ColumnType })
date: Date;
@Column({ type: "time", nullable: true })
@Column({ type: getTypeByORM("time").type as ColumnType, nullable: true })
starttime: Date;
@Column({ type: "time", nullable: true })
@Column({ type: getTypeByORM("time").type as ColumnType, nullable: true })
endtime: Date;
@Column({ type: "text", nullable: true })
summary: string;
@OneToMany(() => protocolAgenda, (agenda) => agenda.protocol, { cascade: ["insert"] })
agendas: protocolAgenda[];
@OneToMany(() => protocolDecision, (decision) => decision.protocol, { cascade: ["insert"] })
decisions: protocolDecision[];
@OneToMany(() => protocolPresence, (presence) => presence.protocol, { cascade: ["insert"] })
presences: protocolPresence[];
@OneToMany(() => protocolPrintout, (printout) => printout.protocol, { cascade: ["insert"] })
printouts: protocolPrintout[];
@OneToMany(() => protocolVoting, (voting) => voting.protocol, { cascade: ["insert"] })
votings: protocolVoting[];
}

View file

@ -5,7 +5,7 @@ import { member } from "../member/member";
@Entity()
export class protocolPresence {
@PrimaryColumn()
memberId: number;
memberId: string;
@PrimaryColumn()
protocolId: number;

View file

@ -1,15 +1,16 @@
import { Column, Entity, ManyToOne, PrimaryColumn } from "typeorm";
import { Column, ColumnType, Entity, ManyToOne, PrimaryColumn } from "typeorm";
import { user } from "./user/user";
import { getTypeByORM } from "../migrations/ormHelper";
@Entity()
export class refresh {
@PrimaryColumn({ type: "varchar", length: 255 })
token: string;
@PrimaryColumn({ type: "int" })
userId: number;
@PrimaryColumn()
userId: string;
@Column({ type: "datetime" })
@Column({ type: getTypeByORM("datetime").type as ColumnType })
expiry: Date;
@ManyToOne(() => user, {

View file

@ -6,7 +6,7 @@ export class award {
@PrimaryColumn({ generated: "increment", type: "int" })
id: number;
@Column({ type: "varchar", length: 255 })
@Column({ type: "varchar", length: 255, unique: true })
award: string;
@OneToMany(() => memberAwards, (member) => member.award)

View file

@ -6,10 +6,10 @@ export class calendarType {
@PrimaryColumn({ generated: "increment", type: "int" })
id: number;
@Column({ type: "varchar", length: 255 })
@Column({ type: "varchar", length: 255, unique: true })
type: string;
@Column({ type: "boolean" }) // none specified cal dav request
@Column({ type: "boolean", default: false }) // none specified cal dav request
nscdr: boolean;
@Column({ type: "varchar", length: 255 })
@ -18,6 +18,12 @@ export class calendarType {
@Column({ type: "varchar", length: 255, nullable: true, default: null })
passphrase: string | null;
@Column({ type: "varchar", length: 255, nullable: false, default: "" })
externalPrefix: string;
@Column({ type: "boolean", default: false })
sendToWebpage: boolean;
@OneToMany(() => calendar, (c) => c.type, {
nullable: false,
onDelete: "RESTRICT",

View file

@ -7,7 +7,7 @@ export class communicationType {
@PrimaryColumn({ generated: "increment", type: "int" })
id: number;
@Column({ type: "varchar", length: 255 })
@Column({ type: "varchar", length: 255, unique: true })
type: string;
@Column({

View file

@ -6,7 +6,7 @@ export class executivePosition {
@PrimaryColumn({ generated: "increment", type: "int" })
id: number;
@Column({ type: "varchar", length: 255 })
@Column({ type: "varchar", length: 255, unique: true })
position: string;
@OneToMany(() => memberExecutivePositions, (memberExecutivePositions) => memberExecutivePositions.executivePosition)

View file

@ -6,7 +6,7 @@ export class membershipStatus {
@PrimaryColumn({ generated: "increment", type: "int" })
id: number;
@Column({ type: "varchar", length: 255 })
@Column({ type: "varchar", length: 255, unique: true })
status: string;
@OneToMany(() => membership, (membership) => membership.status)

View file

@ -4,7 +4,7 @@ import { communicationType } from "./communicationType";
@Entity()
export class newsletterConfig {
@PrimaryColumn({ type: "int" })
@PrimaryColumn()
comTypeId: number;
@Column({
@ -25,6 +25,7 @@ export class newsletterConfig {
nullable: false,
onDelete: "CASCADE",
onUpdate: "RESTRICT",
cascade: ["insert"],
})
comType: communicationType;
}

View file

@ -6,7 +6,7 @@ export class qualification {
@PrimaryColumn({ generated: "increment", type: "int" })
id: number;
@Column({ type: "varchar", length: 255 })
@Column({ type: "varchar", length: 255, unique: true })
qualification: string;
@Column({ type: "varchar", length: 255, nullable: true })

View file

@ -5,7 +5,7 @@ export class template {
@PrimaryColumn({ generated: "increment", type: "int" })
id: number;
@Column({ type: "varchar", length: 255 })
@Column({ type: "varchar", length: 255, unique: true })
template: string;
@Column({ type: "varchar", length: 255, nullable: true })

View file

@ -7,7 +7,7 @@ export class role {
@PrimaryColumn({ generated: "increment", type: "int" })
id: number;
@Column({ type: "varchar", length: 255 })
@Column({ type: "varchar", length: 255, unique: true })
role: string;
@ManyToMany(() => user, (user) => user.roles, {
@ -17,6 +17,6 @@ export class role {
})
users: user[];
@OneToMany(() => rolePermission, (rolePermission) => rolePermission.role)
@OneToMany(() => rolePermission, (rolePermission) => rolePermission.role, { cascade: ["insert"] })
permissions: rolePermission[];
}

View file

@ -4,13 +4,13 @@ import { userPermission } from "./user_permission";
@Entity()
export class user {
@PrimaryColumn({ generated: "increment", type: "int" })
id: number;
@PrimaryColumn({ generated: "uuid", type: "varchar" })
id: string;
@Column({ type: "varchar", length: 255 })
@Column({ type: "varchar", unique: true, length: 255 })
mail: string;
@Column({ type: "varchar", length: 255 })
@Column({ type: "varchar", unique: true, length: 255 })
username: string;
@Column({ type: "varchar", length: 255 })
@ -22,6 +22,9 @@ export class user {
@Column({ type: "varchar", length: 255 })
secret: string;
@Column({ type: "boolean", default: false })
static: boolean;
@Column({ type: "boolean", default: false })
isOwner: boolean;
@ -29,12 +32,13 @@ export class user {
nullable: false,
onDelete: "CASCADE",
onUpdate: "RESTRICT",
cascade: ["insert"],
})
@JoinTable({
name: "user_roles",
})
roles: role[];
@OneToMany(() => userPermission, (userPermission) => userPermission.user)
@OneToMany(() => userPermission, (userPermission) => userPermission.user, { cascade: ["insert"] })
permissions: userPermission[];
}

View file

@ -4,8 +4,8 @@ import { PermissionObject, PermissionString } from "../../type/permissionTypes";
@Entity()
export class userPermission {
@PrimaryColumn({ type: "int" })
userId: number;
@PrimaryColumn()
userId: string;
@PrimaryColumn({ type: "varchar", length: 255 })
permission: PermissionString;

View file

@ -1,5 +1,6 @@
import { Column, CreateDateColumn, Entity, OneToMany, PrimaryColumn } from "typeorm";
import { Column, ColumnType, CreateDateColumn, Entity, OneToMany, PrimaryColumn } from "typeorm";
import { webapiPermission } from "./webapi_permission";
import { getTypeByORM } from "../../migrations/ormHelper";
@Entity()
export class webapi {
@ -15,12 +16,12 @@ export class webapi {
@CreateDateColumn()
createdAt: Date;
@Column({ type: "datetime", nullable: true })
@Column({ type: getTypeByORM("datetime").type as ColumnType, nullable: true })
lastUsage?: Date;
@Column({ type: "date", nullable: true })
@Column({ type: getTypeByORM("date").type as ColumnType, nullable: true })
expiry?: Date;
@OneToMany(() => webapiPermission, (apiPermission) => apiPermission.webapi)
@OneToMany(() => webapiPermission, (apiPermission) => apiPermission.webapi, { cascade: ["insert"] })
permissions: webapiPermission[];
}

View file

@ -24,12 +24,20 @@ export const MAIL_SECURE = process.env.MAIL_SECURE ?? "false";
export const CLUB_NAME = process.env.CLUB_NAME ?? "FF Admin";
export const CLUB_WEBSITE = process.env.CLUB_WEBSITE ?? "";
export const BACKUP_INTERVAL = Number(process.env.BACKUP_INTERVAL ?? "0");
export const BACKUP_COPIES = Number(process.env.BACKUP_COPIES ?? "0");
export const BACKUP_AUTO_RESTORE = process.env.BACKUP_AUTO_RESTORE ?? "true";
export function configCheck() {
if (DB_TYPE != "mysql" && DB_TYPE != "sqlite") throw new Error("set valid value to DB_TYPE (mysql|sqlite)");
if (DB_HOST == "" || typeof DB_HOST != "string") throw new Error("set valid value to DB_HOST");
if (DB_TYPE != "mysql" && DB_TYPE != "sqlite" && DB_TYPE != "postgres")
throw new Error("set valid value to DB_TYPE (mysql|sqlite|postgres)");
if ((DB_HOST == "" || typeof DB_HOST != "string") && DB_TYPE != "sqlite")
throw new Error("set valid value to DB_HOST");
if (DB_NAME == "" || typeof DB_NAME != "string") throw new Error("set valid value to DB_NAME");
if (DB_USERNAME == "" || typeof DB_USERNAME != "string") throw new Error("set valid value to DB_USERNAME");
if (DB_PASSWORD == "" || typeof DB_PASSWORD != "string") throw new Error("set valid value to DB_PASSWORD");
if ((DB_USERNAME == "" || typeof DB_USERNAME != "string") && DB_TYPE != "sqlite")
throw new Error("set valid value to DB_USERNAME");
if ((DB_PASSWORD == "" || typeof DB_PASSWORD != "string") && DB_TYPE != "sqlite")
throw new Error("set valid value to DB_PASSWORD");
if (typeof SERVER_PORT != "number") throw new Error("set valid numeric value to SERVER_PORT");
@ -49,6 +57,9 @@ export function configCheck() {
!/^(http(s):\/\/.)[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/.test(CLUB_WEBSITE)
)
throw new Error("CLUB_WEBSITE is not valid url");
if (BACKUP_AUTO_RESTORE != "true" && BACKUP_AUTO_RESTORE != "false")
throw new Error("set 'true' or 'false' to BACKUP_AUTO_RESTORE");
}
function checkMS(input: string, origin: string) {

View file

@ -0,0 +1,8 @@
import CustomRequestException from "./customRequestException";
export default class DatabaseActionException extends CustomRequestException {
constructor(action: string, table: string, err: any) {
let errstring = `${action} on ${table} with ${err?.code ?? "XX"} at ${err?.sqlMessage ?? "XX"}`;
super(500, errstring, err);
}
}

View file

@ -51,6 +51,7 @@ export default abstract class MemberFactory {
public static mapToMemberStatistic(record: memberView): MemberStatisticsViewModel {
return {
id: record.id,
internalId: record.internalId,
salutation: record.salutation,
firstname: record.firstname,
lastname: record.lastname,

View file

@ -40,6 +40,7 @@ export default abstract class MembershipFactory {
return {
durationInDays: record.durationInDays,
durationInYears: record.durationInYears,
exactDuration: record.exactDuration,
status: record.status,
statusId: record.statusId,
memberId: record.memberId,

741
src/helpers/backupHelper.ts Normal file
View file

@ -0,0 +1,741 @@
import { dataSource } from "../data-source";
import { FileSystemHelper } from "./fileSystemHelper";
import { EntityManager } from "typeorm";
import uniqBy from "lodash.uniqby";
import InternalException from "../exceptions/internalException";
import UserService from "../service/user/userService";
export type BackupSection =
| "member"
| "memberBase"
| "protocol"
| "newsletter"
| "newsletter_config"
| "calendar"
| "query"
| "template"
| "user"
| "webapi";
export type BackupSectionRefered = {
[key in BackupSection]?: Array<string>;
};
export type BackupFileContent = { [key in BackupSection]?: BackupFileContentSection } & {
backup_file_details: { collectIds: boolean; createdAt: Date; version: 1 };
};
export type BackupFileContentSection = Array<any> | { [key: string]: Array<any> };
export default abstract class BackupHelper {
// ! Order matters because of foreign keys
private static readonly backupSection: Array<{ type: BackupSection; orderOnInsert: number; orderOnClear: number }> = [
{ type: "member", orderOnInsert: 2, orderOnClear: 2 }, // CLEAR depends on protcol INSERT depends on Base
{ type: "memberBase", orderOnInsert: 1, orderOnClear: 3 }, // CLEAR depends on member
{ type: "protocol", orderOnInsert: 3, orderOnClear: 1 }, // INSERT depends on member
{ type: "newsletter", orderOnInsert: 3, orderOnClear: 1 }, // INSERT depends on member & query & calendar
{ type: "newsletter_config", orderOnInsert: 2, orderOnClear: 4 }, // INSERT depends on member com
{ type: "calendar", orderOnInsert: 1, orderOnClear: 1 },
{ type: "query", orderOnInsert: 1, orderOnClear: 2 }, // CLEAR depends on newsletter
{ type: "template", orderOnInsert: 2, orderOnClear: 1 }, // INSERT depends on member com
{ type: "user", orderOnInsert: 1, orderOnClear: 1 },
{ type: "webapi", orderOnInsert: 1, orderOnClear: 1 },
];
private static readonly backupSectionRefered: BackupSectionRefered = {
member: [
"member",
"member_awards",
"member_qualifications",
"member_executive_positions",
"membership",
"communication",
],
memberBase: [
"award",
"qualification",
"executive_position",
"membership_status",
"communication_type",
"salutation",
],
protocol: [
"protocol",
"protocol_agenda",
"protocol_decision",
"protocol_presence",
"protocol_printout",
"protocol_voting",
],
newsletter: ["newsletter", "newsletter_dates", "newsletter_recipients", "newsletter_config"],
newsletter_config: ["newsletter_config"],
calendar: ["calendar", "calendar_type"],
query: ["query"],
template: ["template", "template_usage"],
user: ["user", "user_permission", "role", "role_permission", "invite"],
webapi: ["webapi", "webapi_permission"],
};
private static transactionManager: EntityManager;
static async createBackup({
filename,
path = "/backup",
collectIds = true,
}: {
filename?: string;
path?: string;
collectIds?: boolean;
}): Promise<void> {
if (!filename) {
filename = new Date().toISOString().split("T")[0];
}
let json: BackupFileContent = { backup_file_details: { collectIds, createdAt: new Date(), version: 1 } };
for (const section of this.backupSection) {
json[section.type] = await this.getSectionData(section.type, collectIds);
}
FileSystemHelper.writeFile(path, filename + ".json", JSON.stringify(json, null, 2));
// TODO: delete older backups by copies env
}
static async loadBackup({
filename,
path = "/backup",
include = [],
partial = false,
}: {
filename: string;
path?: string;
partial?: boolean;
include?: Array<BackupSection>;
}): Promise<void> {
this.transactionManager = undefined;
let file = FileSystemHelper.readFile(`${path}/${filename}`);
let backup: BackupFileContent = JSON.parse(file);
if ((partial && include.length == 0) || (!partial && include.length != 0)) {
throw new InternalException("partial and include have to be set correctly for restoring backup.");
}
await dataSource.manager
.transaction(async (transaction) => {
this.transactionManager = transaction;
const sections = this.backupSection
.filter((bs) => (partial ? include.includes(bs.type) : true))
.sort((a, b) => a.orderOnClear - b.orderOnClear);
for (const section of sections.filter((s) => Object.keys(backup).includes(s.type))) {
let refered = this.backupSectionRefered[section.type];
for (const ref of refered) {
await this.transactionManager.getRepository(ref).delete({});
}
}
for (const section of sections
.filter((s) => Object.keys(backup).includes(s.type))
.sort((a, b) => a.orderOnInsert - b.orderOnInsert)) {
await this.setSectionData(section.type, backup[section.type], backup.backup_file_details.collectIds ?? false);
}
this.transactionManager = undefined;
})
.catch((err) => {
this.transactionManager = undefined;
throw new InternalException("failed to restore backup - rolling back actions", err);
});
}
public static async autoRestoreBackup() {
let count = await UserService.count();
if (count == 0) {
let files = FileSystemHelper.getFilesInDirectory("/backup", ".json");
let newestFile = files.sort(
(a, b) => new Date(b.split(".")[0]).getTime() - new Date(a.split(".")[0]).getTime()
)[0];
if (newestFile) {
console.log(`${new Date().toISOString()}: auto-restoring ${newestFile}`);
await this.loadBackup({ filename: newestFile });
console.log(`${new Date().toISOString()}: finished auto-restore`);
} else {
console.log(`${new Date().toISOString()}: skip auto-restore as no backup was found`);
}
} else {
console.log(`${new Date().toISOString()}: skip auto-restore as users exist`);
}
}
private static async getSectionData(
section: BackupSection,
collectIds: boolean
): Promise<Array<any> | { [key: string]: any }> {
switch (section) {
case "member":
return await this.getMemberData(collectIds);
case "memberBase":
return await this.getMemberBase();
case "protocol":
return await this.getProtocol(collectIds);
case "newsletter":
return await this.getNewsletter(collectIds);
case "newsletter_config":
return await this.getNewsletterConfig();
case "calendar":
return await this.getCalendar();
case "query":
return await this.getQueryStore();
case "template":
return await this.getTemplate();
case "user":
return await this.getUser(collectIds);
case "webapi":
return await this.getWebapi();
default:
return [];
}
}
private static async getMemberData(collectIds: boolean): Promise<Array<any>> {
return await dataSource
.getRepository("member")
.createQueryBuilder("member")
.leftJoin("member.salutation", "salutation")
.leftJoin("member.communications", "communication")
.leftJoin("communication.type", "communicationType")
.leftJoin("member.memberships", "memberships")
.leftJoin("memberships.status", "membershipStatus")
.leftJoin("member.awards", "awards")
.leftJoin("awards.award", "award")
.leftJoin("member.positions", "positions")
.leftJoin("positions.executivePosition", "executivePosition")
.leftJoin("member.qualifications", "qualifications")
.leftJoin("qualifications.qualification", "qualification")
.select([
...(collectIds ? ["member.id"] : []),
"member.firstname",
"member.lastname",
"member.nameaffix",
"member.birthdate",
"member.internalId",
])
.addSelect(["salutation.salutation"])
.addSelect([
"communication.preferred",
"communication.isSMSAlarming",
"communication.isSendNewsletter",
"communication.mobile",
"communication.email",
"communication.postalCode",
"communication.city",
"communication.street",
"communication.streetNumber",
"communication.streetNumberAddition",
"communicationType.type",
"communicationType.useColumns",
])
.addSelect(["memberships.start", "memberships.end", "memberships.terminationReason", "membershipStatus.status"])
.addSelect(["awards.given", "awards.note", "awards.note", "awards.date", "award.award"])
.addSelect(["positions.note", "positions.start", "positions.end", "executivePosition.position"])
.addSelect([
"qualifications.note",
"qualifications.start",
"qualifications.end",
"qualifications.terminationReason",
"qualification.qualification",
"qualification.description",
])
.getMany();
}
private static async getMemberBase(): Promise<{ [key: string]: Array<any> }> {
return {
award: await dataSource.getRepository("award").find({ select: { award: true } }),
communication_type: await dataSource
.getRepository("communication_type")
.find({ select: { type: true, useColumns: true } }),
executive_position: await dataSource.getRepository("executive_position").find({ select: { position: true } }),
membership_status: await dataSource.getRepository("membership_status").find({ select: { status: true } }),
salutation: await dataSource.getRepository("salutation").find({ select: { salutation: true } }),
qualification: await dataSource
.getRepository("qualification")
.find({ select: { qualification: true, description: true } }),
};
}
private static async getProtocol(collectIds: boolean): Promise<Array<any>> {
return await dataSource
.getRepository("protocol")
.createQueryBuilder("protocol")
.leftJoin("protocol.agendas", "agendas")
.leftJoin("protocol.decisions", "decisions")
.leftJoin("protocol.presences", "presences")
.leftJoin("presences.member", "member")
.leftJoin("protocol.printouts", "printouts")
.leftJoin("protocol.votings", "votings")
.select(["protocol.title", "protocol.date", "protocol.starttime", "protocol.endtime", "protocol.summary"])
.addSelect(["agendas.topic", "agendas.context"])
.addSelect(["decisions.topic", "decisions.context"])
.addSelect(["presences.absent", "presences.excused"])
.addSelect([
...(collectIds ? ["member.id"] : []),
"member.firstname",
"member.lastname",
"member.nameaffix",
"member.birthdate",
"member.internalId",
])
.addSelect(["printouts.title", "printouts.iteration", "printouts.filename", "printouts.createdAt"])
.addSelect(["votings.topic", "votings.context", "votings.favour", "votings.abstain", "votings.against"])
.getMany();
}
private static async getNewsletter(collectIds: boolean): Promise<Array<any>> {
return await dataSource
.getRepository("newsletter")
.createQueryBuilder("newsletter")
.leftJoin("newsletter.dates", "dates")
.leftJoin("newsletter.recipients", "recipients")
.leftJoin("recipients.member", "member")
.leftJoin("newsletter.recipientsByQuery", "recipientsByQuery")
.select([
"newsletter.title",
"newsletter.description",
"newsletter.newsletterTitle",
"newsletter.newsletterText",
"newsletter.newsletterSignatur",
"newsletter.isSent",
])
.addSelect(["dates.calendarId", "dates.diffTitle", "dates.diffDescription"])
.addSelect([
...(collectIds ? ["member.id"] : []),
"member.firstname",
"member.lastname",
"member.nameaffix",
"member.birthdate",
"member.internalId",
])
.addSelect(["recipientsByQuery.title", "recipientsByQuery.query"])
.getMany();
}
private static async getNewsletterConfig(): Promise<Array<any>> {
return await dataSource
.getRepository("newsletter_config")
.createQueryBuilder("newsletter_config")
.leftJoin("newsletter_config.comType", "comType")
.select(["newsletter_config.config"])
.addSelect(["comType.type", "comType.useColumns"])
.getMany();
}
private static async getCalendar(): Promise<{ [key: string]: Array<any> }> {
return {
calendar: await dataSource
.getRepository("calendar")
.createQueryBuilder("calendar")
.leftJoin("calendar.type", "type")
.select([
"calendar.id",
"calendar.starttime",
"calendar.endtime",
"calendar.title",
"calendar.content",
"calendar.location",
"calendar.allDay",
"calendar.sequence",
"calendar.createdAt",
"calendar.updatedAt",
])
.addSelect(["type.type", "type.nscdr", "type.color", "type.passphrase"])
.getMany(),
calendar_type: await dataSource
.getRepository("calendar_type")
.createQueryBuilder("calendar_type")
.select(["calendar_type.type", "calendar_type.nscdr", "calendar_type.color", "calendar_type.passphrase"])
.getMany(),
};
}
private static async getQueryStore(): Promise<Array<any>> {
return await dataSource.getRepository("query").find({ select: { title: true, query: true } });
}
private static async getTemplate(): Promise<{ [key: string]: Array<any> }> {
return {
template: await dataSource
.getRepository("template")
.find({ select: { template: true, description: true, design: true, html: true } }),
template_usage: await dataSource
.getRepository("template_usage")
.createQueryBuilder("template_usage")
.leftJoin("template_usage.header", "header")
.leftJoin("template_usage.body", "body")
.leftJoin("template_usage.footer", "footer")
.select(["template_usage.scope", "template_usage.headerHeight", "template_usage.footerHeight"])
.addSelect(["header.template", "header.description", "header.design", "header.html"])
.addSelect(["body.template", "body.description", "body.design", "body.html"])
.addSelect(["footer.template", "footer.description", "footer.design", "footer.html"])
.getMany(),
};
}
private static async getUser(collectIds: boolean): Promise<{ [key: string]: Array<any> }> {
return {
user: await dataSource
.getRepository("user")
.createQueryBuilder("user")
.leftJoin("user.roles", "roles")
.leftJoin("roles.permissions", "role_permissions")
.leftJoin("user.permissions", "permissions")
.select([
...(collectIds ? ["user.id"] : []),
"user.mail",
"user.username",
"user.firstname",
"user.lastname",
"user.secret",
"user.isOwner",
])
.addSelect(["permissions.permission"])
.addSelect(["roles.role"])
.addSelect(["role_permissions.permission"])
.getMany(),
role: await dataSource
.getRepository("role")
.createQueryBuilder("role")
.leftJoin("role.permissions", "permissions")
.addSelect(["role.role"])
.addSelect(["permissions.permission"])
.getMany(),
invite: await dataSource.getRepository("invite").find(),
};
}
private static async getWebapi(): Promise<Array<any>> {
return await dataSource
.getRepository("webapi")
.createQueryBuilder("webapi")
.leftJoin("webapi.permissions", "permissions")
.select(["webapi.token", "webapi.title", "webapi.createdAt", "webapi.lastUsage", "webapi.expiry"])
.addSelect(["permissions.permission"])
.getMany();
}
private static async setSectionData(
section: BackupSection,
data: BackupFileContentSection,
collectedIds: boolean
): Promise<void> {
if (section == "member" && Array.isArray(data)) await this.setMemberData(data);
if (section == "memberBase" && !Array.isArray(data)) await this.setMemberBase(data);
if (section == "protocol" && Array.isArray(data)) await this.setProtocol(data, collectedIds);
if (section == "newsletter" && Array.isArray(data)) await this.setNewsletter(data, collectedIds);
if (section == "newsletter_config" && Array.isArray(data)) await this.setNewsletterConfig(data);
if (section == "calendar" && !Array.isArray(data)) await this.setCalendar(data);
if (section == "query" && Array.isArray(data)) await this.setQueryStore(data);
if (section == "template" && !Array.isArray(data)) await this.setTemplate(data);
if (section == "user" && !Array.isArray(data)) await this.setUser(data);
if (section == "webapi" && Array.isArray(data)) await this.setWebapi(data);
}
private static async setMemberData(data: Array<any>): Promise<void> {
await this.setMemberBase({
award: uniqBy(
data
.map((d) => d.awards.map((c: any) => c.award))
.flat()
.map((d) => ({ ...d, id: undefined })),
"award"
),
communication_type: uniqBy(
data
.map((d) => d.communications.map((c: any) => c.type))
.flat()
.map((d) => ({ ...d, id: undefined })),
"type"
),
executive_position: uniqBy(
data
.map((d) => d.positions.map((c: any) => c.executivePosition))
.flat()
.map((d) => ({ ...d, id: undefined })),
"position"
),
membership_status: uniqBy(
data
.map((d) => d.memberships.map((c: any) => c.status))
.flat()
.map((d) => ({ ...d, id: undefined })),
"status"
),
salutation: uniqBy(
data.map((d) => d.salutation).map((d) => ({ ...d, id: undefined })),
"salutation"
),
qualification: uniqBy(
data
.map((d) => d.qualifications.map((c: any) => c.qualification))
.flat()
.map((d) => ({ ...d, id: undefined })),
"qualification"
),
});
let salutation = await this.transactionManager.getRepository("salutation").find();
let communication = await this.transactionManager.getRepository("communication_type").find();
let membership = await this.transactionManager.getRepository("membership_status").find();
let award = await this.transactionManager.getRepository("award").find();
let qualification = await this.transactionManager.getRepository("qualification").find();
let position = await this.transactionManager.getRepository("executive_position").find();
let dataWithMappedIds = data.map((d) => ({
...d,
salutation: {
...d.salutation,
id: salutation.find((s) => s.salutation == d.salutation.salutation)?.id ?? undefined,
},
communications: d.communications.map((c: any) => ({
...c,
type: {
...c.type,
id: communication.find((s) => s.type == c.type.type)?.id ?? undefined,
},
})),
memberships: d.memberships.map((m: any) => ({
...m,
status: {
...m.status,
id: membership.find((ms) => ms.status == m.status.status)?.id ?? undefined,
},
})),
awards: d.awards.map((a: any) => ({
...a,
award: {
...a.award,
id: award.find((ia) => ia.award == a.award.award)?.id ?? undefined,
},
})),
positions: d.positions.map((p: any) => ({
...p,
executivePosition: {
...p.executivePosition,
id: position.find((ip) => ip.position == p.executivePosition.position)?.id ?? undefined,
},
})),
qualifications: d.qualifications.map((q: any) => ({
...q,
qualification: {
...q.qualification,
id: qualification.find((iq) => iq.qualification == q.qualification.qualification)?.id ?? undefined,
},
})),
}));
await this.transactionManager.getRepository("member").save(dataWithMappedIds);
}
private static async setMemberBase(data: { [key: string]: Array<any> }): Promise<void> {
let salutation = await this.transactionManager.getRepository("salutation").find();
let communication = await this.transactionManager.getRepository("communication_type").find();
let membership = await this.transactionManager.getRepository("membership_status").find();
let award = await this.transactionManager.getRepository("award").find();
let qualification = await this.transactionManager.getRepository("qualification").find();
let position = await this.transactionManager.getRepository("executive_position").find();
await this.transactionManager
.createQueryBuilder()
.insert()
.into("award")
.values((data?.["award"] ?? []).filter((d) => !award.map((a) => a.award).includes(d.award)))
.orIgnore()
.execute();
await this.transactionManager
.createQueryBuilder()
.insert()
.into("communication_type")
.values((data?.["communication_type"] ?? []).filter((d) => !communication.map((c) => c.type).includes(d.type)))
.orIgnore()
.execute();
await this.transactionManager
.createQueryBuilder()
.insert()
.into("executive_position")
.values((data?.["executive_position"] ?? []).filter((d) => !position.map((p) => p.position).includes(d.position)))
.orIgnore()
.execute();
await this.transactionManager
.createQueryBuilder()
.insert()
.into("membership_status")
.values((data?.["membership_status"] ?? []).filter((d) => !membership.map((m) => m.status).includes(d.status)))
.orIgnore()
.execute();
await this.transactionManager
.createQueryBuilder()
.insert()
.into("salutation")
.values((data?.["salutation"] ?? []).filter((d) => !salutation.map((s) => s.salutation).includes(d.salutation)))
.orIgnore()
.execute();
await this.transactionManager
.createQueryBuilder()
.insert()
.into("qualification")
.values(
(data?.["qualification"] ?? []).filter((d) => !qualification.map((q) => q.award).includes(d.qualification))
)
.orIgnore()
.execute();
}
private static async setProtocol(data: Array<any>, collectedIds: boolean): Promise<void> {
let members = await this.transactionManager.getRepository("member").find();
let dataWithMappedIds = data.map((d) => ({
...d,
...(!collectedIds
? {
presences: d.presences.map((p: any) => ({
...p,
memberId:
members.find(
(m) =>
m.firstname == p.member.firstname &&
m.lastname == p.member.lastname &&
m.nameaffix == p.member.nameaffix &&
m.birthdate == p.member.birthdate &&
m.internalId == p.member.internalId
)?.id ?? undefined,
member: null,
})),
}
: {}),
}));
await this.transactionManager.getRepository("protocol").save(dataWithMappedIds);
}
private static async setNewsletter(data: Array<any>, collectedIds: boolean): Promise<void> {
await this.setQueryStore(
uniqBy(
data.map((d) => d.recipientsByQueryId).map((d) => ({ ...d, id: undefined })),
"query"
)
);
let queries = await this.transactionManager.getRepository("query").find();
let members = await this.transactionManager.getRepository("member").find();
let dataWithMappedIds = data.map((d) => ({
...d,
recipientsByQueryId: {
...d.recipientsByQueryId,
id: queries.find((s) => s.query == d.recipientsByQueryId.query)?.id ?? undefined,
},
...(!collectedIds
? {
recipients: d.recipients.map((r: any) => ({
...r,
memberId:
members.find(
(m) =>
m.firstname == r.member.firstname &&
m.lastname == r.member.lastname &&
m.nameaffix == r.member.nameaffix &&
m.birthdate == r.member.birthdate &&
m.internalId == r.member.internalId
)?.id ?? undefined,
member: null,
})),
}
: {}),
}));
await this.transactionManager.getRepository("newsletter").save(dataWithMappedIds);
}
private static async setNewsletterConfig(data: Array<any>): Promise<void> {
await this.setMemberBase({
communication_type: uniqBy(
data.map((d) => d.comType).map((d) => ({ ...d, id: undefined })),
"type"
),
});
let types = await this.transactionManager.getRepository("communication_type").find();
let dataWithMappedIds = data.map((d) => ({
...d,
comType: {
...d.comType,
id: types.find((type) => type.type == d.comType.type)?.id ?? undefined,
},
}));
await this.transactionManager.getRepository("newsletter_config").save(dataWithMappedIds);
}
private static async setCalendar(data: { [key: string]: Array<any> }): Promise<void> {
let usedTypes = (data?.["calendar"] ?? []).map((d) => d.type).map((d) => ({ ...d, id: undefined }));
await this.transactionManager
.createQueryBuilder()
.insert()
.into("award")
.values(uniqBy([...(data?.["calendar_type"] ?? []), ...usedTypes], "type"))
.orIgnore()
.execute();
let types = await this.transactionManager.getRepository("calendar_type").find();
let dataWithMappedIds = (data?.["calendar"] ?? []).map((c) => ({
...c,
type: {
...c.type,
id: types.find((type) => type.type == c.type.type)?.id ?? undefined,
},
}));
await this.transactionManager.getRepository("calendar").save(dataWithMappedIds);
}
private static async setQueryStore(data: Array<any>): Promise<void> {
let query = await this.transactionManager.getRepository("query").find();
await this.transactionManager
.createQueryBuilder()
.insert()
.into("query")
.values(data.filter((d) => !query.map((s) => s.query).includes(d.query)))
.orIgnore()
.execute();
}
private static async setTemplate(data: { [key: string]: Array<any> }): Promise<void> {
await this.transactionManager
.createQueryBuilder()
.insert()
.into("template")
.values(data?.["template"] ?? [])
.orIgnore()
.execute();
await this.transactionManager
.createQueryBuilder()
.insert()
.into("template_usage")
.values(data?.["template_usage"] ?? [])
.orUpdate(["headerId", "bodyId", "footerId", "headerHeight", "footerHeight"], ["scope"])
.execute();
}
private static async setUser(data: { [key: string]: Array<any> }): Promise<void> {
let usedRoles = (data?.["user"] ?? [])
.map((d) => d.roles)
.flat()
.map((d) => ({ ...d, id: undefined }));
await this.transactionManager
.createQueryBuilder()
.insert()
.into("role")
.values(uniqBy([...(data?.["role"] ?? []), ...usedRoles], "role"))
.orIgnore()
.execute();
let roles = await this.transactionManager.getRepository("role").find();
let dataWithMappedIds = (data?.["user"] ?? []).map((u) => ({
...u,
roles: u.roles.map((r: any) => ({
...r,
id: roles.find((role) => role.role == r.role)?.id ?? undefined,
})),
}));
await this.transactionManager.getRepository("user").save(dataWithMappedIds);
await this.transactionManager
.createQueryBuilder()
.insert()
.into("invite")
.values(data["invite"])
.orIgnore()
.execute();
}
private static async setWebapi(data: Array<any>): Promise<void> {
await this.transactionManager.getRepository("webapi").save(data);
}
}

View file

@ -50,7 +50,7 @@ export abstract class JWTHelper {
});
}
static async buildToken(id: number): Promise<string> {
static async buildToken(id: string): Promise<string> {
let { firstname, lastname, mail, username, isOwner } = await UserService.getById(id);
let userPermissions = await UserPermissionService.getByUser(id);
let userPermissionStrings = userPermissions.map((e) => e.permission);
@ -86,7 +86,7 @@ export abstract class JWTHelper {
let permissionObject = PermissionHelper.convertToObject(webapiPermissionStrings);
let jwtData: JWTToken = {
userId: id,
userId: id.toString(),
mail: "",
username: title,
firstname: "",

View file

@ -121,7 +121,7 @@ export abstract class NewsletterHelper {
): Promise<Array<member>> {
let useQuery = newsletter.recipientsByQuery?.query;
let queryMemberIds: Array<number> = [];
let queryMemberIds: Array<string> = [];
if (useQuery) {
let result = await DynamicQueryBuilder.executeQuery(
useQuery.startsWith("{") ? JSON.parse(useQuery) : useQuery,
@ -131,7 +131,7 @@ export abstract class NewsletterHelper {
if (result.stats == "success") {
let keys = Object.keys(result.rows?.[0] ?? {});
let memberKey = keys.find((k) => k.includes("member_id"));
queryMemberIds = result.rows.map((t) => parseInt((t[memberKey] ?? t.id) as string));
queryMemberIds = result.rows.map((t) => (t[memberKey] ?? t.id) as string);
}
}
@ -253,7 +253,7 @@ export abstract class NewsletterHelper {
for (const [index, rec] of [
...pdfRecipients,
{ id: 0, firstname: "Alle Mitglieder", lastname: CLUB_NAME } as member,
{ id: "0", firstname: "Alle Mitglieder", lastname: CLUB_NAME } as member,
].entries()) {
let data = this.buildData(newsletter, dates, rec, printWithAdress.includes(rec.sendNewsletter?.type?.id));

View file

@ -32,6 +32,19 @@ export default class PermissionHelper {
return false;
}
static canSome(
permissions: PermissionObject,
checks: Array<{
requiredPermissions: PermissionType | "admin";
section: PermissionSection;
module?: PermissionModule;
}>
) {
checks.reduce<boolean>((prev, curr) => {
return prev || this.can(permissions, curr.requiredPermissions, curr.section, curr.module);
}, false);
}
static canSection(
permissions: PermissionObject,
type: PermissionType | "admin",
@ -48,6 +61,18 @@ export default class PermissionHelper {
return false;
}
static canSomeSection(
permissions: PermissionObject,
checks: Array<{
requiredPermissions: PermissionType | "admin";
section: PermissionSection;
}>
): boolean {
return checks.reduce<boolean>((prev, curr) => {
return prev || this.can(permissions, curr.requiredPermissions, curr.section);
}, false);
}
static passCheckMiddleware(
requiredPermissions: PermissionType | "admin",
section: PermissionSection,
@ -60,11 +85,29 @@ export default class PermissionHelper {
if (isOwner || this.can(permissions, requiredPermissions, section, module)) {
next();
} else {
throw new ForbiddenRequestException(
`missing permission for ${section}.${module}.${
Array.isArray(requiredPermissions) ? requiredPermissions.join("|") : requiredPermissions
}`
);
throw new ForbiddenRequestException(`missing permission for ${section}.${module}.${requiredPermissions}`);
}
};
}
static passCheckSomeMiddleware(
checks: Array<{
requiredPermissions: PermissionType | "admin";
section: PermissionSection;
module?: PermissionModule;
}>
): (req: Request, res: Response, next: Function) => void {
return (req: Request, res: Response, next: Function) => {
const permissions = req.permissions;
const isOwner = req.isOwner;
if (isOwner || this.canSome(permissions, checks)) {
next();
} else {
let permissionsToPass = checks.reduce<string>((prev, curr) => {
return prev + (prev != " or " ? "" : "") + `${curr.section}.${curr.module}.${curr.requiredPermissions}`;
}, "");
throw new ForbiddenRequestException(`missing permission for ${permissionsToPass}`);
}
};
}
@ -80,11 +123,25 @@ export default class PermissionHelper {
if (isOwner || this.canSection(permissions, requiredPermissions, section)) {
next();
} else {
throw new ForbiddenRequestException(
`missing permission for ${section}.${module}.${
Array.isArray(requiredPermissions) ? requiredPermissions.join("|") : requiredPermissions
}`
);
throw new ForbiddenRequestException(`missing permission for ${section}.${module}.${requiredPermissions}`);
}
};
}
static sectionPassCheckSomeMiddleware(
checks: Array<{ requiredPermissions: PermissionType | "admin"; section: PermissionSection }>
): (req: Request, res: Response, next: Function) => void {
return (req: Request, res: Response, next: Function) => {
const permissions = req.permissions;
const isOwner = req.isOwner;
if (isOwner || this.canSomeSection(permissions, checks)) {
next();
} else {
let permissionsToPass = checks.reduce<string>((prev, curr) => {
return prev + (prev != " or " ? "" : "") + `${curr.section}.${curr.requiredPermissions}`;
}, "");
throw new ForbiddenRequestException(`missing permission for ${permissionsToPass}`);
}
};
}

View file

@ -1,7 +1,7 @@
import "dotenv/config";
import express from "express";
import { configCheck, SERVER_PORT } from "./env.defaults";
import { BACKUP_AUTO_RESTORE, configCheck, SERVER_PORT } from "./env.defaults";
configCheck();
import { PermissionObject } from "./type/permissionTypes";
@ -19,18 +19,26 @@ declare global {
}
import { dataSource } from "./data-source";
dataSource.initialize();
import BackupHelper from "./helpers/backupHelper";
dataSource.initialize().then(async () => {
if ((BACKUP_AUTO_RESTORE as "true" | "false") == "true" && (await dataSource.createQueryRunner().hasTable("user"))) {
await BackupHelper.autoRestoreBackup().catch((err) => {
console.log(`${new Date().toISOString()}: failed auto-restoring database`);
});
}
});
const app = express();
import router from "./routes/index";
router(app);
app.listen(process.env.NODE_ENV ? SERVER_PORT : 5000, () => {
console.log(`listening on *:${process.env.NODE_ENV ? SERVER_PORT : 5000}`);
console.log(`${new Date().toISOString()}: listening on port ${process.env.NODE_ENV ? SERVER_PORT : 5000}`);
});
import schedule from "node-schedule";
import RefreshCommandHandler from "./command/refreshCommandHandler";
const job = schedule.scheduleJob("0 0 * * *", async () => {
console.log(`running Cron at ${new Date()}`);
console.log(`${new Date().toISOString()}: running Cron`);
await RefreshCommandHandler.deleteExpired();
// TODO: create backup by interval env
});

View file

@ -1,55 +0,0 @@
import { MigrationInterface, QueryRunner, Table, TableForeignKey } from "typeorm";
import { DB_TYPE } from "../env.defaults";
export class Initial1724317398939 implements MigrationInterface {
name = "Initial1724317398939";
public async up(queryRunner: QueryRunner): Promise<void> {
const variableType_int = DB_TYPE == "mysql" ? "int" : "integer";
await queryRunner.createTable(
new Table({
name: "user",
columns: [
{ name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "mail", type: "varchar", length: "255", isNullable: false },
{ name: "username", type: "varchar", length: "255", isNullable: false },
{ name: "secret", type: "varchar", length: "255", isNullable: false },
],
}),
true
);
await queryRunner.createTable(
new Table({
name: "refresh",
columns: [
{ name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "token", type: "varchar", length: "255", isNullable: false },
{ name: "expiry", type: "datetime", isNullable: false },
{ name: "userId", type: variableType_int, isNullable: false },
],
}),
true
);
await queryRunner.createForeignKey(
"refresh",
new TableForeignKey({
columnNames: ["userId"],
referencedColumnNames: ["id"],
referencedTableName: "user",
onDelete: "CASCADE",
onUpdate: "RESTRICT",
})
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const table = await queryRunner.getTable("refresh");
const foreignKey = table.foreignKeys.find((fk) => fk.columnNames.indexOf("userId") !== -1);
await queryRunner.dropForeignKey("refresh", foreignKey);
await queryRunner.dropTable("refresh");
await queryRunner.dropTable("user");
}
}

View file

@ -1,28 +0,0 @@
import { MigrationInterface, QueryRunner, TableColumn } from "typeorm";
import { DB_TYPE } from "../env.defaults";
export class RefreshPrimaryChange1724573307851 implements MigrationInterface {
name = "RefreshPrimaryChange1724573307851";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumn("refresh", "id");
await queryRunner.createPrimaryKey("refresh", ["token", "userId"]);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const variableType_int = DB_TYPE == "mysql" ? "int" : "integer";
await queryRunner.dropPrimaryKey("refresh");
await queryRunner.addColumn(
"refresh",
new TableColumn({
name: "id",
type: variableType_int,
isPrimary: true,
isNullable: false,
isGenerated: true,
generationStrategy: "increment",
})
);
}
}

View file

@ -1,42 +0,0 @@
import { MigrationInterface, QueryRunner, Table, TableColumn } from "typeorm";
export class Invite1724579024939 implements MigrationInterface {
name = "Invite1724579024939";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.createTable(
new Table({
name: "invite",
columns: [
{ name: "mail", type: "varchar", length: "255", isPrimary: true, isNullable: false },
{ name: "token", type: "varchar", length: "255", isNullable: false },
{ name: "username", type: "varchar", length: "255", isNullable: false },
{ name: "firstname", type: "varchar", length: "255", isNullable: false },
{ name: "lastname", type: "varchar", length: "255", isNullable: false },
{ name: "secret", type: "varchar", length: "255", isNullable: false },
],
}),
true
);
await queryRunner.addColumns("user", [
new TableColumn({
name: "firstname",
type: "varchar",
length: "255",
isNullable: false,
}),
new TableColumn({
name: "lastname",
type: "varchar",
length: "255",
isNullable: false,
}),
]);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.dropColumns("user", ["lastname", "firstname"]);
await queryRunner.dropTable("invite");
}
}

View file

@ -1,45 +0,0 @@
import { MigrationInterface, QueryRunner, Table, TableForeignKey } from "typeorm";
import { DB_TYPE } from "../env.defaults";
export class Permissions1724661484664 implements MigrationInterface {
name = "Permissions1724661484664";
public async up(queryRunner: QueryRunner): Promise<void> {
const variableType_int = DB_TYPE == "mysql" ? "int" : "integer";
await queryRunner.createTable(
new Table({
name: "permission",
columns: [
{
name: "permission",
type: "varchar",
length: "255",
isPrimary: true,
isNullable: false,
},
{ name: "userId", type: variableType_int, isPrimary: true, isNullable: false },
],
}),
true
);
await queryRunner.createForeignKey(
"permission",
new TableForeignKey({
columnNames: ["userId"],
referencedColumnNames: ["id"],
referencedTableName: "user",
onDelete: "CASCADE",
onUpdate: "RESTRICT",
})
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const table = await queryRunner.getTable("permission");
const foreignKey = table.foreignKeys.find((fk) => fk.columnNames.indexOf("userId") !== -1);
await queryRunner.dropForeignKey("permission", foreignKey);
await queryRunner.dropTable("permission");
}
}

View file

@ -1,116 +0,0 @@
import { MigrationInterface, QueryRunner, Table, TableForeignKey, TableIndex } from "typeorm";
import { DB_TYPE } from "../env.defaults";
export class RolePermission1724771491085 implements MigrationInterface {
name = "RolePermission1724771491085";
public async up(queryRunner: QueryRunner): Promise<void> {
const variableType_int = DB_TYPE == "mysql" ? "int" : "integer";
await queryRunner.createTable(
new Table({
name: "role",
columns: [
{ name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "role", type: "varchar", length: "255", isNullable: false },
],
}),
true
);
await queryRunner.createTable(
new Table({
name: "role_permission",
columns: [
{
name: "permission",
type: "varchar",
length: "255",
isPrimary: true,
isNullable: false,
},
{ name: "roleId", type: variableType_int, isPrimary: true, isNullable: false },
],
}),
true
);
await queryRunner.renameTable("permission", "user_permission");
await queryRunner.createTable(
new Table({
name: "user_roles",
columns: [
{ name: "userId", type: variableType_int, isPrimary: true, isNullable: false },
{ name: "roleId", type: variableType_int, isPrimary: true, isNullable: false },
],
}),
true
);
await queryRunner.createForeignKey(
"role_permission",
new TableForeignKey({
columnNames: ["roleId"],
referencedColumnNames: ["id"],
referencedTableName: "role",
onDelete: "CASCADE",
onUpdate: "RESTRICT",
})
);
await queryRunner.createForeignKey(
"user_roles",
new TableForeignKey({
columnNames: ["userId"],
referencedColumnNames: ["id"],
referencedTableName: "user",
onDelete: "CASCADE",
onUpdate: "RESTRICT",
})
);
await queryRunner.createForeignKey(
"user_roles",
new TableForeignKey({
columnNames: ["roleId"],
referencedColumnNames: ["id"],
referencedTableName: "role",
onDelete: "CASCADE",
onUpdate: "RESTRICT",
})
);
await queryRunner.createIndex(
"user_roles",
new TableIndex({
columnNames: ["userId"],
})
);
await queryRunner.createIndex(
"user_roles",
new TableIndex({
columnNames: ["roleId"],
})
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const user_roles = await queryRunner.getTable("user_roles");
const roles_foreignKey = user_roles.foreignKeys.find((fk) => fk.columnNames.indexOf("roleId") !== -1);
const user_foreignKey = user_roles.foreignKeys.find((fk) => fk.columnNames.indexOf("userId") !== -1);
await queryRunner.dropForeignKey("user_roles", roles_foreignKey);
await queryRunner.dropForeignKey("user_roles", user_foreignKey);
await queryRunner.dropTable("user_roles");
const role_permission = await queryRunner.getTable("role_permission");
const permission_foreignKey = role_permission.foreignKeys.find((fk) => fk.columnNames.indexOf("roleId") !== -1);
await queryRunner.dropForeignKey("role_permission", permission_foreignKey);
await queryRunner.dropTable("role_permission");
await queryRunner.dropTable("role");
await queryRunner.renameTable("user_permission", "permission");
}
}

View file

@ -1,109 +0,0 @@
import { MigrationInterface, QueryRunner, Table, TableForeignKey } from "typeorm";
import { DB_TYPE } from "../env.defaults";
export class MemberBaseData1725435669492 implements MigrationInterface {
name = "MemberBaseData1725435669492";
public async up(queryRunner: QueryRunner): Promise<void> {
const variableType_int = DB_TYPE == "mysql" ? "int" : "integer";
await queryRunner.createTable(
new Table({
name: "award",
columns: [
{ name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "award", type: "varchar", length: "255", isNullable: false },
],
}),
true
);
await queryRunner.createTable(
new Table({
name: "communication_type",
columns: [
{ name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "type", type: "varchar", length: "255", isNullable: false },
{ name: "useColumns", type: "varchar", length: "255", isNullable: false, default: "''" },
],
}),
true
);
await queryRunner.createTable(
new Table({
name: "communication",
columns: [
{ name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "preferred", type: "tinyint", isNullable: false, default: 0 },
{ name: "mobile", type: "varchar", length: "255", isNullable: false },
{ name: "email", type: "varchar", length: "255", isNullable: false },
{ name: "city", type: "varchar", length: "255", isNullable: false },
{ name: "street", type: "varchar", length: "255", isNullable: false },
{ name: "streetNumber", type: variableType_int, isNullable: false },
{ name: "streetNumberAddition", type: "varchar", length: "255", isNullable: false },
{ name: "typeId", type: variableType_int, isNullable: false },
],
}),
true
);
await queryRunner.createTable(
new Table({
name: "executive_position",
columns: [
{ name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "position", type: "varchar", length: "255", isNullable: false },
],
}),
true
);
await queryRunner.createTable(
new Table({
name: "membership_status",
columns: [
{ name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "status", type: "varchar", length: "255", isNullable: false },
],
}),
true
);
await queryRunner.createTable(
new Table({
name: "qualification",
columns: [
{ name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "qualification", type: "varchar", length: "255", isNullable: false },
{ name: "description", type: "varchar", length: "255", isNullable: true },
],
}),
true
);
await queryRunner.createForeignKey(
"communication",
new TableForeignKey({
columnNames: ["typeId"],
referencedColumnNames: ["id"],
referencedTableName: "communication_type",
onDelete: "RESTRICT",
onUpdate: "RESTRICT",
})
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const communication = await queryRunner.getTable("communication");
const foreignKey = communication.foreignKeys.find((fk) => fk.columnNames.indexOf("typeId") !== -1);
await queryRunner.dropForeignKey("communication", foreignKey);
await queryRunner.dropTable("qualification");
await queryRunner.dropTable("membership_status");
await queryRunner.dropTable("executive_position");
await queryRunner.dropTable("communication");
await queryRunner.dropTable("communication_type");
await queryRunner.dropTable("award");
}
}

View file

@ -1,258 +0,0 @@
import { MigrationInterface, QueryRunner, Table, TableColumn, TableForeignKey } from "typeorm";
import { DB_TYPE } from "../env.defaults";
export class Memberdata1726301836849 implements MigrationInterface {
name = "Memberdata1726301836849";
public async up(queryRunner: QueryRunner): Promise<void> {
const variableType_int = DB_TYPE == "mysql" ? "int" : "integer";
await queryRunner.createTable(
new Table({
name: "membership",
columns: [
{ name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "internalId", type: "varchar", length: "255", isNullable: true },
{ name: "start", type: "date", isNullable: false },
{ name: "end", type: "date", isNullable: true },
{ name: "terminationReason", type: "varchar", length: "255", isNullable: true },
{ name: "memberId", type: variableType_int, isNullable: false },
{ name: "statusId", type: variableType_int, isNullable: false },
],
uniques: [{ name: "IDX_703f499fe3a9892e3a8790cdfc", columnNames: ["internalId"] }],
}),
true
);
await queryRunner.createTable(
new Table({
name: "member_qualifications",
columns: [
{ name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "note", type: "varchar", length: "255", isNullable: true },
{ name: "start", type: "date", isNullable: false },
{ name: "end", type: "date", isNullable: true },
{ name: "terminationReason", type: "varchar", length: "255", isNullable: true },
{ name: "memberId", type: variableType_int, isNullable: false },
{ name: "qualificationId", type: variableType_int, isNullable: false },
],
}),
true
);
await queryRunner.createTable(
new Table({
name: "member_executive_positions",
columns: [
{ name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "note", type: "varchar", length: "255", isNullable: true },
{ name: "start", type: "date", isNullable: false },
{ name: "end", type: "date", isNullable: true },
{ name: "memberId", type: variableType_int, isNullable: false },
{ name: "executivePositionId", type: variableType_int, isNullable: false },
],
}),
true
);
await queryRunner.createTable(
new Table({
name: "member",
columns: [
{ name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "salutation", type: "varchar", length: "255", default: "'none'", isNullable: false },
{ name: "firstname", type: "varchar", length: "255", isNullable: false },
{ name: "lastname", type: "varchar", length: "255", isNullable: false },
{ name: "nameaffix", type: "varchar", length: "255", isNullable: false },
{ name: "birthdate", type: "date", isNullable: false },
{ name: "sendNewsletterId", type: variableType_int, isNullable: true },
],
uniques: [{ name: "REL_d57e160c4513cd949159217281", columnNames: ["sendNewsletterId"] }],
}),
true
);
await queryRunner.createTable(
new Table({
name: "member_awards",
columns: [
{ name: "id", type: variableType_int, isPrimary: true, isGenerated: true, generationStrategy: "increment" },
{ name: "given", type: "tinyint", default: 1, isNullable: false },
{ name: "note", type: "varchar", length: "255", isNullable: true },
{ name: "date", type: "date", isNullable: false },
{ name: "memberId", type: variableType_int, isNullable: false },
{ name: "awardId", type: variableType_int, isNullable: false },
],
}),
true
);
await queryRunner.addColumn(
"communication",
new TableColumn({ name: "memberId", type: variableType_int, isNullable: false })
);
await queryRunner.createForeignKey(
"membership",
new TableForeignKey({
columnNames: ["memberId"],
referencedTableName: "member",
referencedColumnNames: ["id"],
onDelete: "CASCADE",
onUpdate: "RESTRICT",
})
);
await queryRunner.createForeignKey(
"membership",
new TableForeignKey({
columnNames: ["statusId"],
referencedTableName: "membership_status",
referencedColumnNames: ["id"],
onDelete: "RESTRICT",
onUpdate: "RESTRICT",
})
);
await queryRunner.createForeignKey(
"member_qualifications",
new TableForeignKey({
columnNames: ["memberId"],
referencedTableName: "member",
referencedColumnNames: ["id"],
onDelete: "CASCADE",
onUpdate: "RESTRICT",
})
);
await queryRunner.createForeignKey(
"member_qualifications",
new TableForeignKey({
columnNames: ["qualificationId"],
referencedTableName: "qualification",
referencedColumnNames: ["id"],
onDelete: "RESTRICT",
onUpdate: "RESTRICT",
})
);
await queryRunner.createForeignKey(
"member_executive_positions",
new TableForeignKey({
columnNames: ["memberId"],
referencedTableName: "member",
referencedColumnNames: ["id"],
onDelete: "CASCADE",
onUpdate: "RESTRICT",
})
);
await queryRunner.createForeignKey(
"member_executive_positions",
new TableForeignKey({
columnNames: ["executivePositionId"],
referencedTableName: "executive_position",
referencedColumnNames: ["id"],
onDelete: "RESTRICT",
onUpdate: "RESTRICT",
})
);
await queryRunner.createForeignKey(
"communication",
new TableForeignKey({
columnNames: ["memberId"],
referencedTableName: "member",
referencedColumnNames: ["id"],
onDelete: "CASCADE",
onUpdate: "RESTRICT",
})
);
await queryRunner.createForeignKey(
"member",
new TableForeignKey({
columnNames: ["sendNewsletterId"],
referencedTableName: "communication",
referencedColumnNames: ["id"],
onDelete: "SET NULL",
onUpdate: "RESTRICT",
})
);
await queryRunner.createForeignKey(
"member_awards",
new TableForeignKey({
columnNames: ["memberId"],
referencedTableName: "member",
referencedColumnNames: ["id"],
onDelete: "CASCADE",
onUpdate: "RESTRICT",
})
);
await queryRunner.createForeignKey(
"member_awards",
new TableForeignKey({
columnNames: ["awardId"],
referencedTableName: "award",
referencedColumnNames: ["id"],
onDelete: "RESTRICT",
onUpdate: "RESTRICT",
})
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
const member = await queryRunner.getTable("member");
const memeberForeignKey = member.foreignKeys.find((fk) => fk.columnNames.indexOf("sendNewsletterId") !== -1);
await queryRunner.dropForeignKey("member", memeberForeignKey);
const member_awards = await queryRunner.getTable("member_awards");
const memeberAwardsForeignKeyMember = member_awards.foreignKeys.find(
(fk) => fk.columnNames.indexOf("memberId") !== -1
);
const memeberAwardsForeignKeyAward = member_awards.foreignKeys.find(
(fk) => fk.columnNames.indexOf("awardId") !== -1
);
await queryRunner.dropForeignKey("member_awards", memeberAwardsForeignKeyMember);
await queryRunner.dropForeignKey("member_awards", memeberAwardsForeignKeyAward);
const communication = await queryRunner.getTable("communication");
const communicationForeignKey = communication.foreignKeys.find((fk) => fk.columnNames.indexOf("memberId") !== -1);
await queryRunner.dropForeignKey("communication", communicationForeignKey);
const member_executive_positions = await queryRunner.getTable("member_executive_positions");
const memeberExecutivePositionForeignKeyMember = member_executive_positions.foreignKeys.find(
(fk) => fk.columnNames.indexOf("memberId") !== -1
);
const memeberExecutivePositionForeignKeyPosition = member_executive_positions.foreignKeys.find(
(fk) => fk.columnNames.indexOf("executivePositionId") !== -1
);
await queryRunner.dropForeignKey("member_executive_positions", memeberExecutivePositionForeignKeyMember);
await queryRunner.dropForeignKey("member_executive_positions", memeberExecutivePositionForeignKeyPosition);
const member_qualifications = await queryRunner.getTable("member_qualifications");
const memeberQualificationForeignKeyMember = member_qualifications.foreignKeys.find(
(fk) => fk.columnNames.indexOf("memberId") !== -1
);
const memeberQualificationForeignKeyQualification = member_qualifications.foreignKeys.find(
(fk) => fk.columnNames.indexOf("qualificationId") !== -1
);
await queryRunner.dropForeignKey("member_qualifications", memeberQualificationForeignKeyMember);
await queryRunner.dropForeignKey("member_qualifications", memeberQualificationForeignKeyQualification);
const membership = await queryRunner.getTable("membership");
const membershipForeignKeyMember = membership.foreignKeys.find((fk) => fk.columnNames.indexOf("memberId") !== -1);
const membershipForeignKeyStatus = membership.foreignKeys.find((fk) => fk.columnNames.indexOf("statusId") !== -1);
await queryRunner.dropForeignKey("membership", membershipForeignKeyMember);
await queryRunner.dropForeignKey("membership", membershipForeignKeyStatus);
await queryRunner.dropColumn("communication", "memberId");
await queryRunner.dropTable("member_awards");
await queryRunner.dropTable("member");
await queryRunner.dropTable("member_executive_positions");
await queryRunner.dropTable("member_qualifications");
await queryRunner.dropTable("membership");
}
}

View file

@ -1,140 +0,0 @@
import { MigrationInterface, QueryRunner } from "typeorm";
import { TableColumn } from "typeorm";
export class CommunicationFields1727439800630 implements MigrationInterface {
name = "CommunicationFields1727439800630";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.changeColumn(
"communication",
"mobile",
new TableColumn({
name: "mobile",
type: "varchar",
length: "255",
isNullable: true,
})
);
await queryRunner.changeColumn(
"communication",
"email",
new TableColumn({
name: "email",
type: "varchar",
length: "255",
isNullable: true,
})
);
await queryRunner.changeColumn(
"communication",
"city",
new TableColumn({
name: "city",
type: "varchar",
length: "255",
isNullable: true,
})
);
await queryRunner.changeColumn(
"communication",
"street",
new TableColumn({
name: "street",
type: "varchar",
length: "255",
isNullable: true,
})
);
await queryRunner.changeColumn(
"communication",
"streetNumber",
new TableColumn({
name: "streetNumber",
type: "int",
isNullable: true,
})
);
await queryRunner.changeColumn(
"communication",
"streetNumberAddition",
new TableColumn({
name: "streetNumberAddition",
type: "varchar",
length: "255",
isNullable: true,
})
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.changeColumn(
"communication",
"mobile",
new TableColumn({
name: "mobile",
type: "varchar",
length: "255",
isNullable: false,
})
);
await queryRunner.changeColumn(
"communication",
"email",
new TableColumn({
name: "email",
type: "varchar",
length: "255",
isNullable: false,
})
);
await queryRunner.changeColumn(
"communication",
"city",
new TableColumn({
name: "city",
type: "varchar",
length: "255",
isNullable: false,
})
);
await queryRunner.changeColumn(
"communication",
"street",
new TableColumn({
name: "street",
type: "varchar",
length: "255",
isNullable: false,
})
);
await queryRunner.changeColumn(
"communication",
"streetNumber",
new TableColumn({
name: "streetNumber",
type: "int",
isNullable: false,
})
);
await queryRunner.changeColumn(
"communication",
"streetNumberAddition",
new TableColumn({
name: "streetNumberAddition",
type: "varchar",
length: "255",
isNullable: false,
})
);
}
}

View file

@ -1,56 +0,0 @@
import { MigrationInterface, QueryRunner, TableColumn } from "typeorm";
export class Ownership1728313041449 implements MigrationInterface {
name = "Ownership1728313041449";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.addColumn(
"user",
new TableColumn({
name: "isOwner",
type: "tinyint",
default: 0,
isNullable: false,
})
);
await queryRunner.manager
.createQueryBuilder()
.update("user")
.set({ isOwner: 1 })
.where((qb) => {
const subQuery = queryRunner.manager
.createQueryBuilder()
.select("1")
.from("user_permission", "up")
.where("user.id = up.userId")
.andWhere("up.permission = '*'")
.getQuery();
return `EXISTS (${subQuery})`;
})
.execute();
await queryRunner.manager.createQueryBuilder().delete().from("user_permission").where("permission = '*'").execute();
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.manager
.createQueryBuilder()
.insert()
.into("user_permission")
.values(
await queryRunner.manager
.createQueryBuilder()
.select("user.id", "userId")
.addSelect("'*'", "permission")
.from("user", "user")
.where("user.isOwner = 1")
.execute()
)
.execute();
await queryRunner.manager.createQueryBuilder().update("user").set({ isOwner: 0 }).where("isOwner = 1").execute();
await queryRunner.dropColumn("user", "isOwner");
}
}

Some files were not shown because too many files have changed in this diff Show more