From 54c03231056411d69e133e7fb80ebc845cbbc99f Mon Sep 17 00:00:00 2001 From: Aravinth Manivannan Date: Sun, 27 Nov 2022 21:06:42 +0530 Subject: [PATCH] chore: mv deploy and meta API endpoints to src/api/v1 --- src/{ => api/v1}/meta.rs | 0 src/api/v1/mod.rs | 6 +- src/api/v1/pages.rs | 176 +++++++++++++++++++++++++++++++++++ src/api/v1/routes.rs | 5 +- src/deploy.rs | 193 --------------------------------------- src/main.rs | 2 - 6 files changed, 183 insertions(+), 199 deletions(-) rename src/{ => api/v1}/meta.rs (100%) delete mode 100644 src/deploy.rs diff --git a/src/meta.rs b/src/api/v1/meta.rs similarity index 100% rename from src/meta.rs rename to src/api/v1/meta.rs diff --git a/src/api/v1/mod.rs b/src/api/v1/mod.rs index 301d201..0a22156 100644 --- a/src/api/v1/mod.rs +++ b/src/api/v1/mod.rs @@ -20,6 +20,8 @@ use serde::Deserialize; pub mod account; pub mod auth; +pub mod meta; +pub mod pages; pub mod routes; pub use routes::ROUTES; @@ -27,8 +29,8 @@ pub use routes::ROUTES; pub fn services(cfg: &mut ServiceConfig) { auth::services(cfg); account::services(cfg); - crate::meta::services(cfg); - crate::deploy::services(cfg); + meta::services(cfg); + pages::services(cfg); } #[derive(Deserialize)] diff --git a/src/api/v1/pages.rs b/src/api/v1/pages.rs index e504959..69f9e8e 100644 --- a/src/api/v1/pages.rs +++ b/src/api/v1/pages.rs @@ -14,4 +14,180 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +use actix_web::{web, HttpResponse, Responder}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; +use crate::errors::*; +use crate::page::Page; +use crate::AppCtx; + +pub mod routes { + pub struct Deploy { + pub update: &'static str, + pub info: &'static str, + } + + impl Deploy { + pub const fn new() -> Self { + Self { + update: "/api/v1/update", + info: "/api/v1/info", + } + } + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct DeployEvent { + pub secret: String, + pub branch: String, +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct DeployEventResp { + pub id: Uuid, +} + +#[actix_web_codegen_const_routes::post(path = "crate::V1_API_ROUTES.deploy.update")] +#[tracing::instrument(name = "Update webpages", skip(payload, ctx))] +async fn update(payload: web::Json, ctx: AppCtx) -> ServiceResult { + let payload = payload.into_inner(); + let id = ctx + .update_site(&payload.secret, Some(payload.branch)) + .await?; + Ok(HttpResponse::Ok().json(DeployEventResp { id })) +} + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +pub struct DeploySecret { + pub secret: String, +} + +#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] +pub struct DeployInfo { + pub head: String, + pub remote: String, + pub commit: String, +} + +impl DeployInfo { + pub fn from_page(page: &Page) -> ServiceResult { + let repo = page.open_repo()?; + let head = page.get_deploy_branch(&repo)?; + let commit = Page::get_deploy_commit(&repo)?.to_string(); + let remote = Page::get_deploy_remote(&repo)?; + let remote = remote.url().unwrap().to_owned(); + + Ok(Self { + head, + remote, + commit, + }) + } +} + +#[actix_web_codegen_const_routes::post(path = "crate::V1_API_ROUTES.deploy.info")] +#[tracing::instrument(name = "Get webpage deploy info", skip(payload, ctx))] +async fn deploy_info( + payload: web::Json, + ctx: AppCtx, +) -> ServiceResult { + if let Ok(page) = ctx.db.get_site_from_secret(&payload.secret).await { + let resp = DeployInfo::from_page(&Page::from_site(&ctx.settings, page))?; + Ok(HttpResponse::Ok().json(resp)) + } else { + Err(ServiceError::WebsiteNotFound) + } +} + +pub fn services(cfg: &mut web::ServiceConfig) { + cfg.service(update); + cfg.service(deploy_info); +} + +#[cfg(test)] +mod tests { + use actix_web::{http::StatusCode, test}; + + use crate::tests; + use crate::*; + + use super::*; + + #[actix_rt::test] + async fn deploy_update_works() { + const NAME: &str = "dplyupdwrkuser"; + const PASSWORD: &str = "longpasswordasdfa2"; + const EMAIL: &str = "dplyupdwrkuser@a.com"; + + let (_dir, ctx) = tests::get_ctx().await; + let _ = ctx.delete_user(NAME, PASSWORD).await; + let (_, _signin_resp) = ctx.register_and_signin(NAME, EMAIL, PASSWORD).await; + let page = ctx.add_test_site(NAME.into()).await; + let app = get_app!(ctx).await; + + let mut payload = DeployEvent { + secret: page.secret.clone(), + branch: page.branch.clone(), + }; + + let resp = test::call_service( + &app, + post_request!(&payload, V1_API_ROUTES.deploy.update).to_request(), + ) + .await; + check_status!(resp, StatusCode::OK); + let event_id: DeployEventResp = actix_web::test::read_body_json(resp).await; + let update_event = ctx.db.get_event(&page.domain, &event_id.id).await.unwrap(); + assert_eq!(&update_event.site, &page.domain); + assert_eq!(update_event.id, event_id.id); + + payload.secret = page.branch.clone(); + + let resp = test::call_service( + &app, + post_request!(&payload, V1_API_ROUTES.deploy.update).to_request(), + ) + .await; + check_status!(resp, StatusCode::NOT_FOUND); + } + + #[actix_rt::test] + async fn deploy_info_works() { + const NAME: &str = "dplyinfwrkuser"; + const PASSWORD: &str = "longpasswordasdfa2"; + const EMAIL: &str = "dplyinfwrkuser@a.com"; + + let (_dir, ctx) = tests::get_ctx().await; + let _ = ctx.delete_user(NAME, PASSWORD).await; + let (_, _signin_resp) = ctx.register_and_signin(NAME, EMAIL, PASSWORD).await; + let page = ctx.add_test_site(NAME.into()).await; + let app = get_app!(ctx).await; + + let mut payload = DeploySecret { + secret: page.secret.clone(), + }; + + let resp = test::call_service( + &app, + post_request!(&payload, V1_API_ROUTES.deploy.info).to_request(), + ) + .await; + + check_status!(resp, StatusCode::OK); + + let response: DeployInfo = actix_web::test::read_body_json(resp).await; + assert_eq!(response.head, page.branch); + assert_eq!(response.remote, page.repo); + + payload.secret = page.branch.clone(); + + let resp = test::call_service( + &app, + post_request!(&payload, V1_API_ROUTES.deploy.info).to_request(), + ) + .await; + check_status!(resp, StatusCode::NOT_FOUND); + } +} diff --git a/src/api/v1/routes.rs b/src/api/v1/routes.rs index 8d50479..710117a 100644 --- a/src/api/v1/routes.rs +++ b/src/api/v1/routes.rs @@ -17,10 +17,11 @@ //! V1 API Routes use actix_auth_middleware::GetLoginRoute; -use crate::deploy::routes::Deploy; -use crate::meta::routes::Meta; use crate::serve::routes::Serve; +use super::meta::routes::Meta; +use super::pages::routes::Deploy; + /// constant [Routes](Routes) instance pub const ROUTES: Routes = Routes::new(); diff --git a/src/deploy.rs b/src/deploy.rs deleted file mode 100644 index 69f9e8e..0000000 --- a/src/deploy.rs +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2022 Aravinth Manivannan - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -use actix_web::{web, HttpResponse, Responder}; -use serde::{Deserialize, Serialize}; -use uuid::Uuid; - -use crate::errors::*; -use crate::page::Page; -use crate::AppCtx; - -pub mod routes { - pub struct Deploy { - pub update: &'static str, - pub info: &'static str, - } - - impl Deploy { - pub const fn new() -> Self { - Self { - update: "/api/v1/update", - info: "/api/v1/info", - } - } - } -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct DeployEvent { - pub secret: String, - pub branch: String, -} - -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct DeployEventResp { - pub id: Uuid, -} - -#[actix_web_codegen_const_routes::post(path = "crate::V1_API_ROUTES.deploy.update")] -#[tracing::instrument(name = "Update webpages", skip(payload, ctx))] -async fn update(payload: web::Json, ctx: AppCtx) -> ServiceResult { - let payload = payload.into_inner(); - let id = ctx - .update_site(&payload.secret, Some(payload.branch)) - .await?; - Ok(HttpResponse::Ok().json(DeployEventResp { id })) -} - -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -pub struct DeploySecret { - pub secret: String, -} - -#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)] -pub struct DeployInfo { - pub head: String, - pub remote: String, - pub commit: String, -} - -impl DeployInfo { - pub fn from_page(page: &Page) -> ServiceResult { - let repo = page.open_repo()?; - let head = page.get_deploy_branch(&repo)?; - let commit = Page::get_deploy_commit(&repo)?.to_string(); - let remote = Page::get_deploy_remote(&repo)?; - let remote = remote.url().unwrap().to_owned(); - - Ok(Self { - head, - remote, - commit, - }) - } -} - -#[actix_web_codegen_const_routes::post(path = "crate::V1_API_ROUTES.deploy.info")] -#[tracing::instrument(name = "Get webpage deploy info", skip(payload, ctx))] -async fn deploy_info( - payload: web::Json, - ctx: AppCtx, -) -> ServiceResult { - if let Ok(page) = ctx.db.get_site_from_secret(&payload.secret).await { - let resp = DeployInfo::from_page(&Page::from_site(&ctx.settings, page))?; - Ok(HttpResponse::Ok().json(resp)) - } else { - Err(ServiceError::WebsiteNotFound) - } -} - -pub fn services(cfg: &mut web::ServiceConfig) { - cfg.service(update); - cfg.service(deploy_info); -} - -#[cfg(test)] -mod tests { - use actix_web::{http::StatusCode, test}; - - use crate::tests; - use crate::*; - - use super::*; - - #[actix_rt::test] - async fn deploy_update_works() { - const NAME: &str = "dplyupdwrkuser"; - const PASSWORD: &str = "longpasswordasdfa2"; - const EMAIL: &str = "dplyupdwrkuser@a.com"; - - let (_dir, ctx) = tests::get_ctx().await; - let _ = ctx.delete_user(NAME, PASSWORD).await; - let (_, _signin_resp) = ctx.register_and_signin(NAME, EMAIL, PASSWORD).await; - let page = ctx.add_test_site(NAME.into()).await; - let app = get_app!(ctx).await; - - let mut payload = DeployEvent { - secret: page.secret.clone(), - branch: page.branch.clone(), - }; - - let resp = test::call_service( - &app, - post_request!(&payload, V1_API_ROUTES.deploy.update).to_request(), - ) - .await; - check_status!(resp, StatusCode::OK); - let event_id: DeployEventResp = actix_web::test::read_body_json(resp).await; - let update_event = ctx.db.get_event(&page.domain, &event_id.id).await.unwrap(); - assert_eq!(&update_event.site, &page.domain); - assert_eq!(update_event.id, event_id.id); - - payload.secret = page.branch.clone(); - - let resp = test::call_service( - &app, - post_request!(&payload, V1_API_ROUTES.deploy.update).to_request(), - ) - .await; - check_status!(resp, StatusCode::NOT_FOUND); - } - - #[actix_rt::test] - async fn deploy_info_works() { - const NAME: &str = "dplyinfwrkuser"; - const PASSWORD: &str = "longpasswordasdfa2"; - const EMAIL: &str = "dplyinfwrkuser@a.com"; - - let (_dir, ctx) = tests::get_ctx().await; - let _ = ctx.delete_user(NAME, PASSWORD).await; - let (_, _signin_resp) = ctx.register_and_signin(NAME, EMAIL, PASSWORD).await; - let page = ctx.add_test_site(NAME.into()).await; - let app = get_app!(ctx).await; - - let mut payload = DeploySecret { - secret: page.secret.clone(), - }; - - let resp = test::call_service( - &app, - post_request!(&payload, V1_API_ROUTES.deploy.info).to_request(), - ) - .await; - - check_status!(resp, StatusCode::OK); - - let response: DeployInfo = actix_web::test::read_body_json(resp).await; - assert_eq!(response.head, page.branch); - assert_eq!(response.remote, page.repo); - - payload.secret = page.branch.clone(); - - let resp = test::call_service( - &app, - post_request!(&payload, V1_API_ROUTES.deploy.info).to_request(), - ) - .await; - check_status!(resp, StatusCode::NOT_FOUND); - } -} diff --git a/src/main.rs b/src/main.rs index c90d9c9..299fb88 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,10 +29,8 @@ use tracing_actix_web::TracingLogger; mod api; mod ctx; mod db; -mod deploy; mod errors; mod git; -mod meta; mod page; mod page_config; mod pages;