WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit a8bc8e0

Browse files
committed
feat: update user and organization metadata
* REWORK
1 parent d9f0aad commit a8bc8e0

22 files changed

+481
-258
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# User/Organization metadata update rework
2+
## Overview and Motivation
3+
When user or organization metadata needs to be updated, the Service uses the Redis pipeline javascript code.
4+
For each assigned meta hash always exists a single `audience`, but there is no list of `audiences` assigned to the user or company.
5+
To achieve easier audience tracking and a combined metadata update, I advise using a Lua based script.
6+
7+
## Audience lists
8+
Audiences stored in sets formed from `USERS_AUDIENCE` or `ORGANISATION_AUDIENCE` constants and `Id`
9+
(eg: `{ms-users}10110110111!audiences`). Both keys contain `audience` names that are currently have assigned values.
10+
11+
## DEL utils/updateMetadata.js
12+
All logic from this file moved to separate class `utils/metadata/redis/update-metadata.js`.
13+
14+
## utils/metadata/{user|organization}.js
15+
Classes that perform user or organization metadata update and
16+
audience list tracking.
17+
18+
Available methods:
19+
* update
20+
* updateMulti
21+
* batchUpdate
22+
* delete
23+
24+
**TODO** Fill up
25+
26+
27+
## global updates
28+
`ms-users` source code now use new `UserMetadata` when any update operation happens.
29+
30+

src/actions/alias.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ const isActive = require('../utils/isActive');
66
const isBanned = require('../utils/isBanned');
77
const key = require('../utils/key');
88
const handlePipeline = require('../utils/pipelineError');
9+
const UserMetadata = require('../utils/metadata/user');
10+
911
const {
1012
USERS_DATA,
11-
USERS_METADATA,
1213
USERS_ALIAS_TO_ID,
1314
USERS_ID_FIELD,
1415
USERS_ALIAS_FIELD,
@@ -69,10 +70,11 @@ async function assignAlias({ params }) {
6970
return Promise.reject(err);
7071
}
7172

72-
const pipeline = redis.pipeline([
73-
['hset', key(userId, USERS_DATA), USERS_ALIAS_FIELD, alias],
74-
['hset', key(userId, USERS_METADATA, defaultAudience), USERS_ALIAS_FIELD, JSON.stringify(alias)],
75-
]);
73+
const pipeline = redis.pipeline();
74+
const userMetaData = new UserMetadata(pipeline);
75+
76+
pipeline.hset(key(userId, USERS_DATA), USERS_ALIAS_FIELD, alias);
77+
userMetaData.update(userId, USERS_ALIAS_FIELD, JSON.stringify(alias), defaultAudience);
7678

7779
if (activeUser) {
7880
pipeline.sadd(USERS_PUBLIC_INDEX, username);

src/actions/ban.js

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ const mapValues = require('lodash/mapValues');
44
const redisKey = require('../utils/key.js');
55
const { getInternalData } = require('../utils/userData');
66
const handlePipeline = require('../utils/pipelineError.js');
7+
const UserMetadata = require('../utils/metadata/user');
8+
79
const {
8-
USERS_DATA, USERS_METADATA,
9-
USERS_BANNED_FLAG, USERS_TOKENS, USERS_BANNED_DATA,
10+
USERS_DATA, USERS_BANNED_FLAG, USERS_TOKENS, USERS_BANNED_DATA,
1011
} = require('../constants.js');
1112

1213
// helper
@@ -25,26 +26,30 @@ function lockUser({
2526
remoteip: remoteip || '',
2627
},
2728
};
29+
const pipeline = redis.pipeline();
30+
const userMetadata = new UserMetadata(pipeline);
31+
32+
pipeline.hset(redisKey(id, USERS_DATA), USERS_BANNED_FLAG, 'true');
33+
// set .banned on metadata for filtering & sorting users by that field
34+
userMetadata.updateMulti(id, mapValues(data, stringify), defaultAudience);
35+
pipeline.del(redisKey(id, USERS_TOKENS));
2836

29-
return redis
30-
.pipeline()
31-
.hset(redisKey(id, USERS_DATA), USERS_BANNED_FLAG, 'true')
32-
// set .banned on metadata for filtering & sorting users by that field
33-
.hmset(redisKey(id, USERS_METADATA, defaultAudience), mapValues(data, stringify))
34-
.del(redisKey(id, USERS_TOKENS))
35-
.exec();
37+
return pipeline.exec();
3638
}
3739

3840
function unlockUser({ id }) {
3941
const { redis, config } = this;
4042
const { jwt: { defaultAudience } } = config;
43+
const pipeline = redis.pipeline();
44+
const userMetadata = new UserMetadata(pipeline);
4145

42-
return redis
43-
.pipeline()
44-
.hdel(redisKey(id, USERS_DATA), USERS_BANNED_FLAG)
45-
// remove .banned on metadata for filtering & sorting users by that field
46-
.hdel(redisKey(id, USERS_METADATA, defaultAudience), 'banned', USERS_BANNED_DATA)
47-
.exec();
46+
pipeline.hdel(redisKey(id, USERS_DATA), USERS_BANNED_FLAG);
47+
// remove .banned on metadata for filtering & sorting users by that field
48+
userMetadata.delete(id, [
49+
'banned',
50+
USERS_BANNED_DATA,
51+
], defaultAudience);
52+
return pipeline.exec();
4853
}
4954

5055
/**

src/actions/organization/members/permission.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const { checkOrganizationExists } = require('../../../utils/organization');
55
const redisKey = require('../../../utils/key');
66
const handlePipeline = require('../../../utils/pipelineError');
77
const getUserId = require('../../../utils/userData/getUserId');
8+
const UserMetadata = require('../../../utils/metadata/user');
89
const { ErrorUserNotMember, USERS_METADATA, ORGANIZATIONS_MEMBERS } = require('../../../constants');
910

1011
/**
@@ -41,7 +42,9 @@ async function setOrganizationMemberPermission({ params }) {
4142
permissions = JSON.stringify(permissions);
4243

4344
const pipeline = redis.pipeline();
44-
pipeline.hset(memberMetadataKey, organizationId, permissions);
45+
const userMetadata = new UserMetadata(pipeline);
46+
47+
userMetadata.update(userId, organizationId, permissions);
4548
pipeline.hset(redisKey(organizationId, ORGANIZATIONS_MEMBERS, userId), 'permissions', permissions);
4649

4750
return pipeline.exec().then(handlePipeline);

src/actions/organization/members/remove.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const redisKey = require('../../../utils/key');
33
const getUserId = require('../../../utils/userData/getUserId');
44
const handlePipeline = require('../../../utils/pipelineError');
55
const { checkOrganizationExists } = require('../../../utils/organization');
6+
const UserMetadata = require('../../../utils/metadata/user');
67
const {
78
ORGANIZATIONS_MEMBERS,
89
USERS_METADATA,
@@ -34,9 +35,10 @@ async function removeMember({ params }) {
3435
}
3536

3637
const pipeline = redis.pipeline();
38+
const userMetadata = new UserMetadata(pipeline);
3739
pipeline.del(memberKey);
3840
pipeline.zrem(redisKey(organizationId, ORGANIZATIONS_MEMBERS), memberKey);
39-
pipeline.hdel(memberMetadataKey, organizationId);
41+
userMetadata.delete(userId, organizationId, audience);
4042

4143
return pipeline.exec().then(handlePipeline);
4244
}

src/actions/register.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const reduce = require('lodash/reduce');
99
const last = require('lodash/last');
1010

1111
// internal deps
12-
const setMetadata = require('../utils/updateMetadata');
12+
const UserMetadata = require('../utils/metadata/user');
1313
const redisKey = require('../utils/key');
1414
const jwt = require('../utils/jwt');
1515
const isDisposable = require('../utils/isDisposable');
@@ -213,7 +213,7 @@ async function performRegistration({ service, params }) {
213213

214214
await pipeline.exec().then(handlePipeline);
215215

216-
await setMetadata.call(service, {
216+
await new UserMetadata(service.redis).batchUpdate({
217217
userId,
218218
audience,
219219
metadata: audience.map((metaAudience) => ({

src/actions/updateMetadata.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const omit = require('lodash/omit');
22
const Promise = require('bluebird');
3-
const updateMetadata = require('../utils/updateMetadata.js');
3+
const UserMetadata = require('../utils/metadata/user');
44
const { getUserId } = require('../utils/userData');
55

66
/**
@@ -19,12 +19,15 @@ const { getUserId } = require('../utils/userData');
1919
* @apiParam (Payload) {Object} [script] - if present will be called with passed metadata keys & username, provides direct scripting access.
2020
* Be careful with granting access to this function.
2121
*/
22-
module.exports = function updateMetadataAction(request) {
23-
return Promise
22+
module.exports = async function updateMetadataAction(request) {
23+
const userId = await Promise
2424
.bind(this, request.params.username)
25-
.then(getUserId)
26-
.then((userId) => ({ ...omit(request.params, 'username'), userId }))
27-
.then(updateMetadata);
25+
.then(getUserId);
26+
27+
const userMetadata = new UserMetadata(this.redis);
28+
const updateParams = { ...omit(request.params, 'username'), userId };
29+
30+
return userMetadata.batchUpdate(updateParams);
2831
};
2932

3033
module.exports.transports = [require('@microfleet/core').ActionTransport.amqp];

src/auth/oauth/utils/attach.js

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
const get = require('lodash/get');
22
const redisKey = require('../../../utils/key');
3-
const updateMetadata = require('../../../utils/updateMetadata');
3+
const UserMetadata = require('../../../utils/metadata/user');
44
const handlePipeline = require('../../../utils/pipelineError');
55
const {
66
USERS_SSO_TO_ID,
77
USERS_DATA,
88
} = require('../../../constants');
99

10-
module.exports = function attach(account, user) {
10+
module.exports = async function attach(account, user) {
1111
const { redis, config } = this;
1212
const { id: userId } = user;
1313
const {
@@ -23,17 +23,19 @@ module.exports = function attach(account, user) {
2323
// link uid to user id
2424
pipeline.hset(USERS_SSO_TO_ID, uid, userId);
2525

26-
return pipeline.exec().then(handlePipeline)
27-
.bind(this)
28-
.return({
29-
userId,
30-
audience,
31-
metadata: {
32-
$set: {
33-
[provider]: profile,
34-
},
26+
await pipeline.exec().then(handlePipeline);
27+
28+
const userMetadata = new UserMetadata(redis);
29+
const updateParams = {
30+
userId,
31+
audience,
32+
metadata: {
33+
$set: {
34+
[provider]: profile,
3535
},
36-
})
37-
.then(updateMetadata)
38-
.return(profile);
36+
},
37+
};
38+
await userMetadata.batchUpdate(updateParams);
39+
40+
return profile;
3941
};

src/auth/oauth/utils/detach.js

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ const Errors = require('common-errors');
22

33
const get = require('../../../utils/get-value');
44
const redisKey = require('../../../utils/key');
5-
const updateMetadata = require('../../../utils/updateMetadata');
5+
const UserMetadata = require('../../../utils/metadata/user');
66
const handlePipeline = require('../../../utils/pipelineError');
77

88
const {
99
USERS_SSO_TO_ID,
1010
USERS_DATA,
1111
} = require('../../../constants');
1212

13-
module.exports = function detach(provider, userData) {
13+
module.exports = async function detach(provider, userData) {
1414
const { id: userId } = userData;
1515
const { redis, config } = this;
1616
const audience = get(config, 'jwt.defaultAudience');
@@ -28,16 +28,18 @@ module.exports = function detach(provider, userData) {
2828
// delete account reference
2929
pipeline.hdel(USERS_SSO_TO_ID, uid);
3030

31-
return pipeline.exec().then(handlePipeline)
32-
.bind(this)
33-
.return({
34-
userId,
35-
audience,
36-
metadata: {
37-
$remove: [
38-
provider,
39-
],
40-
},
41-
})
42-
.then(updateMetadata);
31+
await pipeline.exec().then(handlePipeline);
32+
33+
const userMetadata = new UserMetadata(redis);
34+
const updateParams = {
35+
userId,
36+
audience,
37+
metadata: {
38+
$remove: [
39+
provider,
40+
],
41+
},
42+
};
43+
44+
return userMetadata.batchUpdate(updateParams);
4345
};

src/constants.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ module.exports = exports = {
1818
// hashes
1919
USERS_DATA: 'data',
2020
USERS_METADATA: 'metadata',
21+
USERS_AUDIENCE: 'users-audiences',
2122
USERS_TOKENS: 'tokens',
2223
USERS_API_TOKENS: 'api-tokens',
2324
USERS_API_TOKENS_ZSET: 'api-tokens-set',
@@ -26,6 +27,7 @@ module.exports = exports = {
2627
USERS_ORGANIZATIONS: 'user-organizations',
2728
ORGANIZATIONS_DATA: 'data',
2829
ORGANIZATIONS_METADATA: 'metadata',
30+
ORGANIZATIONS_AUDIENCE: 'organization-audiences',
2931
ORGANIZATIONS_MEMBERS: 'members',
3032

3133
// standard JWT with TTL

0 commit comments

Comments
 (0)