@stamhoofd/backend 2.4.0 → 2.6.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.
- package/package.json +3 -3
- package/src/endpoints/admin/invoices/GetInvoicesEndpoint.ts +1 -1
- package/src/endpoints/global/events/PatchEventsEndpoint.ts +16 -9
- package/src/endpoints/global/members/GetMembersEndpoint.ts +18 -6
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +21 -8
- package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.ts +3 -2
- package/src/endpoints/global/organizations/GetOrganizationFromUriEndpoint.ts +2 -1
- package/src/endpoints/global/organizations/SearchOrganizationEndpoint.ts +2 -1
- package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +6 -0
- package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +417 -178
- package/src/endpoints/global/webshops/GetWebshopFromDomainEndpoint.ts +5 -5
- package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +88 -11
- package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +10 -4
- package/src/endpoints/organization/dashboard/stripe/GetStripeAccountLinkEndpoint.ts +4 -1
- package/src/endpoints/organization/dashboard/stripe/GetStripeLoginLinkEndpoint.ts +6 -0
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +7 -2
- package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +13 -28
- package/src/helpers/AdminPermissionChecker.ts +9 -4
- package/src/helpers/AuthenticatedStructures.ts +89 -28
- package/src/helpers/MemberUserSyncer.ts +5 -5
- package/src/helpers/StripeHelper.ts +83 -40
- package/src/helpers/StripePayoutChecker.ts +7 -5
- package/src/seeds/1722344160-update-membership.ts +57 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stamhoofd/backend",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"node-rsa": "1.1.1",
|
|
49
49
|
"openid-client": "^5.4.0",
|
|
50
50
|
"postmark": "4.0.2",
|
|
51
|
-
"stripe": "^
|
|
51
|
+
"stripe": "^16.6.0"
|
|
52
52
|
},
|
|
53
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "7a3f9f6c08058dc8b671befbfad73184afdc6d7c"
|
|
54
54
|
}
|
|
@@ -169,7 +169,7 @@ export class GetInvoicesEndpoint extends Endpoint<Params, Query, Body, ResponseB
|
|
|
169
169
|
STInvoicePrivate.create({
|
|
170
170
|
...invoice,
|
|
171
171
|
payment: payment ? PaymentStruct.create(payment) : null,
|
|
172
|
-
organization: organization ?
|
|
172
|
+
organization: organization ? organization.getBaseStructure() : undefined,
|
|
173
173
|
settlement: payment?.settlement ?? null,
|
|
174
174
|
})
|
|
175
175
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AutoEncoderPatchType, Decoder, PatchableArrayAutoEncoder, PatchableArrayDecoder, patchObject, StringDecoder } from '@simonbackx/simple-encoding';
|
|
2
2
|
import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
|
|
3
|
-
import { Event, Organization, Platform, RegistrationPeriod } from '@stamhoofd/models';
|
|
3
|
+
import { Event, Group, Organization, Platform, RegistrationPeriod } from '@stamhoofd/models';
|
|
4
4
|
import { Event as EventStruct, GroupType, PermissionLevel } from "@stamhoofd/structures";
|
|
5
5
|
|
|
6
6
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
@@ -80,6 +80,12 @@ export class PatchEventsEndpoint extends Endpoint<Params, Query, Body, ResponseB
|
|
|
80
80
|
event.startDate = put.startDate
|
|
81
81
|
event.endDate = put.endDate
|
|
82
82
|
event.meta = put.meta
|
|
83
|
+
event.typeId = await PatchEventsEndpoint.validateEventType(put.typeId)
|
|
84
|
+
await PatchEventsEndpoint.checkEventLimits(event)
|
|
85
|
+
|
|
86
|
+
if (!(await Context.auth.canAccessEvent(event, PermissionLevel.Full))) {
|
|
87
|
+
throw Context.auth.error()
|
|
88
|
+
}
|
|
83
89
|
|
|
84
90
|
if (put.group) {
|
|
85
91
|
const period = await RegistrationPeriod.getByDate(event.startDate)
|
|
@@ -99,14 +105,8 @@ export class PatchEventsEndpoint extends Endpoint<Params, Query, Body, ResponseB
|
|
|
99
105
|
put.group.organizationId,
|
|
100
106
|
period.id
|
|
101
107
|
)
|
|
108
|
+
await event.syncGroupRequirements(group)
|
|
102
109
|
event.groupId = group.id
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
event.typeId = await PatchEventsEndpoint.validateEventType(put.typeId)
|
|
106
|
-
await PatchEventsEndpoint.checkEventLimits(event)
|
|
107
|
-
|
|
108
|
-
if (!(await Context.auth.canAccessEvent(event, PermissionLevel.Full))) {
|
|
109
|
-
throw Context.auth.error()
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
await event.save()
|
|
@@ -130,7 +130,6 @@ export class PatchEventsEndpoint extends Endpoint<Params, Query, Body, ResponseB
|
|
|
130
130
|
event.endDate = patch.endDate ?? event.endDate
|
|
131
131
|
event.meta = patchObject(event.meta, patch.meta)
|
|
132
132
|
|
|
133
|
-
|
|
134
133
|
if (patch.organizationId !== undefined) {
|
|
135
134
|
if (organization?.id && patch.organizationId !== organization.id) {
|
|
136
135
|
throw new SimpleError({
|
|
@@ -210,6 +209,14 @@ export class PatchEventsEndpoint extends Endpoint<Params, Query, Body, ResponseB
|
|
|
210
209
|
}
|
|
211
210
|
|
|
212
211
|
await event.save()
|
|
212
|
+
|
|
213
|
+
if (event.groupId) {
|
|
214
|
+
const group = await Group.getByID(event.groupId)
|
|
215
|
+
if (group) {
|
|
216
|
+
await event.syncGroupRequirements(group)
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
213
220
|
events.push(event)
|
|
214
221
|
}
|
|
215
222
|
|
|
@@ -157,6 +157,15 @@ const filterCompilers: SQLFilterDefinitions = {
|
|
|
157
157
|
.where(
|
|
158
158
|
SQL.column('memberId'),
|
|
159
159
|
SQL.column('members', 'id'),
|
|
160
|
+
).whereNot(
|
|
161
|
+
SQL.column('registeredAt'),
|
|
162
|
+
null,
|
|
163
|
+
).where(
|
|
164
|
+
SQL.column('deactivatedAt'),
|
|
165
|
+
null,
|
|
166
|
+
).where(
|
|
167
|
+
SQL.column('groups', 'deletedAt'),
|
|
168
|
+
null
|
|
160
169
|
),
|
|
161
170
|
{
|
|
162
171
|
...registrationFilterCompilers,
|
|
@@ -245,9 +254,12 @@ const filterCompilers: SQLFilterDefinitions = {
|
|
|
245
254
|
).whereNot(
|
|
246
255
|
SQL.column('registeredAt'),
|
|
247
256
|
null,
|
|
248
|
-
).
|
|
249
|
-
SQL.column('
|
|
250
|
-
|
|
257
|
+
).where(
|
|
258
|
+
SQL.column('deactivatedAt'),
|
|
259
|
+
null,
|
|
260
|
+
).where(
|
|
261
|
+
SQL.column('groups', 'deletedAt'),
|
|
262
|
+
null
|
|
251
263
|
),
|
|
252
264
|
registrationFilterCompilers
|
|
253
265
|
),
|
|
@@ -276,9 +288,9 @@ const filterCompilers: SQLFilterDefinitions = {
|
|
|
276
288
|
).whereNot(
|
|
277
289
|
SQL.column('registeredAt'),
|
|
278
290
|
null,
|
|
279
|
-
).
|
|
280
|
-
SQL.column('groups', '
|
|
281
|
-
|
|
291
|
+
).where(
|
|
292
|
+
SQL.column('groups', 'deletedAt'),
|
|
293
|
+
null
|
|
282
294
|
),
|
|
283
295
|
organizationFilterCompilers
|
|
284
296
|
),
|
|
@@ -106,16 +106,29 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
106
106
|
duplicate.details.merge(member.details)
|
|
107
107
|
member = duplicate
|
|
108
108
|
|
|
109
|
-
//
|
|
109
|
+
// You need write permissions, because a user can potentially earn write permissions on a member
|
|
110
|
+
// by registering it
|
|
111
|
+
if (!await Context.auth.canAccessMember(duplicate, PermissionLevel.Write)) {
|
|
112
|
+
throw new SimpleError({
|
|
113
|
+
code: "known_member_missing_rights",
|
|
114
|
+
message: "Creating known member without sufficient access rights",
|
|
115
|
+
human: "Dit lid is al bekend in het systeem, maar je hebt er geen toegang tot. Vraag iemand met de juiste toegangsrechten om dit lid voor jou toe te voegen, of vraag het lid om zelf in te schrijven via het ledenportaal.",
|
|
116
|
+
statusCode: 400
|
|
117
|
+
})
|
|
118
|
+
}
|
|
110
119
|
}
|
|
111
120
|
|
|
112
121
|
if (struct.registrations.length === 0) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
122
|
+
// We risk creating a new member without being able to access it manually afterwards
|
|
123
|
+
|
|
124
|
+
if ((organization && !await Context.auth.hasFullAccess(organization.id)) || (!organization && !Context.auth.hasPlatformFullAccess())) {
|
|
125
|
+
throw new SimpleError({
|
|
126
|
+
code: "missing_group",
|
|
127
|
+
message: "Missing group",
|
|
128
|
+
human: "Je moet hoofdbeheerder zijn om een lid toe te voegen zonder inschrijving in het systeem",
|
|
129
|
+
statusCode: 400
|
|
130
|
+
})
|
|
131
|
+
}
|
|
119
132
|
}
|
|
120
133
|
|
|
121
134
|
// Throw early
|
|
@@ -223,7 +236,7 @@ export class PatchOrganizationMembersEndpoint extends Endpoint<Params, Query, Bo
|
|
|
223
236
|
// Update registrations
|
|
224
237
|
for (const patchRegistration of patch.registrations.getPatches()) {
|
|
225
238
|
const registration = member.registrations.find(r => r.id === patchRegistration.id)
|
|
226
|
-
if (!registration || registration.memberId != member.id) {
|
|
239
|
+
if (!registration || registration.memberId != member.id || (!await Context.auth.canAccessRegistration(registration, PermissionLevel.Write))) {
|
|
227
240
|
throw new SimpleError({
|
|
228
241
|
code: "permission_denied",
|
|
229
242
|
message: "You don't have permissions to access this endpoint",
|
|
@@ -4,6 +4,7 @@ import { SimpleError } from '@simonbackx/simple-errors';
|
|
|
4
4
|
import { Organization } from '@stamhoofd/models';
|
|
5
5
|
import { Organization as OrganizationStruct } from "@stamhoofd/structures";
|
|
6
6
|
import { GoogleTranslateHelper } from "@stamhoofd/utility";
|
|
7
|
+
import { AuthenticatedStructures } from "../../../helpers/AuthenticatedStructures";
|
|
7
8
|
type Params = Record<string, never>;
|
|
8
9
|
|
|
9
10
|
class Query extends AutoEncoder {
|
|
@@ -60,7 +61,7 @@ export class GetOrganizationFromDomainEndpoint extends Endpoint<Params, Query, B
|
|
|
60
61
|
statusCode: 404
|
|
61
62
|
})
|
|
62
63
|
}
|
|
63
|
-
return new Response(await organization
|
|
64
|
+
return new Response(await AuthenticatedStructures.organization(organization));
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
67
|
|
|
@@ -75,6 +76,6 @@ export class GetOrganizationFromDomainEndpoint extends Endpoint<Params, Query, B
|
|
|
75
76
|
statusCode: 404
|
|
76
77
|
})
|
|
77
78
|
}
|
|
78
|
-
return new Response(await organization
|
|
79
|
+
return new Response(await AuthenticatedStructures.organization(organization));
|
|
79
80
|
}
|
|
80
81
|
}
|
|
@@ -4,6 +4,7 @@ import { SimpleError } from '@simonbackx/simple-errors';
|
|
|
4
4
|
import { Organization } from '@stamhoofd/models';
|
|
5
5
|
import { Organization as OrganizationStruct } from "@stamhoofd/structures";
|
|
6
6
|
import { GoogleTranslateHelper } from "@stamhoofd/utility";
|
|
7
|
+
import { AuthenticatedStructures } from "../../../helpers/AuthenticatedStructures";
|
|
7
8
|
type Params = Record<string, never>;
|
|
8
9
|
|
|
9
10
|
class Query extends AutoEncoder {
|
|
@@ -44,6 +45,6 @@ export class GetOrganizationFromUriEndpoint extends Endpoint<Params, Query, Body
|
|
|
44
45
|
statusCode: 404
|
|
45
46
|
})
|
|
46
47
|
}
|
|
47
|
-
return new Response(await organization
|
|
48
|
+
return new Response(await AuthenticatedStructures.organization(organization));
|
|
48
49
|
}
|
|
49
50
|
}
|
|
@@ -2,6 +2,7 @@ import { AutoEncoder, Decoder, field, StringDecoder } from '@simonbackx/simple-e
|
|
|
2
2
|
import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
|
|
3
3
|
import { Organization } from "@stamhoofd/models";
|
|
4
4
|
import { Organization as OrganizationStruct,OrganizationSimple } from "@stamhoofd/structures";
|
|
5
|
+
import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
|
|
5
6
|
|
|
6
7
|
type Params = Record<string, never>;
|
|
7
8
|
|
|
@@ -57,6 +58,6 @@ export class SearchOrganizationEndpoint extends Endpoint<Params, Query, Body, Re
|
|
|
57
58
|
if (request.request.getVersion() < 169) {
|
|
58
59
|
return new Response(organizations.map(o => OrganizationSimple.create(o)));
|
|
59
60
|
}
|
|
60
|
-
return new Response(await Promise.all(organizations.map(o =>
|
|
61
|
+
return new Response(await Promise.all(organizations.map(o => AuthenticatedStructures.organization(o))));
|
|
61
62
|
}
|
|
62
63
|
}
|
|
@@ -18,6 +18,12 @@ class Body extends AutoEncoder {
|
|
|
18
18
|
@field({ decoder: StringDecoder })
|
|
19
19
|
id: string
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Events for direct charges
|
|
23
|
+
*/
|
|
24
|
+
@field({ decoder: StringDecoder, nullable: true, optional: true })
|
|
25
|
+
account: string|null = null
|
|
26
|
+
|
|
21
27
|
@field({ decoder: AnyDecoder })
|
|
22
28
|
data: any
|
|
23
29
|
}
|