use db::sqlx; use session::Session; use crate::{AppService, error::AppError, session_user}; impl AppService { pub async fn git_repo_watch( &self, ctx: &Session, wk_name: &str, repo_name: &str, level: Option, ) -> Result { let user_uid = session_user(ctx)?; let repo = self.git_require_member(ctx, wk_name, repo_name).await?; let level = level.unwrap_or_else(|| "participating".to_string()); sqlx::query( "INSERT INTO repo_watch (repo, \"user\", \"level\", created_at, updated_at) \ VALUES ($1, $2, $3, $4, $5) \ ON CONFLICT (repo, \"user\") DO UPDATE SET level = $3, updated_at = $5", ) .bind(repo.id) .bind(user_uid) .bind(&level) .bind(chrono::Utc::now()) .bind(chrono::Utc::now()) .execute(self.db.writer()) .await .map_err(|e| AppError::DatabaseError(e.to_string()))?; let count: (i64,) = sqlx::query_as( "SELECT COUNT(*) FROM repo_watch WHERE repo = $1", ) .bind(repo.id) .fetch_one(self.db.reader()) .await .map_err(|e| AppError::DatabaseError(e.to_string()))?; Ok(serde_json::json!({ "watching": true, "count": count.0, "level": level })) } pub async fn git_repo_unwatch( &self, ctx: &Session, wk_name: &str, repo_name: &str, ) -> Result { let user_uid = session_user(ctx)?; let repo = self.git_require_member(ctx, wk_name, repo_name).await?; sqlx::query( "DELETE FROM repo_watch WHERE repo = $1 AND \"user\" = $2", ) .bind(repo.id) .bind(user_uid) .execute(self.db.writer()) .await .map_err(|e| AppError::DatabaseError(e.to_string()))?; let count: (i64,) = sqlx::query_as( "SELECT COUNT(*) FROM repo_watch WHERE repo = $1", ) .bind(repo.id) .fetch_one(self.db.reader()) .await .map_err(|e| AppError::DatabaseError(e.to_string()))?; Ok(serde_json::json!({ "watching": false, "count": count.0 })) } pub async fn git_repo_watch_status( &self, ctx: &Session, wk_name: &str, repo_name: &str, ) -> Result { let user_uid = session_user(ctx)?; let repo = self.git_require_member(ctx, wk_name, repo_name).await?; let watch: Option<(bool, String)> = sqlx::query_as( "SELECT EXISTS(SELECT 1 FROM repo_watch WHERE repo = $1 AND \"user\" = $2), \ COALESCE((SELECT level FROM repo_watch WHERE repo = $1 AND \"user\" = $2), '')", ) .bind(repo.id) .bind(user_uid) .fetch_optional(self.db.reader()) .await .map_err(|e| AppError::DatabaseError(e.to_string()))?; let count: (i64,) = sqlx::query_as( "SELECT COUNT(*) FROM repo_watch WHERE repo = $1", ) .bind(repo.id) .fetch_one(self.db.reader()) .await .map_err(|e| AppError::DatabaseError(e.to_string()))?; Ok(serde_json::json!({ "watching": watch.as_ref().map(|(w, _)| *w).unwrap_or(false), "count": count.0, "level": watch.map(|(_, l)| l).unwrap_or_default(), })) } }