Skip to content
Clone
eeff292
118 lines 4.3 KB Rust
use sea_orm::{ColumnTrait, EntityTrait, QueryFilter};
use uuid::Uuid;
use crate::access::{Capability, require};
use crate::errors::{SpaceError, SpaceResult};
use crate::services::service::SpaceService;
fn access_error(error: api::AccessError) -> SpaceError {
SpaceError::Internal(error.to_string())
}
impl SpaceService {
async fn space_of(&self, space_id: Uuid) -> SpaceResult<Option<crate::access::Space>> {
match self.access.by_id(space_id).await {
Ok(space) => Ok(Some(space)),
Err(api::AccessError::NotFound) => Ok(None),
Err(error) => Err(access_error(error)),
}
}
pub async fn authorize_internal_repo(&self, user_id: i64, repo_id: Uuid) -> SpaceResult<bool> {
let repo = models::repo::repos::Entity::find_by_id(repo_id)
.one(self.access.database.read())
.await
.map_err(|error| SpaceError::Internal(error.to_string()))?
.ok_or(SpaceError::NotFound)?;
let Some(space) = self.space_of(repo.space_id).await? else {
return Ok(false);
};
space
.can(
user_id,
Capability::RepositoryRead {
repository: repo.id,
private: repo.is_private,
},
)
.await
.map_err(access_error)
}
pub async fn authorize_internal_issue(
&self,
user_id: i64,
issue_id: Uuid,
) -> SpaceResult<bool> {
let issue = models::issue::issues::Entity::find_by_id(issue_id)
.one(self.access.database.read())
.await
.map_err(|error| SpaceError::Internal(error.to_string()))?
.ok_or(SpaceError::NotFound)?;
let Some(space) = self.space_of(issue.space_id).await? else {
return Ok(false);
};
require(&space, user_id, Capability::Read)
.await
.map(|()| true)
.or_else(|error| match error {
api::AccessError::Forbidden => Ok(false),
other => Err(access_error(other)),
})
}
pub async fn authorize_internal_pull(&self, user_id: i64, pull_id: Uuid) -> SpaceResult<bool> {
let pull = models::pull_request::pull_requests::Entity::find_by_id(pull_id)
.one(self.access.database.read())
.await
.map_err(|error| SpaceError::Internal(error.to_string()))?
.ok_or(SpaceError::NotFound)?;
let repo = models::repo::repos::Entity::find_by_id(pull.repo_id)
.one(self.access.database.read())
.await
.map_err(|error| SpaceError::Internal(error.to_string()))?
.ok_or(SpaceError::NotFound)?;
let Some(space) = self.space_of(repo.space_id).await? else {
return Ok(false);
};
space
.can(
user_id,
Capability::RepositoryRead {
repository: repo.id,
private: repo.is_private,
},
)
.await
.map_err(access_error)
}
pub async fn authorize_internal_space(
&self,
user_id: i64,
space_id: Uuid,
) -> SpaceResult<bool> {
let space = self.access.by_id(space_id).await.map_err(access_error)?;
require(&space, user_id, Capability::Read)
.await
.map(|()| true)
.or_else(|error| match error {
api::AccessError::Forbidden => Ok(false),
other => Err(access_error(other)),
})
}
}
impl SpaceService {
/// 内部事件扇出:列出空间(组织)的有效成员 id(未退出、未封禁)。
pub async fn internal_space_member_ids(&self, space_id: Uuid) -> SpaceResult<Vec<i64>> {
let rows = models::space::space_members::Entity::find()
.filter(models::space::space_members::Column::OrganizationId.eq(space_id))
.filter(models::space::space_members::Column::LeftAt.is_null())
.filter(models::space::space_members::Column::BannedAt.is_null())
.all(self.access.database.read())
.await
.map_err(|error| SpaceError::Internal(error.to_string()))?;
Ok(rows.into_iter().map(|row| row.user_id).collect())
}
}