mirror of
https://github.com/jsbin/jsbin.git
synced 2026-01-25 15:38:56 +00:00
Merge branch 'ably-forks-api'
This commit is contained in:
commit
e34b4a97dd
@ -33,6 +33,24 @@ The original idea spawned from a conversation with another developer in trying t
|
||||
|
||||
[Version 1](http://1.jsbin.com) of [JS Bin](http://www.flickr.com/photos/remysharp/4284906136) took me the best part of 4 hours to develop [back in 2008](http://remysharp.com/2008/10/06/js-bin-for-collaborative-javascript-debugging/), but [version 2](http://2.jsbin.com) was been rewritten from the ground up and is completely [open source](http://github.com/remy/jsbin).
|
||||
|
||||
## API
|
||||
|
||||
A simple REST based API exists for anonymous users if it is enabled in your config.*.json, or can be restricted to registered users with a key specified in `ownership.ownership_api_key`
|
||||
|
||||
If authentication is required (`allowAnonymous = false`), then an auth_key must be provided as part of an token authorization header or as a querystring with the value `api_key`. Curl examples:
|
||||
|
||||
```
|
||||
$ curl http://{{host}}/api/:bin -H "Authorization: token {{token_key}}"
|
||||
$ curl http://{{host}}/api/:bin?api_key={{token_key}}
|
||||
```
|
||||
|
||||
End points are:
|
||||
|
||||
- `GET /api/:bin` - Retrieve the latest version of the bin with that specified ID
|
||||
- `GET /api/:bin/:rev` - Retrieve the specific version of the bin with the specified ID and revision
|
||||
- `POST /api/save` - Create a new bin, the body of the post should be URL encoded and contain `html`, `javascript` and `css` parameters
|
||||
- `POST /api/:bin/save` - Create a new revision for the specified bin, the body of the post should be URL encoded and contain `html`, `javascript` and `css` parameters
|
||||
|
||||
## Build Process
|
||||
|
||||
JS Bin has been designed to work both online at [jsbin.com](http://jsbin.com) but also in your own locally hosted environment - or even live in your own site (if you do host it as a utility, do let us know by pinging [@js_bin](http://twitter.com/js_bin) on twitter).
|
||||
|
||||
@ -67,11 +67,13 @@ CREATE TABLE `ownership` (
|
||||
`name` char(50) NOT NULL,
|
||||
`key` char(255) NOT NULL,
|
||||
`email` varchar(255) NOT NULL DEFAULT '',
|
||||
`api_key` VARCHAR(255) NULL,
|
||||
`last_login` datetime NOT NULL,
|
||||
`created` datetime NOT NULL,
|
||||
`updated` datetime NOT NULL,
|
||||
PRIMARY KEY (`name`),
|
||||
KEY `name_key` (`name`,`key`)
|
||||
KEY `name_key` (`name`,`key`),
|
||||
KEY `ownership_api_key` (`api_key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ CREATE TABLE IF NOT EXISTS `ownership` (
|
||||
`name` VARCHAR(50) PRIMARY KEY NOT NULL,
|
||||
`key` VARCHAR(255) NOT NULL,
|
||||
`email` VARCHAR(255) NOT NULL DEFAULT '',
|
||||
`api_key` VARCHAR(255) NULL,
|
||||
`last_login` DATETIME NOT NULL,
|
||||
`created` DATETIME NOT NULL,
|
||||
`updated` DATETIME NOT NULL
|
||||
@ -52,6 +53,7 @@ CREATE INDEX IF NOT EXISTS "sandbox_streaming_key" ON "sandbox" (`streaming_key`
|
||||
CREATE INDEX IF NOT EXISTS "sandbox_spam" ON "sandbox" (`created`,`last_viewed`);
|
||||
CREATE INDEX IF NOT EXISTS "sandbox_revision" ON "sandbox" (`url`,`revision`);
|
||||
CREATE INDEX IF NOT EXISTS "ownership_name_key" ON "ownership" (`name`,`key`);
|
||||
CREATE INDEX IF NOT EXISTS "ownership_api_key" ON "ownership" (`api_key`);
|
||||
CREATE INDEX IF NOT EXISTS "owners_name_url" ON "owners" (`name`,`url`,`revision`);
|
||||
CREATE INDEX IF NOT EXISTS "index_owners_last_updated" ON "owners" (`name`, `last_updated`);
|
||||
CREATE INDEX IF NOT EXISTS "index_expires" ON "forgot_tokens" (`expires`);
|
||||
|
||||
3
build/upgrade/ownership-api-key-may-2013.mysql.sql
Normal file
3
build/upgrade/ownership-api-key-may-2013.mysql.sql
Normal file
@ -0,0 +1,3 @@
|
||||
ALTER TABLE ownership
|
||||
ADD COLUMN api_key VARCHAR(255) NULL,
|
||||
KEY `ownership_api_key` (`expires`);
|
||||
2
build/upgrade/ownership-api-key-may-2013.sqlite.sql
Normal file
2
build/upgrade/ownership-api-key-may-2013.sqlite.sql
Normal file
@ -0,0 +1,2 @@
|
||||
ALTER TABLE `ownership` ADD COLUMN `api_key` VARCHAR(255) NULL;
|
||||
CREATE INDEX IF NOT EXISTS "ownership_api_key" ON "ownership" (`api_key`);
|
||||
@ -50,6 +50,11 @@
|
||||
"errors": [],
|
||||
"report": []
|
||||
},
|
||||
"api": {
|
||||
"allowAnonymous": false,
|
||||
"allowReadOnly": true,
|
||||
"requireSSL": false
|
||||
},
|
||||
"blacklist": {
|
||||
"html": ["processform.cgi", "habbo.com"],
|
||||
"css": [],
|
||||
@ -66,6 +71,7 @@
|
||||
"activity",
|
||||
"all",
|
||||
"announcements",
|
||||
"api",
|
||||
"api_rules",
|
||||
"api_terms",
|
||||
"apirules",
|
||||
|
||||
@ -149,7 +149,8 @@ app.connect = function (callback) {
|
||||
app.use(express.cookieSession({key: 'jsbin', cookie: {maxAge: 365 * 24 * 60 * 60 * 1000}}));
|
||||
app.use(express.urlencoded());
|
||||
app.use(express.json());
|
||||
app.use(middleware.csrf({ ignore: ['/'] }));
|
||||
app.use(middleware.csrf({ ignore: ['/', /^\/api\//] }));
|
||||
app.use(middleware.api({ app: app }));
|
||||
app.use(middleware.subdomain(app));
|
||||
app.use(middleware.noslashes());
|
||||
app.use(middleware.ajax());
|
||||
|
||||
@ -124,6 +124,9 @@ module.exports = utils.inherit(Object, {
|
||||
getUser: function (id, cb) {
|
||||
cb(null, null);
|
||||
},
|
||||
getUserByApiKey: function (email, cb) {
|
||||
cb(null, null);
|
||||
},
|
||||
getUserByEmail: function (email, cb) {
|
||||
cb(null, null);
|
||||
},
|
||||
|
||||
@ -200,6 +200,14 @@ module.exports = utils.inherit(Object, {
|
||||
}
|
||||
});
|
||||
},
|
||||
getUserByApiKey: function (apiKey, fn) {
|
||||
this.connection.query(templates.getUserByApiKey, [apiKey], function (err, results) {
|
||||
if (err) {
|
||||
return fn(err);
|
||||
}
|
||||
fn(null, results[0]);
|
||||
});
|
||||
},
|
||||
getUserByEmail: function (email, fn) {
|
||||
this.connection.query(templates.getUserByEmail, [email], function (err, results) {
|
||||
if (err) {
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
"setBinPanel": "UPDATE `sandbox` SET `:panel`=?, `settings`=?, `created`=? WHERE `url`=? AND `revision`=? AND `streaming_key`=? AND `streaming_key`!='' AND `active`='y'",
|
||||
"binExists": "SELECT id FROM `sandbox` WHERE `url`=? LIMIT 1",
|
||||
"getUser": "SELECT * FROM `ownership` WHERE `name`=? LIMIT 1",
|
||||
"getUserByApiKey": "SELECT * FROM `ownership` WHERE `api_key`=? LIMIT 1",
|
||||
"getByEmail": "SELECT * FROM `ownership` WHERE `email`=? LIMIT 1",
|
||||
"setUser": "INSERT INTO `ownership` (`name`, `key`, `email`, `last_login`, `created`, `updated`) VALUES (?, ?, ?, ?, ?, ?)",
|
||||
"touchLogin": "UPDATE `ownership` SET `last_login`=? WHERE `name`=?",
|
||||
|
||||
@ -213,6 +213,20 @@ module.exports = utils.inherit(Object, {
|
||||
}
|
||||
});
|
||||
},
|
||||
getUserByApiKey: function (apiKey, fn) {
|
||||
var _this = this;
|
||||
|
||||
this.connection.get(templates.getUserByApiKey, [apiKey], function (err, result) {
|
||||
if (err) {
|
||||
return fn(err);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
result = _this.convertUserDates(result);
|
||||
}
|
||||
fn(null, result);
|
||||
});
|
||||
},
|
||||
getUserByEmail: function (email, fn) {
|
||||
var _this = this;
|
||||
|
||||
@ -406,7 +420,7 @@ module.exports = utils.inherit(Object, {
|
||||
// this is likely because the settings were screwed in a beta build
|
||||
bin.settings = {};
|
||||
}
|
||||
console.log(bin);
|
||||
// console.log(bin);
|
||||
|
||||
return bin;
|
||||
},
|
||||
|
||||
@ -5,8 +5,10 @@ var async = require('asyncjs'),
|
||||
errors = require('../errors'),
|
||||
custom = require('../custom'),
|
||||
blacklist = require('../blacklist'),
|
||||
apiConfig = require('../config').api || {};
|
||||
scripts = require('../../scripts.json'),
|
||||
processors = require('../processors'),
|
||||
_ = require('underscore'),
|
||||
Observable = utils.Observable;
|
||||
|
||||
module.exports = Observable.extend({
|
||||
@ -71,6 +73,44 @@ module.exports = Observable.extend({
|
||||
getBin: function (req, res, next) {
|
||||
this.render(req, res, req.bin);
|
||||
},
|
||||
// creates a object that's API request friendly - ie. gets rendered
|
||||
// output if there's a processor and hides internal fields
|
||||
apiPrepareBin: function (bin) {
|
||||
var out = _.pick(bin,
|
||||
'html',
|
||||
'javascript',
|
||||
'css',
|
||||
'original_html',
|
||||
'original_javascript',
|
||||
'original_css',
|
||||
'created',
|
||||
'last_updated'
|
||||
);
|
||||
|
||||
out.permalink = this.helpers.urlForBin(bin, true);
|
||||
|
||||
if (bin.settings && bin.settings.processors) {
|
||||
out.processors = bin.settings.processors;
|
||||
}
|
||||
|
||||
// note: if there's no processor, then the "original_*" fields
|
||||
|
||||
return out;
|
||||
},
|
||||
loadBinRevision: function (req, res, next) {
|
||||
if (req.param('rev')) {
|
||||
next();
|
||||
} else {
|
||||
this.models.bin.latest({ id: req.bin.url }, function(err, bin) {
|
||||
req.bin = bin;
|
||||
next();
|
||||
});
|
||||
}
|
||||
},
|
||||
apiGetBin: function (req, res, next) {
|
||||
this.applyProcessors(req.bin);
|
||||
res.json(this.apiPrepareBin(req.bin));
|
||||
},
|
||||
live: function (req, res, next) {
|
||||
req.live = true;
|
||||
next();
|
||||
@ -91,13 +131,15 @@ module.exports = Observable.extend({
|
||||
next(err);
|
||||
}
|
||||
|
||||
if (formatted) {
|
||||
if (req.xhr) {
|
||||
res.json(this.apiPrepareBin(req.bin));
|
||||
} else if (formatted) {
|
||||
res.send(formatted);
|
||||
} else {
|
||||
res.contentType('js');
|
||||
res.send(req.bin.javascript);
|
||||
}
|
||||
});
|
||||
}.bind(this));
|
||||
},
|
||||
// TODO decide whether this is used anymore
|
||||
getBinSource: function (req, res) {
|
||||
@ -211,6 +253,25 @@ module.exports = Observable.extend({
|
||||
});
|
||||
});
|
||||
},
|
||||
apiCreateBin: function (req, res, next) {
|
||||
var params = utils.extract(req.body, 'html', 'css', 'javascript', 'settings'),
|
||||
_this = this;
|
||||
|
||||
this.validateBin(params, function (err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
params.settings = params.settings || '{ processors: {} }'; // set default processors
|
||||
_this.models.bin.create(params, function (err, result) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
res.json(result);
|
||||
});
|
||||
});
|
||||
},
|
||||
claimBin: function (req, res, next) {
|
||||
// Handler for ambiguous endpoint that can be used to create a new bin with
|
||||
// a provided bin url, clone the bin and create a new endpoint or update an
|
||||
@ -235,6 +296,47 @@ module.exports = Observable.extend({
|
||||
this.createRevision(req, res, next);
|
||||
}
|
||||
},
|
||||
apiCreateRevision: function (req, res, next) {
|
||||
var that = this,
|
||||
params = utils.extract(req.body, 'html', 'css', 'javascript', 'settings');
|
||||
|
||||
params.url = req.params.bin;
|
||||
params.revision = parseInt(req.params.rev, 10) || req.bin.revision;
|
||||
params.settings = params.settings || '{ processors: {} }'; // set default processors
|
||||
params.summary = utils.titleForBin(params);
|
||||
|
||||
this.validateBin(params, function (err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
var username = req.session.user ? req.session.user.name : undefined;
|
||||
|
||||
that.models.user.isOwnerOf(username, params, function (err, result) {
|
||||
var method = 'create';
|
||||
|
||||
if (result.isowner || result.found === false) { // if anonymous or user is owner
|
||||
params.revision += 1; // bump the revision from the *latest*
|
||||
that.models.bin.createRevision(params, function (err, result) {
|
||||
var query = {id: req.params.bin, revision: result.revision};
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
that.models.bin.load(query, function (err, result) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
res.json(result);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
res.status(403); // forbidden
|
||||
res.json({ error: 'You are not the owner of this bin so you cannot create a revision' });
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
createRevision: function (req, res, next) {
|
||||
var panel = req.param('panel'),
|
||||
params = {},
|
||||
@ -376,53 +478,61 @@ module.exports = Observable.extend({
|
||||
},
|
||||
notFound: function (req, res, next) {
|
||||
var files = this.defaultFiles(),
|
||||
_this = this;
|
||||
_this = this,
|
||||
errorMessage;
|
||||
|
||||
files[0] = 'not_found.html';
|
||||
files[2] = 'not_found.js';
|
||||
|
||||
this.loadFiles(files, function (err, results) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
results.url = req.param('bin');
|
||||
|
||||
// Need to get the most recent revision from the database.
|
||||
_this.models.bin.latest({id: results.url}, function (err, bin) {
|
||||
if (req.isApi) {
|
||||
res.status(404);
|
||||
errorMessage = 'Could not find bin with ID "' + req.param('bin') + '"';
|
||||
if (req.param('rev')) { errorMessage += ' and revision ' + req.param('rev'); }
|
||||
res.json({ error: errorMessage });
|
||||
} else {
|
||||
this.loadFiles(files, function (err, results) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
// We have a missing bin, we check the latest returned bin, if this
|
||||
// is active then we simply render it assuming the user mistyped the
|
||||
// url.
|
||||
if (bin && bin.active) {
|
||||
results = bin;
|
||||
} else {
|
||||
// If we have a bin then take the latest revision plus one.
|
||||
results.revision = bin && (bin.revision + 1);
|
||||
}
|
||||
results.url = req.param('bin');
|
||||
|
||||
if (req.url.indexOf('edit') > -1) {
|
||||
_this.render(req, res, results);
|
||||
} else {
|
||||
var options = {edit: true, silent: true, csrf: req.session._csrf};
|
||||
_this.formatPreview(results, options, function (err, formatted) {
|
||||
if (err) {
|
||||
next(err);
|
||||
}
|
||||
// Need to get the most recent revision from the database.
|
||||
_this.models.bin.latest({id: results.url}, function (err, bin) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (formatted) {
|
||||
res.send(formatted);
|
||||
} else {
|
||||
res.contentType('js');
|
||||
res.send(req.bin.javascript);
|
||||
}
|
||||
});
|
||||
}
|
||||
// We have a missing bin, we check the latest returned bin, if this
|
||||
// is active then we simply render it assuming the user mistyped the
|
||||
// url.
|
||||
if (bin && bin.active) {
|
||||
results = bin;
|
||||
} else {
|
||||
// If we have a bin then take the latest revision plus one.
|
||||
results.revision = bin && (bin.revision + 1);
|
||||
}
|
||||
|
||||
if (req.url.indexOf('edit') > -1) {
|
||||
_this.render(req, res, results);
|
||||
} else {
|
||||
var options = {edit: true, silent: true, csrf: req.session._csrf};
|
||||
_this.formatPreview(results, options, function (err, formatted) {
|
||||
if (err) {
|
||||
next(err);
|
||||
}
|
||||
|
||||
if (formatted) {
|
||||
res.send(formatted);
|
||||
} else {
|
||||
res.contentType('js');
|
||||
res.send(req.bin.javascript);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
loadBin: function (req, res, next) {
|
||||
var rev = parseInt(req.params.rev, 10) || 1,
|
||||
@ -668,20 +778,26 @@ module.exports = Observable.extend({
|
||||
}
|
||||
});
|
||||
},
|
||||
formatPreview: function (bin, options, fn) {
|
||||
(function () {
|
||||
if (bin.settings && bin.settings.processors) {
|
||||
for (var panel in bin.settings.processors) {
|
||||
var processorName = bin.settings.processors[panel],
|
||||
processor = processors[processorName],
|
||||
code = bin[panel];
|
||||
if (processor) {
|
||||
bin['original_' + panel] = code;
|
||||
bin[panel] = processor(code);
|
||||
}
|
||||
// applies the processors to the bin and generates the html, js, etc
|
||||
// based on the appropriate processor. Used in the previews and the API
|
||||
// requests.
|
||||
applyProcessors: function (bin) {
|
||||
if (bin.settings && bin.settings.processors) {
|
||||
for (var panel in bin.settings.processors) {
|
||||
var processorName = bin.settings.processors[panel],
|
||||
processor = processors[processorName],
|
||||
code = bin[panel];
|
||||
if (processor) {
|
||||
bin['original_' + panel] = code;
|
||||
bin[panel] = processor(code);
|
||||
}
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
// nothing returned as it updates the bin object
|
||||
},
|
||||
formatPreview: function (bin, options, fn) {
|
||||
this.applyProcessors(bin);
|
||||
|
||||
var formatted = bin.html || '',
|
||||
helpers = this.helpers,
|
||||
|
||||
@ -38,7 +38,7 @@ module.exports = Observable.extend({
|
||||
// Fall through handler for when no routes match.
|
||||
notFound: function (req, res, next) {
|
||||
var error = new errors.NotFound('Page Does Not Exist');
|
||||
if (req.accepts('html')) {
|
||||
if (req.accepts('html') && (req.url.indexOf('/api/') !== 0)) {
|
||||
this.renderErrorPage(error, req, res);
|
||||
} else {
|
||||
this.renderError(error, req, res);
|
||||
@ -61,10 +61,10 @@ module.exports = Observable.extend({
|
||||
renderError: function (err, req, res) {
|
||||
res.status(err.status);
|
||||
|
||||
if (req.accepts(['html'])) {
|
||||
if (req.accepts(['html']) && !req.isApi) {
|
||||
res.contentType('html');
|
||||
res.send(err.toHTMLString());
|
||||
} else if (req.accepts(['json'])) {
|
||||
} else if (req.accepts(['json']) || req.isApi) {
|
||||
res.json(err);
|
||||
} else {
|
||||
res.contentType('txt');
|
||||
|
||||
@ -2,7 +2,9 @@ var utils = require('./utils'),
|
||||
helpers = require('./helpers'),
|
||||
custom = require('./custom'),
|
||||
errors = require('./errors'),
|
||||
connect = require('express/node_modules/connect');
|
||||
connect = require('express/node_modules/connect'),
|
||||
models = require('./models'),
|
||||
config = require('./config');
|
||||
|
||||
// Custom middleware used by the application.
|
||||
module.exports = {
|
||||
@ -96,15 +98,33 @@ module.exports = {
|
||||
always = {OPTIONS: 1, GET: 1, HEAD: 1};
|
||||
|
||||
return function (req, res, next) {
|
||||
if (always[req.method] || ignore.indexOf(req.url) === -1 && !req.cors) {
|
||||
if (always[req.method]) {
|
||||
return csrf(req, res, next);
|
||||
} else {
|
||||
next();
|
||||
var skipCSRF = false;
|
||||
ignore.forEach(function(matcher) {
|
||||
if (typeof matcher === 'string') {
|
||||
if (matcher == req.url) {
|
||||
skipCSRF = true;
|
||||
}
|
||||
} else {
|
||||
// regular expression matcher
|
||||
if (req.url.match(matcher)) {
|
||||
skipCSRF = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (skipCSRF) {
|
||||
next();
|
||||
} else {
|
||||
return csrf(req, res, next);
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
// Checks for a subdomain in the current url, if found it sets the
|
||||
// req.subdomain property. This supports existing behaviour that allows
|
||||
// req.subdomain property. This supports existing behaviour that allows
|
||||
// subdomains to load custom config files.
|
||||
subdomain: function (app) {
|
||||
return function (req, res, next) {
|
||||
@ -159,5 +179,56 @@ module.exports = {
|
||||
}
|
||||
next();
|
||||
};
|
||||
},
|
||||
|
||||
// detect if this is an API request and add flag isApi to the request object
|
||||
api: function(options) {
|
||||
return function (req, res, next) {
|
||||
var apiKey,
|
||||
userModel = models.createModels(options.app.store).user;
|
||||
|
||||
if (req.url.indexOf('/api') === 0) {
|
||||
req.isApi = true;
|
||||
|
||||
if (config.api.requireSSL) {
|
||||
if (!req.secure && (String(req.headers['x-forwarded-proto']).toLowerCase() !== "https") ) {
|
||||
res.status(403); // forbidden
|
||||
res.json({ error: 'All API requests must be made over SSL/TLS' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (req.query.api_key) {
|
||||
apiKey = req.query.api_key;
|
||||
} else if (req.headers.authorization) {
|
||||
apiKey = req.headers.authorization.replace(/token\s/,'');
|
||||
}
|
||||
|
||||
if (config.api.allowAnonymous || (config.api.allowReadOnly && req.method === 'GET')) {
|
||||
next();
|
||||
} else {
|
||||
if (!apiKey) {
|
||||
res.status(403); // forbidden
|
||||
res.json({ error: 'You need to provide a valid API key when using this API' });
|
||||
} else {
|
||||
userModel.loadByApiKey(apiKey, function (err, user) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
if (user) {
|
||||
req.session.user = user;
|
||||
next();
|
||||
} else {
|
||||
res.status(403); // forbidden
|
||||
res.json({ error: 'The API key you provided is not valid' });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@ -12,6 +12,9 @@ module.exports = Observable.extend({
|
||||
load: function (id, fn) {
|
||||
this.store.getUser(id, fn);
|
||||
},
|
||||
loadByApiKey: function (apiKey, fn) {
|
||||
this.store.getUserByApiKey(apiKey, fn);
|
||||
},
|
||||
loadByEmail: function (email, fn) {
|
||||
this.store.getUserByEmail(email, fn);
|
||||
},
|
||||
|
||||
@ -48,6 +48,7 @@ module.exports = function (app) {
|
||||
// Load the bin from the store when encountered in the url. Also handles the
|
||||
// "latest" url action.
|
||||
app.param('bin', binHandler.loadBin);
|
||||
app.param('rev', binHandler.loadBinRevision);
|
||||
app.param('name', sessionHandler.loadUser);
|
||||
|
||||
// Set up the routes.
|
||||
@ -55,6 +56,19 @@ module.exports = function (app) {
|
||||
app.get('/gist/*', binHandler.getDefault);
|
||||
app.post('/', binHandler.getFromPost);
|
||||
|
||||
// API methods
|
||||
var allowAnonymous = app.settings['api allowAnonymous'],
|
||||
allowReadOnly = app.settings['api allowReadOnly'];
|
||||
|
||||
if (allowAnonymous || allowReadOnly) {
|
||||
app.get('/api/:bin/:rev?', binHandler.apiGetBin);
|
||||
}
|
||||
|
||||
if (allowAnonymous) {
|
||||
app.post('/api/save', binHandler.apiCreateBin);
|
||||
app.post('/api/:bin/save', binHandler.apiCreateRevision);
|
||||
}
|
||||
|
||||
// Login/Create account.
|
||||
app.post('/sethome', sessionHandler.routeSetHome);
|
||||
app.post('/logout', sessionHandler.logoutUser);
|
||||
@ -87,7 +101,6 @@ module.exports = function (app) {
|
||||
// Save
|
||||
app.post('/save', binHandler.createBin);
|
||||
|
||||
|
||||
// Use this handler to check for a user creating/claiming their own bin url.
|
||||
// We use :url here to prevent loadBin() being called and returning a not
|
||||
// found error.
|
||||
|
||||
@ -27,6 +27,7 @@ var methods = [
|
||||
'archiveBin',
|
||||
'getUser',
|
||||
'getUserByEmail',
|
||||
'getUserByApiKey',
|
||||
'setUser',
|
||||
'touchLogin',
|
||||
'touchOwners',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user