@stamhoofd/backend 2.19.0 → 2.20.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.
@@ -58,7 +58,7 @@
58
58
  "LATEST_IOS_VERSION": 0,
59
59
  "LATEST_ANDROID_VERSION": 0,
60
60
 
61
- "NOLT_SSO_SECRET_KEY": "",
61
+ "NOLT_SSO_SECRET_KEY": "optional",
62
62
  "INTERNAL_SECRET_KEY": "",
63
63
  "CRONS_DISABLED": false,
64
64
  "WHITELISTED_EMAIL_DESTINATIONS": ["*"],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamhoofd/backend",
3
- "version": "2.19.0",
3
+ "version": "2.20.0",
4
4
  "main": "./dist/index.js",
5
5
  "exports": {
6
6
  ".": {
@@ -39,10 +39,10 @@
39
39
  "@stamhoofd/backend-i18n": "^2.17.0",
40
40
  "@stamhoofd/backend-middleware": "^2.17.0",
41
41
  "@stamhoofd/email": "^2.17.0",
42
- "@stamhoofd/models": "^2.19.0",
42
+ "@stamhoofd/models": "^2.20.0",
43
43
  "@stamhoofd/queues": "^2.17.3",
44
- "@stamhoofd/sql": "^2.18.0",
45
- "@stamhoofd/structures": "^2.19.0",
44
+ "@stamhoofd/sql": "^2.20.0",
45
+ "@stamhoofd/structures": "^2.20.0",
46
46
  "@stamhoofd/utility": "^2.17.0",
47
47
  "archiver": "^7.0.1",
48
48
  "aws-sdk": "^2.885.0",
@@ -60,5 +60,5 @@
60
60
  "postmark": "4.0.2",
61
61
  "stripe": "^16.6.0"
62
62
  },
63
- "gitHead": "876e7b976122e1c2f67d4cceebe92ec2af2bc35a"
63
+ "gitHead": "946c0ddcaa7cdc9b769d4dc9083a517fe7ad19f8"
64
64
  }
package/src/crons.ts CHANGED
@@ -1,21 +1,14 @@
1
1
  import { Database } from '@simonbackx/simple-database';
2
2
  import { logger, StyledText } from "@simonbackx/simple-logging";
3
3
  import { I18n } from '@stamhoofd/backend-i18n';
4
- import { Email } from '@stamhoofd/email';
5
- import { EmailAddress } from '@stamhoofd/email';
6
- import { Group, STPackage, Webshop } from '@stamhoofd/models';
7
- import { Organization } from '@stamhoofd/models';
8
- import { Payment } from '@stamhoofd/models';
9
- import { Registration } from '@stamhoofd/models';
10
- import { STInvoice } from '@stamhoofd/models';
11
- import { STPendingInvoice } from '@stamhoofd/models';
4
+ import { Email, EmailAddress } from '@stamhoofd/email';
5
+ import { Group, Organization, Payment, Registration, STPackage, STPendingInvoice, Webshop } from '@stamhoofd/models';
12
6
  import { QueueHandler } from '@stamhoofd/queues';
13
7
  import { PaymentMethod, PaymentProvider, PaymentStatus } from '@stamhoofd/structures';
14
8
  import { Formatter, sleep } from '@stamhoofd/utility';
15
9
  import AWS from 'aws-sdk';
16
10
  import { DateTime } from 'luxon';
17
11
 
18
- import { ExchangeSTPaymentEndpoint } from './endpoints/global/payments/ExchangeSTPaymentEndpoint';
19
12
  import { ExchangePaymentEndpoint } from './endpoints/organization/shared/ExchangePaymentEndpoint';
20
13
  import { checkSettlements } from './helpers/CheckSettlements';
21
14
  import { ForwardHandler } from './helpers/ForwardHandler';
@@ -471,12 +464,7 @@ async function checkPayments() {
471
464
  continue;
472
465
  }
473
466
  } else {
474
- // Try stamhoofd payment
475
- const invoices = await STInvoice.where({ paymentId: payment.id })
476
- if (invoices.length === 1) {
477
- await ExchangeSTPaymentEndpoint.pollStatus(payment, invoices[0])
478
- continue
479
- }
467
+ // deprecated
480
468
  }
481
469
 
482
470
  // Check expired
@@ -599,52 +587,6 @@ async function checkReservedUntil() {
599
587
  }
600
588
  }
601
589
 
602
-
603
- // Wait for midnight before checking billing
604
- let lastBillingCheck: Date | null = new Date()
605
- let lastBillingId = ""
606
- async function checkBilling() {
607
- if (STAMHOOFD.environment === "development") {
608
- return
609
- }
610
-
611
- console.log("[BILLING] Checking billing...")
612
-
613
- // Wait for the next day before doing a new check
614
- if (lastBillingCheck && Formatter.dateIso(lastBillingCheck) === Formatter.dateIso(new Date())) {
615
- console.log("[BILLING] Billing check done for today")
616
- return
617
- }
618
-
619
- const organizations = await Organization.where({ id: { sign: '>', value: lastBillingId } }, {
620
- limit: 10,
621
- sort: ["id"]
622
- })
623
-
624
- if (organizations.length == 0) {
625
- // Wait again until next day
626
- lastBillingId = ""
627
- lastBillingCheck = new Date()
628
- return
629
- }
630
-
631
- for (const organization of organizations) {
632
- console.log("[BILLING] Checking billing for "+organization.name)
633
-
634
- try {
635
- await QueueHandler.schedule("billing/invoices-"+organization.id, async () => {
636
- await STPendingInvoice.addAutomaticItems(organization)
637
- });
638
- } catch (e) {
639
- console.error(e)
640
- }
641
-
642
- }
643
-
644
- lastBillingId = organizations[organizations.length - 1].id
645
-
646
- }
647
-
648
590
  let lastDripCheck: Date | null = null
649
591
  let lastDripId = ""
650
592
  async function checkDrips() {
@@ -723,12 +665,6 @@ registeredCronJobs.push({
723
665
  running: false
724
666
  });
725
667
 
726
- registeredCronJobs.push({
727
- name: 'checkBilling',
728
- method: checkBilling,
729
- running: false
730
- });
731
-
732
668
  registeredCronJobs.push({
733
669
  name: 'checkReservedUntil',
734
670
  method: checkReservedUntil,
@@ -9,6 +9,7 @@ import { Formatter } from '@stamhoofd/utility';
9
9
  import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
10
10
  import { Context } from '../../../helpers/Context';
11
11
  import { MemberUserSyncer } from '../../../helpers/MemberUserSyncer';
12
+ import { SetupStepUpdater } from '../../../helpers/SetupStepsUpdater';
12
13
 
13
14
  type Params = Record<string, never>;
14
15
  type Query = undefined;
@@ -150,6 +151,8 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
150
151
  await MemberUserSyncer.onChangeMember(member)
151
152
  }
152
153
 
154
+ let shouldUpdateSetupSteps = false;
155
+
153
156
  // Loop all members one by one
154
157
  for (let patch of request.body.getPatches()) {
155
158
  const member = members.find(m => m.id === patch.id) ?? await Member.getWithRegistrations(patch.id)
@@ -223,6 +226,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
223
226
  }
224
227
 
225
228
  await responsibilityRecord.save()
229
+ shouldUpdateSetupSteps = true;
226
230
  }
227
231
 
228
232
  // Create responsibilities
@@ -323,6 +327,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
323
327
  model.startDate = put.startDate
324
328
 
325
329
  await model.save()
330
+ shouldUpdateSetupSteps = true;
326
331
  }
327
332
 
328
333
  // Auto link users based on data
@@ -443,7 +448,6 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
443
448
  updateMembershipMemberIds.add(member.id)
444
449
  }
445
450
 
446
-
447
451
  if (!members.find(m => m.id === member.id)) {
448
452
  members.push(member)
449
453
  }
@@ -460,6 +464,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
460
464
  await User.deleteForDeletedMember(member.id)
461
465
  await BalanceItem.deleteForDeletedMember(member.id)
462
466
  await member.delete()
467
+ shouldUpdateSetupSteps = true
463
468
 
464
469
  // Update occupancy of this member because we removed registrations
465
470
  const groupIds = member.registrations.flatMap(r => r.groupId)
@@ -498,6 +503,10 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
498
503
  }
499
504
  }
500
505
 
506
+ if(shouldUpdateSetupSteps && organization) {
507
+ SetupStepUpdater.updateForOrganization(organization).catch(console.error);
508
+ }
509
+
501
510
  return new Response(
502
511
  await AuthenticatedStructures.membersBlob(members)
503
512
  );
@@ -1,15 +1,10 @@
1
1
 
2
2
  import { Request } from "@simonbackx/simple-endpoints";
3
- import { Organization, OrganizationFactory, RegisterCodeFactory, STCredit } from "@stamhoofd/models";
4
3
  import { Address, Country, CreateOrganization, NewUser, Organization as OrganizationStruct, Version } from "@stamhoofd/structures";
5
4
 
6
5
  import { testServer } from "../../../../tests/helpers/TestServer";
7
6
  import { CreateOrganizationEndpoint } from "./CreateOrganizationEndpoint";
8
7
 
9
- function expect_toBeDefined<T>(arg: T): asserts arg is NonNullable<T> {
10
- expect(arg).toBeDefined();
11
- }
12
-
13
8
  describe("Endpoint.CreateOrganization", () => {
14
9
  // Test endpoint
15
10
  const endpoint = new CreateOrganizationEndpoint();
@@ -60,46 +55,4 @@ describe("Endpoint.CreateOrganization", () => {
60
55
 
61
56
  await expect(testServer.test(endpoint, r)).rejects.toThrow(/name/);
62
57
  });
63
-
64
- test("Can create an organization with a register code and apply the discount", async () => {
65
- const otherOrganization = await new OrganizationFactory({}).create();
66
- const code = await new RegisterCodeFactory({organization: otherOrganization}).create();
67
- const uri = 'my-organization-with-a-discount';
68
-
69
- const r = Request.buildJson(
70
- "POST",
71
- "/organizations",
72
- "todo-host.be",
73
- CreateOrganization.create({
74
- organization: OrganizationStruct.create({
75
- name: "My organization with a discount",
76
- uri,
77
- address: Address.create({
78
- street: "My street",
79
- number: "1",
80
- postalCode: "9000",
81
- city: "Gent",
82
- country: Country.Belgium
83
- }),
84
- }),
85
- user: NewUser.create({
86
- email: "voorbeeld@stamhoofd.be",
87
- password: "My user password",
88
- }),
89
- registerCode: code.code
90
- })
91
- );
92
-
93
- const response = await testServer.test(endpoint, r);
94
- expect(response.body.token).not.toBeEmpty();
95
-
96
- const organization = await Organization.getByURI(uri);
97
- expect_toBeDefined(organization);
98
-
99
- // Check if this organization has an open register code
100
- const credits = await STCredit.getForOrganization(organization.id);
101
- expect(credits.length).toBe(1);
102
- expect(credits[0].change).toBe(code.value);
103
- });
104
-
105
58
  });
@@ -1,9 +1,7 @@
1
- import { Model } from '@simonbackx/simple-database';
2
1
  import { Decoder } from '@simonbackx/simple-encoding';
3
2
  import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
4
3
  import { SimpleError } from '@simonbackx/simple-errors';
5
- import { Email, EmailInterfaceBase } from '@stamhoofd/email';
6
- import { EmailVerificationCode, Organization, RegisterCode, User } from '@stamhoofd/models';
4
+ import { EmailVerificationCode, Organization, User } from '@stamhoofd/models';
7
5
  import { CreateOrganization, PermissionLevel, Permissions, SignupResponse, UserPermissions } from "@stamhoofd/structures";
8
6
  import { Formatter } from "@stamhoofd/utility";
9
7
 
@@ -83,14 +81,14 @@ export class CreateOrganizationEndpoint extends Endpoint<Params, Query, Body, Re
83
81
  organization.name = request.body.organization.name;
84
82
 
85
83
  // Delay save until after organization is saved, but do validations before the organization is saved
86
- let registerCodeModels: Model[] = []
87
- let delayEmails: EmailInterfaceBase[] = []
84
+ // let registerCodeModels: Model[] = []
85
+ // let delayEmails: EmailInterfaceBase[] = []
88
86
 
89
- if (request.body.registerCode) {
90
- const applied = await RegisterCode.applyRegisterCode(organization, request.body.registerCode)
91
- registerCodeModels = applied.models
92
- delayEmails = applied.emails
93
- }
87
+ //if (request.body.registerCode) {
88
+ // const applied = await RegisterCode.applyRegisterCode(organization, request.body.registerCode)
89
+ // registerCodeModels = applied.models
90
+ // delayEmails = applied.emails
91
+ //}
94
92
 
95
93
  organization.uri = uri;
96
94
  organization.meta = request.body.organization.meta
@@ -126,16 +124,16 @@ export class CreateOrganizationEndpoint extends Endpoint<Params, Query, Body, Re
126
124
  user.permissions.organizationPermissions.set(organization.id, Permissions.create({ level: PermissionLevel.Full }))
127
125
  await user.save()
128
126
 
129
- for (const model of registerCodeModels) {
130
- await model.save()
131
- }
127
+ // for (const model of registerCodeModels) {
128
+ // await model.save()
129
+ // }
132
130
 
133
131
  const code = await EmailVerificationCode.createFor(user, user.email)
134
132
  code.send(user, organization, request.i18n)
135
133
 
136
- for (const email of delayEmails) {
137
- Email.sendInternal(email, organization.i18n)
138
- }
134
+ // for (const email of delayEmails) {
135
+ // Email.sendInternal(email, organization.i18n)
136
+ // }
139
137
 
140
138
  return new Response(SignupResponse.create({
141
139
  token: code.token
@@ -45,7 +45,7 @@ export class SearchOrganizationEndpoint extends Endpoint<Params, Query, Body, Re
45
45
  };
46
46
 
47
47
  // We had to add an order by in the query to fix the limit. MySQL doesn't want to limit the results correctly if we don't explicitly sort the results on their relevance
48
- const organizations = await Organization.where({ searchIndex: match }, {
48
+ const organizations = await Organization.where({ searchIndex: match, active: 1 }, {
49
49
  limit: 15,
50
50
  sort: [
51
51
  {
@@ -1,7 +1,7 @@
1
1
  import { AutoEncoderPatchType, Decoder, patchObject } from "@simonbackx/simple-encoding";
2
2
  import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
3
3
  import { Organization, Platform, RegistrationPeriod } from "@stamhoofd/models";
4
- import { PlatformPremiseType, Platform as PlatformStruct } from "@stamhoofd/structures";
4
+ import { MemberResponsibility, PlatformConfig, PlatformPremiseType, Platform as PlatformStruct } from "@stamhoofd/structures";
5
5
 
6
6
  import { SimpleError } from "@simonbackx/simple-errors";
7
7
  import { Context } from "../../../helpers/Context";
@@ -12,8 +12,15 @@ type Query = undefined;
12
12
  type Body = AutoEncoderPatchType<PlatformStruct>;
13
13
  type ResponseBody = PlatformStruct;
14
14
 
15
- export class PatchPlatformEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
16
- bodyDecoder = PlatformStruct.patchType() as Decoder<AutoEncoderPatchType<PlatformStruct>>
15
+ export class PatchPlatformEndpoint extends Endpoint<
16
+ Params,
17
+ Query,
18
+ Body,
19
+ ResponseBody
20
+ > {
21
+ bodyDecoder = PlatformStruct.patchType() as Decoder<
22
+ AutoEncoderPatchType<PlatformStruct>
23
+ >;
17
24
 
18
25
  protected doesMatch(request: Request): [true, Params] | [false] {
19
26
  if (request.method != "PATCH") {
@@ -29,65 +36,102 @@ export class PatchPlatformEndpoint extends Endpoint<Params, Query, Body, Respons
29
36
  }
30
37
 
31
38
  async handle(request: DecodedRequest<Params, Query, Body>) {
32
- await Context.authenticate()
39
+ await Context.authenticate();
33
40
 
34
41
  // Fast throw first (more in depth checking for patches later)
35
42
  if (!Context.auth.hasPlatformFullAccess()) {
36
- throw Context.auth.error()
43
+ throw Context.auth.error();
37
44
  }
38
45
 
39
- const platform = await Platform.getShared()
46
+ const platform = await Platform.getShared();
40
47
 
41
48
  if (request.body.privateConfig) {
42
49
  // Did we patch roles?
43
50
  if (request.body.privateConfig.roles) {
44
51
  if (!Context.auth.canManagePlatformAdmins()) {
45
- throw Context.auth.error()
52
+ throw Context.auth.error();
46
53
  }
47
54
 
48
55
  // Update roles
49
- platform.privateConfig.roles = patchObject(platform.privateConfig.roles, request.body.privateConfig.roles)
56
+ platform.privateConfig.roles = patchObject(
57
+ platform.privateConfig.roles,
58
+ request.body.privateConfig.roles
59
+ );
50
60
  }
51
61
 
52
62
  if (request.body.privateConfig.emails) {
53
63
  if (!Context.auth.hasPlatformFullAccess()) {
54
- throw Context.auth.error()
64
+ throw Context.auth.error();
55
65
  }
56
66
 
57
67
  // Update roles
58
- platform.privateConfig.emails = patchObject(platform.privateConfig.emails, request.body.privateConfig.emails)
68
+ platform.privateConfig.emails = patchObject(
69
+ platform.privateConfig.emails,
70
+ request.body.privateConfig.emails
71
+ );
59
72
  }
60
73
  }
61
74
 
75
+ let shouldUpdateSetupSteps = false;
76
+
62
77
  if (request.body.config) {
63
78
  if (!Context.auth.hasPlatformFullAccess()) {
64
- throw Context.auth.error()
79
+ throw Context.auth.error();
65
80
  }
66
81
 
82
+ const newConfig = request.body.config;
83
+
67
84
  // Update config
68
- if(request.body.config.premiseTypes) {
69
- const oldConfig = platform.config.clone();
70
- platform.config = patchObject(platform.config, request.body.config);
71
- const newPremiseTypes = platform.config.premiseTypes;
72
-
73
- // update setup step premise types
74
- if(this.shouldUpdateSetupStepPremise(newPremiseTypes, oldConfig.premiseTypes)) {
75
- await SetupStepUpdater.updateSetupStepsForAllOrganizationsInCurrentPeriod({premiseTypes: newPremiseTypes});
85
+ if (newConfig) {
86
+ if (newConfig.premiseTypes || newConfig.responsibilities) {
87
+ const oldConfig = platform.config.clone();
88
+ platform.config = patchObject(platform.config, newConfig);
89
+ const currentConfig = platform.config;
90
+
91
+ shouldUpdateSetupSteps = this.shouldUpdateSetupSteps(
92
+ currentConfig,
93
+ newConfig,
94
+ oldConfig
95
+ );
96
+ } else {
97
+ platform.config = patchObject(platform.config, newConfig);
76
98
  }
77
- } else {
78
- platform.config = patchObject(platform.config, request.body.config)
79
99
  }
80
100
  }
81
101
 
82
- if (request.body.period && request.body.period.id !== platform.periodId) {
83
- const period = await RegistrationPeriod.getByID(request.body.period.id)
102
+ if (
103
+ request.body.period &&
104
+ request.body.period.id !== platform.periodId
105
+ ) {
106
+ const period = await RegistrationPeriod.getByID(
107
+ request.body.period.id
108
+ );
84
109
  if (!period || period.organizationId) {
85
110
  throw new SimpleError({
86
111
  code: "invalid_period",
87
- message: "Invalid period"
88
- })
112
+ message: "Invalid period",
113
+ });
114
+ }
115
+ platform.periodId = period.id;
116
+ }
117
+
118
+ if (request.body.membershipOrganizationId !== undefined) {
119
+ if (!Context.auth.hasPlatformFullAccess()) {
120
+ throw Context.auth.error()
121
+ }
122
+
123
+ if (request.body.membershipOrganizationId) {
124
+ const organization = await Organization.getByID(request.body.membershipOrganizationId)
125
+ if (!organization) {
126
+ throw new SimpleError({
127
+ code: "invalid_organization",
128
+ message: "Invalid organization"
129
+ })
130
+ }
131
+ platform.membershipOrganizationId = organization.id
132
+ } else {
133
+ platform.membershipOrganizationId = null
89
134
  }
90
- platform.periodId = period.id
91
135
  }
92
136
 
93
137
  if (request.body.membershipOrganizationId !== undefined) {
@@ -109,35 +153,126 @@ export class PatchPlatformEndpoint extends Endpoint<Params, Query, Body, Respons
109
153
  }
110
154
  }
111
155
 
112
- await platform.save()
156
+ await platform.save();
157
+
158
+ if(shouldUpdateSetupSteps) {
159
+ SetupStepUpdater.updateSetupStepsForAllOrganizationsInCurrentPeriod().catch(console.error);
160
+ }
161
+
113
162
  return new Response(await Platform.getSharedPrivateStruct());
114
163
  }
115
164
 
116
- private shouldUpdateSetupStepPremise(newPremiseTypes: PlatformPremiseType[], oldPremiseTypes: PlatformPremiseType[]) {
117
- for(const premiseType of newPremiseTypes) {
165
+ private shouldUpdateSetupSteps(
166
+ currentConfig: PlatformConfig,
167
+ newConfig: PlatformConfig | AutoEncoderPatchType<PlatformConfig>,
168
+ oldConfig: PlatformConfig
169
+ ): boolean {
170
+ let shouldUpdate = false;
171
+ const premiseTypes: PlatformPremiseType[] = currentConfig.premiseTypes;
172
+ const responsibilities: MemberResponsibility[] =
173
+ currentConfig.responsibilities;
174
+
175
+ if (
176
+ newConfig.premiseTypes &&
177
+ this.shouldUpdateSetupStepPremise(
178
+ premiseTypes,
179
+ oldConfig.premiseTypes
180
+ )
181
+ ) {
182
+ shouldUpdate = true;
183
+ }
184
+
185
+ if (
186
+ !shouldUpdate &&
187
+ newConfig.responsibilities &&
188
+ this.shouldUpdateSetupStepFunctions(
189
+ responsibilities,
190
+ oldConfig.responsibilities
191
+ )
192
+ ) {
193
+ shouldUpdate = true;
194
+ }
195
+
196
+ return shouldUpdate;
197
+ }
198
+
199
+ private shouldUpdateSetupStepPremise(
200
+ newPremiseTypes: PlatformPremiseType[],
201
+ oldPremiseTypes: PlatformPremiseType[]
202
+ ) {
203
+ for (const premiseType of newPremiseTypes) {
118
204
  const id = premiseType.id;
119
- const oldVersion = oldPremiseTypes.find(x => x.id === id);
205
+ const oldVersion = oldPremiseTypes.find((x) => x.id === id);
120
206
 
121
207
  // if premise type is not new
122
- if(oldVersion) {
123
- if(oldVersion.min !== premiseType.min || oldVersion.max !== premiseType.max) {
208
+ if (oldVersion) {
209
+ if (
210
+ oldVersion.min !== premiseType.min ||
211
+ oldVersion.max !== premiseType.max
212
+ ) {
124
213
  return true;
125
214
  }
126
215
  continue;
127
216
  }
128
217
 
129
218
  // if premise type is new
130
- if(premiseType.min || premiseType.max) {
219
+ if (premiseType.min || premiseType.max) {
131
220
  return true;
132
221
  }
133
222
  }
134
223
 
135
- for(const oldPremiseType of oldPremiseTypes) {
224
+ for (const oldPremiseType of oldPremiseTypes) {
136
225
  const id = oldPremiseType.id;
137
226
 
138
227
  // if premise type is removed
139
- if(!newPremiseTypes.some(x => x.id === id)) {
140
- if(oldPremiseType.min || oldPremiseType.max) {
228
+ if (!newPremiseTypes.some((x) => x.id === id)) {
229
+ if (oldPremiseType.min || oldPremiseType.max) {
230
+ return true;
231
+ }
232
+ }
233
+ }
234
+ }
235
+
236
+ private shouldUpdateSetupStepFunctions(
237
+ newResponsibilities: MemberResponsibility[],
238
+ oldResponsibilities: MemberResponsibility[]
239
+ ) {
240
+ for (const responsibility of newResponsibilities) {
241
+ const id = responsibility.id;
242
+ const oldVersion = oldResponsibilities.find((x) => x.id === id);
243
+
244
+ // if responsibility is not new
245
+ if (oldVersion) {
246
+ // if restrictions changed
247
+ if (
248
+ oldVersion.minimumMembers !==
249
+ responsibility.minimumMembers ||
250
+ oldVersion.maximumMembers !== responsibility.maximumMembers
251
+ ) {
252
+ return true;
253
+ }
254
+ continue;
255
+ }
256
+
257
+ // if responsibility is new
258
+ if (
259
+ responsibility.minimumMembers ||
260
+ responsibility.maximumMembers
261
+ ) {
262
+ return true;
263
+ }
264
+ }
265
+
266
+ for (const oldResponsibility of oldResponsibilities) {
267
+ const id = oldResponsibility.id;
268
+
269
+ // if responsibility is removed
270
+ if (!newResponsibilities.some((x) => x.id === id)) {
271
+ // if responsibility had restrictions
272
+ if (
273
+ oldResponsibility.minimumMembers ||
274
+ oldResponsibility.maximumMembers
275
+ ) {
141
276
  return true;
142
277
  }
143
278
  }
@@ -3,6 +3,7 @@ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-
3
3
  import jwt from 'jsonwebtoken';
4
4
 
5
5
  import { Context } from '../../../../helpers/Context';
6
+ import { SimpleError } from '@simonbackx/simple-errors';
6
7
 
7
8
  type Params = Record<string, never>;
8
9
  type Query = undefined;
@@ -39,7 +40,7 @@ export class CreateNoltTokenEndpoint extends Endpoint<Params, Query, Body, Respo
39
40
  if (!await Context.auth.hasSomeAccess(organization.id)) {
40
41
  throw Context.auth.error()
41
42
  }
42
-
43
+
43
44
  // Create token
44
45
  const payload = {
45
46
  // The ID that you use in your app for this user