iridium
Version:
A custom lightweight ORM for MongoDB designed for power-users
172 lines (150 loc) • 5.44 kB
JavaScript
/// <reference path="../nodelib/node.js"/>
/// <reference path="../lib/Instance.js"/>
/// <reference path="../lib/Model.js"/>
/// <reference path="../lib/Database.js"/>
var _ = require('lodash');
var Database = require('iridium');
var Model = Database.Model;
var Concoction = require('concoction');
(require.modules || {}).User = module.exports = function (db) {
/// <summary>Configure the User model to use the given database</summary>
/// <param name="db" type="Database">The database connection to use</param>
/// <returns type="Model"/>
"use strict";
var database = db;
var options = {
virtuals: {
API: function () {
var $ = this;
return {
username: $.username,
fullname: $.fullname,
email: $.email,
banned: $.banned,
statistics: $.statistics,
skill: {
level: $.skill.level,
xp: $.skill.xp
},
friends: $.friends,
pending_messages: $.pending_messages,
last_seen: $.last_seen
};
}
},
methods: {
setPassword: function (newPassword, callback) {
/// <summary>Updates the user's stored password hash</summary>
/// <param name="newPassword" type="String">The new password to use for the user</param>
/// <param name="callback" type="Function">A function to be called once the user's password has been updated</param>
var passwordTest = /(?=^.{8,}$)((?=.*\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))^.*/;
if (!passwordTest.test(newPassword || '')) return callback(new Error('Password didn\'t meet the minimum safe password requirements. Passwords should be at least 8 characters long, and contain at least 3 of the following categories: lowercase letters, uppercase letters, numbers, characters'));
var hashed = require('crypto').createHash('sha512').update(database.settings.security.salt).update(newPassword).digest('hex');
this.password = hashed;
this.save(callback);
},
checkPassword: function (password) {
/// <summary>Checks whether a given password is correct for a user's account</summary>
/// <param name="password" type="String">The password to validate against the user's password hash.</param>
/// <returns type="Boolean"/>
var hashed = require('crypto').createHash('sha512').update(database.settings.security.salt).update(password).digest('hex');
return hashed == this.password;
},
addFriend: function (friend, callback) {
this.save({ $push: { friends: friend } }, callback);
},
updateLevel: function () {
/// <summary>Update's the user's current level based on the amount of XP they have. Doesn't save the user instance.</summary>
// Amount of XP required per level starts at 1200, doubles for each consecutive level
// tf. XP_n = XP_nm1 + 1200 * 2^n
var remainingXP = this.skill.xp;
var previousLevelXP = 0;
var levelXP = 1200;
var level = 0;
for(; remainingXP >= levelXP; level++, previousLevelXP = levelXP, remainingXP -= levelXP, levelXP += 1200 * Math.pow(2, level));
this.skill.level = level;
this.skill.current_level = previousLevelXP;
this.skill.next_level = levelXP;
}
},
hooks: {
creating: function (done) {
var item = this;
item._id = item.username;
if (item.username) delete item.username;
var passwordTest = /(?=^.{8,}$)((?=.*\d)(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[^A-Za-z0-9])(?=.*[a-z])|(?=.*[^A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z])|(?=.*\d)(?=.*[A-Z])(?=.*[^A-Za-z0-9]))^.*/;
if (!passwordTest.test(item.password || '')) return done('Password didn\'t meet the minimum safe password requirements. Passwords should be at least 8 characters long, and contain at least 3 of the following categories: lowercase letters, uppercase letters, numbers, characters');
item.password = require('crypto').createHash('sha512').update(database.settings.security.salt).update(item.password).digest('hex');
_.defaults(item, {
type: "Player",
banned: false,
statistics: {
won: 0,
drawn: 0,
lost: 0,
incomplete: 0
},
skill: {
matchmaking: 0,
trend: 0,
level: 0,
xp: 0,
current_level: 0,
next_level: 1200
},
friends: [],
friend_requests: [],
pending_messages: [],
sessions: [],
last_seen: new Date()
});
done();
}
},
preprocessors: [
new Concoction.Rename({
_id: 'username'
})
],
indexes: [
[{ email: 1 }, { unique: true, background: true }],
[{ type: 1 }, { background: true }],
[{ sessions: 1 }, { sparse: true, background: true }],
[{ 'skill.xp': -1 }, { background: true }]
]
};
var schema = {
_id: /[a-z0-9]+(_[a-z0-9]+)*/,
fullname: String,
email: String,
password: String,
type: /Player|Moderator|Admin/,
banned: Boolean,
statistics: {
won: Number,
drawn: Number,
lost: Number,
incomplete: Number
},
skill: {
matchmaking: Number,
trend: Number,
level: Number,
xp: Number,
current_level: Number,
next_level: Number
},
friends: [String],
pending_messages: [{
from: String,
time: Date,
message: String,
group: { $type: String, $required: false },
game: { $type: String, $required: false }
}],
sessions: [String],
friend_requests: [String],
last_seen: Date
};
return new Model(db, 'user', schema, options);
};