implement media update

pull/235/head
Sven Sauleau 2023-02-09 14:40:28 +00:00
rodzic c6ecc0624e
commit b01148c9b2
5 zmienionych plików z 119 dodań i 1 usunięć

Wyświetl plik

@ -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)

Wyświetl plik

@ -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())
}

Wyświetl plik

@ -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)
}

Wyświetl plik

@ -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')
})
})
})

Wyświetl plik

@ -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 })
}