From 0063af4496bd197dbdfc9153fe91dbbbd32fc3e7 Mon Sep 17 00:00:00 2001 From: Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com> Date: Fri, 12 Jul 2024 21:51:37 -0400 Subject: [PATCH] fix(model, http)!: fix role position update payload and allow audit log reason (#2342) Closes #2338 and adds audit log reason support for this endpoint. --------- Co-authored-by: Tim Vilgot Mikael Fredenberg <26655508+vilgotf@users.noreply.github.com> --- twilight-http/src/client/mod.rs | 7 +++- twilight-http/src/request/audit_reason.rs | 6 ++- .../guild/role/update_role_positions.rs | 35 +++++++++++----- twilight-model/src/guild/mod.rs | 8 ++-- twilight-model/src/guild/role_position.rs | 41 +++++++++++++++++++ 5 files changed, 79 insertions(+), 18 deletions(-) create mode 100644 twilight-model/src/guild/role_position.rs diff --git a/twilight-http/src/client/mod.rs b/twilight-http/src/client/mod.rs index 4a17119f141..7ea356f300f 100644 --- a/twilight-http/src/client/mod.rs +++ b/twilight-http/src/client/mod.rs @@ -105,7 +105,10 @@ use tokio::time; use twilight_http_ratelimiting::Ratelimiter; use twilight_model::{ channel::{message::AllowedMentions, ChannelType}, - guild::{auto_moderation::AutoModerationEventType, scheduled_event::PrivacyLevel, MfaLevel}, + guild::{ + auto_moderation::AutoModerationEventType, scheduled_event::PrivacyLevel, MfaLevel, + RolePosition, + }, http::{channel_position::Position, permission_overwrite::PermissionOverwrite}, id::{ marker::{ @@ -1708,7 +1711,7 @@ impl Client { pub const fn update_role_positions<'a>( &'a self, guild_id: Id, - roles: &'a [(Id, u64)], + roles: &'a [RolePosition], ) -> UpdateRolePositions<'a> { UpdateRolePositions::new(self, guild_id, roles) } diff --git a/twilight-http/src/request/audit_reason.rs b/twilight-http/src/request/audit_reason.rs index 763f2ffadd5..eafe55d0edf 100644 --- a/twilight-http/src/request/audit_reason.rs +++ b/twilight-http/src/request/audit_reason.rs @@ -34,7 +34,7 @@ mod private { emoji::{CreateEmoji, DeleteEmoji, UpdateEmoji}, integration::DeleteGuildIntegration, member::{AddRoleToMember, RemoveMember, RemoveRoleFromMember, UpdateGuildMember}, - role::{CreateRole, DeleteRole, UpdateRole}, + role::{CreateRole, DeleteRole, UpdateRole, UpdateRolePositions}, sticker::{CreateGuildSticker, UpdateGuildSticker}, update_guild_onboarding::UpdateGuildOnboarding, CreateGuildChannel, CreateGuildPrune, UpdateCurrentMember, UpdateGuild, UpdateGuildMfa, @@ -95,6 +95,7 @@ mod private { impl Sealed for UpdateGuildSticker<'_> {} impl Sealed for UpdateGuildWidgetSettings<'_> {} impl Sealed for UpdateRole<'_> {} + impl Sealed for UpdateRolePositions<'_> {} impl Sealed for UpdateThread<'_> {} impl Sealed for UpdateWebhook<'_> {} } @@ -115,7 +116,7 @@ mod tests { emoji::{CreateEmoji, DeleteEmoji, UpdateEmoji}, integration::DeleteGuildIntegration, member::{AddRoleToMember, RemoveMember, RemoveRoleFromMember, UpdateGuildMember}, - role::{CreateRole, DeleteRole, UpdateRole}, + role::{CreateRole, DeleteRole, UpdateRole, UpdateRolePositions}, sticker::{CreateGuildSticker, UpdateGuildSticker}, CreateGuildChannel, CreateGuildPrune, UpdateCurrentMember, UpdateGuild, }, @@ -157,5 +158,6 @@ mod tests { assert_impl_all!(UpdateGuildMember<'_>: AuditLogReason<'static>); assert_impl_all!(UpdateGuildSticker<'_>: AuditLogReason<'static>); assert_impl_all!(UpdateRole<'_>: AuditLogReason<'static>); + assert_impl_all!(UpdateRolePositions<'_>: AuditLogReason<'static>); assert_impl_all!(UpdateWebhook<'_>: AuditLogReason<'static>); } diff --git a/twilight-http/src/request/guild/role/update_role_positions.rs b/twilight-http/src/request/guild/role/update_role_positions.rs index 51f94d0ec0d..5f4a35d7193 100644 --- a/twilight-http/src/request/guild/role/update_role_positions.rs +++ b/twilight-http/src/request/guild/role/update_role_positions.rs @@ -1,18 +1,16 @@ use crate::{ client::Client, error::Error, - request::{Request, TryIntoRequest}, + request::{self, AuditLogReason, Request, TryIntoRequest}, response::{marker::ListBody, Response, ResponseFuture}, routing::Route, }; use std::future::IntoFuture; use twilight_model::{ - guild::Role, - id::{ - marker::{GuildMarker, RoleMarker}, - Id, - }, + guild::{Role, RolePosition}, + id::{marker::GuildMarker, Id}, }; +use twilight_validate::request::{audit_reason as validate_audit_reason, ValidationError}; /// Modify the position of the roles. /// @@ -21,23 +19,33 @@ use twilight_model::{ pub struct UpdateRolePositions<'a> { guild_id: Id, http: &'a Client, - roles: &'a [(Id, u64)], + roles: &'a [RolePosition], + reason: Result, ValidationError>, } impl<'a> UpdateRolePositions<'a> { pub(crate) const fn new( http: &'a Client, guild_id: Id, - roles: &'a [(Id, u64)], + roles: &'a [RolePosition], ) -> Self { Self { guild_id, http, roles, + reason: Ok(None), } } } +impl<'a> AuditLogReason<'a> for UpdateRolePositions<'a> { + fn reason(mut self, reason: &'a str) -> Self { + self.reason = validate_audit_reason(reason).and(Ok(Some(reason))); + + self + } +} + impl IntoFuture for UpdateRolePositions<'_> { type Output = Result>, Error>; @@ -55,10 +63,15 @@ impl IntoFuture for UpdateRolePositions<'_> { impl TryIntoRequest for UpdateRolePositions<'_> { fn try_into_request(self) -> Result { - Request::builder(&Route::UpdateRolePositions { + let mut request = Request::builder(&Route::UpdateRolePositions { guild_id: self.guild_id.get(), }) - .json(&self.roles) - .build() + .json(&self.roles); + + if let Some(reason) = self.reason.map_err(Error::validation)? { + request = request.headers(request::audit_header(reason)?); + } + + request.build() } } diff --git a/twilight-model/src/guild/mod.rs b/twilight-model/src/guild/mod.rs index 3a26bc830cf..e1ddf9a5b4a 100644 --- a/twilight-model/src/guild/mod.rs +++ b/twilight-model/src/guild/mod.rs @@ -37,6 +37,7 @@ mod preview; mod prune; mod role; mod role_flags; +mod role_position; mod role_tags; mod system_channel_flags; mod unavailable_guild; @@ -54,9 +55,10 @@ pub use self::{ integration_expire_behavior::IntegrationExpireBehavior, integration_type::GuildIntegrationType, member::Member, member_flags::MemberFlags, mfa_level::MfaLevel, partial_guild::PartialGuild, partial_member::PartialMember, premium_tier::PremiumTier, preview::GuildPreview, - prune::GuildPrune, role::Role, role_flags::RoleFlags, role_tags::RoleTags, - system_channel_flags::SystemChannelFlags, unavailable_guild::UnavailableGuild, - vanity_url::VanityUrl, verification_level::VerificationLevel, widget::GuildWidget, + prune::GuildPrune, role::Role, role_flags::RoleFlags, role_position::RolePosition, + role_tags::RoleTags, system_channel_flags::SystemChannelFlags, + unavailable_guild::UnavailableGuild, vanity_url::VanityUrl, + verification_level::VerificationLevel, widget::GuildWidget, }; use super::gateway::presence::PresenceListDeserializer; diff --git a/twilight-model/src/guild/role_position.rs b/twilight-model/src/guild/role_position.rs new file mode 100644 index 00000000000..957cf4d8193 --- /dev/null +++ b/twilight-model/src/guild/role_position.rs @@ -0,0 +1,41 @@ +use crate::id::{marker::RoleMarker, Id}; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +/// Data used to update the positions of roles. +pub struct RolePosition { + /// Role identifier. + pub id: Id, + /// Sorting position of the role. + pub position: u64, +} + +#[cfg(test)] +mod tests { + use super::{Id, RolePosition}; + use serde_test::Token; + + #[test] + fn role_position() { + let role_position = RolePosition { + id: Id::new(123), + position: 12, + }; + + serde_test::assert_tokens( + &role_position, + &[ + Token::Struct { + name: "RolePosition", + len: 2, + }, + Token::Str("id"), + Token::NewtypeStruct { name: "Id" }, + Token::Str("123"), + Token::Str("position"), + Token::U64(12), + Token::StructEnd, + ], + ); + } +}