@nymphjs/tilmeld 1.0.0-beta.6 → 1.0.0-beta.61
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/CHANGELOG.md +284 -0
- package/README.md +14 -1
- package/dist/AbleObject.d.ts +15 -0
- package/dist/AbleObject.js +16 -1
- package/dist/AbleObject.js.map +1 -1
- package/dist/Group.d.ts +119 -8
- package/dist/Group.js +230 -97
- package/dist/Group.js.map +1 -1
- package/dist/Group.test.js +3 -2
- package/dist/Group.test.js.map +1 -1
- package/dist/Tilmeld.d.ts +237 -9
- package/dist/Tilmeld.js +559 -195
- package/dist/Tilmeld.js.map +1 -1
- package/dist/User.d.ts +333 -14
- package/dist/User.js +797 -204
- package/dist/User.js.map +1 -1
- package/dist/User.test.js +3 -2
- package/dist/User.test.js.map +1 -1
- package/dist/conf/d.d.ts +250 -3
- package/dist/conf/defaults.js +146 -98
- package/dist/conf/defaults.js.map +1 -1
- package/dist/enforceTilmeld.d.ts +3 -0
- package/dist/enforceTilmeld.js +22 -0
- package/dist/enforceTilmeld.js.map +1 -0
- package/dist/errors/AccessControlError.d.ts +2 -1
- package/dist/errors/AccessControlError.js +3 -2
- package/dist/errors/AccessControlError.js.map +1 -1
- package/dist/errors/BadDataError.d.ts +2 -1
- package/dist/errors/BadDataError.js +3 -2
- package/dist/errors/BadDataError.js.map +1 -1
- package/dist/errors/BadEmailError.d.ts +2 -1
- package/dist/errors/BadEmailError.js +3 -2
- package/dist/errors/BadEmailError.js.map +1 -1
- package/dist/errors/BadUsernameError.d.ts +2 -1
- package/dist/errors/BadUsernameError.js +3 -2
- package/dist/errors/BadUsernameError.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +30 -26
- package/src/AbleObject.ts +2 -2
- package/src/Group.test.ts +3 -3
- package/src/Group.ts +194 -143
- package/src/Tilmeld.ts +384 -249
- package/src/User.test.ts +3 -3
- package/src/User.ts +876 -266
- package/src/conf/d.ts +26 -13
- package/src/conf/defaults.ts +151 -104
- package/src/enforceTilmeld.ts +20 -0
- package/src/errors/AccessControlError.ts +4 -2
- package/src/errors/BadDataError.ts +4 -2
- package/src/errors/BadEmailError.ts +4 -2
- package/src/errors/BadUsernameError.ts +4 -2
- package/src/index.ts +2 -0
- package/src/tilmeldJoiProps.ts +9 -9
- package/tsconfig.json +1 -1
- package/typedoc.json +4 -0
package/src/Group.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EntityData,
|
|
3
|
-
EntityInterface,
|
|
4
3
|
EntityJson,
|
|
5
4
|
EntityPatch,
|
|
6
5
|
Options,
|
|
@@ -10,7 +9,7 @@ import {
|
|
|
10
9
|
import md5 from 'crypto-js/md5';
|
|
11
10
|
import { difference } from 'lodash';
|
|
12
11
|
|
|
13
|
-
import
|
|
12
|
+
import { enforceTilmeld } from './enforceTilmeld';
|
|
14
13
|
import AbleObject from './AbleObject';
|
|
15
14
|
import {
|
|
16
15
|
BadDataError,
|
|
@@ -85,7 +84,6 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
85
84
|
/**
|
|
86
85
|
* The instance of Tilmeld to use for queries.
|
|
87
86
|
*/
|
|
88
|
-
static tilmeld: Tilmeld;
|
|
89
87
|
static ETYPE = 'tilmeld_group';
|
|
90
88
|
static class = 'Group';
|
|
91
89
|
|
|
@@ -116,12 +114,8 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
116
114
|
*/
|
|
117
115
|
private $skipAcWhenSaving = false;
|
|
118
116
|
|
|
119
|
-
static async factory(guid?: string): Promise<Group & GroupData> {
|
|
120
|
-
return (await super.factory(guid)) as Group & GroupData;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
117
|
static async factoryGroupname(
|
|
124
|
-
groupname?: string
|
|
118
|
+
groupname?: string,
|
|
125
119
|
): Promise<Group & GroupData> {
|
|
126
120
|
const entity = new this();
|
|
127
121
|
if (groupname != null) {
|
|
@@ -132,7 +126,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
132
126
|
{
|
|
133
127
|
type: '&',
|
|
134
128
|
ilike: ['groupname', groupname.replace(/([\\%_])/g, (s) => `\\${s}`)],
|
|
135
|
-
}
|
|
129
|
+
},
|
|
136
130
|
);
|
|
137
131
|
if (entity != null) {
|
|
138
132
|
return entity;
|
|
@@ -141,19 +135,13 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
141
135
|
return entity;
|
|
142
136
|
}
|
|
143
137
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
constructor(guid?: string) {
|
|
149
|
-
super(guid);
|
|
138
|
+
constructor() {
|
|
139
|
+
super();
|
|
150
140
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
this.$updateDataProtection();
|
|
156
|
-
}
|
|
141
|
+
// Defaults.
|
|
142
|
+
this.$data.enabled = true;
|
|
143
|
+
this.$data.abilities = [];
|
|
144
|
+
this.$updateDataProtection();
|
|
157
145
|
}
|
|
158
146
|
|
|
159
147
|
/**
|
|
@@ -165,16 +153,17 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
165
153
|
*/
|
|
166
154
|
public static async getPrimaryGroups(
|
|
167
155
|
options?: Options,
|
|
168
|
-
selectors?: Selector[]
|
|
156
|
+
selectors?: Selector[],
|
|
169
157
|
) {
|
|
170
|
-
|
|
158
|
+
const tilmeld = enforceTilmeld(this);
|
|
159
|
+
if (!tilmeld.gatekeeper('tilmeld/admin')) {
|
|
171
160
|
throw new Error("You don't have permission to do that.");
|
|
172
161
|
}
|
|
173
162
|
|
|
174
163
|
return await this.getAssignableGroups(
|
|
175
|
-
|
|
176
|
-
{ ...options, class:
|
|
177
|
-
[...(selectors ?? [])]
|
|
164
|
+
tilmeld.config.highestPrimary,
|
|
165
|
+
{ ...options, class: tilmeld.Group, return: 'entity' },
|
|
166
|
+
[...(selectors ?? [])],
|
|
178
167
|
);
|
|
179
168
|
}
|
|
180
169
|
|
|
@@ -187,24 +176,26 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
187
176
|
*/
|
|
188
177
|
public static async getSecondaryGroups(
|
|
189
178
|
options?: Options,
|
|
190
|
-
selectors?: Selector[]
|
|
179
|
+
selectors?: Selector[],
|
|
191
180
|
) {
|
|
192
|
-
|
|
181
|
+
const tilmeld = enforceTilmeld(this);
|
|
182
|
+
if (!tilmeld.gatekeeper('tilmeld/admin')) {
|
|
193
183
|
throw new Error("You don't have permission to do that.");
|
|
194
184
|
}
|
|
195
185
|
|
|
196
186
|
return await this.getAssignableGroups(
|
|
197
|
-
|
|
198
|
-
{ ...options, class:
|
|
199
|
-
[...(selectors ?? [])]
|
|
187
|
+
tilmeld.config.highestSecondary,
|
|
188
|
+
{ ...options, class: tilmeld.Group, return: 'entity' },
|
|
189
|
+
[...(selectors ?? [])],
|
|
200
190
|
);
|
|
201
191
|
}
|
|
202
192
|
|
|
203
193
|
private static async getAssignableGroups(
|
|
204
194
|
highestParent: string | boolean,
|
|
205
195
|
options: Options<typeof Group>,
|
|
206
|
-
selectors: Selector[]
|
|
196
|
+
selectors: Selector[],
|
|
207
197
|
) {
|
|
198
|
+
const tilmeld = enforceTilmeld(this);
|
|
208
199
|
let assignableGroups: (Group & GroupData)[] = [];
|
|
209
200
|
|
|
210
201
|
if (highestParent === false) {
|
|
@@ -212,20 +203,28 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
212
203
|
}
|
|
213
204
|
|
|
214
205
|
assignableGroups = await this.nymph.getEntities(
|
|
215
|
-
{ ...options, class:
|
|
216
|
-
...selectors
|
|
206
|
+
{ ...options, class: tilmeld.Group },
|
|
207
|
+
...selectors,
|
|
217
208
|
);
|
|
218
209
|
if (highestParent !== true) {
|
|
219
|
-
assignableGroups =
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
210
|
+
assignableGroups = (
|
|
211
|
+
await Promise.all(
|
|
212
|
+
assignableGroups.map(async (group) => {
|
|
213
|
+
let curGroup = group;
|
|
214
|
+
let parent = curGroup.parent;
|
|
215
|
+
await parent?.$wake();
|
|
216
|
+
while (parent != null && parent?.cdate != null) {
|
|
217
|
+
if (parent?.guid === highestParent) {
|
|
218
|
+
return group;
|
|
219
|
+
}
|
|
220
|
+
curGroup = parent;
|
|
221
|
+
parent = curGroup.parent;
|
|
222
|
+
await parent?.$wake();
|
|
223
|
+
}
|
|
224
|
+
return null;
|
|
225
|
+
}),
|
|
226
|
+
)
|
|
227
|
+
).filter((group) => group != null) as (Group & GroupData)[];
|
|
229
228
|
}
|
|
230
229
|
return assignableGroups;
|
|
231
230
|
}
|
|
@@ -245,17 +244,42 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
245
244
|
}
|
|
246
245
|
|
|
247
246
|
public $jsonAcceptData(input: EntityJson, allowConflict = false) {
|
|
248
|
-
const tilmeld = this
|
|
249
|
-
this.$
|
|
247
|
+
const tilmeld = enforceTilmeld(this);
|
|
248
|
+
this.$check();
|
|
250
249
|
|
|
251
250
|
if (
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
!tilmeld.
|
|
251
|
+
'abilities' in input.data &&
|
|
252
|
+
input.data.abilities?.includes('system/admin') !==
|
|
253
|
+
this.$data.abilities?.includes('system/admin') &&
|
|
254
|
+
(!tilmeld.currentUser ||
|
|
255
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
256
256
|
) {
|
|
257
257
|
throw new BadDataError(
|
|
258
|
-
"You don't have the authority to
|
|
258
|
+
"You don't have the authority to grant or revoke system/admin.",
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (
|
|
263
|
+
'abilities' in input.data &&
|
|
264
|
+
input.data.abilities?.includes('tilmeld/admin') !==
|
|
265
|
+
this.$data.abilities?.includes('tilmeld/admin') &&
|
|
266
|
+
(!tilmeld.currentUser ||
|
|
267
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
268
|
+
) {
|
|
269
|
+
throw new BadDataError(
|
|
270
|
+
"You don't have the authority to grant or revoke tilmeld/admin.",
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (
|
|
275
|
+
'abilities' in input.data &&
|
|
276
|
+
input.data.abilities?.includes('tilmeld/switch') !==
|
|
277
|
+
this.$data.abilities?.includes('tilmeld/switch') &&
|
|
278
|
+
(!tilmeld.currentUser ||
|
|
279
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
280
|
+
) {
|
|
281
|
+
throw new BadDataError(
|
|
282
|
+
"You don't have the authority to grant or revoke tilmeld/switch.",
|
|
259
283
|
);
|
|
260
284
|
}
|
|
261
285
|
|
|
@@ -263,17 +287,42 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
263
287
|
}
|
|
264
288
|
|
|
265
289
|
public $jsonAcceptPatch(patch: EntityPatch, allowConflict = false) {
|
|
266
|
-
const tilmeld = this
|
|
267
|
-
this.$
|
|
290
|
+
const tilmeld = enforceTilmeld(this);
|
|
291
|
+
this.$check();
|
|
292
|
+
|
|
293
|
+
if (
|
|
294
|
+
'abilities' in patch.set &&
|
|
295
|
+
patch.set.abilities?.includes('system/admin') !==
|
|
296
|
+
this.$data.abilities?.includes('system/admin') &&
|
|
297
|
+
(!tilmeld.currentUser ||
|
|
298
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
299
|
+
) {
|
|
300
|
+
throw new BadDataError(
|
|
301
|
+
"You don't have the authority to grant or revoke system/admin.",
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (
|
|
306
|
+
'abilities' in patch.set &&
|
|
307
|
+
patch.set.abilities?.includes('tilmeld/admin') !==
|
|
308
|
+
this.$data.abilities?.includes('tilmeld/admin') &&
|
|
309
|
+
(!tilmeld.currentUser ||
|
|
310
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
311
|
+
) {
|
|
312
|
+
throw new BadDataError(
|
|
313
|
+
"You don't have the authority to grant or revoke tilmeld/admin.",
|
|
314
|
+
);
|
|
315
|
+
}
|
|
268
316
|
|
|
269
317
|
if (
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
!tilmeld.
|
|
318
|
+
'abilities' in patch.set &&
|
|
319
|
+
patch.set.abilities?.includes('tilmeld/switch') !==
|
|
320
|
+
this.$data.abilities?.includes('tilmeld/switch') &&
|
|
321
|
+
(!tilmeld.currentUser ||
|
|
322
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
274
323
|
) {
|
|
275
324
|
throw new BadDataError(
|
|
276
|
-
"You don't have the authority to
|
|
325
|
+
"You don't have the authority to grant or revoke tilmeld/switch.",
|
|
277
326
|
);
|
|
278
327
|
}
|
|
279
328
|
|
|
@@ -291,7 +340,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
291
340
|
* @param givenUser User to update protection for. If undefined, will use the currently logged in user.
|
|
292
341
|
*/
|
|
293
342
|
public $updateDataProtection(givenUser?: User & UserData) {
|
|
294
|
-
const tilmeld = this
|
|
343
|
+
const tilmeld = enforceTilmeld(this);
|
|
295
344
|
let user = givenUser ?? tilmeld.User.current();
|
|
296
345
|
|
|
297
346
|
this.$privateData = [...Group.DEFAULT_PRIVATE_DATA];
|
|
@@ -303,8 +352,8 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
303
352
|
|
|
304
353
|
if (
|
|
305
354
|
user != null &&
|
|
306
|
-
(
|
|
307
|
-
|
|
355
|
+
(user.abilities?.includes('tilmeld/admin') ||
|
|
356
|
+
user.abilities?.includes('system/admin'))
|
|
308
357
|
) {
|
|
309
358
|
// Users who can edit groups can see their data.
|
|
310
359
|
this.$privateData = [];
|
|
@@ -312,7 +361,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
312
361
|
} else if (
|
|
313
362
|
this.$data.user != null &&
|
|
314
363
|
user != null &&
|
|
315
|
-
this.$data.user
|
|
364
|
+
this.$data.user.guid === user.guid
|
|
316
365
|
) {
|
|
317
366
|
// Users can see their group's data.
|
|
318
367
|
this.$privateData = [];
|
|
@@ -325,11 +374,13 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
325
374
|
* @param group The group, or the group's GUID.
|
|
326
375
|
* @returns True or false.
|
|
327
376
|
*/
|
|
328
|
-
public $isDescendant(
|
|
329
|
-
|
|
377
|
+
public async $isDescendant(
|
|
378
|
+
givenGroup: (Group & GroupData) | string,
|
|
379
|
+
): Promise<boolean> {
|
|
380
|
+
const tilmeld = enforceTilmeld(this);
|
|
330
381
|
let group: Group & GroupData;
|
|
331
382
|
if (typeof givenGroup === 'string') {
|
|
332
|
-
group = tilmeld.Group.
|
|
383
|
+
group = await tilmeld.Group.factory(givenGroup);
|
|
333
384
|
} else {
|
|
334
385
|
group = givenGroup;
|
|
335
386
|
}
|
|
@@ -337,13 +388,15 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
337
388
|
return false;
|
|
338
389
|
}
|
|
339
390
|
// Check to see if the group is a descendant of the given group.
|
|
340
|
-
|
|
391
|
+
const parent = this.$data.parent;
|
|
392
|
+
await parent?.$wake();
|
|
393
|
+
if (parent == null) {
|
|
341
394
|
return false;
|
|
342
395
|
}
|
|
343
|
-
if (
|
|
396
|
+
if (parent.$is(group)) {
|
|
344
397
|
return true;
|
|
345
398
|
}
|
|
346
|
-
if (
|
|
399
|
+
if (await parent.$isDescendant(group)) {
|
|
347
400
|
return true;
|
|
348
401
|
}
|
|
349
402
|
return false;
|
|
@@ -355,14 +408,14 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
355
408
|
* @returns An array of groups.
|
|
356
409
|
*/
|
|
357
410
|
public async $getChildren() {
|
|
358
|
-
const tilmeld = this
|
|
411
|
+
const tilmeld = enforceTilmeld(this);
|
|
359
412
|
return await this.$nymph.getEntities(
|
|
360
413
|
{ class: tilmeld.Group },
|
|
361
414
|
{
|
|
362
415
|
type: '&',
|
|
363
416
|
equal: ['enabled', true],
|
|
364
417
|
ref: ['parent', this],
|
|
365
|
-
}
|
|
418
|
+
},
|
|
366
419
|
);
|
|
367
420
|
}
|
|
368
421
|
|
|
@@ -373,9 +426,9 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
373
426
|
* @returns An array of groups.
|
|
374
427
|
*/
|
|
375
428
|
public async $getDescendants(
|
|
376
|
-
andSelf = false
|
|
429
|
+
andSelf = false,
|
|
377
430
|
): Promise<(Group & GroupData)[]> {
|
|
378
|
-
const tilmeld = this
|
|
431
|
+
const tilmeld = enforceTilmeld(this);
|
|
379
432
|
let groups: (Group & GroupData)[] = [];
|
|
380
433
|
const entities = await this.$nymph.getEntities(
|
|
381
434
|
{ class: tilmeld.Group },
|
|
@@ -383,7 +436,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
383
436
|
type: '&',
|
|
384
437
|
equal: ['enabled', true],
|
|
385
438
|
ref: ['parent', this],
|
|
386
|
-
}
|
|
439
|
+
},
|
|
387
440
|
);
|
|
388
441
|
for (let entity of entities) {
|
|
389
442
|
groups = (await entity.$getDescendants(true)).concat(groups);
|
|
@@ -394,37 +447,6 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
394
447
|
return groups;
|
|
395
448
|
}
|
|
396
449
|
|
|
397
|
-
/**
|
|
398
|
-
* Gets an array of the group's descendant groups.
|
|
399
|
-
*
|
|
400
|
-
* @param andSelf Include this group in the returned array.
|
|
401
|
-
* @returns An array of groups.
|
|
402
|
-
*/
|
|
403
|
-
public $getDescendantsSync(andSelf = false): (Group & GroupData)[] {
|
|
404
|
-
const tilmeld = this.$nymph.tilmeld as Tilmeld;
|
|
405
|
-
let groups: (Group & GroupData)[] = [];
|
|
406
|
-
let entity: EntityInterface | null;
|
|
407
|
-
let offset = 0;
|
|
408
|
-
do {
|
|
409
|
-
entity = this.$nymph.driver.getEntitySync(
|
|
410
|
-
{ class: tilmeld.Group, offset },
|
|
411
|
-
{
|
|
412
|
-
type: '&',
|
|
413
|
-
equal: ['enabled', true],
|
|
414
|
-
ref: ['parent', this],
|
|
415
|
-
}
|
|
416
|
-
);
|
|
417
|
-
if (entity != null) {
|
|
418
|
-
groups = entity.$getDescendantsSync(true).concat(groups);
|
|
419
|
-
}
|
|
420
|
-
offset++;
|
|
421
|
-
} while (entity != null);
|
|
422
|
-
if (andSelf) {
|
|
423
|
-
groups.push(this);
|
|
424
|
-
}
|
|
425
|
-
return groups;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
450
|
/**
|
|
429
451
|
* Get the number of parents the group has.
|
|
430
452
|
*
|
|
@@ -436,13 +458,17 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
436
458
|
*
|
|
437
459
|
* @returns The level of the group.
|
|
438
460
|
*/
|
|
439
|
-
public $getLevel() {
|
|
440
|
-
const tilmeld = this
|
|
441
|
-
let group = tilmeld.Group.
|
|
461
|
+
public async $getLevel() {
|
|
462
|
+
const tilmeld = enforceTilmeld(this);
|
|
463
|
+
let group = await tilmeld.Group.factory(this.guid ?? undefined);
|
|
464
|
+
let parent = group.parent;
|
|
465
|
+
await parent?.$wake();
|
|
442
466
|
let level = 0;
|
|
443
|
-
while (
|
|
467
|
+
while (parent != null && parent.cdate != null && level < 1024) {
|
|
444
468
|
level++;
|
|
445
|
-
group =
|
|
469
|
+
group = parent;
|
|
470
|
+
parent = group.parent;
|
|
471
|
+
await parent?.$wake();
|
|
446
472
|
}
|
|
447
473
|
return level;
|
|
448
474
|
}
|
|
@@ -458,9 +484,9 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
458
484
|
public async $getUsers(
|
|
459
485
|
descendants = false,
|
|
460
486
|
limit?: number,
|
|
461
|
-
offset?: number
|
|
487
|
+
offset?: number,
|
|
462
488
|
): Promise<(User & UserData)[]> {
|
|
463
|
-
const tilmeld = this
|
|
489
|
+
const tilmeld = enforceTilmeld(this);
|
|
464
490
|
let groups: (Group & GroupData)[] = [];
|
|
465
491
|
if (descendants) {
|
|
466
492
|
groups = await this.$getDescendants();
|
|
@@ -489,7 +515,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
489
515
|
group,
|
|
490
516
|
]),
|
|
491
517
|
],
|
|
492
|
-
}
|
|
518
|
+
},
|
|
493
519
|
);
|
|
494
520
|
}
|
|
495
521
|
|
|
@@ -502,15 +528,21 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
502
528
|
result: boolean;
|
|
503
529
|
message: string;
|
|
504
530
|
}> {
|
|
505
|
-
const tilmeld = this
|
|
531
|
+
const tilmeld = enforceTilmeld(this);
|
|
506
532
|
if (!tilmeld.config.emailUsernames) {
|
|
507
533
|
if (this.$data.groupname == null || !this.$data.groupname.length) {
|
|
508
534
|
return { result: false, message: 'Please specify a groupname.' };
|
|
509
535
|
}
|
|
510
|
-
if (
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
536
|
+
if (this.$data.groupname.length < tilmeld.config.minUsernameLength) {
|
|
537
|
+
return {
|
|
538
|
+
result: false,
|
|
539
|
+
message:
|
|
540
|
+
'Groupnames must be at least ' +
|
|
541
|
+
tilmeld.config.minUsernameLength +
|
|
542
|
+
' characters.',
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
if (this.$data.groupname.length > tilmeld.config.maxUsernameLength) {
|
|
514
546
|
return {
|
|
515
547
|
result: false,
|
|
516
548
|
message:
|
|
@@ -522,7 +554,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
522
554
|
if (
|
|
523
555
|
difference(
|
|
524
556
|
this.$data.groupname.split(''),
|
|
525
|
-
tilmeld.config.validChars.split('')
|
|
557
|
+
tilmeld.config.validChars.split(''),
|
|
526
558
|
).length
|
|
527
559
|
) {
|
|
528
560
|
return {
|
|
@@ -549,7 +581,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
549
581
|
}
|
|
550
582
|
const test = await this.$nymph.getEntity(
|
|
551
583
|
{ class: tilmeld.Group, skipAc: true },
|
|
552
|
-
selector
|
|
584
|
+
selector,
|
|
553
585
|
);
|
|
554
586
|
if (test != null) {
|
|
555
587
|
return { result: false, message: 'That groupname is taken.' };
|
|
@@ -565,10 +597,16 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
565
597
|
if (this.$data.groupname == null || !this.$data.groupname.length) {
|
|
566
598
|
return { result: false, message: 'Please specify an email.' };
|
|
567
599
|
}
|
|
568
|
-
if (
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
600
|
+
if (this.$data.groupname.length < tilmeld.config.minUsernameLength) {
|
|
601
|
+
return {
|
|
602
|
+
result: false,
|
|
603
|
+
message:
|
|
604
|
+
'Emails must be at least ' +
|
|
605
|
+
tilmeld.config.minUsernameLength +
|
|
606
|
+
' characters.',
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
if (this.$data.groupname.length > tilmeld.config.maxUsernameLength) {
|
|
572
610
|
return {
|
|
573
611
|
result: false,
|
|
574
612
|
message:
|
|
@@ -588,7 +626,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
588
626
|
* @returns An object with a boolean 'result' entry and a 'message' entry.
|
|
589
627
|
*/
|
|
590
628
|
public async $checkEmail(): Promise<{ result: boolean; message: string }> {
|
|
591
|
-
const tilmeld = this
|
|
629
|
+
const tilmeld = enforceTilmeld(this);
|
|
592
630
|
if (this.$data.email === '') {
|
|
593
631
|
return { result: true, message: '' };
|
|
594
632
|
}
|
|
@@ -610,7 +648,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
610
648
|
}
|
|
611
649
|
const test = await this.$nymph.getEntity(
|
|
612
650
|
{ class: tilmeld.Group, skipAc: true },
|
|
613
|
-
selector
|
|
651
|
+
selector,
|
|
614
652
|
);
|
|
615
653
|
if (test != null) {
|
|
616
654
|
return {
|
|
@@ -627,7 +665,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
627
665
|
}
|
|
628
666
|
|
|
629
667
|
public async $save() {
|
|
630
|
-
const tilmeld = this
|
|
668
|
+
const tilmeld = enforceTilmeld(this);
|
|
631
669
|
if (this.$data.groupname == null || !this.$data.groupname.trim().length) {
|
|
632
670
|
return false;
|
|
633
671
|
}
|
|
@@ -643,16 +681,22 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
643
681
|
this.$data.enabled = !!this.$data.enabled;
|
|
644
682
|
|
|
645
683
|
// Clear empty values.
|
|
646
|
-
if (this.$data.name === '') {
|
|
684
|
+
if (this.$data.name === '' || !tilmeld.config.userFields.includes('name')) {
|
|
647
685
|
delete this.$data.name;
|
|
648
686
|
}
|
|
649
|
-
if (
|
|
687
|
+
if (
|
|
688
|
+
this.$data.email === '' ||
|
|
689
|
+
!tilmeld.config.userFields.includes('email')
|
|
690
|
+
) {
|
|
650
691
|
delete this.$data.email;
|
|
651
692
|
}
|
|
652
693
|
if (this.$data.avatar === '') {
|
|
653
694
|
delete this.$data.avatar;
|
|
654
695
|
}
|
|
655
|
-
if (
|
|
696
|
+
if (
|
|
697
|
+
this.$data.phone === '' ||
|
|
698
|
+
!tilmeld.config.userFields.includes('phone')
|
|
699
|
+
) {
|
|
656
700
|
delete this.$data.phone;
|
|
657
701
|
}
|
|
658
702
|
if (this.$data.parent == null) {
|
|
@@ -671,10 +715,12 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
671
715
|
delete this.$data.unverifiedSecondary;
|
|
672
716
|
}
|
|
673
717
|
|
|
674
|
-
// Groups should never have 'system/admin'
|
|
718
|
+
// Groups should never have 'system/admin', 'tilmeld/admin', or
|
|
719
|
+
// 'tilmeld/switch' abilities.
|
|
675
720
|
this.$data.abilities = difference(this.$data.abilities ?? [], [
|
|
676
721
|
'system/admin',
|
|
677
722
|
'tilmeld/admin',
|
|
723
|
+
'tilmeld/switch',
|
|
678
724
|
null,
|
|
679
725
|
undefined,
|
|
680
726
|
]) as string[];
|
|
@@ -684,7 +730,10 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
684
730
|
if (!unCheck.result) {
|
|
685
731
|
throw new BadUsernameError(unCheck.message);
|
|
686
732
|
}
|
|
687
|
-
if (
|
|
733
|
+
if (
|
|
734
|
+
!tilmeld.config.emailUsernames &&
|
|
735
|
+
tilmeld.config.userFields.includes('email')
|
|
736
|
+
) {
|
|
688
737
|
const emCheck = await this.$checkEmail();
|
|
689
738
|
if (!emCheck.result) {
|
|
690
739
|
throw new BadEmailError(emCheck.message);
|
|
@@ -692,19 +741,21 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
692
741
|
}
|
|
693
742
|
|
|
694
743
|
// Validate group parent. Make sure it's not a descendant of this group.
|
|
744
|
+
const parent = this.$data.parent;
|
|
745
|
+
await parent?.$wake();
|
|
695
746
|
if (
|
|
696
|
-
|
|
697
|
-
(
|
|
698
|
-
this.$is(
|
|
699
|
-
|
|
747
|
+
parent &&
|
|
748
|
+
(parent.cdate == null ||
|
|
749
|
+
this.$is(parent) ||
|
|
750
|
+
(await parent.$isDescendant(this)))
|
|
700
751
|
) {
|
|
701
752
|
throw new BadDataError(
|
|
702
|
-
"Group parent can't be itself or descendant of itself."
|
|
753
|
+
"Group parent can't be itself or descendant of itself.",
|
|
703
754
|
);
|
|
704
755
|
}
|
|
705
756
|
|
|
706
757
|
try {
|
|
707
|
-
tilmeld.config.validatorGroup(this);
|
|
758
|
+
tilmeld.config.validatorGroup(tilmeld, this);
|
|
708
759
|
} catch (e: any) {
|
|
709
760
|
throw new BadDataError(e?.message);
|
|
710
761
|
}
|
|
@@ -713,14 +764,14 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
713
764
|
if (this.$data.defaultPrimary) {
|
|
714
765
|
const currentPrimary = await this.$nymph.getEntity(
|
|
715
766
|
{ class: tilmeld.Group },
|
|
716
|
-
{ type: '&', truthy: 'defaultPrimary' }
|
|
767
|
+
{ type: '&', truthy: 'defaultPrimary' },
|
|
717
768
|
);
|
|
718
769
|
if (currentPrimary != null && !this.$is(currentPrimary)) {
|
|
719
770
|
currentPrimary.defaultPrimary = false;
|
|
720
771
|
if (!(await currentPrimary.$save())) {
|
|
721
772
|
throw new CouldNotChangeDefaultPrimaryGroupError(
|
|
722
773
|
'Could not change new user primary group from ' +
|
|
723
|
-
`${currentPrimary.groupname}
|
|
774
|
+
`${currentPrimary.groupname}.`,
|
|
724
775
|
);
|
|
725
776
|
}
|
|
726
777
|
}
|
|
@@ -746,7 +797,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
746
797
|
}
|
|
747
798
|
|
|
748
799
|
public async $delete() {
|
|
749
|
-
let tilmeld = this
|
|
800
|
+
let tilmeld = enforceTilmeld(this);
|
|
750
801
|
if (!tilmeld.gatekeeper('tilmeld/admin')) {
|
|
751
802
|
throw new BadDataError("You don't have the authority to delete groups.");
|
|
752
803
|
}
|
|
@@ -755,7 +806,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
755
806
|
const nymph = this.$nymph;
|
|
756
807
|
const tnymph = await nymph.startTransaction(transaction);
|
|
757
808
|
this.$nymph = tnymph;
|
|
758
|
-
tilmeld = this
|
|
809
|
+
tilmeld = enforceTilmeld(this);
|
|
759
810
|
|
|
760
811
|
// Delete descendants.
|
|
761
812
|
const descendants = await this.$getDescendants();
|
|
@@ -778,7 +829,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
778
829
|
{
|
|
779
830
|
type: '&',
|
|
780
831
|
ref: ['group', this],
|
|
781
|
-
}
|
|
832
|
+
},
|
|
782
833
|
);
|
|
783
834
|
for (let user of primaryUsers) {
|
|
784
835
|
delete user.group;
|
|
@@ -798,7 +849,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
798
849
|
{
|
|
799
850
|
type: '&',
|
|
800
851
|
ref: ['groups', this],
|
|
801
|
-
}
|
|
852
|
+
},
|
|
802
853
|
);
|
|
803
854
|
for (let user of secondaryUsers) {
|
|
804
855
|
user.$delGroup(this);
|