use uuid::Uuid; use crate::error::AppError; use crate::models::common::Role; use crate::models::prs::PrReviewRequest; use crate::service::PrService; use crate::session::Session; impl PrService { pub async fn pr_requested_reviewers( &self, ctx: &Session, wk_name: &str, repo_name: &str, number: i64, ) -> Result, AppError> { let user_uid = ctx.user().ok_or(AppError::Unauthorized)?; let repo = self.resolve_repo(wk_name, repo_name).await?; self.ensure_repo_readable(user_uid, &repo).await?; let pr = self.resolve_pr(wk_name, repo_name, number).await?; self.ensure_pr_readable(user_uid, &pr).await?; sqlx::query_as::<_, PrReviewRequest>( "SELECT * FROM pr_review_request WHERE pull_request_id = $1 ORDER BY created_at ASC", ) .bind(pr.id) .fetch_all(self.ctx.db.reader()) .await .map_err(AppError::Database) } pub async fn pr_request_reviewers( &self, ctx: &Session, wk_name: &str, repo_name: &str, number: i64, reviewer_ids: Vec, ) -> Result, AppError> { let user_uid = ctx.user().ok_or(AppError::Unauthorized)?; let repo = self.resolve_repo(wk_name, repo_name).await?; self.ensure_repo_role_at_least(user_uid, &repo, Role::Member) .await?; let pr = self.resolve_pr(wk_name, repo_name, number).await?; self.ensure_pr_editable(user_uid, &pr).await?; let mut created = Vec::new(); for reviewer_id in reviewer_ids { let result = sqlx::query_as::<_, PrReviewRequest>( "INSERT INTO pr_review_request (id, pull_request_id, reviewer_id, requested_by, created_at) \ VALUES ($1, $2, $3, $4, NOW()) ON CONFLICT (pull_request_id, reviewer_id) DO NOTHING RETURNING *", ) .bind(Uuid::now_v7()) .bind(pr.id) .bind(reviewer_id) .bind(user_uid) .fetch_optional(self.ctx.db.writer()) .await .map_err(AppError::Database)?; if let Some(r) = result { created.push(r); } } Ok(created) } pub async fn pr_remove_requested_reviewer( &self, ctx: &Session, wk_name: &str, repo_name: &str, number: i64, reviewer_id: Uuid, ) -> Result<(), AppError> { let user_uid = ctx.user().ok_or(AppError::Unauthorized)?; let repo = self.resolve_repo(wk_name, repo_name).await?; self.ensure_repo_role_at_least(user_uid, &repo, Role::Member) .await?; let pr = self.resolve_pr(wk_name, repo_name, number).await?; self.ensure_pr_editable(user_uid, &pr).await?; sqlx::query( "DELETE FROM pr_review_request WHERE pull_request_id = $1 AND reviewer_id = $2", ) .bind(pr.id) .bind(reviewer_id) .execute(self.ctx.db.writer()) .await .map_err(AppError::Database)?; Ok(()) } }