0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

Added property mapper to collections responses

closes https://github.com/TryGhost/Team/issues/3259

- API output mappers (soon to be serializers) are meant to work based on allowlist set of output properties. Having the allowlist early on will allow to track the API evolution consistently.
This commit is contained in:
Naz 2023-05-24 16:56:41 +07:00
parent fdd73d01b7
commit b52ec948b0
No known key found for this signature in database
7 changed files with 108 additions and 17 deletions

View file

@ -35,6 +35,20 @@ export class Collection {
this.deleted = data.deleted;
}
toJSON() {
return {
id: this.id,
title: this.title,
slug: this.slug,
description: this.description,
type: this.type,
filter: this.filter,
featureImage: this.featureImage,
createdAt: this.createdAt,
updatedAt: this.updatedAt
};
}
static validateDateField(date: any, fieldName: string): Date {
if (!date) {
return new Date();

View file

@ -52,12 +52,14 @@ export class CollectionsService {
};
}
async destroy(id: string): Promise<void> {
async destroy(id: string): Promise<Collection | null> {
const collection = await this.getById(id);
if (collection) {
collection.deleted = true;
await this.save(collection);
}
return collection;
}
}

View file

@ -18,6 +18,32 @@ describe('Collection', function () {
assert.ok((collection.deleted === false), 'deleted should be false');
});
it('Can serialize Collection to JSON', async function () {
const collection = await Collection.create({
title: 'Serialize me'
});
const json = collection.toJSON();
assert.ok(json);
assert.equal(json.id, collection.id);
assert.equal(json.title, 'Serialize me');
assert.ok(collection.createdAt instanceof Date);
assert.ok(collection.updatedAt instanceof Date);
assert.equal(Object.keys(json).length, 9, 'should only have 9 keys');
assert.deepEqual(Object.keys(json), [
'id',
'title',
'slug',
'description',
'type',
'filter',
'featureImage',
'createdAt',
'updatedAt'
]);
});
it('Can create a Collection with predefined ID', async function () {
const id = new ObjectID();
const savedCollection = await Collection.create({

View file

@ -0,0 +1,38 @@
/**
*
* @param {import('@tryghost/collections').Collection} collection
*
* @returns {SerializedCollection}
*/
const mapper = (collection) => {
const json = collection.toJSON();
const serialized = {
id: json.id,
title: json.title,
slug: json.slug,
description: json.description,
type: json.type,
filter: json.filter,
feature_image: json.featureImage,
created_at: json.createdAt.toISOString().replace(/\d{3}Z$/, '000Z'),
updated_at: json.updatedAt.toISOString().replace(/\d{3}Z$/, '000Z')
};
return serialized;
};
module.exports = mapper;
/**
* @typedef {Object} SerializedCollection
* @prop {string} id
* @prop {string} title
* @prop {string} slug
* @prop {string} description
* @prop {string} type
* @prop {string} filter
* @prop {string} feature_image
* @prop {string} created_at
* @prop {string} updated_at
*/

View file

@ -3,6 +3,7 @@ module.exports = {
activityFeedEvents: require('./activity-feed-events'),
authors: require('./authors'),
comments: require('./comments'),
collections: require('./collections'),
emails: require('./emails'),
emailBatches: require('./email-batches'),
emailFailures: require('./email-failures'),

View file

@ -4,10 +4,11 @@ exports[`Collections API Can add a Collection 1: [body] 1`] = `
Object {
"collections": Array [
Object {
"deleted": false,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": "Test Collection Description",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"title": "Test Collection",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
},
],
}
@ -17,7 +18,7 @@ exports[`Collections API Can add a Collection 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": "137",
"content-length": "201",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -32,10 +33,11 @@ exports[`Collections API Can browse Collections 1: [body] 1`] = `
Object {
"collections": Array [
Object {
"deleted": false,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"description": "Test Collection Description",
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"title": "Test Collection",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
},
],
"meta": Object {
@ -55,7 +57,7 @@ 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": "224",
"content-length": "288",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -68,9 +70,10 @@ exports[`Collections API Can delete a Collection 1: [body] 1`] = `
Object {
"collections": Array [
Object {
"deleted": false,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"title": "Test Collection to Delete",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
},
],
}
@ -80,7 +83,7 @@ exports[`Collections API Can delete a Collection 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": "103",
"content-length": "167",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -140,9 +143,10 @@ exports[`Collections API Can edit a Collection 1: [body] 1`] = `
Object {
"collections": Array [
Object {
"deleted": false,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"title": "Test Collection to Edit",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
},
],
}
@ -152,7 +156,7 @@ exports[`Collections API Can edit a Collection 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": "101",
"content-length": "165",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -167,9 +171,10 @@ exports[`Collections API Can edit a Collection 3: [body] 1`] = `
Object {
"collections": Array [
Object {
"deleted": false,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"title": "Test Collection Edited",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
},
],
}
@ -179,7 +184,7 @@ exports[`Collections API Can edit a Collection 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": "100",
"content-length": "164",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -193,9 +198,10 @@ exports[`Collections API Can read a Collection 1: [body] 1`] = `
Object {
"collections": Array [
Object {
"deleted": false,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"title": "Test Collection to Read",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
},
],
}
@ -205,7 +211,7 @@ exports[`Collections API Can read a Collection 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": "101",
"content-length": "165",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,
@ -220,9 +226,10 @@ exports[`Collections API Can read a Collection 3: [body] 1`] = `
Object {
"collections": Array [
Object {
"deleted": false,
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
"title": "Test Collection to Read",
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
},
],
}
@ -232,7 +239,7 @@ exports[`Collections API Can read a Collection 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": "101",
"content-length": "165",
"content-type": "application/json; charset=utf-8",
"content-version": StringMatching /v\\\\d\\+\\\\\\.\\\\d\\+/,
"etag": StringMatching /\\(\\?:W\\\\/\\)\\?"\\(\\?:\\[ !#-\\\\x7E\\\\x80-\\\\xFF\\]\\*\\|\\\\r\\\\n\\[\\\\t \\]\\|\\\\\\\\\\.\\)\\*"/,

View file

@ -10,11 +10,14 @@ const {
anyEtag,
anyErrorId,
anyLocationFor,
anyObjectId
anyObjectId,
anyISODateTime
} = matchers;
const matchCollection = {
id: anyObjectId
id: anyObjectId,
created_at: anyISODateTime,
updated_at: anyISODateTime
};
describe('Collections API', function () {