@stamhoofd/backend 2.57.0 → 2.58.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamhoofd/backend",
3
- "version": "2.57.0",
3
+ "version": "2.58.0",
4
4
  "main": "./dist/index.js",
5
5
  "exports": {
6
6
  ".": {
@@ -35,16 +35,16 @@
35
35
  "@mollie/api-client": "3.7.0",
36
36
  "@simonbackx/simple-database": "1.25.0",
37
37
  "@simonbackx/simple-encoding": "2.17.0",
38
- "@simonbackx/simple-endpoints": "1.14.0",
38
+ "@simonbackx/simple-endpoints": "1.15.0",
39
39
  "@simonbackx/simple-logging": "^1.0.1",
40
- "@stamhoofd/backend-i18n": "2.57.0",
41
- "@stamhoofd/backend-middleware": "2.57.0",
42
- "@stamhoofd/email": "2.57.0",
43
- "@stamhoofd/models": "2.57.0",
44
- "@stamhoofd/queues": "2.57.0",
45
- "@stamhoofd/sql": "2.57.0",
46
- "@stamhoofd/structures": "2.57.0",
47
- "@stamhoofd/utility": "2.57.0",
40
+ "@stamhoofd/backend-i18n": "2.58.0",
41
+ "@stamhoofd/backend-middleware": "2.58.0",
42
+ "@stamhoofd/email": "2.58.0",
43
+ "@stamhoofd/models": "2.58.0",
44
+ "@stamhoofd/queues": "2.58.0",
45
+ "@stamhoofd/sql": "2.58.0",
46
+ "@stamhoofd/structures": "2.58.0",
47
+ "@stamhoofd/utility": "2.58.0",
48
48
  "archiver": "^7.0.1",
49
49
  "aws-sdk": "^2.885.0",
50
50
  "axios": "1.6.8",
@@ -64,5 +64,5 @@
64
64
  "publishConfig": {
65
65
  "access": "public"
66
66
  },
67
- "gitHead": "9e6e3c22154937a4977cc0d1b669d9577067b832"
67
+ "gitHead": "4159f0bc858d301854c4e38a3e315053aec08399"
68
68
  }
@@ -7,6 +7,8 @@ import { isDebouncedError, QueueHandler } from '@stamhoofd/queues';
7
7
  import { StripeHelper } from '../../../helpers/StripeHelper';
8
8
  import { ExchangePaymentEndpoint } from '../../organization/shared/ExchangePaymentEndpoint';
9
9
  import { PaymentService } from '../../../services/PaymentService';
10
+ import { AuditLogService } from '../../../services/AuditLogService';
11
+ import { AuditLogType } from '@stamhoofd/structures';
10
12
 
11
13
  type Params = Record<string, never>;
12
14
  class Body extends AutoEncoder {
@@ -85,8 +87,17 @@ export class StripeWebookEndpoint extends Endpoint<Params, Query, Body, Response
85
87
  const id = account.id as string;
86
88
  const [model] = await StripeAccount.where({ accountId: id }, { limit: 1 });
87
89
  if (model) {
90
+ const beforeMeta = model.meta.clone();
88
91
  model.setMetaFromStripeAccount(account);
89
- await model.save();
92
+ if (await model.save()) {
93
+ // Track audit log
94
+ await AuditLogService.log({
95
+ type: AuditLogType.StripeAccountEdited,
96
+ stripeAccount: model,
97
+ oldData: beforeMeta,
98
+ patch: model.meta,
99
+ });
100
+ }
90
101
  }
91
102
  else {
92
103
  console.warn('Could not find stripe account with id', id);
@@ -49,10 +49,9 @@ export class PatchPlatformEndpoint extends Endpoint<
49
49
  }
50
50
 
51
51
  const platform = await Platform.getShared();
52
+ const initialStruct = (await Platform.getSharedPrivateStruct()).clone();
52
53
 
53
54
  if (request.body.privateConfig) {
54
- const oldConfig = platform.privateConfig.clone();
55
-
56
55
  // Did we patch roles?
57
56
  if (request.body.privateConfig.roles) {
58
57
  if (!Context.auth.canManagePlatformAdmins()) {
@@ -77,12 +76,6 @@ export class PatchPlatformEndpoint extends Endpoint<
77
76
  request.body.privateConfig.emails,
78
77
  );
79
78
  }
80
-
81
- await AuditLogService.log({
82
- type: AuditLogType.PlatformSettingsChanged,
83
- oldConfig,
84
- patch: request.body.privateConfig,
85
- });
86
79
  }
87
80
 
88
81
  let shouldUpdateSetupSteps = false;
@@ -116,12 +109,6 @@ export class PatchPlatformEndpoint extends Endpoint<
116
109
  else {
117
110
  platform.config = patchObject(platform.config, newConfig);
118
111
  }
119
-
120
- await AuditLogService.log({
121
- type: AuditLogType.PlatformSettingsChanged,
122
- oldConfig,
123
- patch: newConfig,
124
- });
125
112
  }
126
113
 
127
114
  if (newConfig.tags && isPatchableArray(newConfig.tags) && newConfig.tags.changes.length > 0) {
@@ -236,6 +223,12 @@ export class PatchPlatformEndpoint extends Endpoint<
236
223
  SetupStepUpdater.updateSetupStepsForAllOrganizationsInCurrentPeriod().catch(console.error);
237
224
  }
238
225
 
226
+ await AuditLogService.log({
227
+ type: AuditLogType.PlatformSettingsChanged,
228
+ oldData: initialStruct,
229
+ patch: request.body,
230
+ });
231
+
239
232
  return new Response(await Platform.getSharedPrivateStruct());
240
233
  }
241
234
 
@@ -1,11 +1,12 @@
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 { RegistrationPeriod as RegistrationPeriodStruct } from '@stamhoofd/structures';
3
+ import { AuditLogType, RegistrationPeriod as RegistrationPeriodStruct } from '@stamhoofd/structures';
4
4
 
5
5
  import { SimpleError } from '@simonbackx/simple-errors';
6
6
  import { Platform, RegistrationPeriod } from '@stamhoofd/models';
7
7
  import { Context } from '../../../helpers/Context';
8
8
  import { PeriodHelper } from '../../../helpers/PeriodHelper';
9
+ import { AuditLogService } from '../../../services/AuditLogService';
9
10
 
10
11
  type Params = Record<string, never>;
11
12
  type Query = undefined;
@@ -62,6 +63,11 @@ export class PatchRegistrationPeriodsEndpoint extends Endpoint<Params, Query, Bo
62
63
 
63
64
  await period.save();
64
65
  periods.push(period);
66
+
67
+ await AuditLogService.log({
68
+ type: AuditLogType.RegistrationPeriodAdded,
69
+ period,
70
+ });
65
71
  }
66
72
 
67
73
  for (const patch of request.body.getPatches()) {
@@ -74,6 +80,7 @@ export class PatchRegistrationPeriodsEndpoint extends Endpoint<Params, Query, Bo
74
80
  message: 'Registration period not found',
75
81
  });
76
82
  }
83
+ const initialStructure = model.getStructure().clone();
77
84
 
78
85
  if (patch.startDate !== undefined) {
79
86
  model.startDate = patch.startDate;
@@ -95,6 +102,13 @@ export class PatchRegistrationPeriodsEndpoint extends Endpoint<Params, Query, Bo
95
102
 
96
103
  // Schedule patch of all groups in this period
97
104
  PeriodHelper.updateGroupsInPeriod(model).catch(console.error);
105
+
106
+ await AuditLogService.log({
107
+ type: AuditLogType.RegistrationPeriodEdited,
108
+ period: model,
109
+ patch,
110
+ oldData: initialStructure,
111
+ });
98
112
  }
99
113
 
100
114
  for (const id of request.body.getDeletes()) {
@@ -109,6 +123,11 @@ export class PatchRegistrationPeriodsEndpoint extends Endpoint<Params, Query, Bo
109
123
  }
110
124
 
111
125
  await model.delete();
126
+
127
+ await AuditLogService.log({
128
+ type: AuditLogType.RegistrationPeriodDeleted,
129
+ period: model,
130
+ });
112
131
  }
113
132
 
114
133
  // Clear platform cache
@@ -1,4 +1,4 @@
1
- import { AutoEncoderPatchType, Decoder, isPatchableArray, ObjectData, PatchableArrayAutoEncoder, patchObject } from '@simonbackx/simple-encoding';
1
+ import { AutoEncoderPatchType, cloneObject, Decoder, isPatchableArray, ObjectData, PatchableArrayAutoEncoder, patchObject } from '@simonbackx/simple-encoding';
2
2
  import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
3
3
  import { SimpleError, SimpleErrors } from '@simonbackx/simple-errors';
4
4
  import { Organization, OrganizationRegistrationPeriod, PayconiqPayment, Platform, RegistrationPeriod, SetupStepUpdater, StripeAccount, Webshop } from '@stamhoofd/models';
@@ -63,6 +63,8 @@ export class PatchOrganizationEndpoint extends Endpoint<Params, Query, Body, Res
63
63
  });
64
64
  }
65
65
 
66
+ const initialStruct = (await AuthenticatedStructures.organization(organization)).clone();
67
+
66
68
  const errors = new SimpleErrors();
67
69
  let shouldUpdateSetupSteps = false;
68
70
  let updateTags = false;
@@ -136,7 +138,7 @@ export class PatchOrganizationEndpoint extends Endpoint<Params, Query, Body, Res
136
138
 
137
139
  // Apply payconiq patch
138
140
  if (request.body.privateMeta.payconiqAccounts !== undefined) {
139
- organization.privateMeta.payconiqAccounts = patchObject(organization.privateMeta.payconiqAccounts, request.body.privateMeta.payconiqAccounts);
141
+ organization.privateMeta.payconiqAccounts = patchObject(organization.privateMeta.payconiqAccounts, cloneObject(request.body.privateMeta.payconiqAccounts as any));
140
142
 
141
143
  for (const account of organization.privateMeta.payconiqAccounts) {
142
144
  if (account.merchantId === null) {
@@ -214,8 +216,6 @@ export class PatchOrganizationEndpoint extends Endpoint<Params, Query, Body, Res
214
216
  await this.validateCompanies(organization, request.body.meta.companies);
215
217
  shouldUpdateSetupSteps = true;
216
218
  }
217
- const oldMeta = organization.meta.clone();
218
-
219
219
  const savedPackages = organization.meta.packages;
220
220
  organization.meta.patchOrPut(request.body.meta);
221
221
  organization.meta.packages = savedPackages;
@@ -283,13 +283,6 @@ export class PatchOrganizationEndpoint extends Endpoint<Params, Query, Body, Res
283
283
 
284
284
  updateTags = true;
285
285
  }
286
-
287
- await AuditLogService.log({
288
- type: AuditLogType.OrganizationSettingsChanged,
289
- organization,
290
- oldMeta,
291
- patch: request.body.meta,
292
- });
293
286
  }
294
287
 
295
288
  if (request.body.active !== undefined) {
@@ -393,8 +386,16 @@ export class PatchOrganizationEndpoint extends Endpoint<Params, Query, Body, Res
393
386
  if (updateTags) {
394
387
  await TagHelper.updateOrganizations();
395
388
  }
389
+ const struct = await AuthenticatedStructures.organization(organization);
390
+
391
+ await AuditLogService.log({
392
+ type: AuditLogType.OrganizationSettingsChanged,
393
+ organization,
394
+ oldData: initialStruct,
395
+ patch: struct,
396
+ });
396
397
 
397
- return new Response(await AuthenticatedStructures.organization(organization));
398
+ return new Response(struct);
398
399
  }
399
400
 
400
401
  async validateCompanies(organization: Organization, companies: PatchableArrayAutoEncoder<Company> | Company[]) {
@@ -425,6 +425,11 @@ export class PatchOrganizationRegistrationPeriodsEndpoint extends Endpoint<Param
425
425
  Member.updateMembershipsForGroupId(model.id);
426
426
  }
427
427
 
428
+ if (Object.keys(struct).length === 1 && struct.id) {
429
+ // Nothing changed
430
+ return;
431
+ }
432
+
428
433
  await AuditLogService.log({
429
434
  type: AuditLogType.GroupEdited,
430
435
  group: model,
@@ -1,11 +1,12 @@
1
1
  import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
2
2
  import { SimpleError } from '@simonbackx/simple-errors';
3
3
  import { StripeAccount } from '@stamhoofd/models';
4
- import { PermissionLevel, StripeAccount as StripeAccountStruct } from '@stamhoofd/structures';
4
+ import { AuditLogType, PermissionLevel, StripeAccount as StripeAccountStruct } from '@stamhoofd/structures';
5
5
  import Stripe from 'stripe';
6
6
 
7
7
  import { Context } from '../../../../helpers/Context';
8
8
  import { StripeHelper } from '../../../../helpers/StripeHelper';
9
+ import { AuditLogService } from '../../../../services/AuditLogService';
9
10
  type Params = Record<string, never>;
10
11
  type Body = undefined;
11
12
  type Query = undefined;
@@ -91,6 +92,12 @@ export class ConnectMollieEndpoint extends Endpoint<Params, Query, Body, Respons
91
92
  model.setMetaFromStripeAccount(account);
92
93
  await model.save();
93
94
 
95
+ // Track audit log
96
+ await AuditLogService.log({
97
+ type: AuditLogType.StripeAccountAdded,
98
+ stripeAccount: model,
99
+ });
100
+
94
101
  // Return information about the Stripe Account
95
102
 
96
103
  return new Response(StripeAccountStruct.create(model));
@@ -1,10 +1,11 @@
1
1
  import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
2
2
  import { StripeAccount } from '@stamhoofd/models';
3
- import { PermissionLevel } from '@stamhoofd/structures';
3
+ import { AuditLogType, PermissionLevel } from '@stamhoofd/structures';
4
4
 
5
5
  import { Context } from '../../../../helpers/Context';
6
6
  import { StripeHelper } from '../../../../helpers/StripeHelper';
7
7
  import { SimpleError } from '@simonbackx/simple-errors';
8
+ import { AuditLogService } from '../../../../services/AuditLogService';
8
9
 
9
10
  type Params = { id: string };
10
11
  type Body = undefined;
@@ -63,6 +64,12 @@ export class DeleteStripeAccountEndpoint extends Endpoint<Params, Query, Body, R
63
64
  model.status = 'deleted';
64
65
  await model.save();
65
66
 
67
+ // Track audit log
68
+ await AuditLogService.log({
69
+ type: AuditLogType.StripeAccountDeleted,
70
+ stripeAccount: model,
71
+ });
72
+
66
73
  return new Response(undefined);
67
74
  }
68
75
  }
@@ -1,9 +1,11 @@
1
1
  import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
2
2
  import { StripeAccount } from '@stamhoofd/models';
3
- import { PermissionLevel, StripeAccount as StripeAccountStruct } from '@stamhoofd/structures';
3
+ import { AuditLogType, PermissionLevel, StripeAccount as StripeAccountStruct } from '@stamhoofd/structures';
4
4
 
5
5
  import { Context } from '../../../../helpers/Context';
6
6
  import { StripeHelper } from '../../../../helpers/StripeHelper';
7
+ import { AuditLogService } from '../../../../services/AuditLogService';
8
+ import { Model } from '@simonbackx/simple-database';
7
9
 
8
10
  type Params = { id: string };
9
11
  type Body = undefined;
@@ -43,8 +45,18 @@ export class UpdateStripeAccountEndpoint extends Endpoint<Params, Query, Body, R
43
45
  // Get account
44
46
  const stripe = StripeHelper.getInstance();
45
47
  const account = await stripe.accounts.retrieve(model.accountId);
48
+ const beforeMeta = model.meta;
46
49
  model.setMetaFromStripeAccount(account);
47
- await model.save();
50
+
51
+ if (await model.save()) {
52
+ // Track audit log
53
+ await AuditLogService.log({
54
+ type: AuditLogType.StripeAccountEdited,
55
+ stripeAccount: model,
56
+ oldData: beforeMeta,
57
+ patch: model.meta,
58
+ });
59
+ }
48
60
 
49
61
  return new Response(StripeAccountStruct.create(model));
50
62
  }
@@ -5,14 +5,17 @@ import { Group as GroupStruct, PermissionLevel } from '@stamhoofd/structures';
5
5
  import { PatchOrganizationRegistrationPeriodsEndpoint } from '../endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint';
6
6
  import { AuthenticatedStructures } from './AuthenticatedStructures';
7
7
  import { MemberUserSyncer } from './MemberUserSyncer';
8
+ import { AuditLogService } from '../services/AuditLogService';
8
9
 
9
10
  export class PeriodHelper {
10
11
  static async moveOrganizationToPeriod(organization: Organization, period: RegistrationPeriod) {
11
- console.log('moveOrganizationToPeriod', organization.id, period.id);
12
+ await AuditLogService.disable(async () => {
13
+ console.log('moveOrganizationToPeriod', organization.id, period.id);
12
14
 
13
- await this.createOrganizationPeriodForPeriod(organization, period);
14
- organization.periodId = period.id;
15
- await organization.save();
15
+ await this.createOrganizationPeriodForPeriod(organization, period);
16
+ organization.periodId = period.id;
17
+ await organization.save();
18
+ });
16
19
  }
17
20
 
18
21
  static async stopAllResponsibilities() {
@@ -169,29 +172,31 @@ export class PeriodHelper {
169
172
 
170
173
  const batchSize = 100;
171
174
  await QueueHandler.schedule(tag, async () => {
172
- let lastId = '';
173
-
174
- while (true) {
175
- const groups = await Group.where(
176
- {
177
- id: { sign: '>', value: lastId },
178
- periodId: period.id,
179
- },
180
- {
181
- limit: batchSize,
182
- sort: ['id'],
183
- },
184
- );
185
-
186
- for (const group of groups) {
187
- await PatchOrganizationRegistrationPeriodsEndpoint.patchGroup(GroupStruct.patch({ id: group.id }), period);
188
- lastId = group.id;
189
- }
175
+ await AuditLogService.disable(async () => {
176
+ let lastId = '';
177
+
178
+ while (true) {
179
+ const groups = await Group.where(
180
+ {
181
+ id: { sign: '>', value: lastId },
182
+ periodId: period.id,
183
+ },
184
+ {
185
+ limit: batchSize,
186
+ sort: ['id'],
187
+ },
188
+ );
189
+
190
+ for (const group of groups) {
191
+ await PatchOrganizationRegistrationPeriodsEndpoint.patchGroup(GroupStruct.patch({ id: group.id }), period);
192
+ lastId = group.id;
193
+ }
190
194
 
191
- if (groups.length < batchSize) {
192
- break;
195
+ if (groups.length < batchSize) {
196
+ break;
197
+ }
193
198
  }
194
- }
199
+ });
195
200
  });
196
201
  }
197
202
  }
@@ -1,8 +1,9 @@
1
1
  import { AutoEncoder, AutoEncoderPatchType } from '@simonbackx/simple-encoding';
2
- import { AuditLog, Group, Member, Organization, Registration, Event } from '@stamhoofd/models';
2
+ import { AuditLog, Group, Member, Organization, Registration, Event, RegistrationPeriod, StripeAccount } from '@stamhoofd/models';
3
3
  import { AuditLogReplacement, AuditLogReplacementType, AuditLogType, GroupType, MemberDetails, OrganizationMetaData, OrganizationPrivateMetaData, PlatformConfig, PlatformPrivateConfig } from '@stamhoofd/structures';
4
4
  import { Context } from '../helpers/Context';
5
5
  import { explainPatch } from './explainPatch';
6
+ import { AsyncLocalStorage } from 'node:async_hooks';
6
7
 
7
8
  export type MemberAddedAuditOptions = {
8
9
  type: AuditLogType.MemberAdded;
@@ -25,24 +26,16 @@ export type MemberRegisteredAuditOptions = {
25
26
 
26
27
  export type PlatformConfigChangeAuditOptions = {
27
28
  type: AuditLogType.PlatformSettingsChanged;
28
- } & ({
29
- oldConfig: PlatformPrivateConfig;
30
- patch: PlatformPrivateConfig | AutoEncoderPatchType<PlatformPrivateConfig>;
31
- } | {
32
- oldConfig: PlatformConfig;
33
- patch: PlatformConfig | AutoEncoderPatchType<PlatformConfig>;
34
- });
29
+ oldData?: AutoEncoder;
30
+ patch?: AutoEncoder | AutoEncoderPatchType<AutoEncoder>;
31
+ };
35
32
 
36
33
  export type OrganizationConfigChangeAuditOptions = {
37
34
  type: AuditLogType.OrganizationSettingsChanged;
38
35
  organization: Organization;
39
- } & ({
40
- oldMeta: OrganizationMetaData;
41
- patch: OrganizationMetaData | AutoEncoderPatchType<OrganizationMetaData>;
42
- } | {
43
- oldMeta: OrganizationPrivateMetaData;
44
- patch: OrganizationPrivateMetaData | AutoEncoderPatchType<OrganizationPrivateMetaData>;
45
- });
36
+ oldData?: AutoEncoder;
37
+ patch?: AutoEncoder | AutoEncoderPatchType<AutoEncoder>;
38
+ };
46
39
 
47
40
  export type EventAuditOptions = {
48
41
  type: AuditLogType.EventAdded | AuditLogType.EventEdited | AuditLogType.EventDeleted;
@@ -58,11 +51,46 @@ export type GroupAuditOptions = {
58
51
  patch?: AutoEncoder | AutoEncoderPatchType<AutoEncoder>;
59
52
  };
60
53
 
61
- export type AuditLogOptions = GroupAuditOptions | EventAuditOptions | MemberAddedAuditOptions | MemberEditedAuditOptions | MemberRegisteredAuditOptions | PlatformConfigChangeAuditOptions | OrganizationConfigChangeAuditOptions;
54
+ export type PeriodAuditOptions = {
55
+ type: AuditLogType.RegistrationPeriodAdded | AuditLogType.RegistrationPeriodEdited | AuditLogType.RegistrationPeriodDeleted;
56
+ period: RegistrationPeriod;
57
+ oldData?: AutoEncoder;
58
+ patch?: AutoEncoder | AutoEncoderPatchType<AutoEncoder>;
59
+ };
60
+
61
+ export type StripeAccountAuditOptions = {
62
+ type: AuditLogType.StripeAccountAdded | AuditLogType.StripeAccountEdited | AuditLogType.StripeAccountDeleted;
63
+ stripeAccount: StripeAccount;
64
+ oldData?: AutoEncoder;
65
+ patch?: AutoEncoder | AutoEncoderPatchType<AutoEncoder>;
66
+ };
67
+
68
+ export type AuditLogOptions = StripeAccountAuditOptions | PeriodAuditOptions | GroupAuditOptions | EventAuditOptions | MemberAddedAuditOptions | MemberEditedAuditOptions | MemberRegisteredAuditOptions | PlatformConfigChangeAuditOptions | OrganizationConfigChangeAuditOptions;
62
69
 
63
70
  export const AuditLogService = {
71
+ disableLocalStore: new AsyncLocalStorage<boolean>(),
72
+
73
+ disable<T extends Promise<void> | void>(run: () => T): T {
74
+ return this.disableLocalStore.run(true, () => {
75
+ return run();
76
+ });
77
+ },
78
+
79
+ isDisabled(): boolean {
80
+ const c = this.disableLocalStore.getStore();
81
+
82
+ if (!c) {
83
+ return false;
84
+ }
85
+
86
+ return true;
87
+ },
88
+
64
89
  async log(options: AuditLogOptions) {
65
90
  try {
91
+ if (this.isDisabled()) {
92
+ return;
93
+ }
66
94
  const userId = Context.optionalAuth?.user?.id ?? null;
67
95
  const organizationId = Context.organization?.id ?? null;
68
96
 
@@ -96,11 +124,18 @@ export const AuditLogService = {
96
124
  else if (options.type === AuditLogType.GroupAdded || options.type === AuditLogType.GroupEdited || options.type === AuditLogType.GroupDeleted) {
97
125
  this.fillForGroup(model, options);
98
126
  }
127
+ else if (options.type === AuditLogType.RegistrationPeriodAdded || options.type === AuditLogType.RegistrationPeriodEdited || options.type === AuditLogType.RegistrationPeriodDeleted) {
128
+ this.fillForPeriod(model, options);
129
+ }
130
+ else if (options.type === AuditLogType.StripeAccountAdded || options.type === AuditLogType.StripeAccountEdited || options.type === AuditLogType.StripeAccountDeleted) {
131
+ if (this.fillForStripeAccount(model, options) === false) {
132
+ // do not save
133
+ return;
134
+ }
135
+ }
99
136
 
100
137
  // In the future we might group these saves together in one query to improve performance
101
138
  await model.save();
102
-
103
- console.log('Audit log', model.id, options);
104
139
  }
105
140
  catch (e) {
106
141
  console.error('Failed to save log', options, e);
@@ -162,7 +197,10 @@ export const AuditLogService = {
162
197
  model.objectId = null;
163
198
 
164
199
  // Generate changes list
165
- model.patchList = explainPatch(options.oldConfig, options.patch);
200
+ if (options.patch) {
201
+ // Generate changes list
202
+ model.patchList = explainPatch(options.oldData ?? null, options.patch);
203
+ }
166
204
  },
167
205
 
168
206
  fillForOrganizationConfig(model: AuditLog, options: OrganizationConfigChangeAuditOptions) {
@@ -178,7 +216,10 @@ export const AuditLogService = {
178
216
  ]);
179
217
 
180
218
  // Generate changes list
181
- model.patchList = explainPatch(options.oldMeta, options.patch);
219
+ if (options.patch) {
220
+ // Generate changes list
221
+ model.patchList = explainPatch(options.oldData ?? null, options.patch);
222
+ }
182
223
  },
183
224
 
184
225
  fillForEvent(model: AuditLog, options: EventAuditOptions) {
@@ -229,4 +270,48 @@ export const AuditLogService = {
229
270
  })],
230
271
  ]);
231
272
  },
273
+
274
+ fillForPeriod(model: AuditLog, options: PeriodAuditOptions) {
275
+ model.objectId = options.period.id;
276
+
277
+ if (options.patch) {
278
+ // Generate changes list
279
+ model.patchList = explainPatch(options.oldData ?? null, options.patch);
280
+ }
281
+
282
+ model.replacements = new Map([
283
+ ['p', AuditLogReplacement.create({
284
+ id: options.period.id,
285
+ value: options.period.getStructure().nameShort,
286
+ type: AuditLogReplacementType.RegistrationPeriod,
287
+ })],
288
+ ]);
289
+ },
290
+
291
+ fillForStripeAccount(model: AuditLog, options: StripeAccountAuditOptions) {
292
+ model.objectId = options.stripeAccount.id;
293
+
294
+ if (options.patch) {
295
+ // Generate changes list
296
+ model.patchList = explainPatch(options.oldData ?? null, options.patch);
297
+
298
+ if (model.patchList.length === 0) {
299
+ // No changes, ignore (only for stripe)
300
+ return false;
301
+ }
302
+ }
303
+
304
+ if (options.type === AuditLogType.StripeAccountEdited) {
305
+ // Never caused by a user
306
+ model.userId = null;
307
+ }
308
+
309
+ model.replacements = new Map([
310
+ ['a', AuditLogReplacement.create({
311
+ id: options.stripeAccount.id,
312
+ value: options.stripeAccount.accountId,
313
+ type: AuditLogReplacementType.StripeAccount,
314
+ })],
315
+ ]);
316
+ },
232
317
  };