gitdataai/lib/channel/http/handler/helpers.rs

161 lines
4.8 KiB
Rust

use std::collections::HashMap;
use uuid::Uuid;
use crate::event::{RoomInfo, UserInfo, message, reaction};
use crate::{ChannelBus, ChannelError, ChannelResult};
use super::WsHandler;
impl WsHandler {
pub(super) async fn ensure_room_access(
bus: &ChannelBus,
user_id: Uuid,
room: Uuid,
) -> ChannelResult<()> {
let rooms = crate::rooms::user_rooms(
&bus.inner.db,
&bus.inner.cache,
&bus.inner.config,
user_id,
)
.await?;
if rooms.contains(&room) {
Ok(())
} else {
Err(ChannelError::AccessDenied)
}
}
pub(super) async fn ensure_message_in_room(
bus: &ChannelBus,
room: Uuid,
message: Uuid,
) -> ChannelResult<()> {
let exists: Option<(Uuid,)> = db::sqlx::query_as(
"SELECT id FROM room_message WHERE id = $1 AND room = $2 AND deleted_at IS NULL",
)
.bind(message)
.bind(room)
.fetch_optional(bus.inner.db.reader())
.await?;
exists.map(|_| ()).ok_or(ChannelError::RoomNotFound)
}
pub(super) async fn reaction_groups_for_messages(
bus: &ChannelBus,
user_id: Uuid,
message_ids: &[Uuid],
) -> ChannelResult<HashMap<Uuid, Vec<reaction::ReactionGroup>>> {
if message_ids.is_empty() {
return Ok(HashMap::new());
}
let rows = db::sqlx::query_as::<_, (Uuid, String, Uuid)>(
"SELECT message, reaction, \"user\" FROM room_reaction \
WHERE message = ANY($1) ORDER BY created_at ASC",
)
.bind(message_ids)
.fetch_all(bus.inner.db.reader())
.await?;
let user_ids: Vec<Uuid> =
rows.iter().map(|(_, _, user)| *user).collect();
let users = bus.lookup_users(&user_ids).await.unwrap_or_default();
let mut grouped: HashMap<
Uuid,
HashMap<String, reaction::ReactionGroup>,
> = HashMap::new();
for (message_id, emoji, reactor) in rows {
let group = grouped
.entry(message_id)
.or_default()
.entry(emoji.clone())
.or_insert_with(|| reaction::ReactionGroup {
emoji: emoji.clone(),
count: 0,
reacted_by_me: false,
users: Vec::new(),
});
group.count += 1;
group.reacted_by_me |= reactor == user_id;
group.users.push(
users
.get(&reactor)
.cloned()
.unwrap_or_else(|| UserInfo::unknown(reactor)),
);
}
Ok(grouped
.into_iter()
.map(|(message_id, groups)| {
(message_id, groups.into_values().collect::<Vec<_>>())
})
.collect())
}
pub(super) async fn ensure_workspace_member(
bus: &ChannelBus,
user_id: Uuid,
wk: Uuid,
) -> ChannelResult<()> {
let row: Option<(Uuid,)> = db::sqlx::query_as(
"SELECT wk FROM wk_member WHERE wk = $1 AND \"user\" = $2 AND leave_at IS NULL",
)
.bind(wk)
.bind(user_id)
.fetch_optional(bus.inner.db.reader())
.await?;
row.map(|_| ()).ok_or(ChannelError::AccessDenied)
}
#[allow(dead_code)]
pub(super) fn missed_message_data(
m: crate::MissedMessage,
) -> message::MessageNewService {
message::MessageNewService {
id: m.message_id,
seq: m.seq,
room: RoomInfo::unknown(m.room_id),
sender_type: "user".to_string(),
sender: UserInfo::unknown(m.sender_id),
thread: None,
in_reply_to: None,
content: m.content,
content_type: "text".to_string(),
pinned: false,
system_type: None,
metadata: serde_json::Value::Null,
thinking_content: None,
thinking_is_chunked: None,
send_at: m.send_at,
reactions: vec![],
}
}
#[allow(dead_code)]
pub(super) fn message_data(
m: model::room::RoomMessageModel,
) -> message::MessageNewService {
message::MessageNewService {
id: m.id,
seq: m.seq,
room: RoomInfo::unknown(m.room),
sender_type: "user".to_string(),
sender: UserInfo::unknown(m.author),
thread: m.thread,
in_reply_to: m.parent,
content: m.content,
content_type: m.content_type,
pinned: m.pinned,
system_type: m.system_type,
metadata: m.metadata,
thinking_content: None,
thinking_is_chunked: None,
send_at: m.created_at,
reactions: vec![],
}
}
}