Various updates.

This commit is contained in:
Julien Fontanet 2013-07-10 18:11:10 +02:00
parent 2134e3b4d1
commit 16667e0d40
5 changed files with 123 additions and 101 deletions

View File

@ -144,9 +144,6 @@ Api.fn.session = {
}
return this.users.findWhere({'email': p_email}).then(function (user) {
console.log(user);
if (!user)
{
throw Api.err.INVALID_CREDENTIAL;
@ -177,15 +174,17 @@ Api.fn.session = {
throw Api.err.ALREADY_AUTHENTICATED;
}
var token = this.tokens.get(p_token);
return this.tokens.get(p_token).then(function (token) {
if (!token)
{
throw Api.err.INVALID_CREDENTIAL;
}
session.set('token_id', token.id);
session.set('user_id', token.user_id);
session.set('token_id', token.get('id'));
session.set('user_id', token.get('user_id'));
return true;
});
},
'getUser': deprecated(function (session) {
@ -195,7 +194,9 @@ Api.fn.session = {
return null;
}
return _.pick(this.users.get(user_id), 'id', 'email');
return this.users.get(user_id).then(function (user) {
return _.pick(user.properties, 'id', 'email');
});
}),
'getUserId': function (session) {
@ -296,13 +297,8 @@ Api.fn.user = {
return users.update(user);
}).then(
function () {
return true;
},
function () {
// @todo Find a better error.
return Api.err.INVALID_PARAMS;
}
true,
Q.reject(Api.err.INVALID_PARAMS)
);
},
};
@ -320,7 +316,7 @@ Api.fn.token = {
// @todo Token permission.
this.tokens.generate(user_id).then(function (token) {
return this.tokens.generate(user_id).then(function (token) {
return token.get('id');
});
},
@ -328,13 +324,14 @@ Api.fn.token = {
'delete': function (session, req) {
var p_token = req.params.token;
if (!this.tokens.get(p_token))
var tokens = this.tokens;
return tokens.get(p_token).then(function (token) {
if (!token)
{
throw Api.err.INVALID_PARAMS;
}
return this.tokens.remove(p_token).then(function () {
return true;
return tokens.remove(p_token).then(true);
});
},
};
@ -398,9 +395,7 @@ Api.fn.server = {
// @todo Disconnect the server.
return this.servers.remove(p_id).then(function () {
return true;
});
return this.servers.remove(p_id).then(true);
},
'connect': function () {

View File

@ -4,18 +4,18 @@ var Q = require('q');
//////////////////////////////////////////////////////////////////////
// @todo Add events.
function Collection(items)
function Collection(models)
{
// Parent constructor.
Collection.super_.call(this);
this.items = [];
this.models = [];
this.next_id = 0;
if (items)
if (models)
{
this.add(items);
this.add(models);
}
}
require('util').inherits(Collection, require('events').EventEmitter);
@ -23,56 +23,69 @@ require('util').inherits(Collection, require('events').EventEmitter);
Collection.prototype.model = require('./model');
/**
* Adds new items to this collection.
* Adds new models to this collection.
*/
Collection.prototype.add = function (items) {
Collection.prototype.add = function (models) {
var array = true;
if (!_.isArray(items))
if (!_.isArray(models))
{
items = [items];
models = [models];
array = false;
}
_.each(items, function (item, i) {
if ( !(item instanceof this.model) )
_.each(models, function (model, i) {
if ( !(model instanceof this.model) )
{
item = new (this.model)(item);
items[i] = item;
model = new this.model(model);
models[i] = model;
}
var error = item.validate();
var error = model.validate();
if (undefined !== error)
{
// @todo Better system inspired by Backbone.js.
throw error;
}
var id = item.get('id');
var id = model.get('id');
if (undefined === id)
{
id = this.next_id++;
item.set('id', id);
model.set('id', id);
}
// Existing items are ignored.
if (this.items[id])
// Existing models are ignored.
if (this.models[id])
{
return Q.reject('cannot add existing items!');
return Q.reject('cannot add existing models!');
}
this.items[id] = item.properties;
this.models[id] = model.properties;
}, this);
/* jshint newcap: false */
return Q(array ? items : items[0]);
return Q(array ? models : models[0]);
};
Collection.prototype.get = function (id) {
/* jshint newcap:false */
var model = this.models[id];
if (!model)
{
return Q(null);
}
return Q(new this.model(model));
};
/**
*
*/
Collection.prototype.exists = function (id) {
return (undefined !== this.items[id]);
return (undefined !== this.models[id]);
};
/**
@ -81,11 +94,13 @@ Collection.prototype.exists = function (id) {
Collection.prototype.findWhere = function (properties) {
/* jshint newcap: false */
return Q(_.findWhere(this.items, properties));
var model = _.findWhere(this.models, properties);
return Q(model ? new this.model(model) : null);
};
/**
* Removes items from this collection.
* Removes models from this collection.
*/
Collection.prototype.remove = function (ids) {
if (!_.isArray(ids))
@ -94,8 +109,8 @@ Collection.prototype.remove = function (ids) {
}
_.each(ids, function (id) {
delete this.items[id];
});
delete this.models[id];
}, this);
// @todo Maybe return a more meaningful value.
/* jshint newcap: false */
@ -103,24 +118,25 @@ Collection.prototype.remove = function (ids) {
};
/**
* Updates existing items.
* Updates existing models.
*/
Collection.prototype.update = function (items) {
Collection.prototype.update = function (models) {
var array = true;
if (!_.isArray(items))
if (!_.isArray(models))
{
items = [items];
models = [models];
array = false;
}
_.each(items, function (properties, i) {
// @todo Rewrite.
_.each(models, function (properties, i) {
if (properties instanceof this.model)
{
properties = properties.properties;
}
// @todo
// var error = item.validate();
// var error = model.validate();
// if (undefined !== error)
// {
// // @todo Better system inspired by Backbone.js.
@ -129,31 +145,31 @@ Collection.prototype.update = function (items) {
var id = properties.id;
var item = this.items[id];
var model = this.models[id];
// Missing items are ignored.
if (!item)
// Missing models are ignored.
if (!model)
{
return Q.reject('missing item!');
return Q.reject('missing model!');
}
item.set(properties);
_.extend(model.properties, model);
items[i] = item;
models[i] = model;
});
/* jshint newcap: false */
return Q(array ? items : items[0]);
return Q(array ? models : models[0]);
};
/**
* Smartly updates the collection.
*
* - Adds new items.
* - Updates existing items.
* - Removes missing items.
* - Adds new models.
* - Updates existing models.
* - Removes missing models.
*/
Collection.prototype.set = function (/*items*/) {
Collection.prototype.set = function (/*models*/) {
throw 'not implemented';
};

View File

@ -63,7 +63,15 @@ function json_api_call(session, message)
'id': req.id,
});
},
format_error
function (error) {
if (error instanceof Error)
{
console.error(error);
return format_error(Api.err.SERVER_ERROR);
}
return format_error(error);
}
);
}
@ -149,4 +157,4 @@ require('net').createServer(function (socket) {
socket.once('close', function () {
session.close();
});
}).listen(__dirname +'/../socket'); // @todo Should be configurable.
}).listen(8081); // @todo Should be configurable.

View File

@ -7,7 +7,7 @@ function Model(properties)
// Parent constructor.
Model.super_.call(this);
this.properties = this['default'];
this.properties = _.extend({}, this['default']);
if (properties)
{

View File

@ -35,12 +35,12 @@ var check = function () {
// user.permission).
var Token = Model.extend({
// Validates model attributes.
'validate': function (attr) {
check(attr.id).len(10);
check(attr.user_id).isInt();
// 'validate': function (attr) {
// check(attr.id).len(10);
// check(attr.user_id).isInt();
return check.pop();
},
// return check.pop();
// },
}, {
'generate': function (user_id) {
return Q.ninvoke(crypto, 'randomBytes', 32).then(function (buf) {
@ -57,26 +57,21 @@ var User = Model.extend({
'permission': 'none',
},
'initialize': function ()
{
this.on('change:password', function (model, password) {
this.unset('password', {'silent': true});
var user = this;
hashy.hash(password).then(function (hash) {
user.set('pw_hash', hash);
}).done();
});
},
// Validates model attributes.
'validate': function (attr) {
check(attr.id).isInt();
check(attr.email).isEmail();
check(attr.pw_hash).len(40);
check(attr.permission).isIn('none', 'read', 'write', 'admin');
// 'validate': function (attr) {
// check(attr.id).isInt();
// check(attr.email).isEmail();
// check(attr.pw_hash).len(40);
// check(attr.permission).isIn('none', 'read', 'write', 'admin');
return check.pop();
// return check.pop();
// },
'setPassword': function (password) {
var self = this;
return hashy.hash(password).then(function (hash) {
self.set('pw_hash', hash);
});
},
// Checks and updates the hash if necessary.
@ -92,8 +87,10 @@ var User = Model.extend({
if (hashy.needsRehash(hash))
{
user.set('password', password);
return user.setPassword(password).then(true);
}
return true;
});
},
@ -122,8 +119,10 @@ var Tokens = Collection.extend({
'model': Token,
'generate': function (user_id) {
return this.model.generate(user_id).then(function (token) {
return this.add(token);
var self = this;
return Token.generate(user_id).then(function (token) {
return self.add(token);
});
}
});
@ -143,6 +142,10 @@ function Xo()
this.servers = new Servers();
this.tokens = new Tokens();
this.users = new Users();
this.users.add({
'email': 'bob@gmail.com',
'pw_hash': '$2a$10$PsSOXflmnNMEOd0I5ohJQ.cLty0R29koYydD0FBKO9Rb7.jvCelZq',
}).done();
// This events are used to automatically close connections if the
// associated credentials are invalidated.
@ -157,7 +160,7 @@ function Xo()
});
});
}
require('util').inherits(Collection, require('events').EventEmitter);
require('util').inherits(Xo, require('events').EventEmitter);
module.exports = function () {
return new Xo();