use crate::constants::StaticConstraints; use crate::controllers::HttpResult; use crate::extractors::family_extractor::FamilyInPath; use crate::services::login_token_service::LoginToken; use crate::services::rate_limiter_service::RatedAction; use crate::services::{families_service, rate_limiter_service}; use actix_remote_ip::RemoteIP; use actix_web::{web, HttpResponse}; #[derive(Debug, serde::Deserialize)] pub struct CreateFamilyReq { name: String, } /// Create a new family pub async fn create(req: web::Json, token: LoginToken) -> HttpResult { if !StaticConstraints::default() .family_name_len .validate(&req.name) { return Ok(HttpResponse::BadRequest().body("Invalid family name!")); } let family = families_service::create(&req.name, token.user_id).await?; Ok(HttpResponse::Created().json(family)) } #[derive(Debug, serde::Deserialize)] pub struct JoinFamilyReq { code: String, } /// Join a family pub async fn join( remote_ip: RemoteIP, req: web::Json, token: LoginToken, ) -> HttpResult { // Rate limiting if rate_limiter_service::should_block_action(remote_ip.0, RatedAction::JoinFamily).await? { return Ok(HttpResponse::TooManyRequests().finish()); } rate_limiter_service::record_action(remote_ip.0, RatedAction::JoinFamily).await?; let family = match families_service::get_by_invitation_code(&req.code).await { Ok(f) => f, Err(e) => { log::error!("Could not find family by invitation code! {e}"); return Ok(HttpResponse::NotFound().finish()); } }; if families_service::is_member(family.id(), token.user_id).await? { log::error!( "Could not add {:?} to family {:?} because it is already a member of the family!", token.user_id, family.id() ); return Ok(HttpResponse::Conflict().finish()); } families_service::add_member(family.id(), token.user_id, false).await?; Ok(HttpResponse::Accepted().finish()) } /// Get the list of families of the user pub async fn list(token: LoginToken) -> HttpResult { Ok( HttpResponse::Ok() .json(families_service::get_user_family_memberships(token.user_id).await?), ) } /// Get the information of a single family pub async fn single_info(f: FamilyInPath) -> HttpResult { Ok(HttpResponse::Ok() .json(families_service::get_family_membership(f.family_id(), f.user_id()).await?)) }