mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-24 06:35:49 +03:00
Added support for filtering snippets to mobiledoc/lexical (#16636)
refs TryGhost/Team#2904 <!-- Leave the line below if you'd like GitHub Copilot to generate a summary from your commit --> <!-- copilot:summary --> ### <samp>🤖 Generated by Copilot at b3f5423</samp> This pull request adds support for multiple formats of snippet content, especially the `lexical` format, to the Ghost CMS. It modifies the snippets API, model, and test files to handle the format conversion, filtering, and serialization of snippets.
This commit is contained in:
parent
5d43101f40
commit
7f184d2451
@ -15,9 +15,18 @@ module.exports = {
|
||||
options: [
|
||||
'limit',
|
||||
'order',
|
||||
'page'
|
||||
'page',
|
||||
'formats',
|
||||
'filter'
|
||||
],
|
||||
permissions: true,
|
||||
validation: {
|
||||
options: {
|
||||
formats: {
|
||||
values: models.Snippet.allowedFormats
|
||||
}
|
||||
}
|
||||
},
|
||||
query(frame) {
|
||||
return models.Snippet.findPage(frame.options);
|
||||
}
|
||||
@ -25,6 +34,9 @@ module.exports = {
|
||||
|
||||
read: {
|
||||
headers: {},
|
||||
options: [
|
||||
'formats'
|
||||
],
|
||||
data: [
|
||||
'id'
|
||||
],
|
||||
@ -46,6 +58,9 @@ module.exports = {
|
||||
add: {
|
||||
statusCode: 201,
|
||||
headers: {},
|
||||
options: [
|
||||
'formats'
|
||||
],
|
||||
permissions: true,
|
||||
query(frame) {
|
||||
return models.Snippet.add(frame.data.snippets[0], frame.options)
|
||||
@ -62,7 +77,8 @@ module.exports = {
|
||||
edit: {
|
||||
headers: {},
|
||||
options: [
|
||||
'id'
|
||||
'id',
|
||||
'formats'
|
||||
],
|
||||
validation: {
|
||||
options: {
|
||||
|
@ -12,6 +12,7 @@ module.exports = (snippet, frame) => {
|
||||
name: json.name,
|
||||
// @ts-ignore
|
||||
mobiledoc: json.mobiledoc,
|
||||
lexical: json.lexical,
|
||||
created_at: json.created_at,
|
||||
updated_at: json.updated_at,
|
||||
created_by: json.created_by,
|
||||
@ -24,6 +25,7 @@ module.exports = (snippet, frame) => {
|
||||
* @prop {string} id
|
||||
* @prop {string} [name]
|
||||
* @prop {string} [mobiledoc]
|
||||
* @prop {string} [lexical]
|
||||
* @prop {string} created_at
|
||||
* @prop {string} updated_at
|
||||
* @prop {string} created_by
|
||||
|
@ -1,6 +1,8 @@
|
||||
const ghostBookshelf = require('./base');
|
||||
const urlUtils = require('../../shared/url-utils');
|
||||
const mobiledocLib = require('../lib/mobiledoc');
|
||||
const lexicalLib = require('../lib/lexical');
|
||||
const _ = require('lodash');
|
||||
|
||||
const Snippet = ghostBookshelf.Model.extend({
|
||||
tableName: 'snippets',
|
||||
@ -10,6 +12,13 @@ const Snippet = ghostBookshelf.Model.extend({
|
||||
attrs.mobiledoc = urlUtils.mobiledocToTransformReady(attrs.mobiledoc, {cardTransformers: mobiledocLib.cards});
|
||||
}
|
||||
|
||||
if (attrs.lexical) {
|
||||
attrs.lexical = urlUtils.lexicalToTransformReady(attrs.lexical, {
|
||||
nodes: lexicalLib.nodes,
|
||||
transformMap: lexicalLib.urlTransformMap
|
||||
});
|
||||
}
|
||||
|
||||
return attrs;
|
||||
},
|
||||
|
||||
@ -20,8 +29,35 @@ const Snippet = ghostBookshelf.Model.extend({
|
||||
attrs.mobiledoc = urlUtils.transformReadyToAbsolute(attrs.mobiledoc);
|
||||
}
|
||||
|
||||
if (attrs.lexical) {
|
||||
attrs.lexical = urlUtils.transformReadyToAbsolute(attrs.lexical);
|
||||
}
|
||||
|
||||
return attrs;
|
||||
},
|
||||
|
||||
formatsToJSON: function formatsToJSON(attrs, options) {
|
||||
const defaultFormats = ['mobiledoc'];
|
||||
const formatsToKeep = options.formats || defaultFormats;
|
||||
|
||||
// Iterate over all known formats, and if they are not in the keep list, remove them
|
||||
_.each(Snippet.allowedFormats, function (format) {
|
||||
if (formatsToKeep.indexOf(format) === -1) {
|
||||
delete attrs[format];
|
||||
}
|
||||
});
|
||||
|
||||
return attrs;
|
||||
},
|
||||
toJSON: function toJSON(options) {
|
||||
let attrs = ghostBookshelf.Model.prototype.toJSON.call(this, options);
|
||||
|
||||
attrs = this.formatsToJSON(attrs, options);
|
||||
|
||||
return attrs;
|
||||
}
|
||||
}, {
|
||||
allowedFormats: ['mobiledoc', 'lexical']
|
||||
});
|
||||
|
||||
const Snippets = ghostBookshelf.Collection.extend({
|
||||
|
@ -62,7 +62,7 @@
|
||||
"@tryghost/adapter-base-cache": "0.1.5",
|
||||
"@tryghost/adapter-cache-redis": "0.0.0",
|
||||
"@tryghost/adapter-manager": "0.0.0",
|
||||
"@tryghost/admin-api-schema": "4.2.3",
|
||||
"@tryghost/admin-api-schema": "4.3.0",
|
||||
"@tryghost/api-framework": "0.0.0",
|
||||
"@tryghost/api-version-compatibility-service": "0.0.0",
|
||||
"@tryghost/audience-feedback": "0.0.0",
|
||||
|
@ -28,6 +28,34 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Snippets API Can add lexical 1: [body] 1`] = `
|
||||
Object {
|
||||
"snippets": Array [
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"lexical": "{\\"node\\":\\"text\\"}",
|
||||
"name": "test lexical",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Snippets API Can add lexical 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": "182",
|
||||
"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\\?:\\\\/\\\\/\\.\\*\\?\\\\/snippets\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,
|
||||
"vary": "Accept-Version, Origin, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Snippets API Can browse 1: [body] 1`] = `
|
||||
Object {
|
||||
"meta": Object {
|
||||
@ -72,6 +100,43 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Snippets API Can browse lexical 1: [body] 1`] = `
|
||||
Object {
|
||||
"meta": Object {
|
||||
"pagination": Object {
|
||||
"limit": 15,
|
||||
"next": null,
|
||||
"page": 1,
|
||||
"pages": 1,
|
||||
"prev": null,
|
||||
"total": 1,
|
||||
},
|
||||
},
|
||||
"snippets": Array [
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"lexical": "{\\"node\\":\\"text\\"}",
|
||||
"name": "test lexical",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Snippets API Can browse lexical 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": "270",
|
||||
"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[`Snippets API Can destroy 1: [body] 1`] = `
|
||||
Object {
|
||||
"snippets": Array [
|
||||
@ -197,6 +262,61 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Snippets API Can edit lexical 1: [body] 1`] = `
|
||||
Object {
|
||||
"snippets": Array [
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"lexical": "{}",
|
||||
"name": "change me",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Snippets API Can edit lexical 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": "162",
|
||||
"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\\?:\\\\/\\\\/\\.\\*\\?\\\\/snippets\\\\/\\[a-f0-9\\]\\{24\\}\\\\//,
|
||||
"vary": "Accept-Version, Origin, Accept-Encoding",
|
||||
"x-powered-by": "Express",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Snippets API Can edit lexical 3: [body] 1`] = `
|
||||
Object {
|
||||
"snippets": Array [
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"lexical": "{\\"node\\":\\"text\\"}",
|
||||
"name": "changed lexical",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Snippets API Can edit lexical 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": "185",
|
||||
"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[`Snippets API Can read 1: [body] 1`] = `
|
||||
Object {
|
||||
"snippets": Array [
|
||||
@ -224,6 +344,33 @@ Object {
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Snippets API Can read lexical 1: [body] 1`] = `
|
||||
Object {
|
||||
"snippets": Array [
|
||||
Object {
|
||||
"created_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
"id": StringMatching /\\[a-f0-9\\]\\{24\\}/,
|
||||
"lexical": null,
|
||||
"name": "Test snippet 1",
|
||||
"updated_at": StringMatching /\\\\d\\{4\\}-\\\\d\\{2\\}-\\\\d\\{2\\}T\\\\d\\{2\\}:\\\\d\\{2\\}:\\\\d\\{2\\}\\\\\\.000Z/,
|
||||
},
|
||||
],
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`Snippets API Can read lexical 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": "167",
|
||||
"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[`Snippets API Cannot destroy non-existent snippet 1: [body] 1`] = `
|
||||
Object {
|
||||
"errors": Array [
|
||||
|
@ -62,6 +62,19 @@ describe('Snippets API', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('Can read lexical', async function () {
|
||||
await agent
|
||||
.get(`snippets/${fixtureManager.get('snippets', 0).id}/?formats=lexical`)
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot({
|
||||
snippets: [matchSnippet]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
'content-version': anyContentVersion,
|
||||
etag: anyEtag
|
||||
});
|
||||
});
|
||||
|
||||
it('Can edit', async function () {
|
||||
const snippetToChange = {
|
||||
name: 'change me',
|
||||
@ -159,4 +172,79 @@ describe('Snippets API', function () {
|
||||
etag: anyEtag
|
||||
});
|
||||
});
|
||||
|
||||
it('Can add lexical', async function () {
|
||||
const snippet = {
|
||||
name: 'test lexical',
|
||||
lexical: JSON.stringify({node: 'text'}),
|
||||
mobiledoc: '{}'
|
||||
};
|
||||
|
||||
await agent
|
||||
.post('snippets/?formats=lexical')
|
||||
.body({snippets: [snippet]})
|
||||
.expectStatus(201)
|
||||
.matchBodySnapshot({
|
||||
snippets: [matchSnippet]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
'content-version': anyContentVersion,
|
||||
etag: anyEtag,
|
||||
location: anyLocationFor('snippets')
|
||||
});
|
||||
});
|
||||
|
||||
it('Can browse lexical', async function () {
|
||||
await agent
|
||||
.get('snippets?formats=lexical&filter=lexical:-null')
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot({
|
||||
snippets: new Array(1).fill(matchSnippet)
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
'content-version': anyContentVersion,
|
||||
etag: anyEtag
|
||||
});
|
||||
});
|
||||
|
||||
it('Can edit lexical', async function () {
|
||||
const snippetToChange = {
|
||||
name: 'change me',
|
||||
mobiledoc: '{}',
|
||||
lexical: '{}'
|
||||
};
|
||||
|
||||
const snippetChanged = {
|
||||
name: 'changed lexical',
|
||||
mobiledoc: '{}',
|
||||
lexical: JSON.stringify({node: 'text'})
|
||||
};
|
||||
|
||||
const {body} = await agent
|
||||
.post(`snippets/?formats=lexical`)
|
||||
.body({snippets: [snippetToChange]})
|
||||
.expectStatus(201)
|
||||
.matchBodySnapshot({
|
||||
snippets: [matchSnippet]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
'content-version': anyContentVersion,
|
||||
etag: anyEtag,
|
||||
location: anyLocationFor('snippets')
|
||||
});
|
||||
|
||||
const newsnippet = body.snippets[0];
|
||||
|
||||
await agent
|
||||
.put(`snippets/${newsnippet.id}/?formats=lexical`)
|
||||
.body({snippets: [snippetChanged]})
|
||||
.expectStatus(200)
|
||||
.matchBodySnapshot({
|
||||
snippets: [matchSnippet]
|
||||
})
|
||||
.matchHeaderSnapshot({
|
||||
'content-version': anyContentVersion,
|
||||
etag: anyEtag
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -177,6 +177,7 @@ describe('Unit: utils/serializers/output/mappers', function () {
|
||||
id: snippet.id,
|
||||
name: snippet.name,
|
||||
mobiledoc: snippet.mobiledoc,
|
||||
lexical: snippet.lexical,
|
||||
created_at: snippet.created_at,
|
||||
updated_at: snippet.updated_at,
|
||||
created_by: snippet.created_by,
|
||||
|
@ -5557,10 +5557,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@tryghost/adapter-base-cache/-/adapter-base-cache-0.1.5.tgz#66021c4e3e92bc623c82728ab50ca497ac41f7ae"
|
||||
integrity sha512-ZAG7Qzn0RioU6yde67T9cneRtoD1ZxGcjwH81DdbL8ZqiPi66bmPw5TVOiEiFnny2XSDsPuUgc4/PxFO/RfV0g==
|
||||
|
||||
"@tryghost/admin-api-schema@4.2.3":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@tryghost/admin-api-schema/-/admin-api-schema-4.2.3.tgz#fb6216f0c6ed103a32925d4ab2fa7582bb4a000d"
|
||||
integrity sha512-3UmabEJd+fUZv3cSkpQ9Zo17DZpDVuVvG+9Mh0H+zZBmsw7FuTAlb5KzG4T3pFVv6X2/xrf5PMQBfTt+jGR6+g==
|
||||
"@tryghost/admin-api-schema@4.3.0":
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@tryghost/admin-api-schema/-/admin-api-schema-4.3.0.tgz#f3ecc16d9ab7e2a1c25e600f4663738e5e6a63db"
|
||||
integrity sha512-LyS3OnpRjuM89JNGxJAH3t9eFGPVS1CGEpDREHnD6SNn6J9iyYH3hmS8KOfZ87RXmwhF5qOODgaapZ/uMyRMtg==
|
||||
dependencies:
|
||||
"@tryghost/errors" "^1.0.0"
|
||||
ajv "^6.12.6"
|
||||
|
Loading…
Reference in New Issue
Block a user