1use actix_files::NamedFile;
2use actix_multipart::Multipart;
3use actix_web::{HttpRequest, HttpResponse, Responder, delete, get, post, web};
4use chrono::NaiveDate;
5use futures::future::join_all;
6use serde::{Deserialize, Serialize};
7
8use crate::{
9 player::{Player, PlayerRole, PlayerState},
10 time::CustomDateTime,
11 token::Token,
12};
13
14#[derive(Debug, Serialize, Deserialize)]
16pub struct NewPlayer {
17 pub name: String,
18 pub surname: String,
19 pub pronouns: String,
20 pub alias: String,
21 pub niu: String,
22 pub email: String,
23 pub phone: String,
24 pub faculty: String,
25 pub isuab: bool,
26 pub how_did_you_hear_about_us: String,
27 pub social_media: Option<String>,
28 pub password: String,
29 pub birth_date: NaiveDate,
30 pub accept_info_other_editions: bool,
31 pub wants_to_be_zombie: i32,
32}
33
34#[derive(Debug, Serialize, Deserialize)]
36pub struct EditPlayer {
37 pub bio: String,
38 pub pronouns: String,
39 pub alias: String,
40 pub email: String,
41 pub phone: String,
42 pub social_media: Option<String>,
43 pub accept_info_other_editions: bool,
44}
45
46#[derive(Debug, Serialize, Deserialize)]
48pub struct Login {
49 pub username: String,
50 pub password: String,
51}
52
53#[derive(Debug, Serialize, Deserialize)]
55pub struct LoginReturn {
56 pub uuid: String,
57 pub token: String,
58}
59
60#[derive(Debug, Serialize, Deserialize)]
62pub struct ChangePassword {
63 pub old_password: String,
64 pub new_password: String,
65}
66
67#[derive(Debug, Serialize, Deserialize)]
69pub struct PlayerReturnInfo {
70 pub name: String,
71 pub surname: String,
72 pub bio: String,
73 pub pronouns: String,
74 pub alias: String,
75 pub social_media: Option<String>,
76 pub player_number: i32,
77 pub state: PlayerState,
78 pub role: PlayerRole,
79 pub next_feeding: Option<CustomDateTime>,
80}
81
82#[post("/new")]
84pub async fn new_player(form: web::Json<NewPlayer>) -> impl Responder {
85 let player = form.into_inner();
86 let new_db_player = Player::new(
87 player.name,
88 player.surname,
89 player.pronouns,
90 player.alias,
91 player.niu,
92 player.email,
93 player.phone,
94 player.faculty,
95 player.isuab,
96 player.how_did_you_hear_about_us,
97 player.social_media,
98 player.password,
99 player.birth_date,
100 player.accept_info_other_editions,
101 player.wants_to_be_zombie,
102 )
103 .await;
104
105 let insert_result = new_db_player.signup().await;
106
107 match insert_result {
108 Ok(player) => {
109 let token: Token = match Token::generate(&player.id) {
110 Ok(t) => t,
111 Err(e) => return HttpResponse::InternalServerError().body(e),
112 };
113 HttpResponse::Ok().json(LoginReturn { token: token.token, uuid: player.id })
114 }
115 Err(_) => HttpResponse::InternalServerError().body("Failed to create player\n"),
116 }
117}
118
119#[post("/login")]
121pub async fn login(form: web::Json<Login>) -> impl Responder {
122 let Login { username, password } = form.into_inner();
123
124 let result = Player::login(&username, password).await;
125
126 match result {
127 Ok(player) => {
128 let token: Token = match Token::generate(&player.id) {
129 Ok(t) => t,
130 Err(e) => return HttpResponse::InternalServerError().body(e),
131 };
132 HttpResponse::Ok().json(LoginReturn {
133 uuid: player.id,
134 token: token.token,
135 })
136 }
137 Err(_) => HttpResponse::InternalServerError().body("Player not found\n"),
138 }
139}
140
141#[post("/logout/{url_id}")]
143pub async fn logout(url_id: web::Path<String>, req: HttpRequest) -> impl Responder {
144 if let Err(e) = Token::check_token(&req, &url_id).await {
145 return HttpResponse::Forbidden().body(e);
146 }
147
148 let player = match Player::get_player(url_id.into_inner()).await {
149 Ok(Some(player)) => player,
150 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
151 Err(err) => return HttpResponse::InternalServerError().body(err),
152 };
153
154 let result = Token::clear_player_tokens(&player);
155
156 match result {
157 Ok(_) => HttpResponse::Ok().finish(),
158 Err(err) => HttpResponse::InternalServerError().body(err),
159 }
160}
161
162#[post("/change_password/{url_id}")]
164pub async fn change_password(
165 url_id: web::Path<String>,
166 req: HttpRequest,
167 form: web::Json<ChangePassword>,
168) -> impl Responder {
169 if let Err(e) = Token::check_token(&req, &url_id).await {
170 return HttpResponse::Forbidden().body(e);
171 }
172
173 let player = match Player::get_player(url_id.into_inner()).await {
174 Ok(Some(player)) => player,
175 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
176 Err(err) => return HttpResponse::InternalServerError().body(err),
177 };
178
179 let ChangePassword {
180 old_password,
181 new_password,
182 } = form.into_inner();
183
184 if let Err(e) = Token::clear_player_tokens(&player) {
185 return HttpResponse::InternalServerError().body(e);
186 };
187 let token = match Token::generate(&player.id) {
188 Ok(t) => t,
189 Err(e) => return HttpResponse::InternalServerError().body(e),
190 };
191
192 let result = player.change_password(old_password, new_password).await;
193
194 match result {
195 Ok(_) => HttpResponse::Ok().json((token.token, player.id)),
196 Err(e) => HttpResponse::InternalServerError().body(e),
197 }
198}
199
200#[post("/edit_player/{url_id}")]
202pub async fn edit_player(
203 url_id: web::Path<String>,
204 req: HttpRequest,
205 form: web::Json<EditPlayer>,
206) -> impl Responder {
207 if let Err(e) = Token::check_token(&req, &url_id).await {
208 return HttpResponse::Forbidden().body(e);
209 }
210
211 let player = match Player::get_player(url_id.into_inner()).await {
212 Ok(Some(player)) => player,
213 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
214 Err(err) => return HttpResponse::InternalServerError().body(err),
215 };
216
217 let edit_data = form.into_inner();
218 let result = player
219 .edit(
220 edit_data.bio,
221 edit_data.pronouns,
222 edit_data.alias,
223 edit_data.email,
224 edit_data.phone,
225 edit_data.social_media,
226 edit_data.accept_info_other_editions,
227 )
228 .await;
229
230 match result {
231 Ok(_) => HttpResponse::Ok().body("Player edited\n"),
232 Err(_) => HttpResponse::InternalServerError().body("Failed to edit player\n"),
233 }
234}
235
236#[post("/set_pfp/{url_id}")]
238pub async fn set_pfp(
239 url_id: web::Path<String>,
240 req: HttpRequest,
241 mut img: Multipart,
242) -> impl Responder {
243 if let Err(e) = Token::check_token(&req, &url_id).await {
244 return HttpResponse::Forbidden().body(e);
245 }
246
247 let player = match Player::get_player(url_id.into_inner()).await {
248 Ok(Some(player)) => player,
249 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
250 Err(err) => return HttpResponse::InternalServerError().body(err),
251 };
252
253 let result = player.set_pfp(&mut img).await;
254
255 match result {
256 Ok(_) => HttpResponse::Ok().body("Profile picture set\n"),
257 Err(err) => HttpResponse::InternalServerError()
258 .body(format!("Failed to set profile picture: {}", err)),
259 }
260}
261
262#[delete("/remove_pfp/{url_id}")]
264pub async fn remove_pfp(url_id: web::Path<String>, req: HttpRequest) -> impl Responder {
265 if let Err(e) = Token::check_token(&req, &url_id).await {
266 return HttpResponse::Forbidden().body(e);
267 }
268
269 let player = match Player::get_player(url_id.into_inner()).await {
270 Ok(Some(player)) => player,
271 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
272 Err(err) => return HttpResponse::InternalServerError().body(err),
273 };
274
275 let result = player.remove_pfp().await;
276
277 match result {
278 Ok(_) => HttpResponse::Ok().body("Profile picture removed\n"),
279 Err(err) => HttpResponse::InternalServerError()
280 .body(format!("Failed to remove profile picture: {}", err)),
281 }
282}
283
284#[get("/pfp/{url_id}")]
286pub async fn pfp(url_id: web::Path<String>, req: HttpRequest) -> impl Responder {
287 if let Err(e) = Token::check_token(&req, &url_id).await {
288 return HttpResponse::Forbidden().body(e);
289 }
290
291 let player = match Player::get_player(url_id.into_inner()).await {
292 Ok(Some(player)) => player,
293 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
294 Err(err) => return HttpResponse::InternalServerError().body(err),
295 };
296
297 let result = player.get_pfp().await;
298
299 match result {
300 Ok(named_file) => NamedFile::into_response(named_file, &req),
301 Err(_) => HttpResponse::InternalServerError().body("Failed to get profile picture\n"),
302 }
303}
304
305#[post("/get_pfp/{url_id}")]
307pub async fn get_pfp(
308 url_id: web::Path<String>,
309 req: HttpRequest,
310 form: web::Json<String>,
311) -> impl Responder {
312 if let Err(e) = Token::check_token(&req, &url_id).await {
313 return HttpResponse::Forbidden().body(e);
314 }
315
316 match Player::get_player(url_id.into_inner()).await {
317 Ok(Some(player)) => player,
318 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
319 Err(err) => return HttpResponse::InternalServerError().body(err),
320 };
321
322 let other = match Player::get_player_by_alias(form.into_inner()).await {
323 Ok(Some(player)) => player,
324 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
325 Err(err) => return HttpResponse::InternalServerError().body(err),
326 };
327
328 let result = other.get_pfp().await;
329
330 match result {
331 Ok(named_file) => NamedFile::into_response(named_file, &req),
332 Err(_) => HttpResponse::InternalServerError().body("Failed to get profile picture\n"),
333 }
334}
335
336#[get("/player/{url_id}")]
338pub async fn get_player(url_id: web::Path<String>, req: HttpRequest) -> impl Responder {
339 if let Err(e) = Token::check_token(&req, &url_id).await {
340 return HttpResponse::Forbidden().body(e);
341 }
342
343 match Player::get_player(url_id.into_inner()).await {
344 Ok(Some(player)) => HttpResponse::Ok().json(player),
345 Ok(None) => HttpResponse::NotFound().body("Player not found"),
346 Err(err) => HttpResponse::InternalServerError().body(err),
347 }
348}
349
350#[post("/get_username/{url_id}")]
352pub async fn get_username(url_id: web::Path<String>, req: HttpRequest, form: web::Json<String>) -> impl Responder {
353 if let Err(e) = Token::check_token(&req, &url_id).await {
354 return HttpResponse::Forbidden().body(e);
355 }
356
357 let player = match Player::get_player(url_id.into_inner()).await {
358 Ok(Some(player)) => player,
359 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
360 Err(err) => return HttpResponse::InternalServerError().body(err),
361 };
362
363 let other = Player::get_player(form.into_inner()).await;
364
365 match other {
366 Ok(Some(other)) => HttpResponse::Ok().body(other.alias),
367 Ok(None) => HttpResponse::NotFound().body("Player not found"),
368 Err(err) => HttpResponse::InternalServerError().body(err),
369 }
370}
371
372#[post("/get_player/{url_id}")]
374pub async fn get_other_player(
375 url_id: web::Path<String>,
376 req: HttpRequest,
377 form: web::Json<String>,
378) -> impl Responder {
379 if let Err(e) = Token::check_token(&req, &url_id).await {
380 return HttpResponse::Forbidden().body(e);
381 }
382
383 let player = match Player::get_player(url_id.into_inner()).await {
384 Ok(Some(player)) => player,
385 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
386 Err(err) => return HttpResponse::InternalServerError().body(err),
387 };
388
389 let other = Player::get_player_by_alias(form.into_inner()).await;
390
391 match other {
392 Ok(Some(p)) => {
393 let player_response = PlayerReturnInfo {
394 name: p.name,
395 surname: p.surname,
396 bio: p.bio,
397 pronouns: p.pronouns,
398 alias: p.alias,
399 social_media: p.social_media,
400 player_number: p.player_number,
401 state: if p.state == PlayerState::Zombie0 {
402 PlayerState::Human
403 } else {
404 p.state
405 },
406 role: p.role,
407 next_feeding: if player.is_zombie().await {
408 p.next_feeding
409 } else {
410 None
411 },
412 };
413 HttpResponse::Ok().json(player_response)
414 }
415 Ok(None) => HttpResponse::NotFound().body("Player not found"),
416 Err(err) => HttpResponse::InternalServerError().body(err),
417 }
418}
419
420#[get("/users/{url_id}")]
422pub async fn get_users(url_id: web::Path<String>, req: HttpRequest) -> impl Responder {
423 if let Err(e) = Token::check_token(&req, &url_id).await {
424 return HttpResponse::Forbidden().body(e);
425 }
426
427 let player = match Player::get_player(url_id.into_inner()).await {
428 Ok(Some(player)) => player,
429 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
430 Err(err) => return HttpResponse::InternalServerError().body(err),
431 };
432 let is_zombie = player.is_zombie().await;
433
434 let result = Player::get_all_players().await;
435
436 match result {
437 Ok(players) => {
438 let futures = players.into_iter().map(|p| async move {
439 PlayerReturnInfo {
440 name: p.name,
441 surname: p.surname,
442 bio: p.bio,
443 pronouns: p.pronouns,
444 alias: p.alias,
445 social_media: p.social_media,
446 player_number: p.player_number,
447 state: if p.state == PlayerState::Zombie0 {
448 PlayerState::Human
449 } else {
450 p.state
451 },
452 role: p.role,
453 next_feeding: if is_zombie { p.next_feeding } else { None },
454 }
455 });
456
457 let return_players: Vec<PlayerReturnInfo> = join_all(futures).await;
458 HttpResponse::Ok().json(return_players)
459 }
460 Err(e) => {
461 HttpResponse::InternalServerError().body("Failed to get players\n")
462 }
463 }
464}
465
466#[delete("/delete_player/{url_id}")]
468pub async fn delete_player(url_id: web::Path<String>, req: HttpRequest) -> impl Responder {
469 if let Err(e) = Token::check_token(&req, &url_id).await {
470 return HttpResponse::Forbidden().body(e);
471 }
472
473 let player = match Player::get_player(url_id.into_inner()).await {
474 Ok(Some(player)) => player,
475 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
476 Err(err) => return HttpResponse::InternalServerError().body(err),
477 };
478
479 if let Err(e) = Token::clear_player_tokens(&player) {
480 return HttpResponse::InternalServerError().body(e);
481 }
482
483 let result = Player::delete_player(player.id).await;
484
485 match result {
486 Ok(_) => HttpResponse::Ok().body("Player deleted\n"),
487 Err(_) => HttpResponse::InternalServerError().body("Failed to delete player\n"),
488 }
489}