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

Fixed reconstruction of Activity from JSONLD

The use of Article and Actor in Activity meant that we got way more data in the
JSONLD representation, but it wasn't be picked up when reconstructing from data
over the wire. This makes sure that we can recreate the object from the JSONLD.
This commit is contained in:
Fabien O'Carroll 2024-05-16 16:30:01 +07:00 committed by Fabien 'egg' O'Carroll
parent 17fe2395bd
commit a70afcd117
7 changed files with 80 additions and 22 deletions

View file

@ -1,6 +1,9 @@
import assert from 'assert';
import {Activity} from './activity.entity';
import {URI} from './uri.object';
import {Article} from './article.object';
import ObjectID from 'bson-objectid';
import {Actor} from './actor.entity';
describe('Activity', function () {
describe('fromJSONLD', function () {
@ -51,5 +54,36 @@ describe('Activity', function () {
});
}
});
it('Can correctly reconstruct', function () {
const actor = Actor.create({username: 'testing'});
const article = Article.fromPost({
id: new ObjectID(),
title: 'My Title',
slug: 'my-title',
html: '<p> big boi contents </p>',
excerpt: 'lil contents',
authors: ['Jeremy Paxman'],
url: new URI('blah'),
publishedAt: new Date(),
featuredImage: null,
visibility: 'public'
});
const activity = new Activity({
type: 'Create',
activity: null,
actor: actor,
object: article,
to: new URI('bloo')
});
const baseUrl = new URL('https://ghost.org');
const input = activity.getJSONLD(baseUrl);
const created = Activity.fromJSONLD(input);
assert.deepEqual(created.getJSONLD(baseUrl), input);
});
});
});

View file

@ -7,7 +7,12 @@ import {URI} from './uri.object';
type ActivityData = {
activity: URI | null;
type: ActivityPub.ActivityType;
actor: Actor | URI;
actor: {
id: URI;
type: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[x: string]: any;
} | Actor;
object: {
id: URI;
type: string;
@ -58,18 +63,14 @@ export class Activity extends Entity<ActivityData> {
if (this.attr.actor instanceof Actor) {
return this.attr.actor.getJSONLD(url);
}
return {
type: 'Person',
id: this.attr.actor.getValue(url),
preferredUsername: 'index'
};
return this.attr.actor;
}
get actorId() {
if (this.attr.actor instanceof Actor) {
return this.attr.actor.actorId;
}
return this.attr.actor;
return this.attr.actor.id;
}
get objectId() {
@ -90,7 +91,10 @@ export class Activity extends Entity<ActivityData> {
'@context': 'https://www.w3.org/ns/activitystreams',
id: this.activityId?.getValue(url) || null,
type: this.attr.type,
actor: actor,
actor: {
...actor,
id: this.actorId.getValue(url)
},
object: {
...object,
id: this.objectId.getValue(url)
@ -105,12 +109,17 @@ export class Activity extends Entity<ActivityData> {
throw new Error(`Unknown type ${parsed.type}`);
}
return new Activity({
activity: 'id' in json ? getURI(json.id) : null,
activity: 'id' in json && typeof json.id === 'string' ? getURI(json.id) : null,
type: parsed.type as ActivityPub.ActivityType,
actor: getURI(parsed.actor),
actor: {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
...(parsed.actor as any),
id: getURI(parsed.actor)
},
object: {
id: getURI(parsed.object),
type: 'Unknown'
// eslint-disable-next-line @typescript-eslint/no-explicit-any
...(parsed.object as any),
id: getURI(parsed.object)
},
to: 'to' in json ? getURI(json.to) : null
});

View file

@ -144,7 +144,10 @@ describe('Actor', function () {
const followActivity = new Activity({
activity: new URI(`https://activitypub.server/activity`),
type: 'Follow',
actor: newFollower,
actor: {
id: newFollower,
type: 'Person'
},
object: {
id: actor.actorId,
type: 'Person'
@ -165,7 +168,10 @@ describe('Actor', function () {
const followActivity = new Activity({
activity: null,
type: 'Follow',
actor: newFollower,
actor: {
id: newFollower,
type: 'Person'
},
object: {
id: actor.actorId,
type: 'Person'
@ -191,7 +197,10 @@ describe('Actor', function () {
const activity = new Activity({
activity: null,
type: 'Accept',
actor: newFollower,
actor: {
id: newFollower,
type: 'Person'
},
object: {
id: newFollower,
type: 'Person'

View file

@ -109,7 +109,7 @@ export class Actor extends Entity<ActorData> {
const activity = new Activity({
activity: new URI(`activity/${(new ObjectID).toHexString()}`),
type: 'Follow',
actor: this.actorId,
actor: this,
object: {
...actor,
type: 'Person'
@ -128,7 +128,7 @@ export class Actor extends Entity<ActorData> {
activity: new URI(`activity/${(new ObjectID).toHexString()}`),
type: 'Accept',
to: activity.actorId,
actor: this.actorId,
actor: this,
object: {
id: activity.activityId,
type: 'Follow'

View file

@ -30,7 +30,10 @@ describe('InboxService', function () {
type: 'Application',
id: new URI('https://whatever.com')
},
actor: new URI('https://blak.com'),
actor: {
type: 'Person',
id: new URI('https://blak.com')
},
to: new URI('https://whatever.com')
});
@ -63,7 +66,10 @@ describe('InboxService', function () {
type: 'Person',
id: new URI('https://whatever.com')
},
actor: new URI('https://blak.com'),
actor: {
type: 'Person',
id: new URI('https://blak.com')
},
to: new URI('https://whatever.com')
});

View file

@ -25,7 +25,7 @@ describe('TheWorld', function () {
const activity = new Activity({
type: 'Follow',
activity: null,
actor: actor.actorId,
actor: actor,
object: {
type: 'Person',
id: toFollow
@ -61,7 +61,7 @@ describe('TheWorld', function () {
const activity = new Activity({
type: 'Create',
activity: null,
actor: actor.actorId,
actor: actor,
object: {
id: new URI('https://main.ghost.org/hello-world'),
type: 'Note',

View file

@ -28,7 +28,7 @@ describe('ActivityListener', function () {
const activity = new Activity({
type: 'Follow',
activity: null,
actor: actor.actorId,
actor: actor,
object: {
type: 'Person',
id: toFollow