diff --git a/blahd/docs/webapi.yaml b/blahd/docs/webapi.yaml index 0fc394c..1329051 100644 --- a/blahd/docs/webapi.yaml +++ b/blahd/docs/webapi.yaml @@ -244,11 +244,24 @@ components: rooms: type: array items: - $ref: '#/components/schemas/RoomMetadata' + $ref: '#/components/schemas/RoomMetadataForList' next_token: type: string description: An opaque token to fetch the next page. + RoomMetadataForList: + type: object + required: ['ruuid', 'title', 'attrs'] + properties: + ruuid: + type: string + title: + type: string + attrs: + type: int64 + last_chat: + $ref: 'WithSig' + RoomMetadata: type: object properties: diff --git a/blahd/init.sql b/blahd/init.sql index 34103ac..2c6f92e 100644 --- a/blahd/init.sql +++ b/blahd/init.sql @@ -32,3 +32,5 @@ CREATE TABLE IF NOT EXISTS `room_item` ( `sig` BLOB NOT NULL, `rich_text` TEXT NOT NULL ) STRICT; + +CREATE INDEX IF NOT EXISTS `room_latest_item` ON `room_item` (`rid` ASC, `cid` DESC); diff --git a/blahd/src/main.rs b/blahd/src/main.rs index 0a1b3b2..5f412f5 100644 --- a/blahd/src/main.rs +++ b/blahd/src/main.rs @@ -241,11 +241,33 @@ async fn room_list( .unwrap() .prepare(sql)? .query_map(params, |row| { + // TODO: Extract this into a function. last_rid = Some(row.get::<_, u64>("rid")?); + let ruuid = row.get("ruuid")?; + let title = row.get("title")?; + let attrs = row.get("attrs")?; + let last_chat = row + .get::<_, Option>("userkey")? + .map(|user| { + Ok::<_, rusqlite::Error>(ChatItem { + sig: row.get("sig")?, + signee: Signee { + nonce: row.get("nonce")?, + timestamp: row.get("timestamp")?, + user, + payload: ChatPayload { + rich_text: row.get("rich_text")?, + room: ruuid, + }, + }, + }) + }) + .transpose()?; Ok(RoomMetadata { - ruuid: row.get("ruuid")?, - title: row.get("title")?, - attrs: row.get("attrs")?, + ruuid, + title, + attrs, + last_chat, }) })? .collect::, _>>()?; @@ -256,10 +278,14 @@ async fn room_list( match params.filter { ListRoomFilter::Public => query( r" - SELECT `rid`, `ruuid`, `title`, `attrs` + SELECT `rid`, `ruuid`, `title`, `attrs`, + `last_author`.`userkey` AS `userkey`, `timestamp`, `nonce`, `sig`, `rich_text` FROM `room` + LEFT JOIN `room_item` USING (`rid`) + LEFT JOIN `user` AS `last_author` USING (`uid`) WHERE `rid` > :start_rid AND (`attrs` & :perm) = :perm + GROUP BY `rid` HAVING `cid` IS MAX(`cid`) ORDER BY `rid` ASC LIMIT :page_len ", @@ -279,12 +305,17 @@ async fn room_list( }; query( r" - SELECT `rid`, `ruuid`, `title`, `attrs` + SELECT + `rid`, `ruuid`, `title`, `attrs`, + `last_author`.`userkey`, `timestamp`, `nonce`, `sig`, `rich_text` FROM `user` JOIN `room_member` USING (`uid`) JOIN `room` USING (`rid`) - WHERE `userkey` = :userkey AND + LEFT JOIN `room_item` USING (`rid`) + LEFT JOIN `user` AS `last_author` ON (`last_author`.`uid` = `room_item`.`uid`) + WHERE `user`.`userkey` = :userkey AND `rid` > :start_rid + GROUP BY `rid` HAVING `cid` IS MAX(`cid`) ORDER BY `rid` ASC LIMIT :page_len ", @@ -447,6 +478,7 @@ async fn room_get_metadata( ruuid, title, attrs, + last_chat: None, })) } @@ -555,6 +587,10 @@ pub struct RoomMetadata { pub ruuid: Uuid, pub title: String, pub attrs: RoomAttrs, + + /// Optional extra information. Only included by the global room list response. + #[serde(skip_serializing_if = "Option::is_none")] + pub last_chat: Option, } fn get_room_if_readable(