feat: bootstrap tera
This commit is contained in:
parent
fdc10ff28d
commit
fe584190f5
1 changed files with 251 additions and 81 deletions
332
src/pages/mod.rs
332
src/pages/mod.rs
|
@ -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);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
Loading…
Reference in a new issue