@stamhoofd/backend 2.74.0 → 2.75.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/index.ts +7 -2
- package/package.json +13 -13
- package/src/crons/update-cached-balances.ts +1 -2
- package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +2 -2
- package/src/endpoints/auth/CreateAdminEndpoint.ts +4 -15
- package/src/endpoints/auth/OpenIDConnectStartEndpoint.ts +0 -5
- package/src/endpoints/global/audit-logs/GetAuditLogsEndpoint.ts +2 -2
- package/src/endpoints/global/events/GetEventNotificationsCountEndpoint.ts +43 -0
- package/src/endpoints/global/events/GetEventNotificationsEndpoint.ts +181 -0
- package/src/endpoints/global/events/GetEventsEndpoint.ts +2 -2
- package/src/endpoints/global/events/PatchEventNotificationsEndpoint.ts +288 -0
- package/src/endpoints/global/events/PatchEventsEndpoint.ts +2 -2
- package/src/endpoints/global/files/UploadFile.ts +56 -4
- package/src/endpoints/global/files/UploadImage.ts +9 -3
- package/src/endpoints/global/members/GetMembersEndpoint.ts +2 -2
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +10 -1
- package/src/endpoints/global/platform/GetPlatformAdminsEndpoint.ts +1 -5
- package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +7 -0
- package/src/endpoints/global/registration/GetUserDocumentsEndpoint.ts +1 -1
- package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +2084 -164
- package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +2 -2
- package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +48 -2
- package/src/endpoints/organization/dashboard/documents/GetDocumentsEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +1 -1
- package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +8 -0
- package/src/endpoints/organization/dashboard/users/GetOrganizationAdminsEndpoint.ts +3 -3
- package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +2 -2
- package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +2 -2
- package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +1 -2
- package/src/helpers/AdminPermissionChecker.ts +80 -2
- package/src/helpers/AuthenticatedStructures.ts +88 -2
- package/src/helpers/FlagMomentCleanup.ts +1 -8
- package/src/helpers/GlobalHelper.ts +15 -0
- package/src/helpers/MembershipCharger.ts +2 -1
- package/src/services/EventNotificationService.ts +201 -0
- package/src/services/FileSignService.ts +217 -0
- package/src/services/SSOService.ts +7 -2
- package/src/sql-filters/event-notifications.ts +39 -0
- package/src/sql-filters/organizations.ts +1 -1
- package/src/sql-sorters/event-notifications.ts +96 -0
- package/src/sql-sorters/events.ts +2 -2
- package/src/sql-sorters/organizations.ts +2 -2
- package/tests/e2e/private-files.test.ts +497 -0
- package/tests/e2e/register.test.ts +1197 -0
- package/tests/helpers/TestServer.ts +3 -0
- package/tests/jest.setup.ts +15 -2
- package/tsconfig.json +1 -0
|
@@ -5,7 +5,7 @@ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-
|
|
|
5
5
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
6
6
|
import { Email } from '@stamhoofd/email';
|
|
7
7
|
import { BalanceItem, BalanceItemPayment, Group, Member, MemberWithRegistrations, MolliePayment, MollieToken, Organization, PayconiqPayment, Payment, Platform, RateLimiter, Registration, User } from '@stamhoofd/models';
|
|
8
|
-
import { BalanceItemRelation, BalanceItemRelationType, BalanceItemStatus,
|
|
8
|
+
import { BalanceItemRelation, BalanceItemRelationType, BalanceItemStatus, BalanceItem as BalanceItemStruct, BalanceItemType, IDRegisterCheckout, PaymentCustomer, PaymentMethod, PaymentMethodHelper, PaymentProvider, PaymentStatus, Payment as PaymentStruct, PaymentType, PermissionLevel, PlatformFamily, PlatformMember, RegisterItem, RegisterResponse, Version } from '@stamhoofd/structures';
|
|
9
9
|
import { Formatter } from '@stamhoofd/utility';
|
|
10
10
|
|
|
11
11
|
import { AuthenticatedStructures } from '../../../helpers/AuthenticatedStructures';
|
|
@@ -388,7 +388,7 @@ export class RegisterMembersEndpoint extends Endpoint<Params, Query, Body, Respo
|
|
|
388
388
|
if (!await Context.auth.canAccessRegistration(existingRegistration, PermissionLevel.Write)) {
|
|
389
389
|
throw new SimpleError({
|
|
390
390
|
code: 'forbidden',
|
|
391
|
-
message: 'Je hebt geen
|
|
391
|
+
message: 'Je hebt geen toegangsrechten om deze inschrijving te verwijderen.',
|
|
392
392
|
statusCode: 403,
|
|
393
393
|
});
|
|
394
394
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ConvertArrayToPatchableArray, Decoder, PatchableArrayAutoEncoder, PatchableArrayDecoder, StringDecoder, patchObject } from '@simonbackx/simple-encoding';
|
|
2
2
|
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
3
|
-
import { AuditLogSource,
|
|
3
|
+
import { AuditLogSource, RegistrationPeriod as RegistrationPeriodStruct } from '@stamhoofd/structures';
|
|
4
4
|
|
|
5
5
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
6
|
-
import { Platform, RegistrationPeriod } from '@stamhoofd/models';
|
|
6
|
+
import { Organization, Platform, RegistrationPeriod } from '@stamhoofd/models';
|
|
7
7
|
import { Context } from '../../../helpers/Context';
|
|
8
8
|
import { PeriodHelper } from '../../../helpers/PeriodHelper';
|
|
9
9
|
import { AuditLogService } from '../../../services/AuditLogService';
|
|
@@ -34,6 +34,24 @@ export class PatchRegistrationPeriodsEndpoint extends Endpoint<Params, Query, Bo
|
|
|
34
34
|
return [false];
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
static async isCurrentRegistrationPeriod(organizationId: string | null, periodId: string) {
|
|
38
|
+
if (organizationId === null) {
|
|
39
|
+
const platform = await Platform.getSharedStruct();
|
|
40
|
+
return platform.period.id === periodId;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const organization = await Organization.getByID(organizationId);
|
|
44
|
+
if (!organization) {
|
|
45
|
+
throw new SimpleError({
|
|
46
|
+
code: 'not_found',
|
|
47
|
+
statusCode: 404,
|
|
48
|
+
message: 'Organization not found',
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return organization.periodId === periodId;
|
|
53
|
+
}
|
|
54
|
+
|
|
37
55
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
38
56
|
const organization = await Context.setUserOrganizationScope();
|
|
39
57
|
await Context.authenticate();
|
|
@@ -60,6 +78,20 @@ export class PatchRegistrationPeriodsEndpoint extends Endpoint<Params, Query, Bo
|
|
|
60
78
|
period.locked = put.locked;
|
|
61
79
|
period.settings = put.settings;
|
|
62
80
|
period.organizationId = organization?.id ?? null;
|
|
81
|
+
|
|
82
|
+
if (put.locked === true) {
|
|
83
|
+
// current period cannot be locked
|
|
84
|
+
const isCurrentRegistrationPeriod = await PatchRegistrationPeriodsEndpoint.isCurrentRegistrationPeriod(period.organizationId, period.id);
|
|
85
|
+
|
|
86
|
+
if (isCurrentRegistrationPeriod) {
|
|
87
|
+
throw new SimpleError({
|
|
88
|
+
code: 'cannot_lock_current_period',
|
|
89
|
+
message: 'Current registration period cannot be locked',
|
|
90
|
+
human: 'Het huidige werkjaar kan niet vergrendeld worden',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
63
95
|
await period.setPreviousPeriodId();
|
|
64
96
|
|
|
65
97
|
await period.save();
|
|
@@ -76,6 +108,20 @@ export class PatchRegistrationPeriodsEndpoint extends Endpoint<Params, Query, Bo
|
|
|
76
108
|
message: 'Registration period not found',
|
|
77
109
|
});
|
|
78
110
|
}
|
|
111
|
+
|
|
112
|
+
if (patch.locked === true) {
|
|
113
|
+
// current period cannot be locked
|
|
114
|
+
const isCurrentRegistrationPeriod = await PatchRegistrationPeriodsEndpoint.isCurrentRegistrationPeriod(model.organizationId, model.id);
|
|
115
|
+
|
|
116
|
+
if (isCurrentRegistrationPeriod) {
|
|
117
|
+
throw new SimpleError({
|
|
118
|
+
code: 'cannot_lock_current_period',
|
|
119
|
+
message: 'Current registration period cannot be locked',
|
|
120
|
+
human: 'Het huidige werkjaar kan niet vergrendeld worden',
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
79
125
|
if (patch.startDate !== undefined) {
|
|
80
126
|
model.startDate = patch.startDate;
|
|
81
127
|
}
|
|
@@ -3,7 +3,7 @@ import { Document } from '@stamhoofd/models';
|
|
|
3
3
|
import { assertSort, CountFilteredRequest, Document as DocumentStruct, getSortFilter, LimitedFilteredRequest, PaginatedResponse, SearchFilterFactory, StamhoofdFilter } from '@stamhoofd/structures';
|
|
4
4
|
|
|
5
5
|
import { Decoder } from '@simonbackx/simple-encoding';
|
|
6
|
-
import { compileToSQLFilter,
|
|
6
|
+
import { compileToSQLFilter, applySQLSorter, SQL, SQLFilterDefinitions, SQLSortDefinitions } from '@stamhoofd/sql';
|
|
7
7
|
import { AuthenticatedStructures } from '../../../../helpers/AuthenticatedStructures';
|
|
8
8
|
import { Context } from '../../../../helpers/Context';
|
|
9
9
|
import { LimitedFilteredRequestHelper } from '../../../../helpers/LimitedFilteredRequestHelper';
|
|
@@ -68,7 +68,7 @@ export class GetDocumentsEndpoint extends Endpoint<Params, Query, Body, Response
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
q.sort = assertSort(q.sort, [{ key: 'id' }]);
|
|
71
|
-
query
|
|
71
|
+
applySQLSorter(query, q.sort, sorters);
|
|
72
72
|
query.limit(q.limit);
|
|
73
73
|
}
|
|
74
74
|
|
|
@@ -346,7 +346,7 @@ export class PatchOrganizationEndpoint extends Endpoint<Params, Query, Body, Res
|
|
|
346
346
|
await organization.save();
|
|
347
347
|
}
|
|
348
348
|
else {
|
|
349
|
-
if (request.body.name || request.body.address) {
|
|
349
|
+
if (request.body.name || request.body.address || request.body.website || request.body.meta?.companies || request.body.meta?.recordsConfiguration || request.body.meta?.registrationPaymentConfiguration) {
|
|
350
350
|
throw new SimpleError({
|
|
351
351
|
code: 'permission_denied',
|
|
352
352
|
message: 'You do not have permissions to edit the organization settings',
|
|
@@ -2,7 +2,7 @@ import { Decoder } from '@simonbackx/simple-encoding';
|
|
|
2
2
|
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
4
4
|
import { Payment } from '@stamhoofd/models';
|
|
5
|
-
import { SQL, compileToSQLFilter,
|
|
5
|
+
import { SQL, compileToSQLFilter, applySQLSorter } from '@stamhoofd/sql';
|
|
6
6
|
import { CountFilteredRequest, LimitedFilteredRequest, PaginatedResponse, PaymentGeneral, StamhoofdFilter, TransferSettings, assertSort, getSortFilter } from '@stamhoofd/structures';
|
|
7
7
|
|
|
8
8
|
import { SQLResultNamespacedRow } from '@simonbackx/simple-database';
|
|
@@ -152,7 +152,7 @@ export class GetPaymentsEndpoint extends Endpoint<Params, Query, Body, ResponseB
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
q.sort = assertSort(q.sort, [{ key: 'id' }]);
|
|
155
|
-
query
|
|
155
|
+
applySQLSorter(query, q.sort, sorters);
|
|
156
156
|
query.limit(q.limit);
|
|
157
157
|
}
|
|
158
158
|
|
package/src/endpoints/organization/dashboard/receivable-balances/GetReceivableBalancesEndpoint.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Decoder } from '@simonbackx/simple-encoding';
|
|
|
2
2
|
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
3
3
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
4
4
|
import { CachedBalance } from '@stamhoofd/models';
|
|
5
|
-
import { compileToSQLFilter,
|
|
5
|
+
import { compileToSQLFilter, applySQLSorter } from '@stamhoofd/sql';
|
|
6
6
|
import { assertSort, CountFilteredRequest, DetailedReceivableBalance, getSortFilter, LimitedFilteredRequest, PaginatedResponse, ReceivableBalance as ReceivableBalanceStruct, StamhoofdFilter } from '@stamhoofd/structures';
|
|
7
7
|
|
|
8
8
|
import { AuthenticatedStructures } from '../../../../helpers/AuthenticatedStructures';
|
|
@@ -100,7 +100,7 @@ export class GetReceivableBalancesEndpoint extends Endpoint<Params, Query, Body,
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
q.sort = assertSort(q.sort, [{ key: 'id' }]);
|
|
103
|
-
query
|
|
103
|
+
applySQLSorter(query, q.sort, sorters);
|
|
104
104
|
query.limit(q.limit);
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -452,6 +452,14 @@ export class PatchOrganizationRegistrationPeriodsEndpoint extends Endpoint<Param
|
|
|
452
452
|
}
|
|
453
453
|
}
|
|
454
454
|
|
|
455
|
+
if (period.locked) {
|
|
456
|
+
throw new SimpleError({
|
|
457
|
+
code: 'invalid_period',
|
|
458
|
+
message: 'Period is locked',
|
|
459
|
+
human: Context.i18n.$t('f544b972-416c-471d-8836-d7f3b16f947d'),
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
|
|
455
463
|
const user = Context.auth.user;
|
|
456
464
|
|
|
457
465
|
const model = new Group();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
2
2
|
import { User } from '@stamhoofd/models';
|
|
3
|
-
import { OrganizationAdmins
|
|
3
|
+
import { OrganizationAdmins } from '@stamhoofd/structures';
|
|
4
4
|
|
|
5
|
-
import { Context } from '../../../../helpers/Context';
|
|
6
5
|
import { AuthenticatedStructures } from '../../../../helpers/AuthenticatedStructures';
|
|
6
|
+
import { Context } from '../../../../helpers/Context';
|
|
7
7
|
type Params = Record<string, never>;
|
|
8
8
|
type Query = undefined;
|
|
9
9
|
type Body = undefined;
|
|
@@ -33,7 +33,7 @@ export class GetOrganizationAdminsEndpoint extends Endpoint<Params, Query, Body,
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// Get all admins
|
|
36
|
-
const admins = await User.getAdmins(
|
|
36
|
+
const admins = await User.getAdmins(organization.id);
|
|
37
37
|
|
|
38
38
|
return new Response(OrganizationAdmins.create({
|
|
39
39
|
users: await AuthenticatedStructures.usersWithMembers(admins),
|
|
@@ -3,7 +3,7 @@ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-
|
|
|
3
3
|
import { assertSort, CountFilteredRequest, getOrderSearchFilter, getSortFilter, LimitedFilteredRequest, PaginatedResponse, PrivateOrder, StamhoofdFilter } from '@stamhoofd/structures';
|
|
4
4
|
|
|
5
5
|
import { Order } from '@stamhoofd/models';
|
|
6
|
-
import { compileToSQLFilter,
|
|
6
|
+
import { compileToSQLFilter, applySQLSorter, SQL, SQLFilterDefinitions, SQLSortDefinitions } from '@stamhoofd/sql';
|
|
7
7
|
import { parsePhoneNumber } from 'libphonenumber-js/max';
|
|
8
8
|
import { AuthenticatedStructures } from '../../../../helpers/AuthenticatedStructures';
|
|
9
9
|
import { Context } from '../../../../helpers/Context';
|
|
@@ -69,7 +69,7 @@ export class GetWebshopOrdersEndpoint extends Endpoint<Params, Query, Body, Resp
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
q.sort = assertSort(q.sort, [{ key: 'id' }]);
|
|
72
|
-
query
|
|
72
|
+
applySQLSorter(query, q.sort, sorters);
|
|
73
73
|
query.limit(q.limit);
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -3,7 +3,7 @@ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-
|
|
|
3
3
|
import { Ticket } from '@stamhoofd/models';
|
|
4
4
|
import { assertSort, CountFilteredRequest, getSortFilter, LimitedFilteredRequest, PaginatedResponse, TicketPrivate } from '@stamhoofd/structures';
|
|
5
5
|
|
|
6
|
-
import { compileToSQLFilter,
|
|
6
|
+
import { compileToSQLFilter, applySQLSorter, SQL, SQLFilterDefinitions, SQLSortDefinitions } from '@stamhoofd/sql';
|
|
7
7
|
import { AuthenticatedStructures } from '../../../../helpers/AuthenticatedStructures';
|
|
8
8
|
import { Context } from '../../../../helpers/Context';
|
|
9
9
|
import { LimitedFilteredRequestHelper } from '../../../../helpers/LimitedFilteredRequestHelper';
|
|
@@ -60,7 +60,7 @@ export class GetWebshopTicketsEndpoint extends Endpoint<Params, Query, Body, Res
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
q.sort = assertSort(q.sort, [{ key: 'id' }]);
|
|
63
|
-
query
|
|
63
|
+
applySQLSorter(query, q.sort, sorters);
|
|
64
64
|
query.limit(q.limit);
|
|
65
65
|
}
|
|
66
66
|
|
|
@@ -2,11 +2,10 @@ import { createMollieClient, PaymentMethod as molliePaymentMethod } from '@molli
|
|
|
2
2
|
import { Decoder } from '@simonbackx/simple-encoding';
|
|
3
3
|
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
4
4
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
5
|
-
import { I18n } from '@stamhoofd/backend-i18n';
|
|
6
5
|
import { Email } from '@stamhoofd/email';
|
|
7
6
|
import { BalanceItem, BalanceItemPayment, MolliePayment, MollieToken, Order, PayconiqPayment, Payment, RateLimiter, Webshop, WebshopDiscountCode } from '@stamhoofd/models';
|
|
8
7
|
import { QueueHandler } from '@stamhoofd/queues';
|
|
9
|
-
import {
|
|
8
|
+
import { AuditLogSource, BalanceItemRelation, BalanceItemRelationType, BalanceItemStatus, BalanceItemType, OrderData, OrderResponse, Order as OrderStruct, PaymentCustomer, PaymentMethod, PaymentMethodHelper, PaymentProvider, PaymentStatus, Payment as PaymentStruct, Version, WebshopAuthType, Webshop as WebshopStruct } from '@stamhoofd/structures';
|
|
10
9
|
import { Formatter } from '@stamhoofd/utility';
|
|
11
10
|
|
|
12
11
|
import { BuckarooHelper } from '../../../helpers/BuckarooHelper';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AutoEncoderPatchType, PatchMap } from '@simonbackx/simple-encoding';
|
|
2
|
-
import { SimpleError } from '@simonbackx/simple-errors';
|
|
3
|
-
import { BalanceItem, CachedBalance, Document, EmailTemplate, Event, Group, Member, MemberPlatformMembership, MemberWithRegistrations, Order, Organization, OrganizationRegistrationPeriod, Payment, Registration, User, Webshop } from '@stamhoofd/models';
|
|
2
|
+
import { isSimpleError, isSimpleErrors, SimpleError } from '@simonbackx/simple-errors';
|
|
3
|
+
import { BalanceItem, CachedBalance, Document, EmailTemplate, Event, EventNotification, Group, Member, MemberPlatformMembership, MemberWithRegistrations, Order, Organization, OrganizationRegistrationPeriod, Payment, Registration, User, Webshop } from '@stamhoofd/models';
|
|
4
4
|
import { AccessRight, EventPermissionChecker, FinancialSupportSettings, GroupCategory, GroupStatus, MemberWithRegistrationsBlob, PermissionLevel, PermissionsResourceType, Platform as PlatformStruct, RecordCategory } from '@stamhoofd/structures';
|
|
5
5
|
import { Formatter } from '@stamhoofd/utility';
|
|
6
6
|
import { addTemporaryMemberAccess, hasTemporaryMemberAccess } from './TemporaryMemberAccess';
|
|
@@ -206,6 +206,38 @@ export class AdminPermissionChecker {
|
|
|
206
206
|
});
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
async canAccessEvent(event: Event): Promise<boolean> {
|
|
210
|
+
try {
|
|
211
|
+
await this.checkEventAccess(event);
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
if (isSimpleError(e) || isSimpleErrors(e)) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
throw e;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async canAccessEventNotification(notification: EventNotification, permissionLevel: PermissionLevel = PermissionLevel.Read) {
|
|
223
|
+
// todo: check if user has access to this notification
|
|
224
|
+
const events = EventNotification.events.isLoaded(notification) ? notification.events : await EventNotification.events.load(notification);
|
|
225
|
+
for (const event of events) {
|
|
226
|
+
if (!await this.canAccessEvent(event)) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (events.length === 0 || permissionLevel === PermissionLevel.Full) {
|
|
232
|
+
// Requires `OrganizationEventNotificationReviewer` access right for the organization
|
|
233
|
+
if (!await this.canReviewEventNotification(notification)) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
|
|
209
241
|
async canAccessArchivedGroups(organizationId: string) {
|
|
210
242
|
return await this.hasFullAccess(organizationId);
|
|
211
243
|
}
|
|
@@ -785,6 +817,23 @@ export class AdminPermissionChecker {
|
|
|
785
817
|
return !this.user.isApiUser && (await this.hasFullAccess(organizationId));
|
|
786
818
|
}
|
|
787
819
|
|
|
820
|
+
async canReviewEventNotification(eventNotification: { organizationId: string }) {
|
|
821
|
+
if (!this.checkScope(eventNotification.organizationId)) {
|
|
822
|
+
return false;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
const organizationPermissions = await this.getOrganizationPermissions(eventNotification.organizationId);
|
|
826
|
+
|
|
827
|
+
if (!organizationPermissions) {
|
|
828
|
+
return false;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
if (organizationPermissions.hasAccessRight(AccessRight.OrganizationEventNotificationReviewer)) {
|
|
832
|
+
return true;
|
|
833
|
+
}
|
|
834
|
+
return false;
|
|
835
|
+
}
|
|
836
|
+
|
|
788
837
|
async hasFullAccess(organizationId: string, level = PermissionLevel.Full): Promise<boolean> {
|
|
789
838
|
const organizationPermissions = await this.getOrganizationPermissions(organizationId);
|
|
790
839
|
|
|
@@ -1340,6 +1389,35 @@ export class AdminPermissionChecker {
|
|
|
1340
1389
|
return tags;
|
|
1341
1390
|
}
|
|
1342
1391
|
|
|
1392
|
+
getOrganizationTagsWithAccessRight(right: AccessRight): string[] | 'all' {
|
|
1393
|
+
if (!this.hasSomePlatformAccess()) {
|
|
1394
|
+
return [];
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
if (this.hasPlatformFullAccess()) {
|
|
1398
|
+
return 'all';
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
if (this.platformPermissions?.hasResourceAccessRight(PermissionsResourceType.OrganizationTags, '', right)) {
|
|
1402
|
+
return 'all';
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
const allTags = this.platform.config.tags;
|
|
1406
|
+
const tags: string[] = [];
|
|
1407
|
+
|
|
1408
|
+
for (const tag of allTags) {
|
|
1409
|
+
if (this.platformPermissions?.hasResourceAccessRight(PermissionsResourceType.OrganizationTags, tag.id, right)) {
|
|
1410
|
+
tags.push(tag.id);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
if (tags.length === allTags.length) {
|
|
1415
|
+
return 'all';
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
return tags;
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1343
1421
|
hasSomePlatformAccess(): boolean {
|
|
1344
1422
|
return !!this.platformPermissions && !this.platformPermissions.isEmpty;
|
|
1345
1423
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
2
|
-
import { AuditLog, BalanceItem, CachedBalance, Document, Event, Group, Member, MemberPlatformMembership, MemberResponsibilityRecord, MemberWithRegistrations, Order, Organization, OrganizationRegistrationPeriod, Payment, Registration, RegistrationPeriod, Ticket, User, Webshop } from '@stamhoofd/models';
|
|
3
|
-
import { AuditLogReplacement, AuditLogReplacementType, AuditLog as AuditLogStruct, DetailedReceivableBalance, Document as DocumentStruct, Event as EventStruct, GenericBalance, Group as GroupStruct, MemberPlatformMembership as MemberPlatformMembershipStruct, MemberWithRegistrationsBlob, MembersBlob, NamedObject, OrganizationRegistrationPeriod as OrganizationRegistrationPeriodStruct, Organization as OrganizationStruct, PaymentGeneral, PermissionLevel, Platform, PrivateOrder, PrivateWebshop, ReceivableBalanceObject, ReceivableBalanceObjectContact, ReceivableBalance as ReceivableBalanceStruct, ReceivableBalanceType, TicketPrivate, UserWithMembers, WebshopPreview, Webshop as WebshopStruct } from '@stamhoofd/structures';
|
|
2
|
+
import { AuditLog, BalanceItem, CachedBalance, Document, Event, EventNotification, Group, Member, MemberPlatformMembership, MemberResponsibilityRecord, MemberWithRegistrations, Order, Organization, OrganizationRegistrationPeriod, Payment, Registration, RegistrationPeriod, Ticket, User, Webshop } from '@stamhoofd/models';
|
|
3
|
+
import { AuditLogReplacement, AuditLogReplacementType, AuditLog as AuditLogStruct, DetailedReceivableBalance, Document as DocumentStruct, EventNotification as EventNotificationStruct, Event as EventStruct, GenericBalance, Group as GroupStruct, MemberPlatformMembership as MemberPlatformMembershipStruct, MemberWithRegistrationsBlob, MembersBlob, NamedObject, OrganizationRegistrationPeriod as OrganizationRegistrationPeriodStruct, Organization as OrganizationStruct, PaymentGeneral, PermissionLevel, Platform, PrivateOrder, PrivateWebshop, ReceivableBalanceObject, ReceivableBalanceObjectContact, ReceivableBalance as ReceivableBalanceStruct, ReceivableBalanceType, TicketPrivate, UserWithMembers, WebshopPreview, Webshop as WebshopStruct } from '@stamhoofd/structures';
|
|
4
4
|
|
|
5
|
+
import { SQL } from '@stamhoofd/sql';
|
|
5
6
|
import { Formatter } from '@stamhoofd/utility';
|
|
6
7
|
import { Context } from './Context';
|
|
7
8
|
|
|
@@ -479,6 +480,91 @@ export class AuthenticatedStructures {
|
|
|
479
480
|
return result;
|
|
480
481
|
}
|
|
481
482
|
|
|
483
|
+
static async eventNotification(eventNotification: EventNotification): Promise<EventNotificationStruct> {
|
|
484
|
+
return (await this.eventNotifications([eventNotification]))[0];
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
static async eventNotifications(eventNotifications: EventNotification[]): Promise<EventNotificationStruct[]> {
|
|
488
|
+
if (eventNotifications.length === 0) {
|
|
489
|
+
return [];
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Load events
|
|
493
|
+
const rows = await SQL.select()
|
|
494
|
+
.from('_event_notifications_events')
|
|
495
|
+
.where('event_notificationsId', eventNotifications.map(n => n.id))
|
|
496
|
+
.fetch();
|
|
497
|
+
|
|
498
|
+
const eventIdsMapping = new Map<string, string[]>();
|
|
499
|
+
const allEvents = new Set<string>();
|
|
500
|
+
|
|
501
|
+
for (const row of rows) {
|
|
502
|
+
const notificationId = row['_event_notifications_events']['event_notificationsId'];
|
|
503
|
+
const eventId = row['_event_notifications_events']['eventsId'];
|
|
504
|
+
|
|
505
|
+
if (typeof eventId !== 'string') {
|
|
506
|
+
console.error('Invalid event id', eventId);
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
if (typeof notificationId !== 'string') {
|
|
511
|
+
console.error('Invalid notification id', notificationId);
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const array = eventIdsMapping.get(notificationId);
|
|
516
|
+
if (array) {
|
|
517
|
+
array.push(eventId);
|
|
518
|
+
}
|
|
519
|
+
else {
|
|
520
|
+
eventIdsMapping.set(notificationId, [eventId]);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
allEvents.add(eventId);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
const events = allEvents.size > 0 ? await Event.getByIDs(...Array.from(allEvents)) : [];
|
|
527
|
+
const eventStructs = await this.events(events);
|
|
528
|
+
const organizationIds = Formatter.uniqueArray(eventNotifications.map(n => n.organizationId));
|
|
529
|
+
const organizationModels = organizationIds.length > 0 ? await Organization.getByIDs(...organizationIds) : [];
|
|
530
|
+
const userIds = Formatter.uniqueArray(eventNotifications.flatMap(n => [n.createdBy, n.submittedBy]).filter(id => id !== null));
|
|
531
|
+
const users = userIds.length > 0 ? await User.getByIDs(...userIds) : [];
|
|
532
|
+
const userStructs = users.map((user) => {
|
|
533
|
+
return NamedObject.create({
|
|
534
|
+
id: user.id,
|
|
535
|
+
name: user.name ?? user.email,
|
|
536
|
+
});
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
const result: EventNotificationStruct[] = [];
|
|
540
|
+
|
|
541
|
+
for (const notification of eventNotifications) {
|
|
542
|
+
const thisEventStructs = eventIdsMapping.get(notification.id)?.map(id => eventStructs.find(e => e.id === id)).filter(e => !!e) ?? [];
|
|
543
|
+
const organizationModel = organizationModels.find(o => o.id === notification.organizationId);
|
|
544
|
+
if (!organizationModel) {
|
|
545
|
+
throw new SimpleError({
|
|
546
|
+
code: 'organization_not_found',
|
|
547
|
+
message: 'Organization not found',
|
|
548
|
+
human: 'Organisatie niet gevonden',
|
|
549
|
+
});
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
const organizationStruct = organizationModel.getBaseStructure();
|
|
553
|
+
|
|
554
|
+
const struct = EventNotificationStruct.create({
|
|
555
|
+
...notification,
|
|
556
|
+
organization: organizationStruct,
|
|
557
|
+
createdBy: notification.createdBy ? userStructs.find(u => u.id === notification.createdBy) : null,
|
|
558
|
+
submittedBy: notification.submittedBy ? userStructs.find(u => u.id === notification.submittedBy) : null,
|
|
559
|
+
events: thisEventStructs,
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
result.push(struct);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
return result;
|
|
566
|
+
}
|
|
567
|
+
|
|
482
568
|
static async orders(orders: Order[]): Promise<PrivateOrder[]> {
|
|
483
569
|
const result: PrivateOrder[] = [];
|
|
484
570
|
const webshopIds = new Set(orders.map(o => o.webshopId));
|
|
@@ -22,17 +22,10 @@ export class FlagMomentCleanup {
|
|
|
22
22
|
static async getActiveMemberResponsibilityRecordsForOrganizationWithoutRegistrationInCurrentPeriod() {
|
|
23
23
|
const currentPeriodId = (await Platform.getShared()).periodId;
|
|
24
24
|
|
|
25
|
-
const now = new Date();
|
|
26
|
-
|
|
27
25
|
return await MemberResponsibilityRecord.select()
|
|
28
26
|
.whereNot('organizationId', null)
|
|
29
27
|
.where(
|
|
30
|
-
|
|
31
|
-
.or('startDate', null),
|
|
32
|
-
)
|
|
33
|
-
.where(
|
|
34
|
-
SQL.where('endDate', SQLWhereSign.GreaterEqual, now)
|
|
35
|
-
.or('endDate', null),
|
|
28
|
+
MemberResponsibilityRecord.whereActive,
|
|
36
29
|
)
|
|
37
30
|
.whereNot(
|
|
38
31
|
new SQLWhereExists(
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { I18n } from '@stamhoofd/backend-i18n';
|
|
2
|
+
import { FileSignService } from '../services/FileSignService';
|
|
3
|
+
import { Context } from './Context';
|
|
4
|
+
|
|
5
|
+
export class GlobalHelper {
|
|
6
|
+
static async load() {
|
|
7
|
+
await I18n.load();
|
|
8
|
+
this.loadGlobalTranslateFunction();
|
|
9
|
+
await FileSignService.load();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
private static loadGlobalTranslateFunction() {
|
|
13
|
+
(global as any).$t = (key: string, replace?: Record<string, string>) => Context.i18n.$t(key, replace);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -154,7 +154,8 @@ export const MembershipCharger = {
|
|
|
154
154
|
const q = MemberPlatformMembership.select()
|
|
155
155
|
.where('id', SQLWhereSign.Greater, lastId)
|
|
156
156
|
.where('balanceItemId', null)
|
|
157
|
-
.where('deletedAt', null)
|
|
157
|
+
.where('deletedAt', null)
|
|
158
|
+
.where('locked', false);
|
|
158
159
|
|
|
159
160
|
if (organizationId) {
|
|
160
161
|
q.where('organizationId', organizationId);
|