mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-25 02:31:59 -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:
parent
ea40c6ad65
commit
c4091fc000
8 changed files with 92 additions and 12 deletions
|
@ -1,2 +1,3 @@
|
||||||
declare module '@tryghost/errors';
|
declare module '@tryghost/errors';
|
||||||
declare module '@tryghost/domain-events';
|
declare module '@tryghost/domain-events';
|
||||||
|
declare module '@tryghost/html-to-plaintext';
|
||||||
|
|
|
@ -2,6 +2,7 @@ import ObjectID from 'bson-objectid';
|
||||||
import {ActivityService} from './activity.service';
|
import {ActivityService} from './activity.service';
|
||||||
import {Actor} from './actor.entity';
|
import {Actor} from './actor.entity';
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
|
import {URI} from './uri.object';
|
||||||
|
|
||||||
describe('ActivityService', function () {
|
describe('ActivityService', function () {
|
||||||
describe('#createArticleForPost', function () {
|
describe('#createArticleForPost', function () {
|
||||||
|
@ -20,7 +21,12 @@ describe('ActivityService', function () {
|
||||||
title: 'Testing',
|
title: 'Testing',
|
||||||
slug: 'testing',
|
slug: 'testing',
|
||||||
html: '<p> Testing stuff.. </p>',
|
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',
|
title: 'Testing',
|
||||||
slug: 'testing',
|
slug: 'testing',
|
||||||
html: '<p> Testing stuff.. </p>',
|
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',
|
title: 'Testing',
|
||||||
slug: 'testing',
|
slug: 'testing',
|
||||||
html: '<p> Testing stuff.. </p>',
|
html: '<p> Testing stuff.. </p>',
|
||||||
visibility: 'private'
|
visibility: 'private',
|
||||||
|
authors: ['Mr Bean'],
|
||||||
|
publishedAt: new Date(),
|
||||||
|
featuredImage: null,
|
||||||
|
excerpt: 'Small text',
|
||||||
|
url: new URI('blah')
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -36,7 +36,12 @@ describe('Actor', function () {
|
||||||
title: 'Post Title',
|
title: 'Post Title',
|
||||||
slug: 'post-slug',
|
slug: 'post-slug',
|
||||||
html: '<p>Hello world</p>',
|
html: '<p>Hello world</p>',
|
||||||
visibility: 'public'
|
visibility: 'public',
|
||||||
|
url: new URI(''),
|
||||||
|
authors: ['Mr Burns'],
|
||||||
|
featuredImage: null,
|
||||||
|
publishedAt: null,
|
||||||
|
excerpt: 'Hey'
|
||||||
});
|
});
|
||||||
|
|
||||||
actor.createArticle(article);
|
actor.createArticle(article);
|
||||||
|
|
|
@ -7,7 +7,11 @@ type ArticleData = {
|
||||||
id: ObjectID
|
id: ObjectID
|
||||||
name: string
|
name: string
|
||||||
content: 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 {
|
export class Article {
|
||||||
|
@ -30,8 +34,11 @@ export class Article {
|
||||||
id: id.href,
|
id: id.href,
|
||||||
name: this.attr.name,
|
name: this.attr.name,
|
||||||
content: this.attr.content,
|
content: this.attr.content,
|
||||||
url: this.attr.url.href,
|
url: this.attr.url.getValue(url),
|
||||||
attributedTo: url.href
|
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,
|
id: post.id,
|
||||||
name: post.title,
|
name: post.title,
|
||||||
content: post.html,
|
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
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import ObjectID from 'bson-objectid';
|
import ObjectID from 'bson-objectid';
|
||||||
|
import {URI} from './uri.object';
|
||||||
|
|
||||||
export type Post = {
|
export type Post = {
|
||||||
id: ObjectID;
|
id: ObjectID;
|
||||||
|
@ -6,6 +7,11 @@ export type Post = {
|
||||||
slug: string;
|
slug: string;
|
||||||
html: string;
|
html: string;
|
||||||
visibility: string;
|
visibility: string;
|
||||||
|
featuredImage: URI | null;
|
||||||
|
url: URI;
|
||||||
|
publishedAt: Date | null;
|
||||||
|
authors: string[];
|
||||||
|
excerpt: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface PostRepository {
|
export interface PostRepository {
|
||||||
|
|
|
@ -50,8 +50,11 @@ export namespace ActivityPub {
|
||||||
type: 'Article';
|
type: 'Article';
|
||||||
name: string;
|
name: string;
|
||||||
content: string;
|
content: string;
|
||||||
url: string;
|
url?: string;
|
||||||
attributedTo: string | object[];
|
attributedTo?: string | object[];
|
||||||
|
image?: string;
|
||||||
|
published?: string;
|
||||||
|
preview?: {type: string, content: string};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Link = string | {
|
export type Link = string | {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import {Inject} from '@nestjs/common';
|
import {Inject} from '@nestjs/common';
|
||||||
import ObjectID from 'bson-objectid';
|
import ObjectID from 'bson-objectid';
|
||||||
import {PostRepository} from '../../core/activitypub/post.repository';
|
import {PostRepository} from '../../core/activitypub/post.repository';
|
||||||
|
import {URI} from '../../core/activitypub/uri.object';
|
||||||
|
import htmlToPlaintext from '@tryghost/html-to-plaintext';
|
||||||
|
|
||||||
type UrlUtils = {
|
type UrlUtils = {
|
||||||
transformReadyToAbsolute(html: string): string
|
transformReadyToAbsolute(html: string): string
|
||||||
|
@ -18,15 +20,39 @@ export class KnexPostRepository implements PostRepository {
|
||||||
|
|
||||||
async getOneById(id: ObjectID) {
|
async getOneById(id: ObjectID) {
|
||||||
const row = await this.knex('posts').where('id', id.toHexString()).first();
|
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) {
|
if (!row) {
|
||||||
return null;
|
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 {
|
return {
|
||||||
id,
|
id,
|
||||||
title: row.title,
|
title: row.title,
|
||||||
html: this.urlUtils.transformReadyToAbsolute(row.html),
|
html: this.urlUtils.transformReadyToAbsolute(row.html),
|
||||||
slug: row.slug,
|
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
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {TheWorld} from '../../../core/activitypub/tell-the-world.service';
|
||||||
import DomainEvents from '@tryghost/domain-events';
|
import DomainEvents from '@tryghost/domain-events';
|
||||||
import {NestApplication} from '@nestjs/core';
|
import {NestApplication} from '@nestjs/core';
|
||||||
import ObjectID from 'bson-objectid';
|
import ObjectID from 'bson-objectid';
|
||||||
|
import {URI} from '../../../core/activitypub/uri.object';
|
||||||
|
|
||||||
describe('ActivityPubController', function () {
|
describe('ActivityPubController', function () {
|
||||||
let app: NestApplication;
|
let app: NestApplication;
|
||||||
|
@ -58,7 +59,12 @@ describe('ActivityPubController', function () {
|
||||||
title: 'Testing',
|
title: 'Testing',
|
||||||
slug: 'testing',
|
slug: 'testing',
|
||||||
html: '<p> testing </p>',
|
html: '<p> testing </p>',
|
||||||
visibility: 'public'
|
visibility: 'public',
|
||||||
|
authors: ['Mr Roach'],
|
||||||
|
url: new URI('roachie'),
|
||||||
|
publishedAt: new Date(),
|
||||||
|
featuredImage: null,
|
||||||
|
excerpt: 'testing...'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue