blob: e835f53ff780bd2861dd2eab8844b418eed6f506 [file]
// Copyright (c) 2017 Chandan B N. All rights reserved.
const {
ObjectId
} = require('mongodb');
const mongo = require('../lib/mongo');
const USERNAME_REGEX = /^[a-zA-Z0-9]{3,64}$/;
const NAME_REGEX = /[a-zA-Z0-9]{3,64}/;
const EMAIL_REGEX = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
function collection() {
return mongo.getCollection('users');
}
function toProjection(projection) {
if (Array.isArray(projection)) {
var out = {};
for (var x of projection) {
out[x] = 1;
}
return out;
}
return projection;
}
function normalizeUpdates(update) {
var hasOperator = false;
for (var k in update) {
if (k[0] === '$') {
hasOperator = true;
break;
}
}
if (hasOperator) {
return update;
}
return {
$set: update
};
}
function normalizeUsernameForUpdate(update) {
if (update.$set && typeof update.$set.username === 'string') {
update.$set.username = update.$set.username.toLowerCase();
}
if (update.$setOnInsert && typeof update.$setOnInsert.username === 'string') {
update.$setOnInsert.username = update.$setOnInsert.username.toLowerCase();
}
return update;
}
function validateUserDocument(user) {
var issues = [];
if (!user || typeof user !== 'object') {
return new Error('User data is missing');
}
if (!user.name || !NAME_REGEX.test(user.name)) {
issues.push('Need atleast three letters in a name');
}
if (!user.username || !USERNAME_REGEX.test(user.username)) {
issues.push('Usernames should have atleast three alphanumeric characters');
}
if (!user.email || !EMAIL_REGEX.test(user.email)) {
issues.push('Invalid email address');
}
if (!user.password || typeof user.password !== 'string') {
issues.push('Password is required');
}
if (user.priv === undefined || user.priv === null || isNaN(Number(user.priv))) {
issues.push('Privilege provided is invalid');
}
if (issues.length) {
return new Error(issues.join('; '));
}
return null;
}
function findOne(query, cb) {
var p = collection().findOne(query);
if (typeof cb === 'function') {
p.then(function (doc) {
cb(null, doc);
}).catch(function (err) {
cb(err);
});
return;
}
return p;
}
function findById(id, cb) {
var qid = null;
try {
qid = new ObjectId(id);
} catch (e) {
qid = null;
}
if (!qid) {
if (typeof cb === 'function') {
cb(null, null);
return;
}
return Promise.resolve(null);
}
var p = collection().findOne({
_id: qid
});
if (typeof cb === 'function') {
p.then(function (doc) {
cb(null, doc);
}).catch(function (err) {
cb(err);
});
return;
}
return p;
}
function find(query, projection, options, cb) {
if (typeof projection === 'function') {
cb = projection;
projection = undefined;
options = undefined;
} else if (typeof options === 'function') {
cb = options;
options = undefined;
}
var findOptions = Object.assign({}, options || {});
if (projection !== undefined) {
findOptions.projection = toProjection(projection);
}
var p = collection().find(query || {}, findOptions).toArray();
if (typeof cb === 'function') {
p.then(function (docs) {
cb(null, docs);
}).catch(function (err) {
cb(err);
});
return;
}
return p;
}
function findOneAndUpdate(query, updates, options, cb) {
if (typeof options === 'function') {
cb = options;
options = undefined;
}
var update = normalizeUpdates(Object.assign({}, updates));
update = normalizeUsernameForUpdate(update);
var nativeOptions = {
upsert: options && options.upsert ? true : false,
returnDocument: options && options.new ? 'after' : 'before'
};
if (nativeOptions.upsert && options && options.setDefaultsOnInsert) {
var hasPrivInSet = !!(update.$set && Object.prototype.hasOwnProperty.call(update.$set, 'priv'));
update.$setOnInsert = Object.assign({}, update.$setOnInsert || {});
if (hasPrivInSet) {
delete update.$setOnInsert.priv;
} else if (update.$setOnInsert.priv === undefined) {
update.$setOnInsert.priv = 1;
}
}
var p = collection().findOneAndUpdate(query, update, nativeOptions);
if (typeof cb === 'function') {
p.then(function (doc) {
cb(null, doc);
}).catch(function (err) {
cb(err);
});
return;
}
return p;
}
module.exports = {
find: find,
findById: findById,
findOne: findOne,
findOneAndUpdate: findOneAndUpdate,
validateUserDocument: validateUserDocument
};