UNPKG

@universis/user-storage

Version:

Universis Api Server Extension for managing user remote storage

258 lines (241 loc) 9.1 kB
import {AccessDeniedError} from '@themost/common'; import {UserStorageService, UserStorageAccessConfiguration} from './service'; import {MongoAdapter} from '@themost/mongo'; import {QueryExpression} from '@themost/query'; import * as _ from 'lodash'; function escapeKey(key) { let res = key.replace(/\//ig,'.'); if (/^\./.test(res)) { return res.substr(1); } return res; } /** * Tests the given key and returns collection from key * @param key */ function testSelectAttribute(key) { // parse key const keys = escapeKey(key).split('.'); // get collection and property (if any) if (keys.length === 1) { return { collection : keys[0] }; } return { collection : keys[0], property: keys.slice(1).join('.') }; } class MongoUserStorageService extends UserStorageService { /** * @param {IApplication} app */ constructor(app) { super(app); } /** * @name RedisClient#json_set * @param {*} ...args */ /** * @name RedisClient#json_get * @param {*} ...args */ /** * * @param {DataContext} context * @param {string} key * @param {*} value * @param {number=} expiration */ async setItem(context, key, value, expiration) { // parse key const selectAttribute = testSelectAttribute(key); // get collection and property (if any) const collection = selectAttribute.collection; // get property expression let property = selectAttribute.property; // validate user const hasAccess = await context.getConfiguration().getStrategy(UserStorageAccessConfiguration).verify(context, `me/${key}`, 'write'); if (hasAccess == null) { throw new AccessDeniedError('Write access to the specified user storage key is denied'); } // get database connection const db = new MongoAdapter(this.options); if (typeof expiration === "number" && expiration > 0) { // call json_set() with expiration return await new Promise((resolve, reject) => { return reject(new Error('This operation is not supported by the specified user storage adapter.')); }); } // split property and get nested object // set item return await new Promise((resolve, reject) => { let query; let finalValue; let property1 = null; let property1value = null; // check if property contains nested properties if (property && /\./ig.test(property)) { property1 = property.split('.')[0]; } // check if item already exists if (property1) { query = new QueryExpression().select('_id', property1).from(collection).where('owner').equal(context.user.name); } else { query = new QueryExpression().select('_id').from(collection).where('owner').equal(context.user.name); } db.execute(query, null, (err, result) => { if (err) { return reject(err); } let _id; // get object id if (result && result.length) { _id = result[0]._id; // set nested property property1value = property1 ? result[0][property1] : null; } // prepare final value if (property) { finalValue = { }; if (property1) { finalValue[property1] = property1value; } // set value _.set(finalValue, property, value); // set owner Object.assign(finalValue, { "owner": context.user.name }); } else { // property does not exist so prepare simple insert statement finalValue = Object.assign(value, { "owner": context.user.name }); } // if object does not exist if (_id == null) { query = new QueryExpression().insert(finalValue).into(collection); } else { // set id Object.assign(finalValue, { "_id": _id }); // prepare update statement query = new QueryExpression().update(collection).set(finalValue).where("_id").equal(_id); } db.execute(query, null, err => { // close database connection db.close(() => { if (err) { return reject(err); } return resolve(value); }); }); }); }); } /** * @param {DataContext} context * @param {string} key */ async getItem(context, key) { // parse key const selectAttribute = testSelectAttribute(key); // validate user access const hasAccess = await context.getConfiguration().getStrategy(UserStorageAccessConfiguration).verify(context, `me/${key}`, 'read'); if (hasAccess == null) { // throw access denied throw new AccessDeniedError('Read access to the specified user storage key is denied'); } // get database connection const db = new MongoAdapter(this.options); // set item return await new Promise((resolve, reject) => { // prepare where statement const query = new QueryExpression() .select(selectAttribute.property ? selectAttribute.property : '*') .from(selectAttribute.collection) .where('owner') .equal(context.user.name); db.execute(query, null, (err, result) => { // close database connection db.close(() => { if (err) { return reject(err); } if (result && result.length) { // remove identifier delete result[0]._id; // if select contains a nested property if (selectAttribute.property) { //get nested property return resolve(_.get(result[0], selectAttribute.property)); } else { // otherwise get first item return resolve(result[0]); } } return resolve(); }); }); }); } /** * @param {DataContext} context * @param {string} key */ async removeItem(context, key) { // parse key const selectAttribute = testSelectAttribute(key); // validate user access const hasAccess = await context.getConfiguration().getStrategy(UserStorageAccessConfiguration).verify(context, `me/${key}`, 'write'); if (hasAccess == null) { throw new AccessDeniedError('Write access to the specified user storage key is denied'); } if (selectAttribute.property) { // set property to null return this.setItem(context, key, null).then( () => { return Promise.resolve(true); }); } // get database connection const db = new MongoAdapter(this.options); return await new Promise((resolve, reject) => { let query; // prepare where statement query = new QueryExpression().delete(selectAttribute.collection).where('owner').equal(context.user.name); db.execute(query, null, (err) => { // close database connection db.close(() => { if (err) { return reject(err); } return resolve(true); }); }); }); } /** * @param {DataContext} context */ async clear(context) { // validate user access const hasAccess = context.getConfiguration().getStrategy(UserStorageAccessConfiguration).verify(context, `me`, 'write'); if (hasAccess == null) { throw new AccessDeniedError('Write access to the specified user storage key is denied'); } return await new Promise((resolve, reject) => { return reject(new Error('This operation is not supported by the specified user storage adapter.')); }); } } module.exports.MongoUserStorageService = MongoUserStorageService;