@stamhoofd/backend 2.99.1 → 2.100.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 +10 -10
- package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +1 -1
- package/src/endpoints/global/events/PatchEventNotificationsEndpoint.test.ts +7 -1
- package/src/endpoints/global/events/PatchEventNotificationsEndpoint.ts +2 -2
- package/src/endpoints/global/events/PatchEventsEndpoint.test.ts +267 -0
- package/src/endpoints/global/events/PatchEventsEndpoint.ts +4 -4
- package/src/endpoints/global/members/GetMembersEndpoint.ts +1 -1
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +1 -1
- package/src/endpoints/global/organizations/SearchOrganizationEndpoint.test.ts +5 -2
- package/src/endpoints/global/platform/PatchPlatformEnpoint.test.ts +63 -0
- package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +1 -1
- package/src/endpoints/global/registration/GetRegistrationsEndpoint.ts +1 -1
- package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +4 -3
- package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +2 -2
- package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +10 -3
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +67 -2
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +41 -29
- package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.test.ts +32 -8
- package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.test.ts +206 -0
- package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +35 -1
- package/src/helpers/AuthenticatedStructures.ts +1 -1
- package/src/helpers/FlagMomentCleanup.ts +105 -52
- package/src/helpers/PeriodHelper.ts +85 -2
- package/src/sql-filters/registration-periods.ts +1 -1
- package/tests/jest.setup.ts +2 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Group, Member, MemberResponsibilityRecord, Platform, Registration } from '@stamhoofd/models';
|
|
1
|
+
import { Group, Member, MemberResponsibilityRecord, Organization, Platform, Registration } from '@stamhoofd/models';
|
|
2
2
|
import { SQL, SQLWhereExists } from '@stamhoofd/sql';
|
|
3
3
|
import { GroupType } from '@stamhoofd/structures';
|
|
4
4
|
import { MemberUserSyncer } from './MemberUserSyncer';
|
|
@@ -26,60 +26,113 @@ export class FlagMomentCleanup {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
static async getActiveMemberResponsibilityRecordsForOrganizationWithoutRegistrationInCurrentPeriod() {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
if (STAMHOOFD.userMode === 'platform') {
|
|
30
|
+
const platform = await Platform.getShared();
|
|
31
|
+
const currentPeriodId = platform.periodId;
|
|
32
|
+
const platformResponsibilityIds = platform.config.responsibilities.map(r => r.id);
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
34
|
+
return await MemberResponsibilityRecord.select()
|
|
35
|
+
.whereNot('organizationId', null)
|
|
36
|
+
.where(
|
|
37
|
+
MemberResponsibilityRecord.whereActive,
|
|
38
|
+
)
|
|
39
|
+
.whereNot(
|
|
40
|
+
new SQLWhereExists(
|
|
41
|
+
SQL.select()
|
|
42
|
+
.from(Registration.table)
|
|
43
|
+
.join(
|
|
44
|
+
SQL.innerJoin(SQL.table(Group.table))
|
|
45
|
+
.where(
|
|
46
|
+
SQL.column(Group.table, 'id'),
|
|
47
|
+
SQL.column(Registration.table, 'groupId'),
|
|
48
|
+
),
|
|
49
|
+
)
|
|
50
|
+
.where(
|
|
51
|
+
SQL.column(Registration.table, 'memberId'),
|
|
52
|
+
SQL.column(MemberResponsibilityRecord.table, 'memberId'),
|
|
53
|
+
).where(
|
|
54
|
+
SQL.column(Registration.table, 'organizationId'),
|
|
55
|
+
SQL.column(MemberResponsibilityRecord.table, 'organizationId'),
|
|
56
|
+
).where(
|
|
57
|
+
SQL.column(Registration.table, 'periodId'),
|
|
58
|
+
currentPeriodId,
|
|
59
|
+
).where(
|
|
60
|
+
SQL.column(Registration.table, 'deactivatedAt'),
|
|
61
|
+
null,
|
|
62
|
+
).whereNot(
|
|
63
|
+
SQL.column(Registration.table, 'registeredAt'),
|
|
64
|
+
null,
|
|
65
|
+
).where(
|
|
66
|
+
SQL.column(Group.table, 'type'),
|
|
67
|
+
GroupType.Membership,
|
|
68
|
+
).where(
|
|
69
|
+
SQL.where(
|
|
70
|
+
SQL.column(Group.table, 'defaultAgeGroupId'),
|
|
71
|
+
'!=',
|
|
72
|
+
null,
|
|
73
|
+
).or(
|
|
74
|
+
SQL.column(MemberResponsibilityRecord.table, 'responsibilityId'),
|
|
75
|
+
'!=',
|
|
76
|
+
platformResponsibilityIds,
|
|
47
77
|
),
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
78
|
+
).where(
|
|
79
|
+
SQL.column(Group.table, 'deletedAt'),
|
|
80
|
+
null,
|
|
81
|
+
),
|
|
82
|
+
),
|
|
83
|
+
)
|
|
84
|
+
.fetch();
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
return await MemberResponsibilityRecord.select()
|
|
88
|
+
.join(SQL.innerJoin(
|
|
89
|
+
SQL.table(Organization.table))
|
|
90
|
+
.where(
|
|
91
|
+
SQL.column(Organization.table, 'id'),
|
|
92
|
+
SQL.column(MemberResponsibilityRecord.table, 'organizationId'),
|
|
93
|
+
),
|
|
94
|
+
)
|
|
95
|
+
.whereNot('organizationId', null)
|
|
96
|
+
.whereNot(SQL.column(Organization.table, 'periodId'), null)
|
|
97
|
+
.where(
|
|
98
|
+
MemberResponsibilityRecord.whereActive,
|
|
99
|
+
)
|
|
100
|
+
.whereNot(
|
|
101
|
+
new SQLWhereExists(
|
|
102
|
+
SQL.select()
|
|
103
|
+
.from(Registration.table)
|
|
104
|
+
.join(
|
|
105
|
+
SQL.innerJoin(SQL.table(Group.table))
|
|
106
|
+
.where(
|
|
107
|
+
SQL.column(Group.table, 'id'),
|
|
108
|
+
SQL.column(Registration.table, 'groupId'),
|
|
109
|
+
),
|
|
110
|
+
)
|
|
111
|
+
.where(
|
|
112
|
+
SQL.column(Registration.table, 'memberId'),
|
|
113
|
+
SQL.column(MemberResponsibilityRecord.table, 'memberId'),
|
|
114
|
+
).where(
|
|
115
|
+
SQL.column(Registration.table, 'organizationId'),
|
|
116
|
+
SQL.column(MemberResponsibilityRecord.table, 'organizationId'),
|
|
117
|
+
).where(
|
|
118
|
+
SQL.column(Registration.table, 'periodId'),
|
|
119
|
+
SQL.column(Organization.table, 'periodId'),
|
|
120
|
+
).where(
|
|
121
|
+
SQL.column(Registration.table, 'deactivatedAt'),
|
|
122
|
+
null,
|
|
123
|
+
).whereNot(
|
|
124
|
+
SQL.column(Registration.table, 'registeredAt'),
|
|
125
|
+
null,
|
|
126
|
+
).where(
|
|
127
|
+
SQL.column(Group.table, 'type'),
|
|
128
|
+
GroupType.Membership,
|
|
129
|
+
).where(
|
|
130
|
+
SQL.column(Group.table, 'deletedAt'),
|
|
71
131
|
null,
|
|
72
|
-
).or(
|
|
73
|
-
SQL.column(MemberResponsibilityRecord.table, 'responsibilityId'),
|
|
74
|
-
'!=',
|
|
75
|
-
platformResponsibilityIds,
|
|
76
132
|
),
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
),
|
|
82
|
-
)
|
|
83
|
-
.fetch();
|
|
133
|
+
),
|
|
134
|
+
)
|
|
135
|
+
.fetch();
|
|
136
|
+
}
|
|
84
137
|
}
|
|
85
138
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
2
|
-
import { Group, Organization, OrganizationRegistrationPeriod, RegistrationPeriod } from '@stamhoofd/models';
|
|
2
|
+
import { Group, Member, MemberResponsibilityRecord, Organization, OrganizationRegistrationPeriod, Platform, RegistrationPeriod } from '@stamhoofd/models';
|
|
3
3
|
import { QueueHandler } from '@stamhoofd/queues';
|
|
4
|
-
import { AuditLogSource, Group as GroupStruct } from '@stamhoofd/structures';
|
|
4
|
+
import { AuditLogSource, Group as GroupStruct, PermissionLevel } from '@stamhoofd/structures';
|
|
5
5
|
import { PatchOrganizationRegistrationPeriodsEndpoint } from '../endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint';
|
|
6
6
|
import { AuditLogService } from '../services/AuditLogService';
|
|
7
7
|
import { AuthenticatedStructures } from './AuthenticatedStructures';
|
|
8
|
+
import { MemberUserSyncer } from './MemberUserSyncer';
|
|
8
9
|
import { SetupStepUpdater } from './SetupStepUpdater';
|
|
9
10
|
|
|
10
11
|
export class PeriodHelper {
|
|
@@ -17,6 +18,88 @@ export class PeriodHelper {
|
|
|
17
18
|
});
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
static async stopAllResponsibilities() {
|
|
22
|
+
console.log('Stopping all responsibilities');
|
|
23
|
+
const platform = await Platform.getSharedPrivateStruct();
|
|
24
|
+
const keepPlatformResponsibilityIds = platform.config.responsibilities.filter(r => !r.organizationBased).map(r => r.id);
|
|
25
|
+
const keepResponsibilityIds = platform.config.responsibilities.filter(r => !r.organizationBased || r.permissions?.level === PermissionLevel.Full).map(r => r.id);
|
|
26
|
+
const batchSize = 100;
|
|
27
|
+
|
|
28
|
+
let lastId = '';
|
|
29
|
+
let c = 0;
|
|
30
|
+
|
|
31
|
+
while (true) {
|
|
32
|
+
const records = await MemberResponsibilityRecord.where(
|
|
33
|
+
{
|
|
34
|
+
id: { sign: '>', value: lastId },
|
|
35
|
+
endDate: null,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
limit: batchSize,
|
|
39
|
+
sort: ['id'],
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
for (const record of records) {
|
|
44
|
+
lastId = record.id;
|
|
45
|
+
|
|
46
|
+
const invalid = keepPlatformResponsibilityIds.includes(record.responsibilityId) && record.organizationId;
|
|
47
|
+
|
|
48
|
+
if (!keepResponsibilityIds.includes(record.responsibilityId) || invalid) {
|
|
49
|
+
record.endDate = new Date();
|
|
50
|
+
await record.save();
|
|
51
|
+
c++;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (records.length < batchSize) {
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log('Done: stopped all responsibilities: ' + c);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static async syncAllMemberUsers() {
|
|
64
|
+
console.log('Syncing all members');
|
|
65
|
+
|
|
66
|
+
let c = 0;
|
|
67
|
+
let lastId: string = '';
|
|
68
|
+
|
|
69
|
+
while (true) {
|
|
70
|
+
const rawMembers = await Member.where({
|
|
71
|
+
id: {
|
|
72
|
+
value: lastId,
|
|
73
|
+
sign: '>',
|
|
74
|
+
},
|
|
75
|
+
}, { limit: 500, sort: ['id'] });
|
|
76
|
+
|
|
77
|
+
if (rawMembers.length === 0) {
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const membersWithRegistrations = await Member.getBlobByIds(...rawMembers.map(m => m.id));
|
|
82
|
+
|
|
83
|
+
const promises: Promise<any>[] = [];
|
|
84
|
+
|
|
85
|
+
for (const memberWithRegistrations of membersWithRegistrations) {
|
|
86
|
+
promises.push((async () => {
|
|
87
|
+
await MemberUserSyncer.onChangeMember(memberWithRegistrations);
|
|
88
|
+
c++;
|
|
89
|
+
|
|
90
|
+
if (c % 10000 === 0) {
|
|
91
|
+
console.log('Synced ' + c + ' members');
|
|
92
|
+
}
|
|
93
|
+
})());
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
await Promise.all(promises);
|
|
97
|
+
lastId = rawMembers[rawMembers.length - 1].id;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log('Done: synced all members: ' + c);
|
|
101
|
+
}
|
|
102
|
+
|
|
20
103
|
static async createOrganizationPeriodForPeriod(organization: Organization, period: RegistrationPeriod) {
|
|
21
104
|
const oPeriods = await OrganizationRegistrationPeriod.where({ periodId: period.id, organizationId: organization.id }, { limit: 1 });
|
|
22
105
|
|
|
@@ -10,7 +10,7 @@ export const registrationPeriodFilterCompilers: SQLFilterDefinitions = {
|
|
|
10
10
|
organizationId: createColumnFilter({
|
|
11
11
|
expression: SQL.column('organizationId'),
|
|
12
12
|
type: SQLValueType.String,
|
|
13
|
-
nullable:
|
|
13
|
+
nullable: true,
|
|
14
14
|
}),
|
|
15
15
|
startDate: createColumnFilter({
|
|
16
16
|
expression: SQL.column('startDate'),
|
package/tests/jest.setup.ts
CHANGED
|
@@ -52,7 +52,9 @@ beforeAll(async () => {
|
|
|
52
52
|
await Database.delete('DELETE FROM `groups`');
|
|
53
53
|
await Database.delete('DELETE FROM `email_addresses`');
|
|
54
54
|
|
|
55
|
+
await Database.update('UPDATE registration_periods set organizationId = null, customName = ? where organizationId is not null', ['delete']);
|
|
55
56
|
await Database.delete('DELETE FROM `organizations`');
|
|
57
|
+
await Database.delete('DELETE FROM `registration_periods` where customName = ?', ['delete']);
|
|
56
58
|
|
|
57
59
|
await Database.delete('DELETE FROM `payments`');
|
|
58
60
|
await Database.delete('OPTIMIZE TABLE organizations;'); // fix breaking of indexes due to deletes (mysql bug?)
|