rb/routing/api/
reactions.rs

1use crate::database::Database;
2use crate::model::{AssetType, DatabaseError, ReactionCreate};
3use authbeam::model::{NotificationCreate, RelationshipStatus};
4use databeam::prelude::DefaultReturn;
5
6use axum::response::IntoResponse;
7use axum::{
8    extract::{Path, State},
9    routing::{delete, get, post},
10    Json, Router,
11};
12
13use axum_extra::extract::cookie::CookieJar;
14
15pub fn routes(database: Database) -> Router {
16    Router::new()
17        .route("/{id}", post(create_request))
18        .route("/{id}", get(get_request))
19        .route("/{id}", delete(delete_request))
20        // ...
21        .with_state(database)
22}
23
24// routes
25
26/// [`Database::create_reaction`]
27pub async fn create_request(
28    jar: CookieJar,
29    Path(id): Path<String>,
30    State(database): State<Database>,
31    Json(props): Json<ReactionCreate>,
32) -> impl IntoResponse {
33    // get user from token
34    let auth_user = match jar.get("__Secure-Token") {
35        Some(c) => match database
36            .auth
37            .get_profile_by_unhashed(c.value_trimmed())
38            .await
39        {
40            Ok(ua) => ua,
41            Err(_) => return Json(DatabaseError::NotAllowed.into()),
42        },
43        None => return Json(DatabaseError::NotAllowed.into()),
44    };
45
46    // verify asset from type
47    match props.r#type {
48        AssetType::Question => {
49            let asset = match database.get_question(id.clone()).await {
50                Ok(r) => r,
51                Err(e) => {
52                    return Json(DefaultReturn {
53                        success: false,
54                        message: e.to_string(),
55                        payload: None,
56                    })
57                }
58            };
59
60            // create notification
61            if let Err(_) = database
62                .auth
63                .create_notification(
64                    NotificationCreate {
65                        title: format!(
66                            "[@{}](/+u/{}) has reacted to a question you created!",
67                            auth_user.username, auth_user.id
68                        ),
69                        content: String::new(),
70                        address: format!("/question/{id}"),
71                        recipient: asset.author.id,
72                    },
73                    None,
74                )
75                .await
76            {
77                return Json(DefaultReturn {
78                    success: false,
79                    message: DatabaseError::Other.to_string(),
80                    payload: None,
81                });
82            }
83        }
84        AssetType::Response => {
85            let asset = match database.get_response(id.clone()).await {
86                Ok(r) => r.1,
87                Err(e) => {
88                    return Json(DefaultReturn {
89                        success: false,
90                        message: e.to_string(),
91                        payload: None,
92                    })
93                }
94            };
95
96            // check relationship
97            let relationship = database
98                .auth
99                .get_user_relationship(&asset.author.id, &auth_user.id)
100                .await
101                .0;
102
103            if relationship == RelationshipStatus::Blocked {
104                return Json(DefaultReturn {
105                    success: false,
106                    message: DatabaseError::NotAllowed.to_string(),
107                    payload: None,
108                });
109            }
110
111            // create notification
112            if let Err(_) = database
113                .auth
114                .create_notification(
115                    NotificationCreate {
116                        title: format!(
117                            "[@{}](/+u/{}) has reacted to a response you created!",
118                            auth_user.username, auth_user.id
119                        ),
120                        content: String::new(),
121                        address: format!("/response/{id}"),
122                        recipient: asset.author.id,
123                    },
124                    None,
125                )
126                .await
127            {
128                return Json(DefaultReturn {
129                    success: false,
130                    message: DatabaseError::Other.to_string(),
131                    payload: None,
132                });
133            }
134        }
135        AssetType::Comment => {
136            let asset = match database.get_comment(id.clone(), false).await {
137                Ok(r) => r.0,
138                Err(e) => {
139                    return Json(DefaultReturn {
140                        success: false,
141                        message: e.to_string(),
142                        payload: None,
143                    })
144                }
145            };
146
147            // check relationship
148            let relationship = database
149                .auth
150                .get_user_relationship(&asset.author.id, &auth_user.id)
151                .await
152                .0;
153
154            if relationship == RelationshipStatus::Blocked {
155                return Json(DefaultReturn {
156                    success: false,
157                    message: DatabaseError::NotAllowed.to_string(),
158                    payload: None,
159                });
160            }
161
162            // create notification
163            if let Err(_) = database
164                .auth
165                .create_notification(
166                    NotificationCreate {
167                        title: format!(
168                            "[@{}](/+u/{}) has reacted to a comment you created!",
169                            auth_user.username, auth_user.id
170                        ),
171                        content: String::new(),
172                        address: format!("/comment/{id}"),
173                        recipient: asset.author.id,
174                    },
175                    None,
176                )
177                .await
178            {
179                return Json(DefaultReturn {
180                    success: false,
181                    message: DatabaseError::Other.to_string(),
182                    payload: None,
183                });
184            }
185        }
186        AssetType::Item => {
187            let asset = match database.auth.get_item(&id).await {
188                Ok(i) => i,
189                Err(e) => {
190                    return Json(DefaultReturn {
191                        success: false,
192                        message: e.to_string(),
193                        payload: None,
194                    })
195                }
196            };
197
198            // check relationship
199            let relationship = database
200                .auth
201                .get_user_relationship(&asset.creator, &auth_user.id)
202                .await
203                .0;
204
205            if relationship == RelationshipStatus::Blocked {
206                return Json(DefaultReturn {
207                    success: false,
208                    message: DatabaseError::NotAllowed.to_string(),
209                    payload: None,
210                });
211            }
212
213            // create notification
214            if let Err(_) = database
215                .auth
216                .create_notification(
217                    NotificationCreate {
218                        title: format!(
219                            "[@{}](/+u/{}) has reacted to an item you created!",
220                            auth_user.username, auth_user.id
221                        ),
222                        content: String::new(),
223                        address: format!("/market/item/{id}"),
224                        recipient: asset.creator,
225                    },
226                    None,
227                )
228                .await
229            {
230                return Json(DefaultReturn {
231                    success: false,
232                    message: DatabaseError::Other.to_string(),
233                    payload: None,
234                });
235            }
236        }
237    };
238
239    // ...
240    Json(match database.create_reaction(id, auth_user).await {
241        Ok(r) => DefaultReturn {
242            success: true,
243            message: String::new(),
244            payload: Some(r),
245        },
246        Err(e) => e.into(),
247    })
248}
249
250/// [`Database::get_reaction`]
251pub async fn get_request(
252    jar: CookieJar,
253    Path(id): Path<String>,
254    State(database): State<Database>,
255) -> impl IntoResponse {
256    // get user from token
257    let auth_user = match jar.get("__Secure-Token") {
258        Some(c) => match database
259            .auth
260            .get_profile_by_unhashed(c.value_trimmed())
261            .await
262        {
263            Ok(ua) => ua,
264            Err(_) => {
265                return Json(DatabaseError::NotAllowed.into());
266            }
267        },
268        None => {
269            return Json(DatabaseError::NotAllowed.into());
270        }
271    };
272
273    Json(match database.get_reaction(auth_user.id, id).await {
274        Ok(r) => DefaultReturn {
275            success: true,
276            message: String::new(),
277            payload: Some(r),
278        },
279        Err(e) => e.into(),
280    })
281}
282
283/// [`Database::delete_reaction`]
284pub async fn delete_request(
285    jar: CookieJar,
286    Path(id): Path<String>,
287    State(database): State<Database>,
288) -> impl IntoResponse {
289    // get user from token
290    let auth_user = match jar.get("__Secure-Token") {
291        Some(c) => match database
292            .auth
293            .get_profile_by_unhashed(c.value_trimmed())
294            .await
295        {
296            Ok(ua) => ua,
297            Err(_) => {
298                return Json(DatabaseError::NotAllowed.into());
299            }
300        },
301        None => {
302            return Json(DatabaseError::NotAllowed.into());
303        }
304    };
305
306    // ...
307    Json(match database.delete_reaction(id, auth_user).await {
308        Ok(r) => DefaultReturn {
309            success: true,
310            message: String::new(),
311            payload: Some(r),
312        },
313        Err(e) => e.into(),
314    })
315}