From 968a799b3511e2249f1dd0e962e79e533154444c Mon Sep 17 00:00:00 2001 From: Aravinth Manivannan Date: Mon, 19 Dec 2022 00:27:36 +0530 Subject: [PATCH] feat: templates to add gitea oauth configuration --- src/pages/auth/gitea/add.rs | 118 ++++++++++++++++++++++++++ src/pages/auth/gitea/mod.rs | 32 +++++++ src/pages/auth/gitea/search.rs | 118 ++++++++++++++++++++++++++ src/pages/auth/mod.rs | 3 + src/pages/routes.rs | 23 +++++ templates/pages/auth/gitea/add.html | 62 ++++++++++++++ templates/pages/auth/gitea/login.html | 62 ++++++++++++++ 7 files changed, 418 insertions(+) create mode 100644 src/pages/auth/gitea/add.rs create mode 100644 src/pages/auth/gitea/mod.rs create mode 100644 src/pages/auth/gitea/search.rs create mode 100644 templates/pages/auth/gitea/add.html create mode 100644 templates/pages/auth/gitea/login.html diff --git a/src/pages/auth/gitea/add.rs b/src/pages/auth/gitea/add.rs new file mode 100644 index 0000000..c509d7e --- /dev/null +++ b/src/pages/auth/gitea/add.rs @@ -0,0 +1,118 @@ +/* + * 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_web::http::header::ContentType; +use tera::Context; + +use crate::db::AddGiteaInstance; +use crate::pages::errors::*; +use crate::settings::Settings; +use crate::AppCtx; + +pub use super::*; + +pub struct GiteaAddInstanceTemplate { + ctx: RefCell, +} + +pub const GITEA_ADD_INSTANCE: TemplateFile = + TemplateFile::new("gitea_add_instance", "pages/auth/gitea/add.html"); + +impl CtxError for GiteaAddInstanceTemplate { + fn with_error(&self, e: &ReadableError) -> String { + self.ctx.borrow_mut().insert(ERROR_KEY, e); + self.render() + } +} + +impl GiteaAddInstanceTemplate { + pub fn new(settings: &Settings, payload: Option<&AddGiteaInstance>) -> Self { + let ctx = RefCell::new(context(settings)); + if let Some(payload) = payload { + ctx.borrow_mut().insert(PAYLOAD_KEY, payload); + } + Self { ctx } + } + + pub fn render(&self) -> String { + TEMPLATES + .render(GITEA_ADD_INSTANCE.name, &self.ctx.borrow()) + .unwrap() + } + + pub fn page(s: &Settings) -> String { + let p = Self::new(s, None); + p.render() + } +} + +#[actix_web_codegen_const_routes::get(path = "PAGES.auth.gitea.add")] +#[tracing::instrument(name = "Serve add Gitea instance page", skip(ctx))] +pub async fn get_gitea_add_instance(ctx: AppCtx) -> impl Responder { + let login = GiteaAddInstanceTemplate::page(&ctx.settings); + let html = ContentType::html(); + HttpResponse::Ok().content_type(html).body(login) +} + +pub fn services(cfg: &mut web::ServiceConfig) { + cfg.service(get_gitea_add_instance); + cfg.service(post_gitea_add_instance); +} + +#[actix_web_codegen_const_routes::post(path = "PAGES.auth.gitea.add")] +#[tracing::instrument(name = "Submit new Gitea instance", skip(payload, ctx))] +pub async fn post_gitea_add_instance( + payload: web::Form, + ctx: AppCtx, +) -> PageResult { + let payload = payload.into_inner(); + ctx.init_gitea_instance(&payload).await.map_err(|e| { + PageError::new( + GiteaAddInstanceTemplate::new(&ctx.settings, Some(&payload)), + e, + ) + })?; + Ok(HttpResponse::Found() + .insert_header((http::header::LOCATION, PAGES.dash.home)) + .finish()) +} + +#[cfg(test)] +mod tests { + use url::Url; + + use super::GiteaAddInstanceTemplate; + use crate::db::AddGiteaInstance; + use crate::errors::*; + use crate::pages::errors::*; + use crate::settings::Settings; + + #[test] + fn gitea_add_instnace_page_renders() { + let settings = Settings::new().unwrap(); + GiteaAddInstanceTemplate::page(&settings); + let payload = AddGiteaInstance { + client_id: "foo".into(), + client_secret: "foo".into(), + url: Url::parse("https://example.org").unwrap(), + }; + let page = GiteaAddInstanceTemplate::new(&settings, Some(&payload)); + page.with_error(&ReadableError::new(&ServiceError::WrongPassword)); + page.render(); + } +} diff --git a/src/pages/auth/gitea/mod.rs b/src/pages/auth/gitea/mod.rs new file mode 100644 index 0000000..753fb2d --- /dev/null +++ b/src/pages/auth/gitea/mod.rs @@ -0,0 +1,32 @@ +/* + * 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::*; + +pub use super::{context, Footer, TemplateFile, PAGES, PAYLOAD_KEY, TEMPLATES}; + +pub mod add; + +pub fn register_templates(t: &mut tera::Tera) { + for template in [add::GITEA_ADD_INSTANCE].iter() { + template.register(t).expect(template.name); + } +} + + +pub fn services(cfg: &mut web::ServiceConfig) { + add::services(cfg) +} diff --git a/src/pages/auth/gitea/search.rs b/src/pages/auth/gitea/search.rs new file mode 100644 index 0000000..b268703 --- /dev/null +++ b/src/pages/auth/gitea/search.rs @@ -0,0 +1,118 @@ +/* + * 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_web::http::header::ContentType; +use tera::Context; + +use crate::db::AddGiteaInstance; +use crate::pages::errors::*; +use crate::settings::Settings; +use crate::AppCtx; + +pub use super::*; + +pub struct GiteaAddInstanceTemplate { + ctx: RefCell, +} + +pub const GITEA_SEARCH_INSTANCE: TemplateFile = + TemplateFile::new("gitea_add_instance", "pages/auth/gitea/add.html"); + +impl CtxError for GiteaAddInstanceTemplate { + fn with_error(&self, e: &ReadableError) -> String { + self.ctx.borrow_mut().insert(ERROR_KEY, e); + self.render() + } +} + +impl GiteaAddInstanceTemplate { + pub fn new(settings: &Settings, payload: Option<&AddGiteaInstance>) -> Self { + let ctx = RefCell::new(context(settings)); + if let Some(payload) = payload { + ctx.borrow_mut().insert(PAYLOAD_KEY, payload); + } + Self { ctx } + } + + pub fn render(&self) -> String { + TEMPLATES + .render(GITEA_SEARCH_INSTANCE.name, &self.ctx.borrow()) + .unwrap() + } + + pub fn page(s: &Settings) -> String { + let p = Self::new(s, None); + p.render() + } +} + +#[actix_web_codegen_const_routes::get(path = "PAGES.auth.gitea.add")] +#[tracing::instrument(name = "Serve add Gitea instance page", skip(ctx))] +pub async fn get_gitea_add_instance(ctx: AppCtx) -> impl Responder { + let login = GiteaAddInstanceTemplate::page(&ctx.settings); + let html = ContentType::html(); + HttpResponse::Ok().content_type(html).body(login) +} + +pub fn services(cfg: &mut web::ServiceConfig) { + cfg.service(get_gitea_add_instance); + cfg.service(post_gitea_add_instance); +} + +#[actix_web_codegen_const_routes::post(path = "PAGES.auth.gitea.add")] +#[tracing::instrument(name = "Submit new Gitea instance", skip(payload, ctx))] +pub async fn post_gitea_add_instance( + payload: web::Form, + ctx: AppCtx, +) -> PageResult { + let payload = payload.into_inner(); + ctx.init_gitea_instance(&payload).await.map_err(|e| { + PageError::new( + GiteaAddInstanceTemplate::new(&ctx.settings, Some(&payload)), + e, + ) + })?; + Ok(HttpResponse::Found() + .insert_header((http::header::LOCATION, PAGES.dash.home)) + .finish()) +} + +#[cfg(test)] +mod tests { + use url::Url; + + use super::GiteaAddInstanceTemplate; + use crate::db::AddGiteaInstance; + use crate::errors::*; + use crate::pages::errors::*; + use crate::settings::Settings; + + #[test] + fn gitea_add_instnace_page_renders() { + let settings = Settings::new().unwrap(); + GiteaAddInstanceTemplate::page(&settings); + let payload = AddGiteaInstance { + client_id: "foo".into(), + client_secret: "foo".into(), + url: Url::parse("https://example.org").unwrap(), + }; + let page = GiteaAddInstanceTemplate::new(&settings, Some(&payload)); + page.with_error(&ReadableError::new(&ServiceError::WrongPassword)); + page.render(); + } +} diff --git a/src/pages/auth/mod.rs b/src/pages/auth/mod.rs index 5343e89..0bd3fe3 100644 --- a/src/pages/auth/mod.rs +++ b/src/pages/auth/mod.rs @@ -19,6 +19,7 @@ use actix_web::*; pub use super::{context, Footer, TemplateFile, PAGES, PAYLOAD_KEY, TEMPLATES}; +pub mod gitea; pub mod login; pub mod register; #[cfg(test)] @@ -30,12 +31,14 @@ pub fn register_templates(t: &mut tera::Tera) { for template in [AUTH_BASE, login::LOGIN, register::REGISTER].iter() { template.register(t).expect(template.name); } + gitea::register_templates(t); } pub fn services(cfg: &mut web::ServiceConfig) { cfg.service(signout); register::services(cfg); login::services(cfg); + gitea::services(cfg); } #[actix_web_codegen_const_routes::get( diff --git a/src/pages/routes.rs b/src/pages/routes.rs index d2a7870..fe54e5b 100644 --- a/src/pages/routes.rs +++ b/src/pages/routes.rs @@ -41,6 +41,25 @@ impl Pages { } } +#[derive(Serialize)] +/// Gitea authentication routes +pub struct Gitea { + /// add Gitea instance route + pub add: &'static str, + /// search Gitea instance route + pub search: &'static str, + +} + +impl Gitea { + /// create new instance of Authentication route + pub const fn new() -> Self { + let add = "/gitea/add"; + let search = "/gitea/search"; + Self { add, search } + } +} + #[derive(Serialize)] /// Authentication routes pub struct Auth { @@ -50,6 +69,8 @@ pub struct Auth { pub login: &'static str, /// registration route pub register: &'static str, + /// gitea authentication routes + pub gitea: Gitea, } impl Auth { @@ -58,10 +79,12 @@ impl Auth { let login = "/login"; let logout = "/logout"; let register = "/join"; + let gitea = Gitea::new(); Auth { logout, login, register, + gitea, } } } diff --git a/templates/pages/auth/gitea/add.html b/templates/pages/auth/gitea/add.html new file mode 100644 index 0000000..27c257a --- /dev/null +++ b/templates/pages/auth/gitea/add.html @@ -0,0 +1,62 @@ +{% extends 'authbase' %} +{% block login %} +

Add Gitea Instance

+
+ {% include "error_comp" %} + + + + + + + +
+ +
+
+ + +{% endblock %} diff --git a/templates/pages/auth/gitea/login.html b/templates/pages/auth/gitea/login.html new file mode 100644 index 0000000..27c257a --- /dev/null +++ b/templates/pages/auth/gitea/login.html @@ -0,0 +1,62 @@ +{% extends 'authbase' %} +{% block login %} +

Add Gitea Instance

+
+ {% include "error_comp" %} + + + + + + + +
+ +
+
+ + +{% endblock %}