173 lines
5.8 KiB
Rust
173 lines
5.8 KiB
Rust
use chrono::Utc;
|
|
use uuid::Uuid;
|
|
|
|
use crate::event::{RoomInfo, UserInfo, star};
|
|
use crate::{ChannelBus, ChannelResult};
|
|
|
|
use super::WsHandler;
|
|
use super::WsOutEvent;
|
|
|
|
impl WsHandler {
|
|
pub(super) async fn message_star(
|
|
bus: &ChannelBus,
|
|
user_id: Uuid,
|
|
room: Uuid,
|
|
message: Uuid,
|
|
do_star: bool,
|
|
) -> ChannelResult<Option<WsOutEvent>> {
|
|
Self::ensure_room_access(bus, user_id, room).await?;
|
|
Self::ensure_message_in_room(bus, room, message).await?;
|
|
|
|
let room_info = bus
|
|
.lookup_room(room)
|
|
.await
|
|
.unwrap_or_else(|_| RoomInfo::unknown(room));
|
|
let user_info = bus
|
|
.lookup_user(user_id)
|
|
.await
|
|
.unwrap_or_else(|_| UserInfo::unknown(user_id));
|
|
|
|
if do_star {
|
|
let result = db::sqlx::query(
|
|
"INSERT INTO message_star (message, room, \"user\", created_at) \
|
|
VALUES ($1, $2, $3, now()) ON CONFLICT (message, \"user\") DO NOTHING",
|
|
)
|
|
.bind(message)
|
|
.bind(room)
|
|
.bind(user_id)
|
|
.execute(bus.inner.db.writer())
|
|
.await?;
|
|
|
|
if result.rows_affected() == 0 {
|
|
return Ok(None);
|
|
}
|
|
|
|
let seq_row: Option<(i64,)> = db::sqlx::query_as(
|
|
"SELECT seq FROM room_message WHERE id = $1",
|
|
)
|
|
.bind(message)
|
|
.fetch_optional(bus.inner.db.reader())
|
|
.await?;
|
|
|
|
let data = star::MessageStarredService {
|
|
room: room_info.clone(),
|
|
message_id: message,
|
|
message_seq: seq_row.map(|r| r.0).unwrap_or(0),
|
|
starred_by: user_info,
|
|
starred_at: Utc::now(),
|
|
};
|
|
bus.emit_to_user(user_id, "message.starred", &data).await?;
|
|
Ok(Some(WsOutEvent::MessageStarred {
|
|
room: room_info,
|
|
data,
|
|
}))
|
|
} else {
|
|
let result = db::sqlx::query(
|
|
"DELETE FROM message_star WHERE message = $1 AND \"user\" = $2",
|
|
)
|
|
.bind(message)
|
|
.bind(user_id)
|
|
.execute(bus.inner.db.writer())
|
|
.await?;
|
|
|
|
if result.rows_affected() == 0 {
|
|
return Ok(None);
|
|
}
|
|
|
|
let data = star::MessageUnstarredService {
|
|
room: room_info.clone(),
|
|
message_id: message,
|
|
unstarred_by: user_info,
|
|
unstarred_at: Utc::now(),
|
|
};
|
|
bus.emit_to_user(user_id, "message.unstarred", &data)
|
|
.await?;
|
|
Ok(Some(WsOutEvent::MessageUnstarred {
|
|
room: room_info,
|
|
data,
|
|
}))
|
|
}
|
|
}
|
|
pub(super) async fn starred_list(
|
|
bus: &ChannelBus,
|
|
user_id: Uuid,
|
|
room: Option<Uuid>,
|
|
limit: Option<u64>,
|
|
) -> ChannelResult<Option<WsOutEvent>> {
|
|
let limit = limit.unwrap_or(50).min(100) as i64;
|
|
|
|
let rows = if let Some(room_id) = room {
|
|
Self::ensure_room_access(bus, user_id, room_id).await?;
|
|
db::sqlx::query_as::<_, (Uuid, Uuid, i64, String, String, Uuid, chrono::DateTime<Utc>, chrono::DateTime<Utc>)>(
|
|
"SELECT ms.id, rm.id, rm.seq, rm.content, rm.content_type, rm.author, ms.created_at, rm.created_at \
|
|
FROM message_star ms \
|
|
JOIN room_message rm ON rm.id = ms.message \
|
|
WHERE ms.\"user\" = $1 AND ms.room = $2 AND rm.deleted_at IS NULL \
|
|
ORDER BY ms.created_at DESC LIMIT $3",
|
|
)
|
|
.bind(user_id)
|
|
.bind(room_id)
|
|
.bind(limit)
|
|
.fetch_all(bus.inner.db.reader())
|
|
.await?
|
|
} else {
|
|
db::sqlx::query_as::<_, (Uuid, Uuid, i64, String, String, Uuid, chrono::DateTime<Utc>, chrono::DateTime<Utc>)>(
|
|
"SELECT ms.id, rm.id, rm.seq, rm.content, rm.content_type, rm.author, ms.created_at, rm.created_at \
|
|
FROM message_star ms \
|
|
JOIN room_message rm ON rm.id = ms.message \
|
|
WHERE ms.\"user\" = $1 AND rm.deleted_at IS NULL \
|
|
ORDER BY ms.created_at DESC LIMIT $2",
|
|
)
|
|
.bind(user_id)
|
|
.bind(limit)
|
|
.fetch_all(bus.inner.db.reader())
|
|
.await?
|
|
};
|
|
|
|
let author_ids: Vec<Uuid> = rows.iter().map(|r| r.5).collect();
|
|
let user_map = bus.lookup_users(&author_ids).await.unwrap_or_default();
|
|
|
|
let mut entries = Vec::with_capacity(rows.len());
|
|
for (
|
|
_star_id,
|
|
msg_id,
|
|
seq,
|
|
content,
|
|
content_type,
|
|
author_id,
|
|
starred_at,
|
|
sent_at,
|
|
) in rows
|
|
{
|
|
let msg_room_row: Option<(Uuid,)> = db::sqlx::query_as(
|
|
"SELECT room FROM room_message WHERE id = $1",
|
|
)
|
|
.bind(msg_id)
|
|
.fetch_optional(bus.inner.db.reader())
|
|
.await?;
|
|
let msg_room_id = msg_room_row.map(|r| r.0).unwrap_or(Uuid::nil());
|
|
let room_info = bus
|
|
.lookup_room(msg_room_id)
|
|
.await
|
|
.unwrap_or_else(|_| RoomInfo::unknown(msg_room_id));
|
|
let sender = user_map
|
|
.get(&author_id)
|
|
.cloned()
|
|
.unwrap_or_else(|| UserInfo::unknown(author_id));
|
|
|
|
entries.push(star::StarredMessageEntry {
|
|
message_id: msg_id,
|
|
room: room_info,
|
|
seq,
|
|
content,
|
|
content_type,
|
|
sender,
|
|
starred_at,
|
|
sent_at,
|
|
});
|
|
}
|
|
|
|
Ok(Some(WsOutEvent::StarredList { data: entries }))
|
|
}
|
|
}
|