passing 11/11 0.3.0-pre

This commit is contained in:
Ritchie Martori
2012-03-07 16:14:47 -07:00
parent ae2eb1dc0a
commit 32cce09157
27 changed files with 642 additions and 385 deletions

View File

@@ -1 +1,12 @@
module.exports = require('mdoq').require('mdoq-http');
module.exports = require('mdoq')
.require('mdoq-http')
.use(function (req, res, next) {
if(res.statusCode >= 400) {
var err = res.data;
res.data = undefined;
next(err);
} else {
next();
}
})
;

View File

@@ -0,0 +1,8 @@
module.exports = require('../types/collection')
.use('/resources')
;
// TODO
// - Run migration on PUT (when name is deleted remove property)
// - PUT requests come back {task: {$renameFrom: 'title'}}
// - or

View File

@@ -0,0 +1,4 @@
module.exports = require('../types/collection')
.use('/sessions')
;

4
lib/collections/types.js Normal file
View File

@@ -0,0 +1,4 @@
module.exports = function (req, res, next) {
res.data = require('../types');
next();
};

8
lib/db.js Normal file
View File

@@ -0,0 +1,8 @@
/**
* The unrestriced / private interface to the database.
*/
module.exports = require('mdoq')
.require('mdoq-mongodb')
.use('localhost')
;

View File

@@ -1,15 +1,41 @@
/**
* Module dependencies.
* Extend a basic mdoq object
*/
var express = require('express')
, storage = require('./storage')
;
var dpd = require('mdoq')
/**
* Export the deployd constructor.
* Export the dpd mdoq object as the public interface.
*/
module.exports = dpd
/**
* Provide optional network access via an http server.
*/
.use(require('./server'))
/**
* Every request will try to establish a session.
*/
module.exports = function (name) {
return require('./server')(name);
}
.use(require('./session'))
/**
* If a session was established, continue to the router.
*/
.use(require('./router'))
/**
* If the router finds a resource, continue to validation.
*/
.use(require('./validation'))
/**
* If the request passes validation, continue to the requested resource.
*/
.use(require('./resource'))

43
lib/resource.js Normal file
View File

@@ -0,0 +1,43 @@
/**
* Dependencies
*/
var types = require('./types');
/**
* Execute the request against the provided resource.
*/
module.exports = function (req, res, next, end) {
// skip without a resource
if(!req.resource) return next(new Error('404'));
// use type's require if provided
var modulePath = (types[req.resource.type] || req.resource).require;
// skip without a module path
if(!modulePath) return next(new Error('Resource does not have a require property.'));
// require module
var module = require(modulePath);
// end with the module as the finalware
if(module.middleware || typeof module == 'function') {
end(function (req, res, next) {
if(typeof module == 'function') {
module(req, res, next);
} else{
module.exec(req, function (err, data) {
res.data = data;
next();
})
}
});
} else {
return next(new Error('The provided module is not supported'));
}
// continue
next();
}

View File

@@ -1,5 +0,0 @@
var debug = require('mdoq').util.debug;
module.exports = require('./storage')
.use('/resources')
;

View File

@@ -2,43 +2,50 @@
* Dependencies
*/
var storage = require('./storage')
, resources = require('./resources')
var resources = require('./collections/resources')
, revalidator = require('revalidator')
;
module.exports = function (req, res, next) {
var path = req.url.split('?')[0];
resources.get({path: path}, function (err, resource) {
// HACK - REMOVE ONCE `first()` LANDS IN MDOQ-MONGODB
resource = resource && resource[0] || resource;
if(resource && tryingToModify(req)) {
if(resource.settings) {
var result = revalidator.validate(req.body, {properties: resource.settings});
if(result.valid) {
storage.proxy().call(this, req, res, next);
} else {
res.send(result);
}
} else {
storage.proxy().call(this, req, res, next);
}
} else if(resource) {
storage.exec(req, function (err, r) {
res.send(err || r);
});
} else {
next();
}
})
}
/**
* Attach the requested resource definition.
*/
function tryingToModify(req) {
var method = req.method;
return method === 'POST' || method === 'PUT';
}
module.exports = function (req, res, next) {
var parsed = req.url.split('?')[0].replace('/', '').split('/')
, collections = req.collections = []
, references = req.references = []
, internals = {'/types': './collections/types', '/resources': './collections/resources'}
, method = req.method
, path = '/'
;
// parse url into references and collections
parsed.forEach(function (part, i) {
(i % 2 ? references : collections).push(part);
});
path += collections[0];
// route to the first collection
resources.get({path: path}).first(function (err, resource) {
// TODO only allow root
if(!resource && internals[path]) {
resource = {
require: internals[path],
path: path
}
}
// for future reference
req.resource = resource;
if(!resource) {
console.log(req.method, req.url, 404);
err = new Error('404');
}
// continue
next(err);
});
}

View File

@@ -1,37 +1,63 @@
var dpd = require('./deployd')
, name = dpd.name
, express = require('express')
, server = express.createServer(express.bodyParser())
, resources = require('./resources')
, router = require('./router')
, types = require('./types')
;
/**
* Serve storage at each resource route.
* Dependencies
*/
server.use(router);
var express = require('express')
, parse = require('url').parse;
/**
* Serve resources over http.
* Http server as a middleware
*/
server.use('/resources', resources.proxy());
var middleware = function (req, res, next) {
next();
};
/**
* Serve resource types over http.
* Expose the mdoq object over http.
*/
server.get('/types', function (req, res) {
res.send(types);
});
middleware.listen = function (callback) {
var server = this.server = express.createServer(express.bodyParser(), express.cookieParser())
, url = parse(this.url || 'http://localhost:2304');
// port
var port = url.port || 2304;
// host
var hostname = url.hostname || 'localhost';
// proxy requests into the current mdoq stack
// executing the stack when a request comes in
server.use(this.proxy());
// error handling
server.error(function (err, req, res, next) {
if(typeof err == 'object' && !(err instanceof Error)) {
res.statusCode = 400;
res.send(err);
} else {
next(err);
}
});
// start the server
server.listen(port, hostname, callback);
// chainable
return this;
};
/**
* Export a function to mount the new server to a name.
* Stop the server from accepting new connections.
*/
module.exports = function (name) {
server.name = name || 'deployd';
return server;
};
middleware.close = function () {
this.server.close();
};
/**
* Export the middleware
*/
module.exports = middleware;

6
lib/session.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = function (req, res, next) {
next();
}

View File

@@ -1,4 +0,0 @@
module.exports = require('mdoq')
.require('mdoq-mongodb')
.use('mongodb://localhost/dpd-testing')
;

View File

@@ -1,12 +1,32 @@
module.exports = {
Collection: {
defaultPath: '/my-objects'
defaultPath: '/my-objects',
require: './types/collection'
},
UserCollection: {
label: 'Users Collection',
defaultPath: '/users'
defaultPath: '/users',
require: './types/user-collection',
settings: {
email: {
description: 'the unique email of the user',
type: 'string',
pattern: "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
required: true,
unique: true,
minLength: 5,
order: 0
},
password: {
description: "the user's password",
type: 'string',
required: true,
minLength: 5,
order: 1
}
}
}
};

13
lib/types/collection.js Normal file
View File

@@ -0,0 +1,13 @@
function format(name) {
name = name.toLowerCase().replace(/\W/g, '-').replace(/--+/g, '');
return '/' + name;
}
module.exports = require('mdoq')
.use(function (req, res, next) {
var path = req.resource && req.resource.path;
this.url = 'localhost/deployd' + (path || this.url);
next();
})
.require('mdoq-mongodb')
;

View File

@@ -0,0 +1,40 @@
/**
* Dependencies
*/
var sessions = require('../collections/sessions');
/**
* A collection of user objects with login/out support.
*/
module.exports = function (req, res, next) {
var col = require('./collection').use('/users');
if(~req.url.indexOf('/login')) {
console.log(req.url, req.data, 'trying to login');
col.get(req.data).first(function (err, user) {
if(user) {
// login successful - create session
sessions.post({user: user}, function (e, session) {
console.log('created session id', session._id);
res.data = session;
console.log(res.cookie);
next(e || err);
})
}
})
} else if(~req.url.indexOf('/logout')) {
if(req.session) {
} else {
next(new Error('Session not found.'));
}
} else {
col.exec(req, function (err, docs) {
res.data = docs;
next(err);
});
}
};

32
lib/validation.js Normal file
View File

@@ -0,0 +1,32 @@
/**
* Dependencies
*/
var revalidator = require('revalidator');
/**
* Validate the attached resource and request.
*/
module.exports = function (req, res, next) {
var method = req.method
, resource = req.resource
, validation
, err
;
// skip without a resource
if(!resource) return next(new Error('validation 404'));
// if trying to write data
if((method === 'POST' || method === 'PUT') && resource && resource.settings) {
// validate
validation = revalidator.validate(req.body, {properties: resource.settings});
console.log(validation);
err = validation.valid ? err : validation;
}
// continue
next(err);
}