@nymphjs/tilmeld 1.0.0-beta.4 → 1.0.0-beta.41
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 +189 -0
- package/README.md +13 -0
- package/dist/Group.d.ts +4 -7
- package/dist/Group.js +107 -83
- package/dist/Group.js.map +1 -1
- package/dist/Tilmeld.d.ts +10 -9
- package/dist/Tilmeld.js +226 -175
- package/dist/Tilmeld.js.map +1 -1
- package/dist/User.d.ts +66 -13
- package/dist/User.js +421 -128
- package/dist/User.js.map +1 -1
- package/dist/conf/d.d.ts +3 -1
- package/dist/conf/defaults.js +15 -4
- 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 +24 -21
- package/src/Group.ts +140 -102
- package/src/Tilmeld.ts +312 -221
- package/src/User.ts +600 -145
- package/src/conf/d.ts +16 -7
- package/src/conf/defaults.ts +17 -4
- package/src/enforceTilmeld.ts +20 -0
- package/src/index.ts +2 -0
- 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
|
|
|
@@ -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
|
/**
|
|
@@ -167,13 +163,14 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
167
163
|
options?: Options,
|
|
168
164
|
selectors?: Selector[]
|
|
169
165
|
) {
|
|
170
|
-
|
|
166
|
+
const tilmeld = enforceTilmeld(this);
|
|
167
|
+
if (!(await 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:
|
|
172
|
+
tilmeld.config.highestPrimary,
|
|
173
|
+
{ ...options, class: tilmeld.Group, return: 'entity' },
|
|
177
174
|
[...(selectors ?? [])]
|
|
178
175
|
);
|
|
179
176
|
}
|
|
@@ -189,13 +186,14 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
189
186
|
options?: Options,
|
|
190
187
|
selectors?: Selector[]
|
|
191
188
|
) {
|
|
192
|
-
|
|
189
|
+
const tilmeld = enforceTilmeld(this);
|
|
190
|
+
if (!(await 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:
|
|
195
|
+
tilmeld.config.highestSecondary,
|
|
196
|
+
{ ...options, class: tilmeld.Group, return: 'entity' },
|
|
199
197
|
[...(selectors ?? [])]
|
|
200
198
|
);
|
|
201
199
|
}
|
|
@@ -205,6 +203,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
205
203
|
options: Options<typeof Group>,
|
|
206
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:
|
|
214
|
+
{ ...options, class: tilmeld.Group },
|
|
216
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();
|
|
300
|
+
|
|
301
|
+
if (
|
|
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'))
|
|
307
|
+
) {
|
|
308
|
+
throw new BadDataError(
|
|
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
|
+
}
|
|
268
324
|
|
|
269
325
|
if (
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
!tilmeld.
|
|
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'))
|
|
274
331
|
) {
|
|
275
332
|
throw new BadDataError(
|
|
276
|
-
"You don't have the authority to
|
|
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,7 +416,7 @@ 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
|
{
|
|
@@ -375,7 +436,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
375
436
|
public async $getDescendants(
|
|
376
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 },
|
|
@@ -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
|
}
|
|
@@ -460,7 +494,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
460
494
|
limit?: number,
|
|
461
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();
|
|
@@ -502,7 +536,7 @@ 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.' };
|
|
@@ -588,7 +622,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
588
622
|
* @returns An object with a boolean 'result' entry and a 'message' entry.
|
|
589
623
|
*/
|
|
590
624
|
public async $checkEmail(): Promise<{ result: boolean; message: string }> {
|
|
591
|
-
const tilmeld = this
|
|
625
|
+
const tilmeld = enforceTilmeld(this);
|
|
592
626
|
if (this.$data.email === '') {
|
|
593
627
|
return { result: true, message: '' };
|
|
594
628
|
}
|
|
@@ -627,7 +661,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
627
661
|
}
|
|
628
662
|
|
|
629
663
|
public async $save() {
|
|
630
|
-
const tilmeld = this
|
|
664
|
+
const tilmeld = enforceTilmeld(this);
|
|
631
665
|
if (this.$data.groupname == null || !this.$data.groupname.trim().length) {
|
|
632
666
|
return false;
|
|
633
667
|
}
|
|
@@ -671,10 +705,12 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
671
705
|
delete this.$data.unverifiedSecondary;
|
|
672
706
|
}
|
|
673
707
|
|
|
674
|
-
// Groups should never have 'system/admin'
|
|
708
|
+
// Groups should never have 'system/admin', 'tilmeld/admin', or
|
|
709
|
+
// 'tilmeld/switch' abilities.
|
|
675
710
|
this.$data.abilities = difference(this.$data.abilities ?? [], [
|
|
676
711
|
'system/admin',
|
|
677
712
|
'tilmeld/admin',
|
|
713
|
+
'tilmeld/switch',
|
|
678
714
|
null,
|
|
679
715
|
undefined,
|
|
680
716
|
]) as string[];
|
|
@@ -692,11 +728,13 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
692
728
|
}
|
|
693
729
|
|
|
694
730
|
// Validate group parent. Make sure it's not a descendant of this group.
|
|
731
|
+
const parent = this.$data.parent;
|
|
732
|
+
await parent?.$wake();
|
|
695
733
|
if (
|
|
696
|
-
|
|
697
|
-
(
|
|
698
|
-
this.$is(
|
|
699
|
-
|
|
734
|
+
parent &&
|
|
735
|
+
(parent.cdate == null ||
|
|
736
|
+
this.$is(parent) ||
|
|
737
|
+
(await parent.$isDescendant(this)))
|
|
700
738
|
) {
|
|
701
739
|
throw new BadDataError(
|
|
702
740
|
"Group parent can't be itself or descendant of itself."
|
|
@@ -746,8 +784,8 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
746
784
|
}
|
|
747
785
|
|
|
748
786
|
public async $delete() {
|
|
749
|
-
let tilmeld = this
|
|
750
|
-
if (!tilmeld.gatekeeper('tilmeld/admin')) {
|
|
787
|
+
let tilmeld = enforceTilmeld(this);
|
|
788
|
+
if (!(await tilmeld.gatekeeper('tilmeld/admin'))) {
|
|
751
789
|
throw new BadDataError("You don't have the authority to delete groups.");
|
|
752
790
|
}
|
|
753
791
|
|
|
@@ -755,7 +793,7 @@ export default class Group extends AbleObject<GroupData> {
|
|
|
755
793
|
const nymph = this.$nymph;
|
|
756
794
|
const tnymph = await nymph.startTransaction(transaction);
|
|
757
795
|
this.$nymph = tnymph;
|
|
758
|
-
tilmeld = this
|
|
796
|
+
tilmeld = enforceTilmeld(this);
|
|
759
797
|
|
|
760
798
|
// Delete descendants.
|
|
761
799
|
const descendants = await this.$getDescendants();
|