Skip to content

Commit

Permalink
Added reverse-chronological ordering to outbox items (#34)
Browse files Browse the repository at this point in the history
refs [AP-371](https://linear.app/tryghost/issue/AP-371/outbox-item-ordering-is-not-in-reverse-chronological-order)

Added reverse-chronological ordering to outbox items by reversing the order of
the items in the outbox before dispatching them. This could be improved by
comparing the `published` property on the object associated with the outbox
item, but for now this is good enough.
  • Loading branch information
mike182uk authored Aug 30, 2024
1 parent 188a1d7 commit c8dc4ca
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 30 deletions.
14 changes: 0 additions & 14 deletions features/outbox.feature

This file was deleted.

14 changes: 0 additions & 14 deletions features/step_definitions/stepdefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -360,17 +360,3 @@ Then('{string} is in our Followers once only', async function (actorName) {

assert.equal(found.length, 1);
});

When('the contents of the outbox is requested', async function () {
const response = await fetch('http://activitypub-testing:8083/.ghost/activitypub/outbox/index', {
headers: {
'Content-Type': 'application/ld+json'
},
});

this.response = await response.json();
});

Then('the outbox contains {int} activity', function (count) {
assert.equal(this.response.totalItems, count);
});
2 changes: 1 addition & 1 deletion src/dispatchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ export async function outboxDispatcher(
}
}
return {
items,
items: items.reverse(),
};
}

Expand Down
75 changes: 74 additions & 1 deletion src/dispatchers.unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import assert from 'assert';
import sinon from 'sinon';
import {
actorDispatcher,
keypairDispatcher,
Expand All @@ -18,7 +19,7 @@ import {
acceptDispatcher,
createDispatcher,
} from './dispatchers';
import { RequestContext } from '@fedify/fedify';
import { Activity, RequestContext } from '@fedify/fedify';
import { ACTOR_DEFAULT_HANDLE } from './constants';

describe('dispatchers', function () {
Expand All @@ -35,4 +36,76 @@ describe('dispatchers', function () {
});
describe('keypairDispatcher', function () {});
describe('handleFollow', function () {});

describe('outboxDispatcher', function () {
const outboxActivities: Record<string, any> = {
'https://example.com/create/123': {
'@context': [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/data-integrity/v1',
],
id: 'https://example.com/create/123',
type: 'Create',
},
'https://example.com/announce/456': {
'@context': [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/data-integrity/v1',
],
type: 'Announce',
id: 'https://example.com/announce/456',
},
'https://example.com/accept/789': {
'@context': [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/data-integrity/v1',
],
type: 'Accept',
id: 'https://example.com/accept/789',
},
'https://example.com/like/987': {
'@context': [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/data-integrity/v1',
],
type: 'Like',
id: 'https://example.com/like/987',
},
};

const ctx = {
data: {
db: {
get: sinon.stub(),
},
globaldb: {
get: sinon.stub(),
},
},
} as RequestContext<any>;

beforeEach(function () {
ctx.data.db.get.withArgs(['outbox']).resolves(Object.keys(outboxActivities));

Object.keys(outboxActivities).forEach(key => {
ctx.data.globaldb.get.withArgs([key]).resolves(outboxActivities[key]);
});
});

it('returns relevant items from the outbox in the correct order', async function () {
const result = await outboxDispatcher(ctx, ACTOR_DEFAULT_HANDLE);

// Check items exist
assert.ok(result.items);

// Check correct items are returned in the correct order
assert.equal(result.items.length, 2);
assert.equal(result.items[0] instanceof Activity, true);
assert.equal(result.items[1] instanceof Activity, true);
// @ts-ignore: We know that this is the correct type because of the above assertions
assert.equal(result.items[0].id.toString(), 'https://example.com/announce/456');
// @ts-ignore: We know that this is the correct type because of the above assertions
assert.equal(result.items[1].id.toString(), 'https://example.com/create/123');
});
});
});

0 comments on commit c8dc4ca

Please sign in to comment.