1use actix_web::web::BytesMut;
2use diesel::{ExpressionMethods, QueryDsl, Queryable, Selectable, SelectableHelper, update};
3use diesel_async::RunQueryDsl;
4use serde::Serialize;
5use tokio::task;
6use url::Url;
7use uuid::Uuid;
8
9use crate::{
10 Conn, Data,
11 error::Error,
12 schema::{guild_members, guilds, users},
13 utils::{EMAIL_REGEX, USERNAME_REGEX, image_check},
14};
15
16use super::{Guild, guild::GuildBuilder, load_or_empty, member::MemberBuilder};
17
18#[derive(Serialize, Queryable, Selectable)]
19#[diesel(table_name = users)]
20#[diesel(check_for_backend(diesel::pg::Pg))]
21pub struct Me {
22 pub uuid: Uuid,
23 pub username: String,
24 pub display_name: Option<String>,
25 avatar: Option<String>,
26 pronouns: Option<String>,
27 about: Option<String>,
28 pub email: String,
29 pub email_verified: bool,
30}
31
32impl Me {
33 pub async fn get(conn: &mut Conn, user_uuid: Uuid) -> Result<Self, Error> {
34 use users::dsl;
35 let me: Me = dsl::users
36 .filter(dsl::uuid.eq(user_uuid))
37 .select(Me::as_select())
38 .get_result(conn)
39 .await?;
40
41 Ok(me)
42 }
43
44 pub async fn fetch_memberships(&self, conn: &mut Conn) -> Result<Vec<Guild>, Error> {
45 use guild_members::dsl;
46 let memberships: Vec<MemberBuilder> = load_or_empty(
47 dsl::guild_members
48 .filter(dsl::user_uuid.eq(self.uuid))
49 .select(MemberBuilder::as_select())
50 .load(conn)
51 .await,
52 )?;
53
54 let mut guilds: Vec<Guild> = vec![];
55
56 for membership in memberships {
57 use guilds::dsl;
58 guilds.push(
59 dsl::guilds
60 .filter(dsl::uuid.eq(membership.guild_uuid))
61 .select(GuildBuilder::as_select())
62 .get_result(conn)
63 .await?
64 .build(conn)
65 .await?,
66 )
67 }
68
69 Ok(guilds)
70 }
71
72 pub async fn set_avatar(
73 &mut self,
74 data: &Data,
75 cdn_url: Url,
76 avatar: BytesMut,
77 ) -> Result<(), Error> {
78 let avatar_clone = avatar.clone();
79 let image_type = task::spawn_blocking(move || image_check(avatar_clone)).await??;
80
81 let mut conn = data.pool.get().await?;
82
83 if let Some(avatar) = &self.avatar {
84 let avatar_url: Url = avatar.parse()?;
85
86 let relative_url = avatar_url.path().trim_start_matches('/');
87
88 data.bunny_cdn.storage.delete(relative_url).await?;
89 }
90
91 let path = format!("avatar/{}/avatar.{}", self.uuid, image_type);
92
93 data.bunny_cdn
94 .storage
95 .upload(path.clone(), avatar.into())
96 .await?;
97
98 let avatar_url = cdn_url.join(&path)?;
99
100 use users::dsl;
101 update(users::table)
102 .filter(dsl::uuid.eq(self.uuid))
103 .set(dsl::avatar.eq(avatar_url.as_str()))
104 .execute(&mut conn)
105 .await?;
106
107 if data.get_cache_key(self.uuid.to_string()).await.is_ok() {
108 data.del_cache_key(self.uuid.to_string()).await?
109 }
110
111 self.avatar = Some(avatar_url.to_string());
112
113 Ok(())
114 }
115
116 pub async fn verify_email(&self, conn: &mut Conn) -> Result<(), Error> {
117 use users::dsl;
118 update(users::table)
119 .filter(dsl::uuid.eq(self.uuid))
120 .set(dsl::email_verified.eq(true))
121 .execute(conn)
122 .await?;
123
124 Ok(())
125 }
126
127 pub async fn set_username(&mut self, data: &Data, new_username: String) -> Result<(), Error> {
128 if !USERNAME_REGEX.is_match(&new_username) {
129 return Err(Error::BadRequest("Invalid username".to_string()));
130 }
131
132 let mut conn = data.pool.get().await?;
133
134 use users::dsl;
135 update(users::table)
136 .filter(dsl::uuid.eq(self.uuid))
137 .set(dsl::username.eq(new_username.as_str()))
138 .execute(&mut conn)
139 .await?;
140
141 if data.get_cache_key(self.uuid.to_string()).await.is_ok() {
142 data.del_cache_key(self.uuid.to_string()).await?
143 }
144
145 self.username = new_username;
146
147 Ok(())
148 }
149
150 pub async fn set_display_name(
151 &mut self,
152 data: &Data,
153 new_display_name: String,
154 ) -> Result<(), Error> {
155 let mut conn = data.pool.get().await?;
156
157 use users::dsl;
158 update(users::table)
159 .filter(dsl::uuid.eq(self.uuid))
160 .set(dsl::display_name.eq(new_display_name.as_str()))
161 .execute(&mut conn)
162 .await?;
163
164 if data.get_cache_key(self.uuid.to_string()).await.is_ok() {
165 data.del_cache_key(self.uuid.to_string()).await?
166 }
167
168 self.display_name = Some(new_display_name);
169
170 Ok(())
171 }
172
173 pub async fn set_email(&mut self, data: &Data, new_email: String) -> Result<(), Error> {
174 if !EMAIL_REGEX.is_match(&new_email) {
175 return Err(Error::BadRequest("Invalid username".to_string()));
176 }
177
178 let mut conn = data.pool.get().await?;
179
180 use users::dsl;
181 update(users::table)
182 .filter(dsl::uuid.eq(self.uuid))
183 .set((
184 dsl::email.eq(new_email.as_str()),
185 dsl::email_verified.eq(false),
186 ))
187 .execute(&mut conn)
188 .await?;
189
190 if data.get_cache_key(self.uuid.to_string()).await.is_ok() {
191 data.del_cache_key(self.uuid.to_string()).await?
192 }
193
194 self.email = new_email;
195
196 Ok(())
197 }
198
199 pub async fn set_pronouns(&mut self, data: &Data, new_pronouns: String) -> Result<(), Error> {
200 let mut conn = data.pool.get().await?;
201
202 use users::dsl;
203 update(users::table)
204 .filter(dsl::uuid.eq(self.uuid))
205 .set((dsl::pronouns.eq(new_pronouns.as_str()),))
206 .execute(&mut conn)
207 .await?;
208
209 if data.get_cache_key(self.uuid.to_string()).await.is_ok() {
210 data.del_cache_key(self.uuid.to_string()).await?
211 }
212
213 Ok(())
214 }
215
216 pub async fn set_about(&mut self, data: &Data, new_about: String) -> Result<(), Error> {
217 let mut conn = data.pool.get().await?;
218
219 use users::dsl;
220 update(users::table)
221 .filter(dsl::uuid.eq(self.uuid))
222 .set((dsl::about.eq(new_about.as_str()),))
223 .execute(&mut conn)
224 .await?;
225
226 if data.get_cache_key(self.uuid.to_string()).await.is_ok() {
227 data.del_cache_key(self.uuid.to_string()).await?
228 }
229
230 Ok(())
231 }
232}