138 lines
3.5 KiB
Rust
138 lines
3.5 KiB
Rust
|
|
// Projects API endpoints
|
||
|
|
|
||
|
|
use axum::{
|
||
|
|
extract::{Path, State},
|
||
|
|
http::StatusCode,
|
||
|
|
response::IntoResponse,
|
||
|
|
Json,
|
||
|
|
};
|
||
|
|
use vapora_shared::models::{Project, ProjectStatus};
|
||
|
|
use crate::api::ApiResult;
|
||
|
|
|
||
|
|
use crate::api::state::AppState;
|
||
|
|
|
||
|
|
/// List all projects for a tenant
|
||
|
|
///
|
||
|
|
/// GET /api/v1/projects
|
||
|
|
pub async fn list_projects(State(state): State<AppState>) -> ApiResult<impl IntoResponse> {
|
||
|
|
// TODO: Extract tenant_id from JWT token
|
||
|
|
let tenant_id = "default";
|
||
|
|
|
||
|
|
let projects = state.project_service.list_projects(tenant_id).await?;
|
||
|
|
Ok(Json(projects))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Get a specific project
|
||
|
|
///
|
||
|
|
/// GET /api/v1/projects/:id
|
||
|
|
pub async fn get_project(
|
||
|
|
State(state): State<AppState>,
|
||
|
|
Path(id): Path<String>,
|
||
|
|
) -> ApiResult<impl IntoResponse> {
|
||
|
|
// TODO: Extract tenant_id from JWT token
|
||
|
|
let tenant_id = "default";
|
||
|
|
|
||
|
|
let project = state.project_service.get_project(&id, tenant_id).await?;
|
||
|
|
Ok(Json(project))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Create a new project
|
||
|
|
///
|
||
|
|
/// POST /api/v1/projects
|
||
|
|
pub async fn create_project(
|
||
|
|
State(state): State<AppState>,
|
||
|
|
Json(mut project): Json<Project>,
|
||
|
|
) -> ApiResult<impl IntoResponse> {
|
||
|
|
// TODO: Extract tenant_id from JWT token
|
||
|
|
project.tenant_id = "default".to_string();
|
||
|
|
|
||
|
|
let created = state.project_service.create_project(project).await?;
|
||
|
|
Ok((StatusCode::CREATED, Json(created)))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Update a project
|
||
|
|
///
|
||
|
|
/// PUT /api/v1/projects/:id
|
||
|
|
pub async fn update_project(
|
||
|
|
State(state): State<AppState>,
|
||
|
|
Path(id): Path<String>,
|
||
|
|
Json(updates): Json<Project>,
|
||
|
|
) -> ApiResult<impl IntoResponse> {
|
||
|
|
// TODO: Extract tenant_id from JWT token
|
||
|
|
let tenant_id = "default";
|
||
|
|
|
||
|
|
let updated = state
|
||
|
|
.project_service
|
||
|
|
.update_project(&id, tenant_id, updates)
|
||
|
|
.await?;
|
||
|
|
Ok(Json(updated))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Delete a project
|
||
|
|
///
|
||
|
|
/// DELETE /api/v1/projects/:id
|
||
|
|
pub async fn delete_project(
|
||
|
|
State(state): State<AppState>,
|
||
|
|
Path(id): Path<String>,
|
||
|
|
) -> ApiResult<impl IntoResponse> {
|
||
|
|
// TODO: Extract tenant_id from JWT token
|
||
|
|
let tenant_id = "default";
|
||
|
|
|
||
|
|
state.project_service.delete_project(&id, tenant_id).await?;
|
||
|
|
Ok(StatusCode::NO_CONTENT)
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Add a feature to a project
|
||
|
|
///
|
||
|
|
/// POST /api/v1/projects/:id/features
|
||
|
|
pub async fn add_feature(
|
||
|
|
State(state): State<AppState>,
|
||
|
|
Path(id): Path<String>,
|
||
|
|
Json(payload): Json<serde_json::Value>,
|
||
|
|
) -> ApiResult<impl IntoResponse> {
|
||
|
|
// TODO: Extract tenant_id from JWT token
|
||
|
|
let tenant_id = "default";
|
||
|
|
|
||
|
|
let feature = payload["feature"]
|
||
|
|
.as_str()
|
||
|
|
.ok_or_else(|| vapora_shared::VaporaError::InvalidInput("Missing 'feature' field".to_string()))?
|
||
|
|
.to_string();
|
||
|
|
|
||
|
|
let updated = state
|
||
|
|
.project_service
|
||
|
|
.add_feature(&id, tenant_id, feature)
|
||
|
|
.await?;
|
||
|
|
Ok(Json(updated))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Remove a feature from a project
|
||
|
|
///
|
||
|
|
/// DELETE /api/v1/projects/:id/features/:feature
|
||
|
|
pub async fn remove_feature(
|
||
|
|
State(state): State<AppState>,
|
||
|
|
Path((id, feature)): Path<(String, String)>,
|
||
|
|
) -> ApiResult<impl IntoResponse> {
|
||
|
|
// TODO: Extract tenant_id from JWT token
|
||
|
|
let tenant_id = "default";
|
||
|
|
|
||
|
|
let updated = state
|
||
|
|
.project_service
|
||
|
|
.remove_feature(&id, tenant_id, &feature)
|
||
|
|
.await?;
|
||
|
|
Ok(Json(updated))
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Archive a project
|
||
|
|
///
|
||
|
|
/// POST /api/v1/projects/:id/archive
|
||
|
|
pub async fn archive_project(
|
||
|
|
State(state): State<AppState>,
|
||
|
|
Path(id): Path<String>,
|
||
|
|
) -> ApiResult<impl IntoResponse> {
|
||
|
|
// TODO: Extract tenant_id from JWT token
|
||
|
|
let tenant_id = "default";
|
||
|
|
|
||
|
|
let updated = state.project_service.archive_project(&id, tenant_id).await?;
|
||
|
|
Ok(Json(updated))
|
||
|
|
}
|