Merge pull request #276 from cloudflare/sven/timeline-tag

tag timeline
pull/279/head
Sven Sauleau 2023-02-13 16:00:26 +00:00 zatwierdzone przez GitHub
commit 2a3e4b43fc
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
3 zmienionych plików z 81 dodań i 2 usunięć

Wyświetl plik

@ -112,8 +112,14 @@ export async function getPublicTimeline(
domain: string,
db: D1Database,
localPreference: LocalPreference,
offset: number = 0
offset: number = 0,
hashtag?: string
): Promise<Array<MastodonStatus>> {
let hashtagFilter = ''
if (hashtag) {
hashtagFilter = 'AND note_hashtags.value=?3'
}
const QUERY = `
SELECT objects.*,
actors.id as actor_id,
@ -126,17 +132,24 @@ SELECT objects.*,
FROM outbox_objects
INNER JOIN objects ON objects.id=outbox_objects.object_id
INNER JOIN actors ON actors.id=outbox_objects.actor_id
LEFT JOIN note_hashtags ON objects.id=note_hashtags.object_id
WHERE objects.type='Note'
AND ${localPreferenceQuery(localPreference)}
AND json_extract(objects.properties, '$.inReplyTo') IS NULL
AND outbox_objects.target = '${PUBLIC_GROUP}'
${hashtagFilter}
GROUP BY objects.id
ORDER by outbox_objects.published_date DESC
LIMIT ?1 OFFSET ?2
`
const DEFAULT_LIMIT = 20
const { success, error, results } = await db.prepare(QUERY).bind(DEFAULT_LIMIT, offset).all()
let query = db.prepare(QUERY).bind(DEFAULT_LIMIT, offset)
if (hashtagFilter) {
query = db.prepare(QUERY).bind(DEFAULT_LIMIT, offset, hashtag)
}
const { success, error, results } = await query.all()
if (!success) {
throw new Error('SQL error: ' + error)
}

Wyświetl plik

@ -12,6 +12,7 @@ import * as timelines from 'wildebeest/backend/src/mastodon/timeline'
import { insertLike } from 'wildebeest/backend/src/mastodon/like'
import { insertReblog, createReblog } from 'wildebeest/backend/src/mastodon/reblog'
import { createStatus } from 'wildebeest/backend/src/mastodon/status'
import { insertHashtags } from 'wildebeest/backend/src/mastodon/hashtag'
const userKEK = 'test_kek6'
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
@ -294,5 +295,46 @@ describe('Mastodon APIs', () => {
assert.equal(data.length, 1)
assert.equal(data[0].content, 'a post')
})
test('timeline with non exitent tag', async () => {
const db = await makeDB()
const data = await timelines.getPublicTimeline(
domain,
db,
timelines.LocalPreference.NotSet,
0,
'non-existent-tag'
)
assert.equal(data.length, 0)
})
test('timeline tag', async () => {
const db = await makeDB()
const actor = await createPerson(domain, db, userKEK, 'sven@cloudflare.com')
{
const note = await createStatus(domain, db, actor, 'test 1')
await insertHashtags(db, note, ['test', 'a'])
}
await sleep(10)
{
const note = await createStatus(domain, db, actor, 'test 2')
await insertHashtags(db, note, ['test', 'b'])
}
{
const data = await timelines.getPublicTimeline(domain, db, timelines.LocalPreference.NotSet, 0, 'test')
assert.equal(data.length, 2)
assert.equal(data[0].content, 'test 2')
assert.equal(data[1].content, 'test 1')
}
{
const data = await timelines.getPublicTimeline(domain, db, timelines.LocalPreference.NotSet, 0, 'a')
assert.equal(data.length, 1)
assert.equal(data[0].content, 'test 1')
}
})
})
})

Wyświetl plik

@ -0,0 +1,24 @@
import type { Env } from 'wildebeest/backend/src/types/env'
import { cors } from 'wildebeest/backend/src/utils/cors'
import type { ContextData } from 'wildebeest/backend/src/types/context'
import * as timelines from 'wildebeest/backend/src/mastodon/timeline'
const headers = {
...cors(),
'content-type': 'application/json; charset=utf-8',
}
export const onRequest: PagesFunction<Env, any, ContextData> = async ({ request, env, params }) => {
const domain = new URL(request.url).hostname
return handleRequest(env.DATABASE, request, domain, params.tag as string)
}
export async function handleRequest(db: D1Database, request: Request, domain: string, tag: string): Promise<Response> {
const url = new URL(request.url)
if (url.searchParams.has('max_id')) {
return new Response(JSON.stringify([]), { headers })
}
const timeline = await timelines.getPublicTimeline(domain, db, timelines.LocalPreference.NotSet, 0, tag)
return new Response(JSON.stringify(timeline), { headers })
}