@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.
- package/lib/api/team.js +42 -62
- package/lib/blocklet/manager/disk.js +2 -8
- package/lib/blocklet/manager/helper/migrate-application-to-struct-v2.js +5 -5
- package/lib/blocklet/storage/backup/blocklet-extras.js +2 -2
- package/lib/blocklet/storage/backup/blocklet.js +2 -2
- package/lib/index.js +17 -16
- package/lib/migrations/1.16.8-component-title.js +1 -1
- package/lib/migrations/1.6.9-update-node-info-and-certificate.js +1 -1
- package/lib/migrations/index.js +190 -40
- package/lib/monitor/node-runtime-monitor.js +2 -29
- package/lib/router/helper.js +6 -6
- package/lib/router/manager.js +35 -36
- package/lib/states/access-key.js +3 -20
- package/lib/states/audit-log.js +7 -8
- package/lib/states/backup.js +11 -59
- package/lib/states/base.js +13 -5
- package/lib/states/blocklet-extras.js +11 -8
- package/lib/states/blocklet.js +148 -222
- package/lib/states/cache.js +3 -21
- package/lib/states/connect-account.js +8 -0
- package/lib/states/index.js +28 -18
- package/lib/states/job.js +8 -0
- package/lib/states/migration.js +3 -4
- package/lib/states/node.js +104 -145
- package/lib/states/notification.js +18 -40
- package/lib/states/passport.js +8 -0
- package/lib/states/session.js +28 -44
- package/lib/states/site.js +32 -39
- package/lib/states/user.js +169 -378
- package/lib/states/webhook.js +5 -7
- package/lib/team/manager.js +108 -116
- package/lib/util/blocklet.js +0 -1
- package/lib/util/index.js +3 -0
- package/lib/util/queue.js +14 -20
- package/lib/util/ready.js +1 -1
- package/lib/webhook/index.js +6 -4
- package/package.json +19 -18
- package/lib/states/challenge.js +0 -58
package/lib/states/user.js
CHANGED
|
@@ -1,34 +1,18 @@
|
|
|
1
1
|
const pickBy = require('lodash/pickBy');
|
|
2
|
-
const
|
|
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 {
|
|
9
|
-
const {
|
|
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
|
-
*
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
-
|
|
83
|
+
return this.getUser(user.did);
|
|
84
|
+
}
|
|
159
85
|
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
|
|
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 {
|
|
182
|
-
* @
|
|
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(
|
|
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 {
|
|
197
|
-
* @param {
|
|
198
|
-
* @
|
|
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 {
|
|
213
|
-
* @param {
|
|
214
|
-
* @
|
|
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
|
|
234
|
-
const
|
|
235
|
-
const
|
|
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 (
|
|
241
|
-
|
|
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
|
-
|
|
174
|
+
where.did = search;
|
|
251
175
|
} else {
|
|
252
|
-
|
|
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
|
-
|
|
182
|
+
where.did = {
|
|
183
|
+
[Op.notIn]: Sequelize.literal('(SELECT DISTINCT userDid FROM passports)'),
|
|
184
|
+
};
|
|
261
185
|
} else {
|
|
262
|
-
|
|
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
|
-
|
|
267
|
-
if (
|
|
268
|
-
|
|
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
|
-
|
|
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
|
|
307
|
-
|
|
308
|
-
|
|
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
|
-
|
|
317
|
-
return this.find(queryParam);
|
|
209
|
+
return this.find({ where: condition });
|
|
318
210
|
}
|
|
319
211
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
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
|
-
|
|
338
|
-
|
|
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
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
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
|
-
|
|
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
|
|
244
|
+
async getUser(did, { enableConnectedAccount = false } = {}) {
|
|
441
245
|
let user = await this.findOne({ did });
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
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 {
|
|
463
|
-
* @param {string}
|
|
464
|
-
* @param {string}
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
506
|
-
const { error, value: user } = loginSchema.validate(
|
|
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
|
|
512
|
-
|
|
310
|
+
let updated;
|
|
311
|
+
|
|
513
312
|
const now = new Date().toISOString();
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
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
|
-
|
|
532
|
-
sourceProvider: 'wallet',
|
|
533
|
-
connectedAccounts: [],
|
|
534
|
-
},
|
|
318
|
+
passports: user.passport ? [{ ...user.passport, lastLoginAt: now }] : [],
|
|
535
319
|
};
|
|
536
320
|
|
|
537
|
-
if (
|
|
538
|
-
// update
|
|
539
|
-
|
|
540
|
-
|
|
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
|
-
//
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
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
|
-
|
|
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
|
|