Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
"apidoc": "^0.17.7",
"apidoc-plugin-schema": "^0.1.8",
"babel-eslint": "^10.0.1",
"babel-plugin-istanbul": "^5.1.2",
"babel-plugin-istanbul": "^5.1.3",
"chai": "^4.2.0",
"cheerio": "^1.0.0-rc.3",
"codecov": "^3.3.0",
Expand Down
114 changes: 55 additions & 59 deletions schemas/getMetadata.json
Original file line number Diff line number Diff line change
@@ -1,63 +1,59 @@
{
"$id": "getMetadata",
"type": "object",
"required": [
"username",
"audience"
],
"properties": {
"username": {
"oneOf": [
{
"type": "string",
"minLength": 1,
"maxLength": 50
},
{
"type": "array",
"minItems": 1,
"unique": true,
"items": {
"type": "string",
"minLength": 1,
"maxLength": 50
}
}
]
},
"public": {
"type": "boolean"
},
"audience": {
"oneOf": [
{
"type": "string",
"minLength": 1
},
{
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"minItems": 1
}
]
"$id": "getMetadata",
"type": "object",
"required": [
"username",
"audience"
],
"properties": {
"username": {
"anyOf": [{
"type": "string",
"minLength": 1,
"maxLength": 50
}, {
"type": "array",
"minItems": 1,
"unique": true,
"items": {
"type": "string",
"minLength": 1,
"maxLength": 50
}
}]
},
"public": {
"type": "boolean"
},
"audience": {
"anyOf": [{
"type": "string",
"minLength": 1
}, {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"fields": {
"type": "object",
"minProperties": 1,
"patternProperties": {
"^.+$": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "string",
"minLength": 1
}
}
}
"minItems": 1
}]
},
"includingBanned": {
"type": "boolean",
"default": true
},
"fields": {
"type": "object",
"minProperties": 1,
"additionalProperties": {
"type": "array",
"minItems": 1,
"uniqueItems": true,
"items": {
"type": "string",
"minLength": 1
}
}
}
}
}
}
53 changes: 27 additions & 26 deletions src/actions/getMetadata.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const Promise = require('bluebird');
const Errors = require('common-errors');
const noop = require('lodash/noop');
const identity = require('lodash/identity');
const get = require('lodash/get');
const get = require('../utils/get-value');
const getMetadata = require('../utils/getMetadata');
const { getUserId } = require('../utils/userData');
const { USERS_ALIAS_FIELD } = require('../constants');
Expand All @@ -17,19 +17,15 @@ const { isArray } = Array;
*/
function isPublic(audiences) {
return (metadata, username) => {
let notFound = true;

// iterate over passed audiences, generally we only retrieve one audience
// so this check is cheap
audiences.forEach((audience) => {
if (notFound && get(metadata, [audience, USERS_ALIAS_FIELD]) === username) {
notFound = false;
for (const audience of Object.values(audiences)) {
if (get(metadata, [audience, USERS_ALIAS_FIELD]) === username) {
return;
}
});

if (notFound) {
throw new Errors.HttpStatusError(404, 'username was not found');
}

throw new Errors.HttpStatusError(404, 'username was not found');
};
}

Expand All @@ -38,23 +34,23 @@ function isPublic(audiences) {
* @param {String} username
* @return {Promise}
*/
function retrieveMetadata(username) {
return Promise
.bind(this.service, username)
.then(getUserId)
.then(userId => [userId, this.audiences, this.fields])
.spread(getMetadata)
.tap(metadata => this.filter(metadata, username));
async function retrieveMetadata(username) {
const { service, audiences, fields, verifyBanned } = this;

const userId = await getUserId.call(service, username, verifyBanned);
const metadata = await getMetadata.call(service, userId, audiences, fields);

this.filter(metadata, username);

return metadata;
}

/**
* If we request only 1 user - return unwrapped array
* @param {Array} responses
* @return {Array|Object}
*/
function extractResponse(responses) {
return responses[0];
}
const extractResponse = responses => responses[0];

/**
* @api {amqp} <prefix>.getMetadata Retrieve Public Data
Expand All @@ -73,11 +69,12 @@ function extractResponse(responses) {
* @apiParam (Payload) {String[]} fields.* - fields to return from a passed audience
*
*/
module.exports = function getMetadataAction(request) {
async function getMetadataAction(request) {
const {
audience: _audience,
username: _username,
public: isPublicResponse,
includingBanned,
fields,
} = request.params;

Expand All @@ -92,13 +89,17 @@ module.exports = function getMetadataAction(request) {
usernames,
filter,
fields,
verifyBanned: includingBanned === false,
service: this,
};

return Promise
const response = await Promise
.bind(ctx, usernames)
.map(retrieveMetadata)
.then(unnest);
};
.map(retrieveMetadata);

return unnest(response);
}

getMetadataAction.transports = [ActionTransport.amqp, ActionTransport.internal];

module.exports.transports = [ActionTransport.amqp, ActionTransport.internal];
module.exports = getMetadataAction;
1 change: 1 addition & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ module.exports = exports = {
USERS_INVALID_TOKEN: new HttpStatusError(403, 'invalid token'),
USERS_MALFORMED_TOKEN: new HttpStatusError(403, 'malformed token'),
USER_ALREADY_ACTIVE: new HttpStatusError(417, 'this user is already active'),
ErrorAccountLocked: new HttpStatusError(423, 'Account has been locked'),
ErrorConflictUserExists: new HttpStatusError(409, 'user already exists'),
ErrorConflictOrganizationExists: new HttpStatusError(409, 'organization already exists'),
ErrorOrganizationNotFound: new HttpStatusError(404, 'organization not found'),
Expand Down
8 changes: 3 additions & 5 deletions src/utils/isBanned.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
const Promise = require('bluebird');
const Errors = require('common-errors');
const { USERS_BANNED_FLAG } = require('../constants.js');
const { USERS_BANNED_FLAG, ErrorAccountLocked } = require('../constants');

module.exports = function isBanned(data) {
if (String(data[USERS_BANNED_FLAG]) === 'true') {
return Promise.reject(new Errors.HttpStatusError(423, 'Account has been locked'));
throw ErrorAccountLocked;
}

return Promise.resolve(data);
return data;
};
2 changes: 1 addition & 1 deletion src/utils/userData/getInternalData.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function handleNotFound(data) {
}

function reduceData(data) {
return reduce(data, reducer, {});
return reduce(data, reducer, Object.create(null));
}

function getInternalData(userKey, fetchData = true) {
Expand Down
14 changes: 10 additions & 4 deletions src/utils/userData/getUserId.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
const getInternalData = require('./getInternalData');
const isBanned = require('../isBanned');

function getUserId(username) {
return getInternalData
.call(this, username, false)
.get('id');
async function getUserId(username, verifyBanned = false) {
const internalData = await getInternalData
.call(this, username, verifyBanned);

if (verifyBanned === true) {
isBanned(internalData);
}

return internalData.id;
}

module.exports = getUserId;
2 changes: 1 addition & 1 deletion test/suites/activate.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const is = require('is');
const sinon = require('sinon');

describe('#activate', function activateSuite() {
const email = 'v@aminev.me';
const email = 'spa@aminev.me';

beforeEach(global.startService);
afterEach(global.clearRedis);
Expand Down
Loading