use db::conn::sea_orm::*; use time::OffsetDateTime; use time::format_description::well_known::Rfc3339; use uuid::Uuid; use crate::error::{IssueError, IssueResult}; use crate::features::IssueService; use super::super::types::{MilestoneView, UpdateMilestoneOption}; use super::helpers::{load_milestone, require_authenticated}; pub async fn update_milestone( svc: &IssueService, actor: Uuid, channel_id: Uuid, milestone_id: Uuid, input: UpdateMilestoneOption, ) -> IssueResult { require_authenticated(actor)?; let cur = load_milestone(svc, channel_id, milestone_id).await?; if let Some(ref n) = input.name { let trimmed = n.trim().to_string(); if trimmed.is_empty() || trimmed.len() > svc.config.max_milestone_title_len { return Err(IssueError::BadRequest("invalid milestone name".into())); } } if let Some(Some(d)) = input.description.as_ref() && d.len() > svc.config.max_milestone_description_len { return Err(IssueError::BadRequest("description too long".into())); } let due_at = match input.due_at { Some(Some(s)) => Some( OffsetDateTime::parse(&s, &Rfc3339) .map_err(|e| IssueError::BadRequest(format!("invalid due_at: {e}")))?, ), Some(None) => None, None => cur.due_at, }; let db = svc.db.writer(); let mut active: db::issue::milestone::ActiveModel = cur.into(); if let Some(n) = input.name { active.name = Set(n.trim().to_string()); } if let Some(opt) = input.description { active.description = Set(opt); } active.due_at = Set(due_at); if let Some(c) = input.is_closed { active.is_closed = Set(c); } active.updated_at = Set(Some(OffsetDateTime::now_utc())); let saved = active.update(&db).await?; Ok(MilestoneView::from(saved)) }