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

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 +24 -64
  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 +14 -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 +136 -225
  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 +187 -374
  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,175 @@ 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 } = {}) {
161
+ async getUsers({ query, sort, paging } = {}) {
234
162
  const { approved, role, search, connectedDid } = query || {};
235
- const queryParamList = [];
236
163
 
237
- // make query param
238
- const queryParam = {};
164
+ const where = {};
165
+ const include = [
166
+ {
167
+ model: this.models.Passport,
168
+ as: 'passports',
169
+ },
170
+ {
171
+ model: this.models.ConnectedAccount,
172
+ as: 'connectedAccounts',
173
+ },
174
+ ];
239
175
 
240
- if (!isNullOrUndefined(approved)) {
241
- queryParam.approved = !!approved;
176
+ if (isNullOrUndefined(approved) === false) {
177
+ where.approved = approved;
242
178
  }
243
179
 
244
180
  if (search) {
245
181
  if (search.length > 50) {
246
182
  throw new Error('the length of search text should not more than 50');
247
183
  }
248
-
249
184
  if (isValid(search)) {
250
- queryParam.did = search;
185
+ where.did = search;
251
186
  } else {
252
- const reg = new RegExp(escapeStringRegexp(search), 'i');
253
-
254
- queryParam.fullName = { $regex: reg };
187
+ where[Op.or] = [{ fullName: { [Op.like]: `%${search}%` } }, { email: { [Op.like]: `%${search}%` } }];
255
188
  }
256
189
  }
257
190
 
258
191
  if (role && role !== '$all') {
259
192
  if (role === '$none') {
260
- queryParam.passports = { $size: 0 };
193
+ include[0].required = false;
194
+ include[0].where = {
195
+ [Op.or]: [{ name: null }, { id: null }],
196
+ };
261
197
  } else {
262
- queryParam.passports = { $elemMatch: { name: role, status: PASSPORT_STATUS.VALID } };
198
+ include[0].where = { name: role };
199
+ include[0].required = true;
263
200
  }
264
201
  }
265
202
 
266
- // 根据 connectedDid 查询 user 信息(wallet 账户绑定 oauth 账户后,会有该字段)
267
203
  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
- });
204
+ include[1].where = { did: connectedDid };
205
+ include[1].required = true;
278
206
  }
279
207
 
280
- const sortParam = pickBy(sort, (x) => !isNullOrUndefined(x));
281
-
282
- if (!Object.keys(sortParam).length) {
283
- sortParam.createdAt = -1;
208
+ const sorting = pickBy(sort, (x) => !isNullOrUndefined(x));
209
+ if (!Object.keys(sorting).length) {
210
+ sorting.createdAt = -1;
284
211
  }
285
212
 
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
- };
213
+ return this.paginate({ where, include }, sorting, paging);
297
214
  }
298
215
 
299
- /**
300
- * get user list by did list
301
- * @param {string[]} dids user did list
302
- * @returns {BlockletUser[]}
303
- */
304
- async getUsersByDids({ dids, query } = {}) {
216
+ async getUsersByDids({ dids, query }) {
305
217
  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;
218
+ const condition = { did: dids };
219
+ if (isNullOrUndefined(approved) === false) {
220
+ condition.approved = !!approved;
314
221
  }
315
222
 
316
- // get data
317
- return this.find(queryParam);
223
+ return this.find({
224
+ where: condition,
225
+ include: [
226
+ {
227
+ model: this.models.ConnectedAccount,
228
+ as: 'connectedAccounts',
229
+ },
230
+ {
231
+ model: this.models.Passport,
232
+ as: 'passports',
233
+ },
234
+ ],
235
+ });
318
236
  }
319
237
 
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
- };
238
+ async countByPassport({ name, status = PASSPORT_STATUS.VALID }) {
239
+ if (name === '$none') {
240
+ return this.count({
241
+ where: {
242
+ did: {
243
+ [Op.notIn]: Sequelize.literal('(SELECT DISTINCT userDid FROM passports)'),
244
+ },
245
+ },
246
+ });
247
+ }
332
248
 
333
- if (!isNullOrUndefined(approved)) {
334
- queryParam.approved = !!approved;
249
+ if (name === '$all') {
250
+ return this.count({});
335
251
  }
336
252
 
337
- // get data
338
- return this.find(queryParam);
253
+ return this.count({
254
+ distinct: true,
255
+ col: 'did',
256
+ include: [
257
+ {
258
+ model: this.models.Passport,
259
+ as: 'passports',
260
+ attributes: [],
261
+ where: { name, status },
262
+ },
263
+ ],
264
+ });
339
265
  }
340
266
 
341
267
  /**
342
- * user 版本标准化,统一将 user 转换为最新的结构,结构参考 core/state/lib/states/user.js L12-L75
268
+ * get user by did
269
+ * @param {string} did user's did
343
270
  */
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
- }
360
- }
271
+ async getUser(did, { enableConnectedAccount = false } = {}) {
272
+ let user = await this.findOne({
273
+ where: { did },
274
+ include: [
275
+ {
276
+ model: this.models.ConnectedAccount,
277
+ as: 'connectedAccounts',
278
+ },
279
+ {
280
+ model: this.models.Passport,
281
+ as: 'passports',
282
+ },
283
+ ],
284
+ });
361
285
 
362
- const versionMap = {
363
- 1: async () => {
364
- const connectedAccounts = [
286
+ if (enableConnectedAccount && !user) {
287
+ user = await this.findOne({
288
+ include: [
365
289
  {
366
- provider: 'wallet',
367
- did: user.did,
368
- pk: user.pk,
369
- firstLoginAt: user.firstLoginAt,
370
- lastLoginAt: user.lastLoginAt,
290
+ model: this.models.ConnectedAccount,
291
+ as: 'connectedAccounts',
292
+ where: { did },
293
+ required: true,
371
294
  },
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;
383
- },
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,
295
+ {
296
+ model: this.models.Passport,
297
+ as: 'passports',
423
298
  },
424
- source: undefined,
425
- });
426
- return updatedUser;
427
- },
428
- 3: () => {
429
- return user;
430
- },
431
- };
432
- return versionMap[version]();
433
- }
434
-
435
- /**
436
- * get user by did
437
- * @param {string} did user's did
438
- * @returns {BlockletUser}
439
- */
440
- async getUser(did, { enableConnectedAccount = false, enableNormalize = false, blockletSk } = {}) {
441
- 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 }));
450
- }
299
+ ],
300
+ });
451
301
  }
452
- if (enableNormalize) {
453
- if (!blockletSk) {
454
- throw new Error('Normalize user must provide blockletSk params');
455
- }
456
- return this.normalize(user, { blockletSk });
302
+
303
+ // Normalize
304
+ if (user && !user.passports) {
305
+ user.passports = [];
457
306
  }
307
+
458
308
  return user;
459
309
  }
460
310
 
461
311
  /**
462
- * @param {string} did user did
463
- * @param {string} id passport id
464
- * @param {string} status passport status
312
+ * @param {object} params
313
+ * @param {string} params.did user did
314
+ * @param {string} params.id passport id
315
+ * @param {string} params.status passport status
465
316
  */
466
- async _setPassportStatusById({ did, id, status } = {}) {
467
- const exist = await this.findOne({ did });
468
-
317
+ async _setPassportStatusById({ did, id, status }) {
318
+ const exist = this.passport.count({ id });
469
319
  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
320
  throw new Error(`cannot find passport by id ${id}`);
478
321
  }
479
322
 
480
- passport.status = status;
481
-
482
- const [num, doc] = await super.update({ did }, { $set: { passports } });
483
-
323
+ const [num] = await this.passport.update({ id }, { $set: { status } });
484
324
  if (num === 0) {
485
- throw new Error('user does not exist');
325
+ throw new Error('user passport does not exist');
486
326
  }
487
327
 
488
- return doc;
328
+ return this.getUser(did);
489
329
  }
490
330
 
491
331
  /**
@@ -502,66 +342,39 @@ class User extends BaseState {
502
342
  * @param {string} user.lastLoginIp - lastLoginIp
503
343
  * @param {('owner'|'admin'|'member'|'guest'|string)} user.role - deprecated user's role
504
344
  */
505
- async login(_user) {
506
- const { error, value: user } = loginSchema.validate(_user);
345
+ async loginUser(raw) {
346
+ const { error, value: user } = loginSchema.validate(raw);
507
347
  if (error) {
508
348
  throw new Error(error);
509
349
  }
510
350
 
511
- let updatedUser;
512
- let action = '';
351
+ let updated;
352
+
513
353
  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,
354
+ const exist = await this.getUser(user.did, { enableConnectedAccount: true });
355
+
356
+ const updates = {
357
+ ...pick(user, ['fullName', 'email', 'avatar', 'role', 'locale', 'extra', 'lastLoginIp', 'remark']),
530
358
  lastLoginAt: now,
531
- extraConfigs: {
532
- sourceProvider: 'wallet',
533
- connectedAccounts: [],
534
- },
359
+ passports: user.passport ? [{ ...user.passport, lastLoginAt: now }] : [],
535
360
  };
536
361
 
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);
362
+ if (exist) {
363
+ // update user, connectedAccount, passport
364
+ updates.connectedAccounts = updateConnectedAccount(exist.connectedAccounts, user.connectedAccount);
365
+ updated = await this.updateUser(user.did, updates);
549
366
  } 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);
367
+ // create user, connectedAccount, passport
368
+ updates.did = user.did;
369
+ updates.pk = user.pk;
370
+ updates.firstLoginAt = now;
371
+ updates.approved = true;
372
+ updates.connectedAccounts = updateConnectedAccount([], user.connectedAccount);
373
+ updates.sourceProvider = updates.connectedAccounts[0].provider;
374
+ updated = await this.addUser(updates);
563
375
  }
564
- return { ...updatedUser, _action: action };
376
+
377
+ return { ...updated, _action: exist ? 'update' : 'add' };
565
378
  }
566
379
  }
567
380