use models::pull_request::{pull_request_assignee, pull_requests}; use sea_orm::ActiveValue::Set; use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QueryOrder}; use serde::{Deserialize, Serialize}; use space::services::dto::UserDto; 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, pub created_at: OffsetDateTime, } impl PullService { pub async fn list_assignees(&self, pull_id: Uuid) -> Result, 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 .user_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, PullError> { authz::require_unlocked(pull)?; let uid = self.resolve_user_id(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() { pull_request_assignee::ActiveModel { id: Set(Uuid::now_v7()), pull_request_id: Set(pull.id), user_id: Set(uid), created_at: Set(OffsetDateTime::now_utc()), } .insert(self.db_write()) .await?; self.record_event( pull, Some(caller), EVENT_ASSIGNED, None, Some(uid.to_string()), ) .await?; } self.list_assignees(pull.id).await } pub async fn remove_assignee( &self, pull: &pull_requests::Model, caller: i64, reference: &str, ) -> Result, PullError> { authz::require_unlocked(pull)?; let uid = self.resolve_user_id(reference).await?; let deleted = pull_request_assignee::Entity::delete_many() .filter(pull_request_assignee::Column::PullRequestId.eq(pull.id)) .filter(pull_request_assignee::Column::UserId.eq(uid)) .exec(self.db_write()) .await?; if deleted.rows_affected > 0 { self.record_event( pull, Some(caller), EVENT_UNASSIGNED, None, Some(uid.to_string()), ) .await?; } self.list_assignees(pull.id).await } }