use actix_web::{HttpRequest, HttpResponse, web}; use serde::Serialize; use service::{ AppService, workspace::{ types::WorkspaceResponse, workspace::{AvatarUploadResponse, CreateWorkspace, UpdateWorkspace}, }, }; use session::Session; use crate::error::ApiError; fn ok_json(data: T) -> Result { Ok(HttpResponse::Ok().json(data)) } #[utoipa::path( post, path = "/api/v1/workspace", request_body = CreateWorkspace, responses( (status = 200, body = WorkspaceResponse), (status = 401, description = "Unauthorized"), (status = 409, description = "Workspace name already exists"), ), security( ("session" = []) ) )] pub async fn create_workspace( session: Session, service: web::Data, params: web::Json, ) -> Result { let data = service .workspace_create(&session, params.into_inner()) .await?; ok_json(data) } #[utoipa::path( get, path = "/api/v1/workspace/my", responses( (status = 200, body = Vec), (status = 401, description = "Unauthorized"), ), security( ("session" = []) ) )] pub async fn my_workspaces( session: Session, service: web::Data, ) -> Result { let data = service.workspace_my(&session).await?; ok_json(data) } #[utoipa::path( get, path = "/api/v1/workspace/{wk}", params( ("wk" = String, Path, description = "Workspace name"), ), responses( (status = 200, body = WorkspaceResponse), (status = 401, description = "Unauthorized"), (status = 404, description = "Workspace not found"), ), security( ("session" = []) ) )] pub async fn get_workspace( session: Session, service: web::Data, path: web::Path, ) -> Result { let wk = path.into_inner(); let data = service.workspace_get(&session, &wk).await?; ok_json(data) } #[utoipa::path( put, path = "/api/v1/workspace/{wk}", params( ("wk" = String, Path, description = "Workspace name"), ), request_body = UpdateWorkspace, responses( (status = 200, body = WorkspaceResponse), (status = 401, description = "Unauthorized"), (status = 403, description = "Permission denied"), (status = 404, description = "Workspace not found"), ), security( ("session" = []) ) )] pub async fn update_workspace( session: Session, service: web::Data, path: web::Path, params: web::Json, ) -> Result { let wk = path.into_inner(); let data = service .workspace_update(&session, &wk, params.into_inner()) .await?; ok_json(data) } #[utoipa::path( get, path = "/api/v1/workspace/{wk}/avatar", params( ("wk" = String, Path, description = "Workspace name"), ), responses( (status = 302, description = "Redirect to avatar image URL"), (status = 404, description = "Workspace or avatar not found"), ), tag = "workspace" )] pub async fn get_avatar( service: web::Data, path: web::Path, ) -> Result { let wk = path.into_inner(); let url = service.workspace_get_avatar_url(&wk).await?; Ok(HttpResponse::Found() .insert_header(("Location", url)) .finish()) } #[utoipa::path( post, path = "/api/v1/workspace/{wk}/avatar", params( ("wk" = String, Path, description = "Workspace name"), ), request_body(content = Vec, content_type = "image/*"), responses( (status = 200, body = AvatarUploadResponse), (status = 400, description = "Invalid file type or size"), (status = 403, description = "Permission denied"), ), security( ("session" = []) ) )] pub async fn upload_avatar( session: Session, service: web::Data, path: web::Path, body: web::Bytes, req: HttpRequest, ) -> Result { let wk = path.into_inner(); let content_type = req .headers() .get("content-type") .and_then(|v| v.to_str().ok()) .unwrap_or("application/octet-stream"); let response = service .workspace_upload_avatar(&session, &wk, body.to_vec(), content_type) .await?; ok_json(response) }