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(http,model): scheduled events #1347

Merged
merged 14 commits into from
Jan 13, 2022
11 changes: 11 additions & 0 deletions http-ratelimiting/src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,12 @@ pub enum Path {
GuildsIdRoles(u64),
/// Operating on a role of one of the user's guilds.
GuildsIdRolesId(u64),
/// Operating on the guild's scheduled events.
GuildsIdScheduledEvents(u64),
/// Operating on a particular guild's scheduled events.
GuildsIdScheduledEventsId(u64),
/// Operating on a particular guild's scheduled event users.
GuildsIdScheduledEventsIdUsers(u64),
/// Operating on one of the user's guilds' stickers.
GuildsIdStickers(u64),
/// Operating on one of the user's guilds' templates.
Expand Down Expand Up @@ -381,6 +387,11 @@ impl FromStr for Path {
["guilds", id, "regions"] => GuildsIdRegions(parse_id(id)?),
["guilds", id, "roles"] => GuildsIdRoles(parse_id(id)?),
["guilds", id, "roles", _] => GuildsIdRolesId(parse_id(id)?),
["guilds", id, "scheduled-events"] => GuildsIdScheduledEvents(parse_id(id)?),
["guilds", id, "scheduled-events", _] => GuildsIdScheduledEventsId(parse_id(id)?),
["guilds", id, "scheduled-events", _, "users"] => {
GuildsIdScheduledEventsIdUsers(parse_id(id)?)
}
["guilds", id, "stickers"] | ["guilds", id, "stickers", _] => {
GuildsIdStickers(parse_id(id)?)
}
Expand Down
166 changes: 165 additions & 1 deletion http/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ use crate::{
GetGuildWelcomeScreen, GetGuildWidget, UpdateCurrentMember, UpdateCurrentUserNick,
UpdateGuild, UpdateGuildChannelPositions, UpdateGuildWelcomeScreen, UpdateGuildWidget,
},
scheduled_event::{
CreateGuildScheduledEvent, DeleteGuildScheduledEvent, GetGuildScheduledEvent,
GetGuildScheduledEventUsers, GetGuildScheduledEvents, UpdateGuildScheduledEvent,
},
sticker::{GetNitroStickerPacks, GetSticker},
template::{
CreateGuildFromTemplate, CreateTemplate, DeleteTemplate, GetTemplate, GetTemplates,
Expand Down Expand Up @@ -92,7 +96,8 @@ use twilight_model::{
id::{
marker::{
ApplicationMarker, ChannelMarker, EmojiMarker, GuildMarker, IntegrationMarker,
MessageMarker, RoleMarker, StickerMarker, UserMarker, WebhookMarker,
MessageMarker, RoleMarker, ScheduledEventMarker, StickerMarker, UserMarker,
WebhookMarker,
},
Id,
},
Expand Down Expand Up @@ -1985,6 +1990,165 @@ impl Client {
DeleteWebhookMessage::new(self, webhook_id, token, message_id)
}

/// Delete a scheduled event in a guild.
///
/// # 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(1);
/// let scheduled_event_id = Id::new(2);
///
/// client
/// .delete_guild_scheduled_event(guild_id, scheduled_event_id)
/// .exec()
/// .await?;
/// # Ok(()) }
/// ```
pub const fn delete_guild_scheduled_event(
&self,
guild_id: Id<GuildMarker>,
scheduled_event_id: Id<ScheduledEventMarker>,
) -> DeleteGuildScheduledEvent<'_> {
DeleteGuildScheduledEvent::new(self, guild_id, scheduled_event_id)
}

/// Create a scheduled event in a guild.
///
/// Once a guild is selected, you must choose one of three event types to
/// create. The request builders will ensure you provide the correct data to
/// Discord. See [the Discord docs] for more information on which events
/// require which fields.
///
/// The name must be between 1 and 100 characters in length. For external
/// events, the location must be between 1 and 100 characters in length.
///
/// # Examples
///
/// Create an event in a stage instance:
///
/// ```no_run
/// # use twilight_http::Client;
/// use twilight_model::{datetime::Timestamp, 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(1);
/// let channel_id = Id::new(2);
/// let garfield_start_time = Timestamp::parse("2022-01-01T14:00:00+00:00")?;
///
/// client
/// .create_guild_scheduled_event(guild_id)
/// .stage_instance(
/// channel_id,
/// "Garfield Appreciation Hour",
/// &garfield_start_time
/// )?
/// .description("Discuss: How important is Garfield to You?")?
/// .exec()
/// .await?;
/// # Ok(()) }
/// ```
///
/// Create an external event:
///
/// ```no_run
/// # use twilight_http::Client;
/// use twilight_model::{datetime::Timestamp, 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(1);
/// let garfield_con_start_time = Timestamp::parse("2022-01-04T08:00:00+00:00")?;
/// let garfield_con_end_time = Timestamp::parse("2022-01-06T17:00:00+00:00")?;
///
/// client
/// .create_guild_scheduled_event(guild_id)
/// .external(
/// "Garfield Con 2022",
/// "Baltimore Convention Center",
/// &garfield_con_start_time,
/// &garfield_con_end_time
/// )?
/// .description("In a spiritual successor to BronyCon, Garfield fans \
/// from around the globe celebrate all things related to the loveable cat.")?
/// .exec()
/// .await?;
/// # Ok(()) }
/// ```
///
/// [the Discord docs]: https://discord.com/developers/docs/resources/guild-scheduled-event#create-guild-scheduled-event
pub const fn create_guild_scheduled_event(
&self,
guild_id: Id<GuildMarker>,
) -> CreateGuildScheduledEvent<'_> {
CreateGuildScheduledEvent::new(self, guild_id)
}

/// Get a scheduled event in a guild.
pub const fn guild_scheduled_event(
&self,
guild_id: Id<GuildMarker>,
scheduled_event_id: Id<ScheduledEventMarker>,
) -> GetGuildScheduledEvent<'_> {
GetGuildScheduledEvent::new(self, guild_id, scheduled_event_id)
}

/// Get a list of users subscribed to a scheduled event.
///
/// Users are returned in ascending order by `user_id`. [`before`] and
/// [`after`] both take a user id. If both are specified, only [`before`] is
/// respected. The default [`limit`] is 100. See [the Discord docs] for more
/// information.
///
/// [`after`]: GetGuildScheduledEventUsers::after
/// [`before`]: GetGuildScheduledEventUsers::before
/// [`limit`]: GetGuildScheduledEventUsers::limit
/// [the Discord docs]: https://discord.com/developers/docs/resources/guild-scheduled-event#get-guild-scheduled-event-users
pub const fn guild_scheduled_event_users(
&self,
guild_id: Id<GuildMarker>,
scheduled_event_id: Id<ScheduledEventMarker>,
) -> GetGuildScheduledEventUsers<'_> {
GetGuildScheduledEventUsers::new(self, guild_id, scheduled_event_id)
}

/// Get a list of scheduled events in a guild.
pub const fn guild_scheduled_events(
&self,
guild_id: Id<GuildMarker>,
) -> GetGuildScheduledEvents<'_> {
GetGuildScheduledEvents::new(self, guild_id)
}

/// Update a scheduled event in a guild.
///
/// This endpoint supports changing the type of event. When changing the
/// entity type to either [`EntityType::StageInstance`] or
/// [`EntityType::Voice`], an [`Id<ChannelMarker>`] must be provided if it
/// does not already exist.
///
/// When changing the entity type to [`EntityType::External`], the
/// `channel_id` field is cleared and the [`channel_id`] method has no
/// effect. Additionally, you must set a location with [`location`].
///
/// [`EntityType::External`]: twilight_model::scheduled_event::EntityType::External
/// [`EntityType::StageInstance`]: twilight_model::scheduled_event::EntityType::StageInstance
/// [`EntityType::Voice`]: twilight_model::scheduled_event::EntityType::Voice
/// [`channel_id`]: UpdateGuildScheduledEvent::channel_id
/// [`location`]: UpdateGuildScheduledEvent::location
pub const fn update_guild_scheduled_event(
&self,
guild_id: Id<GuildMarker>,
scheduled_event_id: Id<ScheduledEventMarker>,
) -> UpdateGuildScheduledEvent<'_> {
UpdateGuildScheduledEvent::new(self, guild_id, scheduled_event_id)
}

/// Returns a single sticker by its ID.
///
/// # Examples
Expand Down
10 changes: 10 additions & 0 deletions http/src/request/audit_reason.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ mod private {
sticker::{CreateGuildSticker, UpdateGuildSticker},
CreateGuildChannel, CreateGuildPrune, UpdateCurrentMember, UpdateGuild,
},
scheduled_event::{
CreateGuildExternalScheduledEvent, CreateGuildScheduledEvent,
CreateGuildStageInstanceScheduledEvent, CreateGuildVoiceScheduledEvent,
UpdateGuildScheduledEvent,
},
user::UpdateCurrentUser,
};

Expand Down Expand Up @@ -72,6 +77,11 @@ mod private {
impl Sealed for UpdateWebhookMessage<'_> {}
impl<'a> Sealed for UpdateCurrentUser<'a> {}
impl Sealed for UpdateCurrentMember<'_> {}
impl Sealed for CreateGuildScheduledEvent<'_> {}
impl Sealed for CreateGuildExternalScheduledEvent<'_> {}
impl Sealed for CreateGuildStageInstanceScheduledEvent<'_> {}
impl Sealed for CreateGuildVoiceScheduledEvent<'_> {}
impl Sealed for UpdateGuildScheduledEvent<'_> {}
}

impl AuditLogReasonError {
Expand Down
1 change: 1 addition & 0 deletions http/src/request/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod application;
pub mod channel;
pub mod guild;
pub mod scheduled_event;
pub mod sticker;
pub mod template;
pub mod user;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use super::{
super::EntityMetadataFields, CreateGuildScheduledEvent, CreateGuildScheduledEventFields,
};
use crate::{
error::Error,
request::{AuditLogReason, AuditLogReasonError, Request, TryIntoRequest},
response::ResponseFuture,
};
use twilight_model::{
datetime::Timestamp,
scheduled_event::{EntityType, GuildScheduledEvent},
};
use twilight_validate::request::{
scheduled_event_description as validate_scheduled_event_description, ValidationError,
};

/// Create an external scheduled event in a guild.
#[must_use = "requests must be configured and executed"]
pub struct CreateGuildExternalScheduledEvent<'a>(CreateGuildScheduledEvent<'a>);

#[allow(clippy::needless_pass_by_value)]
impl<'a> CreateGuildExternalScheduledEvent<'a> {
pub(crate) const fn new(
inner: CreateGuildScheduledEvent<'a>,
name: &'a str,
location: &'a str,
scheduled_start_time: &'a Timestamp,
scheduled_end_time: &'a Timestamp,
) -> Self {
Self(CreateGuildScheduledEvent {
fields: CreateGuildScheduledEventFields {
entity_type: Some(EntityType::External),
entity_metadata: Some(EntityMetadataFields {
location: Some(location),
}),
name: Some(name),
scheduled_end_time: Some(scheduled_end_time),
scheduled_start_time: Some(scheduled_start_time),
..inner.fields
},
..inner
})
}

/// Set the description of the event.
///
/// Must be between 1 and 1000 characters in length.
///
/// # Errors
///
/// Returns an error of type [`ScheduledEventDescription`] if the
/// description is invalid.
///
/// [`ScheduledEventDescription`]: twilight_validate::request::ValidationErrorType::ScheduledEventDescription
pub fn description(mut self, description: &'a str) -> Result<Self, ValidationError> {
validate_scheduled_event_description(description)?;

self.0.fields.description = Some(description);

Ok(self)
}

/// Execute the request, returning a future resolving to a [`Response`].
///
/// [`Response`]: crate::response::Response
pub fn exec(self) -> ResponseFuture<GuildScheduledEvent> {
self.0.exec()
}
}

impl<'a> AuditLogReason<'a> for CreateGuildExternalScheduledEvent<'a> {
fn reason(mut self, reason: &'a str) -> Result<Self, AuditLogReasonError> {
self.0
.reason
.replace(AuditLogReasonError::validate(reason)?);

Ok(self)
}
}

impl TryIntoRequest for CreateGuildExternalScheduledEvent<'_> {
fn try_into_request(self) -> Result<Request, Error> {
self.0.try_into_request()
}
}
Loading