@nymphjs/tilmeld 1.0.0-beta.5 → 1.0.0-beta.50
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 +238 -0
- package/README.md +14 -1
- package/dist/AbleObject.js.map +1 -1
- package/dist/Group.d.ts +4 -7
- package/dist/Group.js +124 -86
- package/dist/Group.js.map +1 -1
- package/dist/Tilmeld.d.ts +12 -9
- package/dist/Tilmeld.js +240 -179
- package/dist/Tilmeld.js.map +1 -1
- package/dist/User.d.ts +69 -13
- package/dist/User.js +492 -169
- package/dist/User.js.map +1 -1
- package/dist/conf/d.d.ts +4 -1
- package/dist/conf/defaults.js +22 -8
- 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/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +29 -26
- package/src/AbleObject.ts +1 -1
- package/src/Group.test.ts +1 -1
- package/src/Group.ts +180 -130
- package/src/Tilmeld.ts +355 -244
- package/src/User.test.ts +1 -1
- package/src/User.ts +717 -230
- package/src/conf/d.ts +24 -11
- package/src/conf/defaults.ts +30 -14
- package/src/enforceTilmeld.ts +20 -0
- package/src/index.ts +2 -0
- package/src/tilmeldJoiProps.ts +9 -9
- 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
|
|
|
@@ -121,7 +119,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
121
119
|
}
|
|
122
120
|
|
|
123
121
|
static async factoryGroupname(
|
|
124
|
-
groupname?: string
|
|
122
|
+
groupname?: string,
|
|
125
123
|
): Promise<Group & GroupData> {
|
|
126
124
|
const entity = new this();
|
|
127
125
|
if (groupname != null) {
|
|
@@ -132,7 +130,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
132
130
|
{
|
|
133
131
|
type: '&',
|
|
134
132
|
ilike: ['groupname', groupname.replace(/([\\%_])/g, (s) => `\\${s}`)],
|
|
135
|
-
}
|
|
133
|
+
},
|
|
136
134
|
);
|
|
137
135
|
if (entity != null) {
|
|
138
136
|
return entity;
|
|
@@ -141,19 +139,17 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
141
139
|
return entity;
|
|
142
140
|
}
|
|
143
141
|
|
|
144
|
-
static factorySync(
|
|
145
|
-
return super.factorySync(
|
|
142
|
+
static factorySync(): Group & GroupData {
|
|
143
|
+
return super.factorySync() as Group & GroupData;
|
|
146
144
|
}
|
|
147
145
|
|
|
148
|
-
constructor(
|
|
149
|
-
super(
|
|
146
|
+
constructor() {
|
|
147
|
+
super();
|
|
150
148
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
this.$updateDataProtection();
|
|
156
|
-
}
|
|
149
|
+
// Defaults.
|
|
150
|
+
this.$data.enabled = true;
|
|
151
|
+
this.$data.abilities = [];
|
|
152
|
+
this.$updateDataProtection();
|
|
157
153
|
}
|
|
158
154
|
|
|
159
155
|
/**
|
|
@@ -165,16 +161,17 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
165
161
|
*/
|
|
166
162
|
public static async getPrimaryGroups(
|
|
167
163
|
options?: Options,
|
|
168
|
-
selectors?: Selector[]
|
|
164
|
+
selectors?: Selector[],
|
|
169
165
|
) {
|
|
170
|
-
|
|
166
|
+
const tilmeld = enforceTilmeld(this);
|
|
167
|
+
if (!tilmeld.gatekeeper('tilmeld/admin')) {
|
|
171
168
|
throw new Error("You don't have permission to do that.");
|
|
172
169
|
}
|
|
173
170
|
|
|
174
171
|
return await this.getAssignableGroups(
|
|
175
|
-
|
|
176
|
-
{ ...options, class:
|
|
177
|
-
[...(selectors ?? [])]
|
|
172
|
+
tilmeld.config.highestPrimary,
|
|
173
|
+
{ ...options, class: tilmeld.Group, return: 'entity' },
|
|
174
|
+
[...(selectors ?? [])],
|
|
178
175
|
);
|
|
179
176
|
}
|
|
180
177
|
|
|
@@ -187,24 +184,26 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
187
184
|
*/
|
|
188
185
|
public static async getSecondaryGroups(
|
|
189
186
|
options?: Options,
|
|
190
|
-
selectors?: Selector[]
|
|
187
|
+
selectors?: Selector[],
|
|
191
188
|
) {
|
|
192
|
-
|
|
189
|
+
const tilmeld = enforceTilmeld(this);
|
|
190
|
+
if (!tilmeld.gatekeeper('tilmeld/admin')) {
|
|
193
191
|
throw new Error("You don't have permission to do that.");
|
|
194
192
|
}
|
|
195
193
|
|
|
196
194
|
return await this.getAssignableGroups(
|
|
197
|
-
|
|
198
|
-
{ ...options, class:
|
|
199
|
-
[...(selectors ?? [])]
|
|
195
|
+
tilmeld.config.highestSecondary,
|
|
196
|
+
{ ...options, class: tilmeld.Group, return: 'entity' },
|
|
197
|
+
[...(selectors ?? [])],
|
|
200
198
|
);
|
|
201
199
|
}
|
|
202
200
|
|
|
203
201
|
private static async getAssignableGroups(
|
|
204
202
|
highestParent: string | boolean,
|
|
205
203
|
options: Options<typeof Group>,
|
|
206
|
-
selectors: Selector[]
|
|
204
|
+
selectors: Selector[],
|
|
207
205
|
) {
|
|
206
|
+
const tilmeld = enforceTilmeld(this);
|
|
208
207
|
let assignableGroups: (Group & GroupData)[] = [];
|
|
209
208
|
|
|
210
209
|
if (highestParent === false) {
|
|
@@ -212,20 +211,28 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
212
211
|
}
|
|
213
212
|
|
|
214
213
|
assignableGroups = await this.nymph.getEntities(
|
|
215
|
-
{ ...options, class:
|
|
216
|
-
...selectors
|
|
214
|
+
{ ...options, class: tilmeld.Group },
|
|
215
|
+
...selectors,
|
|
217
216
|
);
|
|
218
217
|
if (highestParent !== true) {
|
|
219
|
-
assignableGroups =
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
218
|
+
assignableGroups = (
|
|
219
|
+
await Promise.all(
|
|
220
|
+
assignableGroups.map(async (group) => {
|
|
221
|
+
let curGroup = group;
|
|
222
|
+
let parent = curGroup.parent;
|
|
223
|
+
await parent?.$wake();
|
|
224
|
+
while (parent != null && parent?.cdate != null) {
|
|
225
|
+
if (parent?.guid === highestParent) {
|
|
226
|
+
return group;
|
|
227
|
+
}
|
|
228
|
+
curGroup = parent;
|
|
229
|
+
parent = curGroup.parent;
|
|
230
|
+
await parent?.$wake();
|
|
231
|
+
}
|
|
232
|
+
return null;
|
|
233
|
+
}),
|
|
234
|
+
)
|
|
235
|
+
).filter((group) => group != null) as (Group & GroupData)[];
|
|
229
236
|
}
|
|
230
237
|
return assignableGroups;
|
|
231
238
|
}
|
|
@@ -245,17 +252,42 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
245
252
|
}
|
|
246
253
|
|
|
247
254
|
public $jsonAcceptData(input: EntityJson, allowConflict = false) {
|
|
248
|
-
const tilmeld = this
|
|
249
|
-
this.$
|
|
255
|
+
const tilmeld = enforceTilmeld(this);
|
|
256
|
+
this.$check();
|
|
257
|
+
|
|
258
|
+
if (
|
|
259
|
+
'abilities' in input.data &&
|
|
260
|
+
input.data.abilities?.includes('system/admin') !==
|
|
261
|
+
this.$data.abilities?.includes('system/admin') &&
|
|
262
|
+
(!tilmeld.currentUser ||
|
|
263
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
264
|
+
) {
|
|
265
|
+
throw new BadDataError(
|
|
266
|
+
"You don't have the authority to grant or revoke system/admin.",
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
if (
|
|
271
|
+
'abilities' in input.data &&
|
|
272
|
+
input.data.abilities?.includes('tilmeld/admin') !==
|
|
273
|
+
this.$data.abilities?.includes('tilmeld/admin') &&
|
|
274
|
+
(!tilmeld.currentUser ||
|
|
275
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
276
|
+
) {
|
|
277
|
+
throw new BadDataError(
|
|
278
|
+
"You don't have the authority to grant or revoke tilmeld/admin.",
|
|
279
|
+
);
|
|
280
|
+
}
|
|
250
281
|
|
|
251
282
|
if (
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
!tilmeld.
|
|
283
|
+
'abilities' in input.data &&
|
|
284
|
+
input.data.abilities?.includes('tilmeld/switch') !==
|
|
285
|
+
this.$data.abilities?.includes('tilmeld/switch') &&
|
|
286
|
+
(!tilmeld.currentUser ||
|
|
287
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
256
288
|
) {
|
|
257
289
|
throw new BadDataError(
|
|
258
|
-
"You don't have the authority to
|
|
290
|
+
"You don't have the authority to grant or revoke tilmeld/switch.",
|
|
259
291
|
);
|
|
260
292
|
}
|
|
261
293
|
|
|
@@ -263,17 +295,42 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
263
295
|
}
|
|
264
296
|
|
|
265
297
|
public $jsonAcceptPatch(patch: EntityPatch, allowConflict = false) {
|
|
266
|
-
const tilmeld = this
|
|
267
|
-
this.$
|
|
298
|
+
const tilmeld = enforceTilmeld(this);
|
|
299
|
+
this.$check();
|
|
268
300
|
|
|
269
301
|
if (
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
!tilmeld.
|
|
302
|
+
'abilities' in patch.set &&
|
|
303
|
+
patch.set.abilities?.includes('system/admin') !==
|
|
304
|
+
this.$data.abilities?.includes('system/admin') &&
|
|
305
|
+
(!tilmeld.currentUser ||
|
|
306
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
274
307
|
) {
|
|
275
308
|
throw new BadDataError(
|
|
276
|
-
"You don't have the authority to
|
|
309
|
+
"You don't have the authority to grant or revoke system/admin.",
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (
|
|
314
|
+
'abilities' in patch.set &&
|
|
315
|
+
patch.set.abilities?.includes('tilmeld/admin') !==
|
|
316
|
+
this.$data.abilities?.includes('tilmeld/admin') &&
|
|
317
|
+
(!tilmeld.currentUser ||
|
|
318
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
319
|
+
) {
|
|
320
|
+
throw new BadDataError(
|
|
321
|
+
"You don't have the authority to grant or revoke tilmeld/admin.",
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (
|
|
326
|
+
'abilities' in patch.set &&
|
|
327
|
+
patch.set.abilities?.includes('tilmeld/switch') !==
|
|
328
|
+
this.$data.abilities?.includes('tilmeld/switch') &&
|
|
329
|
+
(!tilmeld.currentUser ||
|
|
330
|
+
!tilmeld.currentUser.abilities?.includes('system/admin'))
|
|
331
|
+
) {
|
|
332
|
+
throw new BadDataError(
|
|
333
|
+
"You don't have the authority to grant or revoke tilmeld/switch.",
|
|
277
334
|
);
|
|
278
335
|
}
|
|
279
336
|
|
|
@@ -291,7 +348,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
291
348
|
* @param givenUser User to update protection for. If undefined, will use the currently logged in user.
|
|
292
349
|
*/
|
|
293
350
|
public $updateDataProtection(givenUser?: User & UserData) {
|
|
294
|
-
const tilmeld = this
|
|
351
|
+
const tilmeld = enforceTilmeld(this);
|
|
295
352
|
let user = givenUser ?? tilmeld.User.current();
|
|
296
353
|
|
|
297
354
|
this.$privateData = [...Group.DEFAULT_PRIVATE_DATA];
|
|
@@ -312,7 +369,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
312
369
|
} else if (
|
|
313
370
|
this.$data.user != null &&
|
|
314
371
|
user != null &&
|
|
315
|
-
this.$data.user
|
|
372
|
+
this.$data.user.guid === user.guid
|
|
316
373
|
) {
|
|
317
374
|
// Users can see their group's data.
|
|
318
375
|
this.$privateData = [];
|
|
@@ -325,11 +382,13 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
325
382
|
* @param group The group, or the group's GUID.
|
|
326
383
|
* @returns True or false.
|
|
327
384
|
*/
|
|
328
|
-
public $isDescendant(
|
|
329
|
-
|
|
385
|
+
public async $isDescendant(
|
|
386
|
+
givenGroup: (Group & GroupData) | string,
|
|
387
|
+
): Promise<boolean> {
|
|
388
|
+
const tilmeld = enforceTilmeld(this);
|
|
330
389
|
let group: Group & GroupData;
|
|
331
390
|
if (typeof givenGroup === 'string') {
|
|
332
|
-
group = tilmeld.Group.
|
|
391
|
+
group = await tilmeld.Group.factory(givenGroup);
|
|
333
392
|
} else {
|
|
334
393
|
group = givenGroup;
|
|
335
394
|
}
|
|
@@ -337,13 +396,15 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
337
396
|
return false;
|
|
338
397
|
}
|
|
339
398
|
// Check to see if the group is a descendant of the given group.
|
|
340
|
-
|
|
399
|
+
const parent = this.$data.parent;
|
|
400
|
+
await parent?.$wake();
|
|
401
|
+
if (parent == null) {
|
|
341
402
|
return false;
|
|
342
403
|
}
|
|
343
|
-
if (
|
|
404
|
+
if (parent.$is(group)) {
|
|
344
405
|
return true;
|
|
345
406
|
}
|
|
346
|
-
if (
|
|
407
|
+
if (await parent.$isDescendant(group)) {
|
|
347
408
|
return true;
|
|
348
409
|
}
|
|
349
410
|
return false;
|
|
@@ -355,14 +416,14 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
355
416
|
* @returns An array of groups.
|
|
356
417
|
*/
|
|
357
418
|
public async $getChildren() {
|
|
358
|
-
const tilmeld = this
|
|
419
|
+
const tilmeld = enforceTilmeld(this);
|
|
359
420
|
return await this.$nymph.getEntities(
|
|
360
421
|
{ class: tilmeld.Group },
|
|
361
422
|
{
|
|
362
423
|
type: '&',
|
|
363
424
|
equal: ['enabled', true],
|
|
364
425
|
ref: ['parent', this],
|
|
365
|
-
}
|
|
426
|
+
},
|
|
366
427
|
);
|
|
367
428
|
}
|
|
368
429
|
|
|
@@ -373,9 +434,9 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
373
434
|
* @returns An array of groups.
|
|
374
435
|
*/
|
|
375
436
|
public async $getDescendants(
|
|
376
|
-
andSelf = false
|
|
437
|
+
andSelf = false,
|
|
377
438
|
): Promise<(Group & GroupData)[]> {
|
|
378
|
-
const tilmeld = this
|
|
439
|
+
const tilmeld = enforceTilmeld(this);
|
|
379
440
|
let groups: (Group & GroupData)[] = [];
|
|
380
441
|
const entities = await this.$nymph.getEntities(
|
|
381
442
|
{ class: tilmeld.Group },
|
|
@@ -383,7 +444,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
383
444
|
type: '&',
|
|
384
445
|
equal: ['enabled', true],
|
|
385
446
|
ref: ['parent', this],
|
|
386
|
-
}
|
|
447
|
+
},
|
|
387
448
|
);
|
|
388
449
|
for (let entity of entities) {
|
|
389
450
|
groups = (await entity.$getDescendants(true)).concat(groups);
|
|
@@ -394,37 +455,6 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
394
455
|
return groups;
|
|
395
456
|
}
|
|
396
457
|
|
|
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
458
|
/**
|
|
429
459
|
* Get the number of parents the group has.
|
|
430
460
|
*
|
|
@@ -436,13 +466,17 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
436
466
|
*
|
|
437
467
|
* @returns The level of the group.
|
|
438
468
|
*/
|
|
439
|
-
public $getLevel() {
|
|
440
|
-
const tilmeld = this
|
|
441
|
-
let group = tilmeld.Group.
|
|
469
|
+
public async $getLevel() {
|
|
470
|
+
const tilmeld = enforceTilmeld(this);
|
|
471
|
+
let group = await tilmeld.Group.factory(this.guid ?? undefined);
|
|
472
|
+
let parent = group.parent;
|
|
473
|
+
await parent?.$wake();
|
|
442
474
|
let level = 0;
|
|
443
|
-
while (
|
|
475
|
+
while (parent != null && parent.cdate != null && level < 1024) {
|
|
444
476
|
level++;
|
|
445
|
-
group =
|
|
477
|
+
group = parent;
|
|
478
|
+
parent = group.parent;
|
|
479
|
+
await parent?.$wake();
|
|
446
480
|
}
|
|
447
481
|
return level;
|
|
448
482
|
}
|
|
@@ -458,9 +492,9 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
458
492
|
public async $getUsers(
|
|
459
493
|
descendants = false,
|
|
460
494
|
limit?: number,
|
|
461
|
-
offset?: number
|
|
495
|
+
offset?: number,
|
|
462
496
|
): Promise<(User & UserData)[]> {
|
|
463
|
-
const tilmeld = this
|
|
497
|
+
const tilmeld = enforceTilmeld(this);
|
|
464
498
|
let groups: (Group & GroupData)[] = [];
|
|
465
499
|
if (descendants) {
|
|
466
500
|
groups = await this.$getDescendants();
|
|
@@ -489,7 +523,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
489
523
|
group,
|
|
490
524
|
]),
|
|
491
525
|
],
|
|
492
|
-
}
|
|
526
|
+
},
|
|
493
527
|
);
|
|
494
528
|
}
|
|
495
529
|
|
|
@@ -502,15 +536,21 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
502
536
|
result: boolean;
|
|
503
537
|
message: string;
|
|
504
538
|
}> {
|
|
505
|
-
const tilmeld = this
|
|
539
|
+
const tilmeld = enforceTilmeld(this);
|
|
506
540
|
if (!tilmeld.config.emailUsernames) {
|
|
507
541
|
if (this.$data.groupname == null || !this.$data.groupname.length) {
|
|
508
542
|
return { result: false, message: 'Please specify a groupname.' };
|
|
509
543
|
}
|
|
510
|
-
if (
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
544
|
+
if (this.$data.groupname.length < tilmeld.config.minUsernameLength) {
|
|
545
|
+
return {
|
|
546
|
+
result: false,
|
|
547
|
+
message:
|
|
548
|
+
'Groupnames must be at least ' +
|
|
549
|
+
tilmeld.config.minUsernameLength +
|
|
550
|
+
' characters.',
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
if (this.$data.groupname.length > tilmeld.config.maxUsernameLength) {
|
|
514
554
|
return {
|
|
515
555
|
result: false,
|
|
516
556
|
message:
|
|
@@ -522,7 +562,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
522
562
|
if (
|
|
523
563
|
difference(
|
|
524
564
|
this.$data.groupname.split(''),
|
|
525
|
-
tilmeld.config.validChars.split('')
|
|
565
|
+
tilmeld.config.validChars.split(''),
|
|
526
566
|
).length
|
|
527
567
|
) {
|
|
528
568
|
return {
|
|
@@ -549,7 +589,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
549
589
|
}
|
|
550
590
|
const test = await this.$nymph.getEntity(
|
|
551
591
|
{ class: tilmeld.Group, skipAc: true },
|
|
552
|
-
selector
|
|
592
|
+
selector,
|
|
553
593
|
);
|
|
554
594
|
if (test != null) {
|
|
555
595
|
return { result: false, message: 'That groupname is taken.' };
|
|
@@ -565,10 +605,16 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
565
605
|
if (this.$data.groupname == null || !this.$data.groupname.length) {
|
|
566
606
|
return { result: false, message: 'Please specify an email.' };
|
|
567
607
|
}
|
|
568
|
-
if (
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
608
|
+
if (this.$data.groupname.length < tilmeld.config.minUsernameLength) {
|
|
609
|
+
return {
|
|
610
|
+
result: false,
|
|
611
|
+
message:
|
|
612
|
+
'Emails must be at least ' +
|
|
613
|
+
tilmeld.config.minUsernameLength +
|
|
614
|
+
' characters.',
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
if (this.$data.groupname.length > tilmeld.config.maxUsernameLength) {
|
|
572
618
|
return {
|
|
573
619
|
result: false,
|
|
574
620
|
message:
|
|
@@ -588,7 +634,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
588
634
|
* @returns An object with a boolean 'result' entry and a 'message' entry.
|
|
589
635
|
*/
|
|
590
636
|
public async $checkEmail(): Promise<{ result: boolean; message: string }> {
|
|
591
|
-
const tilmeld = this
|
|
637
|
+
const tilmeld = enforceTilmeld(this);
|
|
592
638
|
if (this.$data.email === '') {
|
|
593
639
|
return { result: true, message: '' };
|
|
594
640
|
}
|
|
@@ -610,7 +656,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
610
656
|
}
|
|
611
657
|
const test = await this.$nymph.getEntity(
|
|
612
658
|
{ class: tilmeld.Group, skipAc: true },
|
|
613
|
-
selector
|
|
659
|
+
selector,
|
|
614
660
|
);
|
|
615
661
|
if (test != null) {
|
|
616
662
|
return {
|
|
@@ -627,7 +673,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
627
673
|
}
|
|
628
674
|
|
|
629
675
|
public async $save() {
|
|
630
|
-
const tilmeld = this
|
|
676
|
+
const tilmeld = enforceTilmeld(this);
|
|
631
677
|
if (this.$data.groupname == null || !this.$data.groupname.trim().length) {
|
|
632
678
|
return false;
|
|
633
679
|
}
|
|
@@ -671,10 +717,12 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
671
717
|
delete this.$data.unverifiedSecondary;
|
|
672
718
|
}
|
|
673
719
|
|
|
674
|
-
// Groups should never have 'system/admin'
|
|
720
|
+
// Groups should never have 'system/admin', 'tilmeld/admin', or
|
|
721
|
+
// 'tilmeld/switch' abilities.
|
|
675
722
|
this.$data.abilities = difference(this.$data.abilities ?? [], [
|
|
676
723
|
'system/admin',
|
|
677
724
|
'tilmeld/admin',
|
|
725
|
+
'tilmeld/switch',
|
|
678
726
|
null,
|
|
679
727
|
undefined,
|
|
680
728
|
]) as string[];
|
|
@@ -692,14 +740,16 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
692
740
|
}
|
|
693
741
|
|
|
694
742
|
// Validate group parent. Make sure it's not a descendant of this group.
|
|
743
|
+
const parent = this.$data.parent;
|
|
744
|
+
await parent?.$wake();
|
|
695
745
|
if (
|
|
696
|
-
|
|
697
|
-
(
|
|
698
|
-
this.$is(
|
|
699
|
-
|
|
746
|
+
parent &&
|
|
747
|
+
(parent.cdate == null ||
|
|
748
|
+
this.$is(parent) ||
|
|
749
|
+
(await parent.$isDescendant(this)))
|
|
700
750
|
) {
|
|
701
751
|
throw new BadDataError(
|
|
702
|
-
"Group parent can't be itself or descendant of itself."
|
|
752
|
+
"Group parent can't be itself or descendant of itself.",
|
|
703
753
|
);
|
|
704
754
|
}
|
|
705
755
|
|
|
@@ -713,14 +763,14 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
713
763
|
if (this.$data.defaultPrimary) {
|
|
714
764
|
const currentPrimary = await this.$nymph.getEntity(
|
|
715
765
|
{ class: tilmeld.Group },
|
|
716
|
-
{ type: '&', truthy: 'defaultPrimary' }
|
|
766
|
+
{ type: '&', truthy: 'defaultPrimary' },
|
|
717
767
|
);
|
|
718
768
|
if (currentPrimary != null && !this.$is(currentPrimary)) {
|
|
719
769
|
currentPrimary.defaultPrimary = false;
|
|
720
770
|
if (!(await currentPrimary.$save())) {
|
|
721
771
|
throw new CouldNotChangeDefaultPrimaryGroupError(
|
|
722
772
|
'Could not change new user primary group from ' +
|
|
723
|
-
`${currentPrimary.groupname}
|
|
773
|
+
`${currentPrimary.groupname}.`,
|
|
724
774
|
);
|
|
725
775
|
}
|
|
726
776
|
}
|
|
@@ -746,7 +796,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
746
796
|
}
|
|
747
797
|
|
|
748
798
|
public async $delete() {
|
|
749
|
-
let tilmeld = this
|
|
799
|
+
let tilmeld = enforceTilmeld(this);
|
|
750
800
|
if (!tilmeld.gatekeeper('tilmeld/admin')) {
|
|
751
801
|
throw new BadDataError("You don't have the authority to delete groups.");
|
|
752
802
|
}
|
|
@@ -755,7 +805,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
755
805
|
const nymph = this.$nymph;
|
|
756
806
|
const tnymph = await nymph.startTransaction(transaction);
|
|
757
807
|
this.$nymph = tnymph;
|
|
758
|
-
tilmeld = this
|
|
808
|
+
tilmeld = enforceTilmeld(this);
|
|
759
809
|
|
|
760
810
|
// Delete descendants.
|
|
761
811
|
const descendants = await this.$getDescendants();
|
|
@@ -778,7 +828,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
778
828
|
{
|
|
779
829
|
type: '&',
|
|
780
830
|
ref: ['group', this],
|
|
781
|
-
}
|
|
831
|
+
},
|
|
782
832
|
);
|
|
783
833
|
for (let user of primaryUsers) {
|
|
784
834
|
delete user.group;
|
|
@@ -798,7 +848,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
798
848
|
{
|
|
799
849
|
type: '&',
|
|
800
850
|
ref: ['groups', this],
|
|
801
|
-
}
|
|
851
|
+
},
|
|
802
852
|
);
|
|
803
853
|
for (let user of secondaryUsers) {
|
|
804
854
|
user.$delGroup(this);
|