mirror of
https://github.com/Blah-IM/blahrs.git
synced 2025-07-01 03:55:33 +00:00
feat(webapi): impl room member listing
This commit is contained in:
parent
bc6e6c2056
commit
367f6d2a4b
7 changed files with 250 additions and 18 deletions
|
@ -242,19 +242,26 @@ pub trait TransactionOps {
|
|||
.ok_or(ApiError::RoomNotFound)
|
||||
}
|
||||
|
||||
// FIXME: Eliminate this.
|
||||
// Currently broadcasting msgs requires traversing over all members.
|
||||
fn list_room_members(&self, rid: Id) -> Result<Vec<i64>> {
|
||||
fn list_room_members(
|
||||
&self,
|
||||
rid: Id,
|
||||
start_uid: Id,
|
||||
page_len: Option<NonZero<u32>>,
|
||||
) -> Result<Vec<(i64, PubKey, MemberPermission, Id)>> {
|
||||
let page_len = page_len.map_or(-1i64, |v| v.get().into());
|
||||
prepare_cached_and_bind!(
|
||||
self.conn(),
|
||||
r"
|
||||
SELECT `uid`
|
||||
SELECT `uid`, `id_key`, `room_member`.`permission`, `last_seen_cid`
|
||||
FROM `room_member`
|
||||
WHERE `rid` = :rid
|
||||
JOIN `user` USING (`uid`)
|
||||
WHERE `rid` = :rid AND
|
||||
`uid` > :start_uid
|
||||
LIMIT :page_len
|
||||
"
|
||||
)
|
||||
.raw_query()
|
||||
.mapped(|row| row.get::<_, i64>(0))
|
||||
.mapped(|row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)))
|
||||
.collect::<rusqlite::Result<Vec<_>>>()
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ use blah_types::msg::{
|
|||
SignedChatMsgWithId, UserRegisterPayload,
|
||||
};
|
||||
use blah_types::server::{RoomMetadata, ServerCapabilities, ServerMetadata, UserRegisterChallenge};
|
||||
use blah_types::{get_timestamp, Id, Signed, UserKey};
|
||||
use blah_types::{get_timestamp, Id, PubKey, Signed, UserKey};
|
||||
use data_encoding::BASE64_NOPAD;
|
||||
use database::{Transaction, TransactionOps};
|
||||
use feed::FeedData;
|
||||
|
@ -159,6 +159,7 @@ pub fn router(st: Arc<AppState>) -> Router {
|
|||
.route("/room/:rid/msg", get(room_msg_list).post(room_msg_post))
|
||||
.route("/room/:rid/msg/:cid/seen", post(room_msg_mark_seen))
|
||||
.route("/room/:rid/admin", post(room_admin))
|
||||
.route("/room/:rid/member", get(room_member_list))
|
||||
.layer(tower_http::limit::RequestBodyLimitLayer::new(
|
||||
st.config.max_request_len,
|
||||
))
|
||||
|
@ -554,7 +555,11 @@ async fn room_msg_post(
|
|||
|
||||
let cid = Id::gen();
|
||||
txn.add_room_chat_msg(rid, uid, cid, &chat)?;
|
||||
let members = txn.list_room_members(rid)?;
|
||||
let members = txn
|
||||
.list_room_members(rid, Id::MIN, None)?
|
||||
.into_iter()
|
||||
.map(|(uid, ..)| uid)
|
||||
.collect::<Vec<_>>();
|
||||
Ok((cid, members))
|
||||
})?;
|
||||
|
||||
|
@ -668,3 +673,64 @@ async fn room_msg_mark_seen(
|
|||
})?;
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
|
||||
// TODO: Hoist these into types crate.
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct RoomMemberList {
|
||||
pub members: Vec<RoomMember>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub skip_token: Option<Id>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct RoomMember {
|
||||
pub id_key: PubKey,
|
||||
pub permission: MemberPermission,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub last_seen_cid: Option<Id>,
|
||||
}
|
||||
|
||||
async fn room_member_list(
|
||||
st: ArcState,
|
||||
R(Path(rid), _): RE<Path<Id>>,
|
||||
R(Query(pagination), _): RE<Query<Pagination>>,
|
||||
Auth(user): Auth,
|
||||
) -> Result<Json<RoomMemberList>, ApiError> {
|
||||
api_ensure!(
|
||||
pagination.until_token.is_none(),
|
||||
"untilToken is not supported for this API"
|
||||
);
|
||||
|
||||
st.db.with_read(|txn| {
|
||||
let (_, perm, _) = txn.get_room_member(rid, &user)?;
|
||||
api_ensure!(
|
||||
perm.contains(MemberPermission::LIST_MEMBERS),
|
||||
ApiError::PermissionDenied("the user does not have permission to get room members"),
|
||||
);
|
||||
|
||||
let page_len = pagination.effective_page_len(&st);
|
||||
let mut last_uid = None;
|
||||
let members = txn
|
||||
.list_room_members(
|
||||
rid,
|
||||
pagination.skip_token.unwrap_or(Id::MIN),
|
||||
Some(page_len),
|
||||
)?
|
||||
.into_iter()
|
||||
.map(|(uid, id_key, permission, last_seen_cid)| {
|
||||
last_uid = Some(Id(uid));
|
||||
RoomMember {
|
||||
id_key,
|
||||
permission,
|
||||
last_seen_cid: (last_seen_cid != Id(0)).then_some(last_seen_cid),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let skip_token = (members.len() as u32 == page_len.get())
|
||||
.then(|| last_uid.expect("page must not be empty"));
|
||||
Ok(Json(RoomMemberList {
|
||||
members,
|
||||
skip_token,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue