-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathalias.js
More file actions
92 lines (76 loc) · 2.74 KB
/
alias.js
File metadata and controls
92 lines (76 loc) · 2.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
const Promise = require('bluebird');
const Errors = require('common-errors');
const { ActionTransport } = require('@microfleet/core');
const { getInternalData } = require('../utils/userData');
const isActive = require('../utils/is-active');
const isBanned = require('../utils/is-banned');
const DetailedHttpStatusError = require('../utils/detailed-error');
const handlePipeline = require('../utils/pipeline-error');
const UserMetadata = require('../utils/metadata/user');
const {
USERS_ALIAS_TO_ID,
USERS_ID_FIELD,
USERS_ALIAS_FIELD,
USERS_PUBLIC_INDEX,
USERS_USERNAME_FIELD,
lockAlias,
} = require('../constants');
/**
* @api {amqp} <prefix>.alias Add alias to user
* @apiVersion 1.0.0
* @apiName AddAlias
* @apiGroup Users
*
* @apiDescription Adds alias to existing username. This alias must be unique across system, as
* well as obide strict restrictions - ascii chars only, include numbers and dot. It's used to obfuscate
* username in public interfaces
*
* @apiParam (Payload) {String} username - currently email of the user
* @apiParam (Payload) {String{3..15}} alias - chosen alias
*
*/
async function assignAlias({ params }) {
const { redis, config: { jwt: { defaultAudience } } } = this;
const { username, internal } = params;
// lowercase alias
const alias = params.alias.toLowerCase();
const data = await Promise
.bind(this, username)
.then(getInternalData)
.tap(isBanned);
if (data[USERS_ALIAS_FIELD]) {
return Promise.reject(new Errors.HttpStatusError(417, 'alias is already assigned'));
}
// determine if user is active
const userId = data[USERS_ID_FIELD];
const activeUser = isActive(data, true);
if (!activeUser && !internal) {
return Promise.reject(DetailedHttpStatusError(412, 'Account hasn\'t been activated', { username: data[USERS_USERNAME_FIELD] }));
}
let lock;
if (!internal) {
// if we can't claim lock - must fail
lock = await this.dlock.once(lockAlias(alias));
}
try {
const assigned = await redis.hsetnx(USERS_ALIAS_TO_ID, alias, userId);
if (assigned === 0) {
const err = new Errors.HttpStatusError(409, `"${alias}" already exists`);
err.code = 'E_ALIAS_CONFLICT';
return Promise.reject(err);
}
const pipeline = this.userData.setAlias(userId, alias);
UserMetadata
.using(userId, defaultAudience, pipeline)
.update(USERS_ALIAS_FIELD, JSON.stringify(alias));
if (activeUser) {
pipeline.sadd(USERS_PUBLIC_INDEX, username);
}
return pipeline.exec().then(handlePipeline);
} finally {
// release lock, but do not wait for it to return result
if (lock !== undefined) lock.release().reflect();
}
}
assignAlias.transports = [ActionTransport.amqp, ActionTransport.internal];
module.exports = assignAlias;