@abtnode/core 1.16.8-beta-186fd5aa → 1.16.8-next-c66e39c7

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.
Files changed (38) hide show
  1. package/lib/api/team.js +42 -62
  2. package/lib/blocklet/manager/disk.js +2 -8
  3. package/lib/blocklet/manager/helper/migrate-application-to-struct-v2.js +5 -5
  4. package/lib/blocklet/storage/backup/blocklet-extras.js +2 -2
  5. package/lib/blocklet/storage/backup/blocklet.js +2 -2
  6. package/lib/index.js +17 -16
  7. package/lib/migrations/1.16.8-component-title.js +1 -1
  8. package/lib/migrations/1.6.9-update-node-info-and-certificate.js +1 -1
  9. package/lib/migrations/index.js +190 -40
  10. package/lib/monitor/node-runtime-monitor.js +2 -29
  11. package/lib/router/helper.js +6 -6
  12. package/lib/router/manager.js +35 -36
  13. package/lib/states/access-key.js +3 -20
  14. package/lib/states/audit-log.js +7 -8
  15. package/lib/states/backup.js +11 -59
  16. package/lib/states/base.js +13 -5
  17. package/lib/states/blocklet-extras.js +11 -8
  18. package/lib/states/blocklet.js +148 -222
  19. package/lib/states/cache.js +3 -21
  20. package/lib/states/connect-account.js +8 -0
  21. package/lib/states/index.js +28 -18
  22. package/lib/states/job.js +8 -0
  23. package/lib/states/migration.js +3 -4
  24. package/lib/states/node.js +104 -145
  25. package/lib/states/notification.js +18 -40
  26. package/lib/states/passport.js +8 -0
  27. package/lib/states/session.js +28 -44
  28. package/lib/states/site.js +32 -39
  29. package/lib/states/user.js +169 -378
  30. package/lib/states/webhook.js +5 -7
  31. package/lib/team/manager.js +108 -116
  32. package/lib/util/blocklet.js +0 -1
  33. package/lib/util/index.js +3 -0
  34. package/lib/util/queue.js +14 -20
  35. package/lib/util/ready.js +1 -1
  36. package/lib/webhook/index.js +6 -4
  37. package/package.json +19 -18
  38. package/lib/states/challenge.js +0 -58
@@ -1,34 +1,18 @@
1
1
  const pickBy = require('lodash/pickBy');
2
- const escapeStringRegexp = require('escape-string-regexp');
2
+ const get = require('lodash/get');
3
3
  const pick = require('lodash/pick');
4
- const cloneDeep = require('lodash/cloneDeep');
5
- const logger = require('@abtnode/logger')('@abtnode/core:states:user');
6
4
  const { isValid } = require('@arcblock/did');
7
5
  const { PASSPORT_STATUS } = require('@abtnode/constant');
8
- const { upsertToPassports } = require('@abtnode/auth/lib/passport');
9
- const { fromAppDid } = require('@arcblock/did-ext');
6
+ const { BaseState } = require('@abtnode/models');
7
+ const { Sequelize, Op } = require('sequelize');
8
+ const { updateConnectedAccount } = require('@abtnode/util/lib/user');
10
9
 
11
- const BaseState = require('./base');
12
10
  const { validateOwner } = require('../util');
13
11
  const { loginSchema } = require('../validators/user');
12
+ const ExtendBase = require('./base');
14
13
 
15
14
  const isNullOrUndefined = (x) => x === undefined || x === null;
16
15
 
17
- /**
18
- * UserPassport
19
- * @typedef {Object} UserPassport
20
- * @property {string} id - id
21
- * @property {string[]} [type] - passport's type
22
- * @property {string[]} [issuer] - passport's issuer
23
- * @property {Date} [issuanceDate] - passport's issuanceDate
24
- * @property {string} [specVersion] - passport's specVersion
25
- * @property {string} name - passport's name
26
- * @property {string} [title] - passport's title
27
- * @property {string} [endpoint] - passport's endpoint
28
- * @property {string} [status] - passport's status
29
- * @property {string} role - passport's role
30
- */
31
-
32
16
  /**
33
17
  * Auth0Account
34
18
  * @typedef {Object} Auth0Account
@@ -66,126 +50,76 @@ const isNullOrUndefined = (x) => x === undefined || x === null;
66
50
  */
67
51
 
68
52
  /**
69
- * The Data structure of blocklet-service user
70
- * @typedef {Object} BlockletUser - Blocklet Service User Table
71
- * @property {string} _id - id
72
- * @property {('profile')} type - type of user
73
- * @property {string} fullName - user profile's name
74
- * @property {string} avatar - url of user's avatar, eg: bn://avatar/7f8848569405f8cdf8b1b2788ebf7d0f.jpg
75
- * @property {string} did - user's did -> 实际上变为 uid, 是不可变的;真正的 wallet-did 转移到 extraConfigs 中去了
76
- * @property {string} pk - user's publicKey
77
- * @property {UserPassport[]} passports - user's passport list
78
- * @property {boolean} approved - enable user to login
79
- * @property {string} locale - locale
80
- * @property {Object} [extra] - extra data of user
81
- * @property {Object} [extraConfigs] - extra data of user
82
- * @property {ConnectedAccount[]} [extraConfigs.connectedAccounts] - connectedAccounts
83
- * @property {('wallet'|'auth0')} [extraConfigs.sourceProvider] - sourceProvider, the main account provider
84
- * @property {Date} firstLoginAt - firstLoginAt
85
- * @property {Date} lastLoginAt - lastLoginAt
86
- * @property {string} lastLoginIp - lastLoginIp
87
- * @property {Date} createdAt - createdAt
88
- * @property {Date} updatedAt - updatedAt
89
- * @property {('owner'|'admin'|'member'|'guest'|string)} role - user's role deprecated
53
+ * @extends ExtendBase<import('@abtnode/models').UserState>
90
54
  */
55
+ class User extends ExtendBase {
56
+ constructor(model, config, models) {
57
+ super(model, config);
91
58
 
92
- function updateConnectedAccount(connectedAccounts = [], connectedAccount = {}) {
93
- const now = new Date().toISOString();
94
- const filterAccounts = connectedAccounts.filter(Boolean);
95
- const updated = cloneDeep(filterAccounts);
96
- const updates = Array.isArray(connectedAccount) ? connectedAccount : [connectedAccount];
97
- updates.filter(Boolean).forEach((x) => {
98
- if (x.provider && x.did) {
99
- const findAccountIndex = updated.findIndex((item) => item.provider === x.provider && item.did === x.did);
100
- if (findAccountIndex > -1) {
101
- updated[findAccountIndex] = {
102
- ...filterAccounts[findAccountIndex],
103
- ...x,
104
- lastLoginAt: now,
105
- };
106
- } else {
107
- updated.push({
108
- ...x,
109
- firstLoginAt: now,
110
- lastLoginAt: now,
111
- });
112
- }
113
- }
114
- });
115
-
116
- return updated;
117
- }
118
-
119
- class User extends BaseState {
120
- constructor(baseDir, config = {}) {
121
- super(baseDir, { filename: 'user.db', ...config });
122
-
123
- this.onReady(() => {
124
- this.ensureIndex({ fieldName: 'did', unique: true }, (error) => {
125
- if (error) {
126
- logger.error('ensure index failed', { error });
127
- }
128
- });
129
- });
59
+ this.models = models;
60
+ this.passport = new BaseState(models.Passport, config);
61
+ this.connectedAccount = new BaseState(models.ConnectedAccount, config);
130
62
  }
131
63
 
132
- /**
133
- * Add a new user
134
- * @param {BlockletUser} user - user data
135
- * @returns {Promise<number>}
136
- */
137
- async add(user) {
64
+ // FIXME: @wangshijun wrap these in a transaction
65
+ async addUser(user) {
138
66
  if (!validateOwner(user)) {
139
67
  throw new Error('user is invalid');
140
68
  }
141
69
 
142
- return this.insert({
70
+ // create user
71
+ await this.insert({
143
72
  ...user,
73
+ sourceProvider: user.sourceProvider || 'wallet',
144
74
  approved: !!user.approved,
145
75
  });
146
- }
147
76
 
148
- /**
149
- * Update a user
150
- * @param {BlockletUser} user - user data
151
- * @returns {BlockletUser}
152
- */
153
- async update(user) {
154
- if (!validateOwner(user)) {
155
- throw new Error('user is invalid');
156
- }
77
+ // create passports and connectedAccounts
78
+ await Promise.all((get(user, 'passports') || []).map((x) => this.passport.insert({ ...x, userDid: user.did })));
79
+ await Promise.all(
80
+ (get(user, 'connectedAccounts') || []).map((x) => this.connectedAccount.insert({ ...x, userDid: user.did }))
81
+ );
157
82
 
158
- const [num, doc] = await super.update({ did: user.did }, { $set: user });
83
+ return this.getUser(user.did);
84
+ }
159
85
 
160
- if (num === 0) {
161
- throw new Error('user does not exist');
86
+ // FIXME: @wangshijun wrap these in a transaction
87
+ async updateUser(did, updates) {
88
+ const exist = await super.count({ did });
89
+ if (!exist) {
90
+ throw new Error(`user does not exist: ${did}`);
162
91
  }
163
92
 
164
- return doc;
93
+ await super.update({ did }, { $set: updates });
94
+ await Promise.all(
95
+ (get(updates, 'passports') || []).map((x) => this.passport.upsert({ id: x.id }, { ...x, userDid: did }))
96
+ );
97
+ await Promise.all(
98
+ (get(updates, 'connectedAccounts') || []).map((x) =>
99
+ this.connectedAccount.upsert({ did: x.did }, { ...x, userDid: did })
100
+ )
101
+ );
102
+
103
+ return this.getUser(did);
165
104
  }
166
105
 
167
- /**
168
- * @param {string} did user did
169
- * @param {string} id passport id
170
- */
171
- async revokePassportById({ did, id } = {}) {
106
+ async revokePassportById({ did, id }) {
172
107
  return this._setPassportStatusById({ did, id, status: PASSPORT_STATUS.REVOKED });
173
108
  }
174
109
 
175
- async enablePassportById({ did, id } = {}) {
110
+ async enablePassportById({ did, id }) {
176
111
  return this._setPassportStatusById({ did, id, status: PASSPORT_STATUS.VALID });
177
112
  }
178
113
 
179
114
  /**
180
115
  * remove a user by user's did
181
- * @param {string} did - the did of user
182
- * @returns {number} deleted count
116
+ * @param {object} params
117
+ * @param {string} params.did - the did of user
183
118
  */
184
119
  async remove({ did }) {
185
120
  const num = await super.remove({ did });
186
-
187
121
  if (num === 0) {
188
- throw new Error('user does not exist');
122
+ throw new Error(`user does not exist: ${did}`);
189
123
  }
190
124
 
191
125
  return num;
@@ -193,13 +127,12 @@ class User extends BaseState {
193
127
 
194
128
  /**
195
129
  * enable/disable user login
196
- * @param {string} did user's did
197
- * @param {boolean} approved enable/disable user login
198
- * @returns {BlockletUser}
130
+ * @param {object} params
131
+ * @param {string} params.did user's did
132
+ * @param {boolean} params.approved enable/disable user login
199
133
  */
200
134
  async updateApproved({ did, approved }) {
201
- const [num, doc] = await super.update({ did }, { $set: { approved } });
202
-
135
+ const [num, [doc]] = await super.update({ did }, { $set: { approved } });
203
136
  if (num === 0) {
204
137
  throw new Error(`user does not exist: ${did}`);
205
138
  }
@@ -209,13 +142,12 @@ class User extends BaseState {
209
142
 
210
143
  /**
211
144
  * update user's role
212
- * @param {string} did user's did
213
- * @param {BlockletUser.role} role user's role
214
- * @returns {BlockletUser}
145
+ * @param {object} params
146
+ * @param {string} params.did user's did
147
+ * @param {string} params.role user's role
215
148
  */
216
149
  async updateRole({ did, role }) {
217
- const [num, doc] = await super.update({ did }, { $set: { role } });
218
-
150
+ const [num, [doc]] = await super.update({ did }, { $set: { role } });
219
151
  if (num === 0) {
220
152
  throw new Error(`user does not exist: ${did}`);
221
153
  }
@@ -225,267 +157,134 @@ class User extends BaseState {
225
157
 
226
158
  /**
227
159
  * Get blocklet service user list
228
- * @param {Object} query query params
229
- * @param {('asc'|'desc')} sort query sort
230
- * @param {any} paging query paging
231
- * @returns {{list: BlockletUser[]; paging: any;}}
232
160
  */
233
- async getUsers({ query, sort, paging: inputPaging } = {}) {
234
- const { approved, role, search, connectedDid } = query || {};
235
- const queryParamList = [];
236
-
237
- // make query param
238
- const queryParam = {};
161
+ async getUsers({ query, sort, paging } = {}) {
162
+ const where = {};
163
+ const { approved, role, search } = query || {};
239
164
 
240
- if (!isNullOrUndefined(approved)) {
241
- queryParam.approved = !!approved;
165
+ if (isNullOrUndefined(approved) === false) {
166
+ where.approved = approved;
242
167
  }
243
168
 
244
169
  if (search) {
245
170
  if (search.length > 50) {
246
171
  throw new Error('the length of search text should not more than 50');
247
172
  }
248
-
249
173
  if (isValid(search)) {
250
- queryParam.did = search;
174
+ where.did = search;
251
175
  } else {
252
- const reg = new RegExp(escapeStringRegexp(search), 'i');
253
-
254
- queryParam.fullName = { $regex: reg };
176
+ where[Op.or] = [{ fullName: { [Op.like]: `%${search}%` } }, { email: { [Op.like]: `%${search}%` } }];
255
177
  }
256
178
  }
257
179
 
258
- if (role && role !== '$all') {
180
+ if (role && role !== '$all' && !where.did) {
259
181
  if (role === '$none') {
260
- queryParam.passports = { $size: 0 };
182
+ where.did = {
183
+ [Op.notIn]: Sequelize.literal('(SELECT DISTINCT userDid FROM passports)'),
184
+ };
261
185
  } else {
262
- queryParam.passports = { $elemMatch: { name: role, status: PASSPORT_STATUS.VALID } };
186
+ where.did = {
187
+ [Op.in]: Sequelize.literal(
188
+ `(SELECT DISTINCT userDid FROM passports WHERE name = '${role}' AND status = '${PASSPORT_STATUS.VALID}')`
189
+ ),
190
+ };
263
191
  }
264
192
  }
265
193
 
266
- // 根据 connectedDid 查询 user 信息(wallet 账户绑定 oauth 账户后,会有该字段)
267
- if (connectedDid) {
268
- queryParamList.push({
269
- ...queryParam,
270
- 'extraConfigs.connectedAccounts.did': connectedDid,
271
- });
272
- // HACK: 在某些情况下,查询的条件可能是 version2 版本的用户 did,并且查村的 did 是派生出来的,没有实际的用户记录,只能通过这个条件查询出来
273
- // version 1 的用户不需要通过这个条件来查询
274
- queryParamList.push({
275
- ...queryParam,
276
- 'extraConfigs.derivedAccount.did': connectedDid,
277
- });
194
+ const sorting = pickBy(sort, (x) => !isNullOrUndefined(x));
195
+ if (!Object.keys(sorting).length) {
196
+ sorting.createdAt = -1;
278
197
  }
279
198
 
280
- const sortParam = pickBy(sort, (x) => !isNullOrUndefined(x));
281
-
282
- if (!Object.keys(sortParam).length) {
283
- sortParam.createdAt = -1;
284
- }
285
-
286
- // get data
287
- const { list, paging } = await this.paginate(
288
- queryParamList.length > 0 ? { $or: queryParamList } : queryParam,
289
- sortParam,
290
- inputPaging
291
- );
292
-
293
- return {
294
- list,
295
- paging,
296
- };
199
+ return this.paginate({ where }, sorting, paging);
297
200
  }
298
201
 
299
- /**
300
- * get user list by did list
301
- * @param {string[]} dids user did list
302
- * @returns {BlockletUser[]}
303
- */
304
- async getUsersByDids({ dids, query } = {}) {
202
+ async getUsersByDids({ dids, query }) {
305
203
  const { approved } = query || {};
306
- const didList = dids || [];
307
-
308
- const queryParam = {
309
- did: { $in: didList },
310
- };
311
-
312
- if (!isNullOrUndefined(approved)) {
313
- queryParam.approved = !!approved;
204
+ const condition = { did: dids };
205
+ if (isNullOrUndefined(approved) === false) {
206
+ condition.approved = !!approved;
314
207
  }
315
208
 
316
- // get data
317
- return this.find(queryParam);
209
+ return this.find({ where: condition });
318
210
  }
319
211
 
320
- /**
321
- * get user list by sourceId list
322
- * @param {string[]} sourceIds user sourceId list
323
- * @returns {BlockletUser[]}
324
- */
325
- async getUsersBySourceIds({ sourceIds, query } = {}) {
326
- const { approved } = query || {};
327
- const sourceIdList = sourceIds || [];
328
-
329
- const queryParam = {
330
- 'extraConfigs.sourceId': { $in: sourceIdList },
331
- };
332
-
333
- if (!isNullOrUndefined(approved)) {
334
- queryParam.approved = !!approved;
212
+ async countByPassport({ name, status = PASSPORT_STATUS.VALID }) {
213
+ if (name === '$none') {
214
+ return this.count({
215
+ where: {
216
+ did: {
217
+ [Op.notIn]: Sequelize.literal('(SELECT DISTINCT userDid FROM passports)'),
218
+ },
219
+ },
220
+ });
335
221
  }
336
222
 
337
- // get data
338
- return this.find(queryParam);
339
- }
340
-
341
- /**
342
- * user 版本标准化,统一将 user 转换为最新的结构,结构参考 core/state/lib/states/user.js L12-L75
343
- */
344
- // 1: 没有 extraConfigs 字段
345
- // 2: 有 source 和 extraConfigs 字段,oauth 账号的 extraConfigs 中包含 sourceId 和 sourceProvider 字段
346
- // 3: 只有 extraConfigs 字段,且 extraConfigs.connectedAccounts 中包含 extraConfigs.sourceProvider 的 account
347
- async normalize(user, { blockletSk }) {
348
- if (!user) {
349
- return user;
350
- }
351
- let version = 1;
352
- if (user.extraConfigs) {
353
- version = 2;
354
-
355
- const connectedAccounts = user.extraConfigs?.connectedAccounts || [];
356
- const sourceProvider = user.extraConfigs?.sourceProvider || '';
357
- if (connectedAccounts.some((item) => item.provider === sourceProvider)) {
358
- version = 3;
359
- }
223
+ if (name === '$all') {
224
+ return this.count({});
360
225
  }
361
226
 
362
- const versionMap = {
363
- 1: async () => {
364
- const connectedAccounts = [
365
- {
366
- provider: 'wallet',
367
- did: user.did,
368
- pk: user.pk,
369
- firstLoginAt: user.firstLoginAt,
370
- lastLoginAt: user.lastLoginAt,
371
- },
372
- ];
373
- const sourceProvider = 'wallet';
374
- const updatedUser = await this.update({
375
- did: user.did,
376
- pk: user.pk,
377
- extraConfigs: {
378
- sourceProvider,
379
- connectedAccounts,
380
- },
381
- });
382
- return updatedUser;
227
+ return this.count({
228
+ distinct: true,
229
+ col: 'did',
230
+ where: {
231
+ did: {
232
+ [Op.in]: Sequelize.literal(
233
+ `(SELECT DISTINCT userDid FROM passports WHERE name = '${name}' AND status = '${status}')`
234
+ ),
235
+ },
383
236
  },
384
- 2: async () => {
385
- // eslint-disable-next-line prefer-const
386
- let { sourceId, sourceProvider, connectedAccounts = [] } = user.extraConfigs || {};
387
- if (sourceId && sourceProvider) {
388
- connectedAccounts = [
389
- {
390
- provider: sourceProvider,
391
- id: sourceId,
392
- did: user.did,
393
- pk: user.pk,
394
- firstLoginAt: user.firstLoginAt,
395
- lastLoginAt: user.lastLoginAt,
396
- },
397
- ];
398
- } else {
399
- sourceProvider = 'wallet';
400
- connectedAccounts.forEach((account) => {
401
- if (account.id && blockletSk) {
402
- const accountWallet = fromAppDid(account.id, blockletSk);
403
- account.did = accountWallet.address;
404
- account.pk = accountWallet.publicKey;
405
- account.firstLoginAt = account.firstLoginAt || new Date().toISOString();
406
- account.lastLoginAt = account.lastLoginAt || new Date().toISOString();
407
- }
408
- });
409
- connectedAccounts.unshift({
410
- provider: 'wallet',
411
- did: user.did,
412
- pk: user.pk,
413
- firstLoginAt: user.firstLoginAt,
414
- lastLoginAt: user.lastLoginAt,
415
- });
416
- }
417
- const updatedUser = await this.update({
418
- did: user.did,
419
- pk: user.pk,
420
- extraConfigs: {
421
- sourceProvider,
422
- connectedAccounts,
423
- },
424
- source: undefined,
425
- });
426
- return updatedUser;
427
- },
428
- 3: () => {
429
- return user;
430
- },
431
- };
432
- return versionMap[version]();
237
+ });
433
238
  }
434
239
 
435
240
  /**
436
241
  * get user by did
437
242
  * @param {string} did user's did
438
- * @returns {BlockletUser}
439
243
  */
440
- async getUser(did, { enableConnectedAccount = false, enableNormalize = false, blockletSk } = {}) {
244
+ async getUser(did, { enableConnectedAccount = false } = {}) {
441
245
  let user = await this.findOne({ did });
442
- if (enableConnectedAccount) {
443
- if (!user) {
444
- user = await this.findOne({
445
- 'extraConfigs.connectedAccounts.did': did,
446
- });
447
- } else if (user.extraConfig?.bindDid) {
448
- // @deprecated 已经不存在 bindDid 字段
449
- ({ user } = await this.findOne({ did: user.extraConfig.bindDid }));
246
+ let connectedAccounts = [];
247
+ let passports = [];
248
+
249
+ // search in connected accounts
250
+ if (!user && enableConnectedAccount) {
251
+ const connectedAccount = await this.connectedAccount.findOne({ did });
252
+ if (connectedAccount) {
253
+ user = await this.findOne({ did: connectedAccount.userDid });
450
254
  }
451
255
  }
452
- if (enableNormalize) {
453
- if (!blockletSk) {
454
- throw new Error('Normalize user must provide blockletSk params');
455
- }
456
- return this.normalize(user, { blockletSk });
256
+
257
+ if (user) {
258
+ [connectedAccounts, passports] = await Promise.all([
259
+ this.connectedAccount.find({ userDid: user.did }),
260
+ this.passport.find({ userDid: user.did }),
261
+ ]);
262
+
263
+ user.connectedAccounts = connectedAccounts;
264
+ user.passports = passports;
457
265
  }
266
+
458
267
  return user;
459
268
  }
460
269
 
461
270
  /**
462
- * @param {string} did user did
463
- * @param {string} id passport id
464
- * @param {string} status passport status
271
+ * @param {object} params
272
+ * @param {string} params.did user did
273
+ * @param {string} params.id passport id
274
+ * @param {string} params.status passport status
465
275
  */
466
- async _setPassportStatusById({ did, id, status } = {}) {
467
- const exist = await this.findOne({ did });
468
-
276
+ async _setPassportStatusById({ did, id, status }) {
277
+ const exist = this.passport.count({ id });
469
278
  if (!exist) {
470
- throw new Error('did does not exist');
471
- }
472
-
473
- const passports = exist.passports || [];
474
- const passport = passports.find((x) => x.id === id);
475
-
476
- if (!passport) {
477
279
  throw new Error(`cannot find passport by id ${id}`);
478
280
  }
479
281
 
480
- passport.status = status;
481
-
482
- const [num, doc] = await super.update({ did }, { $set: { passports } });
483
-
282
+ const [num] = await this.passport.update({ id }, { $set: { status } });
484
283
  if (num === 0) {
485
- throw new Error('user does not exist');
284
+ throw new Error('user passport does not exist');
486
285
  }
487
286
 
488
- return doc;
287
+ return this.getUser(did);
489
288
  }
490
289
 
491
290
  /**
@@ -502,66 +301,58 @@ class User extends BaseState {
502
301
  * @param {string} user.lastLoginIp - lastLoginIp
503
302
  * @param {('owner'|'admin'|'member'|'guest'|string)} user.role - deprecated user's role
504
303
  */
505
- async login(_user) {
506
- const { error, value: user } = loginSchema.validate(_user);
304
+ async loginUser(raw) {
305
+ const { error, value: user } = loginSchema.validate(raw);
507
306
  if (error) {
508
307
  throw new Error(error);
509
308
  }
510
309
 
511
- let updatedUser;
512
- let action = '';
310
+ let updated;
311
+
513
312
  const now = new Date().toISOString();
514
- const oldUser = await this.getUser(user.did, {
515
- enableConnectedAccount: true,
516
- });
517
- const cloneData = cloneDeep(user);
518
- const passports = upsertToPassports(
519
- oldUser?.passports || [],
520
- cloneData.passport && {
521
- ...cloneData.passport,
522
- lastLoginAt: now,
523
- }
524
- );
525
- const mergeData = {
526
- ...pick(cloneData, ['type', 'fullName', 'email', 'avatar', 'role', 'locale', 'extra', 'lastLoginIp', 'remark']),
527
- did: user.did,
528
- pk: user.pk,
529
- passports,
313
+ const exist = await this.getUser(user.did, { enableConnectedAccount: true });
314
+
315
+ const updates = {
316
+ ...pick(user, ['fullName', 'email', 'avatar', 'role', 'locale', 'extra', 'lastLoginIp', 'remark']),
530
317
  lastLoginAt: now,
531
- extraConfigs: {
532
- sourceProvider: 'wallet',
533
- connectedAccounts: [],
534
- },
318
+ passports: user.passport ? [{ ...user.passport, lastLoginAt: now }] : [],
535
319
  };
536
320
 
537
- if (oldUser) {
538
- // update
539
- action = 'update';
540
- const extraConfigs = {
541
- sourceProvider: oldUser?.extraConfigs?.sourceProvider || 'wallet',
542
- connectedAccounts: updateConnectedAccount(
543
- oldUser?.extraConfigs?.connectedAccounts || [],
544
- cloneData.connectedAccount
545
- ),
546
- };
547
- mergeData.extraConfigs = extraConfigs;
548
- updatedUser = await this.update(mergeData);
321
+ if (exist) {
322
+ // update user, connectedAccount, passport
323
+ updates.connectedAccounts = updateConnectedAccount(exist.connectedAccounts, user.connectedAccount);
324
+ updated = await this.updateUser(user.did, updates);
549
325
  } else {
550
- // insert
551
- action = 'add';
552
- mergeData.firstLoginAt = now;
553
- mergeData.approved = true;
554
- const connectedAccount = Array.isArray(cloneData.connectedAccount)
555
- ? cloneData.connectedAccount.filter(Boolean)[0]
556
- : cloneData.connectedAccount;
557
-
558
- mergeData.extraConfigs = {
559
- sourceProvider: connectedAccount.provider,
560
- connectedAccounts: updateConnectedAccount([], cloneData.connectedAccount),
561
- };
562
- updatedUser = await this.add(mergeData);
326
+ // create user, connectedAccount, passport
327
+ updates.did = user.did;
328
+ updates.pk = user.pk;
329
+ updates.firstLoginAt = now;
330
+ updates.approved = true;
331
+ updates.connectedAccounts = updateConnectedAccount([], user.connectedAccount);
332
+ updates.sourceProvider = updates.connectedAccounts[0].provider;
333
+ updated = await this.addUser(updates);
563
334
  }
564
- return { ...updatedUser, _action: action };
335
+
336
+ return { ...updated, _action: exist ? 'update' : 'add' };
337
+ }
338
+
339
+ async getUserByDid(did) {
340
+ return this.findOne({ did }, { did: 1, pk: 1, fullName: 1, email: 1, role: 1, approved: 1 });
341
+ }
342
+
343
+ async isUserValid(did) {
344
+ const count = await super.count({ did, approved: true });
345
+ return count > 0;
346
+ }
347
+
348
+ async isConnectedAccount(did) {
349
+ const count = await this.connectedAccount.count({ did });
350
+ return count > 0;
351
+ }
352
+
353
+ async isPassportValid(passportId) {
354
+ const count = await this.passport.count({ id: passportId, status: PASSPORT_STATUS.VALID });
355
+ return count > 0;
565
356
  }
566
357
  }
567
358