@nymphjs/tilmeld 1.0.0-beta.131 → 1.0.0-beta.133

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/src/User.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import crypto from 'node:crypto';
2
2
  import {
3
- type EntityData,
4
3
  type EntityJson,
5
4
  type EntityPatch,
6
5
  type Selector,
@@ -17,9 +16,8 @@ import { toDataURL } from 'qrcode';
17
16
  import { splitn } from '@sciactive/splitn';
18
17
 
19
18
  import { enforceTilmeld } from './enforceTilmeld.js';
20
- import AbleObject from './AbleObject.js';
21
- import GroupClass from './Group.js';
22
- import type { GroupData } from './Group.js';
19
+ import { AbleObject } from './AbleObject.js';
20
+ import { Group as GroupClass } from './Group.js';
23
21
  import {
24
22
  AccessControlError,
25
23
  BadDataError,
@@ -46,7 +44,7 @@ export type EventType =
46
44
  * process and return the included message, disallowing the username.
47
45
  */
48
46
  export type TilmeldCheckUsernameCallback = (
49
- user: User & UserData,
47
+ user: User,
50
48
  data: { username: string },
51
49
  ) => Promise<{ result: boolean; message?: string }>;
52
50
  /**
@@ -54,7 +52,7 @@ export type TilmeldCheckUsernameCallback = (
54
52
  * whether registration is allowed and whether the user is already registered.
55
53
  */
56
54
  export type TilmeldBeforeRegisterCallback = (
57
- user: User & UserData,
55
+ user: User,
58
56
  data: { password: string; additionalData?: { [k: string]: any } },
59
57
  ) => Promise<void>;
60
58
  /**
@@ -62,7 +60,7 @@ export type TilmeldBeforeRegisterCallback = (
62
60
  * additional functions on the transaction, which is available in `user.$nymph`.
63
61
  */
64
62
  export type TilmeldAfterRegisterCallback = (
65
- user: User & UserData,
63
+ user: User,
66
64
  result: { loggedin: boolean; message: string },
67
65
  ) => Promise<void>;
68
66
  /**
@@ -70,9 +68,7 @@ export type TilmeldAfterRegisterCallback = (
70
68
  *
71
69
  * The transaction is available in `user.$nymph`.
72
70
  */
73
- export type TilmeldBeforeSaveCallback = (
74
- user: User & UserData,
75
- ) => Promise<void>;
71
+ export type TilmeldBeforeSaveCallback = (user: User) => Promise<void>;
76
72
  /**
77
73
  * This is run before the transaction is committed, and you can perform
78
74
  * additional functions on the transaction, which is available in `user.$nymph`.
@@ -80,45 +76,35 @@ export type TilmeldBeforeSaveCallback = (
80
76
  * This is run after a new email verification email has been sent, so throwing
81
77
  * an error will cause confusion for the user if they've changed their email.
82
78
  */
83
- export type TilmeldAfterSaveCallback = (user: User & UserData) => Promise<void>;
79
+ export type TilmeldAfterSaveCallback = (user: User) => Promise<void>;
84
80
  /**
85
81
  * This is run after the authentication checks, but before the login action.
86
82
  */
87
83
  export type TilmeldBeforeLoginCallback = (
88
- user: User & UserData,
84
+ user: User,
89
85
  data: {
90
86
  username: string;
91
87
  password: string;
92
88
  additionalData?: { [k: string]: any };
93
89
  },
94
90
  ) => Promise<void>;
95
- export type TilmeldAfterLoginCallback = (
96
- user: User & UserData,
97
- ) => Promise<void>;
98
- export type TilmeldBeforeLogoutCallback = (
99
- user: User & UserData,
100
- ) => Promise<void>;
101
- export type TilmeldAfterLogoutCallback = (
102
- user: User & UserData,
103
- ) => Promise<void>;
91
+ export type TilmeldAfterLoginCallback = (user: User) => Promise<void>;
92
+ export type TilmeldBeforeLogoutCallback = (user: User) => Promise<void>;
93
+ export type TilmeldAfterLogoutCallback = (user: User) => Promise<void>;
104
94
  /**
105
95
  * This is run before the user is logged out (if the current user is being
106
96
  * deleted).
107
97
  *
108
98
  * The transaction is available in `user.$nymph`.
109
99
  */
110
- export type TilmeldBeforeDeleteCallback = (
111
- user: User & UserData,
112
- ) => Promise<void>;
100
+ export type TilmeldBeforeDeleteCallback = (user: User) => Promise<void>;
113
101
  /**
114
102
  * This is run before the transaction is committed, and you can perform
115
103
  * additional functions on the transaction, which is available in `user.$nymph`.
116
104
  */
117
- export type TilmeldAfterDeleteCallback = (
118
- user: User & UserData,
119
- ) => Promise<void>;
105
+ export type TilmeldAfterDeleteCallback = (user: User) => Promise<void>;
120
106
 
121
- export type UserData = {
107
+ export interface UserData {
122
108
  /**
123
109
  * The abilities granted to the user.
124
110
  */
@@ -159,11 +145,11 @@ export type UserData = {
159
145
  /**
160
146
  * The user's primary group.
161
147
  */
162
- group?: GroupClass & GroupData;
148
+ group?: GroupClass;
163
149
  /**
164
150
  * The user's secondary groups.
165
151
  */
166
- groups?: (GroupClass & GroupData)[];
152
+ groups?: GroupClass[];
167
153
  /**
168
154
  * Whether the user should inherit the abilities of his groups.
169
155
  */
@@ -228,7 +214,9 @@ export type UserData = {
228
214
  * Two factor auth secret.
229
215
  */
230
216
  totpSecret?: string;
231
- };
217
+ }
218
+
219
+ export interface User extends UserData {}
232
220
 
233
221
  /**
234
222
  * A user data model.
@@ -239,7 +227,7 @@ export type UserData = {
239
227
  * @copyright SciActive Inc
240
228
  * @see http://nymph.io/
241
229
  */
242
- export default class User extends AbleObject<UserData> {
230
+ export class User extends AbleObject<UserData> {
243
231
  static ETYPE = 'tilmeld_user';
244
232
  static class = 'User';
245
233
  private static checkUsernameCallbacks: TilmeldCheckUsernameCallback[] = [];
@@ -324,7 +312,7 @@ export default class User extends AbleObject<UserData> {
324
312
  /**
325
313
  * The user's group descendants.
326
314
  */
327
- private $descendantGroups?: (GroupClass & GroupData)[];
315
+ private $descendantGroups?: GroupClass[];
328
316
  /**
329
317
  * Used to save the current email address to send verification if it changes
330
318
  * from the frontend.
@@ -366,7 +354,7 @@ export default class User extends AbleObject<UserData> {
366
354
  return super.getFTSText(name, value);
367
355
  }
368
356
 
369
- static async factoryUsername(username?: string): Promise<User & UserData> {
357
+ static async factoryUsername(username?: string): Promise<User> {
370
358
  const entity = new this();
371
359
  if (username != null) {
372
360
  const entity = await this.nymph.getEntity(
@@ -383,13 +371,9 @@ export default class User extends AbleObject<UserData> {
383
371
  return entity;
384
372
  }
385
373
 
386
- public static current(returnObjectIfNotExist: true): User & UserData;
387
- public static current(
388
- returnObjectIfNotExist?: false,
389
- ): (User & UserData) | null;
390
- public static current(
391
- returnObjectIfNotExist?: boolean,
392
- ): (User & UserData) | null {
374
+ public static current(returnObjectIfNotExist: true): User;
375
+ public static current(returnObjectIfNotExist?: false): User | null;
376
+ public static current(returnObjectIfNotExist?: boolean): User | null {
393
377
  const tilmeld = enforceTilmeld(this);
394
378
  if (tilmeld.currentUser == null) {
395
379
  return returnObjectIfNotExist ? this.factorySync() : null;
@@ -412,7 +396,7 @@ export default class User extends AbleObject<UserData> {
412
396
  return { result: false, message: 'Account recovery is not allowed.' };
413
397
  }
414
398
 
415
- let user: User & UserData;
399
+ let user: User;
416
400
  const options: EmailOptions = {};
417
401
 
418
402
  if (!tilmeld.config.emailUsernames && data.recoveryType === 'username') {
@@ -575,7 +559,7 @@ export default class User extends AbleObject<UserData> {
575
559
  return { result: false, message: 'Incorrect login/password.' };
576
560
  }
577
561
  const user = await tilmeld.User.factoryUsername(data.username);
578
- const result: { result: boolean; message: string; user?: User & UserData } =
562
+ const result: { result: boolean; message: string; user?: User } =
579
563
  await user.$login(data);
580
564
  if (result.result) {
581
565
  user.$updateDataProtection();
@@ -636,24 +620,24 @@ export default class User extends AbleObject<UserData> {
636
620
  super();
637
621
 
638
622
  // Defaults.
639
- this.$data.enabled = true;
640
- this.$data.abilities = [];
641
- this.$data.groups = [];
642
- this.$data.inheritAbilities = true;
623
+ this.enabled = true;
624
+ this.abilities = [];
625
+ this.groups = [];
626
+ this.inheritAbilities = true;
643
627
  this.$updateDataProtection();
644
628
  }
645
629
 
646
630
  async $getUniques(): Promise<string[]> {
647
631
  const tilmeld = enforceTilmeld(this);
648
- const uniques = [`u:${this.$data.username}`];
632
+ const uniques = [`u:${this.username}`];
649
633
  if (
650
634
  !tilmeld.config.emailUsernames &&
651
635
  tilmeld.config.userFields.includes('email')
652
636
  ) {
653
- uniques.push(`e:${this.$data.email}`);
637
+ uniques.push(`e:${this.email}`);
654
638
 
655
- if (this.$data.newEmailAddress != null) {
656
- uniques.push(`e:${this.$data.newEmailAddress}`);
639
+ if (this.newEmailAddress != null) {
640
+ uniques.push(`e:${this.newEmailAddress}`);
657
641
  }
658
642
  }
659
643
  return uniques;
@@ -674,14 +658,14 @@ export default class User extends AbleObject<UserData> {
674
658
  await tilmeld.config.failedLoginAttempt(this, data);
675
659
  return { result: false, message: 'Incorrect login/password.' };
676
660
  }
677
- if (!this.$data.enabled) {
661
+ if (!this.enabled) {
678
662
  return { result: false, message: 'Your account is disabled.' };
679
663
  }
680
664
  if (await this.$gatekeeper()) {
681
665
  return { result: true, message: 'You are already logged in.' };
682
666
  }
683
667
 
684
- if (this.$data.totpSecret != null) {
668
+ if (this.totpSecret != null) {
685
669
  if (
686
670
  data.code == null ||
687
671
  typeof data.code !== 'string' ||
@@ -713,7 +697,7 @@ export default class User extends AbleObject<UserData> {
713
697
 
714
698
  this.$nymph.config.debugLog(
715
699
  'tilmeld',
716
- `User login for "${this.$data.username}".`,
700
+ `User login for "${this.username}".`,
717
701
  );
718
702
 
719
703
  // Authentication was successful, attempt to login.
@@ -724,7 +708,7 @@ export default class User extends AbleObject<UserData> {
724
708
  for (let callback of (this.constructor as typeof User)
725
709
  .afterLoginCallbacks) {
726
710
  if (callback) {
727
- await callback(this.$proxy());
711
+ await callback(this);
728
712
  }
729
713
  }
730
714
 
@@ -752,7 +736,7 @@ export default class User extends AbleObject<UserData> {
752
736
  return { result: false, message: "You can't switch to yourself." };
753
737
  }
754
738
 
755
- const toAbilities = this.$data.abilities || [];
739
+ const toAbilities = this.abilities || [];
756
740
  const fromAbilities = user.abilities || [];
757
741
 
758
742
  if (
@@ -777,7 +761,7 @@ export default class User extends AbleObject<UserData> {
777
761
  .beforeLoginCallbacks) {
778
762
  if (callback) {
779
763
  await callback(this, {
780
- username: this.$data.username || '',
764
+ username: this.username || '',
781
765
  password: '',
782
766
  ...(data || {}),
783
767
  });
@@ -789,7 +773,7 @@ export default class User extends AbleObject<UserData> {
789
773
 
790
774
  this.$nymph.config.debugLog(
791
775
  'tilmeld',
792
- `User login switch for "${user.username}" to "${this.$data.username}".`,
776
+ `User login switch for "${user.username}" to "${this.username}".`,
793
777
  );
794
778
 
795
779
  // Authentication was successful, attempt to login.
@@ -800,7 +784,7 @@ export default class User extends AbleObject<UserData> {
800
784
  for (let callback of (this.constructor as typeof User)
801
785
  .afterLoginCallbacks) {
802
786
  if (callback) {
803
- await callback(this.$proxy());
787
+ await callback(this);
804
788
  }
805
789
  }
806
790
 
@@ -819,7 +803,7 @@ export default class User extends AbleObject<UserData> {
819
803
  for (let callback of (this.constructor as typeof User)
820
804
  .beforeLogoutCallbacks) {
821
805
  if (callback) {
822
- await callback(this.$proxy());
806
+ await callback(this);
823
807
  }
824
808
  }
825
809
  } catch (e: any) {
@@ -828,7 +812,7 @@ export default class User extends AbleObject<UserData> {
828
812
 
829
813
  this.$nymph.config.debugLog(
830
814
  'tilmeld',
831
- `User logout for "${this.$data.username}".`,
815
+ `User logout for "${this.username}".`,
832
816
  );
833
817
 
834
818
  await tilmeld.logout();
@@ -836,7 +820,7 @@ export default class User extends AbleObject<UserData> {
836
820
  for (let callback of (this.constructor as typeof User)
837
821
  .afterLogoutCallbacks) {
838
822
  if (callback) {
839
- await callback(this.$proxy());
823
+ await callback(this);
840
824
  }
841
825
  }
842
826
 
@@ -844,17 +828,17 @@ export default class User extends AbleObject<UserData> {
844
828
  }
845
829
 
846
830
  public $getAvatar(): string {
847
- if (this.$data.avatar != null && this.$data.avatar !== '') {
848
- return this.$data.avatar;
831
+ if (this.avatar != null && this.avatar !== '') {
832
+ return this.avatar;
849
833
  }
850
- if (this.$data.email == null || this.$data.email === '') {
834
+ if (this.email == null || this.email === '') {
851
835
  return 'https://secure.gravatar.com/avatar/?d=mm&s=40';
852
836
  }
853
837
  return (
854
838
  'https://secure.gravatar.com/avatar/' +
855
839
  crypto
856
840
  .createHash('sha256')
857
- .update(this.$data.email.trim().toLowerCase())
841
+ .update(this.email.trim().toLowerCase())
858
842
  .digest('hex')
859
843
  .toLowerCase() +
860
844
  '?d=identicon&s=40'
@@ -862,15 +846,15 @@ export default class User extends AbleObject<UserData> {
862
846
  }
863
847
 
864
848
  public $getGid() {
865
- if (this.$data.group) {
866
- return this.$data.group.guid;
849
+ if (this.group) {
850
+ return this.group.guid;
867
851
  }
868
852
  return null;
869
853
  }
870
854
 
871
855
  public $getGids() {
872
- if (this.$data.groups) {
873
- return this.$data.groups
856
+ if (this.groups) {
857
+ return this.groups
874
858
  .map((group) => group.guid)
875
859
  .filter((guid) => guid != null) as string[];
876
860
  }
@@ -880,15 +864,15 @@ export default class User extends AbleObject<UserData> {
880
864
  /**
881
865
  * Get the user's group descendants.
882
866
  */
883
- public async $getDescendantGroups(): Promise<(GroupClass & GroupData)[]> {
867
+ public async $getDescendantGroups(): Promise<GroupClass[]> {
884
868
  if (this.$descendantGroups == null) {
885
869
  this.$descendantGroups = [];
886
- if (this.$data.group != null) {
887
- await this.$data.group.$wake();
888
- this.$descendantGroups = await this.$data.group.$getDescendants();
870
+ if (this.group != null) {
871
+ await this.group.$wake();
872
+ this.$descendantGroups = await this.group.$getDescendants();
889
873
  }
890
- await Promise.all(this.$data.groups?.map((e) => e.$wake()) || []);
891
- for (let curGroup of this.$data.groups ?? []) {
874
+ await Promise.all(this.groups?.map((e) => e.$wake()) || []);
875
+ for (let curGroup of this.groups ?? []) {
892
876
  this.$descendantGroups = this.$descendantGroups?.concat(
893
877
  await curGroup.$getDescendants(),
894
878
  );
@@ -920,9 +904,8 @@ export default class User extends AbleObject<UserData> {
920
904
  // While loading, accessing abilities on the current user will infinitely
921
905
  // loop, but if this is the current user, we can use its abilities.
922
906
  const abilities =
923
- (isCurrentUser || user == null
924
- ? this.$data.abilities
925
- : user?.abilities) ?? [];
907
+ (isCurrentUser || user == null ? this.abilities : user?.abilities) ??
908
+ [];
926
909
  const isNewUser = input.guid == null;
927
910
  const isDomainUser =
928
911
  !isCurrentUser &&
@@ -964,7 +947,7 @@ export default class User extends AbleObject<UserData> {
964
947
 
965
948
  if (
966
949
  incoming.includes('system/admin') !==
967
- this.$data.abilities?.includes('system/admin') &&
950
+ this.abilities?.includes('system/admin') &&
968
951
  (!tilmeld.currentUser ||
969
952
  !tilmeld.currentUser.abilities?.includes('system/admin'))
970
953
  ) {
@@ -975,7 +958,7 @@ export default class User extends AbleObject<UserData> {
975
958
 
976
959
  if (
977
960
  incoming.includes('tilmeld/admin') !==
978
- this.$data.abilities?.includes('tilmeld/admin') &&
961
+ this.abilities?.includes('tilmeld/admin') &&
979
962
  (!tilmeld.currentUser ||
980
963
  !tilmeld.currentUser.abilities?.includes('system/admin'))
981
964
  ) {
@@ -986,7 +969,7 @@ export default class User extends AbleObject<UserData> {
986
969
 
987
970
  if (
988
971
  incoming.includes('tilmeld/switch') !==
989
- this.$data.abilities?.includes('tilmeld/switch') &&
972
+ this.abilities?.includes('tilmeld/switch') &&
990
973
  (!tilmeld.currentUser ||
991
974
  !tilmeld.currentUser.abilities?.includes('system/admin'))
992
975
  ) {
@@ -998,7 +981,7 @@ export default class User extends AbleObject<UserData> {
998
981
  if (
999
982
  xor(
1000
983
  incoming.filter((ability: string) => ability.startsWith('tilmeld/')),
1001
- this.$data.abilities?.filter((ability: string) =>
984
+ this.abilities?.filter((ability: string) =>
1002
985
  ability.startsWith('tilmeld/'),
1003
986
  ) ?? [],
1004
987
  ).length &&
@@ -1013,21 +996,21 @@ export default class User extends AbleObject<UserData> {
1013
996
  }
1014
997
 
1015
998
  public $putData(
1016
- data: EntityData,
999
+ data: UserData,
1017
1000
  sdata?: SerializedEntityData,
1018
1001
  source?: 'server',
1019
1002
  ) {
1020
1003
  super.$putData(data, sdata, source);
1021
1004
  // TODO: Fix these being added by the drivers.
1022
1005
  // @ts-ignore
1023
- delete this.$data.acRead;
1006
+ delete this.acRead;
1024
1007
  // @ts-ignore
1025
- delete this.$data.acWrite;
1008
+ delete this.acWrite;
1026
1009
  // @ts-ignore
1027
- delete this.$data.acFull;
1010
+ delete this.acFull;
1028
1011
  if (source === 'server') {
1029
- this.$originalEmail = this.$data.email;
1030
- this.$originalUsername = this.$data.username;
1012
+ this.$originalEmail = this.email;
1013
+ this.$originalUsername = this.username;
1031
1014
  }
1032
1015
  this.$updateDataProtection();
1033
1016
  }
@@ -1037,12 +1020,12 @@ export default class User extends AbleObject<UserData> {
1037
1020
  *
1038
1021
  * @param givenUser User to update protection for. If undefined, will use the currently logged in user.
1039
1022
  */
1040
- public $updateDataProtection(givenUser?: User & UserData) {
1023
+ public $updateDataProtection(givenUser?: User) {
1041
1024
  const tilmeld = enforceTilmeld(this);
1042
1025
  let user = givenUser ?? tilmeld.User.current();
1043
1026
  let [_username, domain] = tilmeld.config.domainSupport
1044
- ? splitn(this.$originalUsername ?? this.$data.username ?? '', '@', 2)
1045
- : [this.$originalUsername ?? this.$data.username, null];
1027
+ ? splitn(this.$originalUsername ?? this.username ?? '', '@', 2)
1028
+ : [this.$originalUsername ?? this.username, null];
1046
1029
  // Lowercase the domain part.
1047
1030
  if (domain) {
1048
1031
  domain = domain.toLowerCase();
@@ -1060,9 +1043,7 @@ export default class User extends AbleObject<UserData> {
1060
1043
  // While loading, accessing abilities on the current user will infinitely
1061
1044
  // loop, but if this is the current user, we can use its abilities.
1062
1045
  const abilities =
1063
- (isCurrentUser || user == null
1064
- ? this.$data.abilities
1065
- : user?.abilities) ?? [];
1046
+ (isCurrentUser || user == null ? this.abilities : user?.abilities) ?? [];
1066
1047
  const isNewUser = this.guid == null;
1067
1048
  const isDomainUser =
1068
1049
  tilmeld.config.domainSupport &&
@@ -1214,10 +1195,10 @@ export default class User extends AbleObject<UserData> {
1214
1195
  }
1215
1196
 
1216
1197
  public $updateGroupDataProtection() {
1217
- if (this.$data.group != null && !this.$data.group.$asleep()) {
1218
- this.$data.group.$updateDataProtection();
1198
+ if (this.group != null && !this.group.$asleep()) {
1199
+ this.group.$updateDataProtection();
1219
1200
  }
1220
- for (let group of this.$data.groups ?? []) {
1201
+ for (let group of this.groups ?? []) {
1221
1202
  if (!group.$asleep()) {
1222
1203
  group.$updateDataProtection();
1223
1204
  }
@@ -1250,7 +1231,7 @@ export default class User extends AbleObject<UserData> {
1250
1231
  }
1251
1232
  return (
1252
1233
  (ability in this.$gatekeeperCache && !!this.$gatekeeperCache[ability]) ||
1253
- !!this.$data.abilities?.includes('system/admin')
1234
+ !!this.abilities?.includes('system/admin')
1254
1235
  );
1255
1236
  }
1256
1237
 
@@ -1259,16 +1240,16 @@ export default class User extends AbleObject<UserData> {
1259
1240
  */
1260
1241
  public async $getGatekeeperCache() {
1261
1242
  await this.$wake();
1262
- let abilities = this.$data.abilities ?? [];
1263
- if (this.$data.inheritAbilities) {
1264
- await Promise.all(this.$data.groups?.map((e) => e.$wake()) || []);
1265
- for (let curGroup of this.$data.groups ?? []) {
1243
+ let abilities = this.abilities ?? [];
1244
+ if (this.inheritAbilities) {
1245
+ await Promise.all(this.groups?.map((e) => e.$wake()) || []);
1246
+ for (let curGroup of this.groups ?? []) {
1266
1247
  if (curGroup.enabled) {
1267
1248
  abilities = abilities.concat(curGroup.abilities ?? []);
1268
1249
  }
1269
1250
  }
1270
- await this.$data.group?.$wake();
1271
- const group = this.$data.group;
1251
+ await this.group?.$wake();
1252
+ const group = this.group;
1272
1253
  if (group != null && group.cdate != null && group.enabled) {
1273
1254
  abilities = abilities.concat(group.abilities ?? []);
1274
1255
  }
@@ -1301,10 +1282,10 @@ export default class User extends AbleObject<UserData> {
1301
1282
  tilmeld.config.setupPath
1302
1283
  }/verify`;
1303
1284
 
1304
- if (this.$data.secret != null) {
1285
+ if (this.secret != null) {
1305
1286
  const link = `${verifyUrl}?action=verify&id=${encodeURIComponent(
1306
1287
  this.guid,
1307
- )}&secret=${encodeURIComponent(this.$data.secret)}`;
1288
+ )}&secret=${encodeURIComponent(this.secret)}`;
1308
1289
  success =
1309
1290
  success &&
1310
1291
  (await tilmeld.config.sendEmail(
@@ -1313,8 +1294,8 @@ export default class User extends AbleObject<UserData> {
1313
1294
  template: 'VerifyEmail',
1314
1295
  message: {
1315
1296
  to: {
1316
- name: this.$data.name ?? '',
1317
- address: this.$data.email ?? '',
1297
+ name: this.name ?? '',
1298
+ address: this.email ?? '',
1318
1299
  },
1319
1300
  },
1320
1301
  locals: { verifyLink: link },
@@ -1323,10 +1304,10 @@ export default class User extends AbleObject<UserData> {
1323
1304
  ));
1324
1305
  }
1325
1306
 
1326
- if (this.$data.newEmailSecret != null) {
1307
+ if (this.newEmailSecret != null) {
1327
1308
  const link = `${verifyUrl}?action=verifychange&id=${encodeURIComponent(
1328
1309
  this.guid,
1329
- )}&secret=${encodeURIComponent(this.$data.newEmailSecret)}`;
1310
+ )}&secret=${encodeURIComponent(this.newEmailSecret)}`;
1330
1311
  success =
1331
1312
  success &&
1332
1313
  (await tilmeld.config.sendEmail(
@@ -1335,24 +1316,24 @@ export default class User extends AbleObject<UserData> {
1335
1316
  template: 'VerifyEmailChange',
1336
1317
  message: {
1337
1318
  to: {
1338
- name: this.$data.name ?? '',
1339
- address: this.$data.newEmailAddress ?? '',
1319
+ name: this.name ?? '',
1320
+ address: this.newEmailAddress ?? '',
1340
1321
  },
1341
1322
  },
1342
1323
  locals: {
1343
1324
  verifyLink: link,
1344
- oldEmail: this.$data.cancelEmailAddress,
1345
- newEmail: this.$data.newEmailAddress,
1325
+ oldEmail: this.cancelEmailAddress,
1326
+ newEmail: this.newEmailAddress,
1346
1327
  },
1347
1328
  },
1348
1329
  this,
1349
1330
  ));
1350
1331
  }
1351
1332
 
1352
- if (this.$data.cancelEmailSecret != null) {
1333
+ if (this.cancelEmailSecret != null) {
1353
1334
  const link = `${verifyUrl}?action=cancelchange&id=${encodeURIComponent(
1354
1335
  this.guid,
1355
- )}&secret=${encodeURIComponent(this.$data.cancelEmailSecret)}`;
1336
+ )}&secret=${encodeURIComponent(this.cancelEmailSecret)}`;
1356
1337
  success =
1357
1338
  success &&
1358
1339
  (await tilmeld.config.sendEmail(
@@ -1361,14 +1342,14 @@ export default class User extends AbleObject<UserData> {
1361
1342
  template: 'CancelEmailChange',
1362
1343
  message: {
1363
1344
  to: {
1364
- name: this.$data.name ?? '',
1365
- address: this.$data.cancelEmailAddress ?? '',
1345
+ name: this.name ?? '',
1346
+ address: this.cancelEmailAddress ?? '',
1366
1347
  },
1367
1348
  },
1368
1349
  locals: {
1369
1350
  cancelLink: link,
1370
- oldEmail: this.$data.cancelEmailAddress,
1371
- newEmail: this.$data.newEmailAddress ?? this.$data.email,
1351
+ oldEmail: this.cancelEmailAddress,
1352
+ newEmail: this.newEmailAddress ?? this.email,
1372
1353
  },
1373
1354
  },
1374
1355
  this,
@@ -1384,15 +1365,15 @@ export default class User extends AbleObject<UserData> {
1384
1365
  * @param group The group.
1385
1366
  * @returns True if the user is already in the group. The resulting array of groups if the user was not.
1386
1367
  */
1387
- public async $addGroup(group: GroupClass & GroupData) {
1388
- await Promise.all(this.$data.groups?.map((e) => e.$wake()) || []);
1389
- let groups = this.$data.groups;
1368
+ public async $addGroup(group: GroupClass) {
1369
+ await Promise.all(this.groups?.map((e) => e.$wake()) || []);
1370
+ let groups = this.groups;
1390
1371
  if (groups == null) {
1391
1372
  groups = [];
1392
1373
  }
1393
1374
  if (!group.$inArray(groups)) {
1394
1375
  groups.push(group);
1395
- this.$data.groups = groups;
1376
+ this.groups = groups;
1396
1377
  return groups;
1397
1378
  }
1398
1379
  return true;
@@ -1408,19 +1389,19 @@ export default class User extends AbleObject<UserData> {
1408
1389
  const tilmeld = enforceTilmeld(this);
1409
1390
  switch (tilmeld.config.pwMethod) {
1410
1391
  case 'plain':
1411
- return this.$data.password === password;
1392
+ return this.password === password;
1412
1393
  case 'digest':
1413
1394
  return (
1414
- this.$data.password ===
1395
+ this.password ===
1415
1396
  crypto.createHash('sha256').update(password).digest('base64')
1416
1397
  );
1417
1398
  case 'salt':
1418
1399
  default:
1419
1400
  return (
1420
- this.$data.password ===
1401
+ this.password ===
1421
1402
  crypto
1422
1403
  .createHash('sha256')
1423
- .update(password + this.$data.salt)
1404
+ .update(password + this.salt)
1424
1405
  .digest('base64')
1425
1406
  );
1426
1407
  }
@@ -1432,18 +1413,18 @@ export default class User extends AbleObject<UserData> {
1432
1413
  * @param group The group.
1433
1414
  * @returns True if the user wasn't in the group. The resulting array of groups if the user was.
1434
1415
  */
1435
- public async $delGroup(group: GroupClass & GroupData) {
1436
- await Promise.all(this.$data.groups?.map((e) => e.$wake()) || []);
1437
- let groups = this.$data.groups || [];
1438
- if (this.$data.groups != null && group.$inArray(groups)) {
1439
- const newGroups: (GroupClass & GroupData)[] = [];
1416
+ public async $delGroup(group: GroupClass) {
1417
+ await Promise.all(this.groups?.map((e) => e.$wake()) || []);
1418
+ let groups = this.groups || [];
1419
+ if (this.groups != null && group.$inArray(groups)) {
1420
+ const newGroups: GroupClass[] = [];
1440
1421
  for (let curGroup of groups) {
1441
1422
  if (!group.$is(curGroup)) {
1442
1423
  newGroups.push(curGroup);
1443
1424
  }
1444
1425
  }
1445
- this.$data.groups = newGroups;
1446
- return this.$data.groups;
1426
+ this.groups = newGroups;
1427
+ return this.groups;
1447
1428
  }
1448
1429
  return true;
1449
1430
  }
@@ -1454,21 +1435,19 @@ export default class User extends AbleObject<UserData> {
1454
1435
  * @param group The group, or the group's GUID.
1455
1436
  * @returns True or false.
1456
1437
  */
1457
- public async $inGroup(group: (GroupClass & GroupData) | string) {
1438
+ public async $inGroup(group: GroupClass | string) {
1458
1439
  if (typeof group === 'string') {
1459
- if (this.$data.group?.guid === group) {
1440
+ if (this.group?.guid === group) {
1460
1441
  return true;
1461
1442
  }
1462
- for (let curGroup of this.$data.groups ?? []) {
1443
+ for (let curGroup of this.groups ?? []) {
1463
1444
  if (curGroup.guid === group) {
1464
1445
  return true;
1465
1446
  }
1466
1447
  }
1467
1448
  return false;
1468
1449
  }
1469
- return (
1470
- group.$is(this.$data.group) || group.$inArray(this.$data.groups ?? [])
1471
- );
1450
+ return group.$is(this.group) || group.$inArray(this.groups ?? []);
1472
1451
  }
1473
1452
 
1474
1453
  /**
@@ -1477,18 +1456,18 @@ export default class User extends AbleObject<UserData> {
1477
1456
  * @param group The group, or the group's GUID.
1478
1457
  * @returns True or false.
1479
1458
  */
1480
- public async $isDescendant(group: (GroupClass & GroupData) | string) {
1459
+ public async $isDescendant(group: GroupClass | string) {
1481
1460
  // Check to see if the user is in a descendant group of the given group.
1482
- await this.$data.group?.$wake();
1461
+ await this.group?.$wake();
1483
1462
  if (
1484
- this.$data.group != null &&
1485
- this.$data.group?.cdate != null &&
1486
- (await this.$data.group?.$isDescendant(group))
1463
+ this.group != null &&
1464
+ this.group?.cdate != null &&
1465
+ (await this.group?.$isDescendant(group))
1487
1466
  ) {
1488
1467
  return true;
1489
1468
  }
1490
- await Promise.all(this.$data.groups?.map((e) => e.$wake()) || []);
1491
- for (let curGroup of this.$data.groups ?? []) {
1469
+ await Promise.all(this.groups?.map((e) => e.$wake()) || []);
1470
+ for (let curGroup of this.groups ?? []) {
1492
1471
  if (await curGroup.$isDescendant(group)) {
1493
1472
  return true;
1494
1473
  }
@@ -1509,7 +1488,7 @@ export default class User extends AbleObject<UserData> {
1509
1488
  }): Promise<{ result: boolean; message: string }> {
1510
1489
  this.$nymph.config.debugLog(
1511
1490
  'tilmeld',
1512
- `Password change request for "${this.$data.username}".`,
1491
+ `Password change request for "${this.username}".`,
1513
1492
  );
1514
1493
  if (!('newPassword' in data) || !data.newPassword.length) {
1515
1494
  return { result: false, message: 'Please specify a password.' };
@@ -1517,13 +1496,13 @@ export default class User extends AbleObject<UserData> {
1517
1496
  if (!this.$checkPassword(data.currentPassword ?? '')) {
1518
1497
  this.$nymph.config.debugLog(
1519
1498
  'tilmeld',
1520
- `Incorrect password for change request for "${this.$data.username}".`,
1499
+ `Incorrect password for change request for "${this.username}".`,
1521
1500
  );
1522
1501
  return { result: false, message: 'Incorrect password.' };
1523
1502
  }
1524
- this.$data.passwordTemp = data.newPassword;
1503
+ this.passwordTemp = data.newPassword;
1525
1504
  if (data.revokeCurrentTokens) {
1526
- this.$data.revokeTokenDate = Date.now();
1505
+ this.revokeTokenDate = Date.now();
1527
1506
  }
1528
1507
  try {
1529
1508
  await this.$save();
@@ -1547,26 +1526,26 @@ export default class User extends AbleObject<UserData> {
1547
1526
  const tilmeld = enforceTilmeld(this);
1548
1527
  switch (tilmeld.config.pwMethod) {
1549
1528
  case 'plain':
1550
- delete this.$data.salt;
1551
- this.$data.password = password;
1529
+ delete this.salt;
1530
+ this.password = password;
1552
1531
  break;
1553
1532
  case 'digest':
1554
- delete this.$data.salt;
1555
- this.$data.password = crypto
1533
+ delete this.salt;
1534
+ this.password = crypto
1556
1535
  .createHash('sha256')
1557
1536
  .update(password)
1558
1537
  .digest('base64');
1559
1538
  break;
1560
1539
  case 'salt':
1561
1540
  default:
1562
- this.$data.salt = nanoid();
1563
- this.$data.password = crypto
1541
+ this.salt = nanoid();
1542
+ this.password = crypto
1564
1543
  .createHash('sha256')
1565
- .update(password + this.$data.salt)
1544
+ .update(password + this.salt)
1566
1545
  .digest('base64');
1567
1546
  break;
1568
1547
  }
1569
- return this.$data.password;
1548
+ return this.password;
1570
1549
  }
1571
1550
 
1572
1551
  /**
@@ -1582,7 +1561,7 @@ export default class User extends AbleObject<UserData> {
1582
1561
  return { result: false, message: 'Incorrect password.' };
1583
1562
  }
1584
1563
 
1585
- this.$data.revokeTokenDate = Date.now();
1564
+ this.revokeTokenDate = Date.now();
1586
1565
 
1587
1566
  try {
1588
1567
  await this.$save();
@@ -1598,7 +1577,7 @@ export default class User extends AbleObject<UserData> {
1598
1577
  }
1599
1578
 
1600
1579
  public $hasTOTPSecret(): boolean {
1601
- return this.$data.totpSecret != null;
1580
+ return this.totpSecret != null;
1602
1581
  }
1603
1582
 
1604
1583
  /**
@@ -1608,7 +1587,7 @@ export default class User extends AbleObject<UserData> {
1608
1587
  * @returns True if the code is valid, otherwise false.
1609
1588
  */
1610
1589
  public $checkTOTPCode(code: string) {
1611
- if (this.$data.totpSecret == null) {
1590
+ if (this.totpSecret == null) {
1612
1591
  return false;
1613
1592
  }
1614
1593
 
@@ -1616,11 +1595,11 @@ export default class User extends AbleObject<UserData> {
1616
1595
 
1617
1596
  const totp = new TOTP({
1618
1597
  issuer: tilmeld.config.appName,
1619
- label: this.$data.username,
1598
+ label: this.username,
1620
1599
  algorithm: 'SHA1',
1621
1600
  digits: 6,
1622
1601
  period: 30,
1623
- secret: this.$data.totpSecret,
1602
+ secret: this.totpSecret,
1624
1603
  });
1625
1604
 
1626
1605
  return totp.validate({ token: code, window: 2 }) != null;
@@ -1638,7 +1617,7 @@ export default class User extends AbleObject<UserData> {
1638
1617
  }> {
1639
1618
  const tilmeld = enforceTilmeld(this);
1640
1619
 
1641
- if (this.$data.totpSecret != null) {
1620
+ if (this.totpSecret != null) {
1642
1621
  throw new BadDataError('You already have a 2FA secret.');
1643
1622
  }
1644
1623
 
@@ -1646,7 +1625,7 @@ export default class User extends AbleObject<UserData> {
1646
1625
 
1647
1626
  const totp = new TOTP({
1648
1627
  issuer: tilmeld.config.appName,
1649
- label: this.$data.username,
1628
+ label: this.username,
1650
1629
  algorithm: 'SHA1',
1651
1630
  digits: 6,
1652
1631
  period: 30,
@@ -1675,7 +1654,7 @@ export default class User extends AbleObject<UserData> {
1675
1654
  return { result: false, message: 'Incorrect password.' };
1676
1655
  }
1677
1656
 
1678
- if (this.$data.totpSecret != null) {
1657
+ if (this.totpSecret != null) {
1679
1658
  return { result: false, message: 'You already have a 2FA secret.' };
1680
1659
  }
1681
1660
 
@@ -1699,7 +1678,7 @@ export default class User extends AbleObject<UserData> {
1699
1678
 
1700
1679
  const totp = new TOTP({
1701
1680
  issuer: tilmeld.config.appName,
1702
- label: this.$data.username,
1681
+ label: this.username,
1703
1682
  algorithm: 'SHA1',
1704
1683
  digits: 6,
1705
1684
  period: 30,
@@ -1710,7 +1689,7 @@ export default class User extends AbleObject<UserData> {
1710
1689
  return { result: false, message: '2FA code is incorrect.' };
1711
1690
  }
1712
1691
 
1713
- this.$data.totpSecret = data.secret;
1692
+ this.totpSecret = data.secret;
1714
1693
 
1715
1694
  try {
1716
1695
  await this.$save();
@@ -1746,17 +1725,17 @@ export default class User extends AbleObject<UserData> {
1746
1725
  return { result: false, message: '2FA code is invalid.' };
1747
1726
  }
1748
1727
 
1749
- if (this.$data.totpSecret == null) {
1728
+ if (this.totpSecret == null) {
1750
1729
  return { result: false, message: "You don't have a 2FA secret." };
1751
1730
  }
1752
1731
 
1753
1732
  const totp = new TOTP({
1754
1733
  issuer: tilmeld.config.appName,
1755
- label: this.$data.username,
1734
+ label: this.username,
1756
1735
  algorithm: 'SHA1',
1757
1736
  digits: 6,
1758
1737
  period: 30,
1759
- secret: this.$data.totpSecret,
1738
+ secret: this.totpSecret,
1760
1739
  });
1761
1740
 
1762
1741
  if (totp.validate({ token: data.code, window: 2 }) == null) {
@@ -1769,7 +1748,7 @@ export default class User extends AbleObject<UserData> {
1769
1748
  };
1770
1749
  }
1771
1750
 
1772
- delete this.$data.totpSecret;
1751
+ delete this.totpSecret;
1773
1752
 
1774
1753
  try {
1775
1754
  await this.$save();
@@ -1789,23 +1768,23 @@ export default class User extends AbleObject<UserData> {
1789
1768
 
1790
1769
  this.$nymph.config.debugInfo(
1791
1770
  'tilmeld',
1792
- `Username check "${this.$data.username}".`,
1771
+ `Username check "${this.username}".`,
1793
1772
  );
1794
1773
 
1795
1774
  if (!tilmeld.config.emailUsernames) {
1796
1775
  let [username, domain] = tilmeld.config.domainSupport
1797
- ? splitn(this.$data.username ?? '', '@', 2)
1798
- : [this.$data.username, null];
1776
+ ? splitn(this.username ?? '', '@', 2)
1777
+ : [this.username, null];
1799
1778
 
1800
1779
  // Lowercase the domain part.
1801
1780
  if (domain) {
1802
1781
  domain = domain.toLowerCase();
1803
- this.$data.username = `${username}@${domain}`;
1782
+ this.username = `${username}@${domain}`;
1804
1783
  }
1805
1784
 
1806
1785
  if (
1807
- this.$data.username == null ||
1808
- !this.$data.username.length ||
1786
+ this.username == null ||
1787
+ !this.username.length ||
1809
1788
  username == null ||
1810
1789
  !username.length
1811
1790
  ) {
@@ -1863,7 +1842,7 @@ export default class User extends AbleObject<UserData> {
1863
1842
  type: '&',
1864
1843
  ilike: [
1865
1844
  'username',
1866
- this.$data.username.replace(/([\\%_])/g, (s) => `\\${s}`),
1845
+ this.username.replace(/([\\%_])/g, (s) => `\\${s}`),
1867
1846
  ],
1868
1847
  };
1869
1848
  if (this.guid != null) {
@@ -1881,7 +1860,7 @@ export default class User extends AbleObject<UserData> {
1881
1860
  .checkUsernameCallbacks) {
1882
1861
  if (callback) {
1883
1862
  const result = await callback(this, {
1884
- username: this.$data.username,
1863
+ username: this.username,
1885
1864
  });
1886
1865
  if (!result.result) {
1887
1866
  return { message: 'Username is not available.', ...result };
@@ -1895,11 +1874,11 @@ export default class User extends AbleObject<UserData> {
1895
1874
  this.guid != null ? 'Username is valid.' : 'Username is available!',
1896
1875
  };
1897
1876
  } else {
1898
- this.$data.email = this.$data.username;
1899
- if (this.$data.username == null || !this.$data.username.length) {
1877
+ this.email = this.username;
1878
+ if (this.username == null || !this.username.length) {
1900
1879
  return { result: false, message: 'Please specify an email.' };
1901
1880
  }
1902
- if (this.$data.username.length < tilmeld.config.minUsernameLength) {
1881
+ if (this.username.length < tilmeld.config.minUsernameLength) {
1903
1882
  return {
1904
1883
  result: false,
1905
1884
  message:
@@ -1908,7 +1887,7 @@ export default class User extends AbleObject<UserData> {
1908
1887
  ' characters.',
1909
1888
  };
1910
1889
  }
1911
- if (this.$data.username.length > tilmeld.config.maxUsernameLength) {
1890
+ if (this.username.length > tilmeld.config.maxUsernameLength) {
1912
1891
  return {
1913
1892
  result: false,
1914
1893
  message:
@@ -1930,24 +1909,21 @@ export default class User extends AbleObject<UserData> {
1930
1909
  public async $checkEmail(): Promise<{ result: boolean; message: string }> {
1931
1910
  const tilmeld = enforceTilmeld(this);
1932
1911
 
1933
- this.$nymph.config.debugInfo(
1934
- 'tilmeld',
1935
- `Email check "${this.$data.email}".`,
1936
- );
1912
+ this.$nymph.config.debugInfo('tilmeld', `Email check "${this.email}".`);
1937
1913
 
1938
- if (this.$data.email == null || !this.$data.email.length) {
1914
+ if (this.email == null || !this.email.length) {
1939
1915
  if (tilmeld.config.verifyEmail) {
1940
1916
  return { result: false, message: 'Please specify an email.' };
1941
1917
  } else {
1942
1918
  return { result: true, message: '' };
1943
1919
  }
1944
1920
  }
1945
- if (!tilmeld.config.validEmailRegex.test(this.$data.email)) {
1921
+ if (!tilmeld.config.validEmailRegex.test(this.email)) {
1946
1922
  return { result: false, message: tilmeld.config.validEmailRegexNotice };
1947
1923
  }
1948
1924
  const selector: Selector = {
1949
1925
  type: '&',
1950
- ilike: ['email', this.$data.email.replace(/([\\%_])/g, (s) => `\\${s}`)],
1926
+ ilike: ['email', this.email.replace(/([\\%_])/g, (s) => `\\${s}`)],
1951
1927
  };
1952
1928
  if (this.guid != null) {
1953
1929
  selector['!guid'] = this.guid;
@@ -1978,16 +1954,13 @@ export default class User extends AbleObject<UserData> {
1978
1954
  public async $checkPhone(): Promise<{ result: boolean; message: string }> {
1979
1955
  const tilmeld = enforceTilmeld(this);
1980
1956
 
1981
- this.$nymph.config.debugInfo(
1982
- 'tilmeld',
1983
- `Phone check "${this.$data.phone}".`,
1984
- );
1957
+ this.$nymph.config.debugInfo('tilmeld', `Phone check "${this.phone}".`);
1985
1958
 
1986
- if (this.$data.phone == null || !this.$data.phone.length) {
1959
+ if (this.phone == null || !this.phone.length) {
1987
1960
  return { result: false, message: 'Please specify a phone number.' };
1988
1961
  }
1989
1962
 
1990
- const stripToDigits = this.$data.phone.replace(/\D/g, () => '');
1963
+ const stripToDigits = this.phone.replace(/\D/g, () => '');
1991
1964
  if (!/\d{10}/.test(stripToDigits)) {
1992
1965
  return {
1993
1966
  result: false,
@@ -2051,16 +2024,16 @@ export default class User extends AbleObject<UserData> {
2051
2024
 
2052
2025
  this.$password(data.password);
2053
2026
  if (tilmeld.config.regFields.includes('name')) {
2054
- this.$data.name =
2055
- this.$data.nameFirst +
2056
- (this.$data.nameMiddle == null ? '' : ' ' + this.$data.nameMiddle) +
2057
- (this.$data.nameLast == null ? '' : ' ' + this.$data.nameLast);
2058
- if (this.$data.name === '') {
2059
- this.$data.name = this.$data.username;
2027
+ this.name =
2028
+ this.nameFirst +
2029
+ (this.nameMiddle == null ? '' : ' ' + this.nameMiddle) +
2030
+ (this.nameLast == null ? '' : ' ' + this.nameLast);
2031
+ if (this.name === '') {
2032
+ this.name = this.username;
2060
2033
  }
2061
2034
  }
2062
2035
  if (tilmeld.config.emailUsernames) {
2063
- this.$data.email = this.$data.username;
2036
+ this.email = this.username;
2064
2037
  }
2065
2038
 
2066
2039
  try {
@@ -2087,10 +2060,10 @@ export default class User extends AbleObject<UserData> {
2087
2060
  ) {
2088
2061
  // The user will be enabled after verifying their e-mail address.
2089
2062
  if (!tilmeld.config.unverifiedAccess) {
2090
- this.$data.enabled = false;
2063
+ this.enabled = false;
2091
2064
  }
2092
2065
  } else {
2093
- this.$data.enabled = true;
2066
+ this.enabled = true;
2094
2067
  }
2095
2068
 
2096
2069
  // If createAdmin is true and there are no other users, grant
@@ -2109,14 +2082,14 @@ export default class User extends AbleObject<UserData> {
2109
2082
  }
2110
2083
  if (!otherUsers.length) {
2111
2084
  this.$grant('system/admin');
2112
- this.$data.enabled = true;
2085
+ this.enabled = true;
2113
2086
  madeAdmin = true;
2114
2087
  }
2115
2088
  }
2116
2089
 
2117
2090
  this.$nymph.config.debugLog(
2118
2091
  'tilmeld',
2119
- `Registering new user "${this.$data.username}".`,
2092
+ `Registering new user "${this.username}".`,
2120
2093
  );
2121
2094
 
2122
2095
  await this.$saveSkipAC();
@@ -2129,7 +2102,7 @@ export default class User extends AbleObject<UserData> {
2129
2102
  tilmeld.config.userFields.includes('email')
2130
2103
  ) {
2131
2104
  message +=
2132
- `Almost there. An email has been sent to ${this.$data.email} ` +
2105
+ `Almost there. An email has been sent to ${this.email} ` +
2133
2106
  'with a verification link for you to finish registration.';
2134
2107
  } else if (
2135
2108
  tilmeld.config.verifyEmail &&
@@ -2142,7 +2115,7 @@ export default class User extends AbleObject<UserData> {
2142
2115
  }
2143
2116
  message +=
2144
2117
  "You're now logged in! An email has been sent to " +
2145
- `${this.$data.email} with a verification link for you to finish ` +
2118
+ `${this.email} with a verification link for you to finish ` +
2146
2119
  'registration.';
2147
2120
  loggedin = true;
2148
2121
  } else {
@@ -2177,12 +2150,12 @@ export default class User extends AbleObject<UserData> {
2177
2150
  template: 'UserRegistered',
2178
2151
  message: { to: tilmeld.config.userRegisteredRecipient },
2179
2152
  locals: {
2180
- userUsername: this.$data.username,
2181
- userName: this.$data.name,
2182
- userFirstName: this.$data.nameFirst,
2183
- userLastName: this.$data.nameLast,
2184
- userEmail: this.$data.email,
2185
- userPhone: this.$data.phone,
2153
+ userUsername: this.username,
2154
+ userName: this.name,
2155
+ userFirstName: this.nameFirst,
2156
+ userLastName: this.nameLast,
2157
+ userEmail: this.email,
2158
+ userPhone: this.phone,
2186
2159
  },
2187
2160
  },
2188
2161
  this,
@@ -2193,7 +2166,7 @@ export default class User extends AbleObject<UserData> {
2193
2166
  } catch (e: any) {
2194
2167
  this.$nymph.config.debugError(
2195
2168
  'tilmeld',
2196
- `Couldn't send new user registered email for "${this.$data.username}": ${e.message}`,
2169
+ `Couldn't send new user registered email for "${this.username}": ${e.message}`,
2197
2170
  );
2198
2171
  }
2199
2172
  }
@@ -2218,7 +2191,7 @@ export default class User extends AbleObject<UserData> {
2218
2191
 
2219
2192
  public async $save() {
2220
2193
  let tilmeld = enforceTilmeld(this);
2221
- if (this.$data.username == null || !this.$data.username.trim().length) {
2194
+ if (this.username == null || !this.username.trim().length) {
2222
2195
  throw new BadUsernameError('Username must not be empty.');
2223
2196
  }
2224
2197
 
@@ -2226,7 +2199,7 @@ export default class User extends AbleObject<UserData> {
2226
2199
  !this.$skipAcWhenSaving &&
2227
2200
  tilmeld.gatekeeper('tilmeld/admin') &&
2228
2201
  !tilmeld.gatekeeper('system/admin') &&
2229
- this.$data.abilities?.includes('system/admin')
2202
+ this.abilities?.includes('system/admin')
2230
2203
  ) {
2231
2204
  throw new AccessControlError(
2232
2205
  "You don't have the authority to modify system admins.",
@@ -2235,14 +2208,14 @@ export default class User extends AbleObject<UserData> {
2235
2208
 
2236
2209
  // Lowercase the domain part.
2237
2210
  if (tilmeld.config.domainSupport) {
2238
- const [username, domain] = splitn(this.$data.username ?? '', '@', 2);
2211
+ const [username, domain] = splitn(this.username ?? '', '@', 2);
2239
2212
  if (domain) {
2240
- this.$data.username = `${username}@${domain.toLowerCase()}`;
2213
+ this.username = `${username}@${domain.toLowerCase()}`;
2241
2214
  }
2242
2215
  }
2243
2216
 
2244
2217
  if (tilmeld.config.domainSupport) {
2245
- const [_username, domain] = splitn(this.$data.username ?? '', '@', 2);
2218
+ const [_username, domain] = splitn(this.username ?? '', '@', 2);
2246
2219
  const [_originalUsername, originalDomain] = splitn(
2247
2220
  this.$originalUsername ?? '',
2248
2221
  '@',
@@ -2289,113 +2262,95 @@ export default class User extends AbleObject<UserData> {
2289
2262
  let sendVerification = false;
2290
2263
 
2291
2264
  // Formatting.
2292
- this.$data.username = this.$data.username.trim();
2265
+ this.username = this.username.trim();
2293
2266
  if (tilmeld.config.emailUsernames) {
2294
- this.$data.email = this.$data.username;
2295
- }
2296
- this.$data.nameFirst = (this.$data.nameFirst ?? '').trim();
2297
- this.$data.nameMiddle = (this.$data.nameMiddle ?? '').trim();
2298
- this.$data.nameLast = (this.$data.nameLast ?? '').trim();
2299
- this.$data.phone = (this.$data.phone ?? '').trim();
2300
- this.$data.name =
2301
- this.$data.nameFirst +
2302
- (this.$data.nameMiddle ? ' ' + this.$data.nameMiddle : '') +
2303
- (this.$data.nameLast ? ' ' + this.$data.nameLast : '');
2304
- this.$data.enabled = !!this.$data.enabled;
2267
+ this.email = this.username;
2268
+ }
2269
+ this.nameFirst = (this.nameFirst ?? '').trim();
2270
+ this.nameMiddle = (this.nameMiddle ?? '').trim();
2271
+ this.nameLast = (this.nameLast ?? '').trim();
2272
+ this.phone = (this.phone ?? '').trim();
2273
+ this.name =
2274
+ this.nameFirst +
2275
+ (this.nameMiddle ? ' ' + this.nameMiddle : '') +
2276
+ (this.nameLast ? ' ' + this.nameLast : '');
2277
+ this.enabled = !!this.enabled;
2305
2278
 
2306
2279
  // Clear empty values.
2307
- if (
2308
- this.$data.nameFirst === '' ||
2309
- !tilmeld.config.userFields.includes('name')
2310
- ) {
2311
- delete this.$data.nameFirst;
2280
+ if (this.nameFirst === '' || !tilmeld.config.userFields.includes('name')) {
2281
+ delete this.nameFirst;
2312
2282
  }
2313
- if (
2314
- this.$data.nameMiddle === '' ||
2315
- !tilmeld.config.userFields.includes('name')
2316
- ) {
2317
- delete this.$data.nameMiddle;
2283
+ if (this.nameMiddle === '' || !tilmeld.config.userFields.includes('name')) {
2284
+ delete this.nameMiddle;
2318
2285
  }
2319
- if (
2320
- this.$data.nameLast === '' ||
2321
- !tilmeld.config.userFields.includes('name')
2322
- ) {
2323
- delete this.$data.nameLast;
2286
+ if (this.nameLast === '' || !tilmeld.config.userFields.includes('name')) {
2287
+ delete this.nameLast;
2324
2288
  }
2325
- if (this.$data.name === '' || !tilmeld.config.userFields.includes('name')) {
2326
- delete this.$data.name;
2289
+ if (this.name === '' || !tilmeld.config.userFields.includes('name')) {
2290
+ delete this.name;
2327
2291
  }
2328
- if (
2329
- this.$data.email === '' ||
2330
- !tilmeld.config.userFields.includes('email')
2331
- ) {
2332
- delete this.$data.email;
2292
+ if (this.email === '' || !tilmeld.config.userFields.includes('email')) {
2293
+ delete this.email;
2333
2294
  }
2334
- if (this.$data.avatar === '') {
2335
- delete this.$data.avatar;
2295
+ if (this.avatar === '') {
2296
+ delete this.avatar;
2336
2297
  }
2337
- if (
2338
- this.$data.phone === '' ||
2339
- !tilmeld.config.userFields.includes('phone')
2340
- ) {
2341
- delete this.$data.phone;
2298
+ if (this.phone === '' || !tilmeld.config.userFields.includes('phone')) {
2299
+ delete this.phone;
2342
2300
  }
2343
- if (
2344
- this.$data.secret === '' ||
2345
- !tilmeld.config.userFields.includes('email')
2346
- ) {
2347
- delete this.$data.secret;
2301
+ if (this.secret === '' || !tilmeld.config.userFields.includes('email')) {
2302
+ delete this.secret;
2348
2303
  }
2349
2304
  if (
2350
- this.$data.emailChangeDate === 0 ||
2305
+ this.emailChangeDate === 0 ||
2351
2306
  !tilmeld.config.userFields.includes('email')
2352
2307
  ) {
2353
- delete this.$data.emailChangeDate;
2308
+ delete this.emailChangeDate;
2354
2309
  }
2355
2310
  if (
2356
- this.$data.newEmailSecret === '' ||
2311
+ this.newEmailSecret === '' ||
2357
2312
  !tilmeld.config.userFields.includes('email')
2358
2313
  ) {
2359
- delete this.$data.newEmailSecret;
2314
+ delete this.newEmailSecret;
2360
2315
  }
2361
2316
  if (
2362
- this.$data.newEmailAddress === '' ||
2317
+ this.newEmailAddress === '' ||
2363
2318
  !tilmeld.config.userFields.includes('email')
2364
2319
  ) {
2365
- delete this.$data.newEmailAddress;
2320
+ delete this.newEmailAddress;
2366
2321
  }
2367
2322
  if (
2368
- this.$data.cancelEmailSecret === '' ||
2323
+ this.cancelEmailSecret === '' ||
2369
2324
  !tilmeld.config.userFields.includes('email')
2370
2325
  ) {
2371
- delete this.$data.cancelEmailSecret;
2326
+ delete this.cancelEmailSecret;
2372
2327
  }
2373
2328
  if (
2374
- this.$data.cancelEmailAddress === '' ||
2329
+ this.cancelEmailAddress === '' ||
2375
2330
  !tilmeld.config.userFields.includes('email')
2376
2331
  ) {
2377
- delete this.$data.cancelEmailAddress;
2332
+ delete this.cancelEmailAddress;
2378
2333
  }
2379
2334
  if (
2380
- this.$data.recoverSecret === '' ||
2335
+ this.recoverSecret === '' ||
2381
2336
  !tilmeld.config.userFields.includes('email')
2382
2337
  ) {
2383
- delete this.$data.recoverSecret;
2338
+ delete this.recoverSecret;
2384
2339
  }
2385
2340
  if (
2386
- this.$data.recoverSecretDate === 0 ||
2341
+ this.recoverSecretDate === 0 ||
2387
2342
  !tilmeld.config.userFields.includes('email')
2388
2343
  ) {
2389
- delete this.$data.recoverSecretDate;
2344
+ delete this.recoverSecretDate;
2390
2345
  }
2391
- if (this.$data.password === '') {
2392
- delete this.$data.password;
2346
+ if (this.password === '') {
2347
+ delete this.password;
2393
2348
  }
2394
- if (this.$data.passwordTemp === '') {
2395
- delete this.$data.passwordTemp;
2349
+ if (this.passwordTemp === '') {
2350
+ delete this.passwordTemp;
2396
2351
  }
2397
- if (this.$data.inheritAbilities === false) {
2398
- delete this.$data.inheritAbilities;
2352
+ if (this.inheritAbilities === false) {
2353
+ delete this.inheritAbilities;
2399
2354
  }
2400
2355
 
2401
2356
  // Verification.
@@ -2425,19 +2380,19 @@ export default class User extends AbleObject<UserData> {
2425
2380
  if (this.guid == null) {
2426
2381
  // If this is the first user, they'll be made an admin, so they don't
2427
2382
  // need to verify.
2428
- if (!this.$data.abilities?.includes('system/admin')) {
2429
- this.$data.secret = nanoid();
2383
+ if (!this.abilities?.includes('system/admin')) {
2384
+ this.secret = nanoid();
2430
2385
  sendVerification = true;
2431
2386
  }
2432
2387
  } else if (
2433
2388
  this.$originalEmail != null &&
2434
- this.$originalEmail !== this.$data.email
2389
+ this.$originalEmail !== this.email
2435
2390
  ) {
2436
2391
  // The user already has an old email address.
2437
2392
  if (
2438
2393
  tilmeld.config.emailRateLimit !== '' &&
2439
- this.$data.emailChangeDate != null &&
2440
- this.$data.emailChangeDate >=
2394
+ this.emailChangeDate != null &&
2395
+ this.emailChangeDate >=
2441
2396
  (strtotime('-' + tilmeld.config.emailRateLimit) || 0) * 1000
2442
2397
  ) {
2443
2398
  throw new EmailChangeRateLimitExceededError(
@@ -2445,61 +2400,61 @@ export default class User extends AbleObject<UserData> {
2445
2400
  new Date(
2446
2401
  (strtotime(
2447
2402
  '+' + tilmeld.config.emailRateLimit,
2448
- Math.floor(this.$data.emailChangeDate / 1000),
2403
+ Math.floor(this.emailChangeDate / 1000),
2449
2404
  ) || 0) * 1000,
2450
2405
  ).toString() +
2451
2406
  ' to change your email address again.',
2452
2407
  );
2453
2408
  } else {
2454
2409
  if (
2455
- this.$data.newEmailSecret == null &&
2410
+ this.newEmailSecret == null &&
2456
2411
  tilmeld.config.emailRateLimit !== '' &&
2457
2412
  // Make sure the user has at least the rate limit time to cancel
2458
2413
  // an email change.
2459
- (this.$data.emailChangeDate == null ||
2460
- this.$data.emailChangeDate <
2414
+ (this.emailChangeDate == null ||
2415
+ this.emailChangeDate <
2461
2416
  (strtotime('-' + tilmeld.config.emailRateLimit) || 0) * 1000)
2462
2417
  ) {
2463
2418
  // Save the old email in case the cancel change link is clicked.
2464
- this.$data.cancelEmailAddress = this.$originalEmail;
2465
- this.$data.cancelEmailSecret = nanoid();
2466
- this.$data.emailChangeDate = Date.now();
2419
+ this.cancelEmailAddress = this.$originalEmail;
2420
+ this.cancelEmailSecret = nanoid();
2421
+ this.emailChangeDate = Date.now();
2467
2422
  }
2468
2423
  // Save the new address and reset to the old one (until they verify
2469
2424
  // it).
2470
- this.$data.newEmailAddress = this.$data.email;
2471
- this.$data.email = this.$originalEmail;
2425
+ this.newEmailAddress = this.email;
2426
+ this.email = this.$originalEmail;
2472
2427
  if (tilmeld.config.emailUsernames) {
2473
- this.$data.username = this.$data.email;
2428
+ this.username = this.email;
2474
2429
  }
2475
- this.$data.newEmailSecret = nanoid();
2430
+ this.newEmailSecret = nanoid();
2476
2431
  sendVerification = true;
2477
2432
  }
2478
2433
  }
2479
2434
  } else if (
2480
2435
  this.guid != null &&
2481
2436
  this.$originalEmail != null &&
2482
- this.$originalEmail !== this.$data.email &&
2437
+ this.$originalEmail !== this.email &&
2483
2438
  // Make sure the user has at least the rate limit time to cancel an
2484
2439
  // email change.
2485
- (this.$data.emailChangeDate == null ||
2486
- this.$data.emailChangeDate <
2440
+ (this.emailChangeDate == null ||
2441
+ this.emailChangeDate <
2487
2442
  (strtotime('-' + tilmeld.config.emailRateLimit) || 0) * 1000)
2488
2443
  ) {
2489
2444
  // The user doesn't need to verify their new email address, but should
2490
2445
  // be able to cancel the email change from their old address.
2491
- this.$data.cancelEmailAddress = this.$originalEmail;
2492
- this.$data.cancelEmailSecret = nanoid();
2446
+ this.cancelEmailAddress = this.$originalEmail;
2447
+ this.cancelEmailSecret = nanoid();
2493
2448
  sendVerification = true;
2494
2449
  }
2495
2450
  }
2496
2451
 
2497
- if (this.$data.passwordTemp != null) {
2498
- this.$password(this.$data.passwordTemp);
2452
+ if (this.passwordTemp != null) {
2453
+ this.$password(this.passwordTemp);
2499
2454
  }
2500
- delete this.$data.passwordTemp;
2455
+ delete this.passwordTemp;
2501
2456
 
2502
- if (this.$data.password == null) {
2457
+ if (this.password == null) {
2503
2458
  throw new BadDataError('A password is required.');
2504
2459
  }
2505
2460
 
@@ -2514,7 +2469,7 @@ export default class User extends AbleObject<UserData> {
2514
2469
  const tilmeld = enforceTilmeld(this);
2515
2470
  const Group = this.$nymph.getEntityClass(GroupClass);
2516
2471
 
2517
- let group = this.$data.group;
2472
+ let group = this.group;
2518
2473
  if (group != null) {
2519
2474
  // Make sure to get fresh group data.
2520
2475
  if (group.$asleep()) {
@@ -2544,64 +2499,64 @@ export default class User extends AbleObject<UserData> {
2544
2499
  { type: '&', equal: ['defaultPrimary', true] },
2545
2500
  );
2546
2501
  if (group != null) {
2547
- this.$data.group = group;
2502
+ this.group = group;
2548
2503
  }
2549
2504
  }
2550
2505
  }
2551
2506
  if (group != null && group.user != null && this.$is(group.user)) {
2552
2507
  // Update the user's generated primary group.
2553
2508
  let changed = false;
2554
- if (group.groupname !== this.$data.username) {
2555
- group.groupname = this.$data.username;
2509
+ if (group.groupname !== this.username) {
2510
+ group.groupname = this.username;
2556
2511
  changed = true;
2557
2512
  }
2558
- if (group.avatar !== this.$data.avatar) {
2559
- group.avatar = this.$data.avatar;
2513
+ if (group.avatar !== this.avatar) {
2514
+ group.avatar = this.avatar;
2560
2515
  changed = true;
2561
2516
  }
2562
2517
  if (
2563
2518
  tilmeld.config.userFields.includes('email') &&
2564
- group.email !== this.$data.email
2519
+ group.email !== this.email
2565
2520
  ) {
2566
- group.email = this.$data.email;
2521
+ group.email = this.email;
2567
2522
  changed = true;
2568
2523
  }
2569
2524
  if (
2570
2525
  tilmeld.config.userFields.includes('name') &&
2571
- group.name !== this.$data.name
2526
+ group.name !== this.name
2572
2527
  ) {
2573
- group.name = this.$data.name;
2528
+ group.name = this.name;
2574
2529
  changed = true;
2575
2530
  }
2576
2531
  if (
2577
2532
  tilmeld.config.userFields.includes('phone') &&
2578
- group.phone !== this.$data.phone
2533
+ group.phone !== this.phone
2579
2534
  ) {
2580
- group.phone = this.$data.phone;
2535
+ group.phone = this.phone;
2581
2536
  changed = true;
2582
2537
  }
2583
2538
  if (changed || group.guid == null) {
2584
2539
  await group.$saveSkipAC();
2585
2540
  }
2586
- this.$data.group = group;
2541
+ this.group = group;
2587
2542
  }
2588
2543
 
2589
- if (this.$data.groups == null || this.$data.groups.length === 0) {
2544
+ if (this.groups == null || this.groups.length === 0) {
2590
2545
  // Add secondary groups.
2591
2546
  if (
2592
2547
  tilmeld.config.userFields.includes('email') &&
2593
2548
  tilmeld.config.verifyEmail &&
2594
2549
  tilmeld.config.unverifiedAccess &&
2595
- this.$data.secret != null
2550
+ this.secret != null
2596
2551
  ) {
2597
2552
  // Add the default secondaries for unverified users.
2598
- this.$data.groups = await this.$nymph.getEntities(
2553
+ this.groups = await this.$nymph.getEntities(
2599
2554
  { class: Group },
2600
2555
  { type: '&', equal: ['unverifiedSecondary', true] },
2601
2556
  );
2602
2557
  } else {
2603
2558
  // Add the default secondaries.
2604
- this.$data.groups = await this.$nymph.getEntities(
2559
+ this.groups = await this.$nymph.getEntities(
2605
2560
  { class: Group },
2606
2561
  { type: '&', equal: ['defaultSecondary', true] },
2607
2562
  );
@@ -2617,7 +2572,7 @@ export default class User extends AbleObject<UserData> {
2617
2572
  for (let callback of (this.constructor as typeof User)
2618
2573
  .beforeSaveCallbacks) {
2619
2574
  if (callback) {
2620
- await callback(this.$proxy());
2575
+ await callback(this);
2621
2576
  }
2622
2577
  }
2623
2578
 
@@ -2636,7 +2591,7 @@ export default class User extends AbleObject<UserData> {
2636
2591
  for (let callback of (this.constructor as typeof User)
2637
2592
  .afterSaveCallbacks) {
2638
2593
  if (callback) {
2639
- await callback(this.$proxy());
2594
+ await callback(this);
2640
2595
  }
2641
2596
  }
2642
2597
  },
@@ -2644,8 +2599,8 @@ export default class User extends AbleObject<UserData> {
2644
2599
  this.$setNymph(nymph);
2645
2600
 
2646
2601
  if (committed) {
2647
- this.$originalEmail = this.$data.email;
2648
- this.$originalUsername = this.$data.username;
2602
+ this.$originalEmail = this.email;
2603
+ this.$originalUsername = this.username;
2649
2604
 
2650
2605
  try {
2651
2606
  const tilmeld = enforceTilmeld(nymph);
@@ -2693,13 +2648,13 @@ export default class User extends AbleObject<UserData> {
2693
2648
  if (
2694
2649
  !this.$skipAcWhenDeleting &&
2695
2650
  !tilmeld.gatekeeper('system/admin') &&
2696
- this.$data.abilities?.includes('system/admin')
2651
+ this.abilities?.includes('system/admin')
2697
2652
  ) {
2698
2653
  throw new AccessControlError(
2699
2654
  "You don't have the authority to delete system admins.",
2700
2655
  );
2701
2656
  }
2702
- if (this.$data.username !== this.$originalUsername) {
2657
+ if (this.username !== this.$originalUsername) {
2703
2658
  throw new AccessControlError(
2704
2659
  "You can't delete a user while switching their username.",
2705
2660
  );
@@ -2709,11 +2664,11 @@ export default class User extends AbleObject<UserData> {
2709
2664
  throw new BadDataError('User could not be refreshed.');
2710
2665
  }
2711
2666
 
2712
- if (this.$data.group != null) {
2713
- if (this.$data.group.$asleep()) {
2714
- await this.$data.group.$wake();
2667
+ if (this.group != null) {
2668
+ if (this.group.$asleep()) {
2669
+ await this.group.$wake();
2715
2670
  } else {
2716
- if (!(await this.$data.group.$refresh())) {
2671
+ if (!(await this.group.$refresh())) {
2717
2672
  throw new BadDataError('Group could not be refreshed.');
2718
2673
  }
2719
2674
  }
@@ -2722,7 +2677,7 @@ export default class User extends AbleObject<UserData> {
2722
2677
  for (let callback of (this.constructor as typeof User)
2723
2678
  .beforeDeleteCallbacks) {
2724
2679
  if (callback) {
2725
- await callback(this.$proxy());
2680
+ await callback(this);
2726
2681
  }
2727
2682
  }
2728
2683
 
@@ -2730,7 +2685,7 @@ export default class User extends AbleObject<UserData> {
2730
2685
  await this.$logout();
2731
2686
  }
2732
2687
 
2733
- if (this.$data.group != null && this.$is(this.$data.group.user)) {
2688
+ if (this.group != null && this.$is(this.group.user)) {
2734
2689
  // Read the skip ac value here, because super.$delete changes it.
2735
2690
  const $skipAcWhenDeleting = this.$skipAcWhenDeleting;
2736
2691
 
@@ -2738,9 +2693,9 @@ export default class User extends AbleObject<UserData> {
2738
2693
  await super.$delete();
2739
2694
  // Delete the generated group.
2740
2695
  if ($skipAcWhenDeleting) {
2741
- await this.$data.group.$deleteSkipAC();
2696
+ await this.group.$deleteSkipAC();
2742
2697
  } else {
2743
- await this.$data.group.$delete();
2698
+ await this.group.$delete();
2744
2699
  }
2745
2700
  } else {
2746
2701
  await super.$delete();
@@ -2749,7 +2704,7 @@ export default class User extends AbleObject<UserData> {
2749
2704
  for (let callback of (this.constructor as typeof User)
2750
2705
  .afterDeleteCallbacks) {
2751
2706
  if (callback) {
2752
- await callback(this.$proxy());
2707
+ await callback(this);
2753
2708
  }
2754
2709
  }
2755
2710
  }