Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 60 additions & 4 deletions twilight-http/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ use crate::request::{
GetEntitlements, GetSKUs,
},
},
guild::user::{GetCurrentUserVoiceState, GetUserVoiceState},
guild::{
screening::{GetGuildJoinRequests, UpdateGuildJoinRequest},
user::{GetCurrentUserVoiceState, GetUserVoiceState},
},
};
#[allow(deprecated)]
use crate::{
Expand Down Expand Up @@ -119,15 +122,15 @@ use twilight_model::{
channel::{ChannelType, message::AllowedMentions},
guild::{
MfaLevel, RolePosition, auto_moderation::AutoModerationEventType,
scheduled_event::PrivacyLevel,
scheduled_event::PrivacyLevel, screening::JoinRequestStatus,
},
http::{channel_position::Position, permission_overwrite::PermissionOverwrite},
id::{
Id,
marker::{
ApplicationMarker, AutoModerationRuleMarker, ChannelMarker, EmojiMarker,
EntitlementMarker, GuildMarker, IntegrationMarker, MessageMarker, RoleMarker,
ScheduledEventMarker, SkuMarker, StickerMarker, UserMarker, WebhookMarker,
EntitlementMarker, GuildMarker, IntegrationMarker, JoinRequestMarker, MessageMarker,
RoleMarker, ScheduledEventMarker, SkuMarker, StickerMarker, UserMarker, WebhookMarker,
},
},
};
Expand Down Expand Up @@ -1062,6 +1065,59 @@ impl Client {
GetGuildInvites::new(self, guild_id)
}

/// List join requests for guild, optionally filtered by application status.
///
/// Requires the [`MANAGE_GUILD`] permission.
///
/// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD
pub const fn get_guild_join_requests(
&self,
guild_id: Id<GuildMarker>,
status: Option<JoinRequestStatus>,
limit: Option<u8>,
before: Option<Id<JoinRequestMarker>>,
after: Option<Id<JoinRequestMarker>>,
) -> GetGuildJoinRequests<'_> {
GetGuildJoinRequests::new(self, guild_id, status, limit, before, after)
}

/// Approve or reject guild join request.
///
/// Requires the [`KICK_MEMBERS`] permission.
///
/// # Examples
///
/// ```no_run
/// use twilight_http::Client;
/// use twilight_model::id::Id;
///
/// # #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let client = Client::new("token".to_owned());
///
/// let guild_id = Id::new(101);
/// let request_id = Id::new(102);
/// let new_status = JoinRequestStatus::Approved;
/// let application = client.update_guild_join_request(guild_id, request_id, new_status).await?.model().await?;
///
/// if new_status == application.application_status {
/// println!("User approved");
/// } else {
/// println!("Failed to approve user");
/// }
/// # Ok(()) }
/// ```
///
/// [`KICK_MEMBERS`]: twilight_model::guild::Permissions::KICK_MEMBERS
pub const fn update_guild_join_request(
&self,
guild_id: Id<GuildMarker>,
request_id: Id<JoinRequestMarker>,
new_status: JoinRequestStatus,
) -> UpdateGuildJoinRequest<'_> {
UpdateGuildJoinRequest::new(self, guild_id, request_id, new_status)
}

/// Update a guild's MFA level.
pub const fn update_guild_mfa(
&self,
Expand Down
1 change: 1 addition & 0 deletions twilight-http/src/request/guild/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod emoji;
pub mod integration;
pub mod member;
pub mod role;
pub mod screening;
pub mod sticker;
pub mod update_guild_channel_positions;
pub mod update_guild_onboarding;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use std::future::IntoFuture;

use twilight_model::{
guild::screening::{JoinRequestList, JoinRequestStatus},
id::{
Id,
marker::{GuildMarker, JoinRequestMarker},
},
};

use crate::{
Client, Error, Response,
request::{Request, TryIntoRequest},
response::ResponseFuture,
routing::Route,
};

/// List join requests for guild, optionally filtered by application status.
///
/// Requires the [`MANAGE_GUILD`] permission.
///
/// [`MANAGE_GUILD`]: twilight_model::guild::Permissions::MANAGE_GUILD
pub struct GetGuildJoinRequests<'a> {
/// Only return requests newer than the request specified.
after: Option<Id<JoinRequestMarker>>,
/// Only return requests older than the request specified.
before: Option<Id<JoinRequestMarker>>,
/// ID of the guild.
guild_id: Id<GuildMarker>,
http: &'a Client,
/// Maximum number of requests to return.
limit: Option<u8>,
/// Only return requests with this status.
status: Option<JoinRequestStatus>,
}

impl<'a> GetGuildJoinRequests<'a> {
pub(crate) const fn new(
http: &'a Client,
guild_id: Id<GuildMarker>,
status: Option<JoinRequestStatus>,
limit: Option<u8>,
before: Option<Id<JoinRequestMarker>>,
after: Option<Id<JoinRequestMarker>>,
) -> Self {
Self {
after,
before,
guild_id,
http,
limit,
status,
}
}
}

impl IntoFuture for GetGuildJoinRequests<'_> {
type Output = Result<Response<JoinRequestList>, Error>;

type IntoFuture = ResponseFuture<JoinRequestList>;

fn into_future(self) -> Self::IntoFuture {
let http = self.http;

match self.try_into_request() {
Ok(request) => http.request(request),
Err(source) => ResponseFuture::error(source),
}
}
}

impl TryIntoRequest for GetGuildJoinRequests<'_> {
fn try_into_request(self) -> Result<Request, Error> {
let request = Request::from_route(&Route::GetGuildJoinRequests {
guild_id: self.guild_id.get(),
status: self.status,
limit: self.limit,
before: self.before.map(Id::get),
after: self.after.map(Id::get),
});

Ok(request)
}
}
7 changes: 7 additions & 0 deletions twilight-http/src/request/guild/screening/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mod get_guild_join_requests;
mod update_guild_join_request;

pub use self::{
get_guild_join_requests::GetGuildJoinRequests,
update_guild_join_request::UpdateGuildJoinRequest,
};
140 changes: 140 additions & 0 deletions twilight-http/src/request/guild/screening/update_guild_join_request.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
use std::future::IntoFuture;

use serde::Serialize;
use twilight_model::{
guild::screening::{JoinRequest, JoinRequestStatus},
id::{
Id,
marker::{GuildMarker, JoinRequestMarker},
},
};

use crate::{
Client, Error, Response,
request::{Request, TryIntoRequest},
response::ResponseFuture,
routing::Route,
};

/// Approve or reject guild join request.
///
/// Requires the [`KICK_MEMBERS`] permission.
///
/// # Examples
///
/// ```no_run
/// use twilight_http::Client;
/// use twilight_model::id::Id;
///
/// # #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let client = Client::new("token".to_owned());
///
/// let guild_id = Id::new(101);
/// let request_id = Id::new(102);
/// let new_status = JoinRequestStatus::Approved;
/// let application = client.update_guild_join_request(guild_id, request_id, new_status).await?.model().await?;
///
/// if new_status == application.application_status {
/// println!("User approved");
/// } else {
/// println!("Failed to approve user");
/// }
/// # Ok(()) }
/// ```
///
/// [`KICK_MEMBERS`]: twilight_model::guild::Permissions::KICK_MEMBERS
#[must_use = "application_status must be checked. Approving an already denied join request (and vice versa) can yield a success response, despite no change being applied."]
pub struct UpdateGuildJoinRequest<'a> {
/// ID of the guild.
guild_id: Id<GuildMarker>,
http: &'a Client,
/// ID of the join request.
request_id: Id<JoinRequestMarker>,
// The new request status.
new_status: JoinRequestStatus,
}

impl<'a> UpdateGuildJoinRequest<'a> {
pub(crate) const fn new(
http: &'a Client,
guild_id: Id<GuildMarker>,
request_id: Id<JoinRequestMarker>,
new_status: JoinRequestStatus,
) -> Self {
Self {
guild_id,
http,
request_id,
new_status,
}
}
}

impl IntoFuture for UpdateGuildJoinRequest<'_> {
type Output = Result<Response<JoinRequest>, Error>;

type IntoFuture = ResponseFuture<JoinRequest>;

fn into_future(self) -> Self::IntoFuture {
let http = self.http;

match self.try_into_request() {
Ok(request) => http.request(request),
Err(source) => ResponseFuture::error(source),
}
}
}

#[derive(Serialize)]
struct StatusPatch {
action: JoinRequestStatus,
}

impl TryIntoRequest for UpdateGuildJoinRequest<'_> {
fn try_into_request(self) -> Result<Request, Error> {
Request::builder(&Route::UpdateGuildJoinRequest {
guild_id: self.guild_id.get(),
request_id: self.request_id.get(),
})
.json(&StatusPatch {
action: self.new_status,
})
.build()
}
}

#[cfg(test)]
mod tests {
use super::{JoinRequestStatus, StatusPatch, UpdateGuildJoinRequest};
use crate::{
Client,
request::{Request, TryIntoRequest},
routing::Route,
};
use std::error::Error;
use twilight_model::id::Id;

#[test]
fn request() -> Result<(), Box<dyn Error>> {
let client = Client::new("token".to_string());
let guild_id = Id::new(101);
let request_id = Id::new(102);
let new_status = JoinRequestStatus::Approved;

let actual = UpdateGuildJoinRequest::new(&client, guild_id, request_id, new_status)
.try_into_request()?;

let expected = Request::builder(&Route::UpdateGuildJoinRequest {
guild_id: guild_id.into(),
request_id: request_id.into(),
})
.json(&StatusPatch { action: new_status })
.build()?;

assert_eq!(expected.body(), actual.body());
assert_eq!(expected.path(), actual.path());

Ok(())
}
}
3 changes: 3 additions & 0 deletions twilight-http/src/request/try_into_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ mod private {
CreateRole, DeleteRole, GetGuildRoleMemberCounts, GetGuildRoles, GetRole,
UpdateRole, UpdateRolePositions,
},
screening::{GetGuildJoinRequests, UpdateGuildJoinRequest},
sticker::{
CreateGuildSticker, DeleteGuildSticker, GetGuildSticker, GetGuildStickers,
UpdateGuildSticker,
Expand Down Expand Up @@ -218,6 +219,7 @@ mod private {
impl Sealed for GetGuildCommands<'_> {}
impl Sealed for GetGuildIntegrations<'_> {}
impl Sealed for GetGuildInvites<'_> {}
impl Sealed for GetGuildJoinRequests<'_> {}
impl Sealed for GetGuildMembers<'_> {}
impl Sealed for GetGuildOnboarding<'_> {}
impl Sealed for GetGuildPreview<'_> {}
Expand Down Expand Up @@ -282,6 +284,7 @@ mod private {
impl Sealed for UpdateGuild<'_> {}
impl Sealed for UpdateGuildChannelPositions<'_> {}
impl Sealed for UpdateGuildCommand<'_> {}
impl Sealed for UpdateGuildJoinRequest<'_> {}
impl Sealed for UpdateGuildMember<'_> {}
impl Sealed for UpdateGuildMfa<'_> {}
impl Sealed for UpdateGuildOnboarding<'_> {}
Expand Down
Loading
Loading