feat: bootstrap tera

This commit is contained in:
Aravinth Manivannan 2023-01-24 19:23:29 +05:30
parent fdc10ff28d
commit fe584190f5
Signed by: realaravinth
GPG key ID: AD9F0F08E855ED88

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2021 Aravinth Manivannan <realaravinth@batsense.net> * Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as * it under the terms of the GNU Affero General Public License as
@ -11,113 +11,283 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * 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 <https://www.gnu.org/licenses/>. * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
use actix_auth_middleware::*; use actix_auth_middleware::*;
use actix_web::web::ServiceConfig; use actix_web::web::ServiceConfig;
use lazy_static::lazy_static;
use rust_embed::RustEmbed;
use serde::*;
use tera::*;
use crate::settings::Settings;
use crate::static_assets::routes::ASSETS;
use crate::{GIT_COMMIT_HASH, VERSION};
pub mod auth; pub mod auth;
pub mod errors; pub mod errors;
mod panel;
pub mod routes; pub mod routes;
//mod sitemap;
pub const NAME: &str = "mCaptcha Survey"; //pub use routes::get_auth_middleware;
pub use routes::PAGES;
pub struct TemplateFile {
pub name: &'static str,
pub path: &'static str,
}
impl TemplateFile {
pub const fn new(name: &'static str, path: &'static str) -> Self {
Self { name, path }
}
pub fn register(&self, t: &mut Tera) -> std::result::Result<(), tera::Error> {
t.add_raw_template(self.name, &Templates::get_template(self).expect(self.name))
}
#[cfg(test)]
#[allow(dead_code)]
pub fn register_from_file(
&self,
t: &mut Tera,
) -> std::result::Result<(), tera::Error> {
use std::path::Path;
t.add_template_file(Path::new("templates/").join(self.path), Some(self.name))
}
}
pub const PAYLOAD_KEY: &str = "payload";
pub const BASE: TemplateFile = TemplateFile::new("base", "components/base.html");
pub const FOOTER: TemplateFile =
TemplateFile::new("footer", "components/footer/index.html");
pub const PANEL_NAV: TemplateFile =
TemplateFile::new("panel_nav", "panel/nav/index.html");
lazy_static! {
pub static ref TEMPLATES: Tera = {
let mut tera = Tera::default();
for t in [BASE, FOOTER, PANEL_NAV].iter() {
t.register(&mut tera).unwrap();
}
errors::register_templates(&mut tera);
tera.autoescape_on(vec![".html", ".sql"]);
auth::register_templates(&mut tera);
tera
};
}
#[derive(RustEmbed)]
#[folder = "templates/"]
pub struct Templates;
impl Templates {
pub fn get_template(t: &TemplateFile) -> Option<String> {
match Self::get(t.path) {
Some(file) => Some(String::from_utf8_lossy(&file.data).into_owned()),
None => None,
}
}
}
pub fn context(s: &Settings, page_title: &str) -> Context {
let mut ctx = Context::new();
let footer = Footer::new(s);
ctx.insert("page_title", page_title);
ctx.insert("page", &PAGES);
ctx.insert("api", &crate::V1_API_ROUTES);
ctx.insert("footer", &footer);
ctx.insert("assets", &*ASSETS);
ctx
}
pub fn auth_ctx(_username: Option<&str>, s: &Settings, page_title: &str) -> Context {
let mut ctx = Context::new();
let footer = Footer::new(s);
ctx.insert("page_title", page_title);
ctx.insert("footer", &footer);
ctx.insert("page", &PAGES);
ctx.insert("api", &crate::V1_API_ROUTES);
ctx.insert("assets", &*ASSETS);
ctx
}
#[derive(Serialize)]
pub struct Footer<'a> {
version: &'a str,
support_email: &'a str,
source_code: &'a str,
git_hash: &'a str,
settings: &'a Settings,
about: &'a str,
privacy: &'a str,
donate: &'a str,
security: &'a str,
thanks: &'a str,
}
impl<'a> Footer<'a> {
pub fn new(settings: &'a Settings) -> Self {
Self {
version: VERSION,
source_code: &settings.source_code,
support_email: &settings.support_email,
git_hash: &GIT_COMMIT_HASH[..8],
about: settings.footer.about.as_str(),
privacy: settings.footer.privacy.as_str(),
thanks: settings.footer.thanks.as_str(),
security: settings.footer.security.as_str(),
donate: settings.footer.donate.as_str(),
settings,
}
}
}
pub fn services(cfg: &mut ServiceConfig) { pub fn services(cfg: &mut ServiceConfig) {
auth::services(cfg); auth::services(cfg);
panel::services(cfg); //panel::services(cfg);
errors::services(cfg);
} }
pub fn get_page_check_login() -> Authentication<auth::routes::Auth> { pub fn get_page_check_login() -> Authentication<auth::routes::Auth> {
Authentication::with_identity(crate::PAGES.auth) Authentication::with_identity(crate::PAGES.auth)
} }
#[cfg(not(tarpaulin_include))]
#[cfg(test)] #[cfg(test)]
mod tests { mod terra_tests {
use actix_web::http::{header, StatusCode};
#[test]
fn templates_work_basic() {
use super::*;
use tera::Tera;
let mut tera = Tera::default();
let mut tera2 = Tera::default();
for t in [
BASE,
FOOTER,
PANEL_NAV,
// auth::AUTH_BASE,
auth::login::LOGIN,
auth::join::REGISTER,
errors::ERROR_TEMPLATE,
]
.iter()
{
t.register_from_file(&mut tera2).unwrap();
t.register(&mut tera).unwrap();
}
}
}
#[cfg(test)]
mod http_page_tests {
use actix_web::http::StatusCode;
use actix_web::test; use actix_web::test;
use crate::tests::*;
use crate::*; use crate::*;
use super::PAGES;
#[actix_rt::test] #[actix_rt::test]
async fn protected_pages_templates_work() { async fn templates_work() {
const NAME: &str = "templateuser"; use crate::tests::*;
const PASSWORD: &str = "longpassword";
const EMAIL: &str = "templateuser@a.com";
const CAMPAIGN_NAME: &str = "delcappageusercamaping";
let data = Data::new().await;
{
delete_user(NAME, &data).await;
}
let (_, _, signin_resp) = register_and_signin(NAME, EMAIL, PASSWORD).await;
let cookies = get_cookie!(signin_resp);
let campaign =
create_new_campaign(CAMPAIGN_NAME, data.clone(), cookies.clone()).await;
let data = get_test_data().await;
let app = get_app!(data).await; let app = get_app!(data).await;
let urls = vec![ for file in [PAGES.auth.login, PAGES.auth.join, PAGES.home].iter() {
PAGES.home.into(), let resp = get_request!(&app, file);
PAGES.panel.campaigns.home.into(),
PAGES.panel.campaigns.new.into(),
// PAGES.panel.campaigns.get_feedback_route(&campaign.uuid),
PAGES
.panel
.campaigns
.get_delete_route(&campaign.campaign_id),
];
for url in urls.iter() {
let resp =
test::call_service(&app, test::TestRequest::get().uri(url).to_request())
.await;
if resp.status() != StatusCode::FOUND {
println!("Probably error url: {}", url);
}
assert_eq!(resp.status(), StatusCode::FOUND);
let authenticated_resp = test::call_service(
&app,
test::TestRequest::get()
.uri(url)
.cookie(cookies.clone())
.to_request(),
)
.await;
if url == PAGES.home {
assert_eq!(authenticated_resp.status(), StatusCode::FOUND);
let headers = authenticated_resp.headers();
assert_eq!(
headers.get(header::LOCATION).unwrap(),
&*super::panel::DEFAULT_CAMPAIGN_ABOUT
);
} else {
assert_eq!(authenticated_resp.status(), StatusCode::OK);
}
}
delete_user(NAME, &data).await;
}
#[actix_rt::test]
async fn public_pages_tempaltes_work() {
let app = test::init_service(App::new().configure(crate::pages::services)).await;
let urls = vec![PAGES.auth.login, PAGES.auth.join]; //, PAGES.sitemap];
for url in urls.iter() {
let resp =
test::call_service(&app, test::TestRequest::get().uri(url).to_request())
.await;
assert_eq!(resp.status(), StatusCode::OK); assert_eq!(resp.status(), StatusCode::OK);
} }
} }
} }
//#[cfg(not(tarpaulin_include))]
//#[cfg(test)]
//mod tests {
// use actix_web::http::{header, StatusCode};
// use actix_web::test;
//
// use crate::tests::*;
// use crate::*;
//
// #[actix_rt::test]
// async fn protected_pages_templates_work() {
// const NAME: &str = "templateuser";
// const PASSWORD: &str = "longpassword";
// const EMAIL: &str = "templateuser@a.com";
// const CAMPAIGN_NAME: &str = "delcappageusercamaping";
//
// let settings = Settings::new().unwrap();
// let data = Data::new(settings).await;
// {
// delete_user(NAME, &data).await;
// }
//
// let (_, _, signin_resp) = register_and_signin(NAME, EMAIL, PASSWORD).await;
// let cookies = get_cookie!(signin_resp);
//
// let campaign =
// create_new_campaign(CAMPAIGN_NAME, data.clone(), cookies.clone()).await;
//
// let app = get_app!(data).await;
//
// let urls = vec![
// PAGES.home.to_string(),
// PAGES.panel.campaigns.home.to_string(),
// PAGES.panel.campaigns.new.to_string(),
// // PAGES.panel.campaigns.get_feedback_route(&campaign.uuid),
// PAGES
// .panel
// .campaigns
// .get_delete_route(&campaign.campaign_id),
// ];
//
// for url in urls.iter() {
// let resp =
// test::call_service(&app, test::TestRequest::get().uri(url).to_request())
// .await;
// if resp.status() != StatusCode::FOUND {
// println!("Probably error url: {}", url);
// }
// assert_eq!(resp.status(), StatusCode::FOUND);
//
// let authenticated_resp = test::call_service(
// &app,
// test::TestRequest::get()
// .uri(url)
// .cookie(cookies.clone())
// .to_request(),
// )
// .await;
//
// if url == PAGES.home {
// assert_eq!(authenticated_resp.status(), StatusCode::FOUND);
// let headers = authenticated_resp.headers();
// assert_eq!(
// headers.get(header::LOCATION).unwrap(),
// &*super::panel::DEFAULT_CAMPAIGN_ABOUT
// );
// } else {
// assert_eq!(authenticated_resp.status(), StatusCode::OK);
// }
// }
//
// delete_user(NAME, &data).await;
// }
//
// #[actix_rt::test]
// async fn public_pages_tempaltes_work() {
// let app = test::init_service(App::new().configure(crate::pages::services)).await;
// let urls = vec![PAGES.auth.login, PAGES.auth.join]; //, PAGES.sitemap];
//
// for url in urls.iter() {
// let resp =
// test::call_service(&app, test::TestRequest::get().uri(url).to_request())
// .await;
//
// assert_eq!(resp.status(), StatusCode::OK);
// }
// }
//}