Impl room listing with filter=unseen

This commit is contained in:
oxalica 2024-09-06 03:32:40 -04:00
parent e74da2812b
commit 8b096ba802
2 changed files with 51 additions and 6 deletions

View file

@ -24,10 +24,11 @@ paths:
in: query
required: true
description: |
Either "public" or "joined".
For "public", it returns all public rooms on the server.
For "joined", `Authorization` must be provided and it will return
rooms user have joined.
Must be one of following values:
- "public": list all public rooms on the server.
- "joined": list rooms the user have joined.
- "unseen": list rooms the user have joined and have unseen
messages.
top:
in: query
description:
@ -41,7 +42,9 @@ paths:
should be included (as the same value) for each page fetch.
headers:
Authorization:
description: Proof of membership for private rooms. Required if `filter=joined`.
description: |
Proof of membership for private rooms.
Required if `filter` is other than "public".
required: false
schema:
$ret: WithSig<AuthPayload>

View file

@ -213,8 +213,12 @@ struct ListRoomParams {
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
enum ListRoomFilter {
/// List all public rooms.
Public,
/// List joined rooms (authentication required).
Joined,
/// List all joined rooms with unseen messages (authentication required).
Unseen,
}
async fn room_list(
@ -261,12 +265,14 @@ async fn room_list(
.transpose()?;
let last_seen_cid =
Some(row.get::<_, Id>("last_seen_cid")?).filter(|cid| cid.0 != 0);
let unseen_cnt = row.get("unseen_cnt").ok();
Ok(RoomMetadata {
rid,
title,
attrs,
last_chat,
last_seen_cid,
unseen_cnt,
})
})?
.collect::<Result<Vec<_>, _>>()?;
@ -320,6 +326,36 @@ async fn room_list(
},
)
}
ListRoomFilter::Unseen => {
let user = auth?.0;
query(
r"
SELECT
`rid`, `title`, `attrs`, `last_seen_cid`,
`cid`, `last_author`.`userkey`, `timestamp`, `nonce`, `sig`, `rich_text`,
(SELECT COUNT(*)
FROM `room_item` AS `unseen_item`
WHERE `unseen_item`.`rid` = `room`.`rid` AND
`last_seen_cid` < `unseen_item`.`cid`) AS `unseen_cnt`
FROM `user`
JOIN `room_member` USING (`uid`)
JOIN `room` USING (`rid`)
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 AND
`cid` > `last_seen_cid`
GROUP BY `rid` HAVING `cid` IS MAX(`cid`)
ORDER BY `rid` ASC
LIMIT :page_len
",
named_params! {
":start_rid": start_rid,
":page_len": page_len,
":userkey": user,
},
)
}
}
.map(Json)
}
@ -466,8 +502,10 @@ async fn room_get_metadata(
rid,
title,
attrs,
// TODO: Should we include these here?
last_chat: None,
last_seen_cid: None,
unseen_cnt: None,
}))
}
@ -579,11 +617,15 @@ pub struct RoomMetadata {
pub title: String,
pub attrs: RoomAttrs,
/// Optional extra information. Only included by the room list response.
// Optional extra information. Only included by the room list response.
#[serde(skip_serializing_if = "Option::is_none")]
pub last_chat: Option<WithItemId<ChatItem>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_seen_cid: Option<Id>,
/// 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<u64>,
}
fn get_room_if_readable<T>(