Ghost/core/server/api/routes.js
Kevin Ansfield bffb3dbd90
Webhooks support for subscriber events (#9230)
no issue

Support for http://resthooks.org style webhooks that can be used with Zapier triggers. This can currently be used in two ways:

a) adding a webhook record to the DB manually
b) using the API with password auth and POSTing to /webhooks/ (this is private API so not documented)

⚠️ only _https_ URLs are supported in the webhook `target_url` field 🚨

- add `webhooks` table to store event names and target urls
- add `POST` and `DELETE` endpoints for `/webhooks/`
- configure `subscribers.added` and `subscribers.deleted` events to trigger registered webhooks
2017-11-21 15:43:14 +00:00

210 lines
8.9 KiB
JavaScript

var express = require('express'),
// This essentially provides the controllers for the routes
api = require('../api'),
// Middleware
mw = require('./middleware'),
// API specific
auth = require('../auth'),
cors = require('../middleware/api/cors'),
brute = require('../middleware/brute'),
// Handling uploads & imports
tmpdir = require('os').tmpdir,
upload = require('multer')({dest: tmpdir()}),
validation = require('../middleware/validation'),
// Temporary
// @TODO find a more appy way to do this!
labs = require('../middleware/labs');
// @TODO refactor/clean this up - how do we want the routing to work long term?
module.exports = function apiRoutes() {
var apiRouter = express.Router();
// alias delete with del
apiRouter.del = apiRouter.delete;
// ## CORS pre-flight check
apiRouter.options('*', cors);
// ## Configuration
apiRouter.get('/configuration', api.http(api.configuration.read));
apiRouter.get('/configuration/:key', mw.authenticatePrivate, api.http(api.configuration.read));
// ## Posts
apiRouter.get('/posts', mw.authenticatePublic, api.http(api.posts.browse));
apiRouter.post('/posts', mw.authenticatePrivate, api.http(api.posts.add));
apiRouter.get('/posts/:id', mw.authenticatePublic, api.http(api.posts.read));
apiRouter.get('/posts/slug/:slug', mw.authenticatePublic, api.http(api.posts.read));
apiRouter.put('/posts/:id', mw.authenticatePrivate, api.http(api.posts.edit));
apiRouter.del('/posts/:id', mw.authenticatePrivate, api.http(api.posts.destroy));
// ## Schedules
apiRouter.put('/schedules/posts/:id', [
auth.authenticate.authenticateClient,
auth.authenticate.authenticateUser
], api.http(api.schedules.publishPost));
// ## Settings
apiRouter.get('/settings', mw.authenticatePrivate, api.http(api.settings.browse));
apiRouter.get('/settings/:key', mw.authenticatePrivate, api.http(api.settings.read));
apiRouter.put('/settings', mw.authenticatePrivate, api.http(api.settings.edit));
// ## Users
apiRouter.get('/users', mw.authenticatePublic, api.http(api.users.browse));
apiRouter.get('/users/:id', mw.authenticatePublic, api.http(api.users.read));
apiRouter.get('/users/slug/:slug', mw.authenticatePublic, api.http(api.users.read));
// NOTE: We don't expose any email addresses via the public api.
apiRouter.get('/users/email/:email', mw.authenticatePrivate, api.http(api.users.read));
apiRouter.put('/users/password', mw.authenticatePrivate, api.http(api.users.changePassword));
apiRouter.put('/users/owner', mw.authenticatePrivate, api.http(api.users.transferOwnership));
apiRouter.put('/users/:id', mw.authenticatePrivate, api.http(api.users.edit));
apiRouter.del('/users/:id', mw.authenticatePrivate, api.http(api.users.destroy));
// ## Tags
apiRouter.get('/tags', mw.authenticatePublic, api.http(api.tags.browse));
apiRouter.get('/tags/:id', mw.authenticatePublic, api.http(api.tags.read));
apiRouter.get('/tags/slug/:slug', mw.authenticatePublic, api.http(api.tags.read));
apiRouter.post('/tags', mw.authenticatePrivate, api.http(api.tags.add));
apiRouter.put('/tags/:id', mw.authenticatePrivate, api.http(api.tags.edit));
apiRouter.del('/tags/:id', mw.authenticatePrivate, api.http(api.tags.destroy));
// ## Subscribers
apiRouter.get('/subscribers', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.browse));
apiRouter.get('/subscribers/csv', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.exportCSV));
apiRouter.post('/subscribers/csv',
labs.subscribers,
mw.authenticatePrivate,
upload.single('subscribersfile'),
validation.upload({type: 'subscribers'}),
api.http(api.subscribers.importCSV)
);
apiRouter.get('/subscribers/:id', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.read));
apiRouter.get('/subscribers/email/:email', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.read));
apiRouter.post('/subscribers', labs.subscribers, mw.authenticatePublic, api.http(api.subscribers.add));
apiRouter.put('/subscribers/:id', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.edit));
apiRouter.del('/subscribers/:id', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.destroy));
apiRouter.del('/subscribers/email/:email', labs.subscribers, mw.authenticatePrivate, api.http(api.subscribers.destroy));
// ## Roles
apiRouter.get('/roles/', mw.authenticatePrivate, api.http(api.roles.browse));
// ## Clients
apiRouter.get('/clients/slug/:slug', api.http(api.clients.read));
// ## Slugs
apiRouter.get('/slugs/:type/:name', mw.authenticatePrivate, api.http(api.slugs.generate));
// ## Themes
apiRouter.get('/themes/', mw.authenticatePrivate, api.http(api.themes.browse));
apiRouter.get('/themes/:name/download',
mw.authenticatePrivate,
api.http(api.themes.download)
);
apiRouter.post('/themes/upload',
mw.authenticatePrivate,
upload.single('theme'),
validation.upload({type: 'themes'}),
api.http(api.themes.upload)
);
apiRouter.put('/themes/:name/activate',
mw.authenticatePrivate,
api.http(api.themes.activate)
);
apiRouter.del('/themes/:name',
mw.authenticatePrivate,
api.http(api.themes.destroy)
);
// ## Notifications
apiRouter.get('/notifications', mw.authenticatePrivate, api.http(api.notifications.browse));
apiRouter.post('/notifications', mw.authenticatePrivate, api.http(api.notifications.add));
apiRouter.del('/notifications/:id', mw.authenticatePrivate, api.http(api.notifications.destroy));
// ## DB
apiRouter.get('/db', mw.authenticatePrivate, api.http(api.db.exportContent));
apiRouter.post('/db',
mw.authenticatePrivate,
upload.single('importfile'),
validation.upload({type: 'db'}),
api.http(api.db.importContent)
);
apiRouter.del('/db', mw.authenticatePrivate, api.http(api.db.deleteAllContent));
// ## Mail
apiRouter.post('/mail', mw.authenticatePrivate, api.http(api.mail.send));
apiRouter.post('/mail/test', mw.authenticatePrivate, api.http(api.mail.sendTest));
// ## Slack
apiRouter.post('/slack/test', mw.authenticatePrivate, api.http(api.slack.sendTest));
// ## Authentication
apiRouter.post('/authentication/passwordreset',
brute.globalReset,
brute.userReset,
api.http(api.authentication.generateResetToken)
);
apiRouter.put('/authentication/passwordreset', brute.globalBlock, api.http(api.authentication.resetPassword));
apiRouter.post('/authentication/invitation', api.http(api.authentication.acceptInvitation));
apiRouter.get('/authentication/invitation', api.http(api.authentication.isInvitation));
apiRouter.post('/authentication/setup', api.http(api.authentication.setup));
apiRouter.put('/authentication/setup', mw.authenticatePrivate, api.http(api.authentication.updateSetup));
apiRouter.get('/authentication/setup', api.http(api.authentication.isSetup));
apiRouter.post('/authentication/token',
brute.globalBlock,
brute.userLogin,
auth.authenticate.authenticateClient,
auth.oauth.generateAccessToken
);
apiRouter.post('/authentication/revoke', mw.authenticatePrivate, api.http(api.authentication.revoke));
// ## Uploads
// @TODO: rename endpoint to /images/upload (or similar)
apiRouter.post('/uploads',
mw.authenticatePrivate,
upload.single('uploadimage'),
validation.upload({type: 'images'}),
api.http(api.uploads.add)
);
apiRouter.post('/db/backup', mw.authenticateClient('Ghost Backup'), api.http(api.db.backupContent));
apiRouter.post('/uploads/icon',
mw.authenticatePrivate,
upload.single('uploadimage'),
validation.upload({type: 'icons'}),
validation.blogIcon(),
api.http(api.uploads.add)
);
// ## Invites
apiRouter.get('/invites', mw.authenticatePrivate, api.http(api.invites.browse));
apiRouter.get('/invites/:id', mw.authenticatePrivate, api.http(api.invites.read));
apiRouter.post('/invites', mw.authenticatePrivate, api.http(api.invites.add));
apiRouter.del('/invites/:id', mw.authenticatePrivate, api.http(api.invites.destroy));
// ## Redirects (JSON based)
apiRouter.get('/redirects/json', mw.authenticatePrivate, api.http(api.redirects.download));
apiRouter.post('/redirects/json',
mw.authenticatePrivate,
upload.single('redirects'),
validation.upload({type: 'redirects'}),
api.http(api.redirects.upload)
);
// ## Webhooks (RESTHooks)
apiRouter.post('/webhooks', mw.authenticatePrivate, api.http(api.webhooks.add));
apiRouter.del('/webhooks/:id', mw.authenticatePrivate, api.http(api.webhooks.destroy));
return apiRouter;
};