@nymphjs/tilmeld 1.0.0-alpha.9 → 1.0.0-beta.1

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
@@ -1,27 +1,38 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
12
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
4
  };
14
5
  Object.defineProperty(exports, "__esModule", { value: true });
15
6
  const strtotime_1 = __importDefault(require("locutus/php/datetime/strtotime"));
16
- const nanoid_1 = require("nanoid");
17
- const nanoid_dictionary_1 = require("nanoid-dictionary");
18
7
  const enc_base64_1 = __importDefault(require("crypto-js/enc-base64"));
19
8
  const sha256_1 = __importDefault(require("crypto-js/sha256"));
20
9
  const md5_1 = __importDefault(require("crypto-js/md5"));
21
10
  const lodash_1 = require("lodash");
11
+ const guid_1 = require("@nymphjs/guid");
22
12
  const AbleObject_1 = __importDefault(require("./AbleObject"));
23
13
  const errors_1 = require("./errors");
24
14
  class User extends AbleObject_1.default {
15
+ static async factory(guid) {
16
+ return (await super.factory(guid));
17
+ }
18
+ static async factoryUsername(username) {
19
+ const entity = new this();
20
+ if (username != null) {
21
+ const entity = await this.nymph.getEntity({
22
+ class: this,
23
+ }, {
24
+ type: '&',
25
+ ilike: ['username', username.replace(/([\\%_])/g, (s) => `\\${s}`)],
26
+ });
27
+ if (entity != null) {
28
+ return entity;
29
+ }
30
+ }
31
+ return entity;
32
+ }
33
+ static factorySync(guid) {
34
+ return super.factorySync(guid);
35
+ }
25
36
  constructor(guid) {
26
37
  super(guid);
27
38
  this.$clientEnabledMethods = [...User.DEFAULT_CLIENT_ENABLED_METHODS];
@@ -37,151 +48,117 @@ class User extends AbleObject_1.default {
37
48
  this.$updateDataProtection();
38
49
  }
39
50
  }
40
- static factory(guid) {
41
- const _super = Object.create(null, {
42
- factory: { get: () => super.factory }
43
- });
44
- return __awaiter(this, void 0, void 0, function* () {
45
- return (yield _super.factory.call(this, guid));
46
- });
47
- }
48
- static factoryUsername(username) {
49
- return __awaiter(this, void 0, void 0, function* () {
50
- const entity = new this();
51
- if (username != null) {
52
- const entity = yield this.nymph.getEntity({
53
- class: this,
54
- }, {
55
- type: '&',
56
- ilike: ['username', username.replace(/([\\%_])/g, (s) => `\\${s}`)],
57
- });
58
- if (entity != null) {
59
- return entity;
60
- }
61
- }
62
- return entity;
63
- });
64
- }
65
- static factorySync(guid) {
66
- return super.factorySync(guid);
67
- }
68
51
  static current(returnObjectIfNotExist) {
69
52
  if (this.tilmeld.currentUser == null) {
70
53
  return returnObjectIfNotExist ? this.factorySync() : null;
71
54
  }
72
55
  return this.tilmeld.currentUser;
73
56
  }
74
- static sendRecovery(data) {
75
- var _a, _b, _c, _d;
76
- return __awaiter(this, void 0, void 0, function* () {
77
- if (!this.tilmeld.config.pwRecovery) {
78
- return {
79
- result: false,
80
- message: 'Account recovery is not allowed.',
81
- };
82
- }
83
- let user;
84
- const options = {};
85
- if (!this.tilmeld.config.emailUsernames &&
86
- data.recoveryType === 'username') {
87
- const getUser = yield this.nymph.getEntity({ class: this.tilmeld.User, skipAc: true }, {
88
- type: '&',
89
- ilike: ['email', data.account.replace(/([\\%_])/g, (s) => `\\${s}`)],
90
- });
91
- if (getUser == null) {
92
- return {
93
- result: false,
94
- message: 'Requested account is not accessible.',
95
- };
96
- }
97
- user = getUser;
98
- options.template = 'RecoverUsername';
99
- options.message = {
100
- to: {
101
- name: (_a = user.name) !== null && _a !== void 0 ? _a : '',
102
- address: (_b = user.email) !== null && _b !== void 0 ? _b : '',
103
- },
104
- };
105
- options.locals = {};
106
- }
107
- else if (data.recoveryType === 'password') {
108
- const getUser = yield this.tilmeld.User.factoryUsername(data.account);
109
- if (getUser.guid == null) {
110
- return {
111
- result: false,
112
- message: 'Requested account is not accessible.',
113
- };
114
- }
115
- getUser.recoverSecret = (0, nanoid_1.customAlphabet)(nanoid_dictionary_1.nolookalikesSafe, 10)();
116
- getUser.recoverSecretDate = Date.now();
117
- if (!(yield getUser.$saveSkipAC())) {
118
- return { result: false, message: "Couldn't save recovery secret." };
119
- }
120
- user = getUser;
121
- options.template = 'RecoverPassword';
122
- options.message = {
123
- to: {
124
- name: (_c = user.name) !== null && _c !== void 0 ? _c : '',
125
- address: (_d = user.email) !== null && _d !== void 0 ? _d : '',
126
- },
127
- };
128
- options.locals = {
129
- recoverCode: getUser.recoverSecret,
130
- timeLimit: this.tilmeld.config.pwRecoveryTimeLimit,
131
- };
132
- }
133
- else {
134
- return { result: false, message: 'Invalid recovery type.' };
135
- }
136
- if (yield this.tilmeld.config.sendEmail(this.tilmeld, options, user)) {
137
- return {
138
- result: true,
139
- message: "We've sent an email to your registered address. Please " +
140
- 'check your email to continue with account recovery.',
141
- };
142
- }
143
- else {
144
- return { result: false, message: "Couldn't send recovery email." };
145
- }
146
- });
147
- }
148
- static recover(data) {
149
- var _a;
150
- return __awaiter(this, void 0, void 0, function* () {
151
- if (!this.tilmeld.config.pwRecovery) {
57
+ static async sendRecovery(data) {
58
+ if (!this.tilmeld.config.pwRecovery) {
59
+ return {
60
+ result: false,
61
+ message: 'Account recovery is not allowed.',
62
+ };
63
+ }
64
+ let user;
65
+ const options = {};
66
+ if (!this.tilmeld.config.emailUsernames &&
67
+ data.recoveryType === 'username') {
68
+ const getUser = await this.nymph.getEntity({ class: this.tilmeld.User, skipAc: true }, {
69
+ type: '&',
70
+ ilike: ['email', data.account.replace(/([\\%_])/g, (s) => `\\${s}`)],
71
+ });
72
+ if (getUser == null) {
152
73
  return {
153
74
  result: false,
154
- message: 'Account recovery is not allowed.',
75
+ message: 'Requested account is not accessible.',
155
76
  };
156
77
  }
157
- const user = yield this.tilmeld.User.factoryUsername(data.username);
158
- if (user.guid == null ||
159
- user.recoverSecret == null ||
160
- data.secret !== user.recoverSecret ||
161
- (0, strtotime_1.default)('+' + this.tilmeld.config.pwRecoveryTimeLimit, Math.floor(((_a = user.recoverSecretDate) !== null && _a !== void 0 ? _a : 0) / 1000)) *
162
- 1000 <
163
- Date.now()) {
78
+ user = getUser;
79
+ options.template = 'RecoverUsername';
80
+ options.message = {
81
+ to: {
82
+ name: user.name ?? '',
83
+ address: user.email ?? '',
84
+ },
85
+ };
86
+ options.locals = {};
87
+ }
88
+ else if (data.recoveryType === 'password') {
89
+ const getUser = await this.tilmeld.User.factoryUsername(data.account);
90
+ if (getUser.guid == null) {
164
91
  return {
165
92
  result: false,
166
- message: 'The secret code does not match.',
167
- };
168
- }
169
- if (!('password' in data) || !data.password.length) {
170
- return { result: false, message: 'Password cannot be empty.' };
171
- }
172
- user.$password(data.password);
173
- delete user.recoverSecret;
174
- delete user.recoverSecretDate;
175
- if (yield user.$saveSkipAC()) {
176
- return {
177
- result: true,
178
- message: 'Your password has been reset. You can now log in using your new password.',
93
+ message: 'Requested account is not accessible.',
179
94
  };
180
95
  }
181
- else {
182
- return { result: false, message: 'Error saving new password.' };
183
- }
184
- });
96
+ getUser.recoverSecret = (0, guid_1.humanSecret)();
97
+ getUser.recoverSecretDate = Date.now();
98
+ if (!(await getUser.$saveSkipAC())) {
99
+ return { result: false, message: "Couldn't save recovery secret." };
100
+ }
101
+ user = getUser;
102
+ options.template = 'RecoverPassword';
103
+ options.message = {
104
+ to: {
105
+ name: user.name ?? '',
106
+ address: user.email ?? '',
107
+ },
108
+ };
109
+ options.locals = {
110
+ recoverCode: getUser.recoverSecret,
111
+ timeLimit: this.tilmeld.config.pwRecoveryTimeLimit,
112
+ };
113
+ }
114
+ else {
115
+ return { result: false, message: 'Invalid recovery type.' };
116
+ }
117
+ if (await this.tilmeld.config.sendEmail(this.tilmeld, options, user)) {
118
+ return {
119
+ result: true,
120
+ message: "We've sent an email to your registered address. Please " +
121
+ 'check your email to continue with account recovery.',
122
+ };
123
+ }
124
+ else {
125
+ return { result: false, message: "Couldn't send recovery email." };
126
+ }
127
+ }
128
+ static async recover(data) {
129
+ if (!this.tilmeld.config.pwRecovery) {
130
+ return {
131
+ result: false,
132
+ message: 'Account recovery is not allowed.',
133
+ };
134
+ }
135
+ const user = await this.tilmeld.User.factoryUsername(data.username);
136
+ if (user.guid == null ||
137
+ user.recoverSecret == null ||
138
+ data.secret !== user.recoverSecret ||
139
+ (0, strtotime_1.default)('+' + this.tilmeld.config.pwRecoveryTimeLimit, Math.floor((user.recoverSecretDate ?? 0) / 1000)) *
140
+ 1000 <
141
+ Date.now()) {
142
+ return {
143
+ result: false,
144
+ message: 'The secret code does not match.',
145
+ };
146
+ }
147
+ if (!('password' in data) || !data.password.length) {
148
+ return { result: false, message: 'Password cannot be empty.' };
149
+ }
150
+ user.$password(data.password);
151
+ delete user.recoverSecret;
152
+ delete user.recoverSecretDate;
153
+ if (await user.$saveSkipAC()) {
154
+ return {
155
+ result: true,
156
+ message: 'Your password has been reset. You can now log in using your new password.',
157
+ };
158
+ }
159
+ else {
160
+ return { result: false, message: 'Error saving new password.' };
161
+ }
185
162
  }
186
163
  static getClientConfig() {
187
164
  return {
@@ -195,19 +172,17 @@ class User extends AbleObject_1.default {
195
172
  unverifiedAccess: this.tilmeld.config.unverifiedAccess,
196
173
  };
197
174
  }
198
- static loginUser(data) {
199
- return __awaiter(this, void 0, void 0, function* () {
200
- if (!('username' in data) || !data.username.length) {
201
- return { result: false, message: 'Incorrect login/password.' };
202
- }
203
- const user = yield this.tilmeld.User.factoryUsername(data.username);
204
- const result = user.$login(data);
205
- if (result.result) {
206
- user.$updateDataProtection();
207
- result.user = user;
208
- }
209
- return result;
210
- });
175
+ static async loginUser(data) {
176
+ if (!('username' in data) || !data.username.length) {
177
+ return { result: false, message: 'Incorrect login/password.' };
178
+ }
179
+ const user = await this.tilmeld.User.factoryUsername(data.username);
180
+ const result = user.$login(data);
181
+ if (result.result) {
182
+ user.$updateDataProtection();
183
+ result.user = user;
184
+ }
185
+ return result;
211
186
  }
212
187
  $login(data) {
213
188
  const tilmeld = this.$nymph.tilmeld;
@@ -223,14 +198,54 @@ class User extends AbleObject_1.default {
223
198
  if (!this.$checkPassword(data.password)) {
224
199
  return { result: false, message: 'Incorrect login/password.' };
225
200
  }
201
+ try {
202
+ for (let callback of this.constructor
203
+ .beforeLoginCallbacks) {
204
+ if (callback) {
205
+ callback(this, data);
206
+ }
207
+ }
208
+ }
209
+ catch (e) {
210
+ return {
211
+ result: false,
212
+ message: e.message,
213
+ };
214
+ }
226
215
  if (!tilmeld.login(this, true)) {
227
216
  return { result: false, message: 'Incorrect login/password.' };
228
217
  }
218
+ for (let callback of this.constructor
219
+ .afterLoginCallbacks) {
220
+ if (callback) {
221
+ callback(this);
222
+ }
223
+ }
229
224
  return { result: true, message: 'You are logged in.' };
230
225
  }
231
226
  $logout() {
232
227
  const tilmeld = this.$nymph.tilmeld;
228
+ try {
229
+ for (let callback of this.constructor
230
+ .beforeLogoutCallbacks) {
231
+ if (callback) {
232
+ callback(this);
233
+ }
234
+ }
235
+ }
236
+ catch (e) {
237
+ return {
238
+ result: false,
239
+ message: e.message,
240
+ };
241
+ }
233
242
  tilmeld.logout();
243
+ for (let callback of this.constructor
244
+ .afterLogoutCallbacks) {
245
+ if (callback) {
246
+ callback(this);
247
+ }
248
+ }
234
249
  return { result: true, message: 'You have been logged out.' };
235
250
  }
236
251
  $getAvatar() {
@@ -244,40 +259,35 @@ class User extends AbleObject_1.default {
244
259
  (0, md5_1.default)(this.$data.email.trim().toLowerCase()).toString() +
245
260
  '?d=identicon&s=40');
246
261
  }
247
- $getDescendantGroups() {
248
- var _a, _b;
249
- return __awaiter(this, void 0, void 0, function* () {
250
- if (this.$descendantGroups == null) {
251
- this.$descendantGroups = [];
252
- if (this.$data.group != null) {
253
- this.$descendantGroups = yield this.$data.group.$getDescendants();
254
- }
255
- for (let curGroup of (_a = this.$data.groups) !== null && _a !== void 0 ? _a : []) {
256
- this.$descendantGroups = (_b = this.$descendantGroups) === null || _b === void 0 ? void 0 : _b.concat(yield curGroup.$getDescendants());
257
- }
262
+ async $getDescendantGroups() {
263
+ if (this.$descendantGroups == null) {
264
+ this.$descendantGroups = [];
265
+ if (this.$data.group != null) {
266
+ this.$descendantGroups = await this.$data.group.$getDescendants();
267
+ }
268
+ for (let curGroup of this.$data.groups ?? []) {
269
+ this.$descendantGroups = this.$descendantGroups?.concat(await curGroup.$getDescendants());
258
270
  }
259
- return this.$descendantGroups;
260
- });
271
+ }
272
+ return this.$descendantGroups;
261
273
  }
262
274
  $getDescendantGroupsSync() {
263
- var _a, _b;
264
275
  if (this.$descendantGroups == null) {
265
276
  this.$descendantGroups = [];
266
277
  if (this.$data.group != null) {
267
278
  this.$descendantGroups = this.$data.group.$getDescendantsSync();
268
279
  }
269
- for (let curGroup of (_a = this.$data.groups) !== null && _a !== void 0 ? _a : []) {
270
- this.$descendantGroups = (_b = this.$descendantGroups) === null || _b === void 0 ? void 0 : _b.concat(curGroup.$getDescendantsSync());
280
+ for (let curGroup of this.$data.groups ?? []) {
281
+ this.$descendantGroups = this.$descendantGroups?.concat(curGroup.$getDescendantsSync());
271
282
  }
272
283
  }
273
284
  return this.$descendantGroups;
274
285
  }
275
286
  $jsonAcceptData(input, allowConflict = false) {
276
- var _a, _b;
277
287
  const tilmeld = this.$nymph.tilmeld;
278
288
  this.$referenceWake();
279
- if (((_a = input.data.abilities) === null || _a === void 0 ? void 0 : _a.indexOf('system/admin')) !== -1 &&
280
- ((_b = this.$data.abilities) === null || _b === void 0 ? void 0 : _b.indexOf('system/admin')) === -1 &&
289
+ if (input.data.abilities?.indexOf('system/admin') !== -1 &&
290
+ this.$data.abilities?.indexOf('system/admin') === -1 &&
281
291
  tilmeld.gatekeeper('tilmeld/admin') &&
282
292
  !tilmeld.gatekeeper('system/admin')) {
283
293
  throw new errors_1.BadDataError("You don't have the authority to make this user a system admin.");
@@ -286,11 +296,10 @@ class User extends AbleObject_1.default {
286
296
  super.$jsonAcceptData(input, allowConflict);
287
297
  }
288
298
  $jsonAcceptPatch(patch, allowConflict = false) {
289
- var _a, _b;
290
299
  const tilmeld = this.$nymph.tilmeld;
291
300
  this.$referenceWake();
292
- if (((_a = patch.set.abilities) === null || _a === void 0 ? void 0 : _a.indexOf('system/admin')) !== -1 &&
293
- ((_b = this.$data.abilities) === null || _b === void 0 ? void 0 : _b.indexOf('system/admin')) === -1 &&
301
+ if (patch.set.abilities?.indexOf('system/admin') !== -1 &&
302
+ this.$data.abilities?.indexOf('system/admin') === -1 &&
294
303
  tilmeld.gatekeeper('tilmeld/admin') &&
295
304
  !tilmeld.gatekeeper('system/admin')) {
296
305
  throw new errors_1.BadDataError("You don't have the authority to make this user a system admin.");
@@ -303,9 +312,8 @@ class User extends AbleObject_1.default {
303
312
  this.$updateDataProtection();
304
313
  }
305
314
  $updateDataProtection(givenUser) {
306
- var _a;
307
315
  const tilmeld = this.$nymph.tilmeld;
308
- let user = givenUser !== null && givenUser !== void 0 ? givenUser : tilmeld.User.current();
316
+ let user = givenUser ?? tilmeld.User.current();
309
317
  this.$clientEnabledMethods = [...User.DEFAULT_CLIENT_ENABLED_METHODS];
310
318
  this.$privateData = [...User.DEFAULT_PRIVATE_DATA];
311
319
  this.$allowlistData = [...User.DEFAULT_ALLOWLIST_DATA];
@@ -313,9 +321,9 @@ class User extends AbleObject_1.default {
313
321
  this.$privateData.push('username');
314
322
  }
315
323
  const isCurrentUser = user != null && user.$is(this);
316
- const abilities = (_a = (isCurrentUser || user == null
324
+ const abilities = (isCurrentUser || user == null
317
325
  ? this.$data.abilities
318
- : user === null || user === void 0 ? void 0 : user.abilities)) !== null && _a !== void 0 ? _a : [];
326
+ : user?.abilities) ?? [];
319
327
  const isNewUser = this.guid == null;
320
328
  if (isCurrentUser) {
321
329
  this.$clientEnabledMethods.push('$gatekeeper');
@@ -360,23 +368,22 @@ class User extends AbleObject_1.default {
360
368
  }
361
369
  }
362
370
  $gatekeeper(ability) {
363
- var _a, _b, _c, _d, _e, _f;
364
371
  const tilmeld = this.$nymph.tilmeld;
365
372
  if (ability == null) {
366
- return (_b = (_a = tilmeld.User.current()) === null || _a === void 0 ? void 0 : _a.$is(this)) !== null && _b !== void 0 ? _b : false;
373
+ return tilmeld.User.current()?.$is(this) ?? false;
367
374
  }
368
375
  if (this.$gatekeeperCache == null) {
369
- let abilities = (_c = this.$data.abilities) !== null && _c !== void 0 ? _c : [];
376
+ let abilities = this.$data.abilities ?? [];
370
377
  if (this.$data.inheritAbilities) {
371
- for (let curGroup of (_d = this.$data.groups) !== null && _d !== void 0 ? _d : []) {
378
+ for (let curGroup of this.$data.groups ?? []) {
372
379
  if (curGroup.enabled) {
373
- abilities = abilities.concat((_e = curGroup.abilities) !== null && _e !== void 0 ? _e : []);
380
+ abilities = abilities.concat(curGroup.abilities ?? []);
374
381
  }
375
382
  }
376
383
  if (this.$data.group != null &&
377
384
  this.$data.group.cdate != null &&
378
385
  this.$data.group.enabled) {
379
- abilities = abilities.concat((_f = this.$data.group.abilities) !== null && _f !== void 0 ? _f : []);
386
+ abilities = abilities.concat(this.$data.group.abilities ?? []);
380
387
  }
381
388
  }
382
389
  this.$gatekeeperCache = Object.fromEntries(abilities.map((ability) => [ability, true]));
@@ -390,72 +397,69 @@ class User extends AbleObject_1.default {
390
397
  this.$gatekeeperCache = undefined;
391
398
  return ret;
392
399
  }
393
- $sendEmailVerification() {
394
- var _a, _b, _c, _d, _e, _f, _g;
395
- return __awaiter(this, void 0, void 0, function* () {
396
- const tilmeld = this.$nymph.tilmeld;
397
- if (this.guid == null) {
398
- return false;
399
- }
400
- let success = true;
401
- const verifyUrl = `${tilmeld.config.appUrl.replace(/\/$/, () => '')}${tilmeld.config.setupPath}/verify`;
402
- if (this.$data.secret != null) {
403
- const link = `${verifyUrl}?action=verify&id=${encodeURIComponent(this.guid)}&secret=${encodeURIComponent(this.$data.secret)}`;
404
- success =
405
- success &&
406
- (yield tilmeld.config.sendEmail(tilmeld, {
407
- template: 'VerifyEmail',
408
- message: {
409
- to: {
410
- name: (_a = this.$data.name) !== null && _a !== void 0 ? _a : '',
411
- address: (_b = this.$data.email) !== null && _b !== void 0 ? _b : '',
412
- },
413
- },
414
- locals: {
415
- verifyLink: link,
416
- },
417
- }, this));
418
- }
419
- if (this.$data.newEmailSecret != null) {
420
- const link = `${verifyUrl}?action=verifychange&id=${encodeURIComponent(this.guid)}&secret=${encodeURIComponent(this.$data.newEmailSecret)}`;
421
- success =
422
- success &&
423
- (yield tilmeld.config.sendEmail(tilmeld, {
424
- template: 'VerifyEmailChange',
425
- message: {
426
- to: {
427
- name: (_c = this.$data.name) !== null && _c !== void 0 ? _c : '',
428
- address: (_d = this.$data.newEmailAddress) !== null && _d !== void 0 ? _d : '',
429
- },
430
- },
431
- locals: {
432
- verifyLink: link,
433
- oldEmail: this.$data.cancelEmailAddress,
434
- newEmail: this.$data.newEmailAddress,
400
+ async $sendEmailVerification() {
401
+ const tilmeld = this.$nymph.tilmeld;
402
+ if (this.guid == null) {
403
+ return false;
404
+ }
405
+ let success = true;
406
+ const verifyUrl = `${tilmeld.config.appUrl.replace(/\/$/, () => '')}${tilmeld.config.setupPath}/verify`;
407
+ if (this.$data.secret != null) {
408
+ const link = `${verifyUrl}?action=verify&id=${encodeURIComponent(this.guid)}&secret=${encodeURIComponent(this.$data.secret)}`;
409
+ success =
410
+ success &&
411
+ (await tilmeld.config.sendEmail(tilmeld, {
412
+ template: 'VerifyEmail',
413
+ message: {
414
+ to: {
415
+ name: this.$data.name ?? '',
416
+ address: this.$data.email ?? '',
435
417
  },
436
- }, this));
437
- }
438
- if (this.$data.cancelEmailSecret != null) {
439
- const link = `${verifyUrl}?action=cancelchange&id=${encodeURIComponent(this.guid)}&secret=${encodeURIComponent(this.$data.cancelEmailSecret)}`;
440
- success =
441
- success &&
442
- (yield tilmeld.config.sendEmail(tilmeld, {
443
- template: 'CancelEmailChange',
444
- message: {
445
- to: {
446
- name: (_e = this.$data.name) !== null && _e !== void 0 ? _e : '',
447
- address: (_f = this.$data.cancelEmailAddress) !== null && _f !== void 0 ? _f : '',
448
- },
418
+ },
419
+ locals: {
420
+ verifyLink: link,
421
+ },
422
+ }, this));
423
+ }
424
+ if (this.$data.newEmailSecret != null) {
425
+ const link = `${verifyUrl}?action=verifychange&id=${encodeURIComponent(this.guid)}&secret=${encodeURIComponent(this.$data.newEmailSecret)}`;
426
+ success =
427
+ success &&
428
+ (await tilmeld.config.sendEmail(tilmeld, {
429
+ template: 'VerifyEmailChange',
430
+ message: {
431
+ to: {
432
+ name: this.$data.name ?? '',
433
+ address: this.$data.newEmailAddress ?? '',
449
434
  },
450
- locals: {
451
- cancelLink: link,
452
- oldEmail: this.$data.cancelEmailAddress,
453
- newEmail: (_g = this.$data.newEmailAddress) !== null && _g !== void 0 ? _g : this.$data.email,
435
+ },
436
+ locals: {
437
+ verifyLink: link,
438
+ oldEmail: this.$data.cancelEmailAddress,
439
+ newEmail: this.$data.newEmailAddress,
440
+ },
441
+ }, this));
442
+ }
443
+ if (this.$data.cancelEmailSecret != null) {
444
+ const link = `${verifyUrl}?action=cancelchange&id=${encodeURIComponent(this.guid)}&secret=${encodeURIComponent(this.$data.cancelEmailSecret)}`;
445
+ success =
446
+ success &&
447
+ (await tilmeld.config.sendEmail(tilmeld, {
448
+ template: 'CancelEmailChange',
449
+ message: {
450
+ to: {
451
+ name: this.$data.name ?? '',
452
+ address: this.$data.cancelEmailAddress ?? '',
454
453
  },
455
- }, this));
456
- }
457
- return success;
458
- });
454
+ },
455
+ locals: {
456
+ cancelLink: link,
457
+ oldEmail: this.$data.cancelEmailAddress,
458
+ newEmail: this.$data.newEmailAddress ?? this.$data.email,
459
+ },
460
+ }, this));
461
+ }
462
+ return success;
459
463
  }
460
464
  $addGroup(group) {
461
465
  if (this.$data.groups == null) {
@@ -494,50 +498,45 @@ class User extends AbleObject_1.default {
494
498
  return true;
495
499
  }
496
500
  $inGroup(group) {
497
- var _a, _b, _c;
498
501
  if (typeof group === 'string') {
499
- if (((_a = this.$data.group) === null || _a === void 0 ? void 0 : _a.guid) === group) {
502
+ if (this.$data.group?.guid === group) {
500
503
  return true;
501
504
  }
502
- for (let curGroup of (_b = this.$data.groups) !== null && _b !== void 0 ? _b : []) {
505
+ for (let curGroup of this.$data.groups ?? []) {
503
506
  if (curGroup.guid === group) {
504
507
  return true;
505
508
  }
506
509
  }
507
510
  return false;
508
511
  }
509
- return (group.$is(this.$data.group) || group.$inArray((_c = this.$data.groups) !== null && _c !== void 0 ? _c : []));
512
+ return (group.$is(this.$data.group) || group.$inArray(this.$data.groups ?? []));
510
513
  }
511
514
  $isDescendant(group) {
512
- var _a, _b;
513
- if (((_a = this.$data.group) === null || _a === void 0 ? void 0 : _a.cdate) != null &&
515
+ if (this.$data.group?.cdate != null &&
514
516
  this.$data.group.$isDescendant(group)) {
515
517
  return true;
516
518
  }
517
- for (let curGroup of (_b = this.$data.groups) !== null && _b !== void 0 ? _b : []) {
519
+ for (let curGroup of this.$data.groups ?? []) {
518
520
  if (curGroup.$isDescendant(group)) {
519
521
  return true;
520
522
  }
521
523
  }
522
524
  return false;
523
525
  }
524
- $changePassword(data) {
525
- var _a;
526
- return __awaiter(this, void 0, void 0, function* () {
527
- if (!('newPassword' in data) || !data.newPassword.length) {
528
- return { result: false, message: 'Please specify a password.' };
529
- }
530
- if (!this.$checkPassword((_a = data.currentPassword) !== null && _a !== void 0 ? _a : '')) {
531
- return { result: false, message: 'Incorrect password.' };
532
- }
533
- this.$data.passwordTemp = data.newPassword;
534
- if (yield this.$save()) {
535
- return { result: true, message: 'Your password has been changed.' };
536
- }
537
- else {
538
- return { result: false, message: "Couldn't save new password." };
539
- }
540
- });
526
+ async $changePassword(data) {
527
+ if (!('newPassword' in data) || !data.newPassword.length) {
528
+ return { result: false, message: 'Please specify a password.' };
529
+ }
530
+ if (!this.$checkPassword(data.currentPassword ?? '')) {
531
+ return { result: false, message: 'Incorrect password.' };
532
+ }
533
+ this.$data.passwordTemp = data.newPassword;
534
+ if (await this.$save()) {
535
+ return { result: true, message: 'Your password has been changed.' };
536
+ }
537
+ else {
538
+ return { result: false, message: "Couldn't save new password." };
539
+ }
541
540
  }
542
541
  $password(password) {
543
542
  const tilmeld = this.$nymph.tilmeld;
@@ -552,554 +551,574 @@ class User extends AbleObject_1.default {
552
551
  break;
553
552
  case 'salt':
554
553
  default:
555
- this.$data.salt = (0, nanoid_1.nanoid)();
554
+ this.$data.salt = (0, guid_1.nanoid)();
556
555
  this.$data.password = (0, sha256_1.default)(password + this.$data.salt).toString(enc_base64_1.default);
557
556
  break;
558
557
  }
559
558
  return this.$data.password;
560
559
  }
561
- $checkUsername() {
562
- return __awaiter(this, void 0, void 0, function* () {
563
- const tilmeld = this.$nymph.tilmeld;
564
- if (!tilmeld.config.emailUsernames) {
565
- if (this.$data.username == null || !this.$data.username.length) {
566
- return { result: false, message: 'Please specify a username.' };
567
- }
568
- if (tilmeld.config.maxUsernameLength > 0 &&
569
- this.$data.username.length > tilmeld.config.maxUsernameLength) {
570
- return {
571
- result: false,
572
- message: 'Usernames must not exceed ' +
573
- tilmeld.config.maxUsernameLength +
574
- ' characters.',
575
- };
576
- }
577
- if ((0, lodash_1.difference)(this.$data.username.split(''), tilmeld.config.validChars.split('')).length) {
578
- return {
579
- result: false,
580
- message: tilmeld.config.validCharsNotice,
581
- };
582
- }
583
- if (!tilmeld.config.validRegex.test(this.$data.username)) {
584
- return {
585
- result: false,
586
- message: tilmeld.config.validRegexNotice,
587
- };
588
- }
589
- const selector = {
590
- type: '&',
591
- ilike: [
592
- 'username',
593
- this.$data.username.replace(/([\\%_])/g, (s) => `\\${s}`),
594
- ],
595
- };
596
- if (this.guid != null) {
597
- selector['!guid'] = this.guid;
598
- }
599
- const test = yield this.$nymph.getEntity({ class: tilmeld.User, skipAc: true }, selector);
600
- if (test != null) {
601
- return { result: false, message: 'That username is taken.' };
602
- }
560
+ async $checkUsername() {
561
+ const tilmeld = this.$nymph.tilmeld;
562
+ if (!tilmeld.config.emailUsernames) {
563
+ if (this.$data.username == null || !this.$data.username.length) {
564
+ return { result: false, message: 'Please specify a username.' };
565
+ }
566
+ if (tilmeld.config.maxUsernameLength > 0 &&
567
+ this.$data.username.length > tilmeld.config.maxUsernameLength) {
603
568
  return {
604
- result: true,
605
- message: this.guid != null ? 'Username is valid.' : 'Username is available!',
569
+ result: false,
570
+ message: 'Usernames must not exceed ' +
571
+ tilmeld.config.maxUsernameLength +
572
+ ' characters.',
606
573
  };
607
574
  }
608
- else {
609
- this.$data.email = this.$data.username;
610
- if (this.$data.username == null || !this.$data.username.length) {
611
- return { result: false, message: 'Please specify an email.' };
612
- }
613
- if (tilmeld.config.maxUsernameLength > 0 &&
614
- this.$data.username.length > tilmeld.config.maxUsernameLength) {
615
- return {
616
- result: false,
617
- message: 'Emails must not exceed ' +
618
- tilmeld.config.maxUsernameLength +
619
- ' characters.',
620
- };
621
- }
622
- return yield this.$checkEmail();
623
- }
624
- });
625
- }
626
- $checkEmail() {
627
- return __awaiter(this, void 0, void 0, function* () {
628
- const tilmeld = this.$nymph.tilmeld;
629
- if (this.$data.email == null || !this.$data.email.length) {
630
- if (tilmeld.config.verifyEmail) {
631
- return { result: false, message: 'Please specify an email.' };
632
- }
633
- else {
634
- return { result: true, message: '' };
635
- }
575
+ if ((0, lodash_1.difference)(this.$data.username.split(''), tilmeld.config.validChars.split('')).length) {
576
+ return {
577
+ result: false,
578
+ message: tilmeld.config.validCharsNotice,
579
+ };
636
580
  }
637
- if (!tilmeld.config.validEmailRegex.test(this.$data.email)) {
581
+ if (!tilmeld.config.validRegex.test(this.$data.username)) {
638
582
  return {
639
583
  result: false,
640
- message: tilmeld.config.validEmailRegexNotice,
584
+ message: tilmeld.config.validRegexNotice,
641
585
  };
642
586
  }
643
587
  const selector = {
644
588
  type: '&',
645
- ilike: ['email', this.$data.email.replace(/([\\%_])/g, (s) => `\\${s}`)],
589
+ ilike: [
590
+ 'username',
591
+ this.$data.username.replace(/([\\%_])/g, (s) => `\\${s}`),
592
+ ],
646
593
  };
647
594
  if (this.guid != null) {
648
595
  selector['!guid'] = this.guid;
649
596
  }
650
- const test = yield this.$nymph.getEntity({ class: tilmeld.User, skipAc: true }, selector);
597
+ const test = await this.$nymph.getEntity({ class: tilmeld.User, skipAc: true }, selector);
651
598
  if (test != null) {
652
- return {
653
- result: false,
654
- message: 'That email address is already registered.',
655
- };
599
+ return { result: false, message: 'That username is taken.' };
656
600
  }
657
601
  return {
658
602
  result: true,
659
- message: this.guid != null ? 'Email is valid.' : 'Email address is valid!',
603
+ message: this.guid != null ? 'Username is valid.' : 'Username is available!',
660
604
  };
661
- });
662
- }
663
- $checkPhone() {
664
- return __awaiter(this, void 0, void 0, function* () {
665
- const tilmeld = this.$nymph.tilmeld;
666
- if (this.$data.phone == null || !this.$data.phone.length) {
667
- return { result: false, message: 'Please specify a phone number.' };
605
+ }
606
+ else {
607
+ this.$data.email = this.$data.username;
608
+ if (this.$data.username == null || !this.$data.username.length) {
609
+ return { result: false, message: 'Please specify an email.' };
668
610
  }
669
- const stripToDigits = this.$data.phone.replace(/\D/g, () => '');
670
- if (!/\d{10}/.test(stripToDigits)) {
611
+ if (tilmeld.config.maxUsernameLength > 0 &&
612
+ this.$data.username.length > tilmeld.config.maxUsernameLength) {
671
613
  return {
672
614
  result: false,
673
- message: 'Phone must contain at least 10 digits, but formatting does not matter.',
615
+ message: 'Emails must not exceed ' +
616
+ tilmeld.config.maxUsernameLength +
617
+ ' characters.',
674
618
  };
675
619
  }
676
- const selector = {
677
- type: '&',
678
- equal: ['phone', stripToDigits],
679
- };
680
- if (this.guid != null) {
681
- selector['!guid'] = this.guid;
620
+ return await this.$checkEmail();
621
+ }
622
+ }
623
+ async $checkEmail() {
624
+ const tilmeld = this.$nymph.tilmeld;
625
+ if (this.$data.email == null || !this.$data.email.length) {
626
+ if (tilmeld.config.verifyEmail) {
627
+ return { result: false, message: 'Please specify an email.' };
682
628
  }
683
- const test = yield this.$nymph.getEntity({ class: tilmeld.User, skipAc: true }, selector);
684
- if (test != null) {
685
- return { result: false, message: 'Phone number is in use.' };
629
+ else {
630
+ return { result: true, message: '' };
686
631
  }
632
+ }
633
+ if (!tilmeld.config.validEmailRegex.test(this.$data.email)) {
687
634
  return {
688
- result: true,
689
- message: this.guid != null ? 'Phone number is valid.' : 'Phone number is valid!',
635
+ result: false,
636
+ message: tilmeld.config.validEmailRegexNotice,
637
+ };
638
+ }
639
+ const selector = {
640
+ type: '&',
641
+ ilike: ['email', this.$data.email.replace(/([\\%_])/g, (s) => `\\${s}`)],
642
+ };
643
+ if (this.guid != null) {
644
+ selector['!guid'] = this.guid;
645
+ }
646
+ const test = await this.$nymph.getEntity({ class: tilmeld.User, skipAc: true }, selector);
647
+ if (test != null) {
648
+ return {
649
+ result: false,
650
+ message: 'That email address is already registered.',
690
651
  };
691
- });
652
+ }
653
+ return {
654
+ result: true,
655
+ message: this.guid != null ? 'Email is valid.' : 'Email address is valid!',
656
+ };
692
657
  }
693
- $register(data) {
694
- return __awaiter(this, void 0, void 0, function* () {
695
- const tilmeld = this.$nymph.tilmeld;
696
- if (!tilmeld.config.allowRegistration) {
697
- return {
698
- result: false,
699
- loggedin: false,
700
- message: 'Registration is not allowed.',
701
- };
658
+ async $checkPhone() {
659
+ const tilmeld = this.$nymph.tilmeld;
660
+ if (this.$data.phone == null || !this.$data.phone.length) {
661
+ return { result: false, message: 'Please specify a phone number.' };
662
+ }
663
+ const stripToDigits = this.$data.phone.replace(/\D/g, () => '');
664
+ if (!/\d{10}/.test(stripToDigits)) {
665
+ return {
666
+ result: false,
667
+ message: 'Phone must contain at least 10 digits, but formatting does not matter.',
668
+ };
669
+ }
670
+ const selector = {
671
+ type: '&',
672
+ equal: ['phone', stripToDigits],
673
+ };
674
+ if (this.guid != null) {
675
+ selector['!guid'] = this.guid;
676
+ }
677
+ const test = await this.$nymph.getEntity({ class: tilmeld.User, skipAc: true }, selector);
678
+ if (test != null) {
679
+ return { result: false, message: 'Phone number is in use.' };
680
+ }
681
+ return {
682
+ result: true,
683
+ message: this.guid != null ? 'Phone number is valid.' : 'Phone number is valid!',
684
+ };
685
+ }
686
+ async $register(data) {
687
+ let tilmeld = this.$nymph.tilmeld;
688
+ if (!tilmeld.config.allowRegistration) {
689
+ return {
690
+ result: false,
691
+ loggedin: false,
692
+ message: 'Registration is not allowed.',
693
+ };
694
+ }
695
+ if (this.guid != null) {
696
+ return {
697
+ result: false,
698
+ loggedin: false,
699
+ message: 'This is already a registered user.',
700
+ };
701
+ }
702
+ try {
703
+ for (let callback of this.constructor
704
+ .beforeRegisterCallbacks) {
705
+ if (callback) {
706
+ await callback(this, data);
707
+ }
702
708
  }
703
- if (this.guid != null) {
704
- return {
705
- result: false,
706
- loggedin: false,
707
- message: 'This is already a registered user.',
708
- };
709
+ }
710
+ catch (e) {
711
+ return {
712
+ result: false,
713
+ loggedin: false,
714
+ message: e.message,
715
+ };
716
+ }
717
+ if (!('password' in data) || !data.password.length) {
718
+ return {
719
+ result: false,
720
+ loggedin: false,
721
+ message: 'Password is a required field.',
722
+ };
723
+ }
724
+ const unCheck = await this.$checkUsername();
725
+ if (!unCheck.result) {
726
+ return { ...unCheck, loggedin: false };
727
+ }
728
+ this.$password(data.password);
729
+ if (tilmeld.config.regFields.indexOf('name') !== -1) {
730
+ this.$data.name =
731
+ this.$data.nameFirst +
732
+ (this.$data.nameMiddle == null ? '' : ' ' + this.$data.nameMiddle) +
733
+ (this.$data.nameLast == null ? '' : ' ' + this.$data.nameLast);
734
+ if (this.$data.name === '') {
735
+ this.$data.name = this.$data.username;
709
736
  }
710
- if (!('password' in data) || !data.password.length) {
711
- return {
712
- result: false,
713
- loggedin: false,
714
- message: 'Password is a required field.',
715
- };
737
+ }
738
+ if (tilmeld.config.emailUsernames) {
739
+ this.$data.email = this.$data.username;
740
+ }
741
+ const transaction = 'tilmeld-register-' + (0, guid_1.nanoid)();
742
+ const nymph = this.$nymph;
743
+ const tnymph = await this.$nymph.startTransaction(transaction);
744
+ this.$nymph = tnymph;
745
+ tilmeld = this.$nymph.tilmeld;
746
+ try {
747
+ let generatedPrimaryGroup = null;
748
+ if (tilmeld.config.generatePrimary) {
749
+ generatedPrimaryGroup = await tilmeld.Group.factory();
750
+ generatedPrimaryGroup.groupname = this.$data.username;
751
+ generatedPrimaryGroup.avatar = this.$data.avatar;
752
+ generatedPrimaryGroup.name = this.$data.name;
753
+ generatedPrimaryGroup.email = this.$data.email;
754
+ const parent = await tnymph.getEntity({ class: tilmeld.Group }, {
755
+ type: '&',
756
+ equal: ['defaultPrimary', true],
757
+ });
758
+ if (parent != null) {
759
+ generatedPrimaryGroup.parent = parent;
760
+ }
761
+ if (!(await generatedPrimaryGroup.$saveSkipAC())) {
762
+ await tnymph.rollback(transaction);
763
+ this.$nymph = nymph;
764
+ return {
765
+ result: false,
766
+ loggedin: false,
767
+ message: 'Error creating primary group for user.',
768
+ };
769
+ }
770
+ this.$data.group = generatedPrimaryGroup;
771
+ }
772
+ else {
773
+ const group = await tnymph.getEntity({ class: tilmeld.Group }, {
774
+ type: '&',
775
+ equal: ['defaultPrimary', true],
776
+ });
777
+ if (group != null) {
778
+ this.$data.group = group;
779
+ }
780
+ }
781
+ if (tilmeld.config.verifyEmail && tilmeld.config.unverifiedAccess) {
782
+ this.$data.groups = await tnymph.getEntities({ class: tilmeld.Group }, {
783
+ type: '&',
784
+ equal: ['unverifiedSecondary', true],
785
+ });
716
786
  }
717
- const unCheck = yield this.$checkUsername();
718
- if (!unCheck.result) {
719
- return Object.assign(Object.assign({}, unCheck), { loggedin: false });
787
+ else {
788
+ this.$data.groups = await tnymph.getEntities({ class: tilmeld.Group }, {
789
+ type: '&',
790
+ equal: ['defaultSecondary', true],
791
+ });
720
792
  }
721
- this.$password(data.password);
722
- if (tilmeld.config.regFields.indexOf('name') !== -1) {
723
- this.$data.name =
724
- this.$data.nameFirst +
725
- (this.$data.nameMiddle == null ? '' : ' ' + this.$data.nameMiddle) +
726
- (this.$data.nameLast == null ? '' : ' ' + this.$data.nameLast);
727
- if (this.$data.name === '') {
728
- this.$data.name = this.$data.username;
793
+ if (tilmeld.config.verifyEmail) {
794
+ if (!tilmeld.config.unverifiedAccess) {
795
+ this.$data.enabled = false;
729
796
  }
730
797
  }
731
- if (tilmeld.config.emailUsernames) {
732
- this.$data.email = this.$data.username;
798
+ else {
799
+ this.$data.enabled = true;
800
+ }
801
+ let madeAdmin = false;
802
+ if (tilmeld.config.createAdmin) {
803
+ const otherUsers = await tnymph.getEntities({
804
+ class: tilmeld.User,
805
+ skipAc: true,
806
+ limit: 1,
807
+ return: 'guid',
808
+ });
809
+ if (!otherUsers.length) {
810
+ this.$grant('system/admin');
811
+ this.$data.enabled = true;
812
+ madeAdmin = true;
813
+ }
733
814
  }
734
- const transaction = 'tilmeld-register-' + (0, nanoid_1.nanoid)();
735
- const nymph = this.$nymph;
736
- const tnymph = yield this.$nymph.startTransaction(transaction);
737
- this.$nymph = tnymph;
738
- try {
739
- let generatedPrimaryGroup = null;
740
- if (tilmeld.config.generatePrimary) {
741
- generatedPrimaryGroup = yield tilmeld.Group.factory();
742
- generatedPrimaryGroup.groupname = this.$data.username;
743
- generatedPrimaryGroup.avatar = this.$data.avatar;
744
- generatedPrimaryGroup.name = this.$data.name;
745
- generatedPrimaryGroup.email = this.$data.email;
746
- const parent = yield tnymph.getEntity({ class: tilmeld.Group }, {
747
- type: '&',
748
- equal: ['defaultPrimary', true],
749
- });
750
- if (parent != null) {
751
- generatedPrimaryGroup.parent = parent;
752
- }
753
- if (!(yield generatedPrimaryGroup.$saveSkipAC())) {
754
- yield tnymph.rollback(transaction);
815
+ if (await this.$saveSkipAC()) {
816
+ if (tilmeld.config.userRegisteredRecipient != null) {
817
+ await tilmeld.config.sendEmail(tilmeld, {
818
+ template: 'UserRegistered',
819
+ message: {
820
+ to: tilmeld.config.userRegisteredRecipient,
821
+ },
822
+ locals: {
823
+ userUsername: this.$data.username,
824
+ userName: this.$data.name,
825
+ userFirstName: this.$data.nameFirst,
826
+ userLastName: this.$data.nameLast,
827
+ userEmail: this.$data.email,
828
+ userPhone: this.$data.phone,
829
+ },
830
+ }, this);
831
+ }
832
+ let message = '';
833
+ let loggedin = false;
834
+ if (generatedPrimaryGroup != null) {
835
+ generatedPrimaryGroup.user = this;
836
+ if (!(await generatedPrimaryGroup.$saveSkipAC())) {
837
+ await tnymph.rollback(transaction);
755
838
  this.$nymph = nymph;
756
839
  return {
757
840
  result: false,
758
841
  loggedin: false,
759
- message: 'Error creating primary group for user.',
842
+ message: 'Your primary group could not be assigned. Please try again later.',
760
843
  };
761
844
  }
762
- this.$data.group = generatedPrimaryGroup;
763
- }
764
- else {
765
- const group = yield tnymph.getEntity({ class: tilmeld.Group }, {
766
- type: '&',
767
- equal: ['defaultPrimary', true],
768
- });
769
- if (group != null) {
770
- this.$data.group = group;
771
- }
772
845
  }
773
- if (tilmeld.config.verifyEmail && tilmeld.config.unverifiedAccess) {
774
- this.$data.groups = yield tnymph.getEntities({ class: tilmeld.Group }, {
775
- type: '&',
776
- equal: ['unverifiedSecondary', true],
777
- });
778
- }
779
- else {
780
- this.$data.groups = yield tnymph.getEntities({ class: tilmeld.Group }, {
781
- type: '&',
782
- equal: ['defaultSecondary', true],
783
- });
846
+ if (tilmeld.config.verifyEmail &&
847
+ !tilmeld.config.unverifiedAccess &&
848
+ !madeAdmin) {
849
+ message +=
850
+ `Almost there. An email has been sent to ${this.$data.email} ` +
851
+ 'with a verification link for you to finish registration.';
784
852
  }
785
- if (tilmeld.config.verifyEmail) {
786
- if (!tilmeld.config.unverifiedAccess) {
787
- this.$data.enabled = false;
853
+ else if (tilmeld.config.verifyEmail &&
854
+ tilmeld.config.unverifiedAccess &&
855
+ !madeAdmin) {
856
+ if (!tilmeld.login(this, true)) {
857
+ throw new Error('An error occurred trying to log you in.');
788
858
  }
859
+ message +=
860
+ "You're now logged in! An email has been sent to " +
861
+ `${this.$data.email} with a verification link for you to finish ` +
862
+ 'registration.';
863
+ loggedin = true;
789
864
  }
790
865
  else {
791
- this.$data.enabled = true;
792
- }
793
- let madeAdmin = false;
794
- if (tilmeld.config.createAdmin) {
795
- const otherUsers = yield tnymph.getEntities({
796
- class: tilmeld.User,
797
- skipAc: true,
798
- limit: 1,
799
- return: 'guid',
800
- });
801
- if (!otherUsers.length) {
802
- this.$grant('system/admin');
803
- this.$data.enabled = true;
804
- madeAdmin = true;
866
+ if (!tilmeld.login(this, true)) {
867
+ throw new Error('An error occurred trying to log you in.');
805
868
  }
869
+ message += "You're now registered and logged in!";
870
+ loggedin = true;
806
871
  }
807
- if (yield this.$saveSkipAC()) {
808
- if (tilmeld.config.userRegisteredRecipient != null) {
809
- yield tilmeld.config.sendEmail(tilmeld, {
810
- template: 'UserRegistered',
811
- message: {
812
- to: tilmeld.config.userRegisteredRecipient,
813
- },
814
- locals: {
815
- userUsername: this.$data.username,
816
- userName: this.$data.name,
817
- userFirstName: this.$data.nameFirst,
818
- userLastName: this.$data.nameLast,
819
- userEmail: this.$data.email,
820
- userPhone: this.$data.phone,
821
- },
822
- }, this);
823
- }
824
- let message = '';
825
- let loggedin = false;
826
- if (generatedPrimaryGroup != null) {
827
- generatedPrimaryGroup.user = this;
828
- if (!(yield generatedPrimaryGroup.$saveSkipAC())) {
829
- yield tnymph.rollback(transaction);
830
- this.$nymph = nymph;
831
- return {
832
- result: false,
833
- loggedin: false,
834
- message: 'Your primary group could not be assigned. Please try again later.',
835
- };
836
- }
872
+ for (let callback of this.constructor
873
+ .afterRegisterCallbacks) {
874
+ if (callback) {
875
+ await callback(this, {
876
+ loggedin,
877
+ message,
878
+ });
837
879
  }
838
- if (tilmeld.config.verifyEmail &&
839
- !tilmeld.config.unverifiedAccess &&
840
- !madeAdmin) {
841
- message +=
842
- `Almost there. An email has been sent to ${this.$data.email} ` +
843
- 'with a verification link for you to finish registration.';
844
- }
845
- else if (tilmeld.config.verifyEmail &&
846
- tilmeld.config.unverifiedAccess &&
847
- !madeAdmin) {
848
- tilmeld.login(this, true);
849
- message +=
850
- "You're now logged in! An email has been sent to " +
851
- `${this.$data.email} with a verification link for you to finish ` +
852
- 'registration.';
853
- loggedin = true;
854
- }
855
- else {
856
- tilmeld.login(this, true);
857
- message += "You're now registered and logged in!";
858
- loggedin = true;
859
- }
860
- yield tnymph.commit(transaction);
861
- this.$nymph = nymph;
862
- return {
863
- result: true,
864
- loggedin,
865
- message,
866
- };
867
880
  }
868
- else {
869
- yield tnymph.rollback(transaction);
881
+ try {
882
+ await tnymph.commit(transaction);
870
883
  this.$nymph = nymph;
871
- return {
872
- result: false,
873
- loggedin: false,
874
- message: 'Error registering user.',
875
- };
884
+ this.$nymph.tilmeld?.fillSession(this);
885
+ }
886
+ catch (e) {
887
+ throw e;
876
888
  }
889
+ return {
890
+ result: true,
891
+ loggedin,
892
+ message,
893
+ };
877
894
  }
878
- catch (e) {
879
- yield tnymph.rollback(transaction);
895
+ else {
896
+ await tnymph.rollback(transaction);
880
897
  this.$nymph = nymph;
881
- throw e;
898
+ return {
899
+ result: false,
900
+ loggedin: false,
901
+ message: 'Error registering user.',
902
+ };
882
903
  }
883
- });
904
+ }
905
+ catch (e) {
906
+ await tnymph.rollback(transaction);
907
+ this.$nymph = nymph;
908
+ throw e;
909
+ }
884
910
  }
885
- $save() {
886
- const _super = Object.create(null, {
887
- $save: { get: () => super.$save }
888
- });
889
- var _a, _b, _c, _d, _e, _f;
890
- return __awaiter(this, void 0, void 0, function* () {
891
- const tilmeld = this.$nymph.tilmeld;
892
- if (this.$data.username == null || !this.$data.username.trim().length) {
893
- return false;
894
- }
895
- if (tilmeld.gatekeeper('tilmeld/admin') &&
896
- !tilmeld.gatekeeper('system/admin') &&
897
- this.$gatekeeper('system/admin')) {
898
- throw new errors_1.BadDataError("You don't have the authority to modify system admins.");
899
- }
900
- let sendVerification = false;
901
- this.$data.username = this.$data.username.trim();
902
- if (tilmeld.config.emailUsernames) {
903
- this.$data.email = this.$data.username;
904
- }
905
- this.$data.nameFirst = ((_a = this.$data.nameFirst) !== null && _a !== void 0 ? _a : '').trim();
906
- this.$data.nameMiddle = ((_b = this.$data.nameMiddle) !== null && _b !== void 0 ? _b : '').trim();
907
- this.$data.nameLast = ((_c = this.$data.nameLast) !== null && _c !== void 0 ? _c : '').trim();
908
- this.$data.phone = ((_d = this.$data.phone) !== null && _d !== void 0 ? _d : '').trim();
909
- this.$data.name =
910
- this.$data.nameFirst +
911
- (this.$data.nameMiddle ? ' ' + this.$data.nameMiddle : '') +
912
- (this.$data.nameLast ? ' ' + this.$data.nameLast : '');
913
- this.$data.enabled = !!this.$data.enabled;
914
- if (this.$data.nameFirst === '') {
915
- delete this.$data.nameFirst;
916
- }
917
- if (this.$data.nameMiddle === '') {
918
- delete this.$data.nameMiddle;
919
- }
920
- if (this.$data.nameLast === '') {
921
- delete this.$data.nameLast;
922
- }
923
- if (this.$data.name === '') {
924
- delete this.$data.name;
925
- }
926
- if (this.$data.email === '') {
927
- delete this.$data.email;
928
- }
929
- if (this.$data.avatar === '') {
930
- delete this.$data.avatar;
931
- }
932
- if (this.$data.phone === '') {
933
- delete this.$data.phone;
934
- }
935
- if (this.$data.secret === '') {
936
- delete this.$data.secret;
937
- }
938
- if (this.$data.emailChangeDate === 0) {
939
- delete this.$data.emailChangeDate;
940
- }
941
- if (this.$data.newEmailSecret === '') {
942
- delete this.$data.newEmailSecret;
943
- }
944
- if (this.$data.newEmailAddress === '') {
945
- delete this.$data.newEmailAddress;
946
- }
947
- if (this.$data.cancelEmailSecret === '') {
948
- delete this.$data.cancelEmailSecret;
949
- }
950
- if (this.$data.cancelEmailAddress === '') {
951
- delete this.$data.cancelEmailAddress;
952
- }
953
- if (this.$data.recoverSecret === '') {
954
- delete this.$data.recoverSecret;
955
- }
956
- if (this.$data.recoverSecretDate === 0) {
957
- delete this.$data.recoverSecretDate;
958
- }
959
- if (this.$data.password === '') {
960
- delete this.$data.password;
961
- }
962
- if (this.$data.passwordTemp === '') {
963
- delete this.$data.passwordTemp;
964
- }
965
- if (this.$data.inheritAbilities === false) {
966
- delete this.$data.inheritAbilities;
967
- }
968
- const unCheck = yield this.$checkUsername();
969
- if (!unCheck.result) {
970
- throw new errors_1.BadUsernameError(unCheck.message);
911
+ async $save() {
912
+ let tilmeld = this.$nymph.tilmeld;
913
+ if (this.$data.username == null || !this.$data.username.trim().length) {
914
+ return false;
915
+ }
916
+ if (tilmeld.gatekeeper('tilmeld/admin') &&
917
+ !tilmeld.gatekeeper('system/admin') &&
918
+ this.$gatekeeper('system/admin')) {
919
+ throw new errors_1.BadDataError("You don't have the authority to modify system admins.");
920
+ }
921
+ let sendVerification = false;
922
+ this.$data.username = this.$data.username.trim();
923
+ if (tilmeld.config.emailUsernames) {
924
+ this.$data.email = this.$data.username;
925
+ }
926
+ this.$data.nameFirst = (this.$data.nameFirst ?? '').trim();
927
+ this.$data.nameMiddle = (this.$data.nameMiddle ?? '').trim();
928
+ this.$data.nameLast = (this.$data.nameLast ?? '').trim();
929
+ this.$data.phone = (this.$data.phone ?? '').trim();
930
+ this.$data.name =
931
+ this.$data.nameFirst +
932
+ (this.$data.nameMiddle ? ' ' + this.$data.nameMiddle : '') +
933
+ (this.$data.nameLast ? ' ' + this.$data.nameLast : '');
934
+ this.$data.enabled = !!this.$data.enabled;
935
+ if (this.$data.nameFirst === '') {
936
+ delete this.$data.nameFirst;
937
+ }
938
+ if (this.$data.nameMiddle === '') {
939
+ delete this.$data.nameMiddle;
940
+ }
941
+ if (this.$data.nameLast === '') {
942
+ delete this.$data.nameLast;
943
+ }
944
+ if (this.$data.name === '') {
945
+ delete this.$data.name;
946
+ }
947
+ if (this.$data.email === '') {
948
+ delete this.$data.email;
949
+ }
950
+ if (this.$data.avatar === '') {
951
+ delete this.$data.avatar;
952
+ }
953
+ if (this.$data.phone === '') {
954
+ delete this.$data.phone;
955
+ }
956
+ if (this.$data.secret === '') {
957
+ delete this.$data.secret;
958
+ }
959
+ if (this.$data.emailChangeDate === 0) {
960
+ delete this.$data.emailChangeDate;
961
+ }
962
+ if (this.$data.newEmailSecret === '') {
963
+ delete this.$data.newEmailSecret;
964
+ }
965
+ if (this.$data.newEmailAddress === '') {
966
+ delete this.$data.newEmailAddress;
967
+ }
968
+ if (this.$data.cancelEmailSecret === '') {
969
+ delete this.$data.cancelEmailSecret;
970
+ }
971
+ if (this.$data.cancelEmailAddress === '') {
972
+ delete this.$data.cancelEmailAddress;
973
+ }
974
+ if (this.$data.recoverSecret === '') {
975
+ delete this.$data.recoverSecret;
976
+ }
977
+ if (this.$data.recoverSecretDate === 0) {
978
+ delete this.$data.recoverSecretDate;
979
+ }
980
+ if (this.$data.password === '') {
981
+ delete this.$data.password;
982
+ }
983
+ if (this.$data.passwordTemp === '') {
984
+ delete this.$data.passwordTemp;
985
+ }
986
+ if (this.$data.inheritAbilities === false) {
987
+ delete this.$data.inheritAbilities;
988
+ }
989
+ const unCheck = await this.$checkUsername();
990
+ if (!unCheck.result) {
991
+ throw new errors_1.BadUsernameError(unCheck.message);
992
+ }
993
+ if (!tilmeld.config.emailUsernames) {
994
+ const emCheck = await this.$checkEmail();
995
+ if (!emCheck.result) {
996
+ throw new errors_1.BadEmailError(emCheck.message);
971
997
  }
972
- if (!tilmeld.config.emailUsernames) {
973
- const emCheck = yield this.$checkEmail();
974
- if (!emCheck.result) {
975
- throw new errors_1.BadEmailError(emCheck.message);
998
+ }
999
+ if (!tilmeld.gatekeeper('tilmeld/admin')) {
1000
+ if (tilmeld.config.verifyEmail) {
1001
+ if (this.guid == null) {
1002
+ if ((this.$data.abilities?.indexOf('system/admin') ?? -1) === -1) {
1003
+ this.$data.secret = (0, guid_1.nanoid)();
1004
+ sendVerification = true;
1005
+ }
976
1006
  }
977
- }
978
- if (!tilmeld.gatekeeper('tilmeld/admin')) {
979
- if (tilmeld.config.verifyEmail) {
980
- if (this.guid == null) {
981
- if (((_f = (_e = this.$data.abilities) === null || _e === void 0 ? void 0 : _e.indexOf('system/admin')) !== null && _f !== void 0 ? _f : -1) === -1) {
982
- this.$data.secret = (0, nanoid_1.nanoid)();
983
- sendVerification = true;
984
- }
1007
+ else if (this.$originalEmail != null &&
1008
+ this.$originalEmail !== this.$data.email) {
1009
+ if (tilmeld.config.emailRateLimit !== '' &&
1010
+ this.$data.emailChangeDate != null &&
1011
+ this.$data.emailChangeDate >=
1012
+ (0, strtotime_1.default)('-' + tilmeld.config.emailRateLimit) * 1000) {
1013
+ throw new errors_1.EmailChangeRateLimitExceededError('You already changed your email address recently. Please wait until ' +
1014
+ new Date((0, strtotime_1.default)('+' + tilmeld.config.emailRateLimit, Math.floor(this.$data.emailChangeDate / 1000)) * 1000).toString() +
1015
+ ' to change your email address again.');
985
1016
  }
986
- else if (this.$originalEmail != null &&
987
- this.$originalEmail !== this.$data.email) {
988
- if (tilmeld.config.emailRateLimit !== '' &&
989
- this.$data.emailChangeDate != null &&
990
- this.$data.emailChangeDate >=
991
- (0, strtotime_1.default)('-' + tilmeld.config.emailRateLimit) * 1000) {
992
- throw new errors_1.EmailChangeRateLimitExceededError('You already changed your email address recently. Please wait until ' +
993
- new Date((0, strtotime_1.default)('+' + tilmeld.config.emailRateLimit, Math.floor(this.$data.emailChangeDate / 1000)) * 1000).toString() +
994
- ' to change your email address again.');
1017
+ else {
1018
+ if (this.$data.newEmailSecret == null &&
1019
+ tilmeld.config.emailRateLimit !== '' &&
1020
+ (this.$data.emailChangeDate == null ||
1021
+ this.$data.emailChangeDate <
1022
+ (0, strtotime_1.default)('-' + tilmeld.config.emailRateLimit) * 1000)) {
1023
+ this.$data.cancelEmailAddress = this.$originalEmail;
1024
+ this.$data.cancelEmailSecret = (0, guid_1.nanoid)();
1025
+ this.$data.emailChangeDate = Date.now();
995
1026
  }
996
- else {
997
- if (this.$data.newEmailSecret == null &&
998
- tilmeld.config.emailRateLimit !== '' &&
999
- (this.$data.emailChangeDate == null ||
1000
- this.$data.emailChangeDate <
1001
- (0, strtotime_1.default)('-' + tilmeld.config.emailRateLimit) * 1000)) {
1002
- this.$data.cancelEmailAddress = this.$originalEmail;
1003
- this.$data.cancelEmailSecret = (0, nanoid_1.nanoid)();
1004
- this.$data.emailChangeDate = Date.now();
1005
- }
1006
- this.$data.newEmailAddress = this.$data.email;
1007
- this.$data.email = this.$originalEmail;
1008
- if (tilmeld.config.emailUsernames) {
1009
- this.$data.username = this.$data.email;
1010
- }
1011
- this.$data.newEmailSecret = (0, nanoid_1.nanoid)();
1012
- sendVerification = true;
1027
+ this.$data.newEmailAddress = this.$data.email;
1028
+ this.$data.email = this.$originalEmail;
1029
+ if (tilmeld.config.emailUsernames) {
1030
+ this.$data.username = this.$data.email;
1013
1031
  }
1032
+ this.$data.newEmailSecret = (0, guid_1.nanoid)();
1033
+ sendVerification = true;
1014
1034
  }
1015
1035
  }
1016
- else if (this.guid != null &&
1017
- this.$originalEmail != null &&
1018
- this.$originalEmail !== this.$data.email &&
1019
- (this.$data.emailChangeDate == null ||
1020
- this.$data.emailChangeDate <
1021
- (0, strtotime_1.default)('-' + tilmeld.config.emailRateLimit) * 1000)) {
1022
- this.$data.cancelEmailAddress = this.$originalEmail;
1023
- this.$data.cancelEmailSecret = (0, nanoid_1.nanoid)();
1024
- sendVerification = true;
1025
- }
1026
- }
1027
- if (this.$data.passwordTemp != null) {
1028
- this.$password(this.$data.passwordTemp);
1029
1036
  }
1030
- delete this.$data.passwordTemp;
1031
- if (this.$data.password == null) {
1032
- throw new errors_1.BadDataError('A password is required.');
1037
+ else if (this.guid != null &&
1038
+ this.$originalEmail != null &&
1039
+ this.$originalEmail !== this.$data.email &&
1040
+ (this.$data.emailChangeDate == null ||
1041
+ this.$data.emailChangeDate <
1042
+ (0, strtotime_1.default)('-' + tilmeld.config.emailRateLimit) * 1000)) {
1043
+ this.$data.cancelEmailAddress = this.$originalEmail;
1044
+ this.$data.cancelEmailSecret = (0, guid_1.nanoid)();
1045
+ sendVerification = true;
1033
1046
  }
1047
+ }
1048
+ if (this.$data.passwordTemp != null) {
1049
+ this.$password(this.$data.passwordTemp);
1050
+ }
1051
+ delete this.$data.passwordTemp;
1052
+ if (this.$data.password == null) {
1053
+ throw new errors_1.BadDataError('A password is required.');
1054
+ }
1055
+ try {
1056
+ tilmeld.config.validatorUser(this);
1057
+ }
1058
+ catch (e) {
1059
+ throw new errors_1.BadDataError(e?.message);
1060
+ }
1061
+ const transaction = 'tilmeld-save-' + (0, guid_1.nanoid)();
1062
+ const nymph = this.$nymph;
1063
+ const tnymph = await this.$nymph.startTransaction(transaction);
1064
+ this.$nymph = tnymph;
1065
+ tilmeld = this.$nymph.tilmeld;
1066
+ if (this.$data.group != null &&
1067
+ this.$data.group.user != null &&
1068
+ this.$is(this.$data.group.user)) {
1034
1069
  try {
1035
- tilmeld.config.validatorUser(this);
1036
- }
1037
- catch (e) {
1038
- throw new errors_1.BadDataError(e === null || e === void 0 ? void 0 : e.message);
1039
- }
1040
- const transaction = 'tilmeld-save-' + (0, nanoid_1.nanoid)();
1041
- const nymph = this.$nymph;
1042
- const tnymph = yield this.$nymph.startTransaction(transaction);
1043
- this.$nymph = tnymph;
1044
- if (this.$data.group != null &&
1045
- this.$data.group.user != null &&
1046
- this.$is(this.$data.group.user)) {
1047
- try {
1048
- this.$data.group.groupname = this.$data.username;
1049
- this.$data.group.avatar = this.$data.avatar;
1050
- this.$data.group.email = this.$data.email;
1051
- this.$data.group.name = this.$data.name;
1052
- this.$data.group.phone = this.$data.phone;
1053
- yield this.$data.group.$saveSkipAC();
1054
- }
1055
- catch (e) {
1056
- yield tnymph.rollback(transaction);
1057
- this.$nymph = nymph;
1058
- throw e;
1059
- }
1060
- }
1061
- let ret;
1062
- let preGuid = this.guid;
1063
- let preCdate = this.cdate;
1064
- let preMdate = this.mdate;
1065
- try {
1066
- ret = yield _super.$save.call(this);
1070
+ this.$data.group.groupname = this.$data.username;
1071
+ this.$data.group.avatar = this.$data.avatar;
1072
+ this.$data.group.email = this.$data.email;
1073
+ this.$data.group.name = this.$data.name;
1074
+ this.$data.group.phone = this.$data.phone;
1075
+ await this.$data.group.$saveSkipAC();
1067
1076
  }
1068
1077
  catch (e) {
1069
- yield tnymph.rollback(transaction);
1078
+ await tnymph.rollback(transaction);
1070
1079
  this.$nymph = nymph;
1071
1080
  throw e;
1072
1081
  }
1073
- if (ret) {
1074
- if (sendVerification) {
1075
- if (!(yield this.$sendEmailVerification())) {
1076
- yield tnymph.rollback(transaction);
1077
- this.guid = preGuid;
1078
- this.cdate = preCdate;
1079
- this.mdate = preMdate;
1080
- this.$nymph = nymph;
1081
- throw new Error("Couldn't send verification email.");
1082
- }
1083
- }
1084
- if (tilmeld.User.current(true).$is(this)) {
1085
- tilmeld.fillSession(this);
1082
+ }
1083
+ let ret;
1084
+ let preGuid = this.guid;
1085
+ let preCdate = this.cdate;
1086
+ let preMdate = this.mdate;
1087
+ try {
1088
+ ret = await super.$save();
1089
+ }
1090
+ catch (e) {
1091
+ await tnymph.rollback(transaction);
1092
+ this.$nymph = nymph;
1093
+ throw e;
1094
+ }
1095
+ if (ret) {
1096
+ if (sendVerification) {
1097
+ if (!(await this.$sendEmailVerification())) {
1098
+ await tnymph.rollback(transaction);
1099
+ this.guid = preGuid;
1100
+ this.cdate = preCdate;
1101
+ this.mdate = preMdate;
1102
+ this.$nymph = nymph;
1103
+ throw new Error("Couldn't send verification email.");
1086
1104
  }
1087
- this.$descendantGroups = undefined;
1088
- this.$gatekeeperCache = undefined;
1089
- yield tnymph.commit(transaction);
1090
1105
  }
1091
- else {
1092
- yield tnymph.rollback(transaction);
1106
+ this.$descendantGroups = undefined;
1107
+ this.$gatekeeperCache = undefined;
1108
+ await tnymph.commit(transaction);
1109
+ if (nymph.tilmeld.User.current(true).$is(this)) {
1110
+ nymph.tilmeld.fillSession(this);
1093
1111
  }
1094
- this.$nymph = nymph;
1095
- return ret;
1096
- });
1112
+ }
1113
+ else {
1114
+ await tnymph.rollback(transaction);
1115
+ }
1116
+ this.$nymph = nymph;
1117
+ return ret;
1097
1118
  }
1098
- $saveSkipAC() {
1099
- return __awaiter(this, void 0, void 0, function* () {
1100
- this.$skipAcWhenSaving = true;
1101
- return yield this.$save();
1102
- });
1119
+ async $saveSkipAC() {
1120
+ this.$skipAcWhenSaving = true;
1121
+ return await this.$save();
1103
1122
  }
1104
1123
  $tilmeldSaveSkipAC() {
1105
1124
  if (this.$skipAcWhenSaving) {
@@ -1108,29 +1127,49 @@ class User extends AbleObject_1.default {
1108
1127
  }
1109
1128
  return false;
1110
1129
  }
1111
- $delete() {
1112
- const _super = Object.create(null, {
1113
- $delete: { get: () => super.$delete }
1114
- });
1115
- return __awaiter(this, void 0, void 0, function* () {
1116
- const tilmeld = this.$nymph.tilmeld;
1117
- if (!tilmeld.gatekeeper('tilmeld/admin')) {
1118
- throw new errors_1.BadDataError("You don't have the authority to delete users.");
1119
- }
1120
- if (!tilmeld.gatekeeper('system/admin') &&
1121
- this.$gatekeeper('system/admin')) {
1122
- throw new errors_1.BadDataError("You don't have the authority to delete system admins.");
1123
- }
1124
- if (tilmeld.User.current(true).$is(this)) {
1125
- this.$logout();
1126
- }
1127
- return yield _super.$delete.call(this);
1128
- });
1130
+ async $delete() {
1131
+ const tilmeld = this.$nymph.tilmeld;
1132
+ if (!tilmeld.gatekeeper('tilmeld/admin')) {
1133
+ throw new errors_1.BadDataError("You don't have the authority to delete users.");
1134
+ }
1135
+ if (!tilmeld.gatekeeper('system/admin') &&
1136
+ this.$gatekeeper('system/admin')) {
1137
+ throw new errors_1.BadDataError("You don't have the authority to delete system admins.");
1138
+ }
1139
+ if (tilmeld.User.current(true).$is(this)) {
1140
+ this.$logout();
1141
+ }
1142
+ return await super.$delete();
1143
+ }
1144
+ static on(event, callback) {
1145
+ const prop = (event + 'Callbacks');
1146
+ if (!(prop in this)) {
1147
+ throw new Error('Invalid event type.');
1148
+ }
1149
+ this[prop].push(callback);
1150
+ return () => this.off(event, callback);
1151
+ }
1152
+ static off(event, callback) {
1153
+ const prop = (event + 'Callbacks');
1154
+ if (!(prop in this)) {
1155
+ return false;
1156
+ }
1157
+ const i = this[prop].indexOf(callback);
1158
+ if (i > -1) {
1159
+ this[prop].splice(i, 1);
1160
+ }
1161
+ return true;
1129
1162
  }
1130
1163
  }
1131
1164
  exports.default = User;
1132
1165
  User.ETYPE = 'tilmeld_user';
1133
1166
  User.class = 'User';
1167
+ User.beforeRegisterCallbacks = [];
1168
+ User.afterRegisterCallbacks = [];
1169
+ User.beforeLoginCallbacks = [];
1170
+ User.afterLoginCallbacks = [];
1171
+ User.beforeLogoutCallbacks = [];
1172
+ User.afterLogoutCallbacks = [];
1134
1173
  User.DEFAULT_CLIENT_ENABLED_METHODS = [
1135
1174
  '$checkUsername',
1136
1175
  '$checkEmail',