Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
etaypere committed Apr 30, 2013
0 parents commit 81a12ca
Show file tree
Hide file tree
Showing 10 changed files with 297 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/node_modules
/.idea
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Resors
=====

Resources for mongoose. Check `\example` for now.
52 changes: 52 additions & 0 deletions example/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
var express = require('express'),
http = require('http'),
path = require('path'),
models = require('./models');

var app = express();

app.set('site', 'resors');
app.set('port', 80);
app.set('mongo', 'mongodb://localhost/resors');
app.set('admin', { username: 'admin', password: 'admin'});

// dust
/*app.engine('dust', require('consolidate').dust);
app.set('view engine', 'dust');
app.set('views', path.join(__dirname, 'views'));
require('dustjs-linkedin').optimizers.format = function(ctx, node) { return node };*/

app.use(express.favicon());
//app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('magical resors'));
app.use(express.cookieSession({cookie: { maxAge: 60 * 1000 * 20 }}));
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}

// formage-admin
require('formage-admin').init(app, express, require('./models'), {
title: app.get('site') + ' Admin'
});

// mock user
app.use(function(req, res, next) {
req.user = { name: 'me', admin: true };
next();
});

require('mongoose').connect(app.get('mongo'));
app.use('/api', require('../')(express, models));
app.get('/', function(req, res) {
res.redirect('/api');
});

http.createServer(app).listen(app.get('port'), function(){
console.log('Server listening on port ' + app.get('port'));
});
13 changes: 13 additions & 0 deletions example/models/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
var path = require('path'),
fs = require('fs'),
files = fs.readdirSync(__dirname);

require('formage-admin').forms.loadTypes(require('mongoose'));

files.forEach(function(file) {
var name = path.basename(file, '.js');
if (name === 'index')
return;

exports[name] = require('./' + name);
});
67 changes: 67 additions & 0 deletions example/models/users.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
var mongoose = require('mongoose'),
Types = mongoose.Schema.Types;

var schema = new mongoose.Schema({
name: { type: String, required: true, lowercase: true, trim: true, match: /^\w+$/ },
email: String
});
schema.methods.toString = function(){
return this.name;
};
schema.statics.checkName = function(value, cb){
this.count().where('username', value).exec(function(err, count){
cb(err, count === 0)
})
};
var users = module.exports = mongoose.model('users', schema);


/*
Resors
*/
users.resors = {
allow: [ 'get', 'post', 'put', 'delete' ],
select: 'email', // TODO
editable: 'email', // TODO
filtering: 'name', // TODO
sorting: 'name', // TODO
before: function(req, res, next) {
var resors = req.resors;

// Authentication
if (!req.user)
return res.redirect('/login');

// Authorization
if (!req.user.admin)
req.resors.allow = [ 'get' ];

// Validation or sanitation (use mongoose if you can!)
if (resors.validation) {
if (!req.body.email) {
console.log('validation', req.body);
return res.status(400).json({
email: 'Email is required.'
});
}
}

next();
},
query: function(req, res, next) {
var q = res.query;
// q = q.select('name');

// Authorization
if (req.user && !req.user.admin) {
q = q.where('name', req.user.name);
}

res.query = q;
next();
},
after: function(req, res, next) {
// console.log('after', res.result);
next();
}
};
8 changes: 8 additions & 0 deletions example/public/css/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
body {
padding: 50px;
font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
}

a {
color: #00B7FF;
}
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./lib');
19 changes: 19 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
var Resors = require('./resors');

var resors = module.exports = function(express, models) {
var app = express();

app.get('/', function(req, res) {
res.json({
models: Object.keys(models)
});
});

Object.keys(models).forEach(function(name) {
var resource = Resors.fetch(models[name]);
resource.routes(app);
});

return app;
};
resors.Resors = Resors;
113 changes: 113 additions & 0 deletions lib/resors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
var extend = require('xtend');

/*
A do-nothing middleware
*/
var middleware = function(req, res, next) {
next();
};


/*
Resors Class
*/
var Resors = module.exports = function(model, options) {
this.model = model;
this.name = model.modelName;
this.options = extend(Resors.defaults, options);

Resors.register(this);
};
Resors.fn = Resors.prototype;
Resors.fn.index = function(req, res, next) {
res.query = this.model.find();
next();
};
Resors.fn.show = function(req, res, next) {
res.query = this.model.findById(req.params.id);
next();
};
Resors.fn.create = function(req, res, next) {
this.model.create(req.body, function(err, result) {
res.err = err;
res.result = result;
next();
});
};
Resors.fn.update = function(req, res, next) {
res.query = this.model.findByIdAndUpdate(req.params.id, req.body);
next();
};
Resors.fn.destroy = function(req, res, next) {
res.query = this.model.findByIdAndRemove(req.params.id);
next();
};
Resors.fn.exec = function(req, res, next) {
res.query.exec(function(err, result) {
delete res.query;
res.err = err;
res.result = result;
next();
});
};
Resors.fn.finish = function(req, res) {
if (res.err)
res.status(400).json({ err: res.err });
else
res.json(res.result);
};
Resors.fn.middlewares = function(route) {
var self = this;

return [
function(req, res, next) {
req.resors = extend({}, self.options, {
validation: ~[ 'POST', 'PUT' ].indexOf(req.method)
});
next();
},
this.options.before,
function(req, res, next) {
if (!~req.resors.allow.indexOf(req.method.toLowerCase()))
return res.status(403).end('No permissions.');
next();
},
this[route],
(~[ 'index', 'show' ].indexOf(route) ? this.options.query : middleware),
('create' != route ? this.exec : middleware),
this.options.after,
this.finish
].map(function(m) { return m.bind(self) });
};
Resors.fn.routes = function(app) {
var name = this.name;

app.get('/' + name, this.middlewares('index'));
app.get('/' + name + '/:id', this.middlewares('show'));
app.post('/' + name + '', this.middlewares('create'));
app.put('/' + name + '/:id', this.middlewares('update'));
app.delete('/' + name + '/:id', this.middlewares('destroy'));
};


/*
Resors Registry
*/
var resources = {};
Resors.register = function(resource) {
resources[resource.name] = resource;
};
Resors.fetch = function(model) {
var name = model.modelName;

if (resources[name])
return resources[name];
else
return new Resors(model, model.resors);
};
Resors.defaults = {
allow: [ 'get' ],
before: middleware,
query: middleware,
after: middleware
};
18 changes: 18 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "resors",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node example/app"
},
"dependencies": {
"express": "3.2.0",
"formage-admin": "",
"jade": "*",
"consolidate": "",
"dustjs-linkedin": "",
"dustjs-helpers": "",
"mongoose": "",
"xtend": ""
}
}

0 comments on commit 81a12ca

Please sign in to comment.