@stamhoofd/backend 2.39.0 โ†’ 2.40.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 (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 +102 -103
  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 +50 -52
  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,8 +1,8 @@
1
1
  import { AutoEncoderPatchType, Decoder, PatchableArrayAutoEncoder, PatchableArrayDecoder, StringDecoder } from '@simonbackx/simple-encoding';
2
- import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
3
- import { SimpleError } from "@simonbackx/simple-errors";
2
+ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
3
+ import { SimpleError } from '@simonbackx/simple-errors';
4
4
  import { Organization, OrganizationRegistrationPeriod, Platform } from '@stamhoofd/models';
5
- import { OrganizationMetaData, Organization as OrganizationStruct } from "@stamhoofd/structures";
5
+ import { OrganizationMetaData, Organization as OrganizationStruct } from '@stamhoofd/structures';
6
6
 
7
7
  import { Context } from '../../../helpers/Context';
8
8
  import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
@@ -10,18 +10,18 @@ import { Formatter } from '@stamhoofd/utility';
10
10
 
11
11
  type Params = Record<string, never>;
12
12
  type Query = undefined;
13
- type Body = PatchableArrayAutoEncoder<OrganizationStruct>
14
- type ResponseBody = OrganizationStruct[]
13
+ type Body = PatchableArrayAutoEncoder<OrganizationStruct>;
14
+ type ResponseBody = OrganizationStruct[];
15
15
 
16
16
  export class PatchOrganizationsEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
17
- bodyDecoder = new PatchableArrayDecoder(OrganizationStruct as Decoder<OrganizationStruct>, OrganizationStruct.patchType() as Decoder<AutoEncoderPatchType<OrganizationStruct>>, StringDecoder)
17
+ bodyDecoder = new PatchableArrayDecoder(OrganizationStruct as Decoder<OrganizationStruct>, OrganizationStruct.patchType() as Decoder<AutoEncoderPatchType<OrganizationStruct>>, StringDecoder);
18
18
 
19
19
  protected doesMatch(request: Request): [true, Params] | [false] {
20
- if (request.method != "PATCH") {
20
+ if (request.method !== 'PATCH') {
21
21
  return [false];
22
22
  }
23
23
 
24
- const params = Endpoint.parseParameters(request.url, "/admin/organizations", {});
24
+ const params = Endpoint.parseParameters(request.url, '/admin/organizations', {});
25
25
 
26
26
  if (params) {
27
27
  return [true, params as Params];
@@ -30,26 +30,26 @@ export class PatchOrganizationsEndpoint extends Endpoint<Params, Query, Body, Re
30
30
  }
31
31
 
32
32
  async handle(request: DecodedRequest<Params, Query, Body>) {
33
- await Context.authenticate()
33
+ await Context.authenticate();
34
34
  if (!Context.auth.hasPlatformFullAccess()) {
35
- throw Context.auth.error()
35
+ throw Context.auth.error();
36
36
  }
37
-
37
+
38
38
  if (request.body.changes.length == 0) {
39
39
  return new Response([]);
40
40
  }
41
41
 
42
42
  const result: Organization[] = [];
43
- const platform = await Platform.getShared()
43
+ const platform = await Platform.getShared();
44
44
 
45
45
  for (const id of request.body.getDeletes()) {
46
46
  if (!Context.auth.hasPlatformFullAccess()) {
47
- throw Context.auth.error('Enkel een platform hoofdbeheerder kan groepen verwijderen')
47
+ throw Context.auth.error('Enkel een platform hoofdbeheerder kan groepen verwijderen');
48
48
  }
49
49
 
50
50
  const organization = await Organization.getByID(id);
51
51
  if (!organization) {
52
- throw new SimpleError({ code: "not_found", message: "Organization not found", statusCode: 404 });
52
+ throw new SimpleError({ code: 'not_found', message: 'Organization not found', statusCode: 404 });
53
53
  }
54
54
 
55
55
  await organization.delete();
@@ -59,17 +59,17 @@ export class PatchOrganizationsEndpoint extends Endpoint<Params, Query, Body, Re
59
59
  for (const patch of request.body.getPatches()) {
60
60
  const organization = await Organization.getByID(patch.id);
61
61
  if (!organization) {
62
- throw new SimpleError({ code: "not_found", message: "Organization not found", statusCode: 404 });
62
+ throw new SimpleError({ code: 'not_found', message: 'Organization not found', statusCode: 404 });
63
63
  }
64
64
 
65
65
  if (patch.meta?.tags) {
66
66
  const cleanedPatch = OrganizationMetaData.patch({
67
- tags: patch.meta.tags as any
68
- })
67
+ tags: patch.meta.tags as any,
68
+ });
69
69
  const patchedMeta = organization.meta.patch(cleanedPatch);
70
70
  for (const tag of patchedMeta.tags) {
71
71
  if (!platform.config.tags.find(t => t.id === tag)) {
72
- throw new SimpleError({ code: "invalid_tag", message: "Invalid tag", statusCode: 400 });
72
+ throw new SimpleError({ code: 'invalid_tag', message: 'Invalid tag', statusCode: 400 });
73
73
  }
74
74
  }
75
75
 
@@ -78,7 +78,7 @@ export class PatchOrganizationsEndpoint extends Endpoint<Params, Query, Body, Re
78
78
  const aIndex = platform.config.tags.findIndex(t => t.id === a);
79
79
  const bIndex = platform.config.tags.findIndex(t => t.id === b);
80
80
  return aIndex - bIndex;
81
- })
81
+ });
82
82
 
83
83
  organization.meta.tags = patchedMeta.tags;
84
84
  }
@@ -88,58 +88,58 @@ export class PatchOrganizationsEndpoint extends Endpoint<Params, Query, Body, Re
88
88
  }
89
89
 
90
90
  // Organization creation
91
- for (const {put} of request.body.getPuts()) {
91
+ for (const { put } of request.body.getPuts()) {
92
92
  if (!Context.auth.hasPlatformFullAccess()) {
93
- throw Context.auth.error('Enkel een platform hoofdbeheerder kan nieuwe groepen aanmaken')
93
+ throw Context.auth.error('Enkel een platform hoofdbeheerder kan nieuwe groepen aanmaken');
94
94
  }
95
95
 
96
96
  if (put.name.length < 4) {
97
97
  if (put.name.length == 0) {
98
98
  throw new SimpleError({
99
- code: "invalid_field",
100
- message: "Should not be empty",
101
- human: "Je bent de naam van je organisatie vergeten in te vullen",
102
- field: "organization.name"
103
- })
99
+ code: 'invalid_field',
100
+ message: 'Should not be empty',
101
+ human: 'Je bent de naam van je organisatie vergeten in te vullen',
102
+ field: 'organization.name',
103
+ });
104
104
  }
105
-
105
+
106
106
  throw new SimpleError({
107
- code: "invalid_field",
108
- message: "Field is too short",
109
- human: "Kijk de naam van je organisatie na, deze is te kort. Vul eventueel aan met de gemeente.",
110
- field: "organization.name"
111
- })
107
+ code: 'invalid_field',
108
+ message: 'Field is too short',
109
+ human: 'Kijk de naam van je organisatie na, deze is te kort. Vul eventueel aan met de gemeente.',
110
+ field: 'organization.name',
111
+ });
112
112
  }
113
-
113
+
114
114
  const uri = put.uri || Formatter.slug(put.name);
115
-
115
+
116
116
  if (uri.length > 100) {
117
117
  throw new SimpleError({
118
- code: "invalid_field",
119
- message: "Field is too long",
120
- human: "De naam van de vereniging is te lang. Probeer de naam wat te verkorten en probeer opnieuw.",
121
- field: "organization.name"
122
- })
118
+ code: 'invalid_field',
119
+ message: 'Field is too long',
120
+ human: 'De naam van de vereniging is te lang. Probeer de naam wat te verkorten en probeer opnieuw.',
121
+ field: 'organization.name',
122
+ });
123
123
  }
124
124
  const uriExists = await Organization.getByURI(uri);
125
-
125
+
126
126
  if (uriExists) {
127
127
  throw new SimpleError({
128
- code: "name_taken",
129
- message: "An organization with the same name already exists",
130
- human: "Er bestaat al een vereniging met dezelfde URI. Pas deze aan zodat deze uniek is, en controleer of deze vereniging niet al bestaat.",
131
- field: "name",
128
+ code: 'name_taken',
129
+ message: 'An organization with the same name already exists',
130
+ human: 'Er bestaat al een vereniging met dezelfde URI. Pas deze aan zodat deze uniek is, en controleer of deze vereniging niet al bestaat.',
131
+ field: 'name',
132
132
  });
133
133
  }
134
134
 
135
135
  const alreadyExists = await Organization.getByURI(Formatter.slug(put.name));
136
-
136
+
137
137
  if (alreadyExists) {
138
138
  throw new SimpleError({
139
- code: "name_taken",
140
- message: "An organization with the same name already exists",
141
- human: "Er bestaat al een vereniging met dezelfde naam. Voeg bijvoorbeeld de naam van je gemeente toe.",
142
- field: "name",
139
+ code: 'name_taken',
140
+ message: 'An organization with the same name already exists',
141
+ human: 'Er bestaat al een vereniging met dezelfde naam. Voeg bijvoorbeeld de naam van je gemeente toe.',
142
+ field: 'name',
143
143
  });
144
144
  }
145
145
 
@@ -148,27 +148,28 @@ export class PatchOrganizationsEndpoint extends Endpoint<Params, Query, Body, Re
148
148
  organization.name = put.name;
149
149
 
150
150
  organization.uri = put.uri;
151
- organization.meta = put.meta
152
- organization.address = put.address
151
+ organization.meta = put.meta;
152
+ organization.address = put.address;
153
153
 
154
154
  if (put.privateMeta) {
155
- organization.privateMeta = put.privateMeta
155
+ organization.privateMeta = put.privateMeta;
156
156
  }
157
157
 
158
158
  try {
159
159
  await organization.save();
160
- } catch (e) {
160
+ }
161
+ catch (e) {
161
162
  console.error(e);
162
163
  throw new SimpleError({
163
- code: "creating_organization",
164
- message: "Something went wrong while creating the organization. Please try again later or contact us.",
165
- statusCode: 500
164
+ code: 'creating_organization',
165
+ message: 'Something went wrong while creating the organization. Please try again later or contact us.',
166
+ statusCode: 500,
166
167
  });
167
168
  }
168
169
 
169
170
  const organizationPeriod = new OrganizationRegistrationPeriod();
170
171
  organizationPeriod.organizationId = organization.id;
171
- organizationPeriod.periodId = (await Platform.getShared()).periodId
172
+ organizationPeriod.periodId = (await Platform.getShared()).periodId;
172
173
  await organizationPeriod.save();
173
174
 
174
175
  result.push(organization);
@@ -1,26 +1,26 @@
1
1
  import { Decoder } from '@simonbackx/simple-encoding';
2
- import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
3
- import { SimpleError } from "@simonbackx/simple-errors";
2
+ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
3
+ import { SimpleError } from '@simonbackx/simple-errors';
4
4
  import { PasswordToken, Platform, sendEmailTemplate, User } from '@stamhoofd/models';
5
- import { EmailTemplateType, Recipient, Replacement, UserPermissions, User as UserStruct, UserWithMembers } from "@stamhoofd/structures";
5
+ import { EmailTemplateType, Recipient, Replacement, UserPermissions, User as UserStruct, UserWithMembers } from '@stamhoofd/structures';
6
6
  import { Formatter } from '@stamhoofd/utility';
7
7
 
8
8
  import { AuthenticatedStructures } from '../../helpers/AuthenticatedStructures';
9
9
  import { Context } from '../../helpers/Context';
10
10
  type Params = Record<string, never>;
11
11
  type Query = undefined;
12
- type Body = UserStruct
13
- type ResponseBody = UserWithMembers
12
+ type Body = UserStruct;
13
+ type ResponseBody = UserWithMembers;
14
14
 
15
15
  export class CreateAdminEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
16
- bodyDecoder = UserStruct as Decoder<UserStruct>
16
+ bodyDecoder = UserStruct as Decoder<UserStruct>;
17
17
 
18
18
  protected doesMatch(request: Request): [true, Params] | [false] {
19
- if (request.method != "POST") {
19
+ if (request.method !== 'POST') {
20
20
  return [false];
21
21
  }
22
22
 
23
- const params = Endpoint.parseParameters(request.url, "/user", {});
23
+ const params = Endpoint.parseParameters(request.url, '/user', {});
24
24
 
25
25
  if (params) {
26
26
  return [true, params as Params];
@@ -30,37 +30,38 @@ export class CreateAdminEndpoint extends Endpoint<Params, Query, Body, ResponseB
30
30
 
31
31
  async handle(request: DecodedRequest<Params, Query, Body>) {
32
32
  const organization = await Context.setOptionalOrganizationScope();
33
- const {user} = await Context.authenticate()
33
+ const { user } = await Context.authenticate();
34
34
 
35
35
  // Fast throw first (more in depth checking for patches later)
36
36
  if (organization) {
37
37
  if (!await Context.auth.canManageAdmins(organization.id)) {
38
- throw Context.auth.error()
38
+ throw Context.auth.error();
39
39
  }
40
- } else {
40
+ }
41
+ else {
41
42
  // Fast throw first (more in depth checking for patches later)
42
43
  if (!Context.auth.canManagePlatformAdmins()) {
43
- throw Context.auth.error()
44
+ throw Context.auth.error();
44
45
  }
45
46
  }
46
47
 
47
48
  // First check if a user exists with this email?
48
- const existing = await User.getForRegister(organization?.id ?? null, request.body.email)
49
+ const existing = await User.getForRegister(organization?.id ?? null, request.body.email);
49
50
 
50
51
  const admin = existing ?? (await User.createInvited(organization, {
51
52
  firstName: request.body.firstName,
52
53
  lastName: request.body.lastName,
53
54
  email: request.body.email,
54
- allowPlatform: true
55
- }))
55
+ allowPlatform: true,
56
+ }));
56
57
 
57
58
  if (!admin) {
58
59
  throw new SimpleError({
59
60
  code: 'internal_error',
60
61
  message: 'Something went wrong while creating the admin',
61
62
  human: 'Er ging iets mis bij het aanmaken van dit account',
62
- statusCode: 500
63
- })
63
+ statusCode: 500,
64
+ });
64
65
  }
65
66
 
66
67
  // Merge permissions
@@ -68,28 +69,30 @@ export class CreateAdminEndpoint extends Endpoint<Params, Query, Body, ResponseB
68
69
  throw new SimpleError({
69
70
  code: 'missing_field',
70
71
  message: 'When creating administrators, you are required to specify permissions in the request',
71
- field: 'permissions'
72
- })
72
+ field: 'permissions',
73
+ });
73
74
  }
74
75
 
75
76
  if (organization) {
76
- admin.permissions = UserPermissions.limitedPatch(admin.permissions, request.body.permissions, organization.id)
77
- } else {
77
+ admin.permissions = UserPermissions.limitedPatch(admin.permissions, request.body.permissions, organization.id);
78
+ }
79
+ else {
78
80
  if (admin.permissions) {
79
- admin.permissions.patchOrPut(request.body.permissions)
80
- } else {
81
- admin.permissions = request.body.permissions.isPut() ? request.body.permissions : null
81
+ admin.permissions.patchOrPut(request.body.permissions);
82
+ }
83
+ else {
84
+ admin.permissions = request.body.permissions.isPut() ? request.body.permissions : null;
82
85
  }
83
86
  }
84
87
 
85
88
  if (!admin.firstName && request.body.firstName) {
86
89
  // Allow setting the name if the user didn't had a name yet
87
- admin.firstName = request.body.firstName
90
+ admin.firstName = request.body.firstName;
88
91
  }
89
92
 
90
93
  if (!admin.lastName && request.body.lastName) {
91
94
  // Allow setting the name if the user didn't had a name yet
92
- admin.lastName = request.body.lastName
95
+ admin.lastName = request.body.lastName;
93
96
  }
94
97
 
95
98
  await admin.save();
@@ -98,12 +101,12 @@ export class CreateAdminEndpoint extends Endpoint<Params, Query, Body, ResponseB
98
101
  const validUntil = new Date();
99
102
  validUntil.setTime(validUntil.getTime() + 7 * 24 * 3600 * 1000);
100
103
 
101
- const dateTime = Formatter.dateTime(validUntil)
102
- const recoveryUrl = await PasswordToken.getPasswordRecoveryUrl(admin, organization, request.i18n, validUntil)
103
- const platformName = ((await Platform.getSharedStruct()).config.name)
104
-
105
- const name = organization?.name ?? platformName
106
- const what = organization ? `de vereniging ${name} op ${platformName}` : platformName
104
+ const dateTime = Formatter.dateTime(validUntil);
105
+ const recoveryUrl = await PasswordToken.getPasswordRecoveryUrl(admin, organization, request.i18n, validUntil);
106
+ const platformName = ((await Platform.getSharedStruct()).config.name);
107
+
108
+ const name = organization?.name ?? platformName;
109
+ const what = organization ? `de vereniging ${name} op ${platformName}` : platformName;
107
110
 
108
111
  const emailTo = admin.getEmailTo();
109
112
  const email: string = typeof emailTo === 'string' ? emailTo : emailTo[0]?.email;
@@ -115,39 +118,39 @@ export class CreateAdminEndpoint extends Endpoint<Params, Query, Body, ResponseB
115
118
  replacements: [
116
119
  Replacement.create({
117
120
  token: 'greeting',
118
- value: admin.firstName ? `Dag ${admin.firstName},` : 'Hallo!'
121
+ value: admin.firstName ? `Dag ${admin.firstName},` : 'Hallo!',
119
122
  }),
120
123
  Replacement.create({
121
124
  token: 'resetUrl',
122
- value: recoveryUrl
125
+ value: recoveryUrl,
123
126
  }),
124
127
  Replacement.create({
125
128
  token: 'platformOrOrganizationName',
126
- value: what
129
+ value: what,
127
130
  }),
128
131
  Replacement.create({
129
132
  token: 'inviterName',
130
- value: user.firstName ?? 'Iemand'
133
+ value: user.firstName ?? 'Iemand',
131
134
  }),
132
135
  Replacement.create({
133
136
  token: 'validUntil',
134
- value: dateTime
137
+ value: dateTime,
135
138
  }),
136
139
  Replacement.create({
137
140
  token: 'email',
138
- value: admin.email
139
- })
140
- ]
141
- })
141
+ value: admin.email,
142
+ }),
143
+ ],
144
+ }),
142
145
  ],
143
146
  template: {
144
- type: admin.hasAccount() ? EmailTemplateType.AdminInvitation : EmailTemplateType.AdminInvitationNewUser
147
+ type: admin.hasAccount() ? EmailTemplateType.AdminInvitation : EmailTemplateType.AdminInvitationNewUser,
145
148
  },
146
- type: 'transactional'
149
+ type: 'transactional',
147
150
  });
148
151
 
149
152
  return new Response(
150
- await AuthenticatedStructures.userWithMembers(admin)
151
- );
153
+ await AuthenticatedStructures.userWithMembers(admin),
154
+ );
152
155
  }
153
156
  }
@@ -1,68 +1,68 @@
1
- import { Request } from "@simonbackx/simple-endpoints";
2
- import { OrganizationFactory, Token, UserFactory } from "@stamhoofd/models";
3
- import { Token as TokenStruct } from "@stamhoofd/structures";
1
+ import { Request } from '@simonbackx/simple-endpoints';
2
+ import { OrganizationFactory, Token, UserFactory } from '@stamhoofd/models';
3
+ import { Token as TokenStruct } from '@stamhoofd/structures';
4
4
 
5
- import { testServer } from "../../../tests/helpers/TestServer";
5
+ import { testServer } from '../../../tests/helpers/TestServer';
6
6
  import { CreateTokenEndpoint } from './CreateTokenEndpoint';
7
7
 
8
- describe("Endpoint.CreateToken", () => {
8
+ describe('Endpoint.CreateToken', () => {
9
9
  // Test endpoint
10
10
  const endpoint = new CreateTokenEndpoint();
11
11
 
12
- test("Can get a token via password flow", async () => {
13
- const organization = await new OrganizationFactory({}).create()
12
+ test('Can get a token via password flow', async () => {
13
+ const organization = await new OrganizationFactory({}).create();
14
14
  // Also check UTF8 passwords
15
- const password = "54๐Ÿ˜‚test๐Ÿ‘Œ๐Ÿพ86s&รฉ"
16
- const user = await new UserFactory({ organization, password }).create()
15
+ const password = '54๐Ÿ˜‚test๐Ÿ‘Œ๐Ÿพ86s&รฉ';
16
+ const user = await new UserFactory({ organization, password }).create();
17
17
 
18
- const r = Request.buildJson("POST", "/oauth/token", organization.getApiHost(), {
19
- grant_type: "password",
18
+ const r = Request.buildJson('POST', '/oauth/token', organization.getApiHost(), {
19
+ grant_type: 'password',
20
20
  username: user.email,
21
- password: password
21
+ password: password,
22
22
  });
23
23
 
24
24
  const response = await testServer.test(endpoint, r);
25
25
  expect(response.body).toBeDefined();
26
26
 
27
27
  if (!(response.body instanceof TokenStruct)) {
28
- throw new Error("Expected TokenStruct")
28
+ throw new Error('Expected TokenStruct');
29
29
  }
30
30
 
31
31
  // Check token is valid
32
- const token = await Token.getByAccessToken(response.body.accessToken)
33
- expect(token).toBeDefined()
32
+ const token = await Token.getByAccessToken(response.body.accessToken);
33
+ expect(token).toBeDefined();
34
34
 
35
- const byRefresh = await Token.getByRefreshToken(response.body.refreshToken)
36
- expect(byRefresh).toBeDefined()
35
+ const byRefresh = await Token.getByRefreshToken(response.body.refreshToken);
36
+ expect(byRefresh).toBeDefined();
37
37
  });
38
38
 
39
- test("Can get a token via refresh flow", async () => {
40
- const organization = await new OrganizationFactory({}).create()
39
+ test('Can get a token via refresh flow', async () => {
40
+ const organization = await new OrganizationFactory({}).create();
41
41
  // Also check UTF8 passwords
42
- const password = "54๐Ÿ˜‚test๐Ÿ‘Œ๐Ÿพ86s&รฉ"
43
- const user = await new UserFactory({ organization, password }).create()
42
+ const password = '54๐Ÿ˜‚test๐Ÿ‘Œ๐Ÿพ86s&รฉ';
43
+ const user = await new UserFactory({ organization, password }).create();
44
44
  const token = await Token.createToken(user);
45
45
 
46
- const r = Request.buildJson("POST", "/oauth/token", organization.getApiHost(), {
47
- grant_type: "refresh_token",
48
- refresh_token: token.refreshToken
46
+ const r = Request.buildJson('POST', '/oauth/token', organization.getApiHost(), {
47
+ grant_type: 'refresh_token',
48
+ refresh_token: token.refreshToken,
49
49
  });
50
50
 
51
51
  const response = await testServer.test(endpoint, r);
52
52
  expect(response.body).toBeDefined();
53
53
 
54
54
  if (!(response.body instanceof TokenStruct)) {
55
- throw new Error("Expected TokenStruct")
55
+ throw new Error('Expected TokenStruct');
56
56
  }
57
57
 
58
- expect(response.body.accessToken).not.toEqual(token.accessToken)
59
- expect(response.body.refreshToken).not.toEqual(token.refreshToken)
58
+ expect(response.body.accessToken).not.toEqual(token.accessToken);
59
+ expect(response.body.refreshToken).not.toEqual(token.refreshToken);
60
60
 
61
61
  // Check token is valid
62
- const byAccess = await Token.getByAccessToken(response.body.accessToken)
63
- expect(byAccess).toBeDefined()
62
+ const byAccess = await Token.getByAccessToken(response.body.accessToken);
63
+ expect(byAccess).toBeDefined();
64
64
 
65
- const byRefresh = await Token.getByRefreshToken(response.body.refreshToken)
66
- expect(byRefresh).toBeDefined()
65
+ const byRefresh = await Token.getByRefreshToken(response.body.refreshToken);
66
+ expect(byRefresh).toBeDefined();
67
67
  });
68
68
  });