Skip to content

Commit

Permalink
Renamed /users to /authors for Content API V2 (#10096)
Browse files Browse the repository at this point in the history
refs #10061

- Made /authors endpoint available in Content API V2
  • Loading branch information
kirrg001 authored and naz committed Nov 7, 2018
1 parent 3b8621e commit ff6bf5f
Show file tree
Hide file tree
Showing 34 changed files with 494 additions and 339 deletions.
66 changes: 66 additions & 0 deletions core/server/api/v2/authors.js
@@ -0,0 +1,66 @@
const Promise = require('bluebird');
const common = require('../../lib/common');
const models = require('../../models');
const ALLOWED_INCLUDES = ['count.posts'];

module.exports = {
docName: 'authors',

browse: {
options: [
'include',
'filter',
'fields',
'limit',
'status',
'order',
'page'
],
validation: {
options: {
include: {
values: ALLOWED_INCLUDES
}
}
},
permissions: true,
query(frame) {
return models.User.findPage(frame.options);
}
},

read: {
options: [
'include',
'filter',
'fields'
],
data: [
'id',
'slug',
'status',
'email',
'role'
],
validation: {
options: {
include: {
values: ALLOWED_INCLUDES
}
}
},
permissions: true,
query(frame) {
return models.User.findOne(frame.data, frame.options)
.then((model) => {
if (!model) {
return Promise.reject(new common.errors.NotFoundError({
message: common.i18n.t('errors.api.authors.notFound')
}));
}

return model;
});
}
}
};
4 changes: 4 additions & 0 deletions core/server/api/v2/index.js
Expand Up @@ -77,5 +77,9 @@ module.exports = {

get slack() {
return shared.pipeline(require('./slack'), localUtils);
},

get authors() {
return shared.pipeline(require('./authors'), localUtils);
}
};
25 changes: 25 additions & 0 deletions core/server/api/v2/utils/serializers/output/authors.js
@@ -0,0 +1,25 @@
const debug = require('ghost-ignition').debug('api:v2:utils:serializers:output:authors');
const mapper = require('./utils/mapper');

module.exports = {
browse(models, apiConfig, frame) {
debug('browse');

frame.response = {
authors: models.data.map(model => mapper.mapUser(model, frame)),
meta: models.meta
};

debug(frame.response);
},

read(model, apiConfig, frame) {
debug('read');

frame.response = {
authors: [mapper.mapUser(model, frame)]
};

debug(frame.response);
}
};
4 changes: 4 additions & 0 deletions core/server/api/v2/utils/serializers/output/index.js
Expand Up @@ -61,5 +61,9 @@ module.exports = {

get oembed() {
return require('./oembed');
},

get authors() {
return require('./authors');
}
};
2 changes: 1 addition & 1 deletion core/server/apps/amp/lib/router.js
Expand Up @@ -64,7 +64,7 @@ function getPostData(req, res, next) {
}

// @NOTE: amp is not supported for static pages
helpers.entryLookup(urlWithoutSubdirectoryWithoutAmp, {permalinks, resourceType: 'posts'}, res.locals)
helpers.entryLookup(urlWithoutSubdirectoryWithoutAmp, {permalinks, query: {resource: 'posts'}}, res.locals)
.then((result) => {
if (result && result.entry) {
req.body.post = result.entry;
Expand Down
10 changes: 10 additions & 0 deletions core/server/helpers/get.js
Expand Up @@ -37,6 +37,9 @@ const RESOURCES = {
pages: {
alias: 'pages',
resource: 'posts'
},
authors: {
alias: 'authors'
}
};

Expand Down Expand Up @@ -145,6 +148,13 @@ get = function get(resource, options) {
const controller = api[apiVersion][RESOURCES[resource].alias] ? RESOURCES[resource].alias : RESOURCES[resource].resource;
const action = isBrowse(apiOptions) ? 'browse' : 'read';

// CASE: no fallback defined e.g. v0.1 tries to fetch "authors"
if (!controller) {
data.error = i18n.t('warnings.helpers.get.invalidResource');
logging.warn(data.error);
return Promise.resolve(options.inverse(self, {data: data}));
}

// Parse the options we're going to pass to the API
apiOptions = parseOptions(this, apiOptions);

Expand Down
1 change: 1 addition & 0 deletions core/server/models/user.js
Expand Up @@ -341,6 +341,7 @@ User = ghostBookshelf.Model.extend({

// CASE: The `withRelated` parameter is allowed when using the public API, but not the `roles` value.
// Otherwise we expose too much information.
// @TODO: the target controller should define the allowed includes, but not the model layer O_O (https://github.com/TryGhost/Ghost/issues/10106)
if (options && options.context && options.context.public) {
if (options.withRelated && options.withRelated.indexOf('roles') !== -1) {
options.withRelated.splice(options.withRelated.indexOf('roles'), 1);
Expand Down
4 changes: 4 additions & 0 deletions core/server/services/routing/CollectionRouter.js
Expand Up @@ -91,6 +91,10 @@ class CollectionRouter extends ParentRouter {
order: this.order,
permalinks: this.permalinks.getValue({withUrlOptions: true}),
resourceType: this.getResourceType(),
query: {
alias: 'posts',
resource: 'posts'
},
context: this.context,
frontPageTemplate: 'home',
templates: this.templates,
Expand Down
5 changes: 4 additions & 1 deletion core/server/services/routing/PreviewRouter.js
Expand Up @@ -20,7 +20,10 @@ class PreviewRouter extends ParentRouter {
_prepareContext(req, res, next) {
res.routerOptions = {
type: 'entry',
resourceType: 'preview'
query: {
alias: 'preview',
resource: 'posts'
}
};

next();
Expand Down
4 changes: 4 additions & 0 deletions core/server/services/routing/StaticPagesRouter.js
Expand Up @@ -39,6 +39,10 @@ class StaticPagesRouter extends ParentRouter {
filter: this.filter,
permalinks: this.permalinks.getValue(),
resourceType: this.getResourceType(),
query: {
alias: 'pages',
resource: 'posts'
},
context: ['page']
};

Expand Down
4 changes: 2 additions & 2 deletions core/server/services/routing/TaxonomyRouter.js
Expand Up @@ -54,7 +54,7 @@ class TaxonomyRouter extends ParentRouter {
type: 'channel',
name: this.taxonomyKey,
permalinks: this.permalinks.getValue(),
data: {[this.taxonomyKey]: _.omit(RESOURCE_CONFIG.QUERY[this.taxonomyKey], ['alias', 'internal'])},
data: {[this.taxonomyKey]: _.omit(RESOURCE_CONFIG.QUERY[this.taxonomyKey], ['internal'])},
filter: RESOURCE_CONFIG.TAXONOMIES[this.taxonomyKey].filter,
resourceType: this.getResourceType(),
context: [this.taxonomyKey],
Expand All @@ -70,7 +70,7 @@ class TaxonomyRouter extends ParentRouter {
}

getResourceType() {
return RESOURCE_CONFIG.QUERY[this.taxonomyKey].resource;
return RESOURCE_CONFIG.QUERY[this.taxonomyKey].alias;
}

getRoute() {
Expand Down
5 changes: 2 additions & 3 deletions core/server/services/routing/assets/resource-config.js
Expand Up @@ -10,8 +10,7 @@ module.exports.QUERY = {
}
},
author: {
internal: true,
alias: 'users',
alias: 'authors',
type: 'read',
resource: 'users',
options: {
Expand All @@ -20,7 +19,7 @@ module.exports.QUERY = {
}
},
user: {
alias: 'users',
alias: 'authors',
type: 'read',
resource: 'users',
options: {
Expand Down
14 changes: 2 additions & 12 deletions core/server/services/routing/controllers/preview.js
Expand Up @@ -14,20 +14,10 @@ module.exports = function previewController(req, res, next) {
include: 'author,authors,tags'
};

let resourceType = res.routerOptions.resourceType;

/**
* @TODO:
* Remove fallback to posts if we drop v0.1.
*/
if (!api[resourceType]) {
resourceType = 'posts';
}

api[resourceType]
(api[res.routerOptions.query.alias] || api[res.routerOptions.query.resource])
.read(params)
.then(function then(result) {
const post = result[resourceType][0];
const post = (result[res.routerOptions.query.alias] || result[res.routerOptions.query.resource])[0];

if (!post) {
return next();
Expand Down
4 changes: 2 additions & 2 deletions core/server/services/routing/controllers/static.js
Expand Up @@ -8,7 +8,7 @@ function processQuery(query, locals) {
query = _.cloneDeep(query);

// Return a promise for the api query
return api[query.resource][query.type](query.options);
return (api[query.alias] || api[query.resource])[query.type](query.options);
}

module.exports = function staticController(req, res, next) {
Expand All @@ -31,7 +31,7 @@ module.exports = function staticController(req, res, next) {
if (config.type === 'browse') {
response.data[name] = result[name];
} else {
response.data[name] = result[name][config.resource];
response.data[name] = result[name][config.alias] || result[name][config.resource];
}
});
}
Expand Down
12 changes: 2 additions & 10 deletions core/server/services/routing/helpers/entry-lookup.js
Expand Up @@ -30,22 +30,14 @@ function entryLookup(postUrl, routerOptions, locals) {
isEditURL = true;
}

let resourceType = routerOptions.resourceType;

// @NOTE: v0.1 does not have a pages controller.
// @TODO: remove me when we drop v0.1
if (!api[resourceType]) {
resourceType = 'posts';
}

/**
* Query database to find entry.
* @deprecated: `author`, will be removed in Ghost 3.0
*/
return api[resourceType]
return (api[routerOptions.query.alias] || api[routerOptions.query.resource])
.read(_.extend(_.pick(params, 'slug', 'id'), {include: 'author,authors,tags'}))
.then(function then(result) {
const entry = result[resourceType][0];
const entry = (result[routerOptions.query.alias] || result[routerOptions.query.resource])[0];

if (!entry) {
return Promise.resolve();
Expand Down
23 changes: 13 additions & 10 deletions core/server/services/routing/helpers/fetch-data.js
Expand Up @@ -2,27 +2,31 @@
* # Fetch Data
* Dynamically build and execute queries on the API
*/
const _ = require('lodash'),
Promise = require('bluebird'),
defaultPostQuery = {};
const _ = require('lodash');
const Promise = require('bluebird');

// The default settings for a default post query
const queryDefaults = {
type: 'browse',
resource: 'posts',
alias: 'posts',
options: {}
};

/**
* Default post query needs to always include author, authors & tags
*
* @deprecated: `author`, will be removed in Ghost 3.0
*/
_.extend(defaultPostQuery, queryDefaults, {
const defaultQueryOptions = {
options: {
include: 'author,authors,tags'
}
});
};

/**
* Default post query needs to always include author, authors & tags
*/
const defaultPostQuery = _.cloneDeep(queryDefaults);
defaultPostQuery.options = defaultQueryOptions.options;

/**
* ## Process Query
Expand All @@ -39,7 +43,6 @@ function processQuery(query, slugParam, locals) {

query = _.cloneDeep(query);

// Ensure that all the properties are filled out
_.defaultsDeep(query, queryDefaults);

// Replace any slugs, see TaxonomyRouter. We replace any '%s' by the slug
Expand All @@ -48,7 +51,7 @@ function processQuery(query, slugParam, locals) {
});

// Return a promise for the api query
return api[query.resource][query.type](query.options);
return (api[query.alias] || api[query.resource])[query.type](query.options);
}

/**
Expand Down Expand Up @@ -100,7 +103,7 @@ function fetchData(pathOptions, routerOptions, locals) {
if (config.type === 'browse') {
response.data[name] = results[name];
} else {
response.data[name] = results[name][config.resource];
response.data[name] = results[name][config.alias] || results[name][config.resource];
}
});
}
Expand Down
4 changes: 2 additions & 2 deletions core/server/services/settings/validate.js
Expand Up @@ -48,7 +48,6 @@ _private.validateData = function validateData(object) {

let [resourceKey, slug] = shortForm.split('.');

// @NOTE: `data: author.foo` is not allowed currently, because this will make {{author}} available in the theme, which is deprecated (single author usage)
if (!RESOURCE_CONFIG.QUERY[resourceKey] ||
(RESOURCE_CONFIG.QUERY[resourceKey].hasOwnProperty('internal') && RESOURCE_CONFIG.QUERY[resourceKey].internal === true)) {
throw new common.errors.ValidationError({
Expand All @@ -58,7 +57,7 @@ _private.validateData = function validateData(object) {
}

longForm.query[options.resourceKey || resourceKey] = {};
longForm.query[options.resourceKey || resourceKey] = _.omit(_.cloneDeep(RESOURCE_CONFIG.QUERY[resourceKey]), 'alias');
longForm.query[options.resourceKey || resourceKey] = _.cloneDeep(RESOURCE_CONFIG.QUERY[resourceKey]);

// redirect is enabled by default when using the short form
longForm.router = {
Expand Down Expand Up @@ -148,6 +147,7 @@ _private.validateData = function validateData(object) {
});

const DEFAULT_RESOURCE = _.find(RESOURCE_CONFIG.QUERY, {resource: data.query[key].resource});
data.query[key] = _.defaults(data.query[key], _.omit(DEFAULT_RESOURCE, 'options'));

data.query[key].options = _.pick(object.data[key], allowedQueryOptions);
if (data.query[key].type === 'read') {
Expand Down
2 changes: 1 addition & 1 deletion core/server/services/url/Resources.js
Expand Up @@ -109,7 +109,7 @@ const resourcesConfig = [
}
},
{
type: 'users',
type: 'authors',
modelOptions: {
modelName: 'User',
exclude: [
Expand Down
3 changes: 3 additions & 0 deletions core/server/translations/en.json
Expand Up @@ -349,6 +349,9 @@
"posts": {
"postNotFound": "Post not found."
},
"authors": {
"notFound": "Author not found."
},
"pages": {
"pageNotFound": "Page not found."
},
Expand Down

0 comments on commit ff6bf5f

Please sign in to comment.