0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-04-08 02:52:39 -05:00

Switched URL calls to use Content API SDK

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

-  The Content API SDK is the recommended way to interact with the API
This commit is contained in:
Naz 2022-07-06 17:09:01 +02:00
parent 2ef8eb0586
commit 44c8969192
7 changed files with 84 additions and 46 deletions

View file

@ -21,6 +21,7 @@
"@testing-library/jest-dom": "5.16.2",
"@testing-library/react": "12.1.2",
"@testing-library/user-event": "14.0.0",
"@tryghost/content-api": "^1.11.0",
"elasticlunr": "0.9.5",
"react": "17.0.2",
"react-dom": "17.0.2",

View file

@ -9,7 +9,7 @@ export default class App extends React.Component {
super(props);
const searchIndex = new SearchIndex({
apiUrl: props.apiUrl,
siteURL: props.siteURL,
apiKey: props.apiKey
});

View file

@ -4,7 +4,7 @@ import React from 'react';
test('renders Sodo Search app component', () => {
window.location.hash = '#/search';
render(<App />);
render(<App siteURL="http://localhost" apiKey="69010382388f9de5869ad6e558" />);
// const containerElement = screen.getElementsByClassName('gh-portal-popup-container');
const containerElement = document.querySelector('.gh-root-frame');
expect(containerElement).toBeInTheDocument();

View file

@ -19,9 +19,8 @@ function getSiteData() {
if (scriptTag) {
const siteUrl = scriptTag.dataset.sodoSearch;
const apiKey = scriptTag.dataset.key;
const apiUrl = scriptTag.dataset.api;
const appVersion = scriptTag.dataset.version;
return {siteUrl, apiKey, apiUrl, appVersion};
return {siteUrl, apiKey, appVersion};
}
return {};
}

View file

@ -1,9 +1,13 @@
import elasticlunr from 'elasticlunr';
import GhostContentAPI from '@tryghost/content-api';
export default class SearchIndex {
constructor({apiUrl, apiKey}) {
this.apiUrl = apiUrl;
this.apiKey = apiKey;
constructor({siteURL, apiKey}) {
this.api = new GhostContentAPI({
url: siteURL,
key: apiKey,
version: 'v5.0'
});
this.postsIndex = null;
this.authorsIndex = null;
@ -12,8 +16,8 @@ export default class SearchIndex {
this.search = this.search.bind(this);
}
#updatePostIndex(data) {
data.posts.forEach((post) => {
#updatePostIndex(posts) {
posts.forEach((post) => {
this.postsIndex.addDoc({
id: post.id,
title: post.title,
@ -24,8 +28,8 @@ export default class SearchIndex {
});
}
#updateAuthorsIndex(data) {
data.authors.forEach((author) => {
#updateAuthorsIndex(authors) {
authors.forEach((author) => {
this.authorsIndex.addDoc({
id: author.id,
name: author.name,
@ -35,8 +39,8 @@ export default class SearchIndex {
});
}
#updateTagsIndex(data) {
data.tags.forEach((tag) => {
#updateTagsIndex(tags) {
tags.forEach((tag) => {
this.tagsIndex.addDoc({
id: tag.id,
name: tag.name,
@ -49,12 +53,12 @@ export default class SearchIndex {
// remove default stop words to search of *any* word
elasticlunr.clearStopWords();
const postsAPIUrl = `${this.apiUrl}/posts/?key=${this.apiKey}&limit=all&fields=id,slug,title,excerpt,url,updated_at,visibility&order=updated_at%20desc&formats=plaintext`;
const authorsAPIUrl = `${this.apiUrl}/authors/?key=${this.apiKey}&limit=all&fields=id,slug,name,url,profile_image`;
const tagsAPIUrl = `${this.apiUrl}/tags/?key=${this.apiKey}&limit=all&fields=id,slug,name,url`;
const postsResponse = await fetch(postsAPIUrl);
const posts = await postsResponse.json();
let posts = await this.api.posts.browse({
limit: 'all',
fields: 'id,slug,title,excerpt,url,updated_at,visibility',
order: 'updated_at DESC',
formats: 'plaintext'
});
this.postsIndex = elasticlunr();
this.postsIndex.addField('title');
@ -62,12 +66,17 @@ export default class SearchIndex {
this.postsIndex.addField('excerpt');
this.postsIndex.setRef('id');
if (posts.posts.length > 0) {
if (posts || posts.length > 0) {
if (!posts.length) {
posts = [posts];
}
this.#updatePostIndex(posts);
}
const authorsResponse = await fetch(authorsAPIUrl);
const authors = await authorsResponse.json();
let authors = await this.api.authors.browse({
limit: 'all',
fields: 'id,slug,name,url,profile_image'
});
this.authorsIndex = elasticlunr();
this.authorsIndex.addField('name');
@ -75,19 +84,28 @@ export default class SearchIndex {
this.authorsIndex.addField('profile_image');
this.authorsIndex.setRef('id');
if (authors.authors.length > 0) {
if (authors || authors.length > 0) {
if (!authors.length) {
authors = [authors];
}
this.#updateAuthorsIndex(authors);
}
const tagsResponse = await fetch(tagsAPIUrl);
const tags = await tagsResponse.json();
let tags = await this.api.tags.browse({
limit: 'all',
fields: 'id,slug,name,url'
});
this.tagsIndex = elasticlunr();
this.tagsIndex.addField('name');
this.tagsIndex.addField('url');
this.tagsIndex.setRef('id');
if (tags.tags.length > 0) {
if (tags || tags.length > 0) {
if (!tags.length) {
tags = [tags];
}
this.#updateTagsIndex(tags);
}
}

View file

@ -2,30 +2,26 @@ import SearchIndex from './search-index';
import nock from 'nock';
describe('search index', function () {
afterEach(function () {
localStorage.clear();
});
test('initializes search index', async () => {
const apiUrl = 'http://localhost/ghost/api/content';
const apiKey = 'secret_key';
const searchIndex = new SearchIndex({apiUrl, apiKey, storage: localStorage});
const siteURL = 'http://localhost';
const apiKey = '69010382388f9de5869ad6e558';
const searchIndex = new SearchIndex({siteURL, apiKey, storage: localStorage});
const scope = nock('http://localhost/ghost/api/content')
.get('/posts/?key=secret_key&limit=all&fields=id,slug,title,excerpt,url,updated_at,visibility&order=updated_at%20desc&formats=plaintext')
.get('/posts/?key=69010382388f9de5869ad6e558&limit=all&fields=id%2Cslug%2Ctitle%2Cexcerpt%2Curl%2Cupdated_at%2Cvisibility&order=updated_at%20DESC&formats=plaintext')
.reply(200, {
posts: []
})
.get('/authors/?key=secret_key&limit=all&fields=id,slug,name,url,profile_image')
.get('/authors/?key=69010382388f9de5869ad6e558&limit=all&fields=id,slug,name,url,profile_image')
.reply(200, {
authors: []
})
.get('/tags/?key=secret_key&&limit=all&fields=id,slug,name,url')
.get('/tags/?key=69010382388f9de5869ad6e558&&limit=all&fields=id,slug,name,url')
.reply(200, {
tags: []
});
await searchIndex.init({apiUrl, apiKey});
await searchIndex.init({siteURL, apiKey});
expect(scope.isDone()).toBeTruthy();
@ -37,12 +33,12 @@ describe('search index', function () {
});
test('allows to search for indexed posts and authors', async () => {
const apiUrl = 'http://localhost/ghost/api/content';
const apiKey = 'secret_key';
const searchIndex = new SearchIndex({apiUrl, apiKey, storage: localStorage});
const siteURL = 'http://localhost';
const apiKey = '69010382388f9de5869ad6e558';
const searchIndex = new SearchIndex({siteURL, apiKey, storage: localStorage});
nock('http://localhost/ghost/api/content')
.get('/posts/?key=secret_key&limit=all&fields=id,slug,title,excerpt,url,updated_at,visibility&order=updated_at%20desc&formats=plaintext')
.get('/posts/?key=69010382388f9de5869ad6e558&limit=all&fields=id%2Cslug%2Ctitle%2Cexcerpt%2Curl%2Cupdated_at%2Cvisibility&order=updated_at%20DESC&formats=plaintext')
.reply(200, {
posts: [{
id: 'sounique',
@ -51,7 +47,7 @@ describe('search index', function () {
url: 'http://localhost/ghost/awesome-barcelona-life/'
}]
})
.get('/authors/?key=secret_key&limit=all&fields=id,slug,name,url,profile_image')
.get('/authors/?key=69010382388f9de5869ad6e558&limit=all&fields=id,slug,name,url,profile_image')
.reply(200, {
authors: [{
id: 'different_uniq',
@ -67,7 +63,7 @@ describe('search index', function () {
url: 'http://localhost/ghost/authors/bob/'
}]
})
.get('/tags/?key=secret_key&&limit=all&fields=id,slug,name,url')
.get('/tags/?key=69010382388f9de5869ad6e558&&limit=all&fields=id,slug,name,url')
.reply(200, {
tags: [{
id: 'uniq_tag',
@ -77,7 +73,7 @@ describe('search index', function () {
}]
});
await searchIndex.init({apiUrl, apiKey});
await searchIndex.init({siteURL, apiKey});
let searchResults = searchIndex.search('Barcelona');
expect(searchResults.posts.length).toEqual(1);

View file

@ -1680,6 +1680,13 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
"@tryghost/content-api@^1.11.0":
version "1.11.0"
resolved "https://registry.yarnpkg.com/@tryghost/content-api/-/content-api-1.11.0.tgz#25ab0e2c5618f4ae190d5ad739611a07a551b245"
integrity sha512-0JTlp5Ln4BfCJzCYuT2X3MC9ZupIkRtzZaHpf9KZw7O8uOsRnO9RwjItN+lwvkoLIesMzfgrZd/tBJ4BAzeBrg==
dependencies:
axios "^0.27.0"
"@types/aria-query@^4.2.0":
version "4.2.2"
resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.2.tgz#ed4e0ad92306a704f9fb132a0cfcf77486dbe2bc"
@ -2583,6 +2590,14 @@ axe-core@^4.4.2:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.2.tgz#dcf7fb6dea866166c3eab33d68208afe4d5f670c"
integrity sha512-LVAaGp/wkkgYJcjmHsoKx4juT1aQvJyPcW09MLCjVTh3V2cc6PnyempiLMNH5iMdfIX/zdbjUx2KDjMLCTdPeA==
axios@^0.27.0:
version "0.27.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
dependencies:
follow-redirects "^1.14.9"
form-data "^4.0.0"
axobject-query@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
@ -5382,7 +5397,7 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
follow-redirects@^1.0.0:
follow-redirects@^1.0.0, follow-redirects@^1.14.9:
version "1.15.1"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==
@ -5414,6 +5429,15 @@ form-data@^3.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"
form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
forwarded@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"