d5939db
use db::channel::channel_overwrite_role as role_ow_entity;
use db::channel::channel_overwrite_users as user_ow_entity;
use db::channel::channels as channel_entity;
use db::conn::sea_orm::*;
use db::space::space_members as space_member_entity;
use db::space::space_roles as space_role_entity;
use db::space::spaces as space_entity;
use uuid::Uuid;
use crate::error::{SpaceError, SpaceResult};
use crate::features::authz;
use crate::features::SpaceService;
use super::types::{RoleOverwriteView, SetRoleOverwriteCmd, SetUserOverwriteCmd, UserOverwriteView};
async fn member_space(svc: &SpaceService, caller: Uuid, space_id: Uuid) -> SpaceResult<space_entity::Model> {
let db = svc.db.reader();
let space = space_entity::Entity::find_by_id(space_id)
.one(&db)
.await?
.ok_or_else(|| SpaceError::NotFound(format!("space {space_id}")))?;
let member = space_member_entity::Entity::find_by_id((space_id, caller)).one(&db).await?;
let active = member
.map(|m| m.status == space_member_entity::MemberStatus::Active)
.unwrap_or(false);
if !active {
return Err(SpaceError::Forbidden("caller is not an active member of this space".to_string()));
}
Ok(space)
}
async fn channel_in_space<C>(
db: &C,
space_id: Uuid,
channel_id: Uuid,
) -> SpaceResult<channel_entity::Model>
where
C: ConnectionTrait,
{
let channel = channel_entity::Entity::find_by_id(channel_id)
.one(db)
.await?
.ok_or_else(|| SpaceError::NotFound(format!("channel {channel_id}")))?;
if channel.space_id != Some(space_id) {
return Err(SpaceError::NotFound(format!("channel {channel_id}")));
}
Ok(channel)
}
pub async fn set_role_overwrite(
svc: &SpaceService,
caller: Uuid,
space_id: Uuid,
channel_id: Uuid,
cmd: SetRoleOverwriteCmd,
) -> SpaceResult<RoleOverwriteView> {
authz::require_perm(svc, caller, space_id, authz::MANAGE_OVERWRITES).await?;
let db = svc.db.writer();
channel_in_space(&db, space_id, channel_id).await?;
let role = space_role_entity::Entity::find_by_id(cmd.role_id)
.one(&db)
.await?
.ok_or_else(|| SpaceError::NotFound(format!("role {}", cmd.role_id)))?;
if role.space_id != space_id {
return Err(SpaceError::NotFound(format!("role {}", cmd.role_id)));
}
let existing = role_ow_entity::Entity::find()
.filter(
role_ow_entity::Column::ChannelId
.eq(channel_id)
.and(role_ow_entity::Column::RoleId.eq(cmd.role_id)),
)
.one(&db)
.await?;
let saved: role_ow_entity::Model = if let Some(ow) = existing {
let mut active: role_ow_entity::ActiveModel = ow.into();
active.allow_mask = Set(cmd.allow_mask);
active.deny_mask = Set(cmd.deny_mask);
active.update(&db).await?
} else {
let active: role_ow_entity::ActiveModel = role_ow_entity::ActiveModel::builder()
.set_id(Uuid::new_v4())
.set_space_id(space_id)
.set_channel_id(channel_id)
.set_role_id(cmd.role_id)
.set_allow_mask(cmd.allow_mask)
.set_deny_mask(cmd.deny_mask)
.into();
active.insert(&db).await?
};
Ok(saved.into())
}
pub async fn remove_role_overwrite(
svc: &SpaceService,
caller: Uuid,
space_id: Uuid,
channel_id: Uuid,
role_id: Uuid,
) -> SpaceResult<()> {
authz::require_perm(svc, caller, space_id, authz::MANAGE_OVERWRITES).await?;
let db = svc.db.writer();
channel_in_space(&db, space_id, channel_id).await?;
let res = role_ow_entity::Entity::delete_many()
.filter(
role_ow_entity::Column::ChannelId
.eq(channel_id)
.and(role_ow_entity::Column::RoleId.eq(role_id)),
)
.exec(&db)
.await?;
if res.rows_affected == 0 {
return Err(SpaceError::NotFound(format!(
"role overwrite for role {role_id} in channel {channel_id}"
)));
}
Ok(())
}
pub async fn list_role_overwrites(
svc: &SpaceService,
caller: Uuid,
space_id: Uuid,
channel_id: Uuid,
) -> SpaceResult<Vec<RoleOverwriteView>> {
member_space(svc, caller, space_id).await?;
let db = svc.db.reader();
channel_in_space(&db, space_id, channel_id).await?;
let items = role_ow_entity::Entity::find()
.filter(role_ow_entity::Column::ChannelId.eq(channel_id))
.all(&db)
.await?;
Ok(items.into_iter().map(RoleOverwriteView::from).collect())
}
pub async fn set_user_overwrite(
svc: &SpaceService,
caller: Uuid,
space_id: Uuid,
channel_id: Uuid,
cmd: SetUserOverwriteCmd,
) -> SpaceResult<UserOverwriteView> {
authz::require_perm(svc, caller, space_id, authz::MANAGE_OVERWRITES).await?;
let db = svc.db.writer();
channel_in_space(&db, space_id, channel_id).await?;
let existing = user_ow_entity::Entity::find_by_id((channel_id, cmd.user_id))
.one(&db)
.await?;
let saved: user_ow_entity::Model = if let Some(ow) = existing {
let mut active: user_ow_entity::ActiveModel = ow.into();
active.allow_mask = Set(cmd.allow_mask);
active.deny_mask = Set(cmd.deny_mask);
active.update(&db).await?
} else {
let active: user_ow_entity::ActiveModel = user_ow_entity::ActiveModel::builder()
.set_channel_id(channel_id)
.set_user_id(cmd.user_id)
.set_allow_mask(cmd.allow_mask)
.set_deny_mask(cmd.deny_mask)
.into();
active.insert(&db).await?
};
Ok(saved.into())
}
pub async fn remove_user_overwrite(
svc: &SpaceService,
caller: Uuid,
space_id: Uuid,
channel_id: Uuid,
user_id: Uuid,
) -> SpaceResult<()> {
authz::require_perm(svc, caller, space_id, authz::MANAGE_OVERWRITES).await?;
let db = svc.db.writer();
channel_in_space(&db, space_id, channel_id).await?;
let res = user_ow_entity::Entity::delete_by_id((channel_id, user_id))
.exec(&db)
.await?;
if res.rows_affected == 0 {
return Err(SpaceError::NotFound(format!(
"user overwrite for user {user_id} in channel {channel_id}"
)));
}
Ok(())
}
pub async fn list_user_overwrites(
svc: &SpaceService,
caller: Uuid,
space_id: Uuid,
channel_id: Uuid,
) -> SpaceResult<Vec<UserOverwriteView>> {
member_space(svc, caller, space_id).await?;
let db = svc.db.reader();
channel_in_space(&db, space_id, channel_id).await?;
let items = user_ow_entity::Entity::find()
.filter(user_ow_entity::Column::ChannelId.eq(channel_id))
.all(&db)
.await?;
Ok(items.into_iter().map(UserOverwriteView::from).collect())
}