/* * 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 std::cell::RefCell; use actix_identity::Identity; use actix_web::http::header::ContentType; use tera::Context; use tracing::info; use super::get_auth_middleware; use crate::api::v1::forgejo::AddWebhook; use crate::pages::errors::*; use crate::settings::Settings; use crate::AppCtx; pub use super::*; pub const DASH_FORGEJO_WEBHOOK_ADD: TemplateFile = TemplateFile::new("dash_forgejo_webhook_add", "pages/dash/forgejo/add.html"); pub struct Add { ctx: RefCell, } impl CtxError for Add { fn with_error(&self, e: &ReadableError) -> String { self.ctx.borrow_mut().insert(ERROR_KEY, e); self.render() } } impl Add { pub fn new(settings: &Settings) -> Self { let ctx = RefCell::new(context(settings)); Self { ctx } } pub fn render(&self) -> String { TEMPLATES .render(DASH_FORGEJO_WEBHOOK_ADD.name, &self.ctx.borrow()) .unwrap() } } #[actix_web_codegen_const_routes::get( path = "PAGES.dash.forgejo_webhook.add", wrap = "get_auth_middleware()" )] #[tracing::instrument(name = "Dashboard add forgejo webhook webpage", skip(ctx))] pub async fn get_add_forgejo_webhook(ctx: AppCtx) -> PageResult { let add = Add::new(&ctx.settings).render(); let html = ContentType::html(); Ok(HttpResponse::Ok().content_type(html).body(add)) } #[actix_web_codegen_const_routes::post( path = "PAGES.dash.forgejo_webhook.add", wrap = "get_auth_middleware()" )] #[tracing::instrument( name = "Post Dashboard add Forgejo webhook webpage", skip(ctx, id, payload) )] pub async fn post_add_forgejo_webhook( ctx: AppCtx, id: Identity, payload: web::Form, ) -> PageResult { let owner = id.identity().unwrap(); let payload = payload.into_inner(); info!( "Adding webhook for Forgejo instance: {}", payload.forgejo_url.as_str() ); let hook = ctx .db .new_webhook(payload.forgejo_url, &owner) .await .map_err(|e| PageError::new(Add::new(&ctx.settings), e))?; Ok(HttpResponse::Found() .append_header(( http::header::LOCATION, PAGES.dash.forgejo_webhook.get_view(&hook.auth_token), )) .finish()) } pub fn services(cfg: &mut web::ServiceConfig) { cfg.service(get_add_forgejo_webhook); cfg.service(post_add_forgejo_webhook); } #[cfg(test)] mod tests { use actix_web::http::StatusCode; use actix_web::test; use url::Url; use crate::api::v1::forgejo::AddWebhook; use crate::ctx::ArcCtx; use crate::tests; use crate::*; use super::PAGES; #[actix_rt::test] async fn postgres_dashboadr_add_forgejo_webhook_works() { let (_, ctx) = tests::get_ctx().await; dashboadr_add_forgejo_webhook_works(ctx.clone()).await; } async fn dashboadr_add_forgejo_webhook_works(ctx: ArcCtx) { const NAME: &str = "testdashwebhookforgejoadduser"; const EMAIL: &str = "testdashwebhookforgejoadduser@foo.com"; const PASSWORD: &str = "longpassword"; let _ = ctx.delete_user(NAME, PASSWORD).await; let (_, signin_resp) = ctx.register_and_signin(NAME, EMAIL, PASSWORD).await; let cookies = get_cookie!(signin_resp); let app = get_app!(ctx.clone()).await; let resp = get_request!(&app, PAGES.dash.forgejo_webhook.add, cookies.clone()); assert_eq!(resp.status(), StatusCode::OK); let res = String::from_utf8(test::read_body(resp).await.to_vec()).unwrap(); assert!(res.contains("Add Forgejo Webhook")); let payload = AddWebhook { forgejo_url: Url::parse("https://git.batsense.net").unwrap(), }; let add_webhook = test::call_service( &app, post_request!(&payload, PAGES.dash.forgejo_webhook.add, FORM) .cookie(cookies.clone()) .to_request(), ) .await; assert_eq!(add_webhook.status(), StatusCode::FOUND); let mut hooks = ctx.db.list_all_webhooks_with_owner(NAME).await.unwrap(); let hook = hooks.pop().unwrap(); // let mut event = ctx.db.list(&site.hostname).await.unwrap(); // let event = event.pop().unwrap(); let headers = add_webhook.headers(); let view_webhook_url = PAGES.dash.forgejo_webhook.get_view(&hook.auth_token); assert_eq!( headers.get(actix_web::http::header::LOCATION).unwrap(), &view_webhook_url ); // list webhooks let resp = get_request!(&app, PAGES.dash.forgejo_webhook.list, cookies.clone()); assert_eq!(resp.status(), StatusCode::OK); let res = String::from_utf8(test::read_body(resp).await.to_vec()).unwrap(); assert!(res.contains(hook.forgejo_url.as_str())); // view webhook let resp = get_request!(&app, &view_webhook_url, cookies.clone()); assert_eq!(resp.status(), StatusCode::OK); let res = String::from_utf8(test::read_body(resp).await.to_vec()).unwrap(); assert!(res.contains("****")); assert!(res.contains( &crate::V1_API_ROUTES .forgejo .get_webhook_url(&ctx, &hook.auth_token) )); let show_forgejo_webhook_secret = format!("{view_webhook_url}?show_forgejo_webhook_secret=true"); let resp = get_request!(&app, &show_forgejo_webhook_secret, cookies.clone()); assert_eq!(resp.status(), StatusCode::OK); let res = String::from_utf8(test::read_body(resp).await.to_vec()).unwrap(); assert!(res.contains(&hook.forgejo_webhook_secret)); } }