e034b46
use db::conn::sea_orm::*;
use db::issue::issue as issue_entity;
use db::issue::issues as issues_entity;
use time::OffsetDateTime;
use uuid::Uuid;
use crate::error::{IssueError, IssueResult};
use crate::features::IssueService;
use crate::metrics;
use super::super::{CreateIssueOption, IssueView};
use super::helpers::require_authenticated;
pub async fn create_issue(
svc: &IssueService,
actor: Uuid,
channel_id: Uuid,
input: CreateIssueOption,
) -> IssueResult<IssueView> {
let _timer = metrics::Timer::start(metrics::FEATURE_ISSUES_CREATE);
let result: IssueResult<IssueView> = async {
require_authenticated(actor)?;
if input.title.trim().is_empty() || input.title.len() > svc.config.max_title_len {
return Err(IssueError::BadRequest(format!(
"title length must be in 1..={}",
svc.config.max_title_len
)));
}
if input.body.len() > svc.config.max_body_len {
return Err(IssueError::BadRequest(format!(
"body too long (max {})",
svc.config.max_body_len
)));
}
let db = svc.db.writer();
let txn = db.begin().await?;
let collection: issues_entity::Model = match issues_entity::Entity::find()
.filter(issues_entity::COLUMN.channel_id.eq(channel_id))
.order_by_asc(issues_entity::COLUMN.created_at)
.lock_exclusive()
.one(&txn)
.await?
{
Some(c) => c,
None => {
let now = OffsetDateTime::now_utc();
let new_collection_id = Uuid::now_v7();
let active: issues_entity::ActiveModel = issues_entity::ActiveModel::builder()
.set_id(new_collection_id)
.set_channel_id(channel_id)
.set_name(svc.config.default_collection_name.clone())
.set_icon(None)
.set_description(None)
.set_created_at(now)
.set_updated_at(None)
.into();
active.insert(&txn).await?
}
};
let max_id: Option<i32> = issue_entity::Entity::find()
.filter(issue_entity::COLUMN.collection_id.eq(collection.id))
.lock_exclusive()
.select_only()
.column_as(issue_entity::COLUMN.autoincrement_id.max(), "max")
.into_tuple::<Option<i32>>()
.one(&txn)
.await?
.flatten();
let next_id = max_id.map(|n| n + 1).unwrap_or(1);
let now = OffsetDateTime::now_utc();
let issue_id = Uuid::now_v7();
let active: issue_entity::ActiveModel = issue_entity::ActiveModel::builder()
.set_id(issue_id)
.set_collection_id(collection.id)
.set_autoincrement_id(next_id)
.set_author_id(actor)
.set_title(input.title.trim().to_string())
.set_description(input.description)
.set_body(input.body)
.set_milestone_id(input.milestone_id)
.set_created_at(now)
.set_updated_at(None)
.set_closed_at(None)
.into();
let saved = active.insert(&txn).await?;
txn.commit().await?;
Ok(IssueView::from(saved))
}
.await;
metrics::record_outcome(metrics::FEATURE_ISSUES_CREATE, &result);
result
}