use db::sqlx; use model::users::UserModel; use serde::Deserialize; use session::Session; use crate::{ AppService, error::AppError, issues::types::IssueAuthor, session_user, }; #[derive(Debug, Clone, Deserialize, utoipa::ToSchema)] pub struct AssignPrUser { pub username: String, } impl AppService { pub async fn pr_assign( &self, ctx: &Session, wk_name: &str, repo_name: &str, number: i64, params: AssignPrUser, ) -> Result, AppError> { let user_uid = session_user(ctx)?; let (repo_id, _) = self.pr_resolve_repo(ctx, wk_name, repo_name).await?; let pr = self.pr_resolve(repo_id, number).await?; let assignee = sqlx::query_as::<_, UserModel>( "SELECT id, username, display_name, avatar_url, website_url, allow_use, can_search, \ last_sign_in_at, created_at, updated_at \ FROM \"user\" WHERE username = $1 AND allow_use = true", ) .bind(¶ms.username) .fetch_optional(self.db.reader()) .await .map_err(|e| AppError::DatabaseError(e.to_string()))? .ok_or(AppError::UserNotFound)?; sqlx::query( "INSERT INTO pull_request_assignee (pull_request, \"user\", assigned_by, created_at) \ VALUES ($1, $2, $3, $4) ON CONFLICT (pull_request, \"user\") DO NOTHING", ) .bind(pr.id) .bind(assignee.id) .bind(user_uid) .bind(chrono::Utc::now()) .execute(self.db.writer()) .await .map_err(|e| AppError::DatabaseError(e.to_string()))?; self.pr_assignees_list(pr.id).await } pub async fn pr_unassign( &self, ctx: &Session, wk_name: &str, repo_name: &str, number: i64, username: &str, ) -> Result, AppError> { let _user_uid = session_user(ctx)?; let (repo_id, _) = self.pr_resolve_repo(ctx, wk_name, repo_name).await?; let pr = self.pr_resolve(repo_id, number).await?; let assignee = sqlx::query_as::<_, UserModel>( "SELECT id, username, display_name, avatar_url, website_url, allow_use, can_search, \ last_sign_in_at, created_at, updated_at \ FROM \"user\" WHERE username = $1", ) .bind(username) .fetch_optional(self.db.reader()) .await .map_err(|e| AppError::DatabaseError(e.to_string()))? .ok_or(AppError::UserNotFound)?; sqlx::query("DELETE FROM pull_request_assignee WHERE pull_request = $1 AND \"user\" = $2") .bind(pr.id) .bind(assignee.id) .execute(self.db.writer()) .await .map_err(|e| AppError::DatabaseError(e.to_string()))?; self.pr_assignees_list(pr.id).await } pub async fn pr_assignees_list( &self, pr_id: uuid::Uuid, ) -> Result, AppError> { let assignees = sqlx::query_as::<_, UserModel>( "SELECT u.id, u.username, u.display_name, u.avatar_url, u.website_url, u.allow_use, u.can_search, \ u.last_sign_in_at, u.created_at, u.updated_at \ FROM pull_request_assignee pa INNER JOIN \"user\" u ON u.id = pa.\"user\" \ WHERE pa.pull_request = $1 \ ORDER BY u.username ASC", ) .bind(pr_id) .fetch_all(self.db.reader()) .await .map_err(|e| AppError::DatabaseError(e.to_string()))?; Ok(assignees .into_iter() .map(|u| crate::issues::types::issue_author(u)) .collect()) } }