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