mirror of
https://github.com/djdevin/recflare.git
synced 2026-10-25 15:09:18 -07:00
[chat] fix favorite thread
This commit is contained in:
+27
-10
@@ -20,6 +20,7 @@ import {
|
|||||||
CreatePartyChatResponse,
|
CreatePartyChatResponse,
|
||||||
CreateThreadRequest,
|
CreateThreadRequest,
|
||||||
CreateThreadResponse,
|
CreateThreadResponse,
|
||||||
|
FavoriteChatResponse,
|
||||||
FavoriteThreadRequest,
|
FavoriteThreadRequest,
|
||||||
form,
|
form,
|
||||||
json,
|
json,
|
||||||
@@ -572,7 +573,7 @@ async function formField(c: Context<App>, name: string): Promise<string | undefi
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A concise `describeRoute` spec for one of the thread-scoped actions that answers the
|
* A concise `describeRoute` spec for one of the thread-scoped actions that answers the
|
||||||
* bare ChatResult integer rather than an HTTP status — rename, leave, snooze, favorite,
|
* bare ChatResult integer rather than an HTTP status — rename, leave, snooze,
|
||||||
* add-member and the read-pointer moves. They share the auth gate, the `:id` path param,
|
* add-member and the read-pointer moves. They share the auth gate, the `:id` path param,
|
||||||
* and the "3 when the caller isn't on the thread" behaviour.
|
* and the "3 when the caller isn't on the thread" behaviour.
|
||||||
*/
|
*/
|
||||||
@@ -1361,28 +1362,44 @@ const app = new Hono<App>()
|
|||||||
|
|
||||||
// Favorite or unfavorite a thread (`favorite=True`), for the caller alone — like
|
// Favorite or unfavorite a thread (`favorite=True`), for the caller alone — like
|
||||||
// snoozing, it's a per-member flag that pins the thread in their own inbox.
|
// snoozing, it's a per-member flag that pins the thread in their own inbox.
|
||||||
|
//
|
||||||
|
// Answers the client's `FavoriteChatResponse` — a bare `{ ChatResult, IsFavorited }`
|
||||||
|
// object, not the bare ChatResult integer the neighbouring thread actions answer.
|
||||||
.on(
|
.on(
|
||||||
['PUT', 'POST'],
|
['PUT', 'POST'],
|
||||||
'/thread/:id{[0-9]+}/favorite',
|
'/thread/:id{[0-9]+}/favorite',
|
||||||
chatResultRoute(
|
describeRoute({
|
||||||
'Favorite or unfavorite a thread',
|
tags: ['Chat'],
|
||||||
[
|
summary: 'Favorite or unfavorite a thread',
|
||||||
|
description: [
|
||||||
'Like snoozing, a per-member flag that pins the thread in the caller’s own inbox and',
|
'Like snoozing, a per-member flag that pins the thread in the caller’s own inbox and',
|
||||||
'leaves everyone else’s untouched.',
|
'leaves everyone else’s untouched. Answers the client’s `FavoriteChatResponse`, a bare',
|
||||||
|
'`{ ChatResult, IsFavorited }` object — not the bare ChatResult integer the other thread',
|
||||||
|
'actions answer.',
|
||||||
].join(' '),
|
].join(' '),
|
||||||
{ requestBody: form(FavoriteThreadRequest, 'The favorite flag') }
|
security: AUTHED,
|
||||||
),
|
parameters: [THREAD_ID_PARAM],
|
||||||
|
requestBody: form(FavoriteThreadRequest, 'The favorite flag'),
|
||||||
|
responses: {
|
||||||
|
200: json(
|
||||||
|
FavoriteChatResponse,
|
||||||
|
'ChatResult 0 and the new flag on success; ChatResult 3 when the caller isn’t on the thread'
|
||||||
|
),
|
||||||
|
401: UNAUTHORIZED_RESPONSE,
|
||||||
|
},
|
||||||
|
}),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const id = await authedId(c)
|
const id = await authedId(c)
|
||||||
if (id === null) return c.body(null, 401)
|
if (id === null) return c.body(null, 401)
|
||||||
|
|
||||||
const chatThreadId = Number.parseInt(c.req.param('id'), 10)
|
const chatThreadId = Number.parseInt(c.req.param('id'), 10)
|
||||||
if (!(await isThreadMember(c.env.DB, chatThreadId, id))) {
|
if (!(await isThreadMember(c.env.DB, chatThreadId, id))) {
|
||||||
return c.json(CHAT_MEMBERSHIP_NOT_FOUND)
|
return c.json({ ChatResult: CHAT_MEMBERSHIP_NOT_FOUND, IsFavorited: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
await setThreadFavorited(c.env.DB, chatThreadId, id, await formBool(c, 'favorite'))
|
const isFavorited = await formBool(c, 'favorite')
|
||||||
return c.json(CHAT_SUCCESS)
|
await setThreadFavorited(c.env.DB, chatThreadId, id, isFavorited)
|
||||||
|
return c.json({ ChatResult: CHAT_SUCCESS, IsFavorited: isFavorited })
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -388,6 +388,18 @@ export const FavoriteThreadRequest = z.object({
|
|||||||
.describe('`True`/`False` as the client spells it (`1`/`yes` also count as true)'),
|
.describe('`True`/`False` as the client spells it (`1`/`yes` also count as true)'),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `PUT|POST /thread/:id/favorite` response — the client's `FavoriteChatResponse`, a bare
|
||||||
|
* two-key object with no envelope. Unlike the other thread actions it is NOT a bare
|
||||||
|
* ChatResult integer: the client parses this object either way.
|
||||||
|
*/
|
||||||
|
export const FavoriteChatResponse = z.object({
|
||||||
|
ChatResult,
|
||||||
|
IsFavorited: z
|
||||||
|
.boolean()
|
||||||
|
.describe('The caller’s favorite flag after the call (false when they aren’t on the thread)'),
|
||||||
|
})
|
||||||
|
|
||||||
// ---- Shared parameters -----------------------------------------------------
|
// ---- Shared parameters -----------------------------------------------------
|
||||||
|
|
||||||
/** The numeric `:id` path segment naming a thread (constrained to digits by the route). */
|
/** The numeric `:id` path segment naming a thread (constrained to digits by the route). */
|
||||||
|
|||||||
@@ -2164,13 +2164,17 @@ describe('PUT /thread/:id/favorite', () => {
|
|||||||
|
|
||||||
const res = await favorite(caller, chatThreadId, 'favorite=True')
|
const res = await favorite(caller, chatThreadId, 'favorite=True')
|
||||||
expect(res.status).toBe(200)
|
expect(res.status).toBe(200)
|
||||||
expect(await res.json()).toBe(0)
|
// The client's FavoriteChatResponse: a bare 2-key object, no envelope.
|
||||||
|
expect(await res.json()).toEqual({ ChatResult: 0, IsFavorited: true })
|
||||||
|
|
||||||
expect((await getThreadForPlayer(env.DB, chatThreadId, caller))?.isFavorited).toBe(true)
|
expect((await getThreadForPlayer(env.DB, chatThreadId, caller))?.isFavorited).toBe(true)
|
||||||
// Per-member, like snoozing: the other player's inbox is untouched.
|
// Per-member, like snoozing: the other player's inbox is untouched.
|
||||||
expect((await getThreadForPlayer(env.DB, chatThreadId, other))?.isFavorited).toBe(false)
|
expect((await getThreadForPlayer(env.DB, chatThreadId, other))?.isFavorited).toBe(false)
|
||||||
|
|
||||||
await favorite(caller, chatThreadId, 'favorite=False')
|
expect(await (await favorite(caller, chatThreadId, 'favorite=False')).json()).toEqual({
|
||||||
|
ChatResult: 0,
|
||||||
|
IsFavorited: false,
|
||||||
|
})
|
||||||
expect((await getThreadForPlayer(env.DB, chatThreadId, caller))?.isFavorited).toBe(false)
|
expect((await getThreadForPlayer(env.DB, chatThreadId, caller))?.isFavorited).toBe(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -2178,13 +2182,19 @@ describe('PUT /thread/:id/favorite', () => {
|
|||||||
const caller = 893003
|
const caller = 893003
|
||||||
const chatThreadId = await createThread(env.DB, [caller, 893004], null, caller)
|
const chatThreadId = await createThread(env.DB, [caller, 893004], null, caller)
|
||||||
|
|
||||||
expect(await (await favorite(caller, chatThreadId, 'favorite=True', 'POST')).json()).toBe(0)
|
expect(await (await favorite(caller, chatThreadId, 'favorite=True', 'POST')).json()).toEqual({
|
||||||
|
ChatResult: 0,
|
||||||
|
IsFavorited: true,
|
||||||
|
})
|
||||||
expect((await getThreadForPlayer(env.DB, chatThreadId, caller))?.isFavorited).toBe(true)
|
expect((await getThreadForPlayer(env.DB, chatThreadId, caller))?.isFavorited).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('refuses a thread the caller is not on', async () => {
|
it('refuses a thread the caller is not on', async () => {
|
||||||
const chatThreadId = await createThread(env.DB, [893005, 893006], null, 893005)
|
const chatThreadId = await createThread(env.DB, [893005, 893006], null, 893005)
|
||||||
expect(await (await favorite(893007, chatThreadId, 'favorite=True')).json()).toBe(3)
|
expect(await (await favorite(893007, chatThreadId, 'favorite=True')).json()).toEqual({
|
||||||
|
ChatResult: 3,
|
||||||
|
IsFavorited: false,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('401s without a token', async () => {
|
it('401s without a token', async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user