kopia lustrzana https://github.com/cloudflare/wildebeest
commit
2a3e4b43fc
|
@ -112,8 +112,14 @@ export async function getPublicTimeline(
|
||||||
domain: string,
|
domain: string,
|
||||||
db: D1Database,
|
db: D1Database,
|
||||||
localPreference: LocalPreference,
|
localPreference: LocalPreference,
|
||||||
offset: number = 0
|
offset: number = 0,
|
||||||
|
hashtag?: string
|
||||||
): Promise<Array<MastodonStatus>> {
|
): Promise<Array<MastodonStatus>> {
|
||||||
|
let hashtagFilter = ''
|
||||||
|
if (hashtag) {
|
||||||
|
hashtagFilter = 'AND note_hashtags.value=?3'
|
||||||
|
}
|
||||||
|
|
||||||
const QUERY = `
|
const QUERY = `
|
||||||
SELECT objects.*,
|
SELECT objects.*,
|
||||||
actors.id as actor_id,
|
actors.id as actor_id,
|
||||||
|
@ -126,17 +132,24 @@ SELECT objects.*,
|
||||||
FROM outbox_objects
|
FROM outbox_objects
|
||||||
INNER JOIN objects ON objects.id=outbox_objects.object_id
|
INNER JOIN objects ON objects.id=outbox_objects.object_id
|
||||||
INNER JOIN actors ON actors.id=outbox_objects.actor_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'
|
WHERE objects.type='Note'
|
||||||
AND ${localPreferenceQuery(localPreference)}
|
AND ${localPreferenceQuery(localPreference)}
|
||||||
AND json_extract(objects.properties, '$.inReplyTo') IS NULL
|
AND json_extract(objects.properties, '$.inReplyTo') IS NULL
|
||||||
AND outbox_objects.target = '${PUBLIC_GROUP}'
|
AND outbox_objects.target = '${PUBLIC_GROUP}'
|
||||||
|
${hashtagFilter}
|
||||||
GROUP BY objects.id
|
GROUP BY objects.id
|
||||||
ORDER by outbox_objects.published_date DESC
|
ORDER by outbox_objects.published_date DESC
|
||||||
LIMIT ?1 OFFSET ?2
|
LIMIT ?1 OFFSET ?2
|
||||||
`
|
`
|
||||||
const DEFAULT_LIMIT = 20
|
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) {
|
if (!success) {
|
||||||
throw new Error('SQL error: ' + error)
|
throw new Error('SQL error: ' + error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import * as timelines from 'wildebeest/backend/src/mastodon/timeline'
|
||||||
import { insertLike } from 'wildebeest/backend/src/mastodon/like'
|
import { insertLike } from 'wildebeest/backend/src/mastodon/like'
|
||||||
import { insertReblog, createReblog } from 'wildebeest/backend/src/mastodon/reblog'
|
import { insertReblog, createReblog } from 'wildebeest/backend/src/mastodon/reblog'
|
||||||
import { createStatus } from 'wildebeest/backend/src/mastodon/status'
|
import { createStatus } from 'wildebeest/backend/src/mastodon/status'
|
||||||
|
import { insertHashtags } from 'wildebeest/backend/src/mastodon/hashtag'
|
||||||
|
|
||||||
const userKEK = 'test_kek6'
|
const userKEK = 'test_kek6'
|
||||||
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
|
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.length, 1)
|
||||||
assert.equal(data[0].content, 'a post')
|
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')
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -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 })
|
||||||
|
}
|
Ładowanie…
Reference in New Issue