tenants
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
use axum::extract::{Path, State};
|
||||
use axum::{http::StatusCode, Json};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::auth::{AuthenticatedUser, TenantMembershipUser};
|
||||
use crate::error::AppResult;
|
||||
use crate::http::responders::JsonResponse;
|
||||
use crate::services::auth::{AuthService, TenantSnippet};
|
||||
use crate::services::tenants::{
|
||||
TenantApiService, TenantUserListResponse, TenantUserSummary, UpdateTenantRequest,
|
||||
UpdateTenantUserRequest,
|
||||
};
|
||||
use crate::state::AppState;
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/tenants",
|
||||
responses((status = 200, body = [TenantSnippet], description = "Tenant memberships for the current user")),
|
||||
tag = "Tenants"
|
||||
)]
|
||||
pub async fn list_tenants(
|
||||
State(state): State<AppState>,
|
||||
user: TenantMembershipUser,
|
||||
) -> AppResult<Json<Vec<TenantSnippet>>> {
|
||||
let response = AuthService::new(&state).list_tenants(user.user_id)?;
|
||||
Ok(Json(response.into_inner().tenants))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/tenants/{tenant_id}",
|
||||
params(("tenant_id" = Uuid, Path, description = "Tenant identifier")),
|
||||
responses((status = 200, body = TenantSnippet, description = "Tenant details")),
|
||||
tag = "Tenants"
|
||||
)]
|
||||
pub async fn get_tenant(
|
||||
State(state): State<AppState>,
|
||||
Path(tenant_id): Path<Uuid>,
|
||||
user: TenantMembershipUser,
|
||||
) -> AppResult<JsonResponse<TenantSnippet>> {
|
||||
AuthService::new(&state).get_tenant(user.user_id, tenant_id)
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
path = "/api/tenants/{tenant_id}",
|
||||
params(("tenant_id" = Uuid, Path, description = "Tenant identifier")),
|
||||
request_body = UpdateTenantRequest,
|
||||
responses((status = 200, body = TenantSnippet, description = "Updated tenant")),
|
||||
tag = "Tenants"
|
||||
)]
|
||||
pub async fn update_tenant(
|
||||
State(state): State<AppState>,
|
||||
Path(tenant_id): Path<Uuid>,
|
||||
user: AuthenticatedUser,
|
||||
Json(payload): Json<UpdateTenantRequest>,
|
||||
) -> AppResult<JsonResponse<TenantSnippet>> {
|
||||
TenantApiService::new(&state).update_name(user, tenant_id, payload)
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/tenants/{tenant_id}/users",
|
||||
params(("tenant_id" = Uuid, Path, description = "Tenant ID")),
|
||||
responses((status = 200, body = [TenantUserSummary], description = "All users for the tenant")),
|
||||
tag = "Tenants"
|
||||
)]
|
||||
pub async fn list_tenant_users(
|
||||
State(state): State<AppState>,
|
||||
Path(tenant_id): Path<Uuid>,
|
||||
user: AuthenticatedUser,
|
||||
) -> AppResult<Json<Vec<TenantUserSummary>>> {
|
||||
let response = TenantApiService::new(&state).list_users(&user, tenant_id)?;
|
||||
Ok(Json(response.into_inner().users))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
get,
|
||||
path = "/api/tenants/{tenant_id}/users/{user_id}",
|
||||
params(
|
||||
("tenant_id" = Uuid, Path, description = "Tenant ID"),
|
||||
("user_id" = Uuid, Path, description = "User ID")
|
||||
),
|
||||
responses((status = 200, body = TenantUserSummary, description = "Tenant user details")),
|
||||
tag = "Tenants"
|
||||
)]
|
||||
pub async fn get_tenant_user(
|
||||
State(state): State<AppState>,
|
||||
Path((tenant_id, target_user_id)): Path<(Uuid, Uuid)>,
|
||||
user: AuthenticatedUser,
|
||||
) -> AppResult<JsonResponse<TenantUserSummary>> {
|
||||
TenantApiService::new(&state).get_user(&user, tenant_id, target_user_id)
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
patch,
|
||||
path = "/api/tenants/{tenant_id}/users/{user_id}",
|
||||
params(
|
||||
("tenant_id" = Uuid, Path, description = "Tenant ID"),
|
||||
("user_id" = Uuid, Path, description = "User ID")
|
||||
),
|
||||
request_body = UpdateTenantUserRequest,
|
||||
responses((status = 200, body = TenantUserSummary, description = "Updated tenant user")),
|
||||
tag = "Tenants"
|
||||
)]
|
||||
pub async fn update_tenant_user(
|
||||
State(state): State<AppState>,
|
||||
Path((tenant_id, target_user_id)): Path<(Uuid, Uuid)>,
|
||||
user: AuthenticatedUser,
|
||||
Json(payload): Json<UpdateTenantUserRequest>,
|
||||
) -> AppResult<JsonResponse<TenantUserSummary>> {
|
||||
TenantApiService::new(&state).update_user(&user, tenant_id, target_user_id, payload)
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
delete,
|
||||
path = "/api/tenants/{tenant_id}/users/{user_id}",
|
||||
params(
|
||||
("tenant_id" = Uuid, Path, description = "Tenant ID"),
|
||||
("user_id" = Uuid, Path, description = "User ID")
|
||||
),
|
||||
responses((status = 204, description = "Membership removed")),
|
||||
tag = "Tenants"
|
||||
)]
|
||||
pub async fn delete_tenant_user(
|
||||
State(state): State<AppState>,
|
||||
Path((tenant_id, target_user_id)): Path<(Uuid, Uuid)>,
|
||||
user: AuthenticatedUser,
|
||||
) -> AppResult<StatusCode> {
|
||||
TenantApiService::new(&state).remove_user(&user, tenant_id, target_user_id)?;
|
||||
Ok(StatusCode::NO_CONTENT)
|
||||
}
|
||||
|
||||
#[derive(utoipa::OpenApi)]
|
||||
#[openapi(
|
||||
paths(
|
||||
list_tenants,
|
||||
get_tenant,
|
||||
update_tenant,
|
||||
list_tenant_users,
|
||||
get_tenant_user,
|
||||
update_tenant_user,
|
||||
delete_tenant_user,
|
||||
),
|
||||
components(schemas(
|
||||
crate::services::auth::TenantListResponse,
|
||||
crate::services::auth::TenantSnippet,
|
||||
UpdateTenantRequest,
|
||||
UpdateTenantUserRequest,
|
||||
TenantUserListResponse,
|
||||
TenantUserSummary,
|
||||
))
|
||||
)]
|
||||
pub struct TenantsApiDoc;
|
||||
Reference in New Issue
Block a user