0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-18 02:21:47 -05:00

Added more data to Articles

ref https://linear.app/tryghost/issue/MOM-128

We want to render more than just the content, so we need to bulk out the
Article objects with metadata like feature images etc...
This commit is contained in:
Fabien O'Carroll 2024-05-16 15:28:32 +07:00 committed by Fabien 'egg' O'Carroll
parent ea40c6ad65
commit c4091fc000
8 changed files with 92 additions and 12 deletions

View file

@ -1,2 +1,3 @@
declare module '@tryghost/errors';
declare module '@tryghost/domain-events';
declare module '@tryghost/html-to-plaintext';

View file

@ -2,6 +2,7 @@ import ObjectID from 'bson-objectid';
import {ActivityService} from './activity.service';
import {Actor} from './actor.entity';
import assert from 'assert';
import {URI} from './uri.object';
describe('ActivityService', function () {
describe('#createArticleForPost', function () {
@ -20,7 +21,12 @@ describe('ActivityService', function () {
title: 'Testing',
slug: 'testing',
html: '<p> Testing stuff.. </p>',
visibility: 'public'
visibility: 'public',
authors: ['Mr Bean'],
publishedAt: new Date(),
featuredImage: null,
excerpt: 'Small text',
url: new URI('blah')
};
}
};
@ -53,7 +59,12 @@ describe('ActivityService', function () {
title: 'Testing',
slug: 'testing',
html: '<p> Testing stuff.. </p>',
visibility: 'private'
visibility: 'private',
authors: ['Mr Bean'],
publishedAt: new Date(),
featuredImage: null,
excerpt: 'Small text',
url: new URI('blah')
};
}
};
@ -110,7 +121,12 @@ describe('ActivityService', function () {
title: 'Testing',
slug: 'testing',
html: '<p> Testing stuff.. </p>',
visibility: 'private'
visibility: 'private',
authors: ['Mr Bean'],
publishedAt: new Date(),
featuredImage: null,
excerpt: 'Small text',
url: new URI('blah')
};
}
};

View file

@ -36,7 +36,12 @@ describe('Actor', function () {
title: 'Post Title',
slug: 'post-slug',
html: '<p>Hello world</p>',
visibility: 'public'
visibility: 'public',
url: new URI(''),
authors: ['Mr Burns'],
featuredImage: null,
publishedAt: null,
excerpt: 'Hey'
});
actor.createArticle(article);

View file

@ -7,7 +7,11 @@ type ArticleData = {
id: ObjectID
name: string
content: string
url: URL
url: URI
image: URI | null
published: Date | null
attributedTo: {type: string, name: string}[]
preview: {type: string, content: string}
};
export class Article {
@ -30,8 +34,11 @@ export class Article {
id: id.href,
name: this.attr.name,
content: this.attr.content,
url: this.attr.url.href,
attributedTo: url.href
url: this.attr.url.getValue(url),
image: this.attr.image?.getValue(url),
published: this.attr.published?.toISOString(),
attributedTo: this.attr.attributedTo,
preview: this.attr.preview
};
}
@ -40,7 +47,17 @@ export class Article {
id: post.id,
name: post.title,
content: post.html,
url: new URL(`/posts/${post.slug}`, 'https://example.com')
url: post.url,
image: post.featuredImage,
published: post.publishedAt,
attributedTo: post.authors.map(name => ({
type: 'Person',
name
})),
preview: {
type: 'Note',
content: post.excerpt
}
});
}
}

View file

@ -1,4 +1,5 @@
import ObjectID from 'bson-objectid';
import {URI} from './uri.object';
export type Post = {
id: ObjectID;
@ -6,6 +7,11 @@ export type Post = {
slug: string;
html: string;
visibility: string;
featuredImage: URI | null;
url: URI;
publishedAt: Date | null;
authors: string[];
excerpt: string;
};
export interface PostRepository {

View file

@ -50,8 +50,11 @@ export namespace ActivityPub {
type: 'Article';
name: string;
content: string;
url: string;
attributedTo: string | object[];
url?: string;
attributedTo?: string | object[];
image?: string;
published?: string;
preview?: {type: string, content: string};
};
export type Link = string | {

View file

@ -1,6 +1,8 @@
import {Inject} from '@nestjs/common';
import ObjectID from 'bson-objectid';
import {PostRepository} from '../../core/activitypub/post.repository';
import {URI} from '../../core/activitypub/uri.object';
import htmlToPlaintext from '@tryghost/html-to-plaintext';
type UrlUtils = {
transformReadyToAbsolute(html: string): string
@ -18,15 +20,39 @@ export class KnexPostRepository implements PostRepository {
async getOneById(id: ObjectID) {
const row = await this.knex('posts').where('id', id.toHexString()).first();
const authorRows = await this.knex('users')
.leftJoin('posts_authors', 'users.id', 'posts_authors.author_id')
.where('posts_authors.post_id', id.toHexString())
.select('users.name');
if (!row) {
return null;
}
let excerpt = row.custom_excerpt;
if (!excerpt) {
const metaRow = await this.knex('posts_meta').where('post_id', id.toHexString()).select('meta_description').first();
if (metaRow?.meta_description) {
excerpt = metaRow.meta_description;
}
}
if (!excerpt) {
excerpt = htmlToPlaintext.excerpt(row.html);
}
return {
id,
title: row.title,
html: this.urlUtils.transformReadyToAbsolute(row.html),
slug: row.slug,
visibility: row.visibility
visibility: row.visibility,
featuredImage: row.feature_image ? new URI(row.feature_image) : null,
publishedAt: row.published_at ? new Date(row.published_at) : null,
authors: authorRows.map((authorRow: {name: string}) => authorRow.name),
excerpt,
url: new URI('') // TODO: Get URL for Post
};
}
};

View file

@ -14,6 +14,7 @@ import {TheWorld} from '../../../core/activitypub/tell-the-world.service';
import DomainEvents from '@tryghost/domain-events';
import {NestApplication} from '@nestjs/core';
import ObjectID from 'bson-objectid';
import {URI} from '../../../core/activitypub/uri.object';
describe('ActivityPubController', function () {
let app: NestApplication;
@ -58,7 +59,12 @@ describe('ActivityPubController', function () {
title: 'Testing',
slug: 'testing',
html: '<p> testing </p>',
visibility: 'public'
visibility: 'public',
authors: ['Mr Roach'],
url: new URI('roachie'),
publishedAt: new Date(),
featuredImage: null,
excerpt: 'testing...'
};
}
}