forked from didirus/AstralRinth
Organizations (#712)
* untested, unformatted, un-refactored * minor simplification * simplification fix * refactoring, changes * some fixes * fixes, refactoring * missed cache * revs * revs - more! * removed donation links; added all org members to route * renamed slug to title --------- Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
use crate::auth::{get_user_from_headers, is_authorized};
|
||||
use crate::database::models::notification_item::NotificationBuilder;
|
||||
use crate::database::models::TeamMember;
|
||||
use crate::models::ids::ProjectId;
|
||||
use crate::database::models::team_item::TeamAssociationId;
|
||||
use crate::database::models::{Organization, Team, TeamMember};
|
||||
use crate::database::Project;
|
||||
use crate::models::notifications::NotificationBody;
|
||||
use crate::models::pats::Scopes;
|
||||
use crate::models::teams::{Permissions, TeamId};
|
||||
use crate::models::teams::{OrganizationPermissions, ProjectPermissions, TeamId};
|
||||
use crate::models::users::UserId;
|
||||
use crate::queue::session::AuthQueue;
|
||||
use crate::routes::ApiError;
|
||||
@@ -27,6 +28,10 @@ pub fn config(cfg: &mut web::ServiceConfig) {
|
||||
);
|
||||
}
|
||||
|
||||
// Returns all members of a project,
|
||||
// including the team members of the project's team, but
|
||||
// also the members of the organization's team if the project is associated with an organization
|
||||
// (Unlike team_members_get_project, which only returns the members of the project's team)
|
||||
#[get("{id}/members")]
|
||||
pub async fn team_members_get_project(
|
||||
req: HttpRequest,
|
||||
@@ -53,9 +58,85 @@ pub async fn team_members_get_project(
|
||||
if !is_authorized(&project.inner, ¤t_user, &pool).await? {
|
||||
return Ok(HttpResponse::NotFound().body(""));
|
||||
}
|
||||
let mut members_data =
|
||||
TeamMember::get_from_team_full(project.inner.team_id, &**pool, &redis).await?;
|
||||
let mut member_user_ids = members_data.iter().map(|x| x.user_id).collect::<Vec<_>>();
|
||||
|
||||
// Adds the organization's team members to the list of members, if the project is associated with an organization
|
||||
if let Some(oid) = project.inner.organization_id {
|
||||
let organization_data = Organization::get_id(oid, &**pool, &redis).await?;
|
||||
if let Some(organization_data) = organization_data {
|
||||
let org_team =
|
||||
TeamMember::get_from_team_full(organization_data.team_id, &**pool, &redis)
|
||||
.await?;
|
||||
for member in org_team {
|
||||
if !member_user_ids.contains(&member.user_id) {
|
||||
member_user_ids.push(member.user_id);
|
||||
members_data.push(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let users =
|
||||
crate::database::models::User::get_many_ids(&member_user_ids, &**pool, &redis).await?;
|
||||
|
||||
let user_id = current_user.as_ref().map(|x| x.id.into());
|
||||
|
||||
let logged_in = current_user
|
||||
.and_then(|user| {
|
||||
members_data
|
||||
.iter()
|
||||
.find(|x| x.user_id == user.id.into() && x.accepted)
|
||||
})
|
||||
.is_some();
|
||||
let team_members: Vec<_> = members_data
|
||||
.into_iter()
|
||||
.filter(|x| {
|
||||
logged_in
|
||||
|| x.accepted
|
||||
|| user_id
|
||||
.map(|y: crate::database::models::UserId| y == x.user_id)
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.flat_map(|data| {
|
||||
users.iter().find(|x| x.id == data.user_id).map(|user| {
|
||||
crate::models::teams::TeamMember::from(data, user.clone(), !logged_in)
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
Ok(HttpResponse::Ok().json(team_members))
|
||||
} else {
|
||||
Ok(HttpResponse::NotFound().body(""))
|
||||
}
|
||||
}
|
||||
|
||||
#[get("{id}/members")]
|
||||
pub async fn team_members_get_organization(
|
||||
req: HttpRequest,
|
||||
info: web::Path<(String,)>,
|
||||
pool: web::Data<PgPool>,
|
||||
redis: web::Data<deadpool_redis::Pool>,
|
||||
session_queue: web::Data<AuthQueue>,
|
||||
) -> Result<HttpResponse, ApiError> {
|
||||
let string = info.into_inner().0;
|
||||
let organization_data =
|
||||
crate::database::models::Organization::get(&string, &**pool, &redis).await?;
|
||||
|
||||
if let Some(organization) = organization_data {
|
||||
let current_user = get_user_from_headers(
|
||||
&req,
|
||||
&**pool,
|
||||
&redis,
|
||||
&session_queue,
|
||||
Some(&[Scopes::ORGANIZATION_READ]),
|
||||
)
|
||||
.await
|
||||
.map(|x| x.1)
|
||||
.ok();
|
||||
|
||||
let members_data =
|
||||
TeamMember::get_from_team_full(project.inner.team_id, &**pool, &redis).await?;
|
||||
TeamMember::get_from_team_full(organization.team_id, &**pool, &redis).await?;
|
||||
let users = crate::database::models::User::get_many_ids(
|
||||
&members_data.iter().map(|x| x.user_id).collect::<Vec<_>>(),
|
||||
&**pool,
|
||||
@@ -95,6 +176,7 @@ pub async fn team_members_get_project(
|
||||
}
|
||||
}
|
||||
|
||||
// Returns all members of a team, but not necessarily those of a project-team's organization (unlike team_members_get_project)
|
||||
#[get("{id}/members")]
|
||||
pub async fn team_members_get(
|
||||
req: HttpRequest,
|
||||
@@ -258,6 +340,7 @@ pub async fn join_team(
|
||||
current_user.id.into(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
Some(true),
|
||||
None,
|
||||
None,
|
||||
@@ -290,8 +373,10 @@ pub struct NewTeamMember {
|
||||
pub user_id: UserId,
|
||||
#[serde(default = "default_role")]
|
||||
pub role: String,
|
||||
#[serde(default = "Permissions::default")]
|
||||
pub permissions: Permissions,
|
||||
#[serde(default)]
|
||||
pub permissions: ProjectPermissions,
|
||||
#[serde(default)]
|
||||
pub organization_permissions: Option<OrganizationPermissions>,
|
||||
#[serde(default)]
|
||||
pub payouts_split: Decimal,
|
||||
#[serde(default = "default_ordering")]
|
||||
@@ -320,23 +405,76 @@ pub async fn add_team_member(
|
||||
)
|
||||
.await?
|
||||
.1;
|
||||
let member = TeamMember::get_from_user_id(team_id, current_user.id.into(), &**pool)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
ApiError::CustomAuthentication(
|
||||
"You don't have permission to edit members of this team".to_string(),
|
||||
)
|
||||
})?;
|
||||
|
||||
if !member.permissions.contains(Permissions::MANAGE_INVITES) {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You don't have permission to invite users to this team".to_string(),
|
||||
));
|
||||
}
|
||||
if !member.permissions.contains(new_member.permissions) {
|
||||
return Err(ApiError::InvalidInput(
|
||||
"The new member has permissions that you don't have".to_string(),
|
||||
));
|
||||
let team_association = Team::get_association(team_id, &**pool)
|
||||
.await?
|
||||
.ok_or_else(|| ApiError::InvalidInput("The team specified does not exist".to_string()))?;
|
||||
let member = TeamMember::get_from_user_id(team_id, current_user.id.into(), &**pool).await?;
|
||||
|
||||
match team_association {
|
||||
// If team is associated with a project, check if they have permissions to invite users to that project
|
||||
TeamAssociationId::Project(pid) => {
|
||||
let organization =
|
||||
Organization::get_associated_organization_project_id(pid, &**pool).await?;
|
||||
let organization_team_member = if let Some(organization) = &organization {
|
||||
TeamMember::get_from_user_id(organization.team_id, current_user.id.into(), &**pool)
|
||||
.await?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let permissions = ProjectPermissions::get_permissions_by_role(
|
||||
¤t_user.role,
|
||||
&member,
|
||||
&organization_team_member,
|
||||
)
|
||||
.unwrap_or_default();
|
||||
|
||||
if !permissions.contains(ProjectPermissions::MANAGE_INVITES) {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You don't have permission to invite users to this team".to_string(),
|
||||
));
|
||||
}
|
||||
if !permissions.contains(new_member.permissions) {
|
||||
return Err(ApiError::InvalidInput(
|
||||
"The new member has permissions that you don't have".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if new_member.organization_permissions.is_some() {
|
||||
return Err(ApiError::InvalidInput(
|
||||
"The organization permissions of a project team member cannot be set"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
// If team is associated with an organization, check if they have permissions to invite users to that organization
|
||||
TeamAssociationId::Organization(_) => {
|
||||
let organization_permissions =
|
||||
OrganizationPermissions::get_permissions_by_role(¤t_user.role, &member)
|
||||
.unwrap_or_default();
|
||||
println!("{:?}", organization_permissions);
|
||||
if !organization_permissions.contains(OrganizationPermissions::MANAGE_INVITES) {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You don't have permission to invite users to this organization".to_string(),
|
||||
));
|
||||
}
|
||||
if !organization_permissions
|
||||
.contains(new_member.organization_permissions.unwrap_or_default())
|
||||
{
|
||||
return Err(ApiError::InvalidInput(
|
||||
"The new member has organization permissions that you don't have".to_string(),
|
||||
));
|
||||
}
|
||||
if !organization_permissions
|
||||
.contains(OrganizationPermissions::EDIT_MEMBER_DEFAULT_PERMISSIONS)
|
||||
&& !new_member.permissions.is_empty()
|
||||
{
|
||||
return Err(ApiError::InvalidInput(
|
||||
"You do not have permission to give this user default project permissions."
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if new_member.role == crate::models::teams::OWNER_ROLE {
|
||||
@@ -365,8 +503,7 @@ pub async fn add_team_member(
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
crate::database::models::User::get_id(member.user_id, &**pool, &redis)
|
||||
crate::database::models::User::get_id(new_member.user_id.into(), &**pool, &redis)
|
||||
.await?
|
||||
.ok_or_else(|| ApiError::InvalidInput("An invalid User ID specified".to_string()))?;
|
||||
|
||||
@@ -377,6 +514,7 @@ pub async fn add_team_member(
|
||||
user_id: new_member.user_id.into(),
|
||||
role: new_member.role.clone(),
|
||||
permissions: new_member.permissions,
|
||||
organization_permissions: new_member.organization_permissions,
|
||||
accepted: false,
|
||||
payouts_split: new_member.payouts_split,
|
||||
ordering: new_member.ordering,
|
||||
@@ -384,27 +522,32 @@ pub async fn add_team_member(
|
||||
.insert(&mut transaction)
|
||||
.await?;
|
||||
|
||||
let result = sqlx::query!(
|
||||
"
|
||||
SELECT m.id
|
||||
FROM mods m
|
||||
WHERE m.team_id = $1
|
||||
",
|
||||
team_id as crate::database::models::ids::TeamId
|
||||
)
|
||||
.fetch_one(&**pool)
|
||||
.await?;
|
||||
|
||||
NotificationBuilder {
|
||||
body: NotificationBody::TeamInvite {
|
||||
project_id: ProjectId(result.id as u64),
|
||||
team_id: team_id.into(),
|
||||
invited_by: current_user.id,
|
||||
role: new_member.role.clone(),
|
||||
},
|
||||
match team_association {
|
||||
TeamAssociationId::Project(pid) => {
|
||||
NotificationBuilder {
|
||||
body: NotificationBody::TeamInvite {
|
||||
project_id: pid.into(),
|
||||
team_id: team_id.into(),
|
||||
invited_by: current_user.id,
|
||||
role: new_member.role.clone(),
|
||||
},
|
||||
}
|
||||
.insert(new_member.user_id.into(), &mut transaction)
|
||||
.await?;
|
||||
}
|
||||
TeamAssociationId::Organization(oid) => {
|
||||
NotificationBuilder {
|
||||
body: NotificationBody::OrganizationInvite {
|
||||
organization_id: oid.into(),
|
||||
team_id: team_id.into(),
|
||||
invited_by: current_user.id,
|
||||
role: new_member.role.clone(),
|
||||
},
|
||||
}
|
||||
.insert(new_member.user_id.into(), &mut transaction)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
.insert(new_member.user_id.into(), &mut transaction)
|
||||
.await?;
|
||||
|
||||
TeamMember::clear_cache(team_id, &redis).await?;
|
||||
|
||||
@@ -415,7 +558,8 @@ pub async fn add_team_member(
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct EditTeamMember {
|
||||
pub permissions: Option<Permissions>,
|
||||
pub permissions: Option<ProjectPermissions>,
|
||||
pub organization_permissions: Option<OrganizationPermissions>,
|
||||
pub role: Option<String>,
|
||||
pub payouts_split: Option<Decimal>,
|
||||
pub ordering: Option<i64>,
|
||||
@@ -443,13 +587,11 @@ pub async fn edit_team_member(
|
||||
)
|
||||
.await?
|
||||
.1;
|
||||
let member = TeamMember::get_from_user_id(id, current_user.id.into(), &**pool)
|
||||
|
||||
let team_association = Team::get_association(id, &**pool)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
ApiError::CustomAuthentication(
|
||||
"You don't have permission to edit members of this team".to_string(),
|
||||
)
|
||||
})?;
|
||||
.ok_or_else(|| ApiError::InvalidInput("The team specified does not exist".to_string()))?;
|
||||
let member = TeamMember::get_from_user_id(id, current_user.id.into(), &**pool).await?;
|
||||
let edit_member_db = TeamMember::get_from_user_id_pending(id, user_id, &**pool)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
@@ -468,17 +610,72 @@ pub async fn edit_team_member(
|
||||
));
|
||||
}
|
||||
|
||||
if !member.permissions.contains(Permissions::EDIT_MEMBER) {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You don't have permission to edit members of this team".to_string(),
|
||||
));
|
||||
}
|
||||
match team_association {
|
||||
TeamAssociationId::Project(project_id) => {
|
||||
let organization =
|
||||
Organization::get_associated_organization_project_id(project_id, &**pool).await?;
|
||||
let organization_team_member = if let Some(organization) = &organization {
|
||||
TeamMember::get_from_user_id(organization.team_id, current_user.id.into(), &**pool)
|
||||
.await?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let permissions = ProjectPermissions::get_permissions_by_role(
|
||||
¤t_user.role,
|
||||
&member.clone(),
|
||||
&organization_team_member,
|
||||
)
|
||||
.unwrap_or_default();
|
||||
if !permissions.contains(ProjectPermissions::EDIT_MEMBER) {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You don't have permission to edit members of this team".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(new_permissions) = edit_member.permissions {
|
||||
if !member.permissions.contains(new_permissions) {
|
||||
return Err(ApiError::InvalidInput(
|
||||
"The new permissions have permissions that you don't have".to_string(),
|
||||
));
|
||||
if let Some(new_permissions) = edit_member.permissions {
|
||||
if !permissions.contains(new_permissions) {
|
||||
return Err(ApiError::InvalidInput(
|
||||
"The new permissions have permissions that you don't have".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if edit_member.organization_permissions.is_some() {
|
||||
return Err(ApiError::InvalidInput(
|
||||
"The organization permissions of a project team member cannot be edited"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
TeamAssociationId::Organization(_) => {
|
||||
let organization_permissions =
|
||||
OrganizationPermissions::get_permissions_by_role(¤t_user.role, &member)
|
||||
.unwrap_or_default();
|
||||
|
||||
if !organization_permissions.contains(OrganizationPermissions::EDIT_MEMBER) {
|
||||
return Err(ApiError::InvalidInput(
|
||||
"You don't have permission to edit organization permissions".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(new_permissions) = edit_member.organization_permissions {
|
||||
if !organization_permissions.contains(new_permissions) {
|
||||
return Err(ApiError::InvalidInput(
|
||||
"The new organization permissions have permissions that you don't have"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if edit_member.permissions.is_some()
|
||||
&& !organization_permissions
|
||||
.contains(OrganizationPermissions::EDIT_MEMBER_DEFAULT_PERMISSIONS)
|
||||
{
|
||||
return Err(ApiError::InvalidInput(
|
||||
"You do not have permission to give this user default project permissions."
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,6 +697,7 @@ pub async fn edit_team_member(
|
||||
id,
|
||||
user_id,
|
||||
edit_member.permissions,
|
||||
edit_member.organization_permissions,
|
||||
edit_member.role.clone(),
|
||||
None,
|
||||
edit_member.payouts_split,
|
||||
@@ -541,6 +739,21 @@ pub async fn transfer_ownership(
|
||||
.await?
|
||||
.1;
|
||||
|
||||
// Forbid transferring ownership of a project team that is owned by an organization
|
||||
// These are owned by the organization owner, and must be removed from the organization first
|
||||
let pid = Team::get_association(id.into(), &**pool).await?;
|
||||
if let Some(TeamAssociationId::Project(pid)) = pid {
|
||||
let result = Project::get_id(pid, &**pool, &redis).await?;
|
||||
if let Some(project_item) = result {
|
||||
if project_item.inner.organization_id.is_some() {
|
||||
return Err(ApiError::InvalidInput(
|
||||
"You cannot transfer ownership of a project team that is owend by an organization"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !current_user.role.is_admin() {
|
||||
let member = TeamMember::get_from_user_id(id.into(), current_user.id.into(), &**pool)
|
||||
.await?
|
||||
@@ -575,6 +788,7 @@ pub async fn transfer_ownership(
|
||||
id.into(),
|
||||
current_user.id.into(),
|
||||
None,
|
||||
None,
|
||||
Some(crate::models::teams::DEFAULT_ROLE.to_string()),
|
||||
None,
|
||||
None,
|
||||
@@ -586,7 +800,8 @@ pub async fn transfer_ownership(
|
||||
TeamMember::edit_team_member(
|
||||
id.into(),
|
||||
new_owner.user_id.into(),
|
||||
Some(Permissions::ALL),
|
||||
Some(ProjectPermissions::all()),
|
||||
Some(OrganizationPermissions::all()),
|
||||
Some(crate::models::teams::OWNER_ROLE.to_string()),
|
||||
None,
|
||||
None,
|
||||
@@ -623,13 +838,11 @@ pub async fn remove_team_member(
|
||||
)
|
||||
.await?
|
||||
.1;
|
||||
let member = TeamMember::get_from_user_id(id, current_user.id.into(), &**pool)
|
||||
|
||||
let team_association = Team::get_association(id, &**pool)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
ApiError::CustomAuthentication(
|
||||
"You don't have permission to edit members of this team".to_string(),
|
||||
)
|
||||
})?;
|
||||
.ok_or_else(|| ApiError::InvalidInput("The team specified does not exist".to_string()))?;
|
||||
let member = TeamMember::get_from_user_id(id, current_user.id.into(), &**pool).await?;
|
||||
|
||||
let delete_member = TeamMember::get_from_user_id_pending(id, user_id, &**pool).await?;
|
||||
|
||||
@@ -643,29 +856,101 @@ pub async fn remove_team_member(
|
||||
|
||||
let mut transaction = pool.begin().await?;
|
||||
|
||||
if delete_member.accepted {
|
||||
// Members other than the owner can either leave the team, or be
|
||||
// removed by a member with the REMOVE_MEMBER permission.
|
||||
if delete_member.user_id == member.user_id
|
||||
|| (member.permissions.contains(Permissions::REMOVE_MEMBER) && member.accepted)
|
||||
{
|
||||
TeamMember::delete(id, user_id, &mut transaction).await?;
|
||||
} else {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You do not have permission to remove a member from this team".to_string(),
|
||||
));
|
||||
// Organization attached to a project this team is attached to
|
||||
match team_association {
|
||||
TeamAssociationId::Project(pid) => {
|
||||
let organization =
|
||||
Organization::get_associated_organization_project_id(pid, &**pool).await?;
|
||||
let organization_team_member = if let Some(organization) = &organization {
|
||||
TeamMember::get_from_user_id(
|
||||
organization.team_id,
|
||||
current_user.id.into(),
|
||||
&**pool,
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let permissions = ProjectPermissions::get_permissions_by_role(
|
||||
¤t_user.role,
|
||||
&member,
|
||||
&organization_team_member,
|
||||
)
|
||||
.unwrap_or_default();
|
||||
|
||||
if delete_member.accepted {
|
||||
// Members other than the owner can either leave the team, or be
|
||||
// removed by a member with the REMOVE_MEMBER permission.
|
||||
if Some(delete_member.user_id) == member.as_ref().map(|m| m.user_id)
|
||||
|| permissions.contains(ProjectPermissions::REMOVE_MEMBER)
|
||||
&& member.as_ref().map(|m| m.accepted).unwrap_or(true)
|
||||
// true as if the permission exists, but the member does not, they are part of an org
|
||||
{
|
||||
TeamMember::delete(id, user_id, &mut transaction).await?;
|
||||
} else {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You do not have permission to remove a member from this team"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
} else if Some(delete_member.user_id) == member.as_ref().map(|m| m.user_id)
|
||||
|| permissions.contains(ProjectPermissions::MANAGE_INVITES)
|
||||
&& member.as_ref().map(|m| m.accepted).unwrap_or(true)
|
||||
// true as if the permission exists, but the member does not, they are part of an org
|
||||
{
|
||||
// This is a pending invite rather than a member, so the
|
||||
// user being invited or team members with the MANAGE_INVITES
|
||||
// permission can remove it.
|
||||
TeamMember::delete(id, user_id, &mut transaction).await?;
|
||||
} else {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You do not have permission to cancel a team invite".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
TeamAssociationId::Organization(_) => {
|
||||
let organization_permissions =
|
||||
OrganizationPermissions::get_permissions_by_role(¤t_user.role, &member)
|
||||
.unwrap_or_default();
|
||||
if let Some(member) = member {
|
||||
// Organization teams requires a TeamMember, so we can 'unwrap'
|
||||
if delete_member.accepted {
|
||||
// Members other than the owner can either leave the team, or be
|
||||
// removed by a member with the REMOVE_MEMBER permission.
|
||||
if delete_member.user_id == member.user_id
|
||||
|| organization_permissions
|
||||
.contains(OrganizationPermissions::REMOVE_MEMBER)
|
||||
&& member.accepted
|
||||
{
|
||||
TeamMember::delete(id, user_id, &mut transaction).await?;
|
||||
} else {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You do not have permission to remove a member from this organization"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
} else if delete_member.user_id == member.user_id
|
||||
|| organization_permissions
|
||||
.contains(OrganizationPermissions::MANAGE_INVITES)
|
||||
&& member.accepted
|
||||
{
|
||||
// This is a pending invite rather than a member, so the
|
||||
// user being invited or team members with the MANAGE_INVITES
|
||||
// permission can remove it.
|
||||
TeamMember::delete(id, user_id, &mut transaction).await?;
|
||||
} else {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You do not have permission to cancel an organization invite"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You do not have permission to remove a member from this organization"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
} else if delete_member.user_id == member.user_id
|
||||
|| (member.permissions.contains(Permissions::MANAGE_INVITES) && member.accepted)
|
||||
{
|
||||
// This is a pending invite rather than a member, so the
|
||||
// user being invited or team members with the MANAGE_INVITES
|
||||
// permission can remove it.
|
||||
TeamMember::delete(id, user_id, &mut transaction).await?;
|
||||
} else {
|
||||
return Err(ApiError::CustomAuthentication(
|
||||
"You do not have permission to cancel a team invite".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
TeamMember::clear_cache(id, &redis).await?;
|
||||
|
||||
Reference in New Issue
Block a user