tetratto_core/database/
emojis.rs1use std::collections::HashMap;
2
3use oiseau::cache::Cache;
4use crate::model::{
5 Error, Result, auth::User, permissions::FinePermission,
6 communities_permissions::CommunityPermission, uploads::CustomEmoji,
7};
8use crate::{auto_method, DataManager};
9
10use oiseau::{PostgresRow, execute, get, query_row, query_rows, params};
11
12impl DataManager {
13 pub(crate) fn get_emoji_from_row(x: &PostgresRow) -> CustomEmoji {
15 CustomEmoji {
16 id: get!(x->0(i64)) as usize,
17 owner: get!(x->1(i64)) as usize,
18 created: get!(x->2(i64)) as usize,
19 community: get!(x->3(i64)) as usize,
20 upload_id: get!(x->4(i64)) as usize,
21 name: get!(x->5(String)),
22 is_animated: get!(x->6(i32)) as i8 == 1,
23 }
24 }
25
26 auto_method!(get_emoji_by_id(usize as i64)@get_emoji_from_row -> "SELECT * FROM emojis WHERE id = $1" --name="emoji" --returns=CustomEmoji --cache-key-tmpl="atto.emoji:{}");
27
28 pub async fn get_emojis_by_community(&self, community: usize) -> Result<Vec<CustomEmoji>> {
33 let conn = match self.0.connect().await {
34 Ok(c) => c,
35 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
36 };
37
38 let res = query_rows!(
39 &conn,
40 "SELECT * FROM emojis WHERE community = $1 ORDER BY name ASC",
41 &[&(community as i64)],
42 |x| { Self::get_emoji_from_row(x) }
43 );
44
45 if res.is_err() {
46 return Err(Error::GeneralNotFound("emoji".to_string()));
47 }
48
49 Ok(res.unwrap())
50 }
51
52 pub async fn get_user_emojis(
54 &self,
55 id: usize,
56 ) -> Result<HashMap<usize, (String, Vec<CustomEmoji>)>> {
57 let memberships = self.get_memberships_by_owner(id).await?;
58 let mut out = HashMap::new();
59
60 for membership in memberships {
61 let community = self.get_community_by_id(membership.community).await?;
62
63 out.insert(
64 community.id,
65 (
66 community.title.clone(),
67 self.get_emojis_by_community(community.id).await?,
68 ),
69 );
70 }
71
72 Ok(out)
73 }
74
75 pub async fn get_emoji_by_community_name(
90 &self,
91 community: usize,
92 name: &str,
93 ) -> Result<(Option<CustomEmoji>, Option<String>)> {
94 if community == 0 {
95 return Ok((None, Some("🐇".to_string())));
96 }
97
98 let conn = match self.0.connect().await {
100 Ok(c) => c,
101 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
102 };
103
104 let res = query_row!(
105 &conn,
106 "SELECT * FROM emojis WHERE community = $1 AND name = $2 ORDER BY name ASC",
107 params![&(community as i64), &name],
108 |x| { Ok((Some(Self::get_emoji_from_row(x)), None)) }
109 );
110
111 if res.is_err() {
112 return Err(Error::GeneralNotFound("emoji".to_string()));
113 }
114
115 Ok(res.unwrap())
116 }
117
118 pub async fn create_emoji(&self, data: CustomEmoji) -> Result<()> {
123 let user = self.get_user_by_id(data.owner).await?;
124
125 if !user.permissions.check(FinePermission::SUPPORTER) && data.is_animated {
127 return Err(Error::RequiresSupporter);
128 }
129
130 if data.community != 0 {
132 let membership = self
133 .get_membership_by_owner_community(user.id, data.community)
134 .await?;
135
136 if !membership.role.check(CommunityPermission::MANAGE_EMOJIS)
137 && !user.permissions.check(FinePermission::MANAGE_EMOJIS)
138 {
139 return Err(Error::NotAllowed);
140 }
141 }
142
143 let conn = match self.0.connect().await {
145 Ok(c) => c,
146 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
147 };
148
149 let res = execute!(
150 &conn,
151 "INSERT INTO emojis VALUES ($1, $2, $3, $4, $5, $6, $7)",
152 params![
153 &(data.id as i64),
154 &(data.created as i64),
155 &(data.owner as i64),
156 &(data.community as i64),
157 &(data.upload_id as i64),
158 &data.name,
159 &{ if data.is_animated { 1 } else { 0 } },
160 ]
161 );
162
163 if let Err(e) = res {
164 return Err(Error::DatabaseError(e.to_string()));
165 }
166
167 Ok(())
168 }
169
170 pub async fn delete_emoji(&self, id: usize, user: &User) -> Result<()> {
171 let emoji = self.get_emoji_by_id(id).await?;
172
173 if user.id != emoji.owner {
175 let membership = self
176 .get_membership_by_owner_community(user.id, emoji.community)
177 .await?;
178
179 if !membership.role.check(CommunityPermission::MANAGE_EMOJIS) {
180 return Err(Error::NotAllowed);
181 }
182 }
183
184 let conn = match self.0.connect().await {
186 Ok(c) => c,
187 Err(e) => return Err(Error::DatabaseConnection(e.to_string())),
188 };
189
190 let res = execute!(&conn, "DELETE FROM emojis WHERE id = $1", &[&(id as i64)]);
191
192 if let Err(e) = res {
193 return Err(Error::DatabaseError(e.to_string()));
194 }
195
196 self.delete_upload(emoji.upload_id).await?;
198
199 self.0.1.remove(format!("atto.emoji:{}", id)).await;
201 Ok(())
202 }
203
204 auto_method!(update_emoji_name(&str)@get_emoji_by_id:FinePermission::MANAGE_EMOJIS; -> "UPDATE emojis SET name = $1 WHERE id = $2" --cache-key-tmpl="atto.emoji:{}");
205}