use db::conn::sea_orm::sea_query::OnConflict; use db::conn::sea_orm::*; use db::common::watch_mode::WatchMode; use db::issue::issue_watch as watch_entity; use time::OffsetDateTime; use uuid::Uuid; use crate::error::{IssueError, IssueResult}; use crate::features::IssueService; pub fn require_authenticated(actor: Uuid) -> IssueResult<()> { if actor.is_nil() { return Err(IssueError::Unauthorized("authentication required".into())); } Ok(()) } fn parse_mode(s: &str) -> IssueResult { Ok(match s { "normal" | "Normal" => WatchMode::Normal, "no_watch" | "NoWatch" => WatchMode::NoWatch, "watch" | "Watch" => WatchMode::Watch, "ignore" | "Ignore" => WatchMode::Ignore, other => { return Err(IssueError::BadRequest(format!( "invalid watch mode: {other}" ))); } }) } pub async fn load_my_watch( svc: &IssueService, issue_id: Uuid, user_id: Uuid, ) -> IssueResult { let db = svc.db.reader(); let row = watch_entity::Entity::find() .filter(watch_entity::COLUMN.issue_id.eq(issue_id)) .filter(watch_entity::COLUMN.user_id.eq(user_id)) .one(&db) .await? .ok_or_else(|| IssueError::NotFound("watch record".into()))?; Ok(row) } pub async fn upsert_watch( svc: &IssueService, actor: Uuid, channel_id: Uuid, issue_id: Uuid, mode_str: &str, ) -> IssueResult { require_authenticated(actor)?; crate::features::issue::usecase::load_issue(svc, channel_id, issue_id).await?; let mode = parse_mode(mode_str)?; let db = svc.db.writer(); let now = OffsetDateTime::now_utc(); let active: watch_entity::ActiveModel = watch_entity::ActiveModel::builder() .set_id(Uuid::new_v4()) .set_issue_id(issue_id) .set_user_id(actor) .set_mode(mode) .set_created_at(now) .set_updated_at(Some(now)) .into(); let saved = watch_entity::Entity::insert(active) .on_conflict( OnConflict::columns([watch_entity::COLUMN.issue_id, watch_entity::COLUMN.user_id]) .update_column(watch_entity::COLUMN.mode) .update_column(watch_entity::COLUMN.updated_at) .to_owned(), ) .exec_with_returning(&db) .await?; Ok(saved.into()) }