use axum::{ Json, Router, extract::State, response::{IntoResponse, Response}, routing::{get, post}, }; use http::StatusCode; use services::{ User, organization::{OrganizationService, OrganizationServiceError}, }; use thiserror::Error; use tracing::warn; use types::organization::{JoinOrganization, Organization}; use crate::AppState; #[derive(Error, Debug, PartialEq)] enum ApiError { #[error(transparent)] ServiceError(#[from] OrganizationServiceError), #[error("organization already exists")] OrganizationAlreadyExists, #[error("organization does not exists")] OrganizationDoesNotExists, #[error("organization already exists")] OrganizationAlreadyJoined, #[error("organization does not exists")] OrganizationNotJoined, } impl IntoResponse for ApiError { fn into_response(self) -> Response { let status = match &self { ApiError::ServiceError(_) => StatusCode::INTERNAL_SERVER_ERROR, ApiError::OrganizationAlreadyExists | ApiError::OrganizationDoesNotExists | ApiError::OrganizationAlreadyJoined | ApiError::OrganizationNotJoined => StatusCode::BAD_REQUEST, }; warn!("{:?}", self); status.into_response() } } pub fn routes(state: AppState) -> Router { Router::new() .route("/", get(get_organizations)) .route("/", post(add_organization)) .route("/join", post(join_organization)) .route("/leave", post(leave_organization)) .with_state(state) } async fn get_organizations( state: State, user: User, ) -> Result>, ApiError> { let organizations = OrganizationService::get_all(&user, &state.db_connection).await?; Ok(Json(organizations)) } async fn add_organization( state: State, user: User, Json(organization): Json, ) -> Result, ApiError> { let org_uuid = organization.uuid; if OrganizationService::exists(&state.db_connection, org_uuid).await? { return Err(ApiError::OrganizationAlreadyExists); } let new_organization = OrganizationService::create(&state.db_connection, organization).await?; OrganizationService::join(&user, &state.db_connection, org_uuid).await?; Ok(Json(new_organization)) } async fn join_organization( state: State, user: User, Json(organization): Json, ) -> Result { let org_uuid = organization.uuid; if !OrganizationService::exists(&state.db_connection, org_uuid).await? { return Err(ApiError::OrganizationDoesNotExists); } if OrganizationService::joined(&user, &state.db_connection, org_uuid).await? { return Err(ApiError::OrganizationAlreadyJoined); } OrganizationService::join(&user, &state.db_connection, organization.uuid).await?; Ok(StatusCode::OK) } async fn leave_organization( state: State, user: User, Json(organization): Json, ) -> Result { let org_uuid = organization.uuid; if !OrganizationService::exists(&state.db_connection, org_uuid).await? { return Err(ApiError::OrganizationDoesNotExists); } if !OrganizationService::joined(&user, &state.db_connection, org_uuid).await? { return Err(ApiError::OrganizationNotJoined); } OrganizationService::leave(&user, &state.db_connection, organization.uuid).await?; Ok(StatusCode::OK) }