kopia lustrzana https://github.com/cloudflare/wildebeest
implement media update
rodzic
c6ecc0624e
commit
b01148c9b2
|
@ -4,7 +4,9 @@ import type { Actor } from 'wildebeest/backend/src/activitypub/actors'
|
|||
export const IMAGE = 'Image'
|
||||
|
||||
// https://www.w3.org/TR/activitystreams-vocabulary/#dfn-image
|
||||
export interface Image extends objects.Document {}
|
||||
export interface Image extends objects.Document {
|
||||
description?: string
|
||||
}
|
||||
|
||||
export async function createImage(domain: string, db: D1Database, actor: Actor, properties: any): Promise<Image> {
|
||||
const actorId = new URL(actor.id)
|
||||
|
|
|
@ -156,6 +156,16 @@ export async function updateObject(db: D1Database, properties: any, id: URL): Pr
|
|||
return true
|
||||
}
|
||||
|
||||
export async function updateObjectProperty(db: D1Database, obj: APObject, key: string, value: string) {
|
||||
const { success, error } = await db
|
||||
.prepare(`UPDATE objects SET properties=json_set(properties, '$.${key}', ?) WHERE id=?`)
|
||||
.bind(value, obj.id.toString())
|
||||
.run()
|
||||
if (!success) {
|
||||
throw new Error('SQL error: ' + error)
|
||||
}
|
||||
}
|
||||
|
||||
export async function getObjectById(db: D1Database, id: string | URL): Promise<APObject | null> {
|
||||
return getObjectBy(db, 'id', id.toString())
|
||||
}
|
||||
|
|
|
@ -42,6 +42,10 @@ export function statusNotFound(id: string): Response {
|
|||
return generateErrorResponse('Resource not found', 404, `Status "${id}" not found`)
|
||||
}
|
||||
|
||||
export function mediaNotFound(id: string): Response {
|
||||
return generateErrorResponse('Resource not found', 404, `Media "${id}" not found`)
|
||||
}
|
||||
|
||||
export function exceededLimit(detail: string): Response {
|
||||
return generateErrorResponse('Limit exceeded', 400, detail)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import * as media from 'wildebeest/functions/api/v2/media'
|
||||
import { createImage } from 'wildebeest/backend/src/activitypub/objects/image'
|
||||
import * as media_id from 'wildebeest/functions/api/v2/media/[id]'
|
||||
import { createPerson } from 'wildebeest/backend/src/activitypub/actors'
|
||||
import { strict as assert } from 'node:assert/strict'
|
||||
import { makeDB, assertJSON, isUrlValid } from '../utils'
|
||||
|
@ -56,5 +58,32 @@ describe('Mastodon APIs', () => {
|
|||
assert.equal(obj.type, 'Image')
|
||||
assert.equal(obj[originalActorIdSymbol], connectedActor.id.toString())
|
||||
})
|
||||
|
||||
test('update image description', async () => {
|
||||
const db = await makeDB()
|
||||
const connectedActor = await createPerson(domain, db, userKEK, 'sven@cloudflare.com')
|
||||
const properties = {
|
||||
url: 'https://cloudflare.com/image.jpg',
|
||||
description: 'foo bar',
|
||||
}
|
||||
const image = await createImage(domain, db, connectedActor, properties)
|
||||
|
||||
const request = new Request('https://' + domain, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ description: 'new foo bar' }),
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
const res = await media_id.handleRequestPut(db, image[mastodonIdSymbol]!, request)
|
||||
assert.equal(res.status, 200)
|
||||
|
||||
const data = await res.json<any>()
|
||||
assert.equal(data.description, 'new foo bar')
|
||||
|
||||
const newImage = (await objects.getObjectByMastodonId(db, image[mastodonIdSymbol]!)) as any
|
||||
assert.equal(newImage.description, 'new foo bar')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
// https://docs.joinmastodon.org/methods/media/#update
|
||||
|
||||
import { getObjectByMastodonId } from 'wildebeest/backend/src/activitypub/objects'
|
||||
import { mastodonIdSymbol } from 'wildebeest/backend/src/activitypub/objects'
|
||||
import { cors } from 'wildebeest/backend/src/utils/cors'
|
||||
import type { MediaAttachment } from 'wildebeest/backend/src/types/media'
|
||||
import type { Image } from 'wildebeest/backend/src/activitypub/objects/image'
|
||||
import { readBody } from 'wildebeest/backend/src/utils/body'
|
||||
import type { UUID } from 'wildebeest/backend/src/types'
|
||||
import type { Env } from 'wildebeest/backend/src/types/env'
|
||||
import type { ContextData } from 'wildebeest/backend/src/types/context'
|
||||
import * as errors from 'wildebeest/backend/src/errors'
|
||||
import { updateObjectProperty } from 'wildebeest/backend/src/activitypub/objects'
|
||||
|
||||
export const onRequestPut: PagesFunction<Env, any, ContextData> = async ({ params, env, request }) => {
|
||||
return handleRequestPut(env.DATABASE, params.id as UUID, request)
|
||||
}
|
||||
|
||||
type UpdateMedia = {
|
||||
description?: string
|
||||
}
|
||||
|
||||
export async function handleRequestPut(db: D1Database, id: UUID, request: Request): Promise<Response> {
|
||||
// Update the image properties
|
||||
{
|
||||
const image = (await getObjectByMastodonId(db, id)) as Image
|
||||
if (image === null) {
|
||||
return errors.mediaNotFound(id)
|
||||
}
|
||||
|
||||
const body = await readBody<UpdateMedia>(request)
|
||||
|
||||
if (body.description !== undefined) {
|
||||
await updateObjectProperty(db, image, 'description', body.description)
|
||||
}
|
||||
}
|
||||
|
||||
// reload the image for fresh state
|
||||
const image = (await getObjectByMastodonId(db, id)) as Image
|
||||
|
||||
const res: MediaAttachment = {
|
||||
id: image[mastodonIdSymbol]!,
|
||||
url: image.url,
|
||||
preview_url: image.url,
|
||||
type: 'image',
|
||||
meta: {
|
||||
original: {
|
||||
width: 640,
|
||||
height: 480,
|
||||
size: '640x480',
|
||||
aspect: 1.3333333333333333,
|
||||
},
|
||||
small: {
|
||||
width: 461,
|
||||
height: 346,
|
||||
size: '461x346',
|
||||
aspect: 1.3323699421965318,
|
||||
},
|
||||
focus: {
|
||||
x: -0.27,
|
||||
y: 0.51,
|
||||
},
|
||||
},
|
||||
description: image.description || '',
|
||||
blurhash: 'UFBWY:8_0Jxv4mx]t8t64.%M-:IUWGWAt6M}',
|
||||
}
|
||||
|
||||
const headers = {
|
||||
...cors(),
|
||||
'content-type': 'application/json; charset=utf-8',
|
||||
}
|
||||
return new Response(JSON.stringify(res), { headers })
|
||||
}
|
Ładowanie…
Reference in New Issue