mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 14:41:28 -07:00
more endpoints, fix orientation on new accounts
This commit is contained in:
+11
-4
@@ -431,16 +431,23 @@ const app = new Hono<App>({ strict: false })
|
||||
.get('/api/images/v2/named', (c) => c.json([])) // TODO: hydrate from JSON/namedimages.json
|
||||
.post('/api/images/v4/uploadsaved', async (c) => {
|
||||
const body = await c.req.parseBody().catch(() => ({}) as Record<string, unknown>)
|
||||
const file = body.file
|
||||
if (!(file instanceof File)) return c.json({ error: 'No file found in request' }, 400)
|
||||
// The client posts the file as `image`; accept `file` too for safety.
|
||||
const candidate = body.image ?? body.file
|
||||
if (!(candidate instanceof File)) return c.json({ error: 'No file found in request' }, 400)
|
||||
const file = candidate
|
||||
|
||||
const valid = ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp']
|
||||
const dot = file.name.lastIndexOf('.')
|
||||
const ext = dot >= 0 ? file.name.slice(dot).toLowerCase() : ''
|
||||
const extension = valid.includes(ext) ? ext : '.png'
|
||||
|
||||
// TODO: persist the upload (R2?). For now just mint a name.
|
||||
return c.json({ ImageName: crypto.randomUUID().replace(/-/g, '') + extension })
|
||||
// Store the upload in the shared image bucket under a random key. The `img`
|
||||
// worker serves it back by that key, which is the returned ImageName.
|
||||
const name = crypto.randomUUID().replace(/-/g, '') + extension
|
||||
await c.env.IMAGES.put(name, await file.arrayBuffer(), {
|
||||
httpMetadata: { contentType: file.type || 'image/png' },
|
||||
})
|
||||
return c.json({ ImageName: name })
|
||||
})
|
||||
|
||||
// ---- Rooms ----------------------------------------------------------------
|
||||
|
||||
@@ -5,6 +5,9 @@ export type Env = SharedHonoEnv & {
|
||||
// Shared rooms database (schema/migrations owned by the `rooms` worker). Used
|
||||
// read-only here for the /roomserver/rooms/* endpoints.
|
||||
DB: D1Database
|
||||
// Image bucket (shared with the `img` worker, which serves objects back by
|
||||
// key). Uploaded saved images are written here.
|
||||
IMAGES: R2Bucket
|
||||
}
|
||||
|
||||
/** Variables can be extended */
|
||||
|
||||
@@ -337,3 +337,33 @@ describe('room server', () => {
|
||||
expect(await res.json()).toEqual({ Cheered: false, Favorited: false })
|
||||
})
|
||||
})
|
||||
|
||||
describe('images', () => {
|
||||
test('POST /api/images/v4/uploadsaved stores the file in R2 and returns its name', async () => {
|
||||
const bytes = new Uint8Array([0x89, 0x50, 0x4e, 0x47, 1, 2, 3, 4])
|
||||
const fd = new FormData()
|
||||
fd.append('image', new File([bytes], 'avatar.png', { type: 'image/png' }))
|
||||
|
||||
const res = await exports.default.fetch(`${ORIGIN}/api/images/v4/uploadsaved`, {
|
||||
method: 'POST',
|
||||
body: fd,
|
||||
})
|
||||
expect(res.status).toBe(200)
|
||||
const { ImageName } = (await res.json()) as { ImageName: string }
|
||||
expect(ImageName).toMatch(/^[0-9a-f]+\.png$/)
|
||||
|
||||
// The object is in the shared bucket under that key.
|
||||
const stored = await env.IMAGES.get(ImageName)
|
||||
expect(stored).not.toBeNull()
|
||||
expect(new Uint8Array(await stored!.arrayBuffer())).toEqual(bytes)
|
||||
})
|
||||
|
||||
test('POST /api/images/v4/uploadsaved 400s without a file', async () => {
|
||||
const res = await exports.default.fetch(`${ORIGIN}/api/images/v4/uploadsaved`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: 'foo=bar',
|
||||
})
|
||||
expect(res.status).toBe(400)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -18,6 +18,14 @@
|
||||
"database_id": "d44083e1-5bfe-4467-aa9a-f13c5c2496d5"
|
||||
}
|
||||
],
|
||||
// Image bucket shared with the `img` worker (which serves objects back by key).
|
||||
// Saved-image uploads are written here.
|
||||
"r2_buckets": [
|
||||
{
|
||||
"binding": "IMAGES",
|
||||
"bucket_name": "rec-img"
|
||||
}
|
||||
],
|
||||
"logpush": false,
|
||||
"upload_source_maps": true,
|
||||
"observability": {
|
||||
|
||||
Reference in New Issue
Block a user