1use diesel::{
2 ExpressionMethods, Insertable, QueryDsl, Queryable, Selectable, SelectableHelper, delete,
3 insert_into, update,
4};
5use diesel_async::{RunQueryDsl, pooled_connection::AsyncDieselConnectionManager};
6use serde::{Deserialize, Serialize};
7use uuid::Uuid;
8
9use crate::{
10 Conn, Data,
11 error::Error,
12 schema::{channel_permissions, channels, messages},
13 utils::{CHANNEL_REGEX, order_by_is_above},
14};
15
16use super::{HasIsAbove, HasUuid, Message, load_or_empty, message::MessageBuilder};
17
18#[derive(Queryable, Selectable, Insertable, Clone, Debug)]
19#[diesel(table_name = channels)]
20#[diesel(check_for_backend(diesel::pg::Pg))]
21struct ChannelBuilder {
22 uuid: Uuid,
23 guild_uuid: Uuid,
24 name: String,
25 description: Option<String>,
26 is_above: Option<Uuid>,
27}
28
29impl ChannelBuilder {
30 async fn build(self, conn: &mut Conn) -> Result<Channel, Error> {
31 use self::channel_permissions::dsl::*;
32 let channel_permission: Vec<ChannelPermission> = load_or_empty(
33 channel_permissions
34 .filter(channel_uuid.eq(self.uuid))
35 .select(ChannelPermission::as_select())
36 .load(conn)
37 .await,
38 )?;
39
40 Ok(Channel {
41 uuid: self.uuid,
42 guild_uuid: self.guild_uuid,
43 name: self.name,
44 description: self.description,
45 is_above: self.is_above,
46 permissions: channel_permission,
47 })
48 }
49}
50
51#[derive(Serialize, Deserialize, Clone, Debug)]
52pub struct Channel {
53 pub uuid: Uuid,
54 pub guild_uuid: Uuid,
55 name: String,
56 description: Option<String>,
57 pub is_above: Option<Uuid>,
58 pub permissions: Vec<ChannelPermission>,
59}
60
61#[derive(Serialize, Deserialize, Clone, Queryable, Selectable, Debug)]
62#[diesel(table_name = channel_permissions)]
63#[diesel(check_for_backend(diesel::pg::Pg))]
64pub struct ChannelPermission {
65 pub role_uuid: Uuid,
66 pub permissions: i64,
67}
68
69impl HasUuid for Channel {
70 fn uuid(&self) -> &Uuid {
71 self.uuid.as_ref()
72 }
73}
74
75impl HasIsAbove for Channel {
76 fn is_above(&self) -> Option<&Uuid> {
77 self.is_above.as_ref()
78 }
79}
80
81impl Channel {
82 pub async fn fetch_all(
83 pool: &deadpool::managed::Pool<
84 AsyncDieselConnectionManager<diesel_async::AsyncPgConnection>,
85 Conn,
86 >,
87 guild_uuid: Uuid,
88 ) -> Result<Vec<Self>, Error> {
89 let mut conn = pool.get().await?;
90
91 use channels::dsl;
92 let channel_builders: Vec<ChannelBuilder> = load_or_empty(
93 dsl::channels
94 .filter(dsl::guild_uuid.eq(guild_uuid))
95 .select(ChannelBuilder::as_select())
96 .load(&mut conn)
97 .await,
98 )?;
99
100 let channel_futures = channel_builders.iter().map(async move |c| {
101 let mut conn = pool.get().await?;
102 c.clone().build(&mut conn).await
103 });
104
105 futures::future::try_join_all(channel_futures).await
106 }
107
108 pub async fn fetch_one(data: &Data, channel_uuid: Uuid) -> Result<Self, Error> {
109 if let Ok(cache_hit) = data.get_cache_key(channel_uuid.to_string()).await {
110 return Ok(serde_json::from_str(&cache_hit)?);
111 }
112
113 let mut conn = data.pool.get().await?;
114
115 use channels::dsl;
116 let channel_builder: ChannelBuilder = dsl::channels
117 .filter(dsl::uuid.eq(channel_uuid))
118 .select(ChannelBuilder::as_select())
119 .get_result(&mut conn)
120 .await?;
121
122 let channel = channel_builder.build(&mut conn).await?;
123
124 data.set_cache_key(channel_uuid.to_string(), channel.clone(), 60)
125 .await?;
126
127 Ok(channel)
128 }
129
130 pub async fn new(
131 data: actix_web::web::Data<Data>,
132 guild_uuid: Uuid,
133 name: String,
134 description: Option<String>,
135 ) -> Result<Self, Error> {
136 if !CHANNEL_REGEX.is_match(&name) {
137 return Err(Error::BadRequest("Channel name is invalid".to_string()));
138 }
139
140 let mut conn = data.pool.get().await?;
141
142 let channel_uuid = Uuid::now_v7();
143
144 let channels = Self::fetch_all(&data.pool, guild_uuid).await?;
145
146 let channels_ordered = order_by_is_above(channels).await?;
147
148 let last_channel = channels_ordered.last();
149
150 let new_channel = ChannelBuilder {
151 uuid: channel_uuid,
152 guild_uuid,
153 name: name.clone(),
154 description: description.clone(),
155 is_above: None,
156 };
157
158 insert_into(channels::table)
159 .values(new_channel.clone())
160 .execute(&mut conn)
161 .await?;
162
163 if let Some(old_last_channel) = last_channel {
164 use channels::dsl;
165 update(channels::table)
166 .filter(dsl::uuid.eq(old_last_channel.uuid))
167 .set(dsl::is_above.eq(new_channel.uuid))
168 .execute(&mut conn)
169 .await?;
170 }
171
172 let channel = Self {
174 uuid: channel_uuid,
175 guild_uuid,
176 name,
177 description,
178 is_above: None,
179 permissions: vec![],
180 };
181
182 data.set_cache_key(channel_uuid.to_string(), channel.clone(), 1800)
183 .await?;
184
185 if data
186 .get_cache_key(format!("{}_channels", guild_uuid))
187 .await
188 .is_ok()
189 {
190 data.del_cache_key(format!("{}_channels", guild_uuid))
191 .await?;
192 }
193
194 Ok(channel)
195 }
196
197 pub async fn delete(self, data: &Data) -> Result<(), Error> {
198 let mut conn = data.pool.get().await?;
199
200 use channels::dsl;
201 match update(channels::table)
202 .filter(dsl::is_above.eq(self.uuid))
203 .set(dsl::is_above.eq(None::<Uuid>))
204 .execute(&mut conn)
205 .await
206 {
207 Ok(r) => Ok(r),
208 Err(diesel::result::Error::NotFound) => Ok(0),
209 Err(e) => Err(e),
210 }?;
211
212 delete(channels::table)
213 .filter(dsl::uuid.eq(self.uuid))
214 .execute(&mut conn)
215 .await?;
216
217 match update(channels::table)
218 .filter(dsl::is_above.eq(self.uuid))
219 .set(dsl::is_above.eq(self.is_above))
220 .execute(&mut conn)
221 .await
222 {
223 Ok(r) => Ok(r),
224 Err(diesel::result::Error::NotFound) => Ok(0),
225 Err(e) => Err(e),
226 }?;
227
228 if data.get_cache_key(self.uuid.to_string()).await.is_ok() {
229 data.del_cache_key(self.uuid.to_string()).await?;
230 }
231
232 if data
233 .get_cache_key(format!("{}_channels", self.guild_uuid))
234 .await
235 .is_ok()
236 {
237 data.del_cache_key(format!("{}_channels", self.guild_uuid))
238 .await?;
239 }
240
241 Ok(())
242 }
243
244 pub async fn fetch_messages(
245 &self,
246 data: &Data,
247 amount: i64,
248 offset: i64,
249 ) -> Result<Vec<Message>, Error> {
250 let mut conn = data.pool.get().await?;
251
252 use messages::dsl;
253 let messages: Vec<MessageBuilder> = load_or_empty(
254 dsl::messages
255 .filter(dsl::channel_uuid.eq(self.uuid))
256 .select(MessageBuilder::as_select())
257 .order(dsl::uuid.desc())
258 .limit(amount)
259 .offset(offset)
260 .load(&mut conn)
261 .await,
262 )?;
263
264 let message_futures = messages.iter().map(async move |b| b.build(data).await);
265
266 futures::future::try_join_all(message_futures).await
267 }
268
269 pub async fn new_message(
270 &self,
271 data: &Data,
272 user_uuid: Uuid,
273 message: String,
274 ) -> Result<Message, Error> {
275 let message_uuid = Uuid::now_v7();
276
277 let message = MessageBuilder {
278 uuid: message_uuid,
279 channel_uuid: self.uuid,
280 user_uuid,
281 message,
282 };
283
284 let mut conn = data.pool.get().await?;
285
286 insert_into(messages::table)
287 .values(message.clone())
288 .execute(&mut conn)
289 .await?;
290
291 message.build(data).await
292 }
293
294 pub async fn set_name(&mut self, data: &Data, new_name: String) -> Result<(), Error> {
295 if !CHANNEL_REGEX.is_match(&new_name) {
296 return Err(Error::BadRequest("Channel name is invalid".to_string()));
297 }
298
299 let mut conn = data.pool.get().await?;
300
301 use channels::dsl;
302 update(channels::table)
303 .filter(dsl::uuid.eq(self.uuid))
304 .set(dsl::name.eq(&new_name))
305 .execute(&mut conn)
306 .await?;
307
308 self.name = new_name;
309
310 Ok(())
311 }
312
313 pub async fn set_description(
314 &mut self,
315 data: &Data,
316 new_description: String,
317 ) -> Result<(), Error> {
318 let mut conn = data.pool.get().await?;
319
320 use channels::dsl;
321 update(channels::table)
322 .filter(dsl::uuid.eq(self.uuid))
323 .set(dsl::description.eq(&new_description))
324 .execute(&mut conn)
325 .await?;
326
327 self.description = Some(new_description);
328
329 Ok(())
330 }
331
332 pub async fn move_channel(&mut self, data: &Data, new_is_above: Uuid) -> Result<(), Error> {
333 let mut conn = data.pool.get().await?;
334
335 use channels::dsl;
336 let old_above_uuid: Option<Uuid> = match dsl::channels
337 .filter(dsl::is_above.eq(self.uuid))
338 .select(dsl::uuid)
339 .get_result(&mut conn)
340 .await
341 {
342 Ok(r) => Ok(Some(r)),
343 Err(diesel::result::Error::NotFound) => Ok(None),
344 Err(e) => Err(e),
345 }?;
346
347 if let Some(uuid) = old_above_uuid {
348 update(channels::table)
349 .filter(dsl::uuid.eq(uuid))
350 .set(dsl::is_above.eq(None::<Uuid>))
351 .execute(&mut conn)
352 .await?;
353 }
354
355 match update(channels::table)
356 .filter(dsl::is_above.eq(new_is_above))
357 .set(dsl::is_above.eq(self.uuid))
358 .execute(&mut conn)
359 .await
360 {
361 Ok(r) => Ok(r),
362 Err(diesel::result::Error::NotFound) => Ok(0),
363 Err(e) => Err(e),
364 }?;
365
366 update(channels::table)
367 .filter(dsl::uuid.eq(self.uuid))
368 .set(dsl::is_above.eq(new_is_above))
369 .execute(&mut conn)
370 .await?;
371
372 if let Some(uuid) = old_above_uuid {
373 update(channels::table)
374 .filter(dsl::uuid.eq(uuid))
375 .set(dsl::is_above.eq(self.is_above))
376 .execute(&mut conn)
377 .await?;
378 }
379
380 self.is_above = Some(new_is_above);
381
382 Ok(())
383 }
384}