diff --git a/backend/test/mastodon/statuses.spec.ts b/backend/test/mastodon/statuses.spec.ts index fa6fe73..4d3ab26 100644 --- a/backend/test/mastodon/statuses.spec.ts +++ b/backend/test/mastodon/statuses.spec.ts @@ -20,6 +20,9 @@ import { MessageType } from 'wildebeest/backend/src/types/queue' const userKEK = 'test_kek4' const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)) const domain = 'cloudflare.com' +const kv_cache: any = { + async put() {}, +} describe('Mastodon APIs', () => { describe('statuses', () => { @@ -35,7 +38,7 @@ describe('Mastodon APIs', () => { }) const connectedActor: any = {} - const res = await statuses.handleRequest(req, db, connectedActor, userKEK, queue) + const res = await statuses.handleRequest(req, db, connectedActor, userKEK, queue, kv_cache) assert.equal(res.status, 400) }) @@ -55,7 +58,7 @@ describe('Mastodon APIs', () => { }) const connectedActor = actor - const res = await statuses.handleRequest(req, db, connectedActor, userKEK, queue) + const res = await statuses.handleRequest(req, db, connectedActor, userKEK, queue, kv_cache) assert.equal(res.status, 200) assertJSON(res) @@ -89,6 +92,41 @@ describe('Mastodon APIs', () => { assert.equal(row.original_object_id, null) }) + test('create new status regenerates the timeline and contains post', async () => { + const db = await makeDB() + const queue = makeQueue() + const actor = await createPerson(domain, db, userKEK, 'sven@cloudflare.com') + + let cache = null + const kv_cache: any = { + async put(key: string, value: any) { + assert.equal(key, actor.id + '/timeline/home') + cache = value + }, + } + + const body = { + status: 'my status', + visibility: 'public', + } + const req = new Request('https://example.com', { + method: 'POST', + headers: { 'content-type': 'application/json' }, + body: JSON.stringify(body), + }) + + const res = await statuses.handleRequest(req, db, actor, userKEK, queue, kv_cache) + assert.equal(res.status, 200) + assertJSON(res) + + const data = await res.json() + + assert(cache) + const timeline = JSON.parse(cache) + assert.equal(timeline.length, 1) + assert.equal(timeline[0].id, data.id) + }) + test("create new status adds to Actor's outbox", async () => { const db = await makeDB() const queue = makeQueue() @@ -105,7 +143,7 @@ describe('Mastodon APIs', () => { }) const connectedActor = actor - const res = await statuses.handleRequest(req, db, connectedActor, userKEK, queue) + const res = await statuses.handleRequest(req, db, connectedActor, userKEK, queue, kv_cache) assert.equal(res.status, 200) const row = await db.prepare(`SELECT count(*) as count FROM outbox_objects`).first() @@ -133,7 +171,7 @@ describe('Mastodon APIs', () => { body: JSON.stringify(body), }) - const res = await statuses.handleRequest(req, db, actor, userKEK, queue) + const res = await statuses.handleRequest(req, db, actor, userKEK, queue, kv_cache) assert.equal(res.status, 200) assert.equal(queue.messages.length, 2) @@ -212,7 +250,7 @@ describe('Mastodon APIs', () => { }) const connectedActor = actor - const res = await statuses.handleRequest(req, db, connectedActor, userKEK, queue) + const res = await statuses.handleRequest(req, db, connectedActor, userKEK, queue, kv_cache) assert.equal(res.status, 200) assert(deliveredNote) @@ -229,7 +267,7 @@ describe('Mastodon APIs', () => { const queue = makeQueue() const connectedActor = await createPerson(domain, db, userKEK, 'sven@cloudflare.com') - const properties = { url: 'foo' } + const properties = { url: 'https://example.com/image.jpg' } const image = await createImage(domain, db, connectedActor, properties) const body = { @@ -243,7 +281,7 @@ describe('Mastodon APIs', () => { body: JSON.stringify(body), }) - const res = await statuses.handleRequest(req, db, connectedActor, userKEK, queue) + const res = await statuses.handleRequest(req, db, connectedActor, userKEK, queue, kv_cache) assert.equal(res.status, 200) const data = await res.json() diff --git a/frontend/mock-db/init.ts b/frontend/mock-db/init.ts index 31f952f..66d53f1 100644 --- a/frontend/mock-db/init.ts +++ b/frontend/mock-db/init.ts @@ -9,6 +9,9 @@ const queue = { async send() {}, async sendBatch() {}, } +const kv_cache: any = { + async put() {}, +} /** * Run helper commands to initialize the database with actors, statuses, etc. */ @@ -43,7 +46,7 @@ async function createStatus(db: D1Database, actor: Person, status: string, visib headers, body: JSON.stringify(body), }) - const resp = await statusesAPI.handleRequest(req, db, actor, kek, queue) + const resp = await statusesAPI.handleRequest(req, db, actor, kek, queue, kv_cache) return (await resp.json()) as MastodonStatus } diff --git a/functions/api/v1/statuses.ts b/functions/api/v1/statuses.ts index 92c6983..02d3943 100644 --- a/functions/api/v1/statuses.ts +++ b/functions/api/v1/statuses.ts @@ -1,4 +1,5 @@ // https://docs.joinmastodon.org/methods/statuses/#create +import * as timeline from 'wildebeest/backend/src/mastodon/timeline' import type { Queue, DeliverMessageBody } from 'wildebeest/backend/src/types/queue' import { loadLocalMastodonAccount } from 'wildebeest/backend/src/mastodon/account' import { createPublicNote } from 'wildebeest/backend/src/activitypub/objects/note' @@ -23,7 +24,7 @@ type StatusCreate = { } export const onRequest: PagesFunction = async ({ request, env, data }) => { - return handleRequest(request, env.DATABASE, data.connectedActor, env.userKEK, env.QUEUE) + return handleRequest(request, env.DATABASE, data.connectedActor, env.userKEK, env.QUEUE, env.KV_CACHE) } // FIXME: add tests for delivery to followers and mentions to a specific Actor. @@ -32,7 +33,8 @@ export async function handleRequest( db: D1Database, connectedActor: Person, userKEK: string, - queue: Queue + queue: Queue, + cache: KVNamespace ): Promise { // TODO: implement Idempotency-Key @@ -89,6 +91,8 @@ export async function handleRequest( } } + await timeline.pregenerateTimelines(domain, db, cache, connectedActor) + const account = await loadLocalMastodonAccount(db, connectedActor) const res: any = {