use chrono::Utc; use uuid::Uuid; use crate::event::{RoomInfo, UserInfo, pin}; use crate::{ChannelBus, ChannelResult}; use super::WsOutEvent; use super::WsHandler; impl WsHandler { pub(super) async fn pin_add( bus: &ChannelBus, user_id: Uuid, room: Uuid, message: Uuid, ) -> ChannelResult> { Self::ensure_room_access(bus, user_id, room).await?; Self::ensure_message_in_room(bus, room, message).await?; let seq = bus.inner.seq.seq(room).await?; let result = db::sqlx::query( "INSERT INTO room_pin (room, message, seq, pinned_by, created_at) \ VALUES ($1, $2, $3, $4, now()) \ ON CONFLICT DO NOTHING", ) .bind(room) .bind(message) .bind(seq) .bind(user_id) .execute(bus.inner.db.writer()) .await?; if result.rows_affected() == 0 { return Ok(None); } db::sqlx::query("UPDATE room_message SET pinned = true, updated_at = now() WHERE id = $1") .bind(message) .execute(bus.inner.db.writer()) .await?; let pa_room = bus.lookup_room(room).await.unwrap_or_else(|_| RoomInfo::unknown(room)); let pinned_by = bus.lookup_user(user_id).await.unwrap_or_else(|_| UserInfo::unknown(user_id)); let data = pin::PinAddedService { room: pa_room, message, pinned_by, pinned_at: Utc::now(), }; bus.publish_room_event(room, "pin.added", &data).await?; Ok(Some(WsOutEvent::PinAdded { room: data.room.clone(), data })) } pub(super) async fn pin_remove( bus: &ChannelBus, user_id: Uuid, room: Uuid, message: Uuid, ) -> ChannelResult> { Self::ensure_room_access(bus, user_id, room).await?; Self::ensure_message_in_room(bus, room, message).await?; let result = db::sqlx::query( "DELETE FROM room_pin WHERE room = $1 AND message = $2", ) .bind(room) .bind(message) .execute(bus.inner.db.writer()) .await?; if result.rows_affected() == 0 { return Ok(None); } db::sqlx::query("UPDATE room_message SET pinned = false, updated_at = now() WHERE id = $1") .bind(message) .execute(bus.inner.db.writer()) .await?; let pr_room = bus.lookup_room(room).await.unwrap_or_else(|_| RoomInfo::unknown(room)); let removed_by = bus.lookup_user(user_id).await.unwrap_or_else(|_| UserInfo::unknown(user_id)); let data = pin::PinRemovedService { room: pr_room, message, removed_by, removed_at: Utc::now(), }; bus.publish_room_event(room, "pin.removed", &data).await?; Ok(Some(WsOutEvent::PinRemoved { room: data.room.clone(), data })) } }