var _ = require('lodash'), url = require('url'), moment = require('moment'), config = require('../../server/config'), schema = require('../../server/data/schema').tables, ApiRouteBase = '/ghost/api/v0.1/', host = config.get('server').host, port = config.get('server').port, protocol = 'http://', expectedProperties = { // API top level posts: ['posts', 'meta'], tags: ['tags', 'meta'], users: ['users', 'meta'], settings: ['settings', 'meta'], subscribers: ['subscribers', 'meta'], roles: ['roles'], pagination: ['page', 'limit', 'pages', 'total', 'next', 'prev'], slugs: ['slugs'], slug: ['slug'], post: _(schema.posts) .keys() // by default we only return html .without('mobiledoc', 'amp', 'plaintext') // swaps author_id to author, and always returns computed properties: url, comment_id, primary_tag, primary_author .without('author_id').concat('author', 'url', 'comment_id', 'primary_tag', 'primary_author') .value(), user: { default: _(schema.users).keys().without('password').without('ghost_auth_access_token').value(), public: _(schema.users) .keys() .without( 'password', 'email', 'ghost_auth_access_token', 'ghost_auth_id', 'created_at', 'created_by', 'updated_at', 'updated_by', 'last_seen', 'status' ) .value() }, // Tag API swaps parent_id to parent tag: _(schema.tags).keys().without('parent_id').concat('parent').value(), setting: _.keys(schema.settings), subscriber: _.keys(schema.subscribers), accesstoken: _.keys(schema.accesstokens), role: _.keys(schema.roles), permission: _.keys(schema.permissions), notification: ['type', 'message', 'status', 'id', 'dismissible', 'location', 'custom'], theme: ['name', 'package', 'active'], themes: ['themes'], invites: _(schema.invites).keys().without('token').value(), webhook: _.keys(schema.webhooks) }; function getApiQuery(route) { return url.resolve(ApiRouteBase, route); } function getApiURL(route) { var baseURL = url.resolve(protocol + host + ':' + port, ApiRouteBase); return url.resolve(baseURL, route); } function getURL() { return protocol + host; } function getSigninURL() { return url.resolve(protocol + host + ':' + port, 'ghost/signin/'); } function getAdminURL() { return url.resolve(protocol + host + ':' + port, 'ghost/'); } function isISO8601(date) { return moment(date).parsingFlags().iso; } // make sure the API only returns expected properties only function checkResponseValue(jsonResponse, expectedProperties) { var providedProperties = _.keys(jsonResponse), missing = _.difference(expectedProperties, providedProperties), unexpected = _.difference(providedProperties, expectedProperties); _.each(missing, function (prop) { jsonResponse.should.have.property(prop); }); _.each(unexpected, function (prop) { jsonResponse.should.not.have.property(prop); }); providedProperties.length.should.eql(expectedProperties.length); } // @TODO: support options pattern only, it's annoying to call checkResponse(null, null, null, something) function checkResponse(jsonResponse, objectType, additionalProperties, missingProperties, onlyProperties, options) { options = options || {}; var checkProperties = options.public ? (expectedProperties[objectType].public || expectedProperties[objectType]) : (expectedProperties[objectType].default || expectedProperties[objectType]); checkProperties = onlyProperties ? onlyProperties : checkProperties; checkProperties = additionalProperties ? checkProperties.concat(additionalProperties) : checkProperties; checkProperties = missingProperties ? _.xor(checkProperties, missingProperties) : checkProperties; checkResponseValue(jsonResponse, checkProperties); } module.exports = { getApiURL: getApiURL, getApiQuery: getApiQuery, getSigninURL: getSigninURL, getAdminURL: getAdminURL, getURL: getURL, checkResponse: checkResponse, checkResponseValue: checkResponseValue, isISO8601: isISO8601 };