@stamhoofd/backend 2.88.1 → 2.89.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamhoofd/backend",
3
- "version": "2.88.1",
3
+ "version": "2.89.1",
4
4
  "main": "./dist/index.js",
5
5
  "exports": {
6
6
  ".": {
@@ -44,14 +44,14 @@
44
44
  "@simonbackx/simple-encoding": "2.22.0",
45
45
  "@simonbackx/simple-endpoints": "1.20.1",
46
46
  "@simonbackx/simple-logging": "^1.0.1",
47
- "@stamhoofd/backend-i18n": "2.88.1",
48
- "@stamhoofd/backend-middleware": "2.88.1",
49
- "@stamhoofd/email": "2.88.1",
50
- "@stamhoofd/models": "2.88.1",
51
- "@stamhoofd/queues": "2.88.1",
52
- "@stamhoofd/sql": "2.88.1",
53
- "@stamhoofd/structures": "2.88.1",
54
- "@stamhoofd/utility": "2.88.1",
47
+ "@stamhoofd/backend-i18n": "2.89.1",
48
+ "@stamhoofd/backend-middleware": "2.89.1",
49
+ "@stamhoofd/email": "2.89.1",
50
+ "@stamhoofd/models": "2.89.1",
51
+ "@stamhoofd/queues": "2.89.1",
52
+ "@stamhoofd/sql": "2.89.1",
53
+ "@stamhoofd/structures": "2.89.1",
54
+ "@stamhoofd/utility": "2.89.1",
55
55
  "archiver": "^7.0.1",
56
56
  "axios": "^1.8.2",
57
57
  "cookie": "^0.7.0",
@@ -69,5 +69,5 @@
69
69
  "publishConfig": {
70
70
  "access": "public"
71
71
  },
72
- "gitHead": "33241749f01af23fbe52480a8a89a2bfd695b22d"
72
+ "gitHead": "538a0e198d2db14c1e7650c75a645113b4394e71"
73
73
  }
@@ -1,13 +1,13 @@
1
1
  import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
2
2
  import { User } from '@stamhoofd/models';
3
- import { User as UserStruct } from '@stamhoofd/structures';
3
+ import { OrganizationAdmins } from '@stamhoofd/structures';
4
4
 
5
5
  import { Context } from '../../../helpers/Context';
6
- import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
6
+
7
7
  type Params = Record<string, never>;
8
8
  type Query = undefined;
9
9
  type Body = undefined;
10
- type ResponseBody = UserStruct[];
10
+ type ResponseBody = OrganizationAdmins;
11
11
 
12
12
  export class GetPlatformAdminsEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
13
13
  protected doesMatch(request: Request): [true, Params] | [false] {
@@ -35,7 +35,9 @@ export class GetPlatformAdminsEndpoint extends Endpoint<Params, Query, Body, Res
35
35
  const admins = await User.getPlatformAdmins();
36
36
 
37
37
  return new Response(
38
- await AuthenticatedStructures.usersWithMembers(admins),
38
+ OrganizationAdmins.create({
39
+ users: admins.map(user => user.getStructure()),
40
+ }),
39
41
  );
40
42
  }
41
43
  }
@@ -324,7 +324,13 @@ export class PatchOrganizationRegistrationPeriodsEndpoint extends Endpoint<Param
324
324
  for (const s of struct.groups) {
325
325
  s.settings.registeredMembers = 0;
326
326
  s.settings.reservedMembers = 0;
327
- await PatchOrganizationRegistrationPeriodsEndpoint.createGroup(s, organization.id, period);
327
+ try {
328
+ await PatchOrganizationRegistrationPeriodsEndpoint.createGroup(s, organization.id, period);
329
+ }
330
+ catch (e) {
331
+ // Can happen when a group is no longer valid anymore when duplicating a period
332
+ console.error('Error creating group', s.id, e);
333
+ }
328
334
  }
329
335
  const groups = await Group.getAll(organization.id, organizationPeriod.periodId);
330
336
 
@@ -2,7 +2,6 @@ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-
2
2
  import { User } from '@stamhoofd/models';
3
3
  import { OrganizationAdmins } from '@stamhoofd/structures';
4
4
 
5
- import { AuthenticatedStructures } from '../../../../helpers/AuthenticatedStructures';
6
5
  import { Context } from '../../../../helpers/Context';
7
6
  type Params = Record<string, never>;
8
7
  type Query = undefined;
@@ -35,8 +34,10 @@ export class GetOrganizationAdminsEndpoint extends Endpoint<Params, Query, Body,
35
34
  // Get all admins
36
35
  const admins = await User.getAdmins(organization.id);
37
36
 
38
- return new Response(OrganizationAdmins.create({
39
- users: await AuthenticatedStructures.usersWithMembers(admins),
40
- }));
37
+ return new Response(
38
+ OrganizationAdmins.create({
39
+ users: admins.map(user => user.getStructure()),
40
+ }),
41
+ );
41
42
  }
42
43
  }
@@ -1,5 +1,5 @@
1
1
  import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
2
- import { SimpleError } from '@simonbackx/simple-errors';
2
+ import { isSimpleError, isSimpleErrors, SimpleError } from '@simonbackx/simple-errors';
3
3
  import { UitpasPriceCheckRequest, UitpasPriceCheckResponse } from '@stamhoofd/structures';
4
4
 
5
5
  import { UitpasNumberValidator } from '../../../helpers/UitpasNumberValidator';
@@ -9,7 +9,7 @@ type Query = undefined;
9
9
  type Body = UitpasPriceCheckRequest;
10
10
  type ResponseBody = UitpasPriceCheckResponse;
11
11
 
12
- export class retrieveUitpasSocialTariffPrice extends Endpoint<Params, Query, Body, ResponseBody> {
12
+ export class RetrieveUitpasSocialTariffPricesEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
13
13
  bodyDecoder = UitpasPriceCheckRequest as Decoder<UitpasPriceCheckRequest>;
14
14
 
15
15
  protected doesMatch(request: Request): [true, Params] | [false] {
@@ -28,7 +28,7 @@ export class retrieveUitpasSocialTariffPrice extends Endpoint<Params, Query, Bod
28
28
  async handle(request: DecodedRequest<Params, Query, Body>) {
29
29
  if (request.body.uitpasEventId) {
30
30
  // OFFICIAL FLOW
31
- if (!request.body.uitpasNumber) {
31
+ if (!request.body.uitpasNumbers) {
32
32
  // STATIC CHECK
33
33
  // request shouldn't include a reduced price
34
34
  }
@@ -44,7 +44,7 @@ export class retrieveUitpasSocialTariffPrice extends Endpoint<Params, Query, Bod
44
44
  }
45
45
  else {
46
46
  // NON-OFFICIAL FLOW
47
- // request should include UiTPAS-number, reduced price AND base price
47
+ // request should include UiTPAS-numbers, reduced price AND base price
48
48
  if (!request.body.reducedPrice) {
49
49
  throw new SimpleError({
50
50
  code: 'missing_reduced_price',
@@ -52,16 +52,25 @@ export class retrieveUitpasSocialTariffPrice extends Endpoint<Params, Query, Bod
52
52
  human: $t('Je moet een verlaagd tarief opgeven voor de UiTPAS.'),
53
53
  });
54
54
  }
55
- if (!request.body.uitpasNumber) {
55
+ const reducedPrice = request.body.reducedPrice;
56
+ if (!request.body.uitpasNumbers) {
56
57
  throw new SimpleError({
57
- code: 'missing_uitpas_number',
58
- message: 'Uitpas number must be provided for non-official flow.',
59
- human: $t('Je moet een UiTPAS-nummer opgeven.'),
58
+ code: 'missing_uitpas_numbers',
59
+ message: 'Uitpas numbers must be provided for non-official flow.',
60
+ human: $t('Je moet UiTPAS-nummers opgeven.'),
60
61
  });
61
62
  }
62
- await UitpasNumberValidator.checkUitpasNumber(request.body.uitpasNumber);
63
+ try {
64
+ await UitpasNumberValidator.checkUitpasNumbers(request.body.uitpasNumbers); // Throws if invalid
65
+ }
66
+ catch (e) {
67
+ if (isSimpleError(e) || isSimpleErrors(e)) {
68
+ e.addNamespace('uitpasNumbers');
69
+ }
70
+ throw e;
71
+ }
63
72
  const uitpasPriceCheckResponse = UitpasPriceCheckResponse.create({
64
- price: request.body.reducedPrice,
73
+ prices: request.body.uitpasNumbers.map(_ => reducedPrice), // All reduced prices are the same in this non-official flow
65
74
  });
66
75
  return new Response(uitpasPriceCheckResponse);
67
76
  }
@@ -157,7 +157,6 @@ export class MemberUserSyncerStatic {
157
157
 
158
158
  async updateInheritedPermissions(user: User) {
159
159
  // Fetch all members for this user
160
-
161
160
  const responsibilities = user.memberId ? (await this.getResponsibilitiesForMembers([user.memberId])) : [];
162
161
 
163
162
  // Check if the member has active registrations
@@ -144,7 +144,12 @@ export class PeriodHelper {
144
144
  );
145
145
 
146
146
  for (const organization of organizations) {
147
- await this.moveOrganizationToPeriod(organization, period);
147
+ try {
148
+ await this.moveOrganizationToPeriod(organization, period);
149
+ }
150
+ catch (error) {
151
+ console.error('Error moving organization to period', organization.id, error);
152
+ }
148
153
  lastId = organization.id;
149
154
  }
150
155
 
@@ -1,4 +1,4 @@
1
- import { SimpleError } from '@simonbackx/simple-errors';
1
+ import { isSimpleError, isSimpleErrors, SimpleError, SimpleErrors } from '@simonbackx/simple-errors';
2
2
  import { UitpasTokenRepository } from './UitpasTokenRepository';
3
3
  import { DataValidator } from '@stamhoofd/utility';
4
4
 
@@ -152,6 +152,34 @@ export class UitpasNumberValidatorStatic {
152
152
  }
153
153
  // no errors -> the uitpas number is valid and social tariff is applicable
154
154
  }
155
+
156
+ /**
157
+ * Checks multiple uitpas numbers
158
+ * If any of the uitpas numbers is invalid, it will throw a SimpleErrors instance with all errors.
159
+ * The field of the error will be the index of the uitpas number in the array.
160
+ * @param uitpasNumbers The uitpas numbers to check
161
+ */
162
+ async checkUitpasNumbers(uitpasNumbers: string[]) {
163
+ const simpleErrors = new SimpleErrors();
164
+ for (let i = 0; i < uitpasNumbers.length; i++) {
165
+ const uitpasNumber = uitpasNumbers[i];
166
+ try {
167
+ await this.checkUitpasNumber(uitpasNumber); // Throws if invalid
168
+ }
169
+ catch (e) {
170
+ if (isSimpleError(e) || isSimpleErrors(e)) {
171
+ e.addNamespace(i.toString());
172
+ simpleErrors.addError(e);
173
+ }
174
+ else {
175
+ throw e;
176
+ }
177
+ }
178
+ }
179
+ if (simpleErrors.errors.length > 0) {
180
+ throw simpleErrors;
181
+ }
182
+ }
155
183
  }
156
184
 
157
185
  export const UitpasNumberValidator = new UitpasNumberValidatorStatic();