use db::conn::sea_orm::*; use db::issue::milestone as milestone_entity; 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::super::issue::usecase::load_issue_collection; use super::super::{CreateMilestoneOption, MilestoneView}; use super::helpers::require_authenticated; pub async fn create_milestone( svc: &IssueService, actor: Uuid, channel_id: Uuid, input: CreateMilestoneOption, ) -> IssueResult { require_authenticated(actor)?; let name = input.name.trim().to_string(); if name.is_empty() || name.len() > svc.config.max_milestone_title_len { return Err(IssueError::BadRequest(format!( "milestone name length must be in 1..={}", svc.config.max_milestone_title_len ))); } if let Some(ref d) = input.description && d.len() > svc.config.max_milestone_description_len { return Err(IssueError::BadRequest("milestone description too long".into())); } let due_at = match input.due_at.as_deref() { Some(s) => Some( OffsetDateTime::parse(s, &Rfc3339) .map_err(|e| IssueError::BadRequest(format!("invalid due_at: {e}")))?, ), None => None, }; let collection = load_issue_collection(svc, channel_id).await?; let db = svc.db.writer(); let now = OffsetDateTime::now_utc(); let id = Uuid::new_v4(); let active: milestone_entity::ActiveModel = milestone_entity::ActiveModel::builder() .set_id(id) .set_collection_id(collection.id) .set_name(name) .set_description(input.description) .set_is_closed(false) .set_due_at(due_at) .set_num_issues(0) .set_num_closed_issues(0) .set_created_at(now) .set_updated_at(None) .into(); let saved = active.insert(&db).await?; Ok(MilestoneView::from(saved)) }