@nymphjs/tilmeld 1.0.0-beta.60 → 1.0.0-beta.62

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/dist/User.js CHANGED
@@ -39,23 +39,6 @@ class User extends AbleObject_1.default {
39
39
  }
40
40
  return entity;
41
41
  }
42
- constructor() {
43
- super();
44
- this.$clientEnabledMethods = [...User.DEFAULT_CLIENT_ENABLED_METHODS];
45
- this.$privateData = [...User.DEFAULT_PRIVATE_DATA];
46
- this.$allowlistData = [...User.DEFAULT_ALLOWLIST_DATA];
47
- this.$allowlistTags = [];
48
- /**
49
- * This is explicitly used only during the registration proccess.
50
- */
51
- this.$skipAcWhenSaving = false;
52
- // Defaults.
53
- this.$data.enabled = true;
54
- this.$data.abilities = [];
55
- this.$data.groups = [];
56
- this.$data.inheritAbilities = true;
57
- this.$updateDataProtection();
58
- }
59
42
  static current(returnObjectIfNotExist) {
60
43
  const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
61
44
  if (tilmeld.currentUser == null) {
@@ -216,6 +199,52 @@ class User extends AbleObject_1.default {
216
199
  }
217
200
  return result;
218
201
  }
202
+ constructor() {
203
+ super();
204
+ this.$clientEnabledMethods = [...User.DEFAULT_CLIENT_ENABLED_METHODS];
205
+ this.$privateData = [...User.DEFAULT_PRIVATE_DATA];
206
+ this.$allowlistData = [...User.DEFAULT_ALLOWLIST_DATA];
207
+ this.$allowlistTags = [];
208
+ /**
209
+ * This should only be used by the backend.
210
+ */
211
+ this.$skipAcWhenSaving = false;
212
+ /**
213
+ * This should only be used by the backend.
214
+ */
215
+ this.$skipAcWhenDeleting = false;
216
+ // Defaults.
217
+ this.$data.enabled = true;
218
+ this.$data.abilities = [];
219
+ this.$data.groups = [];
220
+ this.$data.inheritAbilities = true;
221
+ this.$updateDataProtection();
222
+ }
223
+ $setNymph(nymph) {
224
+ this.$nymph = nymph;
225
+ if (!this.$asleep()) {
226
+ if (this.$data.group && this.$data.group.$nymph !== nymph) {
227
+ this.$data.group.$setNymph(nymph);
228
+ }
229
+ for (const group of this.$data.groups ?? []) {
230
+ if (group && group.$nymph !== nymph) {
231
+ group.$setNymph(nymph);
232
+ }
233
+ }
234
+ }
235
+ }
236
+ async $getUniques() {
237
+ const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
238
+ const uniques = [`u:${this.$data.username}`];
239
+ if (!tilmeld.config.emailUsernames &&
240
+ tilmeld.config.userFields.includes('email')) {
241
+ uniques.push(`e:${this.$data.email}`);
242
+ if (this.$data.newEmailAddress != null) {
243
+ uniques.push(`e:${this.$data.newEmailAddress}`);
244
+ }
245
+ }
246
+ return uniques;
247
+ }
219
248
  async $login(data) {
220
249
  const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
221
250
  if (this.guid == null) {
@@ -1227,7 +1256,7 @@ class User extends AbleObject_1.default {
1227
1256
  const transaction = 'tilmeld-register-' + (0, guid_1.nanoid)();
1228
1257
  const nymph = this.$nymph;
1229
1258
  const tnymph = await this.$nymph.startTransaction(transaction);
1230
- this.$nymph = tnymph;
1259
+ this.$setNymph(tnymph);
1231
1260
  tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
1232
1261
  let message = '';
1233
1262
  let loggedin = false;
@@ -1242,71 +1271,13 @@ class User extends AbleObject_1.default {
1242
1271
  }
1243
1272
  catch (e) {
1244
1273
  await tnymph.rollback(transaction);
1245
- this.$nymph = nymph;
1274
+ this.$setNymph(nymph);
1246
1275
  return {
1247
1276
  result: false,
1248
1277
  loggedin: false,
1249
1278
  message: e.message,
1250
1279
  };
1251
1280
  }
1252
- // Add primary group.
1253
- let generatedPrimaryGroup = null;
1254
- if (tilmeld.config.generatePrimary) {
1255
- // Generate a new primary group for the user.
1256
- generatedPrimaryGroup = await tilmeld.Group.factory();
1257
- generatedPrimaryGroup.groupname = this.$data.username;
1258
- generatedPrimaryGroup.avatar = this.$data.avatar;
1259
- if (tilmeld.config.userFields.includes('name')) {
1260
- generatedPrimaryGroup.name = this.$data.name;
1261
- }
1262
- if (tilmeld.config.userFields.includes('email')) {
1263
- generatedPrimaryGroup.email = this.$data.email;
1264
- }
1265
- const parent = await tnymph.getEntity({ class: tilmeld.Group }, {
1266
- type: '&',
1267
- equal: ['defaultPrimary', true],
1268
- });
1269
- if (parent != null) {
1270
- generatedPrimaryGroup.parent = parent;
1271
- }
1272
- if (!(await generatedPrimaryGroup.$saveSkipAC())) {
1273
- await tnymph.rollback(transaction);
1274
- this.$nymph = nymph;
1275
- return {
1276
- result: false,
1277
- loggedin: false,
1278
- message: 'Error creating primary group for user.',
1279
- };
1280
- }
1281
- this.$data.group = generatedPrimaryGroup;
1282
- }
1283
- else {
1284
- // Add the default primary.
1285
- const group = await tnymph.getEntity({ class: tilmeld.Group }, {
1286
- type: '&',
1287
- equal: ['defaultPrimary', true],
1288
- });
1289
- if (group != null) {
1290
- this.$data.group = group;
1291
- }
1292
- }
1293
- // Add secondary groups.
1294
- if (tilmeld.config.userFields.includes('email') &&
1295
- tilmeld.config.verifyEmail &&
1296
- tilmeld.config.unverifiedAccess) {
1297
- // Add the default secondaries for unverified users.
1298
- this.$data.groups = await tnymph.getEntities({ class: tilmeld.Group }, {
1299
- type: '&',
1300
- equal: ['unverifiedSecondary', true],
1301
- });
1302
- }
1303
- else {
1304
- // Add the default secondaries.
1305
- this.$data.groups = await tnymph.getEntities({ class: tilmeld.Group }, {
1306
- type: '&',
1307
- equal: ['defaultSecondary', true],
1308
- });
1309
- }
1310
1281
  if (tilmeld.config.userFields.includes('email') &&
1311
1282
  tilmeld.config.verifyEmail) {
1312
1283
  // The user will be enabled after verifying their e-mail address.
@@ -1317,7 +1288,7 @@ class User extends AbleObject_1.default {
1317
1288
  else {
1318
1289
  this.$data.enabled = true;
1319
1290
  }
1320
- // If create_admin is true and there are no other users, grant
1291
+ // If createAdmin is true and there are no other users, grant
1321
1292
  // "system/admin".
1322
1293
  let madeAdmin = false;
1323
1294
  if (tilmeld.config.createAdmin) {
@@ -1354,19 +1325,6 @@ class User extends AbleObject_1.default {
1354
1325
  },
1355
1326
  }, this);
1356
1327
  }
1357
- // Save the primary group.
1358
- if (generatedPrimaryGroup != null) {
1359
- generatedPrimaryGroup.user = this;
1360
- if (!(await generatedPrimaryGroup.$saveSkipAC())) {
1361
- await tnymph.rollback(transaction);
1362
- this.$nymph = nymph;
1363
- return {
1364
- result: false,
1365
- loggedin: false,
1366
- message: 'Your primary group could not be assigned. Please try again later.',
1367
- };
1368
- }
1369
- }
1370
1328
  // Finish up.
1371
1329
  if (tilmeld.config.verifyEmail &&
1372
1330
  !tilmeld.config.unverifiedAccess &&
@@ -1409,7 +1367,7 @@ class User extends AbleObject_1.default {
1409
1367
  else {
1410
1368
  this.$nymph.config.debugError('tilmeld', `Error registering new user "${this.$data.username}".`);
1411
1369
  await tnymph.rollback(transaction);
1412
- this.$nymph = nymph;
1370
+ this.$setNymph(nymph);
1413
1371
  return {
1414
1372
  result: false,
1415
1373
  loggedin: false,
@@ -1420,12 +1378,12 @@ class User extends AbleObject_1.default {
1420
1378
  catch (e) {
1421
1379
  this.$nymph.config.debugError('tilmeld', `Error registering new user "${this.$data.username}": ${e}`);
1422
1380
  await tnymph.rollback(transaction);
1423
- this.$nymph = nymph;
1381
+ this.$setNymph(nymph);
1424
1382
  throw e;
1425
1383
  }
1426
1384
  try {
1427
1385
  await tnymph.commit(transaction);
1428
- this.$nymph = nymph;
1386
+ this.$setNymph(nymph);
1429
1387
  await this.$nymph.tilmeld?.fillSession(this);
1430
1388
  }
1431
1389
  catch (e) {
@@ -1442,7 +1400,8 @@ class User extends AbleObject_1.default {
1442
1400
  if (this.$data.username == null || !this.$data.username.trim().length) {
1443
1401
  return false;
1444
1402
  }
1445
- if (tilmeld.gatekeeper('tilmeld/admin') &&
1403
+ if (!this.$skipAcWhenSaving &&
1404
+ tilmeld.gatekeeper('tilmeld/admin') &&
1446
1405
  !tilmeld.gatekeeper('system/admin') &&
1447
1406
  this.$data.abilities?.includes('system/admin')) {
1448
1407
  throw new errors_1.BadDataError("You don't have the authority to modify system admins.");
@@ -1615,53 +1574,133 @@ class User extends AbleObject_1.default {
1615
1574
  if (this.$data.password == null) {
1616
1575
  throw new errors_1.BadDataError('A password is required.');
1617
1576
  }
1618
- try {
1619
- tilmeld.config.validatorUser(tilmeld, this);
1620
- }
1621
- catch (e) {
1622
- throw new errors_1.BadDataError(e?.message);
1623
- }
1624
1577
  // Start transaction.
1625
1578
  const transaction = 'tilmeld-save-' + (0, guid_1.nanoid)();
1626
1579
  const nymph = this.$nymph;
1627
1580
  const tnymph = await this.$nymph.startTransaction(transaction);
1628
- this.$nymph = tnymph;
1581
+ this.$setNymph(tnymph);
1629
1582
  tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
1630
- const group = this.$data.group;
1631
- await group?.$wake();
1632
- if (group != null && group.user != null && this.$is(group.user)) {
1633
- try {
1583
+ // If the primary group is generated now, the user assigned to it won't have
1584
+ // a guid yet, so it needs to be assigned after the user is saved.
1585
+ let saveGeneratedPrimaryGroupAgain = false;
1586
+ try {
1587
+ let group = this.$data.group;
1588
+ await group?.$wake();
1589
+ if (group == null && this.guid == null) {
1590
+ if (tilmeld.config.generatePrimary) {
1591
+ // Generate a new primary group for the user.
1592
+ group = await tilmeld.Group.factory();
1593
+ // This user doesn't have a guid yet, so that's why we set
1594
+ // saveGeneratedPrimaryGroupAgain.
1595
+ group.user = this;
1596
+ saveGeneratedPrimaryGroupAgain = true;
1597
+ const parent = await tnymph.getEntity({ class: tilmeld.Group }, {
1598
+ type: '&',
1599
+ equal: ['defaultPrimary', true],
1600
+ });
1601
+ if (parent != null) {
1602
+ group.parent = parent;
1603
+ }
1604
+ }
1605
+ else {
1606
+ // Add the default primary.
1607
+ const group = await tnymph.getEntity({ class: tilmeld.Group }, {
1608
+ type: '&',
1609
+ equal: ['defaultPrimary', true],
1610
+ });
1611
+ if (group != null) {
1612
+ this.$data.group = group;
1613
+ }
1614
+ }
1615
+ }
1616
+ if (group != null && group.user != null && this.$is(group.user)) {
1634
1617
  // Update the user's generated primary group.
1635
- group.groupname = this.$data.username;
1636
- group.avatar = this.$data.avatar;
1637
- if (tilmeld.config.userFields.includes('email')) {
1618
+ let changed = false;
1619
+ if (group.groupname !== this.$data.username) {
1620
+ group.groupname = this.$data.username;
1621
+ changed = true;
1622
+ }
1623
+ if (group.avatar !== this.$data.avatar) {
1624
+ group.avatar = this.$data.avatar;
1625
+ changed = true;
1626
+ }
1627
+ if (tilmeld.config.userFields.includes('email') &&
1628
+ group.email !== this.$data.email) {
1638
1629
  group.email = this.$data.email;
1630
+ changed = true;
1639
1631
  }
1640
- if (tilmeld.config.userFields.includes('name')) {
1632
+ if (tilmeld.config.userFields.includes('name') &&
1633
+ group.name !== this.$data.name) {
1641
1634
  group.name = this.$data.name;
1635
+ changed = true;
1642
1636
  }
1643
- if (tilmeld.config.userFields.includes('phone')) {
1637
+ if (tilmeld.config.userFields.includes('phone') &&
1638
+ group.phone !== this.$data.phone) {
1644
1639
  group.phone = this.$data.phone;
1640
+ changed = true;
1641
+ }
1642
+ if (changed) {
1643
+ if (!(await group.$saveSkipAC())) {
1644
+ throw Error('Error updating primary group for user.');
1645
+ }
1645
1646
  }
1646
- await group.$saveSkipAC();
1647
1647
  this.$data.group = group;
1648
1648
  }
1649
+ if (this.$data.groups == null || this.$data.groups.length === 0) {
1650
+ // Add secondary groups.
1651
+ if (tilmeld.config.userFields.includes('email') &&
1652
+ tilmeld.config.verifyEmail &&
1653
+ tilmeld.config.unverifiedAccess &&
1654
+ this.$data.secret != null) {
1655
+ // Add the default secondaries for unverified users.
1656
+ this.$data.groups = await tnymph.getEntities({ class: tilmeld.Group }, {
1657
+ type: '&',
1658
+ equal: ['unverifiedSecondary', true],
1659
+ });
1660
+ }
1661
+ else {
1662
+ // Add the default secondaries.
1663
+ this.$data.groups = await tnymph.getEntities({ class: tilmeld.Group }, {
1664
+ type: '&',
1665
+ equal: ['defaultSecondary', true],
1666
+ });
1667
+ }
1668
+ }
1669
+ try {
1670
+ tilmeld.config.validatorUser(tilmeld, this);
1671
+ }
1649
1672
  catch (e) {
1650
- await tnymph.rollback(transaction);
1651
- this.$nymph = nymph;
1652
- throw e;
1673
+ throw new errors_1.BadDataError(e?.message);
1653
1674
  }
1654
1675
  }
1676
+ catch (e) {
1677
+ await tnymph.rollback(transaction);
1678
+ this.$setNymph(nymph);
1679
+ throw e;
1680
+ }
1655
1681
  let ret;
1656
1682
  let preGuid = this.guid;
1657
1683
  let preCdate = this.cdate;
1658
1684
  let preMdate = this.mdate;
1659
1685
  try {
1660
1686
  ret = await super.$save();
1687
+ if (ret && saveGeneratedPrimaryGroupAgain) {
1688
+ const group = this.$data.group;
1689
+ if (group == null) {
1690
+ throw Error('Generated primary group not found.');
1691
+ }
1692
+ await group.$wake();
1693
+ // Now this user has a GUID, so saving it on the group will succeed.
1694
+ group.user = this;
1695
+ if (!(await group.$saveSkipAC())) {
1696
+ throw Error("Generated primary group couldn't be saved.");
1697
+ }
1698
+ this.$data.group = group;
1699
+ }
1661
1700
  }
1662
1701
  catch (e) {
1663
1702
  await tnymph.rollback(transaction);
1664
- this.$nymph = nymph;
1703
+ this.$setNymph(nymph);
1665
1704
  throw e;
1666
1705
  }
1667
1706
  if (ret) {
@@ -1672,7 +1711,7 @@ class User extends AbleObject_1.default {
1672
1711
  this.guid = preGuid;
1673
1712
  this.cdate = preCdate;
1674
1713
  this.mdate = preMdate;
1675
- this.$nymph = nymph;
1714
+ this.$setNymph(nymph);
1676
1715
  throw new Error("Couldn't send verification email.");
1677
1716
  }
1678
1717
  }
@@ -1688,7 +1727,7 @@ class User extends AbleObject_1.default {
1688
1727
  else {
1689
1728
  await tnymph.rollback(transaction);
1690
1729
  }
1691
- this.$nymph = nymph;
1730
+ this.$setNymph(nymph);
1692
1731
  return ret;
1693
1732
  }
1694
1733
  /**
@@ -1707,10 +1746,11 @@ class User extends AbleObject_1.default {
1707
1746
  }
1708
1747
  async $delete() {
1709
1748
  const tilmeld = (0, enforceTilmeld_1.enforceTilmeld)(this);
1710
- if (!tilmeld.gatekeeper('tilmeld/admin')) {
1749
+ if (!this.$skipAcWhenDeleting && !tilmeld.gatekeeper('tilmeld/admin')) {
1711
1750
  throw new errors_1.BadDataError("You don't have the authority to delete users.");
1712
1751
  }
1713
- if (!tilmeld.gatekeeper('system/admin') &&
1752
+ if (!this.$skipAcWhenDeleting &&
1753
+ !tilmeld.gatekeeper('system/admin') &&
1714
1754
  this.$data.abilities?.includes('system/admin')) {
1715
1755
  throw new errors_1.BadDataError("You don't have the authority to delete system admins.");
1716
1756
  }
@@ -1719,6 +1759,20 @@ class User extends AbleObject_1.default {
1719
1759
  }
1720
1760
  return await super.$delete();
1721
1761
  }
1762
+ /*
1763
+ * This should *never* be accessible on the client.
1764
+ */
1765
+ async $deleteSkipAC() {
1766
+ this.$skipAcWhenDeleting = true;
1767
+ return await this.$delete();
1768
+ }
1769
+ $tilmeldDeleteSkipAC() {
1770
+ if (this.$skipAcWhenDeleting) {
1771
+ this.$skipAcWhenDeleting = false;
1772
+ return true;
1773
+ }
1774
+ return false;
1775
+ }
1722
1776
  static on(event, callback) {
1723
1777
  const prop = (event + 'Callbacks');
1724
1778
  if (!(prop in this)) {