From 6ad3da5f35f989a2e7d8e29718b98374248e76af Mon Sep 17 00:00:00 2001 From: izzy Date: Thu, 7 Aug 2025 12:57:33 +0200 Subject: [PATCH] fix: permit empty `remove` array in edit requests --- crates/core/models/src/v0/bots.rs | 4 +- crates/core/models/src/v0/channels.rs | 2 +- crates/core/models/src/v0/server_members.rs | 4 +- crates/core/models/src/v0/servers.rs | 8 ++-- crates/core/models/src/v0/users.rs | 4 +- crates/delta/src/routes/bots/edit.rs | 5 +- .../delta/src/routes/channels/channel_edit.rs | 34 ++++++------- .../delta/src/routes/servers/member_edit.rs | 48 ++++--------------- crates/delta/src/routes/servers/roles_edit.rs | 4 +- .../delta/src/routes/servers/server_edit.rs | 28 ++++------- crates/delta/src/routes/users/edit_user.rs | 36 +++++++------- 11 files changed, 62 insertions(+), 115 deletions(-) diff --git a/crates/core/models/src/v0/bots.rs b/crates/core/models/src/v0/bots.rs index 0e58bd15..70c66c46 100644 --- a/crates/core/models/src/v0/bots.rs +++ b/crates/core/models/src/v0/bots.rs @@ -132,8 +132,8 @@ auto_derived!( #[cfg_attr(feature = "validator", validate(length(min = 1, max = 2048)))] pub interactions_url: Option, /// Fields to remove from bot object - #[cfg_attr(feature = "validator", validate(length(min = 1)))] - pub remove: Option>, + #[cfg_attr(feature = "serde", serde(default))] + pub remove: Vec, } /// Where we are inviting a bot to diff --git a/crates/core/models/src/v0/channels.rs b/crates/core/models/src/v0/channels.rs index 70e9e444..ec25257b 100644 --- a/crates/core/models/src/v0/channels.rs +++ b/crates/core/models/src/v0/channels.rs @@ -207,7 +207,7 @@ auto_derived!( /// Fields to remove from channel #[cfg_attr(feature = "serde", serde(default))] - pub remove: Option>, + pub remove: Vec, } /// Create new group diff --git a/crates/core/models/src/v0/server_members.rs b/crates/core/models/src/v0/server_members.rs index 5b26b88a..a47ceda4 100644 --- a/crates/core/models/src/v0/server_members.rs +++ b/crates/core/models/src/v0/server_members.rs @@ -124,7 +124,7 @@ auto_derived!( /// Timestamp this member is timed out until pub timeout: Option, /// Fields to remove from channel object - #[cfg_attr(feature = "validator", validate(length(min = 1)))] - pub remove: Option>, + #[cfg_attr(feature = "serde", serde(default))] + pub remove: Vec, } ); diff --git a/crates/core/models/src/v0/servers.rs b/crates/core/models/src/v0/servers.rs index d29594bf..c3ed20a8 100644 --- a/crates/core/models/src/v0/servers.rs +++ b/crates/core/models/src/v0/servers.rs @@ -249,8 +249,8 @@ auto_derived!( pub analytics: Option, /// Fields to remove from server object - #[cfg_attr(feature = "validator", validate(length(min = 1)))] - pub remove: Option>, + #[cfg_attr(feature = "serde", serde(default))] + pub remove: Vec, } /// New role information @@ -272,8 +272,8 @@ auto_derived!( /// **Removed** - no effect, use the edit server role positions route pub rank: Option, /// Fields to remove from role object - #[cfg_attr(feature = "validator", validate(length(min = 1)))] - pub remove: Option>, + #[cfg_attr(feature = "serde", serde(default))] + pub remove: Vec, } /// New role permissions diff --git a/crates/core/models/src/v0/users.rs b/crates/core/models/src/v0/users.rs index ba913dd0..ef1c8f1a 100644 --- a/crates/core/models/src/v0/users.rs +++ b/crates/core/models/src/v0/users.rs @@ -245,8 +245,8 @@ auto_derived!( pub flags: Option, /// Fields to remove from user object - #[cfg_attr(feature = "validator", validate(length(min = 1)))] - pub remove: Option>, + #[cfg_attr(feature = "serde", serde(default))] + pub remove: Vec, } /// User flag reponse diff --git a/crates/delta/src/routes/bots/edit.rs b/crates/delta/src/routes/bots/edit.rs index e90b4bef..20136415 100644 --- a/crates/delta/src/routes/bots/edit.rs +++ b/crates/delta/src/routes/bots/edit.rs @@ -37,7 +37,7 @@ pub async fn edit_bot( if data.public.is_none() && data.analytics.is_none() && data.interactions_url.is_none() - && data.remove.is_none() + && data.remove.is_empty() { return Ok(Json(v0::BotWithUserResponse { bot: bot.into(), @@ -64,7 +64,6 @@ pub async fn edit_bot( db, partial, remove - .unwrap_or_default() .into_iter() .map(|v| v.into()) .collect(), @@ -100,7 +99,7 @@ mod test { .body( json!(v0::DataEditBot { public: Some(true), - remove: Some(vec![FieldsBot::Token]), + remove: vec![FieldsBot::Token], ..Default::default() }) .to_string(), diff --git a/crates/delta/src/routes/channels/channel_edit.rs b/crates/delta/src/routes/channels/channel_edit.rs index 1977ec9b..37555f8c 100644 --- a/crates/delta/src/routes/channels/channel_edit.rs +++ b/crates/delta/src/routes/channels/channel_edit.rs @@ -38,7 +38,7 @@ pub async fn edit( && data.icon.is_none() && data.nsfw.is_none() && data.owner.is_none() - && data.remove.is_none() + && data.remove.is_empty() { return Ok(Json(channel.into())); } @@ -112,23 +112,21 @@ pub async fn edit( nsfw, .. } => { - if let Some(fields) = &data.remove { - if fields.contains(&v0::FieldsChannel::Icon) { - if let Some(icon) = &icon { - db.mark_attachment_as_deleted(&icon.id).await?; - } + if data.remove.contains(&v0::FieldsChannel::Icon) { + if let Some(icon) = &icon { + db.mark_attachment_as_deleted(&icon.id).await?; } + } - for field in fields { - match field { - v0::FieldsChannel::Description => { - description.take(); - } - v0::FieldsChannel::Icon => { - icon.take(); - } - _ => {} + for field in &data.remove { + match field { + v0::FieldsChannel::Description => { + description.take(); } + v0::FieldsChannel::Icon => { + icon.take(); + } + _ => {} } } @@ -214,11 +212,7 @@ pub async fn edit( .update( db, partial, - data.remove - .unwrap_or_default() - .into_iter() - .map(|f| f.into()) - .collect(), + data.remove.into_iter().map(|f| f.into()).collect(), ) .await?; } diff --git a/crates/delta/src/routes/servers/member_edit.rs b/crates/delta/src/routes/servers/member_edit.rs index 005e65c7..ef3ff663 100644 --- a/crates/delta/src/routes/servers/member_edit.rs +++ b/crates/delta/src/routes/servers/member_edit.rs @@ -39,13 +39,7 @@ pub async fn edit( let permissions = calculate_server_permissions(&mut query).await; // Check permissions in server - if data.nickname.is_some() - || data - .remove - .as_ref() - .map(|x| x.contains(&v0::FieldsMember::Nickname)) - .unwrap_or_default() - { + if data.nickname.is_some() || data.remove.contains(&v0::FieldsMember::Nickname) { if user.id == member.id.user { permissions.throw_if_lacking_channel_permission(ChannelPermission::ChangeNickname)?; } else { @@ -53,13 +47,7 @@ pub async fn edit( } } - if data.avatar.is_some() - || data - .remove - .as_ref() - .map(|x| x.contains(&v0::FieldsMember::Avatar)) - .unwrap_or_default() - { + if data.avatar.is_some() || data.remove.contains(&v0::FieldsMember::Avatar) { if user.id == member.id.user { permissions.throw_if_lacking_channel_permission(ChannelPermission::ChangeAvatar)?; } else { @@ -67,23 +55,11 @@ pub async fn edit( } } - if data.roles.is_some() - || data - .remove - .as_ref() - .map(|x| x.contains(&v0::FieldsMember::Roles)) - .unwrap_or_default() - { + if data.roles.is_some() || data.remove.contains(&v0::FieldsMember::Roles) { permissions.throw_if_lacking_channel_permission(ChannelPermission::AssignRoles)?; } - if data.timeout.is_some() - || data - .remove - .as_ref() - .map(|x| x.contains(&v0::FieldsMember::Timeout)) - .unwrap_or_default() - { + if data.timeout.is_some() || data.remove.contains(&v0::FieldsMember::Timeout) { if data.timeout.is_some() && member.id.user == user.id { return Err(create_error!(CannotTimeoutYourself)); } @@ -136,11 +112,9 @@ pub async fn edit( }; // 1. Remove fields from object - if let Some(fields) = &remove { - if fields.contains(&v0::FieldsMember::Avatar) { - if let Some(avatar) = &member.avatar { - db.mark_attachment_as_deleted(&avatar.id).await?; - } + if remove.contains(&v0::FieldsMember::Avatar) { + if let Some(avatar) = &member.avatar { + db.mark_attachment_as_deleted(&avatar.id).await?; } } @@ -150,13 +124,7 @@ pub async fn edit( } member - .update( - db, - partial, - remove - .map(|v| v.into_iter().map(Into::into).collect()) - .unwrap_or_default(), - ) + .update(db, partial, remove.into_iter().map(Into::into).collect()) .await?; Ok(Json(member.into())) diff --git a/crates/delta/src/routes/servers/roles_edit.rs b/crates/delta/src/routes/servers/roles_edit.rs index f8152efe..be62a9b2 100644 --- a/crates/delta/src/routes/servers/roles_edit.rs +++ b/crates/delta/src/routes/servers/roles_edit.rs @@ -61,9 +61,7 @@ pub async fn edit( &server.id, &role_id, partial, - remove - .map(|v| v.into_iter().map(Into::into).collect()) - .unwrap_or_default(), + remove.into_iter().map(Into::into).collect(), ) .await?; diff --git a/crates/delta/src/routes/servers/server_edit.rs b/crates/delta/src/routes/servers/server_edit.rs index 05688473..8616e154 100644 --- a/crates/delta/src/routes/servers/server_edit.rs +++ b/crates/delta/src/routes/servers/server_edit.rs @@ -43,7 +43,7 @@ pub async fn edit( && data.flags.is_none() && data.analytics.is_none() && data.discoverable.is_none() - && data.remove.is_none() + && data.remove.is_empty() { return Ok(Json(server.into())); } else if data.name.is_some() @@ -52,7 +52,7 @@ pub async fn edit( || data.banner.is_some() || data.system_messages.is_some() || data.analytics.is_some() - || data.remove.is_some() + || !data.remove.is_empty() { permissions.throw_if_lacking_channel_permission(ChannelPermission::ManageServer)?; } @@ -96,17 +96,15 @@ pub async fn edit( }; // 1. Remove fields from object - if let Some(fields) = &remove { - if fields.contains(&v0::FieldsServer::Banner) { - if let Some(banner) = &server.banner { - db.mark_attachment_as_deleted(&banner.id).await?; - } + if remove.contains(&v0::FieldsServer::Banner) { + if let Some(banner) = &server.banner { + db.mark_attachment_as_deleted(&banner.id).await?; } + } - if fields.contains(&v0::FieldsServer::Icon) { - if let Some(icon) = &server.icon { - db.mark_attachment_as_deleted(&icon.id).await?; - } + if remove.contains(&v0::FieldsServer::Icon) { + if let Some(icon) = &server.icon { + db.mark_attachment_as_deleted(&icon.id).await?; } } @@ -149,13 +147,7 @@ pub async fn edit( } server - .update( - db, - partial, - remove - .map(|v| v.into_iter().map(Into::into).collect()) - .unwrap_or_default(), - ) + .update(db, partial, remove.into_iter().map(Into::into).collect()) .await?; Ok(Json(server.into())) diff --git a/crates/delta/src/routes/users/edit_user.rs b/crates/delta/src/routes/users/edit_user.rs index aa91e3f8..de8aa002 100644 --- a/crates/delta/src/routes/users/edit_user.rs +++ b/crates/delta/src/routes/users/edit_user.rs @@ -53,31 +53,29 @@ pub async fn edit( && data.avatar.is_none() && data.badges.is_none() && data.flags.is_none() - && data.remove.is_none() + && data.remove.is_empty() { return Ok(Json(user.into_self(false).await)); } // 1. Remove fields from object - if let Some(fields) = &data.remove { - if fields.contains(&v0::FieldsUser::Avatar) { - if let Some(avatar) = &user.avatar { - db.mark_attachment_as_deleted(&avatar.id).await?; + if data.remove.contains(&v0::FieldsUser::Avatar) { + if let Some(avatar) = &user.avatar { + db.mark_attachment_as_deleted(&avatar.id).await?; + } + } + + if data.remove.contains(&v0::FieldsUser::ProfileBackground) { + if let Some(profile) = &user.profile { + if let Some(background) = &profile.background { + db.mark_attachment_as_deleted(&background.id).await?; } } + } - if fields.contains(&v0::FieldsUser::ProfileBackground) { - if let Some(profile) = &user.profile { - if let Some(background) = &profile.background { - db.mark_attachment_as_deleted(&background.id).await?; - } - } - } - - for field in fields { - let field: FieldsUser = field.clone().into(); - user.remove_field(&field); - } + for field in &data.remove { + let field: FieldsUser = field.clone().into(); + user.remove_field(&field); } let mut partial: PartialUser = PartialUser { @@ -124,9 +122,7 @@ pub async fn edit( user.update( db, partial, - data.remove - .map(|v| v.into_iter().map(Into::into).collect()) - .unwrap_or_default(), + data.remove.into_iter().map(Into::into).collect(), ) .await?;