mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-28 21:33:24 +03:00
Used proper ActivityPub Collection for Followers/Following
ref https://linear.app/tryghost/issue/MOM-126 We want to return proper ActivityPub JSONLD rather than a plain array! That was just a stop-gap to get us moving.
This commit is contained in:
parent
27b8bad664
commit
603891645d
@ -58,58 +58,4 @@ describe('ActivityPubService', function () {
|
||||
assert(mockActorRepository.save.calledWith(actor));
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getFollowing', function () {
|
||||
it('Throws if the default actor is not found', async function () {
|
||||
const mockWebFingerService: WebFingerService = {
|
||||
finger: Sinon.stub().resolves({
|
||||
id: 'https://example.com/user-to-follow'
|
||||
})
|
||||
} as unknown as WebFingerService;
|
||||
const mockActorRepository = {
|
||||
getOne: Sinon.stub().resolves(null),
|
||||
save: Sinon.stub().resolves()
|
||||
};
|
||||
|
||||
const service = new ActivityPubService(
|
||||
mockWebFingerService,
|
||||
mockActorRepository
|
||||
);
|
||||
|
||||
await assert.rejects(async () => {
|
||||
await service.getFollowing();
|
||||
}, /Could not find default actor/);
|
||||
});
|
||||
|
||||
it('Returns a list of the default actors following', async function () {
|
||||
const mockWebFingerService: WebFingerService = {
|
||||
finger: Sinon.stub().resolves({
|
||||
id: 'https://example.com/user-to-follow'
|
||||
})
|
||||
} as unknown as WebFingerService;
|
||||
const actor = Actor.create({
|
||||
username: 'testing',
|
||||
following: [{
|
||||
id: new URI('https://site.com/user'),
|
||||
username: '@person@site.com'
|
||||
}]
|
||||
});
|
||||
const mockActorRepository = {
|
||||
getOne: Sinon.stub().resolves(actor),
|
||||
save: Sinon.stub().resolves()
|
||||
};
|
||||
|
||||
const service = new ActivityPubService(
|
||||
mockWebFingerService,
|
||||
mockActorRepository
|
||||
);
|
||||
|
||||
const result = await service.getFollowing();
|
||||
|
||||
assert.deepEqual(result, [{
|
||||
id: 'https://site.com/user',
|
||||
username: '@person@site.com'
|
||||
}]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -26,19 +26,4 @@ export class ActivityPubService {
|
||||
|
||||
await this.actors.save(actor);
|
||||
}
|
||||
|
||||
async getFollowing(): Promise<{id: string, username?: string}[]> {
|
||||
const actor = await this.actors.getOne('index');
|
||||
|
||||
if (!actor) {
|
||||
throw new Error('Could not find default actor');
|
||||
}
|
||||
|
||||
return actor.following.map((x) => {
|
||||
return {
|
||||
id: x.id.href,
|
||||
username: x.username
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,35 @@ export class JSONLDService {
|
||||
return actor?.getJSONLD(this.url);
|
||||
}
|
||||
|
||||
async getFollowing(owner: ObjectID) {
|
||||
const actor = await this.repository.getOne(owner);
|
||||
if (!actor) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: actor.followingCollectionId.getValue(this.url),
|
||||
summary: `Following collection for ${actor.username}`,
|
||||
type: 'Collection',
|
||||
totalItems: actor.following.length,
|
||||
items: actor.following.map(item => ({id: item.id.getValue(this.url), username: item.username}))
|
||||
};
|
||||
}
|
||||
|
||||
async getFollowers(owner: ObjectID) {
|
||||
const actor = await this.repository.getOne(owner);
|
||||
if (!actor) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: actor.followersCollectionId.getValue(this.url),
|
||||
summary: `Followers collection for ${actor.username}`,
|
||||
type: 'Collection',
|
||||
totalItems: actor.followers.length,
|
||||
items: actor.followers.map(item => item.id.getValue(this.url))
|
||||
};
|
||||
}
|
||||
async getOutbox(owner: ObjectID) {
|
||||
const actor = await this.repository.getOne(owner);
|
||||
if (!actor) {
|
||||
|
@ -17,20 +17,4 @@ describe('ActivityPubController', function () {
|
||||
assert((mockActivityPubService.follow as Sinon.SinonStub).calledWith('@egg@ghost.org'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getFollowing', function () {
|
||||
it('Calls getFollowing on the ActivityPubService and returns the result', async function () {
|
||||
const mockActivityPubService = {
|
||||
follow: Sinon.stub().resolves(),
|
||||
getFollowing: Sinon.stub().resolves([])
|
||||
} as unknown as ActivityPubService;
|
||||
const controller = new ActivityPubController(mockActivityPubService);
|
||||
|
||||
const result = await controller.getFollowing();
|
||||
|
||||
assert((mockActivityPubService.getFollowing as Sinon.SinonStub).called);
|
||||
const returnValue = await (mockActivityPubService.getFollowing as Sinon.SinonStub).returnValues[0];
|
||||
assert.equal(result, returnValue);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,6 +1,5 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Param,
|
||||
Post,
|
||||
UseGuards,
|
||||
@ -26,14 +25,4 @@ export class ActivityPubController {
|
||||
await this.activitypub.follow(username);
|
||||
return {};
|
||||
}
|
||||
|
||||
@Roles([
|
||||
'Owner'
|
||||
])
|
||||
@Get('following')
|
||||
async getFollowing(): Promise<{id: string, username?: string;}[]> {
|
||||
const followers = await this.activitypub.getFollowing();
|
||||
|
||||
return followers;
|
||||
}
|
||||
}
|
||||
|
@ -99,6 +99,12 @@ describe('ActivityPubController', function () {
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
it('Can handle requests to get the followers', async function () {
|
||||
await request(app.getHttpServer())
|
||||
.get('/activitypub/followers/deadbeefdeadbeefdeadbeef')
|
||||
.expect(200);
|
||||
});
|
||||
|
||||
it('Can handle requests to get an article', async function () {
|
||||
await request(app.getHttpServer())
|
||||
.get('/activitypub/article/deadbeefdeadbeefdeadbeef')
|
||||
|
@ -5,14 +5,12 @@ import {JSONLDService} from '../../../core/activitypub/jsonld.service';
|
||||
import {HTTPSignature} from '../../../core/activitypub/http-signature.service';
|
||||
import {InboxService} from '../../../core/activitypub/inbox.service';
|
||||
import {Activity} from '../../../core/activitypub/activity.entity';
|
||||
import {ActivityPubService} from '../../../core/activitypub/activitypub.service';
|
||||
|
||||
@Controller('activitypub')
|
||||
export class ActivityPubController {
|
||||
constructor(
|
||||
private readonly service: JSONLDService,
|
||||
private readonly inboxService: InboxService,
|
||||
private readonly activitypub: ActivityPubService
|
||||
private readonly inboxService: InboxService
|
||||
) {}
|
||||
|
||||
@Header('Cache-Control', 'no-store')
|
||||
@ -72,7 +70,18 @@ export class ActivityPubController {
|
||||
if (typeof owner !== 'string') {
|
||||
throw new Error('Bad Request');
|
||||
}
|
||||
return this.activitypub.getFollowing();
|
||||
return this.service.getFollowing(ObjectID.createFromHexString(owner));
|
||||
}
|
||||
|
||||
@Header('Cache-Control', 'no-store')
|
||||
@Header('Content-Type', 'application/activity+json')
|
||||
@Roles(['Anon'])
|
||||
@Get('followers/:owner')
|
||||
async getFollowers(@Param('owner') owner: unknown) {
|
||||
if (typeof owner !== 'string') {
|
||||
throw new Error('Bad Request');
|
||||
}
|
||||
return this.service.getFollowers(ObjectID.createFromHexString(owner));
|
||||
}
|
||||
|
||||
@Header('Cache-Control', 'no-store')
|
||||
|
Loading…
Reference in New Issue
Block a user