@stamhoofd/backend 2.91.0 → 2.93.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/package.json +10 -10
  2. package/src/audit-logs/EmailLogger.ts +6 -6
  3. package/src/crons/amazon-ses.ts +100 -4
  4. package/src/crons/balance-emails.ts +1 -1
  5. package/src/crons/endFunctionsOfUsersWithoutRegistration.ts +6 -0
  6. package/src/email-recipient-loaders/receivable-balances.ts +3 -1
  7. package/src/endpoints/global/email/CreateEmailEndpoint.ts +37 -7
  8. package/src/endpoints/global/email/GetAdminEmailsEndpoint.ts +205 -0
  9. package/src/endpoints/global/email/GetEmailEndpoint.ts +5 -1
  10. package/src/endpoints/global/email/PatchEmailEndpoint.test.ts +404 -8
  11. package/src/endpoints/global/email/PatchEmailEndpoint.ts +81 -26
  12. package/src/endpoints/global/email-recipients/GetEmailRecipientsCountEndpoint.ts +47 -0
  13. package/src/endpoints/global/email-recipients/GetEmailRecipientsEndpoint.test.ts +225 -0
  14. package/src/endpoints/global/email-recipients/GetEmailRecipientsEndpoint.ts +164 -0
  15. package/src/endpoints/global/email-recipients/helpers/validateEmailRecipientFilter.ts +64 -0
  16. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +5 -1
  17. package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +19 -1
  18. package/src/endpoints/organization/dashboard/webshops/DeleteWebshopEndpoint.ts +10 -1
  19. package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +8 -1
  20. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +2 -67
  21. package/src/helpers/AdminPermissionChecker.ts +81 -5
  22. package/src/helpers/EmailResumer.ts +2 -2
  23. package/src/seeds/1752848560-groups-registration-periods.ts +768 -0
  24. package/src/seeds/1755532883-update-email-sender-ids.ts +47 -0
  25. package/src/seeds/1755790070-fill-email-recipient-errors.ts +96 -0
  26. package/src/seeds/1755876819-remove-duplicate-members.ts +145 -0
  27. package/src/seeds/1756115432-remove-old-drafts.ts +16 -0
  28. package/src/seeds/1756115433-fill-email-recipient-organization-id.ts +30 -0
  29. package/src/services/uitpas/UitpasService.ts +71 -2
  30. package/src/services/uitpas/checkUitpasNumbers.ts +1 -0
  31. package/src/sql-filters/email-recipients.ts +59 -0
  32. package/src/sql-filters/emails.ts +95 -0
  33. package/src/sql-filters/members.ts +42 -1
  34. package/src/sql-filters/registration-periods.ts +5 -0
  35. package/src/sql-sorters/email-recipients.ts +69 -0
  36. package/src/sql-sorters/emails.ts +47 -0
@@ -1,6 +1,6 @@
1
1
  import { AutoEncoderPatchType, PatchMap } from '@simonbackx/simple-encoding';
2
2
  import { isSimpleError, isSimpleErrors, SimpleError } from '@simonbackx/simple-errors';
3
- import { BalanceItem, CachedBalance, Document, EmailTemplate, Event, EventNotification, Group, Member, MemberPlatformMembership, MemberWithRegistrations, Order, Organization, OrganizationRegistrationPeriod, Payment, Registration, User, Webshop } from '@stamhoofd/models';
3
+ import { BalanceItem, CachedBalance, Document, Email, EmailTemplate, Event, EventNotification, Group, Member, MemberPlatformMembership, MemberWithRegistrations, Order, Organization, OrganizationRegistrationPeriod, Payment, Registration, User, Webshop } from '@stamhoofd/models';
4
4
  import { AccessRight, EmailTemplate as EmailTemplateStruct, EventPermissionChecker, FinancialSupportSettings, GroupCategory, GroupStatus, GroupType, MemberWithRegistrationsBlob, PermissionLevel, PermissionsResourceType, Platform as PlatformStruct, RecordSettings, ResourcePermissions } from '@stamhoofd/structures';
5
5
  import { Formatter } from '@stamhoofd/utility';
6
6
  import { MemberRecordStore } from '../services/MemberRecordStore';
@@ -709,7 +709,7 @@ export class AdminPermissionChecker {
709
709
  }
710
710
 
711
711
  if (!template.organizationId) {
712
- return this.hasPlatformFullAccess();
712
+ return this.hasPlatformFullAccess() || !!this.platformPermissions?.hasAccessRight(AccessRight.ManageEmailTemplates);
713
713
  }
714
714
 
715
715
  if (await this.hasFullAccess(template.organizationId)) {
@@ -734,6 +734,11 @@ export class AdminPermissionChecker {
734
734
  return true;
735
735
  }
736
736
 
737
+ const o = await this.getOrganizationPermissions(template.organizationId);
738
+ if (o && o.hasAccessRight(AccessRight.ManageEmailTemplates)) {
739
+ return true;
740
+ }
741
+
737
742
  return false;
738
743
  }
739
744
 
@@ -845,8 +850,79 @@ export class AdminPermissionChecker {
845
850
  return this.hasSomeAccess(organizationId);
846
851
  }
847
852
 
848
- canSendEmails() {
849
- return !!this.user.permissions;
853
+ async canSendEmails(organizationId: Organization | string | null) {
854
+ if (organizationId) {
855
+ return (await this.getOrganizationPermissions(organizationId))?.hasAccessRightForSomeResourceOfType(PermissionsResourceType.Senders, AccessRight.SendMessages) ?? false;
856
+ }
857
+ return this.platformPermissions?.hasAccessRightForSomeResourceOfType(PermissionsResourceType.Senders, AccessRight.SendMessages) ?? false;
858
+ }
859
+
860
+ /**
861
+ * Fast check if this user can read at least one email in the system.
862
+ */
863
+ async canReadEmails(organizationId: Organization | string | null) {
864
+ if (await this.canSendEmails(organizationId)) {
865
+ // A user can reads its own emails, so they can read.
866
+ return true;
867
+ }
868
+ if (organizationId) {
869
+ return (await this.getOrganizationPermissions(organizationId))?.hasAccessForSomeResourceOfType(PermissionsResourceType.Senders, PermissionLevel.Read) ?? false;
870
+ }
871
+ return this.platformPermissions?.hasAccessForSomeResourceOfType(PermissionsResourceType.Senders, PermissionLevel.Read) ?? false;
872
+ }
873
+
874
+ async canReadAllEmails(organizationId: Organization | string | null, senderId = ''): Promise<boolean> {
875
+ if (organizationId) {
876
+ return (await this.getOrganizationPermissions(organizationId))?.hasResourceAccess(PermissionsResourceType.Senders, senderId, PermissionLevel.Read) ?? false;
877
+ }
878
+ return this.platformPermissions?.hasResourceAccess(PermissionsResourceType.Senders, senderId, PermissionLevel.Read) ?? false;
879
+ }
880
+
881
+ async canAccessEmail(email: Email, level: PermissionLevel = PermissionLevel.Read): Promise<boolean> {
882
+ if (!this.checkScope(email.organizationId)) {
883
+ return false;
884
+ }
885
+
886
+ if (email.userId === this.user.id) {
887
+ // User can always read their own emails
888
+ // Note; for sending we'll always need to use 'canSendEmailsFrom' externally
889
+ return true;
890
+ }
891
+
892
+ if (email.organizationId) {
893
+ const organizationPermissions = await this.getOrganizationPermissions(email.organizationId);
894
+ if (!organizationPermissions) {
895
+ return false;
896
+ }
897
+ if (!email.senderId) {
898
+ return organizationPermissions.hasResourceAccess(PermissionsResourceType.Senders, '', level);
899
+ }
900
+ return organizationPermissions.hasResourceAccess(PermissionsResourceType.Senders, email.senderId, level);
901
+ }
902
+
903
+ // Platform email
904
+ const platformPermissions = this.platformPermissions;
905
+ if (!platformPermissions) {
906
+ return false;
907
+ }
908
+ if (!email.senderId) {
909
+ return platformPermissions.hasResourceAccess(PermissionsResourceType.Senders, '', level);
910
+ }
911
+ return platformPermissions.hasResourceAccess(PermissionsResourceType.Senders, email.senderId, level);
912
+ }
913
+
914
+ async canSendEmail(email: Email): Promise<boolean> {
915
+ if (email.senderId) {
916
+ return await this.canSendEmailsFrom(email.organizationId, email.senderId);
917
+ }
918
+ return await this.canSendEmails(email.organizationId);
919
+ }
920
+
921
+ async canSendEmailsFrom(organizationId: Organization | string | null, senderId: string): Promise<boolean> {
922
+ if (organizationId) {
923
+ return (await this.getOrganizationPermissions(organizationId))?.hasResourceAccessRight(PermissionsResourceType.Senders, senderId, AccessRight.SendMessages) ?? false;
924
+ }
925
+ return this.platformPermissions?.hasResourceAccessRight(PermissionsResourceType.Senders, senderId, AccessRight.SendMessages) ?? false;
850
926
  }
851
927
 
852
928
  async canReadEmailTemplates(organizationId: string) {
@@ -909,7 +985,7 @@ export class AdminPermissionChecker {
909
985
  */
910
986
  async hasSomeAccess(organizationOrId: string | Organization): Promise<boolean> {
911
987
  const organizationPermissions = await this.getOrganizationPermissions(organizationOrId);
912
- return !!organizationPermissions;
988
+ return !!organizationPermissions && !organizationPermissions.isEmpty;
913
989
  }
914
990
 
915
991
  async canManageAdmins(organizationId: string) {
@@ -6,7 +6,7 @@ import { ContextInstance } from './Context';
6
6
  export async function resumeEmails() {
7
7
  const query = SQL.select()
8
8
  .from(SQL.table(Email.table))
9
- .where(SQL.column('status'), EmailStatus.Sending);
9
+ .where(SQL.column('status'), [EmailStatus.Sending, EmailStatus.Queued]);
10
10
 
11
11
  const result = await query.fetch();
12
12
  const emails = Email.fromRows(result, Email.table);
@@ -28,7 +28,7 @@ export async function resumeEmails() {
28
28
 
29
29
  try {
30
30
  await ContextInstance.startForUser(user, organization, async () => {
31
- await email.send();
31
+ await email.resumeSending();
32
32
  });
33
33
  }
34
34
  catch (e) {