feat(issues): add milestone usecase create
zhenyi committed
Added lib/issues/features/milestone/usecase/create.rs lib/issues/features/milestone/usecase/create.rs +60 −0 View lib/issues/features/milestone/usecase/create.rs
@@ -0,0 +1,60 @@
1use db::conn::sea_orm::*;
2use db::issue::milestone as milestone_entity;
3use time::OffsetDateTime;
4use time::format_description::well_known::Rfc3339;
5use uuid::Uuid;
6
7use crate::error::{IssueError, IssueResult};
8use crate::features::IssueService;
9
10use super::super::super::issue::usecase::load_issue_collection;
11use super::super::types::{CreateMilestoneOption, MilestoneView};
12use super::helpers::require_authenticated;
13
14pub async fn create_milestone(
15 svc: &IssueService,
16 actor: Uuid,
17 channel_id: Uuid,
18 input: CreateMilestoneOption,
19) -> IssueResult<MilestoneView> {
20 require_authenticated(actor)?;
21
22 let name = input.name.trim().to_string();
23 if name.is_empty() || name.len() > svc.config.max_milestone_title_len {
24 return Err(IssueError::BadRequest(format!(
25 "milestone name length must be in 1..={}",
26 svc.config.max_milestone_title_len
27 )));
28 }
29 if let Some(ref d) = input.description
30 && d.len() > svc.config.max_milestone_description_len
31 {
32 return Err(IssueError::BadRequest("milestone description too long".into()));
33 }
34 let due_at = match input.due_at.as_deref() {
35 Some(s) => Some(
36 OffsetDateTime::parse(s, &Rfc3339)
37 .map_err(|e| IssueError::BadRequest(format!("invalid due_at: {e}")))?,
38 ),
39 None => None,
40 };
41
42 let collection = load_issue_collection(svc, channel_id).await?;
43 let db = svc.db.writer();
44 let now = OffsetDateTime::now_utc();
45 let id = Uuid::new_v4();
46 let active: milestone_entity::ActiveModel = milestone_entity::ActiveModel::builder()
47 .set_id(id)
48 .set_collection_id(collection.id)
49 .set_name(name)
50 .set_description(input.description)
51 .set_is_closed(false)
52 .set_due_at(due_at)
53 .set_num_issues(0)
54 .set_num_closed_issues(0)
55 .set_created_at(now)
56 .set_updated_at(None)
57 .into();
58 let saved = active.insert(&db).await?;
59 Ok(MilestoneView::from(saved))
60}
No newline at end of file