@stamhoofd/backend 2.39.1 → 2.40.1

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 (198) hide show
  1. package/eslint.config.mjs +5 -0
  2. package/index.ts +81 -74
  3. package/jest.config.cjs +10 -0
  4. package/migrations.ts +16 -14
  5. package/package.json +11 -11
  6. package/src/crons/clear-excel-cache.test.ts +48 -50
  7. package/src/crons/clear-excel-cache.ts +18 -18
  8. package/src/crons/setup-steps.ts +2 -2
  9. package/src/crons.ts +325 -306
  10. package/src/decoders/StringArrayDecoder.ts +7 -7
  11. package/src/decoders/StringNullableDecoder.ts +1 -2
  12. package/src/email-recipient-loaders/members.ts +22 -22
  13. package/src/endpoints/admin/memberships/ChargeMembershipsEndpoint.ts +8 -9
  14. package/src/endpoints/admin/memberships/GetChargeMembershipsSummaryEndpoint.ts +39 -40
  15. package/src/endpoints/admin/organizations/GetOrganizationsCountEndpoint.ts +8 -8
  16. package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +44 -45
  17. package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +58 -57
  18. package/src/endpoints/auth/CreateAdminEndpoint.ts +48 -45
  19. package/src/endpoints/auth/CreateTokenEndpoint.test.ts +31 -31
  20. package/src/endpoints/auth/CreateTokenEndpoint.ts +146 -147
  21. package/src/endpoints/auth/DeleteTokenEndpoint.ts +7 -7
  22. package/src/endpoints/auth/DeleteUserEndpoint.ts +15 -15
  23. package/src/endpoints/auth/ForgotPasswordEndpoint.ts +17 -18
  24. package/src/endpoints/auth/GetOtherUserEndpoint.ts +9 -10
  25. package/src/endpoints/auth/GetUserEndpoint.test.ts +32 -35
  26. package/src/endpoints/auth/GetUserEndpoint.ts +5 -6
  27. package/src/endpoints/auth/PatchApiUserEndpoint.ts +35 -33
  28. package/src/endpoints/auth/PatchUserEndpoint.ts +55 -52
  29. package/src/endpoints/auth/PollEmailVerificationEndpoint.ts +9 -9
  30. package/src/endpoints/auth/RetryEmailVerificationEndpoint.ts +8 -8
  31. package/src/endpoints/auth/SignupEndpoint.ts +37 -36
  32. package/src/endpoints/auth/VerifyEmailEndpoint.ts +29 -28
  33. package/src/endpoints/global/addresses/SearchRegionsEndpoint.ts +33 -33
  34. package/src/endpoints/global/addresses/ValidateAddressEndpoint.ts +7 -7
  35. package/src/endpoints/global/caddy/CheckDomainCertEndpoint.ts +37 -37
  36. package/src/endpoints/global/email/CreateEmailEndpoint.ts +30 -30
  37. package/src/endpoints/global/email/GetEmailAddressEndpoint.ts +13 -13
  38. package/src/endpoints/global/email/GetEmailEndpoint.ts +13 -13
  39. package/src/endpoints/global/email/ManageEmailAddressEndpoint.ts +16 -16
  40. package/src/endpoints/global/email/PatchEmailEndpoint.ts +25 -25
  41. package/src/endpoints/global/events/GetEventsEndpoint.ts +43 -44
  42. package/src/endpoints/global/events/PatchEventsEndpoint.ts +127 -172
  43. package/src/endpoints/global/files/ExportToExcelEndpoint.ts +49 -50
  44. package/src/endpoints/global/files/GetFileCache.ts +13 -13
  45. package/src/endpoints/global/files/UploadFile.ts +51 -54
  46. package/src/endpoints/global/files/UploadImage.ts +53 -53
  47. package/src/endpoints/global/groups/GetGroupsEndpoint.ts +25 -25
  48. package/src/endpoints/global/members/GetMemberFamilyEndpoint.ts +24 -23
  49. package/src/endpoints/global/members/GetMembersCountEndpoint.ts +8 -8
  50. package/src/endpoints/global/members/GetMembersEndpoint.ts +105 -102
  51. package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +240 -239
  52. package/src/endpoints/global/organizations/CheckRegisterCodeEndpoint.ts +12 -14
  53. package/src/endpoints/global/organizations/CreateOrganizationEndpoint.test.ts +32 -33
  54. package/src/endpoints/global/organizations/CreateOrganizationEndpoint.ts +48 -57
  55. package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.test.ts +21 -22
  56. package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.ts +28 -28
  57. package/src/endpoints/global/organizations/GetOrganizationFromUriEndpoint.ts +18 -18
  58. package/src/endpoints/global/organizations/SearchOrganizationEndpoint.test.ts +20 -20
  59. package/src/endpoints/global/organizations/SearchOrganizationEndpoint.ts +17 -17
  60. package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +81 -75
  61. package/src/endpoints/global/platform/GetPlatformAdminsEndpoint.ts +14 -14
  62. package/src/endpoints/global/platform/GetPlatformEnpoint.ts +11 -11
  63. package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +71 -68
  64. package/src/endpoints/global/registration/GetPaymentRegistrations.ts +27 -27
  65. package/src/endpoints/global/registration/GetUserBillingStatusEndpoint.ts +30 -30
  66. package/src/endpoints/global/registration/GetUserDetailedBillingStatusEndpoint.ts +34 -34
  67. package/src/endpoints/global/registration/GetUserDocumentsEndpoint.ts +26 -26
  68. package/src/endpoints/global/registration/GetUserMembersEndpoint.ts +12 -12
  69. package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +90 -90
  70. package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +118 -121
  71. package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +362 -350
  72. package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +8 -9
  73. package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +21 -21
  74. package/src/endpoints/global/webshops/GetWebshopFromDomainEndpoint.ts +65 -65
  75. package/src/endpoints/organization/dashboard/billing/GetOrganizationBillingStatusEndpoint.ts +9 -9
  76. package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedBillingStatusEndpoint.ts +14 -14
  77. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplateXML.ts +17 -17
  78. package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesEndpoint.ts +21 -21
  79. package/src/endpoints/organization/dashboard/documents/GetDocumentsEndpoint.ts +15 -15
  80. package/src/endpoints/organization/dashboard/documents/PatchDocumentEndpoint.ts +52 -52
  81. package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplateEndpoint.ts +37 -37
  82. package/src/endpoints/organization/dashboard/email/CheckEmailBouncesEndpoint.ts +14 -14
  83. package/src/endpoints/organization/dashboard/email/EmailEndpoint.ts +113 -112
  84. package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +29 -29
  85. package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +48 -47
  86. package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +22 -21
  87. package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +13 -14
  88. package/src/endpoints/organization/dashboard/mollie/DisconnectMollieEndpoint.ts +12 -13
  89. package/src/endpoints/organization/dashboard/mollie/GetMollieDashboardEndpoint.ts +24 -24
  90. package/src/endpoints/organization/dashboard/nolt/CreateNoltTokenEndpoint.ts +10 -12
  91. package/src/endpoints/organization/dashboard/organization/GetOrganizationArchivedGroups.ts +14 -14
  92. package/src/endpoints/organization/dashboard/organization/GetOrganizationDeletedGroups.ts +13 -13
  93. package/src/endpoints/organization/dashboard/organization/GetOrganizationSSOEndpoint.ts +12 -12
  94. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +120 -124
  95. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +172 -173
  96. package/src/endpoints/organization/dashboard/organization/SetOrganizationDomainEndpoint.ts +88 -89
  97. package/src/endpoints/organization/dashboard/organization/SetOrganizationSSOEndpoint.ts +12 -12
  98. package/src/endpoints/organization/dashboard/payments/GetMemberBalanceEndpoint.ts +17 -17
  99. package/src/endpoints/organization/dashboard/payments/GetPaymentsCountEndpoint.ts +8 -8
  100. package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +66 -67
  101. package/src/endpoints/organization/dashboard/payments/PatchBalanceItemsEndpoint.ts +47 -47
  102. package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +93 -91
  103. package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.ts +16 -17
  104. package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +170 -167
  105. package/src/endpoints/organization/dashboard/registration-periods/SetupStepReviewEndpoint.ts +25 -24
  106. package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +22 -23
  107. package/src/endpoints/organization/dashboard/stripe/DeleteStripeAccountEndpoint.ts +22 -22
  108. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountLinkEndpoint.ts +17 -18
  109. package/src/endpoints/organization/dashboard/stripe/GetStripeAccountsEndpoint.ts +8 -9
  110. package/src/endpoints/organization/dashboard/stripe/GetStripeLoginLinkEndpoint.ts +17 -18
  111. package/src/endpoints/organization/dashboard/stripe/UpdateStripeAccountEndpoint.ts +14 -15
  112. package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.ts +19 -19
  113. package/src/endpoints/organization/dashboard/users/DeleteUserEndpoint.ts +19 -19
  114. package/src/endpoints/organization/dashboard/users/GetApiUsersEndpoint.ts +14 -14
  115. package/src/endpoints/organization/dashboard/users/GetOrganizationAdminsEndpoint.ts +12 -12
  116. package/src/endpoints/organization/dashboard/webshops/CreateWebshopEndpoint.ts +103 -100
  117. package/src/endpoints/organization/dashboard/webshops/DeleteWebshopEndpoint.ts +11 -12
  118. package/src/endpoints/organization/dashboard/webshops/GetDiscountCodesEndpoint.ts +15 -15
  119. package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +14 -14
  120. package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +14 -14
  121. package/src/endpoints/organization/dashboard/webshops/GetWebshopUriAvailabilityEndpoint.ts +23 -23
  122. package/src/endpoints/organization/dashboard/webshops/PatchDiscountCodesEndpoint.ts +54 -52
  123. package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +84 -81
  124. package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +120 -111
  125. package/src/endpoints/organization/dashboard/webshops/PatchWebshopTicketsEndpoint.ts +24 -24
  126. package/src/endpoints/organization/dashboard/webshops/VerifyWebshopDomainEndpoint.ts +18 -18
  127. package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +141 -130
  128. package/src/endpoints/organization/shared/GetDocumentHtml.ts +25 -25
  129. package/src/endpoints/organization/shared/GetPaymentEndpoint.ts +18 -18
  130. package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.test.ts +36 -37
  131. package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.ts +9 -9
  132. package/src/endpoints/organization/shared/auth/OpenIDConnectCallbackEndpoint.ts +11 -11
  133. package/src/endpoints/organization/shared/auth/OpenIDConnectStartEndpoint.ts +28 -27
  134. package/src/endpoints/organization/webshops/CheckWebshopDiscountCodesEndpoint.ts +20 -20
  135. package/src/endpoints/organization/webshops/GetOrderByPaymentEndpoint.ts +22 -22
  136. package/src/endpoints/organization/webshops/GetOrderEndpoint.ts +14 -14
  137. package/src/endpoints/organization/webshops/GetTicketsEndpoint.ts +57 -56
  138. package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +65 -66
  139. package/src/endpoints/organization/webshops/GetWebshopEndpoint.ts +18 -17
  140. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.test.ts +124 -128
  141. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +154 -145
  142. package/src/excel-loaders/members.ts +275 -273
  143. package/src/excel-loaders/payments.ts +155 -156
  144. package/src/helpers/AddressValidator.test.ts +32 -32
  145. package/src/helpers/AddressValidator.ts +128 -122
  146. package/src/helpers/AdminPermissionChecker.ts +339 -236
  147. package/src/helpers/AuthenticatedStructures.ts +233 -134
  148. package/src/helpers/BuckarooHelper.ts +134 -134
  149. package/src/helpers/CheckSettlements.ts +94 -88
  150. package/src/helpers/Context.ts +87 -86
  151. package/src/helpers/CookieHelper.ts +23 -22
  152. package/src/helpers/EmailResumer.ts +10 -10
  153. package/src/helpers/FileCache.ts +62 -62
  154. package/src/helpers/ForwardHandler.test.ts +122 -124
  155. package/src/helpers/ForwardHandler.ts +76 -70
  156. package/src/helpers/MemberUserSyncer.ts +101 -96
  157. package/src/helpers/MembershipCharger.ts +69 -69
  158. package/src/helpers/MembershipHelper.ts +11 -12
  159. package/src/helpers/OpenIDConnectHelper.ts +85 -82
  160. package/src/helpers/PeriodHelper.ts +65 -70
  161. package/src/helpers/StripeHelper.ts +146 -137
  162. package/src/helpers/StripePayoutChecker.ts +51 -52
  163. package/src/helpers/ViesHelper.ts +46 -44
  164. package/src/helpers/fetchToAsyncIterator.ts +14 -14
  165. package/src/helpers/xlsxAddressTransformerColumnFactory.ts +58 -60
  166. package/src/middleware/ContextMiddleware.ts +5 -5
  167. package/src/migrations/1646578856-validate-addresses.ts +6 -9
  168. package/src/seeds/0000000000-example.ts +3 -5
  169. package/src/seeds/1715028563-user-permissions.ts +16 -18
  170. package/src/seeds/1722256498-group-update-occupancy.ts +12 -12
  171. package/src/seeds/1722344162-sync-member-users.ts +14 -15
  172. package/src/seeds/1722344162-update-membership.ts +6 -6
  173. package/src/seeds/1726055544-balance-item-paid.ts +4 -4
  174. package/src/seeds/1726055545-balance-item-pending.ts +4 -4
  175. package/src/seeds/1726494419-update-cached-outstanding-balance.ts +16 -16
  176. package/src/seeds/1726494420-update-cached-outstanding-balance-from-items.ts +12 -12
  177. package/src/seeds/1726572303-schedule-stock-updates.ts +12 -12
  178. package/src/seeds/1726847064-setup-steps.ts +16 -0
  179. package/src/sql-filters/balance-item-payments.ts +7 -7
  180. package/src/sql-filters/events.ts +14 -14
  181. package/src/sql-filters/members.ts +96 -96
  182. package/src/sql-filters/organizations.ts +139 -75
  183. package/src/sql-filters/payments.ts +28 -28
  184. package/src/sql-filters/registrations.ts +14 -14
  185. package/src/sql-sorters/events.ts +25 -25
  186. package/src/sql-sorters/members.ts +26 -26
  187. package/src/sql-sorters/organizations.ts +36 -36
  188. package/src/sql-sorters/payments.ts +26 -26
  189. package/tests/e2e/stock.test.ts +616 -621
  190. package/tests/e2e/tickets.test.ts +255 -260
  191. package/tests/helpers/StripeMocker.ts +177 -179
  192. package/tests/helpers/TestServer.ts +9 -9
  193. package/tests/jest.global.setup.ts +14 -13
  194. package/tests/jest.setup.ts +33 -32
  195. package/.eslintrc.js +0 -61
  196. package/jest.config.js +0 -11
  197. package/src/helpers/SetupStepsUpdater.ts +0 -359
  198. package/src/seeds/1724076679-setup-steps.ts +0 -16
@@ -1,7 +1,7 @@
1
1
  import { AutoEncoderPatchType, Decoder, PatchableArrayAutoEncoder, PatchableArrayDecoder, patchObject, StringDecoder } from '@simonbackx/simple-encoding';
2
- import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
3
- import { Event, Group, Organization, Platform, RegistrationPeriod } from '@stamhoofd/models';
4
- import { Event as EventStruct, GroupType, NamedObject, PermissionLevel } from "@stamhoofd/structures";
2
+ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
3
+ import { Event, Group, Platform, RegistrationPeriod } from '@stamhoofd/models';
4
+ import { Event as EventStruct, GroupType, NamedObject } from '@stamhoofd/structures';
5
5
 
6
6
  import { SimpleError } from '@simonbackx/simple-errors';
7
7
  import { SQL, SQLWhereSign } from '@stamhoofd/sql';
@@ -12,18 +12,18 @@ import { PatchOrganizationRegistrationPeriodsEndpoint } from '../../organization
12
12
 
13
13
  type Params = { id: string };
14
14
  type Query = undefined;
15
- type Body = PatchableArrayAutoEncoder<EventStruct>
16
- type ResponseBody = EventStruct[]
15
+ type Body = PatchableArrayAutoEncoder<EventStruct>;
16
+ type ResponseBody = EventStruct[];
17
17
 
18
18
  export class PatchEventsEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
19
- bodyDecoder = new PatchableArrayDecoder(EventStruct as Decoder<EventStruct>, EventStruct.patchType() as Decoder<AutoEncoderPatchType<EventStruct>>, StringDecoder)
19
+ bodyDecoder = new PatchableArrayDecoder(EventStruct as Decoder<EventStruct>, EventStruct.patchType() as Decoder<AutoEncoderPatchType<EventStruct>>, StringDecoder);
20
20
 
21
21
  protected doesMatch(request: Request): [true, Params] | [false] {
22
- if (request.method != "PATCH") {
22
+ if (request.method !== 'PATCH') {
23
23
  return [false];
24
24
  }
25
25
 
26
- const params = Endpoint.parseParameters(request.url, "/events", { id: String });
26
+ const params = Endpoint.parseParameters(request.url, '/events', { id: String });
27
27
 
28
28
  if (params) {
29
29
  return [true, params as Params];
@@ -33,280 +33,230 @@ export class PatchEventsEndpoint extends Endpoint<Params, Query, Body, ResponseB
33
33
 
34
34
  async handle(request: DecodedRequest<Params, Query, Body>) {
35
35
  const organization = await Context.setOptionalOrganizationScope();
36
- await Context.authenticate()
36
+ await Context.authenticate();
37
37
 
38
38
  if (organization) {
39
39
  if (!await Context.auth.hasSomeAccess(organization.id)) {
40
- throw Context.auth.error()
40
+ throw Context.auth.error();
41
41
  }
42
- } else {
42
+ }
43
+ else {
43
44
  if (!Context.auth.hasSomePlatformAccess()) {
44
- throw Context.auth.error()
45
+ throw Context.auth.error();
45
46
  }
46
47
  }
47
48
 
48
49
  const events: Event[] = [];
49
50
 
50
- for (const {put} of request.body.getPuts()) {
51
- if (organization?.id && put.organizationId !== organization.id) {
52
- throw new SimpleError({
53
- code: 'invalid_data',
54
- message: 'Invalid organizationId',
55
- human: 'Je kan geen activiteiten aanmaken voor een andere organisatie',
56
- })
57
- }
58
-
59
- if (!organization?.id && !Context.auth.hasPlatformFullAccess()) {
60
- throw new SimpleError({
61
- code: 'invalid_data',
62
- message: 'Invalid organizationId',
63
- human: 'Je kan activiteiten aanmaken via het administratieportaal als je geen platform hoofdbeheerder bent',
64
- })
65
- }
66
-
67
- const eventOrganization = put.organizationId ? (await Organization.getByID(put.organizationId)) : null
68
- if (!eventOrganization && put.organizationId) {
69
- throw new SimpleError({
70
- code: 'invalid_data',
71
- message: 'Invalid organizationId',
72
- human: 'De organisatie werd niet gevonden',
73
- })
74
- }
75
-
76
- const event = new Event()
77
- event.id = put.id
78
- event.organizationId = put.organizationId
79
- event.name = put.name
80
- event.startDate = put.startDate
81
- event.endDate = put.endDate
51
+ for (const { put } of request.body.getPuts()) {
52
+ const event = new Event();
53
+ event.organizationId = put.organizationId;
82
54
  event.meta = put.meta;
55
+ const eventOrganization = await this.checkEventAccess(event);
56
+ event.id = put.id;
57
+ event.name = put.name;
58
+ event.startDate = put.startDate;
59
+ event.endDate = put.endDate;
60
+
83
61
  const type = await PatchEventsEndpoint.getEventType(put.typeId);
84
62
  event.typeId = type.id;
85
- event.meta.organizationCache = eventOrganization ? NamedObject.create({id: eventOrganization.id, name: eventOrganization.name}) : null
86
- await PatchEventsEndpoint.checkEventLimits(event)
87
-
88
- if (!(await Context.auth.canAccessEvent(event, PermissionLevel.Full))) {
89
- throw Context.auth.error()
90
- }
63
+ event.meta.organizationCache = eventOrganization ? NamedObject.create({ id: eventOrganization.id, name: eventOrganization.name }) : null;
64
+ await PatchEventsEndpoint.checkEventLimits(event);
91
65
 
92
66
  if (put.group) {
93
- const period = await RegistrationPeriod.getByDate(event.startDate)
67
+ const period = await RegistrationPeriod.getByDate(event.startDate);
94
68
 
95
69
  if (!period) {
96
70
  throw new SimpleError({
97
71
  code: 'invalid_period',
98
72
  message: 'No period found for this start date',
99
73
  human: 'Oeps, je kan nog geen evenementen met inschrijvingen aanmaken in deze periode. Dit werkjaar is nog niet aangemaakt in het systeem.',
100
- field: 'startDate'
101
- })
74
+ field: 'startDate',
75
+ });
102
76
  }
103
77
 
104
- put.group.type = GroupType.EventRegistration
78
+ put.group.type = GroupType.EventRegistration;
105
79
  const group = await PatchOrganizationRegistrationPeriodsEndpoint.createGroup(
106
80
  put.group,
107
81
  put.group.organizationId,
108
- period
109
- )
110
- await event.syncGroupRequirements(group)
111
- event.groupId = group.id
82
+ period,
83
+ );
84
+ await event.syncGroupRequirements(group);
85
+ event.groupId = group.id;
112
86
  }
113
87
 
114
- if(type.isLocationRequired === true) {
88
+ if (type.isLocationRequired === true) {
115
89
  PatchEventsEndpoint.throwIfAddressIsMissing(event);
116
90
  }
117
91
 
118
- await event.save()
92
+ await event.save();
119
93
 
120
- events.push(event)
94
+ events.push(event);
121
95
  }
122
96
 
123
97
  for (const patch of request.body.getPatches()) {
124
- const event = await Event.getByID(patch.id)
98
+ const event = await Event.getByID(patch.id);
125
99
 
126
- if (!event || !(await Context.auth.canAccessEvent(event, PermissionLevel.Full))) {
100
+ if (!event) {
127
101
  throw new SimpleError({
128
102
  code: 'not_found',
129
103
  message: 'Event not found',
130
104
  human: 'De activiteit werd niet gevonden',
131
- })
105
+ });
132
106
  }
133
107
 
134
- event.name = patch.name ?? event.name
135
- event.startDate = patch.startDate ?? event.startDate
136
- event.endDate = patch.endDate ?? event.endDate
108
+ await this.checkEventAccess(event);
137
109
 
138
110
  if (patch.meta?.organizationCache) {
139
111
  throw new SimpleError({
140
112
  code: 'invalid_field',
141
113
  message: 'Cannot patch organizationCache',
142
114
  human: 'Je kan de organizationCache niet aanpassen via een patch',
143
- field: 'meta.organizationCache'
144
- })
115
+ field: 'meta.organizationCache',
116
+ });
145
117
  }
146
118
 
147
- event.meta = patchObject(event.meta, patch.meta)
119
+ event.meta = patchObject(event.meta, patch.meta);
148
120
 
149
121
  if (patch.organizationId !== undefined) {
150
- if (organization?.id && patch.organizationId !== organization.id) {
151
- throw new SimpleError({
152
- code: 'invalid_data',
153
- message: 'Invalid organizationId',
154
- human: 'Je kan geen activiteiten aanmaken voor een andere organisatie',
155
- })
156
- }
157
-
158
- if (!organization?.id && !Context.auth.hasPlatformFullAccess()) {
159
- throw new SimpleError({
160
- code: 'invalid_data',
161
- message: 'Invalid organizationId',
162
- human: 'Je kan geen activiteiten voor een specifieke organisatie aanmaken als je geen platform hoofdbeheerder bent',
163
- })
164
- }
165
-
166
- const eventOrganization = patch.organizationId ? (await Organization.getByID(patch.organizationId)) : null
167
- if (!eventOrganization && patch.organizationId) {
168
- throw new SimpleError({
169
- code: 'invalid_data',
170
- message: 'Invalid organizationId',
171
- human: 'De organisatie werd niet gevonden',
172
- })
173
- }
174
- event.organizationId = patch.organizationId
175
- event.meta.organizationCache = eventOrganization ? NamedObject.create({id: eventOrganization.id, name: eventOrganization.name}) : null
176
- } else {
177
- // Update cache
178
- if (event.organizationId) {
179
- const eventOrganization = await Organization.getByID(event.organizationId)
180
- if (eventOrganization) {
181
- event.meta.organizationCache = NamedObject.create({id: eventOrganization.id, name: eventOrganization.name})
182
- }
183
- }
122
+ event.organizationId = patch.organizationId;
123
+ }
124
+
125
+ const eventOrganization = await this.checkEventAccess(event);
126
+ if (eventOrganization) {
127
+ event.meta.organizationCache = NamedObject.create({ id: eventOrganization.id, name: eventOrganization.name });
128
+ }
129
+ else {
130
+ event.meta.organizationCache = null;
184
131
  }
185
132
 
133
+ event.name = patch.name ?? event.name;
134
+ event.startDate = patch.startDate ?? event.startDate;
135
+ event.endDate = patch.endDate ?? event.endDate;
136
+
186
137
  const type = await PatchEventsEndpoint.getEventType(patch.typeId ?? event.typeId);
187
138
 
188
- if(patch.typeId) {
139
+ if (patch.typeId) {
189
140
  event.typeId = type.id;
190
141
  }
191
142
 
192
- await PatchEventsEndpoint.checkEventLimits(event)
143
+ await PatchEventsEndpoint.checkEventLimits(event);
193
144
 
194
145
  if (patch.group !== undefined) {
195
146
  if (patch.group === null) {
196
147
  // delete
197
148
  if (event.groupId) {
198
- await PatchOrganizationRegistrationPeriodsEndpoint.deleteGroup(event.groupId)
149
+ await PatchOrganizationRegistrationPeriodsEndpoint.deleteGroup(event.groupId);
199
150
  event.groupId = null;
200
151
  }
201
-
202
- } else if (patch.group.isPatch()) {
152
+ }
153
+ else if (patch.group.isPatch()) {
203
154
  if (!event.groupId) {
204
155
  throw new SimpleError({
205
156
  code: 'invalid_field',
206
157
  field: 'group',
207
- message: 'Cannot patch group before it is created'
208
- })
158
+ message: 'Cannot patch group before it is created',
159
+ });
209
160
  }
210
- patch.group.id = event.groupId
211
- patch.group.type = GroupType.EventRegistration
161
+ patch.group.id = event.groupId;
162
+ patch.group.type = GroupType.EventRegistration;
212
163
 
213
- const period = await RegistrationPeriod.getByDate(event.startDate)
214
- await PatchOrganizationRegistrationPeriodsEndpoint.patchGroup(patch.group, period)
215
- } else {
164
+ const period = await RegistrationPeriod.getByDate(event.startDate);
165
+ await PatchOrganizationRegistrationPeriodsEndpoint.patchGroup(patch.group, period);
166
+ }
167
+ else {
216
168
  if (event.groupId) {
217
169
  // need to delete old group first
218
- await PatchOrganizationRegistrationPeriodsEndpoint.deleteGroup(event.groupId)
170
+ await PatchOrganizationRegistrationPeriodsEndpoint.deleteGroup(event.groupId);
219
171
  event.groupId = null;
220
172
  }
221
- patch.group.type = GroupType.EventRegistration
173
+ patch.group.type = GroupType.EventRegistration;
222
174
 
223
- const period = await RegistrationPeriod.getByDate(event.startDate)
175
+ const period = await RegistrationPeriod.getByDate(event.startDate);
224
176
 
225
177
  if (!period) {
226
178
  throw new SimpleError({
227
179
  code: 'invalid_period',
228
180
  message: 'No period found for this start date',
229
181
  human: 'Oeps, je kan nog geen evenementen met inschrijvingen aanmaken in deze periode. Dit werkjaar is nog niet aangemaakt in het systeem.',
230
- field: 'startDate'
231
- })
182
+ field: 'startDate',
183
+ });
232
184
  }
233
185
 
234
186
  const group = await PatchOrganizationRegistrationPeriodsEndpoint.createGroup(
235
187
  patch.group,
236
188
  patch.group.organizationId,
237
- period
238
- )
239
- event.groupId = group.id
189
+ period,
190
+ );
191
+ event.groupId = group.id;
240
192
  }
241
193
  }
242
194
 
243
- if(type.isLocationRequired === true) {
195
+ if (type.isLocationRequired === true) {
244
196
  PatchEventsEndpoint.throwIfAddressIsMissing(event);
245
197
  }
246
198
 
247
- await event.save()
199
+ await event.save();
248
200
 
249
201
  if (event.groupId) {
250
- const group = await Group.getByID(event.groupId)
202
+ const group = await Group.getByID(event.groupId);
251
203
  if (group) {
252
- await event.syncGroupRequirements(group)
204
+ await event.syncGroupRequirements(group);
253
205
  }
254
206
  }
255
-
256
- events.push(event)
207
+
208
+ events.push(event);
257
209
  }
258
210
 
259
211
  for (const id of request.body.getDeletes()) {
260
212
  const event = await Event.getByID(id);
261
213
  if (!event) {
262
- throw new SimpleError({ code: "not_found", message: "Event not found", statusCode: 404 });
214
+ throw new SimpleError({ code: 'not_found', message: 'Event not found', statusCode: 404 });
263
215
  }
264
216
 
265
- if (!(await Context.auth.canAccessEvent(event, PermissionLevel.Full))) {
266
- throw Context.auth.error()
267
- }
217
+ await this.checkEventAccess(event);
268
218
 
269
- if(event.groupId) {
270
- await PatchOrganizationRegistrationPeriodsEndpoint.deleteGroup(event.groupId)
219
+ if (event.groupId) {
220
+ await PatchOrganizationRegistrationPeriodsEndpoint.deleteGroup(event.groupId);
271
221
  event.groupId = null;
272
222
  }
273
-
223
+
274
224
  await event.delete();
275
225
  }
276
226
 
277
227
  return new Response(
278
- await AuthenticatedStructures.events(events)
228
+ await AuthenticatedStructures.events(events),
279
229
  );
280
230
  }
281
231
 
282
232
  static async validateEventType(typeId: string) {
283
- return (await this.getEventType(typeId)).id
233
+ return (await this.getEventType(typeId)).id;
284
234
  }
285
235
 
286
236
  static async getEventType(typeId: string) {
287
237
  const platform = await Platform.getSharedStruct();
288
- const type = platform.config.eventTypes.find(t => t.id == typeId)
238
+ const type = platform.config.eventTypes.find(t => t.id == typeId);
289
239
  if (!type) {
290
240
  throw new SimpleError({
291
241
  code: 'invalid_field',
292
242
  message: 'Invalid typeId',
293
243
  human: 'Dit type activiteit wordt niet ondersteund',
294
- field: 'typeId'
295
- })
244
+ field: 'typeId',
245
+ });
296
246
  }
297
- return type
247
+ return type;
298
248
  }
299
249
 
300
250
  static async checkEventLimits(event: Event) {
301
- const type = await this.getEventType(event.typeId)
251
+ const type = await this.getEventType(event.typeId);
302
252
 
303
253
  if (event.name.length < 2) {
304
254
  throw new SimpleError({
305
255
  code: 'invalid_field',
306
256
  message: 'Name is too short',
307
257
  human: 'Vul een naam voor je activiteit in',
308
- field: 'name'
309
- })
258
+ field: 'name',
259
+ });
310
260
  }
311
261
 
312
262
  if (event.endDate < event.startDate) {
@@ -314,25 +264,25 @@ export class PatchEventsEndpoint extends Endpoint<Params, Query, Body, ResponseB
314
264
  code: 'invalid_dates',
315
265
  message: 'End date is before start date',
316
266
  human: 'De einddatum moet na de startdatum liggen',
317
- field: 'endDate'
318
- })
267
+ field: 'endDate',
268
+ });
319
269
  }
320
270
 
321
271
  if (type.maximumDays !== null || type.minimumDays !== null) {
322
- const start = Formatter.luxon(event.startDate).startOf('day')
323
- const end = Formatter.luxon(event.endDate).startOf('day')
272
+ const start = Formatter.luxon(event.startDate).startOf('day');
273
+ const end = Formatter.luxon(event.endDate).startOf('day');
324
274
 
325
275
  const days = end.diff(start, 'days').days + 1;
326
276
 
327
- console.log('Detected days:', days)
277
+ console.log('Detected days:', days);
328
278
 
329
279
  if (type.minimumDays !== null && days < type.minimumDays) {
330
280
  throw new SimpleError({
331
281
  code: 'minimum_days',
332
282
  message: 'An event with this type has a minimum of ' + type.minimumDays + ' days',
333
283
  human: 'Een ' + type.name + ' moet minimum ' + Formatter.pluralText(type.minimumDays, 'dag', 'dagen') + ' duren',
334
- field: 'startDate'
335
- })
284
+ field: 'startDate',
285
+ });
336
286
  }
337
287
 
338
288
  if (type.maximumDays !== null && days > type.maximumDays) {
@@ -340,54 +290,59 @@ export class PatchEventsEndpoint extends Endpoint<Params, Query, Body, ResponseB
340
290
  code: 'maximum_days',
341
291
  message: 'An event with this type has a maximum of ' + type.maximumDays + ' days',
342
292
  human: 'Een ' + type.name + ' mag maximaal ' + Formatter.pluralText(type.maximumDays, 'dag', 'dagen') + ' duren',
343
- field: 'startDate'
344
- })
293
+ field: 'startDate',
294
+ });
345
295
  }
346
296
  }
347
297
 
348
- if (type.maximum && (!event.existsInDatabase || ("typeId" in (await event.getChangedDatabaseProperties()).fields))) {
298
+ if (type.maximum && (!event.existsInDatabase || ('typeId' in (await event.getChangedDatabaseProperties()).fields))) {
349
299
  const currentPeriod = await RegistrationPeriod.getByDate(event.startDate);
350
- console.log('event.startDate', event.startDate)
300
+ console.log('event.startDate', event.startDate);
351
301
  if (currentPeriod) {
352
302
  const count = await SQL.select().from(
353
- SQL.table(Event.table)
354
- )
303
+ SQL.table(Event.table),
304
+ )
355
305
  .where(SQL.column('organizationId'), event.organizationId)
356
306
  .where(SQL.column('typeId'), event.typeId)
357
307
  .where(SQL.column('id'), SQLWhereSign.NotEqual, event.id)
358
308
  .where(SQL.column('startDate'), SQLWhereSign.GreaterEqual, currentPeriod.startDate)
359
309
  .where(SQL.column('endDate'), SQLWhereSign.LessEqual, currentPeriod.endDate)
360
- .count()
361
-
310
+ .count();
311
+
362
312
  if (count >= type.maximum) {
363
313
  throw new SimpleError({
364
314
  code: 'type_maximum_reached',
365
315
  message: 'Maximum number of events with this type reached',
366
316
  human: 'Het maximum aantal voor ' + type.name + ' is bereikt (' + type.maximum + ')',
367
- field: 'typeId'
368
- })
317
+ field: 'typeId',
318
+ });
369
319
  }
370
- } else {
320
+ }
321
+ else {
371
322
  throw new SimpleError({
372
323
  code: 'invalid_period',
373
324
  message: 'No period found for this start date',
374
325
  human: 'Oeps, je kan nog geen evenementen van dit type aanmaken in deze periode',
375
- field: 'startDate'
376
- })
326
+ field: 'startDate',
327
+ });
377
328
  }
378
329
  }
379
330
  }
380
331
 
332
+ private async checkEventAccess(event: Event) {
333
+ return await Context.auth.checkEventAccess(event);
334
+ }
335
+
381
336
  private static throwIfAddressIsMissing(event: Event) {
382
337
  const address = event.meta.location?.address;
383
338
 
384
- if(!address) {
339
+ if (!address) {
385
340
  throw new SimpleError({
386
- code: "invalid_field",
387
- message: "Empty number",
388
- human: "De locatie is verplicht voor deze soort activiteit.",
389
- field: "event_required"
390
- })
341
+ code: 'invalid_field',
342
+ message: 'Empty number',
343
+ human: 'De locatie is verplicht voor deze soort activiteit.',
344
+ field: 'event_required',
345
+ });
391
346
  }
392
347
 
393
348
  address.throwIfIncomplete();