From 77e8143290e8c0683bcdebe62263540f3e612a0b Mon Sep 17 00:00:00 2001 From: Geometrically <18202329+Geometrically@users.noreply.github.com> Date: Sat, 13 Nov 2021 16:35:21 -0700 Subject: [PATCH] Fix transferring ownership (#256) --- sqlx-data.json | 85 +++++++++++++++--------------- src/database/models/team_item.rs | 9 ++-- src/routes/teams.rs | 88 ++++++++++++++++---------------- src/validate/pack.rs | 10 ++-- 4 files changed, 94 insertions(+), 98 deletions(-) diff --git a/sqlx-data.json b/sqlx-data.json index 6d2f3440..690ef9e3 100644 --- a/sqlx-data.json +++ b/sqlx-data.json @@ -171,21 +171,6 @@ ] } }, - "0739834cfbef869855ed4e1aea7e1f7601f6519867ee48c573ee901c4498e04c": { - "query": "\n UPDATE team_members\n SET permissions = $1\n WHERE (team_id = $2 AND user_id = $3 AND NOT role = $4)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Int8", - "Int8", - "Text" - ] - }, - "nullable": [] - } - }, "07ebc9dc82cd012cd4f5880b1eb3d82602c195a3e3ddd557103ee037aa6dad1c": { "query": "\n INSERT INTO mods_donations (joining_mod_id, joining_platform_id, url)\n VALUES ($1, $2, $3)\n ", "describe": { @@ -663,6 +648,20 @@ ] } }, + "232d7d0319c20dd5fff29331b067d6c6373bcff761a77958a2bb5f59068a83a5": { + "query": "\n UPDATE team_members\n SET permissions = $1\n WHERE (team_id = $2 AND user_id = $3)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int8", + "Int8" + ] + }, + "nullable": [] + } + }, "24e5daad907eec54505274f93952d5c20f4bbdd3f771eb0a2fdfa6324768df39": { "query": "\n SELECT short, name FROM licenses\n WHERE id = $1\n ", "describe": { @@ -933,20 +932,6 @@ "nullable": [] } }, - "3b52d9f68ba23d1e3764f8df9f28bcaec0741101f6afd0c7c234b7f1b91054a4": { - "query": "\n UPDATE team_members\n SET accepted = TRUE\n WHERE (team_id = $1 AND user_id = $2 AND NOT role = $3)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Int8", - "Int8", - "Text" - ] - }, - "nullable": [] - } - }, "3bdcbfa5abe43cc9b4f996f147277a7f6921cca00f82cad0ef5d85032c761a36": { "query": "\n DELETE FROM mod_follows\n WHERE follower_id = $1 AND mod_id = $2\n ", "describe": { @@ -2232,21 +2217,6 @@ "nullable": [] } }, - "6c2299a7b7ab22f83049bc41fb5dd380adea3579e7b00df7d16fb6747a0a7313": { - "query": "\n UPDATE team_members\n SET role = $1\n WHERE (team_id = $2 AND user_id = $3 AND NOT role = $4)\n ", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Varchar", - "Int8", - "Int8", - "Text" - ] - }, - "nullable": [] - } - }, "6c7aeb0db4a4fb3387c37b8d7aca6fdafaa637fd883a44416b56270aeebb7a01": { "query": "\n INSERT INTO loaders_versions (loader_id, version_id)\n VALUES ($1, $2)\n ", "describe": { @@ -4669,6 +4639,20 @@ "nullable": [] } }, + "cef01012769dcd499a0d16ce65ffc1e94bce362a7246b6a0a38d133afb90d3b6": { + "query": "\n UPDATE team_members\n SET role = $1\n WHERE (team_id = $2 AND user_id = $3)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Varchar", + "Int8", + "Int8" + ] + }, + "nullable": [] + } + }, "d03630ab0ff37f5f0a8c088558fdc8a1955bad78bea282c40f72d15e5cf77a79": { "query": "\n SELECT v.id id\n FROM versions v\n INNER JOIN game_versions_versions gvv ON gvv.joining_version_id = v.id AND gvv.game_version_id = ANY($2)\n INNER JOIN loaders_versions lv ON lv.version_id = v.id AND lv.loader_id = ANY($3)\n WHERE v.mod_id = $1\n ORDER BY v.date_published DESC\n LIMIT 1\n ", "describe": { @@ -4828,6 +4812,19 @@ "nullable": [] } }, + "d3991923355b2e0ed7bbe6c85d9158754d7e7d28f5ac75ee5b4e782dbc5c38a9": { + "query": "\n UPDATE team_members\n SET accepted = TRUE\n WHERE (team_id = $1 AND user_id = $2)\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Int8", + "Int8" + ] + }, + "nullable": [] + } + }, "d5807cb9a5766acc832b8715aab2b692a99e249a73974f0945710b1b394b1d74": { "query": "\n SELECT id, filename, is_primary, url\n FROM files\n WHERE version_id = $1\n ", "describe": { diff --git a/src/database/models/team_item.rs b/src/database/models/team_item.rs index 22507fe6..e7d67e89 100644 --- a/src/database/models/team_item.rs +++ b/src/database/models/team_item.rs @@ -439,12 +439,11 @@ impl TeamMember { " UPDATE team_members SET permissions = $1 - WHERE (team_id = $2 AND user_id = $3 AND NOT role = $4) + WHERE (team_id = $2 AND user_id = $3) ", permissions.bits() as i64, id as TeamId, user_id as UserId, - crate::models::teams::OWNER_ROLE, ) .execute(&mut *transaction) .await?; @@ -455,12 +454,11 @@ impl TeamMember { " UPDATE team_members SET role = $1 - WHERE (team_id = $2 AND user_id = $3 AND NOT role = $4) + WHERE (team_id = $2 AND user_id = $3) ", role, id as TeamId, user_id as UserId, - crate::models::teams::OWNER_ROLE, ) .execute(&mut *transaction) .await?; @@ -472,11 +470,10 @@ impl TeamMember { " UPDATE team_members SET accepted = TRUE - WHERE (team_id = $1 AND user_id = $2 AND NOT role = $3) + WHERE (team_id = $1 AND user_id = $2) ", id as TeamId, user_id as UserId, - crate::models::teams::OWNER_ROLE, ) .execute(&mut *transaction) .await?; diff --git a/src/routes/teams.rs b/src/routes/teams.rs index ce454901..50e71b89 100644 --- a/src/routes/teams.rs +++ b/src/routes/teams.rs @@ -153,17 +153,13 @@ pub async fn add_team_member( let mut transaction = pool.begin().await?; let current_user = get_user_from_headers(req.headers(), &**pool).await?; - let team_member = - TeamMember::get_from_user_id(team_id, current_user.id.into(), &**pool).await?; - - let member = match team_member { - Some(m) => m, - None => { - return Err(ApiError::CustomAuthenticationError( - "You don't have permission to invite users to this team".to_string(), - )) - } - }; + let member = TeamMember::get_from_user_id(team_id, current_user.id.into(), &**pool) + .await? + .ok_or_else(|| { + ApiError::CustomAuthenticationError( + "You don't have permission to edit members of this team".to_string(), + ) + })?; if !member.permissions.contains(Permissions::MANAGE_INVITES) { return Err(ApiError::CustomAuthenticationError( @@ -277,18 +273,21 @@ pub async fn edit_team_member( let user_id = ids.1.into(); let current_user = get_user_from_headers(req.headers(), &**pool).await?; - let team_member = TeamMember::get_from_user_id(id, current_user.id.into(), &**pool).await?; + let member = TeamMember::get_from_user_id(id, current_user.id.into(), &**pool) + .await? + .ok_or_else(|| { + ApiError::CustomAuthenticationError( + "You don't have permission to edit members of this team".to_string(), + ) + })?; let mut transaction = pool.begin().await?; - let member = match team_member { - Some(m) => m, - None => { - return Err(ApiError::CustomAuthenticationError( - "You don't have permission to edit members of this team".to_string(), - )) - } - }; + if &*member.role == crate::models::teams::OWNER_ROLE { + return Err(ApiError::InvalidInputError( + "The owner of a team cannot be edited".to_string(), + )); + } if !member.permissions.contains(Permissions::EDIT_MEMBER) { return Err(ApiError::CustomAuthenticationError( @@ -340,17 +339,18 @@ pub async fn transfer_ownership( let id = info.into_inner().0; let current_user = get_user_from_headers(req.headers(), &**pool).await?; - let team_member = - TeamMember::get_from_user_id(id.into(), current_user.id.into(), &**pool).await?; - - let member = match team_member { - Some(m) => m, - None => { - return Err(ApiError::CustomAuthenticationError( + let member = TeamMember::get_from_user_id(id.into(), current_user.id.into(), &**pool) + .await? + .ok_or_else(|| { + ApiError::CustomAuthenticationError( "You don't have permission to edit members of this team".to_string(), - )) - } - }; + ) + })?; + let new_member = TeamMember::get_from_user_id(id.into(), new_owner.user_id.into(), &**pool) + .await? + .ok_or_else(|| { + ApiError::InvalidInputError("The new owner specified does not exist".to_string()) + })?; if member.role != crate::models::teams::OWNER_ROLE { return Err(ApiError::CustomAuthenticationError( @@ -358,12 +358,18 @@ pub async fn transfer_ownership( )); } + if !new_member.accepted { + return Err(ApiError::InvalidInputError( + "You can only transfer ownership to members who are currently in your team".to_string(), + )); + } + let mut transaction = pool.begin().await?; TeamMember::edit_team_member( id.into(), current_user.id.into(), - Some(Permissions::ALL), + None, Some(crate::models::teams::DEFAULT_ROLE.to_string()), None, &mut transaction, @@ -373,7 +379,7 @@ pub async fn transfer_ownership( TeamMember::edit_team_member( id.into(), new_owner.user_id.into(), - None, + Some(Permissions::ALL), Some(crate::models::teams::OWNER_ROLE.to_string()), None, &mut transaction, @@ -396,17 +402,13 @@ pub async fn remove_team_member( let user_id = ids.1.into(); let current_user = get_user_from_headers(req.headers(), &**pool).await?; - let team_member = - TeamMember::get_from_user_id_pending(id, current_user.id.into(), &**pool).await?; - - let member = match team_member { - Some(m) => m, - None => { - return Err(ApiError::CustomAuthenticationError( - "You don't have permission to remove members from this team".to_string(), - )) - } - }; + let member = TeamMember::get_from_user_id(id, current_user.id.into(), &**pool) + .await? + .ok_or_else(|| { + ApiError::CustomAuthenticationError( + "You don't have permission to edit members of this team".to_string(), + ) + })?; let delete_member = TeamMember::get_from_user_id_pending(id, user_id, &**pool).await?; diff --git a/src/validate/pack.rs b/src/validate/pack.rs index 6d32fb91..9176b628 100644 --- a/src/validate/pack.rs +++ b/src/validate/pack.rs @@ -1,10 +1,10 @@ use crate::models::projects::SideType; +use crate::util::validate::validation_errors_to_string; use crate::validate::{SupportedGameVersions, ValidationError, ValidationResult}; use serde::{Deserialize, Serialize}; use std::io::{Cursor, Read}; -use zip::ZipArchive; use validator::Validate; -use crate::util::validate::validation_errors_to_string; +use zip::ZipArchive; #[derive(Serialize, Deserialize, Validate)] #[serde(rename_all = "camelCase")] @@ -112,9 +112,9 @@ impl super::Validator for PackValidator { let pack: PackFormat = serde_json::from_str(&contents)?; - pack - .validate() - .map_err(|err| ValidationError::InvalidInputError(validation_errors_to_string(err, None).into()))?; + pack.validate().map_err(|err| { + ValidationError::InvalidInputError(validation_errors_to_string(err, None).into()) + })?; if pack.game != "minecraft" { return Err(ValidationError::InvalidInputError(