From 2355bd17cb7ec50d91be2da2c295387443438a9b Mon Sep 17 00:00:00 2001 From: Eguo Wang Date: Thu, 18 Jan 2024 22:43:35 +0800 Subject: [PATCH] refactor: New file service handler and service --- src/handlers/file.rs | 213 +++++++++++++++++++++++++++++++++++++++ src/handlers/logger.rs | 2 +- src/handlers/mod.rs | 1 + src/handlers/playbook.rs | 57 +---------- src/requests/file.rs | 26 +++++ src/requests/mod.rs | 1 + src/requests/playbook.rs | 14 --- src/routes.rs | 21 ++-- src/services/file.rs | 73 ++++++++++++++ src/services/mod.rs | 10 +- src/swagger.rs | 14 ++- 11 files changed, 352 insertions(+), 80 deletions(-) create mode 100644 src/handlers/file.rs create mode 100644 src/requests/file.rs create mode 100644 src/services/file.rs diff --git a/src/handlers/file.rs b/src/handlers/file.rs new file mode 100644 index 0000000..bfc3264 --- /dev/null +++ b/src/handlers/file.rs @@ -0,0 +1,213 @@ +// Copyright (c) The Amphitheatre Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::sync::Arc; + +use axum::extract::{Path, State}; +use axum::http::StatusCode; +use axum::response::IntoResponse; +use axum::Json; +use uuid::Uuid; + +use crate::context::Context; +use crate::errors::Result; +use crate::requests::file::{DestinationRequest, FileRequest}; +use crate::services::FileService; + +// The Files Service Handlers. + +/// Returns a file's content. +#[utoipa::path( + get, path = "/v1/playbooks/{id}/files/{reference}/{path}", + params( + ("id" = Uuid, description = "The id of playbook"), + ("reference" = String, description = "The name of the commit/branch/tag."), + ("path" = String, description = "The file path relative to the root of the repository."), + ), + responses( + (status = 200, description = "The file content", body = Content), + (status = 404, description = "Playbook not found"), + (status = 404, description = "File not found"), + (status = 500, description = "Internal Server Error"), + ), + tag = "Files" +)] +pub async fn get( + State(ctx): State>, + + Path(id): Path, + Path(reference): Path, + Path(path): Path, +) -> Result { + Ok(Json(FileService::get(ctx, id, reference, path).await?)) +} + +/// Create a file +#[utoipa::path( + post, path = "/v1/playbooks/{id}/files/{reference}/{path}", + params( + ("id" = Uuid, description = "The id of playbook"), + ("reference" = String, description = "The name of the commit/branch/tag."), + ("path" = String, description = "The file path relative to the root of the repository."), + ), + request_body( + content = inline(FileRequest), + description = "Create file request", + content_type = "application/json" + ), + responses( + (status = 201, description = "The file created successfully", body = Content), + (status = 404, description = "Playbook not found"), + (status = 500, description = "Internal Server Error"), + ), + tag = "Files" +)] +pub async fn create( + State(ctx): State>, + + Path(id): Path, + Path(reference): Path, + Path(path): Path, + + Json(req): Json, +) -> Result { + Ok((StatusCode::CREATED, Json(FileService::create(ctx, id, reference, path, req.content).await?))) +} + +/// Update a file +#[utoipa::path( + put, path = "/v1/playbooks/{id}/files/{reference}/{path}", + params( + ("id" = Uuid, description = "The id of playbook"), + ("reference" = String, description = "The name of the commit/branch/tag. Default: default branch."), + ("path" = String, description = "The file path relative to the root of the repository."), + ), + request_body( + content = inline(FileRequest), + description = "Update file request", + content_type = "application/json" + ), + responses( + (status = 200, description = "The file updated successfully", body = Content), + (status = 404, description = "Playbook not found"), + (status = 404, description = "File not found"), + (status = 500, description = "Internal Server Error"), + ), + tag = "Files" +)] +pub async fn update( + State(ctx): State>, + + Path(id): Path, + Path(reference): Path, + Path(path): Path, + + Json(req): Json, +) -> Result { + Ok(Json(FileService::update(ctx, id, reference, path, req.content).await?)) +} + +/// Delete a file +#[utoipa::path( + delete, path = "/v1/playbooks/{id}/files/{reference}/{path}", + params( + ("id" = Uuid, description = "The id of playbook"), + ("reference" = String, description = "The name of the commit/branch/tag."), + ("path" = String, description = "The file path relative to the root of the repository."), + ), + responses( + (status = 204, description = "The file deleted successfully"), + (status = 404, description = "Playbook not found"), + (status = 404, description = "File not found"), + (status = 500, description = "Internal Server Error"), + ), + tag = "Files" +)] +pub async fn delete( + State(ctx): State>, + + Path(id): Path, + Path(reference): Path, + Path(path): Path, +) -> Result { + FileService::delete(ctx, id, reference, path).await?; + + Ok(StatusCode::NO_CONTENT) +} + +/// Copy a file +#[utoipa::path( + post, path = "/v1/playbooks/{id}/files/{reference}/{path}/actions/copy", + params( + ("id" = Uuid, description = "The id of playbook"), + ("reference" = String, description = "The name of the commit/branch/tag. Default: default branch."), + ("path" = String, description = "The file path relative to the root of the repository."), + ), + request_body( + content = inline(DestinationRequest), + description = "The destination request", + content_type = "application/json" + ), + responses( + (status = 200, description = "The file copied successfully", body = Content), + (status = 404, description = "Playbook not found"), + (status = 404, description = "File not found"), + (status = 500, description = "Internal Server Error"), + ), + tag = "Files" +)] +pub async fn copy( + State(ctx): State>, + + Path(id): Path, + Path(reference): Path, + Path(path): Path, + + Json(req): Json, +) -> Result { + Ok(Json(FileService::copy(ctx, id, reference, path, req.destination).await?)) +} + +/// Move a file +#[utoipa::path( + post, path = "/v1/playbooks/{id}/files/{reference}/{path}/actions/move", + params( + ("id" = Uuid, description = "The id of playbook"), + ("reference" = String, description = "The name of the commit/branch/tag. Default: default branch."), + ("path" = String, description = "The file path relative to the root of the repository."), + ), + request_body( + content = inline(DestinationRequest), + description = "The destination request", + content_type = "application/json" + ), + responses( + (status = 200, description = "The file moved successfully", body = Content), + (status = 404, description = "Playbook not found"), + (status = 404, description = "File not found"), + (status = 500, description = "Internal Server Error"), + ), + tag = "Files" +)] +pub async fn rename( + State(ctx): State>, + + Path(id): Path, + Path(reference): Path, + Path(path): Path, + + Json(req): Json, +) -> Result { + Ok(Json(FileService::rename(ctx, id, reference, path, req.destination).await?)) +} diff --git a/src/handlers/logger.rs b/src/handlers/logger.rs index 62f25ff..c79b927 100644 --- a/src/handlers/logger.rs +++ b/src/handlers/logger.rs @@ -21,7 +21,7 @@ use uuid::Uuid; use crate::context::Context; use crate::errors::Result; -use crate::services::logger::LoggerService; +use crate::services::LoggerService; // The Logging Service Handlers. diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index 291b5c6..4b9e820 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -12,5 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. +pub mod file; pub mod logger; pub mod playbook; diff --git a/src/handlers/playbook.rs b/src/handlers/playbook.rs index d60aa08..29e9d9b 100644 --- a/src/handlers/playbook.rs +++ b/src/handlers/playbook.rs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use amp_common::sync::Synchronization; use std::sync::Arc; use axum::extract::{Path, State}; @@ -23,8 +22,8 @@ use uuid::Uuid; use crate::context::Context; use crate::errors::Result; -use crate::requests::playbook::{CreatePlaybookRequest, GetPlaybookRequest}; -use crate::services::playbook::PlaybookService; +use crate::requests::playbook::CreatePlaybookRequest; +use crate::services::PlaybookService; // The Playbooks Service Handlers. @@ -48,53 +47,6 @@ pub async fn create( Ok((StatusCode::CREATED, Json(PlaybookService::create(ctx, &req).await?))) } -/// Returns a playbook detail. -#[utoipa::path( - get, path = "/v1/playbooks/{id}/files/{reference}/{path}", - params( - ("id" = Uuid, description = "The id of playbook"), - ("reference" = String, description = "The name of the commit/branch/tag. Default: the repository’s default branch."), - ("path" = String, description = "path parameter"), - ), - responses( - (status = 200, description = "Playbook found successfully", body = FilesResponse), - (status = 404, description = "Playbook not found"), - (status = 500, description = "Internal Server Error"), - ), - tag = "Playbooks" -)] -pub async fn detail( - Path(params): Path, - State(ctx): State>, -) -> Result { - Ok(Json(PlaybookService::get(ctx, params.id, params.reference, params.path, true).await?)) -} -/// Update a playbook. -#[utoipa::path( - put, path = "/v1/playbooks/{id}", - params( - ("id" = Uuid, description = "The id of playbook"), - ), - request_body( - content = inline(Synchronization), - description = "Update playbook request", - content_type = "application/json" - ), - responses( - (status = 204, description = "Playbook updated successfully", body = PlaybookResponse), - (status = 404, description = "Playbook not found") - ), - tag = "Playbooks" -)] -pub async fn update( - Path(id): Path, - State(ctx): State>, - Json(req): Json, -) -> Result { - PlaybookService::update(ctx, id, req).await?; - Ok(StatusCode::NO_CONTENT) -} - /// Delete a playbook #[utoipa::path( delete, path = "/v1/playbooks/{id}", @@ -108,7 +60,7 @@ pub async fn update( ), tag = "Playbooks" )] -pub async fn delete(Path(id): Path, State(ctx): State>) -> Result { +pub async fn delete(State(ctx): State>, Path(id): Path) -> Result { PlaybookService::delete(ctx, id).await?; Ok(StatusCode::NO_CONTENT) @@ -127,7 +79,8 @@ pub async fn delete(Path(id): Path, State(ctx): State>) -> Re ), tag = "Playbooks" )] -pub async fn start(Path(id): Path, State(ctx): State>) -> Result { +pub async fn start(State(ctx): State>, Path(id): Path) -> Result { PlaybookService::start(ctx, id).await?; + Ok(StatusCode::NO_CONTENT) } diff --git a/src/requests/file.rs b/src/requests/file.rs new file mode 100644 index 0000000..0de5463 --- /dev/null +++ b/src/requests/file.rs @@ -0,0 +1,26 @@ +// Copyright (c) The Amphitheatre Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use serde::{Deserialize, Serialize}; +use utoipa::ToSchema; + +#[derive(Debug, Serialize, Deserialize, ToSchema)] +pub struct FileRequest { + pub content: String, +} + +#[derive(Debug, Serialize, Deserialize, ToSchema)] +pub struct DestinationRequest { + pub destination: String, +} diff --git a/src/requests/mod.rs b/src/requests/mod.rs index f904979..1f4a24f 100644 --- a/src/requests/mod.rs +++ b/src/requests/mod.rs @@ -12,4 +12,5 @@ // See the License for the specific language governing permissions and // limitations under the License. +pub mod file; pub mod playbook; diff --git a/src/requests/playbook.rs b/src/requests/playbook.rs index 7973d42..a9e5e5b 100644 --- a/src/requests/playbook.rs +++ b/src/requests/playbook.rs @@ -15,7 +15,6 @@ use amp_common::resource::Preface; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; -use uuid::Uuid; #[derive(Debug, Serialize, Deserialize, ToSchema)] pub struct CreatePlaybookRequest { @@ -23,16 +22,3 @@ pub struct CreatePlaybookRequest { pub description: Option, pub preface: Preface, } - -#[derive(Debug, Serialize, Deserialize, ToSchema)] -pub struct UpdatePlaybookRequest { - pub title: Option, - pub description: Option, -} - -#[derive(Debug, Serialize, Deserialize, ToSchema)] -pub struct GetPlaybookRequest { - pub id: Uuid, - pub reference: String, - pub path: Option, -} diff --git a/src/routes.rs b/src/routes.rs index 9c1e5d9..0fda94d 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -18,14 +18,23 @@ use axum::routing::{delete, get, post, put}; use axum::Router; use crate::context::Context; -use crate::handlers; +use crate::handlers::{file, logger, playbook}; pub fn build() -> Router> { Router::new() // playbooks - .route("/v1/playbooks", post(handlers::playbook::create)) - .route("/v1/playbooks/:id/files/:reference/:path", get(handlers::playbook::detail)) - .route("/v1/playbooks/:id", put(handlers::playbook::update)) - .route("/v1/playbooks/:id", delete(handlers::playbook::delete)) - .route("/v1/playbooks/:id/actions/start", get(handlers::playbook::start)) + .route("/v1/playbooks", post(playbook::create)) + .route("/v1/playbooks/:id", delete(playbook::delete)) + .route("/v1/playbooks/:id/actions/start", get(playbook::start)) + // + // logging + .route("/v1/playbooks/:id/logs", get(logger::logs)) + // + // files + .route("/v1/playbooks/:id/files/:reference/:path", get(file::get)) + .route("/v1/playbooks/:id/files/:reference/:path", post(file::create)) + .route("/v1/playbooks/:id/files/:reference/:path", put(file::update)) + .route("/v1/playbooks/:id/files/:reference/:path", delete(file::delete)) + .route("/v1/playbooks/:id/files/:reference/:path/actions/copy", post(file::copy)) + .route("/v1/playbooks/:id/files/:reference/:path/actions/move", post(file::rename)) } diff --git a/src/services/file.rs b/src/services/file.rs new file mode 100644 index 0000000..f3ca2a6 --- /dev/null +++ b/src/services/file.rs @@ -0,0 +1,73 @@ +// Copyright (c) The Amphitheatre Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::sync::Arc; +use uuid::Uuid; + +use amp_common::scm::content::Content; + +use crate::context::Context; +use crate::errors::Result; + +pub struct FileService; + +impl FileService { + pub async fn get(_ctx: Arc, _id: Uuid, _reference: String, _path: String) -> Result { + todo!() + } + + pub async fn create( + _ctx: Arc, + _id: Uuid, + _reference: String, + _path: String, + _content: String, + ) -> Result { + todo!() + } + + pub async fn update( + _ctx: Arc, + _id: Uuid, + _reference: String, + _path: String, + _content: String, + ) -> Result { + todo!() + } + + pub async fn delete(_ctx: Arc, _id: Uuid, _reference: String, _path: String) -> Result<()> { + todo!() + } + + pub async fn copy( + _ctx: Arc, + _id: Uuid, + _reference: String, + _path: String, + _destination: String, + ) -> Result { + todo!() + } + + pub async fn rename( + _ctx: Arc, + _id: Uuid, + _reference: String, + _path: String, + _destination: String, + ) -> Result { + todo!() + } +} diff --git a/src/services/mod.rs b/src/services/mod.rs index 291b5c6..cf6e61b 100644 --- a/src/services/mod.rs +++ b/src/services/mod.rs @@ -12,5 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub mod logger; -pub mod playbook; +mod file; +pub use file::FileService; + +mod logger; +pub use logger::LoggerService; + +mod playbook; +pub use playbook::PlaybookService; diff --git a/src/swagger.rs b/src/swagger.rs index 01da3e5..ba479a1 100644 --- a/src/swagger.rs +++ b/src/swagger.rs @@ -21,17 +21,23 @@ use crate::{handlers, requests}; #[openapi( paths( handlers::playbook::create, - handlers::playbook::detail, - handlers::playbook::update, handlers::playbook::delete, handlers::playbook::start, handlers::logger::logs, + + handlers::file::get, + handlers::file::create, + handlers::file::update, + handlers::file::delete, + handlers::file::copy, + handlers::file::rename, ), components( schemas( requests::playbook::CreatePlaybookRequest, - requests::playbook::UpdatePlaybookRequest, + requests::file::FileRequest, + requests::file::DestinationRequest, amp_common::resource::ActorSpec, amp_common::resource::CharacterSpec, @@ -53,8 +59,6 @@ use crate::{handlers, requests}; amp_common::scm::content::Content, amp_common::scm::git::Tree, amp_common::scm::git::TreeEntry, - - amp_common::sync::Synchronization, ) ), tags(