From 74c6fa6f6a7c6c8c48d4bbc60c5d088ab0b8e68f Mon Sep 17 00:00:00 2001 From: oxalica Date: Tue, 10 Sep 2024 09:19:15 -0400 Subject: [PATCH] refactor(webapi): hoist `RoomMetadata` to `blah_types` and rename `last_chat` to `last_item` --- blah-types/src/lib.rs | 23 +++++++++++++++++++++++ blahd/src/lib.rs | 42 +++++++++++++----------------------------- blahd/tests/webapi.rs | 2 +- docs/webapi.yaml | 2 +- test-frontend/main.js | 4 ++-- 5 files changed, 40 insertions(+), 33 deletions(-) diff --git a/blah-types/src/lib.rs b/blah-types/src/lib.rs index 9cb270c..cfb0c30 100644 --- a/blah-types/src/lib.rs +++ b/blah-types/src/lib.rs @@ -308,6 +308,29 @@ impl RichText { pub type ChatItem = WithSig; +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct RoomMetadata { + /// Room id. + pub rid: Id, + /// Plain text room title. + pub title: String, + /// Room attributes. + pub attrs: RoomAttrs, + + // Extra information is only available for some APIs. + /// The last item in the room. + #[serde(skip_serializing_if = "Option::is_none")] + pub last_item: Option>, + /// The current user's last seen item id. + #[serde(skip_serializing_if = "Option::is_none")] + pub last_seen_cid: Option, + /// The number of unseen messages, ie. the number of items from `last_seen_cid` to + /// `last_item.cid`. + /// This may or may not be a precise number. + #[serde(skip_serializing_if = "Option::is_none")] + pub unseen_cnt: Option, +} + #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[serde(tag = "typ", rename = "create_room")] pub struct CreateRoomPayload { diff --git a/blahd/src/lib.rs b/blahd/src/lib.rs index a709314..9923fc1 100644 --- a/blahd/src/lib.rs +++ b/blahd/src/lib.rs @@ -12,7 +12,7 @@ use axum::{Json, Router}; use axum_extra::extract::WithRejection as R; use blah_types::{ ChatItem, ChatPayload, CreateRoomPayload, Id, MemberPermission, RoomAdminOp, RoomAdminPayload, - RoomAttrs, ServerPermission, Signee, UserKey, WithItemId, WithSig, + RoomAttrs, RoomMetadata, ServerPermission, Signee, UserKey, WithItemId, WithSig, }; use config::ServerConfig; use ed25519_dalek::SIGNATURE_LENGTH; @@ -138,7 +138,7 @@ async fn handle_ws(State(st): ArcState, ws: WebSocketUpgrade) -> Response { }) } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct RoomList { pub rooms: Vec, #[serde(skip_serializing_if = "Option::is_none")] @@ -189,7 +189,7 @@ async fn room_list( let rid = row.get("rid")?; let title = row.get("title")?; let attrs = row.get("attrs")?; - let last_chat = row + let last_item = row .get::<_, Option>("cid")? .map(|cid| { Ok::<_, rusqlite::Error>(WithItemId { @@ -216,7 +216,7 @@ async fn room_list( rid, title, attrs, - last_chat, + last_item, last_seen_cid, unseen_cnt, }) @@ -439,20 +439,21 @@ async fn room_get_metadata( R(Path(rid), _): RE>, auth: MaybeAuth, ) -> Result, ApiError> { - let (title, attrs) = - get_room_if_readable(&st.db.get(), rid, auth.into_optional()?.as_ref(), |row| { - Ok(( - row.get::<_, String>("title")?, - row.get::<_, RoomAttrs>("attrs")?, - )) - })?; + let conn = st.db.get(); + let (title, attrs) = get_room_if_readable(&conn, rid, auth.into_optional()?.as_ref(), |row| { + Ok(( + row.get::<_, String>("title")?, + row.get::<_, RoomAttrs>("attrs")?, + )) + })?; Ok(Json(RoomMetadata { rid, title, attrs, + // TODO: Should we include these here? - last_chat: None, + last_item: None, last_seen_cid: None, unseen_cnt: None, })) @@ -560,23 +561,6 @@ struct FeedItemExtra { sig: [u8; SIGNATURE_LENGTH], } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct RoomMetadata { - pub rid: Id, - pub title: String, - pub attrs: RoomAttrs, - - // Optional extra information. Only included by the room list response. - #[serde(skip_serializing_if = "Option::is_none")] - pub last_chat: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - pub last_seen_cid: Option, - /// The number of unseen messages. Only available for `room_list` response with - /// "filter=unseen". - #[serde(skip_serializing_if = "Option::is_none")] - pub unseen_cnt: Option, -} - fn get_room_if_readable( conn: &rusqlite::Connection, rid: Id, diff --git a/blahd/tests/webapi.rs b/blahd/tests/webapi.rs index 80b623b..4397c12 100644 --- a/blahd/tests/webapi.rs +++ b/blahd/tests/webapi.rs @@ -233,7 +233,7 @@ async fn room_create_get(server: Server, ref mut rng: impl RngCore, #[case] publ } else { RoomAttrs::empty() }, - last_chat: None, + last_item: None, last_seen_cid: None, unseen_cnt: None, }; diff --git a/docs/webapi.yaml b/docs/webapi.yaml index e176bb9..0442aa6 100644 --- a/docs/webapi.yaml +++ b/docs/webapi.yaml @@ -377,7 +377,7 @@ components: description: Room attributes bitset, see `RoomAttrs`. type: integer format: int64 - last_chat: + last_item: $ref: '#/components/schemas/WithItemId-WithSig-Chat' last_seen_cid: description: The `cid` of the last chat being marked as seen. diff --git a/test-frontend/main.js b/test-frontend/main.js index 10d5f17..64942d5 100644 --- a/test-frontend/main.js +++ b/test-frontend/main.js @@ -269,11 +269,11 @@ async function loadRoomList(autoJoin) { const resp = await fetch(`${serverUrl}/room?filter=${filter}`, await genAuthHeader()) const json = await resp.json() if (resp.status !== 200) throw new Error(`status ${resp.status}: ${json.error.message}`); - for (const { rid, title, attrs, last_chat, last_seen_cid } of json.rooms) { + for (const { rid, title, attrs, last_item, last_seen_cid } of json.rooms) { const el = document.createElement('option'); el.value = rid; el.innerText = `${title} (rid=${rid}, attrs=${attrs})`; - if (last_chat !== undefined && last_chat.cid !== last_seen_cid) { + if (last_item !== undefined && last_item.cid !== last_seen_cid) { el.innerText += ' (unread)'; } targetEl.appendChild(el);