Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(model, cache): Add support for application editing and new application fields #2284

Merged
3 changes: 3 additions & 0 deletions twilight-http-ratelimiting/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ pub enum Path {
ApplicationGuildCommand(u64),
/// Operating on a specific command in a guild.
ApplicationGuildCommandId(u64),
/// Operating on current user application,
ApplicationsMe,
/// Operating on a channel.
ChannelsId(u64),
/// Operating on a channel's followers.
Expand Down Expand Up @@ -330,6 +332,7 @@ impl FromStr for Path {
let parts = s.split('/').skip(skip).collect::<Vec<&str>>();

Ok(match parts[..] {
["applications", "me"] => ApplicationsMe,
["applications", id, "commands"] => ApplicationCommand(parse_id(id)?),
["applications", id, "commands", _] => ApplicationCommandId(parse_id(id)?),
["applications", id, "guilds", _, "commands"]
Expand Down
7 changes: 6 additions & 1 deletion twilight-http/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::request::{
update_guild_onboarding::{UpdateGuildOnboarding, UpdateGuildOnboardingFields},
GetGuildOnboarding,
},
GetCurrentAuthorizationInformation,
GetCurrentAuthorizationInformation, UpdateCurrentUserApplication,
};
#[allow(deprecated)]
use crate::{
Expand Down Expand Up @@ -698,6 +698,11 @@ impl Client {
GetUserApplicationInfo::new(self)
}

/// Update the current user's application.
pub const fn update_current_user_application(&self) -> UpdateCurrentUserApplication<'_> {
UpdateCurrentUserApplication::new(self)
}

/// Update the current user.
///
/// All parameters are optional. If the username is changed, it may cause the discriminator to
Expand Down
2 changes: 2 additions & 0 deletions twilight-http/src/request/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ mod get_user_application;
mod get_voice_regions;
mod multipart;
mod try_into_request;
mod update_user_application;

pub use self::{
audit_reason::AuditLogReason,
Expand All @@ -69,6 +70,7 @@ pub use self::{
get_voice_regions::GetVoiceRegions,
multipart::Form,
try_into_request::TryIntoRequest,
update_user_application::UpdateCurrentUserApplication,
};
pub use twilight_http_ratelimiting::request::Method;

Expand Down
2 changes: 2 additions & 0 deletions twilight-http/src/request/try_into_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ mod private {
CreateGuildFromTemplate, CreateTemplate, DeleteTemplate, GetTemplate, GetTemplates,
SyncTemplate, UpdateTemplate,
},
update_user_application::UpdateCurrentUserApplication,
user::{
CreatePrivateChannel, GetCurrentUser, GetCurrentUserConnections,
GetCurrentUserGuildMember, GetCurrentUserGuilds, GetUser, LeaveGuild,
Expand Down Expand Up @@ -269,6 +270,7 @@ mod private {
impl Sealed for UpdateWebhook<'_> {}
impl Sealed for UpdateWebhookMessage<'_> {}
impl Sealed for UpdateWebhookWithToken<'_> {}
impl Sealed for UpdateCurrentUserApplication<'_> {}
}

use super::base::Request;
Expand Down
180 changes: 180 additions & 0 deletions twilight-http/src/request/update_user_application.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
use std::future::IntoFuture;

use serde::Serialize;
use twilight_model::oauth::{Application, ApplicationFlags, InstallParams};

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

#[derive(Serialize)]
struct UpdateCurrentUserApplicationFields<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
cover_image: Option<Nullable<&'a str>>,
#[serde(skip_serializing_if = "Option::is_none")]
custom_install_url: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
flags: Option<ApplicationFlags>,
#[serde(skip_serializing_if = "Option::is_none")]
icon: Option<Nullable<&'a str>>,
#[serde(skip_serializing_if = "Option::is_none")]
install_params: Option<InstallParams>,
#[serde(skip_serializing_if = "Option::is_none")]
interactions_endpoint_url: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
role_connections_verification_url: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
tags: Option<Vec<&'a str>>,
}

/// Update the current user's application.
///
/// Returns the newly updated application.
///
/// Refer to [Discord Docs/Update Current User Application][1].
///
/// # Examples
///
/// ```no_run
/// # #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// use std::env;
/// use twilight_http::Client;
///
/// let bearer_token = env::var("BEARER_TOKEN")?;
///
/// let client = Client::new(bearer_token);
/// let response = client
/// .update_current_user_application()
/// .description("My cool application")
/// .await?;
/// let application = response.model().await?;
///
/// println!("Application: {}", application.description);
///
/// # Ok(()) }
/// ```
///
/// [1]: https://discord.com/developers/docs/resources/application#edit-current-application
#[must_use = "requests must be configured and executed"]
pub struct UpdateCurrentUserApplication<'a> {
fields: UpdateCurrentUserApplicationFields<'a>,
http: &'a Client,
}

impl<'a> UpdateCurrentUserApplication<'a> {
pub(crate) const fn new(http: &'a Client) -> Self {
Self {
fields: UpdateCurrentUserApplicationFields {
cover_image: None,
custom_install_url: None,
description: None,
flags: None,
icon: None,
install_params: None,
interactions_endpoint_url: None,
role_connections_verification_url: None,
tags: None,
},
http,
}
}

/// Sets the cover image of the application.
pub const fn cover_image(mut self, cover_image: Option<&'a str>) -> Self {
self.fields.cover_image = Some(Nullable(cover_image));

self
}

/// Sets the custom install URL of the application.
pub const fn custom_install_url(mut self, custom_install_url: &'a str) -> Self {
self.fields.custom_install_url = Some(custom_install_url);

self
}

/// Sets the description of the application.
pub const fn description(mut self, description: &'a str) -> Self {
self.fields.description = Some(description);

self
}

/// Sets the flags of the application.
/// Only limited intent flags (`GATEWAY_PRESENCE_LIMITED`, `GATEWAY_GUILD_MEMBERS_LIMITED`,
/// and `GATEWAY_MESSAGE_CONTENT_LIMITED`) can be updated via the API.
pub const fn flags(mut self, flags: ApplicationFlags) -> Self {
self.fields.flags = Some(flags);

self
}

/// Sets the icon of the application.
pub const fn icon(mut self, icon: Option<&'a str>) -> Self {
self.fields.icon = Some(Nullable(icon));

self
}

/// Sets the install params of the application.
pub fn install_params(mut self, install_params: InstallParams) -> Self {
self.fields.install_params = Some(install_params);

self
}

/// Sets the interactions endpoint URL of the application.
pub const fn interactions_endpoint_url(mut self, interactions_endpoint_url: &'a str) -> Self {
self.fields.interactions_endpoint_url = Some(interactions_endpoint_url);

self
}

/// Sets the role connections verification URL of the application.
pub const fn role_connections_verification_url(
mut self,
role_connections_verification_url: &'a str,
) -> Self {
self.fields.role_connections_verification_url = Some(role_connections_verification_url);

self
}

/// Sets the tags of the application.
pub fn tags(mut self, tags: Vec<&'a str>) -> Self {
self.fields.tags = Some(tags);

self
}
}

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

type IntoFuture = ResponseFuture<Application>;

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 UpdateCurrentUserApplication<'_> {
fn try_into_request(self) -> Result<Request, Error> {
let mut request = Request::builder(&Route::UpdateCurrentUserApplication);

request = request.json(&self.fields)?;

Ok(request.build())
}
}
23 changes: 19 additions & 4 deletions twilight-http/src/routing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ use twilight_model::id::{marker::RoleMarker, Id};
#[non_exhaustive]
pub enum Route<'a> {
/// Route information to add a user to a guild.
AddGuildMember { guild_id: u64, user_id: u64 },
AddGuildMember {
guild_id: u64,
user_id: u64,
},
/// Route information to add a role to guild member.
AddMemberRole {
/// The ID of the guild.
Expand Down Expand Up @@ -1099,6 +1102,7 @@ pub enum Route<'a> {
token: &'a str,
webhook_id: u64,
},
UpdateCurrentUserApplication,
}

impl<'a> Route<'a> {
Expand Down Expand Up @@ -1249,6 +1253,7 @@ impl<'a> Route<'a> {
| Self::UpdateTemplate { .. }
| Self::UpdateUserVoiceState { .. }
| Self::UpdateWebhookMessage { .. }
| Self::UpdateCurrentUserApplication
| Self::UpdateWebhook { .. } => Method::Patch,
Self::CreateChannel { .. }
| Self::CreateGlobalCommand { .. }
Expand Down Expand Up @@ -1537,7 +1542,9 @@ impl<'a> Route<'a> {
Path::ApplicationGuildCommandId(application_id)
}
Self::GetCurrentAuthorizationInformation => Path::OauthMe,
Self::GetCurrentUserApplicationInfo => Path::OauthApplicationsMe,
Self::GetCurrentUserApplicationInfo | Self::UpdateCurrentUserApplication => {
Path::ApplicationsMe
}
Self::GetCurrentUser | Self::GetUser { .. } | Self::UpdateCurrentUser => Path::UsersId,
Self::GetCurrentUserGuildMember { .. } => Path::UsersIdGuildsIdMember,
Self::GetEmoji { guild_id, .. } | Self::UpdateEmoji { guild_id, .. } => {
Expand Down Expand Up @@ -2341,7 +2348,9 @@ impl Display for Route<'_> {
f.write_str("/permissions")
}
Route::GetCurrentAuthorizationInformation => f.write_str("oauth2/@me"),
Route::GetCurrentUserApplicationInfo => f.write_str("oauth2/applications/@me"),
Route::GetCurrentUserApplicationInfo | Route::UpdateCurrentUserApplication => {
f.write_str("applications/@me")
}
Route::GetCurrentUser | Route::UpdateCurrentUser => f.write_str("users/@me"),
Route::GetCurrentUserGuildMember { guild_id } => {
f.write_str("users/@me/guilds/")?;
Expand Down Expand Up @@ -4005,7 +4014,13 @@ mod tests {
#[test]
fn get_current_user_application_info() {
let route = Route::GetCurrentUserApplicationInfo;
assert_eq!(route.to_string(), "oauth2/applications/@me");
assert_eq!(route.to_string(), "applications/@me");
}

#[test]
fn update_current_user_application() {
let route = Route::UpdateCurrentUserApplication;
assert_eq!(route.to_string(), "applications/@me");
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion twilight-model/src/guild/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ use serde::{
};
use std::fmt::{Formatter, Result as FmtResult};

#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Hash)]
pub struct Guild {
pub afk_channel_id: Option<Id<ChannelMarker>>,
pub afk_timeout: AfkTimeout,
Expand Down
Loading