0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-06 22:40:14 -05:00

Fixed date filtering in collections

refs https://github.com/TryGhost/Team/issues/3169

- To be able to apply NQL filtering on Collection Posts the dates should be serialized to be ISO Date Strings instead of raw Dates. Otherwise, NQL filtering fails to compare Date with a Date String.
This commit is contained in:
Naz 2023-06-23 14:52:53 +07:00 committed by naz
parent 36783e456b
commit f74588f9c2
3 changed files with 83 additions and 288 deletions

View file

@ -1,16 +1,44 @@
class PostsRepository {
constructor({models, browsePostsAPI}) {
constructor({models, browsePostsAPI, moment}) {
this.models = models;
this.browsePostsAPI = browsePostsAPI;
this.moment = moment;
}
/**
* @NOTE: This is a copy of the date serialization from Posts Content API.
* We need the dates serialized instead of keeping them as plain dates
* to be able to apply NQL filtering inside of Collections.
* @param {Object} attrs
* @returns
*/
serializeDates(attrs) {
const formatDate = (date) => {
return this.moment(date)
.toISOString(true);
};
['created_at', 'updated_at', 'published_at'].forEach((field) => {
if (attrs[field]) {
attrs[field] = formatDate(attrs[field]);
}
});
return attrs;
}
async getAll({filter}) {
const posts = await this.models.Post.findAll({
// @NOTE: enforce "post" type to avoid ever fetching pages
filter: `(${filter})+type:post`
const response = await this.browsePostsAPI({
options: {
filter: `(${filter})+type:post`,
limit: 'all'
}
});
return posts.toJSON();
response.posts = response.posts
.map(this.serializeDates.bind(this));
return response.posts;
}
async getBulk(ids) {
@ -20,6 +48,9 @@ class PostsRepository {
}
});
response.posts = response.posts
.map(this.serializeDates.bind(this));
return response.posts;
}
}
@ -27,6 +58,7 @@ class PostsRepository {
module.exports = PostsRepository;
module.exports.getInstance = () => {
const moment = require('moment-timezone');
const models = require('../../models');
const browsePostsAPI = async (options) => {
const rawPosts = await require('../../api/').endpoints.posts.browse.query(options);
@ -35,5 +67,5 @@ module.exports.getInstance = () => {
return options.response;
};
return new PostsRepository({models, browsePostsAPI});
return new PostsRepository({models, browsePostsAPI, moment});
};

View file

@ -104,48 +104,6 @@ Object {
}
`;
exports[`Collections API Automatic Collection Filtering Creates an automatic Collection with a relational tag filter 1: [body] 1`] = `
Object {
"collections": Array [
Object {
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": "Test Collection Description with relational tag filter",
"feature_image": null,
"filter": "tag:kitchen-sink",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"posts": Array [
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": 0,
},
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": 1,
},
],
"title": "Test Collection with relational tag filter",
"type": "automatic",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
},
],
}
`;
exports[`Collections API Automatic Collection Filtering Creates an automatic Collection with a relational tag filter 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "431",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"location": StringMatching /https\\?:\\\\/\\\\/\\.\\*\\?\\\\/collections\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-cache-invalidate": "/*",
"x-powered-by": "Express",
}
`;
exports[`Collections API Browse Can browse Collections 1: [body] 1`] = `
Object {
"collections": Array [
@ -284,7 +242,7 @@ Object {
"codeinjection_foot": null,
"codeinjection_head": null,
"comment_id": "6194d3ce51e2700162531a77",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"custom_excerpt": "We've crammed the most important information to help you get started with Ghost into this one post. It's your cheat-sheet to get started, and your shortcut to advanced features.",
"custom_template": null,
"email_only": false,
@ -303,7 +261,7 @@ Object {
"og_description": null,
"og_image": null,
"og_title": null,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"reading_time": 2,
"slug": "welcome",
"status": "published",
@ -311,7 +269,7 @@ Object {
"twitter_description": null,
"twitter_image": null,
"twitter_title": null,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"url": "http://127.0.0.1:2369/welcome/",
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "public",
@ -321,7 +279,7 @@ Object {
"codeinjection_foot": null,
"codeinjection_head": null,
"comment_id": "6194d3ce51e2700162531a76",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"custom_excerpt": "How to tweak a few settings in Ghost to transform your site from a generic template to a custom brand with style and personality.",
"custom_template": null,
"email_only": false,
@ -352,7 +310,7 @@ Object {
"og_description": null,
"og_image": null,
"og_title": null,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"reading_time": 3,
"slug": "design",
"status": "published",
@ -360,7 +318,7 @@ Object {
"twitter_description": null,
"twitter_image": null,
"twitter_title": null,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"url": "http://127.0.0.1:2369/design/",
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "public",
@ -370,7 +328,7 @@ Object {
"codeinjection_foot": null,
"codeinjection_head": null,
"comment_id": "6194d3ce51e2700162531a75",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"custom_excerpt": "A full overview of all the features built into the Ghost editor, including powerful workflow automations to speed up your creative process.",
"custom_template": null,
"email_only": false,
@ -389,7 +347,7 @@ Object {
"og_description": null,
"og_image": null,
"og_title": null,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"reading_time": 5,
"slug": "write",
"status": "published",
@ -397,7 +355,7 @@ Object {
"twitter_description": null,
"twitter_image": null,
"twitter_title": null,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"url": "http://127.0.0.1:2369/write/",
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "public",
@ -407,7 +365,7 @@ Object {
"codeinjection_foot": null,
"codeinjection_head": null,
"comment_id": "6194d3ce51e2700162531a74",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"custom_excerpt": "How Ghost allows you to turn anonymous readers into an audience of active subscribers, so you know what's working and what isn't.",
"custom_template": null,
"email_only": false,
@ -426,7 +384,7 @@ Object {
"og_description": null,
"og_image": null,
"og_title": null,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"reading_time": 2,
"slug": "portal",
"status": "published",
@ -434,7 +392,7 @@ Object {
"twitter_description": null,
"twitter_image": null,
"twitter_title": null,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"url": "http://127.0.0.1:2369/portal/",
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "public",
@ -444,7 +402,7 @@ Object {
"codeinjection_foot": null,
"codeinjection_head": null,
"comment_id": "6194d3ce51e2700162531a73",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"custom_excerpt": null,
"custom_template": null,
"email_only": false,
@ -469,7 +427,7 @@ Using subscrip",
"og_description": null,
"og_image": null,
"og_title": null,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"reading_time": 1,
"slug": "sell",
"status": "published",
@ -477,7 +435,7 @@ Using subscrip",
"twitter_description": null,
"twitter_image": null,
"twitter_title": null,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"url": "http://127.0.0.1:2369/sell/",
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "paid",
@ -487,7 +445,7 @@ Using subscrip",
"codeinjection_foot": null,
"codeinjection_head": null,
"comment_id": "6194d3ce51e2700162531a72",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"custom_excerpt": "A guide to collaborating with other staff users to publish, and some resources to help you with the next steps of growing your business",
"custom_template": null,
"email_only": false,
@ -506,7 +464,7 @@ Using subscrip",
"og_description": null,
"og_image": null,
"og_title": null,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"reading_time": 2,
"slug": "grow",
"status": "published",
@ -514,7 +472,7 @@ Using subscrip",
"twitter_description": null,
"twitter_image": null,
"twitter_title": null,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"url": "http://127.0.0.1:2369/grow/",
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "public",
@ -524,7 +482,7 @@ Using subscrip",
"codeinjection_foot": null,
"codeinjection_head": null,
"comment_id": "6194d3ce51e2700162531a71",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"custom_excerpt": "Work with all your favorite apps and tools or create your own custom integrations using the Ghost API.",
"custom_template": null,
"email_only": false,
@ -544,7 +502,7 @@ Using subscrip",
"og_description": null,
"og_image": null,
"og_title": null,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"reading_time": 1,
"slug": "integrations",
"status": "published",
@ -552,7 +510,7 @@ Using subscrip",
"twitter_description": null,
"twitter_image": null,
"twitter_title": null,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"url": "http://127.0.0.1:2369/integrations/",
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "public",
@ -562,7 +520,7 @@ Using subscrip",
"codeinjection_foot": null,
"codeinjection_head": null,
"comment_id": "618ba1ffbe2896088840a6e7",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"custom_excerpt": null,
"custom_template": null,
"email_only": false,
@ -592,7 +550,7 @@ Definition listConsectetur adipisicing elit, sed do eiusmod tempor incididunt ut
"og_description": null,
"og_image": null,
"og_title": null,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"reading_time": 1,
"slug": "not-so-short-bit-complex",
"status": "published",
@ -600,7 +558,7 @@ Definition listConsectetur adipisicing elit, sed do eiusmod tempor incididunt ut
"twitter_description": null,
"twitter_image": null,
"twitter_title": null,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"url": "http://127.0.0.1:2369/not-so-short-bit-complex/",
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "public",
@ -610,7 +568,7 @@ Definition listConsectetur adipisicing elit, sed do eiusmod tempor incididunt ut
"codeinjection_foot": null,
"codeinjection_head": null,
"comment_id": "618ba1ffbe2896088840a6e3",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"custom_excerpt": null,
"custom_template": null,
"email_only": false,
@ -645,7 +603,7 @@ mctesters
"og_description": null,
"og_image": null,
"og_title": null,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"reading_time": 0,
"slug": "short-and-sweet",
"status": "published",
@ -653,7 +611,7 @@ mctesters
"twitter_description": null,
"twitter_image": null,
"twitter_title": null,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"url": "http://127.0.0.1:2369/short-and-sweet/",
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "public",
@ -663,7 +621,7 @@ mctesters
"codeinjection_foot": null,
"codeinjection_head": null,
"comment_id": "618ba1ffbe2896088840a6e1",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"custom_excerpt": null,
"custom_template": null,
"email_only": false,
@ -684,7 +642,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu
"og_description": null,
"og_image": null,
"og_title": null,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"reading_time": 1,
"slug": "ghostly-kitchen-sink",
"status": "published",
@ -692,7 +650,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu
"twitter_description": null,
"twitter_image": null,
"twitter_title": null,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"url": "http://127.0.0.1:2369/ghostly-kitchen-sink/",
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "public",
@ -702,7 +660,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu
"codeinjection_foot": null,
"codeinjection_head": null,
"comment_id": "618ba1ffbe2896088840a6df",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"custom_excerpt": "This is my custom excerpt!",
"custom_template": null,
"email_only": false,
@ -721,7 +679,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu
"og_description": null,
"og_image": null,
"og_title": null,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"reading_time": 1,
"slug": "html-ipsum",
"status": "published",
@ -729,7 +687,7 @@ Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac tu
"twitter_description": null,
"twitter_image": null,
"twitter_title": null,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"url": "http://127.0.0.1:2369/html-ipsum/",
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "public",
@ -752,49 +710,7 @@ exports[`Collections API Browse Posts Can browse Collections Posts 2: [headers]
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "45967",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-powered-by": "Express",
}
`;
exports[`Collections API Browse Posts Can browse Collections Posts 3: [body] 1`] = `
Object {
"collection_posts": Array [
Object {
"featured": false,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"slug": "write",
"title": "Writing and managing content in Ghost, an advanced guide",
},
Object {
"featured": false,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"slug": "portal",
"title": "Building your audience with subscriber signups",
},
],
"meta": Object {
"pagination": Object {
"limit": "2",
"next": null,
"page": "2",
"pages": 1,
"prev": null,
"total": 2,
},
},
}
`;
exports[`Collections API Browse Posts Can browse Collections Posts 4: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "370",
"content-length": "46132",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -811,7 +727,7 @@ Object {
"codeinjection_foot": null,
"codeinjection_head": null,
"comment_id": "6194d3ce51e2700162531a75",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"custom_excerpt": "A full overview of all the features built into the Ghost editor, including powerful workflow automations to speed up your creative process.",
"custom_template": null,
"email_only": false,
@ -830,7 +746,7 @@ Object {
"og_description": null,
"og_image": null,
"og_title": null,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"reading_time": 5,
"slug": "write",
"status": "published",
@ -838,7 +754,7 @@ Object {
"twitter_description": null,
"twitter_image": null,
"twitter_title": null,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"url": "http://127.0.0.1:2369/write/",
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "public",
@ -848,7 +764,7 @@ Object {
"codeinjection_foot": null,
"codeinjection_head": null,
"comment_id": "6194d3ce51e2700162531a74",
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"custom_excerpt": "How Ghost allows you to turn anonymous readers into an audience of active subscribers, so you know what's working and what isn't.",
"custom_template": null,
"email_only": false,
@ -867,7 +783,7 @@ Object {
"og_description": null,
"og_image": null,
"og_title": null,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"published_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"reading_time": 2,
"slug": "portal",
"status": "published",
@ -875,7 +791,7 @@ Object {
"twitter_description": null,
"twitter_image": null,
"twitter_title": null,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000\\\\\\+\\\\d\\{2\\}:\\\\d\\{2\\}/,
"url": "http://127.0.0.1:2369/portal/",
"uuid": StringMatching /\\[a-f0-9\\]\\{8\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{4\\}-\\[a-f0-9\\]\\{12\\}/,
"visibility": "public",
@ -898,7 +814,7 @@ exports[`Collections API Browse Posts Can browse Collections Posts using paging
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "14035",
"content-length": "14065",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -940,125 +856,6 @@ Object {
}
`;
exports[`Collections API Can browse Collections 1: [body] 1`] = `
Object {
"collections": Array [
Object {
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": "Collection with all posts",
"feature_image": null,
"filter": "status:published",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"posts": Array [
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": Any<Number>,
},
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": Any<Number>,
},
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": Any<Number>,
},
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": Any<Number>,
},
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": Any<Number>,
},
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": Any<Number>,
},
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": Any<Number>,
},
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": Any<Number>,
},
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": Any<Number>,
},
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": Any<Number>,
},
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": Any<Number>,
},
],
"slug": "index",
"title": "Index",
"type": "automatic",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
},
Object {
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": "Collection of featured posts",
"feature_image": null,
"filter": "featured:true",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"posts": Array [
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": Any<Number>,
},
Object {
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"sort_order": Any<Number>,
},
],
"slug": "featured",
"title": "Featured Posts",
"type": "automatic",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
},
Object {
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": "Test Collection Description",
"feature_image": null,
"filter": null,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"posts": Array [],
"title": "Test Collection",
"type": "manual",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
},
],
"meta": Object {
"pagination": Object {
"limit": 3,
"next": null,
"page": 1,
"pages": 1,
"prev": null,
"total": 3,
},
},
}
`;
exports[`Collections API Can browse Collections 2: [headers] 1`] = `
Object {
"access-control-allow-origin": "http://127.0.0.1:2369",
"cache-control": "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0",
"content-length": "1530",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
"vary": "Accept-Version, Origin, Accept-Encoding",
"x-powered-by": "Express",
}
`;
exports[`Collections API Can delete a Collection 1: [body] 1`] = `
Object {
"collections": Array [

View file

@ -12,6 +12,7 @@ const {
anyLocationFor,
anyObjectId,
anyISODateTime,
anyISODateTimeWithTZ,
anyNumber,
anyUuid,
anyString
@ -25,9 +26,9 @@ const matchCollection = {
const matchCollectionPost = {
id: anyObjectId,
created_at: anyISODateTime,
updated_at: anyISODateTime,
published_at: anyISODateTime,
created_at: anyISODateTimeWithTZ,
updated_at: anyISODateTimeWithTZ,
published_at: anyISODateTimeWithTZ,
uuid: anyUuid
};
@ -352,40 +353,5 @@ describe('Collections API', function () {
collections: [buildMatcher(7)]
});
});
it('Creates an automatic Collection with a relational tag filter', async function () {
const collection = {
title: 'Test Collection with relational tag filter',
description: 'Test Collection Description with relational tag filter',
type: 'automatic',
filter: 'tag:kitchen-sink'
};
const automaticTagCollection = await agent
.post('/collections/')
.body({
collections: [collection]
})
.expectStatus(201)
.matchHeaderSnapshot({
'content-version': anyContentVersion,
etag: anyEtag,
location: anyLocationFor('collections')
})
.matchBodySnapshot({
collections: [buildMatcher(2)]
});
const kitchenSinkTagPosts = await agent
.get('/posts/?filter=tag:kitchen-sink');
assert.equal(automaticTagCollection.body.collections[0].posts.length, 2);
assert.equal(kitchenSinkTagPosts.body.posts.length, 2);
const collectionPostIds = automaticTagCollection.body.collections[0].posts.map(p => p.id);
const tagFilteredPosts = kitchenSinkTagPosts.body.posts.map(p => p.id);
assert.deepEqual(collectionPostIds, tagFilteredPosts);
});
});
});