use serde::{Deserialize, Serialize}; use uuid::Uuid; use crate::error::AppError; use crate::models::channels::Stage; use crate::models::common::StagePrivacyLevel; use crate::service::ImService; use super::session::ImSession; #[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)] pub struct CreateStageParams { pub topic: String, pub privacy_level: Option, pub discoverable: Option, } #[derive(Deserialize, Serialize, Clone, Debug, utoipa::ToSchema)] pub struct UpdateStageParams { pub topic: Option, pub privacy_level: Option, pub discoverable: Option, } impl ImService { pub async fn stage_get( &self, _ctx: &ImSession, channel_id: Uuid, ) -> Result, AppError> { sqlx::query_as::<_, Stage>( "SELECT id, channel_id, topic, privacy_level, discoverable, \ started_by, started_at, ended_at, created_at, updated_at \ FROM stage WHERE channel_id = $1 AND ended_at IS NULL \ ORDER BY started_at DESC LIMIT 1", ) .bind(channel_id) .fetch_optional(self.ctx.db.reader()) .await .map_err(AppError::Database) } pub async fn stage_create( &self, ctx: &ImSession, channel_id: Uuid, params: CreateStageParams, ) -> Result { let now = chrono::Utc::now(); let privacy = params .privacy_level .as_deref() .and_then(|s| s.parse::().ok()) .filter(|s| *s != StagePrivacyLevel::Unknown) .unwrap_or(StagePrivacyLevel::GuildOnly); sqlx::query_as::<_, Stage>( "INSERT INTO stage \ (id, channel_id, topic, privacy_level, discoverable, \ started_by, started_at, created_at, updated_at) \ VALUES ($1, $2, $3, $4::stage_privacy_level, $5, $6, $7, $7, $7) \ RETURNING id, channel_id, topic, privacy_level, discoverable, \ started_by, started_at, ended_at, created_at, updated_at", ) .bind(Uuid::now_v7()) .bind(channel_id) .bind(¶ms.topic) .bind(privacy) .bind(params.discoverable.unwrap_or(false)) .bind(ctx.user) .bind(now) .fetch_one(self.ctx.db.writer()) .await .map_err(AppError::Database) } pub async fn stage_update( &self, _ctx: &ImSession, stage_id: Uuid, params: UpdateStageParams, ) -> Result { let now = chrono::Utc::now(); sqlx::query_as::<_, Stage>( "UPDATE stage SET \ topic = COALESCE($1, topic), \ privacy_level = COALESCE($2::stage_privacy_level, privacy_level), \ discoverable = COALESCE($3, discoverable), \ updated_at = $4 \ WHERE id = $5 \ RETURNING id, channel_id, topic, privacy_level, discoverable, \ started_by, started_at, ended_at, created_at, updated_at", ) .bind(params.topic.as_deref()) .bind(params.privacy_level.as_deref()) .bind(params.discoverable) .bind(now) .bind(stage_id) .fetch_one(self.ctx.db.writer()) .await .map_err(AppError::Database) } pub async fn stage_delete( &self, _ctx: &ImSession, stage_id: Uuid, ) -> Result<(), AppError> { let now = chrono::Utc::now(); sqlx::query( "UPDATE stage SET ended_at = $1, updated_at = $1 WHERE id = $2 AND ended_at IS NULL", ) .bind(now) .bind(stage_id) .execute(self.ctx.db.writer()) .await .map_err(AppError::Database)?; Ok(()) } }