Ghost/core/server/helpers/has.js

166 lines
4.9 KiB
JavaScript
Raw Normal View History

// # Has Helper
// Usage: `{{#has tag="video, music"}}`, `{{#has author="sam, pat"}}`
✨ Multiple authors (#9426) no issue This PR adds the server side logic for multiple authors. This adds the ability to add multiple authors per post. We keep and support single authors (maybe till the next major - this is still in discussion) ### key notes - `authors` are not fetched by default, only if we need them - the migration script iterates over all posts and figures out if an author_id is valid and exists (in master we can add invalid author_id's) and then adds the relation (falls back to owner if invalid) - ~~i had to push a fork of bookshelf to npm because we currently can't bump bookshelf + the two bugs i discovered are anyway not yet merged (https://github.com/kirrg001/bookshelf/commits/master)~~ replaced by new bookshelf release - the implementation of single & multiple authors lives in a single place (introduction of a new concept: model relation) - if you destroy an author, we keep the behaviour for now -> remove all posts where the primary author id matches. furthermore, remove all relations in posts_authors (e.g. secondary author) - we make re-use of the `excludeAttrs` concept which was invented in the contributors PR (to protect editing authors as author/contributor role) -> i've added a clear todo that we need a logic to make a diff of the target relation -> both for tags and authors - `authors` helper available (same as `tags` helper) - `primary_author` computed field available - `primary_author` functionality available (same as `primary_tag` e.g. permalinks, prev/next helper etc)
2018-03-27 17:16:15 +03:00
// `{{#has author="count:1"}}`, `{{#has tag="count:>1"}}`
//
// Checks if a post has a particular property
var proxy = require('./proxy'),
_ = require('lodash'),
logging = proxy.logging,
i18n = proxy.i18n,
validAttrs = ['tag', 'author', 'slug', 'id', 'number', 'index', 'any', 'all'];
✨ Multiple authors (#9426) no issue This PR adds the server side logic for multiple authors. This adds the ability to add multiple authors per post. We keep and support single authors (maybe till the next major - this is still in discussion) ### key notes - `authors` are not fetched by default, only if we need them - the migration script iterates over all posts and figures out if an author_id is valid and exists (in master we can add invalid author_id's) and then adds the relation (falls back to owner if invalid) - ~~i had to push a fork of bookshelf to npm because we currently can't bump bookshelf + the two bugs i discovered are anyway not yet merged (https://github.com/kirrg001/bookshelf/commits/master)~~ replaced by new bookshelf release - the implementation of single & multiple authors lives in a single place (introduction of a new concept: model relation) - if you destroy an author, we keep the behaviour for now -> remove all posts where the primary author id matches. furthermore, remove all relations in posts_authors (e.g. secondary author) - we make re-use of the `excludeAttrs` concept which was invented in the contributors PR (to protect editing authors as author/contributor role) -> i've added a clear todo that we need a logic to make a diff of the target relation -> both for tags and authors - `authors` helper available (same as `tags` helper) - `primary_author` computed field available - `primary_author` functionality available (same as `primary_tag` e.g. permalinks, prev/next helper etc)
2018-03-27 17:16:15 +03:00
function handleCount(ctxAttr, data) {
let count;
if (ctxAttr.match(/count:\d+/)) {
count = Number(ctxAttr.match(/count:(\d+)/)[1]);
return count === data.length;
} else if (ctxAttr.match(/count:>\d/)) {
count = Number(ctxAttr.match(/count:>(\d+)/)[1]);
return count < data.length;
} else if (ctxAttr.match(/count:<\d/)) {
count = Number(ctxAttr.match(/count:<(\d+)/)[1]);
return count > data.length;
}
return false;
}
function evaluateTagList(expr, tags) {
return expr.split(',').map(function (v) {
return v.trim();
}).reduce(function (p, c) {
return p || (_.findIndex(tags, function (item) {
// Escape regex special characters
item = item.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
item = new RegExp('^' + item + '$', 'i');
return item.test(c);
}) !== -1);
}, false);
}
✨ Multiple authors (#9426) no issue This PR adds the server side logic for multiple authors. This adds the ability to add multiple authors per post. We keep and support single authors (maybe till the next major - this is still in discussion) ### key notes - `authors` are not fetched by default, only if we need them - the migration script iterates over all posts and figures out if an author_id is valid and exists (in master we can add invalid author_id's) and then adds the relation (falls back to owner if invalid) - ~~i had to push a fork of bookshelf to npm because we currently can't bump bookshelf + the two bugs i discovered are anyway not yet merged (https://github.com/kirrg001/bookshelf/commits/master)~~ replaced by new bookshelf release - the implementation of single & multiple authors lives in a single place (introduction of a new concept: model relation) - if you destroy an author, we keep the behaviour for now -> remove all posts where the primary author id matches. furthermore, remove all relations in posts_authors (e.g. secondary author) - we make re-use of the `excludeAttrs` concept which was invented in the contributors PR (to protect editing authors as author/contributor role) -> i've added a clear todo that we need a logic to make a diff of the target relation -> both for tags and authors - `authors` helper available (same as `tags` helper) - `primary_author` computed field available - `primary_author` functionality available (same as `primary_tag` e.g. permalinks, prev/next helper etc)
2018-03-27 17:16:15 +03:00
function handleTag(data, attrs) {
if (!attrs.tag) {
return false;
}
if (attrs.tag.match(/count:/)) {
return handleCount(attrs.tag, data.tags);
}
return evaluateTagList(attrs.tag, _.map(data.tags, 'name')) || false;
}
function evaluateAuthorList(expr, authors) {
var authorList = expr.split(',').map(function (v) {
return v.trim().toLocaleLowerCase();
});
✨ Multiple authors (#9426) no issue This PR adds the server side logic for multiple authors. This adds the ability to add multiple authors per post. We keep and support single authors (maybe till the next major - this is still in discussion) ### key notes - `authors` are not fetched by default, only if we need them - the migration script iterates over all posts and figures out if an author_id is valid and exists (in master we can add invalid author_id's) and then adds the relation (falls back to owner if invalid) - ~~i had to push a fork of bookshelf to npm because we currently can't bump bookshelf + the two bugs i discovered are anyway not yet merged (https://github.com/kirrg001/bookshelf/commits/master)~~ replaced by new bookshelf release - the implementation of single & multiple authors lives in a single place (introduction of a new concept: model relation) - if you destroy an author, we keep the behaviour for now -> remove all posts where the primary author id matches. furthermore, remove all relations in posts_authors (e.g. secondary author) - we make re-use of the `excludeAttrs` concept which was invented in the contributors PR (to protect editing authors as author/contributor role) -> i've added a clear todo that we need a logic to make a diff of the target relation -> both for tags and authors - `authors` helper available (same as `tags` helper) - `primary_author` computed field available - `primary_author` functionality available (same as `primary_tag` e.g. permalinks, prev/next helper etc)
2018-03-27 17:16:15 +03:00
return _.filter(authors, (author) => {
return _.includes(authorList, author.name.toLocaleLowerCase());
}).length;
}
function handleAuthor(data, attrs) {
if (!attrs.author) {
return false;
}
if (attrs.author.match(/count:/)) {
return handleCount(attrs.author, data.authors);
}
return evaluateAuthorList(attrs.author, data.authors) || false;
}
function evaluateIntegerMatch(expr, integer) {
var nthMatch = expr.match(/^nth:(\d+)/);
if (nthMatch) {
return integer % parseInt(nthMatch[1], 10) === 0;
}
return expr.split(',').reduce(function (bool, _integer) {
return bool || parseInt(_integer, 10) === integer;
}, false);
}
function evaluateStringMatch(expr, str, ci) {
if (ci) {
return expr && str && expr.toLocaleLowerCase() === str.toLocaleLowerCase();
}
return expr === str;
}
/**
*
* @param {String} type - either some or every - the lodash function to use
* @param {String} expr - the attribute value passed into {{#has}}
* @param {Object} obj - "this" context from the helper
* @param {Object} data - global params
*/
function evaluateList(type, expr, obj, data) {
return expr.split(',').map(function (prop) {
return prop.trim().toLocaleLowerCase();
})[type](function (prop) {
if (prop.match(/^@/)) {
return _.has(data, prop.replace(/@/, '')) && !_.isEmpty(_.get(data, prop.replace(/@/, '')));
} else {
return _.has(obj, prop) && !_.isEmpty(_.get(obj, prop));
}
});
}
module.exports = function has(options) {
options = options || {};
options.hash = options.hash || {};
options.data = options.data || {};
var self = this,
attrs = _.pick(options.hash, validAttrs),
data = _.pick(options.data, ['blog', 'config', 'labs']),
checks = {
✨ Multiple authors (#9426) no issue This PR adds the server side logic for multiple authors. This adds the ability to add multiple authors per post. We keep and support single authors (maybe till the next major - this is still in discussion) ### key notes - `authors` are not fetched by default, only if we need them - the migration script iterates over all posts and figures out if an author_id is valid and exists (in master we can add invalid author_id's) and then adds the relation (falls back to owner if invalid) - ~~i had to push a fork of bookshelf to npm because we currently can't bump bookshelf + the two bugs i discovered are anyway not yet merged (https://github.com/kirrg001/bookshelf/commits/master)~~ replaced by new bookshelf release - the implementation of single & multiple authors lives in a single place (introduction of a new concept: model relation) - if you destroy an author, we keep the behaviour for now -> remove all posts where the primary author id matches. furthermore, remove all relations in posts_authors (e.g. secondary author) - we make re-use of the `excludeAttrs` concept which was invented in the contributors PR (to protect editing authors as author/contributor role) -> i've added a clear todo that we need a logic to make a diff of the target relation -> both for tags and authors - `authors` helper available (same as `tags` helper) - `primary_author` computed field available - `primary_author` functionality available (same as `primary_tag` e.g. permalinks, prev/next helper etc)
2018-03-27 17:16:15 +03:00
tag: function () {
return handleTag(self, attrs);
},
author: function () {
return handleAuthor(self, attrs);
},
number: function () {
return attrs.number && evaluateIntegerMatch(attrs.number, options.data.number) || false;
},
index: function () {
return attrs.index && evaluateIntegerMatch(attrs.index, options.data.index) || false;
},
slug: function () {
return attrs.slug && evaluateStringMatch(attrs.slug, self.slug, true) || false;
},
id: function () {
return attrs.id && evaluateStringMatch(attrs.id, self.id, true) || false;
},
any: function () {
return attrs.any && evaluateList('some', attrs.any, self, data) || false;
},
all: function () {
return attrs.all && evaluateList('every', attrs.all, self, data) || false;
}
},
result;
if (_.isEmpty(attrs)) {
🎨 configurable logging with bunyan (#7431) - 🛠 add bunyan and prettyjson, remove morgan - ✨ add logging module - GhostLogger class that handles setup of bunyan - PrettyStream for stdout - ✨ config for logging - @TODO: testing level fatal? - ✨ log each request via GhostLogger (express middleware) - @TODO: add errors to output - 🔥 remove errors.updateActiveTheme - we can read the value from config - 🔥 remove 15 helper functions in core/server/errors/index.js - all these functions get replaced by modules: 1. logging 2. error middleware handling for html/json 3. error creation (which will be part of PR #7477) - ✨ add express error handler for html/json - one true error handler for express responses - contains still some TODO's, but they are not high priority for first implementation/integration - this middleware only takes responsibility of either rendering html responses or return json error responses - 🎨 use new express error handler in middleware/index - 404 and 500 handling - 🎨 return error instead of error message in permissions/index.js - the rule for error handling should be: if you call a unit, this unit should return a custom Ghost error - 🎨 wrap serve static module - rule: if you call a module/unit, you should always wrap this error - it's always the same rule - so the caller never has to worry about what comes back - it's always a clear error instance - in this case: we return our notfounderror if serve static does not find the resource - this avoid having checks everywhere - 🎨 replace usages of errors/index.js functions and adapt tests - use logging.error, logging.warn - make tests green - remove some usages of logging and throwing api errors -> because when a request is involved, logging happens automatically - 🐛 return errorDetails to Ghost-Admin - errorDetails is used for Theme error handling - 🎨 use 500er error for theme is missing error in theme-handler - 🎨 extend file rotation to 1w
2016-10-04 18:33:43 +03:00
logging.warn(i18n.t('warnings.helpers.has.invalidAttribute'));
return;
}
result = _.some(attrs, function (value, attr) {
return checks[attr]();
});
if (result) {
return options.fn(this);
}
return options.inverse(this);
};