twilight_http/request/guild/emoji/
create_emoji.rs1#[cfg(not(target_os = "wasi"))]
2use crate::response::{Response, ResponseFuture};
3use crate::{
4 client::Client,
5 error::Error,
6 request::{self, AuditLogReason, Request, TryIntoRequest},
7 routing::Route,
8};
9use serde::Serialize;
10use std::future::IntoFuture;
11use twilight_model::{
12 guild::Emoji,
13 id::{
14 Id,
15 marker::{GuildMarker, RoleMarker},
16 },
17};
18use twilight_validate::request::{ValidationError, audit_reason as validate_audit_reason};
19
20#[derive(Serialize)]
21struct CreateEmojiFields<'a> {
22 image: &'a str,
23 name: &'a str,
24 #[serde(skip_serializing_if = "Option::is_none")]
25 roles: Option<&'a [Id<RoleMarker>]>,
26}
27
28#[must_use = "requests must be configured and executed"]
36pub struct CreateEmoji<'a> {
37 fields: CreateEmojiFields<'a>,
38 guild_id: Id<GuildMarker>,
39 http: &'a Client,
40 reason: Result<Option<&'a str>, ValidationError>,
41}
42
43impl<'a> CreateEmoji<'a> {
44 pub(crate) const fn new(
45 http: &'a Client,
46 guild_id: Id<GuildMarker>,
47 name: &'a str,
48 image: &'a str,
49 ) -> Self {
50 Self {
51 fields: CreateEmojiFields {
52 image,
53 name,
54 roles: None,
55 },
56 guild_id,
57 http,
58 reason: Ok(None),
59 }
60 }
61
62 pub const fn roles(mut self, roles: &'a [Id<RoleMarker>]) -> Self {
68 self.fields.roles = Some(roles);
69
70 self
71 }
72}
73
74impl<'a> AuditLogReason<'a> for CreateEmoji<'a> {
75 fn reason(mut self, reason: &'a str) -> Self {
76 self.reason = validate_audit_reason(reason).and(Ok(Some(reason)));
77
78 self
79 }
80}
81
82#[cfg(not(target_os = "wasi"))]
83impl IntoFuture for CreateEmoji<'_> {
84 type Output = Result<Response<Emoji>, Error>;
85
86 type IntoFuture = ResponseFuture<Emoji>;
87
88 fn into_future(self) -> Self::IntoFuture {
89 let http = self.http;
90
91 match self.try_into_request() {
92 Ok(request) => http.request(request),
93 Err(source) => ResponseFuture::error(source),
94 }
95 }
96}
97
98impl TryIntoRequest for CreateEmoji<'_> {
99 fn try_into_request(self) -> Result<Request, Error> {
100 let mut request = Request::builder(&Route::CreateEmoji {
101 guild_id: self.guild_id.get(),
102 });
103
104 request = request.json(&self.fields);
105
106 if let Some(reason) = self.reason.map_err(Error::validation)? {
107 request = request.headers(request::audit_header(reason)?);
108 }
109
110 request.build()
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117 use std::error::Error;
118
119 #[test]
120 fn test_create_emoji() -> Result<(), Box<dyn Error>> {
121 const GUILD_ID: Id<GuildMarker> = Id::new(1);
122 const ROLE_ID: Id<RoleMarker> = Id::new(2);
123
124 let client = Client::new("token".into());
125
126 {
127 let expected = r#"{"image":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI","name":"square"}"#;
128 let actual = CreateEmoji::new(
129 &client,
130 GUILD_ID,
131 "square",
132 "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI",
133 )
134 .try_into_request()?;
135
136 assert_eq!(Some(expected.as_bytes()), actual.body());
137 }
138
139 {
140 let expected = r#"{"image":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI","name":"square","roles":["2"]}"#;
141 let actual = CreateEmoji::new(
142 &client,
143 GUILD_ID,
144 "square",
145 "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI",
146 )
147 .roles(&[ROLE_ID])
148 .try_into_request()?;
149
150 assert_eq!(Some(expected.as_bytes()), actual.body());
151 }
152 Ok(())
153 }
154}