Skip to main content

twilight_http/request/scheduled_event/create_guild_scheduled_event/
mod.rs

1mod external;
2mod stage_instance;
3mod voice;
4
5pub use self::{
6    external::CreateGuildExternalScheduledEvent,
7    stage_instance::CreateGuildStageInstanceScheduledEvent, voice::CreateGuildVoiceScheduledEvent,
8};
9
10use super::EntityMetadataFields;
11use crate::{
12    client::Client,
13    error::Error,
14    request::{AuditLogReason, Request},
15    response::ResponseFuture,
16    routing::Route,
17};
18use serde::Serialize;
19use twilight_model::{
20    guild::scheduled_event::{
21        EntityType, GuildScheduledEvent, PrivacyLevel, recurrence_rule::RecurrenceRule,
22    },
23    id::{
24        Id,
25        marker::{ChannelMarker, GuildMarker},
26    },
27    util::Timestamp,
28};
29use twilight_validate::request::{
30    ValidationError, audit_reason as validate_audit_reason,
31    scheduled_event_name as validate_scheduled_event_name,
32};
33
34#[derive(Serialize)]
35struct CreateGuildScheduledEventFields<'a> {
36    #[serde(skip_serializing_if = "Option::is_none")]
37    channel_id: Option<Id<ChannelMarker>>,
38    #[serde(skip_serializing_if = "Option::is_none")]
39    description: Option<&'a str>,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    entity_metadata: Option<EntityMetadataFields<'a>>,
42    #[serde(skip_serializing_if = "Option::is_none")]
43    entity_type: Option<EntityType>,
44    #[serde(skip_serializing_if = "Option::is_none")]
45    image: Option<&'a str>,
46    #[serde(skip_serializing_if = "Option::is_none")]
47    name: Option<&'a str>,
48    #[serde(skip_serializing_if = "Option::is_none")]
49    privacy_level: Option<PrivacyLevel>,
50    #[serde(skip_serializing_if = "Option::is_none")]
51    recurrence_rule: Option<&'a RecurrenceRule>,
52    #[serde(skip_serializing_if = "Option::is_none")]
53    scheduled_end_time: Option<&'a Timestamp>,
54    #[serde(skip_serializing_if = "Option::is_none")]
55    scheduled_start_time: Option<&'a Timestamp>,
56}
57
58/// Create a scheduled event in a guild.
59///
60/// Once a guild is selected, you must choose one of three event types to
61/// create. The request builders will ensure you provide the correct data to
62/// Discord. See [Discord Docs/Create Guild Schedule Event].
63///
64/// The name must be between 1 and 100 characters in length. For external
65/// events, the location must be between 1 and 100 characters in length.
66///
67/// # Examples
68///
69/// Create an event in a stage instance:
70///
71/// ```no_run
72/// # use twilight_http::Client;
73/// use twilight_model::{guild::scheduled_event::PrivacyLevel, id::Id, util::Timestamp};
74/// # #[tokio::main]
75/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
76/// # let client = Client::new("token".to_owned());
77/// let guild_id = Id::new(1);
78/// let channel_id = Id::new(2);
79/// let garfield_start_time = Timestamp::parse("2022-01-01T14:00:00+00:00")?;
80///
81/// client
82///     .create_guild_scheduled_event(guild_id, PrivacyLevel::GuildOnly)
83///     .stage_instance(
84///         channel_id,
85///         "Garfield Appreciation Hour",
86///         &garfield_start_time,
87///     )
88///     .description("Discuss: How important is Garfield to You?")
89///     .await?;
90/// # Ok(()) }
91/// ```
92///
93/// Create an external event:
94///
95/// ```no_run
96/// # use twilight_http::Client;
97/// use twilight_model::{guild::scheduled_event::PrivacyLevel, id::Id, util::Timestamp};
98/// # #[tokio::main]
99/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
100/// # let client = Client::new("token".to_owned());
101/// let guild_id = Id::new(1);
102/// let garfield_con_start_time = Timestamp::parse("2022-01-04T08:00:00+00:00")?;
103/// let garfield_con_end_time = Timestamp::parse("2022-01-06T17:00:00+00:00")?;
104///
105/// client
106///     .create_guild_scheduled_event(guild_id, PrivacyLevel::GuildOnly)
107///     .external(
108///         "Garfield Con 2022",
109///         "Baltimore Convention Center",
110///         &garfield_con_start_time,
111///         &garfield_con_end_time,
112///     )
113///     .description(
114///         "In a spiritual successor to BronyCon, Garfield fans from \
115/// around the globe celebrate all things related to the loveable cat.",
116///     )
117///     .await?;
118/// # Ok(()) }
119/// ```
120///
121/// [Discord Docs/Create Guild Scheduled Event]: https://discord.com/developers/docs/resources/guild-scheduled-event#create-guild-scheduled-event
122pub struct CreateGuildScheduledEvent<'a> {
123    guild_id: Id<GuildMarker>,
124    http: &'a Client,
125    fields: Result<CreateGuildScheduledEventFields<'a>, ValidationError>,
126    reason: Result<Option<&'a str>, ValidationError>,
127}
128
129impl<'a> CreateGuildScheduledEvent<'a> {
130    pub(crate) const fn new(
131        http: &'a Client,
132        guild_id: Id<GuildMarker>,
133        privacy_level: PrivacyLevel,
134    ) -> Self {
135        Self {
136            guild_id,
137            http,
138            fields: Ok(CreateGuildScheduledEventFields {
139                channel_id: None,
140                description: None,
141                entity_metadata: None,
142                entity_type: None,
143                image: None,
144                name: None,
145                privacy_level: Some(privacy_level),
146                recurrence_rule: None,
147                scheduled_end_time: None,
148                scheduled_start_time: None,
149            }),
150            reason: Ok(None),
151        }
152    }
153
154    /// Create an external scheduled event in a guild.
155    ///
156    /// The name must be between 1 and 100 characters in length.
157    ///
158    /// # Errors
159    ///
160    /// Returns an error of type [`ScheduledEventName`] if the name is invalid.
161    ///
162    /// [`ScheduledEventName`]: twilight_validate::request::ValidationErrorType::ScheduledEventName
163    pub fn external(
164        mut self,
165        name: &'a str,
166        location: &'a str,
167        scheduled_start_time: &'a Timestamp,
168        scheduled_end_time: &'a Timestamp,
169    ) -> CreateGuildExternalScheduledEvent<'a> {
170        self.fields = self.fields.and_then(|mut fields| {
171            validate_scheduled_event_name(name)?;
172
173            fields.name.replace(name);
174
175            Ok(fields)
176        });
177
178        CreateGuildExternalScheduledEvent::new(
179            self,
180            name,
181            location,
182            scheduled_start_time,
183            scheduled_end_time,
184        )
185    }
186
187    /// Create a stage instance scheduled event in a guild.
188    ///
189    /// The name must be between 1 and 100 characters in length.
190    ///
191    /// # Errors
192    ///
193    /// Returns an error of type [`ScheduledEventName`] if the name is invalid.
194    ///
195    /// [`ScheduledEventName`]: twilight_validate::request::ValidationErrorType::ScheduledEventName
196    pub fn stage_instance(
197        mut self,
198        channel_id: Id<ChannelMarker>,
199        name: &'a str,
200        scheduled_start_time: &'a Timestamp,
201    ) -> CreateGuildStageInstanceScheduledEvent<'a> {
202        self.fields = self.fields.and_then(|mut fields| {
203            validate_scheduled_event_name(name)?;
204            fields.name.replace(name);
205
206            Ok(fields)
207        });
208
209        CreateGuildStageInstanceScheduledEvent::new(self, channel_id, name, scheduled_start_time)
210    }
211
212    /// Create a voice channel scheduled event in a guild.
213    ///
214    /// The name must be between 1 and 100 characters in length.
215    ///
216    /// # Errors
217    ///
218    /// Returns an error of type [`ScheduledEventName`] if the name is invalid.
219    ///
220    /// [`ScheduledEventName`]: twilight_validate::request::ValidationErrorType::ScheduledEventName
221    pub fn voice(
222        mut self,
223        channel_id: Id<ChannelMarker>,
224        name: &'a str,
225        scheduled_start_time: &'a Timestamp,
226    ) -> CreateGuildVoiceScheduledEvent<'a> {
227        self.fields = self.fields.and_then(|mut fields| {
228            validate_scheduled_event_name(name)?;
229            fields.name.replace(name);
230
231            Ok(fields)
232        });
233
234        CreateGuildVoiceScheduledEvent::new(self, channel_id, name, scheduled_start_time)
235    }
236
237    fn exec(self) -> ResponseFuture<GuildScheduledEvent> {
238        let http = self.http;
239
240        match self.try_into_request() {
241            Ok(request) => http.request(request),
242            Err(source) => ResponseFuture::error(source),
243        }
244    }
245
246    fn try_into_request(self) -> Result<Request, Error> {
247        let fields = self.fields.map_err(Error::validation)?;
248
249        Request::builder(&Route::CreateGuildScheduledEvent {
250            guild_id: self.guild_id.get(),
251        })
252        .json(&fields)
253        .build()
254    }
255}
256
257impl<'a> AuditLogReason<'a> for CreateGuildScheduledEvent<'a> {
258    fn reason(mut self, reason: &'a str) -> Self {
259        self.reason = validate_audit_reason(reason).and(Ok(Some(reason)));
260
261        self
262    }
263}