use crate::AppService; use crate::errors::AppError; use session::Session; use models::active_enums::MemberRole; use models::project::{project_members, projects}; use models::repos::repo; use sea_orm::*; use uuid::Uuid; pub enum RepoPermission { Read, Write, } impl AppService { pub async fn check_repo_permission( &self, ctx: &Session, namespace: &str, repo_name: &str, required_permission: RepoPermission, ) -> Result<(repo::Model, projects::Model), AppError> { let repository = repo::Entity::find() .filter(repo::Column::Namespace.eq(namespace)) .filter(repo::Column::RepoName.eq(repo_name)) .one(&self.db) .await? .ok_or(AppError::NotFound("Repository not found".to_string()))?; let project = projects::Entity::find() .filter(projects::Column::Name.eq(namespace)) .one(&self.db) .await? .ok_or(AppError::ProjectNotFound)?; if repository.project_uid != Some(project.uid) { return Err(AppError::NotFound( "Repository not found in project".to_string(), )); } let user_uid = ctx.user(); match required_permission { RepoPermission::Read => { if project.is_public && !repository.is_private { return Ok((repository, project)); } let user_uid = user_uid.ok_or(AppError::Unauthorized)?; let member = project_members::Entity::find() .filter(project_members::Column::ProjectId.eq(project.uid)) .filter(project_members::Column::UserId.eq(user_uid)) .one(&self.db) .await?; if member.is_some() { Ok((repository, project)) } else { Err(AppError::PermissionDenied) } } RepoPermission::Write => { let user_uid = user_uid.ok_or(AppError::Unauthorized)?; let member = project_members::Entity::find() .filter(project_members::Column::ProjectId.eq(project.uid)) .filter(project_members::Column::UserId.eq(user_uid)) .one(&self.db) .await? .ok_or(AppError::PermissionDenied)?; if member.scope == MemberRole::Owner || member.scope == MemberRole::Admin { Ok((repository, project)) } else { Err(AppError::PermissionDenied) } } } } pub async fn check_repo_read_permission( &self, ctx: &Session, namespace: &str, repo_name: &str, ) -> Result<(repo::Model, projects::Model), AppError> { self.check_repo_permission(ctx, namespace, repo_name, RepoPermission::Read) .await } pub async fn check_repo_write_permission( &self, ctx: &Session, namespace: &str, repo_name: &str, ) -> Result<(repo::Model, projects::Model), AppError> { self.check_repo_permission(ctx, namespace, repo_name, RepoPermission::Write) .await } pub async fn check_repo_permission_by_uid( &self, ctx: &Session, repo_uid: Uuid, required_permission: RepoPermission, ) -> Result<(repo::Model, projects::Model), AppError> { let repository = repo::Entity::find_by_id(repo_uid) .one(&self.db) .await? .ok_or(AppError::NotFound("Repository not found".to_string()))?; let project_uid = repository.project_uid.ok_or(AppError::NotFound( "Repository has no associated project".to_string(), ))?; let project = projects::Entity::find_by_id(project_uid) .one(&self.db) .await? .ok_or(AppError::ProjectNotFound)?; let user_uid = ctx.user(); match required_permission { RepoPermission::Read => { if project.is_public && !repository.is_private { return Ok((repository, project)); } let user_uid = user_uid.ok_or(AppError::Unauthorized)?; let member = project_members::Entity::find() .filter(project_members::Column::ProjectId.eq(project.uid)) .filter(project_members::Column::UserId.eq(user_uid)) .one(&self.db) .await?; if member.is_some() { Ok((repository, project)) } else { Err(AppError::PermissionDenied) } } RepoPermission::Write => { let user_uid = user_uid.ok_or(AppError::Unauthorized)?; let member = project_members::Entity::find() .filter(project_members::Column::ProjectId.eq(project.uid)) .filter(project_members::Column::UserId.eq(user_uid)) .one(&self.db) .await? .ok_or(AppError::PermissionDenied)?; if member.scope == MemberRole::Owner || member.scope == MemberRole::Admin { Ok((repository, project)) } else { Err(AppError::PermissionDenied) } } } } }