Skip to content

Commit

Permalink
feat: delete inactive users
Browse files Browse the repository at this point in the history
* org member remove
  • Loading branch information
pajgo committed Nov 12, 2019
1 parent f9c042d commit d030408
Show file tree
Hide file tree
Showing 16 changed files with 504 additions and 87 deletions.
4 changes: 2 additions & 2 deletions src/actions/activate.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const jwt = require('../utils/jwt.js');
const { getInternalData } = require('../utils/userData');
const getMetadata = require('../utils/get-metadata');
const handlePipeline = require('../utils/pipeline-error.js');
const InactiveUser = require('../utils/inactive-user/inactive-user');
const InactiveUser = require('../utils/user/inactive-user');
const User = require('../utils/user/user');

const {
Expand Down Expand Up @@ -206,7 +206,7 @@ async function activateAction({ params }) {
};

const inactiveUsers = new InactiveUser(this);
await inactiveUsers.deleteInactive(config.deleteInactiveAccounts);
await inactiveUsers.cleanUsersOnce(config.deleteInactiveAccounts);

return Promise
.bind(context)
Expand Down
4 changes: 2 additions & 2 deletions src/actions/register.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const checkLimits = require('../utils/check-ip-limits');
const challenge = require('../utils/challenges/challenge');
const handlePipeline = require('../utils/pipeline-error');
const hashPassword = require('../utils/register/password/hash');
const InactiveUser = require('../utils/inactive-user/inactive-user');
const InactiveUser = require('../utils/user/inactive-user');

const {
USERS_REF,
Expand Down Expand Up @@ -175,7 +175,7 @@ async function performRegistration({ service, params }) {
}

const inactiveUsers = new InactiveUser(service);
await inactiveUsers.deleteInactive(config.deleteInactiveAccounts);
await inactiveUsers.cleanUsersOnce(config.deleteInactiveAccounts);

const [creatorAudience] = audience;
const defaultAudience = last(audience);
Expand Down
2 changes: 1 addition & 1 deletion src/actions/remove.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const intersection = require('lodash/intersection');
const { getInternalData } = require('../utils/userData');
const getMetadata = require('../utils/get-metadata');
const User = require('../utils/user/user');
const InactiveUser = require('../utils/inactive-user/inactive-user');
const InactiveUser = require('../utils/user/inactive-user');
const {
USERS_ID_FIELD,
USERS_ADMIN_ROLE,
Expand Down
52 changes: 0 additions & 52 deletions src/utils/inactive-user/inactive-user.js

This file was deleted.

22 changes: 0 additions & 22 deletions src/utils/inactive-user/redis/inactive-user.js

This file was deleted.

19 changes: 19 additions & 0 deletions src/utils/metadata/redis/metadata.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const Promise = require('bluebird');
const mapValues = require('lodash/mapValues');
const pick = require('lodash/pick');
const assert = require('assert');
const { HttpStatusError } = require('common-errors');
const handlePipeline = require('../../pipeline-error');
Expand Down Expand Up @@ -38,6 +39,16 @@ class Metadata {
return `${id}!${this.metadataKeyBase}!${audience}`;
}

/**
* Gets metadata
* @param id
* @param audience
* @returns {*}
*/
get(id, audience) {
return this.redis.hgetall(this.getMetadataKey(id, audience));
}

/**
* Updates metadata hash key
* @param {String} id
Expand Down Expand Up @@ -229,6 +240,14 @@ class Metadata {
});
return output;
}

static parse(data, fields) {
const parsedData = mapValues(data, JSON.parse);
if (fields) {
return pick(parsedData, fields);
}
return parsedData;
}
}

module.exports = Metadata;
16 changes: 15 additions & 1 deletion src/utils/metadata/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ class UserMetadata {

/**
* Deletes key from user metadata object
* @param {String|Number} id
* @param {String} hashKey
* @param {String} [audience]
* @returns {Promise|void}
Expand Down Expand Up @@ -93,6 +92,21 @@ class UserMetadata {
return this.audience.get(this.userId);
}

/**
* Gets metadata for assigned audiences
* @param audiences
* @param fields
* @returns {Promise<any[]>}
*/
async getMetadata(audiences = this.userAudience, fields = {}) {
const _audiences = Array.isArray(audiences) ? audiences : [audiences];
const data = await Promise.map(_audiences, (a) => this.metadata.get(this.userId, a));
const output = _audiences.map((audience, idx) => {
return Metadata.parse(data[idx], fields[audience]);
});
return _audiences.length === 1 ? output[0] : output;
}

async syncAudience() {
const metaKeyTemplate = this.metadata.getMetadataKey(this.userId, '{{AUDIENCE}}');
return this.audience.resyncSet(this.userId, metaKeyTemplate);
Expand Down
35 changes: 35 additions & 0 deletions src/utils/organization/member/member.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const RedisOrgMember = require('./redis/member');

/**
* Class handing Organization Member data
*/
class OrganizationMember {
/**
* @param {ioredis}redis
* @param {String|Number}memberId
* @param {String|Number}orgId
*/
constructor(redis, memberId, orgId) {
this.backend = new RedisOrgMember(redis);
this.id = memberId;
this.orgId = orgId;
}

/**
* Deletes Organization Member record
* @returns {*}
*/
delete() {
return this.backend.delete(this.orgId, this.id);
}

getOrganizationMemberKey(memberId = this.id, orgId = this.orgId) {
return RedisOrgMember.getRedisKey(orgId, memberId);
}

static using(redis, memberId, orgId) {
return new OrganizationMember(redis, memberId, orgId);
}
}

module.exports = OrganizationMember;
66 changes: 66 additions & 0 deletions src/utils/organization/member/redis/member.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const mapValues = require('lodash/mapValues');
const assert = require('assert');
const { isRedis } = require('../../../asserts/redis');
const isValidId = require('../../../asserts/id');

const {
ORGANIZATIONS_MEMBERS,
} = require('../../../../constants');

const JSONStringify = (data) => JSON.stringify(data);

/**
* Class handling Organization member Redis backend
*/
class OrganizationMember {
/**
* @param {ioredis|Pipeline}redis
*/
constructor(redis) {
assert(isRedis(redis), 'must be a valid redis instance');
this.redis = redis;
}

/**
* Generates Organization member Redis key
* @param {String|Number}orgId
* @param {String|Number}memberId
* @returns {string}
*/
static getRedisKey(orgId, memberId) {
assert(isValidId(orgId), 'must be valid organization id');
assert(isValidId(memberId), 'must be valid member id');
return `${orgId}!${ORGANIZATIONS_MEMBERS}!${memberId}`;
}

/**
* Deletes Organization Member key
* @param {String|Number}orgId
* @param {String|Number}memberId
* @param {ioredis|Pipeline}[redis]
* @returns {*}
*/
delete(orgId, memberId, redis = this.redis) {
assert(isRedis(redis), 'must be a valid redis instance');
return redis.del(OrganizationMember.getRedisKey(orgId, memberId));
}

/**
* Updates Organization member hash contents
* @param {String|Number}orgId
* @param {String|Number}memberId
* @param {Object}params
* @param redis
* @returns {*}
*/
update(orgId, memberId, params, redis = this.redis) {
assert(isRedis(redis), 'must be a valid redis instance');
return redis.hmset(OrganizationMember.getRedisKey(orgId, memberId), OrganizationMember.stringify(params));
}

static stringify(params) {
return mapValues(params, JSONStringify);
}
}

module.exports = OrganizationMember;
41 changes: 41 additions & 0 deletions src/utils/organization/organization.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const Promise = require('bluebird');
const RedisOrganization = require('./redis/organization');
const OrganizationMember = require('./member/member');

/**
* Class Handing Organization actions
*/
class Organization {
id = undefined;

constructor(redis, orgId) {
this.redis = redis;
this.id = orgId;
this.backend = new RedisOrganization(redis);
}

removeMember(memberId) {
const orgMember = OrganizationMember.using(this.redis, memberId, this.id);
const memberKey = orgMember.getOrganizationMemberKey();
return Promise.all([
orgMember.delete(),
this.backend.removeMember(this.id, memberKey, this.redis),
]);
}

static filterIds(obj) {
const ids = [];
const re = /^\d+$/;
for (const [key] of Object.entries(obj)) {
if (re.test(key)) ids.push(key);
}
return ids;
}

static using(orgId, redis) {
const org = new Organization(redis, orgId);
return org;
}
}

module.exports = Organization;
43 changes: 43 additions & 0 deletions src/utils/organization/redis/organization.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const assert = require('assert');
const { isRedis } = require('../../asserts/redis');
const isValidId = require('../../asserts/id');
const isNotEmptyString = require('../../asserts/string-not-empty');

const { ORGANIZATIONS_MEMBERS } = require('../../../constants');

/**
* Class handles Organization Data Redis Backend
*/
class Organization {
/**
* @param {ioredis|Pipeline}redis
*/
constructor(redis) {
assert(isRedis(redis), 'must be a valid redis instance');
this.redis = redis;
}

/**
* Gets Key with Organization information
* @param {String|Number}orgId
* @returns {string}
*/
static getMembersKey(orgId) {
assert(isValidId(orgId), 'must be valid organization id');
return `${orgId}!${ORGANIZATIONS_MEMBERS}`;
}

/**
* Deletes provided member key from Organization Members list
* @param {String|Number}orgId
* @param {String}memberKey
* @param {ioredis|Pipeline}[redis]
* @returns {*}
*/
removeMember(orgId, memberKey, redis = this.redis) {
assert(isNotEmptyString(memberKey), 'must be not epty string');
return redis.zrem(Organization.getMembersKey(orgId), memberKey);
}
}

module.exports = Organization;
Loading

0 comments on commit d030408

Please sign in to comment.