eeff292
use api::users::UserDto;
use models::pull_request::{pull_request_assignee, pull_requests};
use sea_orm::ActiveValue::Set;
use sea_orm::{
ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, TransactionTrait,
};
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
use utoipa::ToSchema;
use uuid::Uuid;
use crate::errors::PullError;
use crate::services::events::{EVENT_ASSIGNED, EVENT_UNASSIGNED};
use crate::services::reviews;
use crate::services::service::PullService;
use crate::share::authz;
#[derive(Debug, Clone, Deserialize, ToSchema)]
pub struct AssignCmd {
/// 用户名或 UUID。
pub user: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PullAssigneeDto {
pub id: Uuid,
pub user: Option<UserDto>,
pub created_at: OffsetDateTime,
}
impl PullService {
pub async fn list_assignees(&self, pull_id: Uuid) -> Result<Vec<PullAssigneeDto>, PullError> {
let rows = pull_request_assignee::Entity::find()
.filter(pull_request_assignee::Column::PullRequestId.eq(pull_id))
.order_by_asc(pull_request_assignee::Column::CreatedAt)
.all(self.db_read())
.await?;
let users = self
.actors
.briefs(&reviews::unique_ids(rows.iter().map(|row| row.user_id)))
.await?;
Ok(rows
.iter()
.map(|row| PullAssigneeDto {
id: row.id,
user: users.get(&row.user_id).cloned(),
created_at: row.created_at,
})
.collect())
}
pub async fn add_assignee(
&self,
pull: &pull_requests::Model,
caller: i64,
reference: &str,
) -> Result<Vec<PullAssigneeDto>, PullError> {
authz::require_unlocked(pull)?;
let uid = self.actors.resolve(reference).await?;
let existing = pull_request_assignee::Entity::find()
.filter(pull_request_assignee::Column::PullRequestId.eq(pull.id))
.filter(pull_request_assignee::Column::UserId.eq(uid))
.one(self.db_read())
.await?;
if existing.is_none() {
let event_pull = pull.clone();
let this = self.clone();
self.db_write()
.transaction::<_, (), PullError>(move |tx| {
Box::pin(async move {
pull_request_assignee::ActiveModel {
id: Set(Uuid::now_v7()),
pull_request_id: Set(event_pull.id),
user_id: Set(uid),
created_at: Set(OffsetDateTime::now_utc()),
}
.insert(tx)
.await?;
this.record_event_with(
tx,
&event_pull,
Some(caller),
EVENT_ASSIGNED,
None,
Some(uid.to_string()),
)
.await?;
Ok(())
})
})
.await?;
}
self.list_assignees(pull.id).await
}
pub async fn remove_assignee(
&self,
pull: &pull_requests::Model,
caller: i64,
reference: &str,
) -> Result<Vec<PullAssigneeDto>, PullError> {
authz::require_unlocked(pull)?;
let uid = self.actors.resolve(reference).await?;
let event_pull = pull.clone();
let this = self.clone();
self.db_write()
.transaction::<_, (), PullError>(move |tx| {
Box::pin(async move {
let deleted = pull_request_assignee::Entity::delete_many()
.filter(pull_request_assignee::Column::PullRequestId.eq(event_pull.id))
.filter(pull_request_assignee::Column::UserId.eq(uid))
.exec(tx)
.await?;
if deleted.rows_affected > 0 {
this.record_event_with(
tx,
&event_pull,
Some(caller),
EVENT_UNASSIGNED,
None,
Some(uid.to_string()),
)
.await?;
}
Ok(())
})
})
.await?;
self.list_assignees(pull.id).await
}
}