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((token.token, 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#[get("/pfp/{url_id}")]
264pub async fn 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.get_pfp().await;
276
277 match result {
278 Ok(named_file) => NamedFile::into_response(named_file, &req),
279 Err(_) => HttpResponse::InternalServerError().body("Failed to get profile picture\n"),
280 }
281}
282
283#[post("/get_pfp/{url_id}")]
285pub async fn get_pfp(
286 url_id: web::Path<String>,
287 req: HttpRequest,
288 form: web::Json<String>,
289) -> impl Responder {
290 if let Err(e) = Token::check_token(&req, &url_id).await {
291 return HttpResponse::Forbidden().body(e);
292 }
293
294 match Player::get_player(url_id.into_inner()).await {
295 Ok(Some(player)) => player,
296 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
297 Err(err) => return HttpResponse::InternalServerError().body(err),
298 };
299
300 let other = match Player::get_player_by_alias(form.into_inner()).await {
301 Ok(Some(player)) => player,
302 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
303 Err(err) => return HttpResponse::InternalServerError().body(err),
304 };
305
306 let result = other.get_pfp().await;
307
308 match result {
309 Ok(named_file) => NamedFile::into_response(named_file, &req),
310 Err(_) => HttpResponse::InternalServerError().body("Failed to get profile picture\n"),
311 }
312}
313
314#[get("/checkpoint/{url_id}")]
316pub async fn get_checkpoint(url_id: web::Path<String>, req: HttpRequest) -> impl Responder {
317 if let Err(e) = Token::check_token(&req, &url_id).await {
318 return HttpResponse::Forbidden().body(e);
319 }
320
321 let player = match Player::get_player(url_id.into_inner()).await {
322 Ok(Some(player)) => player,
323 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
324 Err(err) => return HttpResponse::InternalServerError().body(err),
325 };
326
327 let result = player.get_checkpoint().await;
328
329 match result {
330 Ok(checkpoint) => HttpResponse::Ok().json(checkpoint),
331 Err(_) => HttpResponse::InternalServerError().body("Failed to get checkpoint\n"),
332 }
333}
334
335#[get("/player/{url_id}")]
337pub async fn get_player(url_id: web::Path<String>, req: HttpRequest) -> impl Responder {
338 if let Err(e) = Token::check_token(&req, &url_id).await {
339 return HttpResponse::Forbidden().body(e);
340 }
341
342 match Player::get_player(url_id.into_inner()).await {
343 Ok(Some(player)) => HttpResponse::Ok().json(player),
344 Ok(None) => HttpResponse::NotFound().body("Player not found"),
345 Err(err) => HttpResponse::InternalServerError().body(err),
346 }
347}
348
349#[post("/get_player/{url_id}")]
351pub async fn get_other_player(
352 url_id: web::Path<String>,
353 req: HttpRequest,
354 form: web::Json<String>,
355) -> impl Responder {
356 if let Err(e) = Token::check_token(&req, &url_id).await {
357 return HttpResponse::Forbidden().body(e);
358 }
359
360 let player = match Player::get_player(url_id.into_inner()).await {
361 Ok(Some(player)) => player,
362 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
363 Err(err) => return HttpResponse::InternalServerError().body(err),
364 };
365
366 let other = Player::get_player_by_alias(form.into_inner()).await;
367
368 match other {
369 Ok(Some(p)) => {
370 let player_response = PlayerReturnInfo {
371 name: p.name,
372 surname: p.surname,
373 bio: p.bio,
374 pronouns: p.pronouns,
375 alias: p.alias,
376 social_media: p.social_media,
377 player_number: p.player_number,
378 state: if p.state == PlayerState::Zombie0 {
379 PlayerState::Human
380 } else {
381 p.state
382 },
383 role: p.role,
384 next_feeding: if player.is_zombie().await {
385 p.next_feeding
386 } else {
387 None
388 },
389 };
390 HttpResponse::Ok().json(player_response)
391 }
392 Ok(None) => HttpResponse::NotFound().body("Player not found"),
393 Err(err) => HttpResponse::InternalServerError().body(err),
394 }
395}
396
397#[get("/users/{url_id}")]
399pub async fn get_users(url_id: web::Path<String>, req: HttpRequest) -> impl Responder {
400 if let Err(e) = Token::check_token(&req, &url_id).await {
401 return HttpResponse::Forbidden().body(e);
402 }
403
404 let player = match Player::get_player(url_id.into_inner()).await {
405 Ok(Some(player)) => player,
406 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
407 Err(err) => return HttpResponse::InternalServerError().body(err),
408 };
409 let is_zombie = player.is_zombie().await;
410
411 let result = Player::get_all_players().await;
412
413 match result {
414 Ok(players) => {
415 let futures = players.into_iter().map(|p| async move {
416 PlayerReturnInfo {
417 name: p.name,
418 surname: p.surname,
419 bio: p.bio,
420 pronouns: p.pronouns,
421 alias: p.alias,
422 social_media: p.social_media,
423 player_number: p.player_number,
424 state: if p.state == PlayerState::Zombie0 {
425 PlayerState::Human
426 } else {
427 p.state
428 },
429 role: p.role,
430 next_feeding: if is_zombie { p.next_feeding } else { None },
431 }
432 });
433
434 let return_players: Vec<PlayerReturnInfo> = join_all(futures).await;
435 HttpResponse::Ok().json(return_players)
436 }
437 Err(e) => {
438 eprintln!("Failed to get players: {:?}\n", e);
439 HttpResponse::InternalServerError().body("Failed to get players\n")
440 }
441 }
442}
443
444#[delete("/delete_player/{url_id}")]
446pub async fn delete_player(url_id: web::Path<String>, req: HttpRequest) -> impl Responder {
447 if let Err(e) = Token::check_token(&req, &url_id).await {
448 return HttpResponse::Forbidden().body(e);
449 }
450
451 let player = match Player::get_player(url_id.into_inner()).await {
452 Ok(Some(player)) => player,
453 Ok(None) => return HttpResponse::NotFound().body("Player not found"),
454 Err(err) => return HttpResponse::InternalServerError().body(err),
455 };
456
457 if let Err(e) = Token::clear_player_tokens(&player) {
458 return HttpResponse::InternalServerError().body(e);
459 }
460
461 let result = Player::delete_player(player.id).await;
462
463 match result {
464 Ok(_) => HttpResponse::Ok().body("Player deleted\n"),
465 Err(_) => HttpResponse::InternalServerError().body("Failed to delete player\n"),
466 }
467}