122 lines
4.9 KiB
Rust
122 lines
4.9 KiB
Rust
use chrono::Utc;
|
|
use uuid::Uuid;
|
|
|
|
use crate::event::{RoomInfo, UserInfo, thread};
|
|
use crate::{ChannelBus, ChannelError, ChannelResult};
|
|
|
|
use super::WsOutEvent;
|
|
use super::WsHandler;
|
|
|
|
impl WsHandler {
|
|
pub(super) async fn thread_create(
|
|
bus: &ChannelBus,
|
|
user_id: Uuid,
|
|
room: Uuid,
|
|
parent: i64,
|
|
) -> ChannelResult<Option<WsOutEvent>> {
|
|
Self::ensure_room_access(bus, user_id, room).await?;
|
|
// Look up the message UUID from seq + room
|
|
let parent_id: Option<(Uuid,)> = db::sqlx::query_as(
|
|
"SELECT id FROM room_message WHERE room = $1 AND seq = $2 AND deleted_at IS NULL",
|
|
)
|
|
.bind(room)
|
|
.bind(parent)
|
|
.fetch_optional(bus.inner.db.reader())
|
|
.await?;
|
|
let parent_msg_id = parent_id.ok_or(ChannelError::RoomNotFound)?.0;
|
|
let seq = bus.inner.seq.seq(room).await?;
|
|
let row = db::sqlx::query_as::<_, model::room::RoomThreadModel>(
|
|
"INSERT INTO room_thread (room, seq, starter_message, title, created_by, created_at, updated_at) \
|
|
VALUES ($1, $2, $3, '', $4, now(), now()) \
|
|
RETURNING id, room, seq, starter_message, title, created_by, archived, locked, \
|
|
last_message_at, created_at, updated_at, archived_at",
|
|
)
|
|
.bind(room)
|
|
.bind(seq)
|
|
.bind(parent_msg_id) // UUID of the starter message
|
|
.bind(user_id)
|
|
.fetch_one(bus.inner.db.writer())
|
|
.await?;
|
|
let tc_room = bus.lookup_room(room).await.unwrap_or_else(|_| RoomInfo::unknown(room));
|
|
let created_by = bus.lookup_user(user_id).await.unwrap_or_else(|_| UserInfo::unknown(user_id));
|
|
let data = thread::ThreadCreatedService {
|
|
id: row.id,
|
|
room: tc_room,
|
|
parent,
|
|
created_by,
|
|
participants: serde_json::Value::Null,
|
|
created_at: row.created_at,
|
|
};
|
|
bus.publish_room_event(room, "thread.created", &data).await?;
|
|
Ok(Some(WsOutEvent::ThreadCreated { room: data.room.clone(), data }))
|
|
}
|
|
|
|
pub(super) async fn thread_resolve(
|
|
bus: &ChannelBus,
|
|
user_id: Uuid,
|
|
thread_id: Uuid,
|
|
) -> ChannelResult<Option<WsOutEvent>> {
|
|
let existing: (Uuid,) = db::sqlx::query_as(
|
|
"SELECT room FROM room_thread WHERE id = $1",
|
|
)
|
|
.bind(thread_id)
|
|
.fetch_optional(bus.inner.db.reader())
|
|
.await?
|
|
.ok_or(ChannelError::RoomNotFound)?;
|
|
Self::ensure_room_access(bus, user_id, existing.0).await?;
|
|
let row = db::sqlx::query_as::<_, model::room::RoomThreadModel>(
|
|
"UPDATE room_thread SET locked = true, updated_at = now() \
|
|
WHERE id = $1 \
|
|
RETURNING id, room, seq, starter_message, title, created_by, archived, locked, \
|
|
last_message_at, created_at, updated_at, archived_at",
|
|
)
|
|
.bind(thread_id)
|
|
.fetch_one(bus.inner.db.writer())
|
|
.await?;
|
|
let tr_room = bus.lookup_room(row.room).await.unwrap_or_else(|_| RoomInfo::unknown(row.room));
|
|
let resolved_by = bus.lookup_user(user_id).await.unwrap_or_else(|_| UserInfo::unknown(user_id));
|
|
let data = thread::ThreadResolvedService {
|
|
id: row.id,
|
|
room: tr_room,
|
|
resolved_by,
|
|
resolved_at: Utc::now(),
|
|
};
|
|
bus.publish_room_event(row.room, "thread.resolved", &data).await?;
|
|
Ok(Some(WsOutEvent::ThreadResolved { room: data.room.clone(), data }))
|
|
}
|
|
|
|
pub(super) async fn thread_archive(
|
|
bus: &ChannelBus,
|
|
user_id: Uuid,
|
|
thread_id: Uuid,
|
|
) -> ChannelResult<Option<WsOutEvent>> {
|
|
let existing: (Uuid,) = db::sqlx::query_as(
|
|
"SELECT room FROM room_thread WHERE id = $1",
|
|
)
|
|
.bind(thread_id)
|
|
.fetch_optional(bus.inner.db.reader())
|
|
.await?
|
|
.ok_or(ChannelError::RoomNotFound)?;
|
|
Self::ensure_room_access(bus, user_id, existing.0).await?;
|
|
let row = db::sqlx::query_as::<_, model::room::RoomThreadModel>(
|
|
"UPDATE room_thread SET archived = true, archived_at = now(), updated_at = now() \
|
|
WHERE id = $1 \
|
|
RETURNING id, room, seq, starter_message, title, created_by, archived, locked, \
|
|
last_message_at, created_at, updated_at, archived_at",
|
|
)
|
|
.bind(thread_id)
|
|
.fetch_one(bus.inner.db.writer())
|
|
.await?;
|
|
let ta_room = bus.lookup_room(row.room).await.unwrap_or_else(|_| RoomInfo::unknown(row.room));
|
|
let archived_by = bus.lookup_user(user_id).await.unwrap_or_else(|_| UserInfo::unknown(user_id));
|
|
let data = thread::ThreadArchivedService {
|
|
id: row.id,
|
|
room: ta_room,
|
|
archived_by,
|
|
archived_at: Utc::now(),
|
|
};
|
|
bus.publish_room_event(row.room, "thread.archived", &data).await?;
|
|
Ok(Some(WsOutEvent::ThreadArchived { room: data.room.clone(), data }))
|
|
}
|
|
}
|