moved template logic into own module.

This commit is contained in:
didier amyot committed 2023-03-09 10:09:12 -05:00
1 parent f8d676e5df
commit eebe848e4b
11 files changed
+68 -76

No files matched your search

+2 -1
View File
@@ -1,6 +1,6 @@
use crate::util::{CustomResult, Error}; use crate::util::{CustomResult, Error};
use base64::{engine::general_purpose, Engine as _}; use base64::{engine::general_purpose, Engine as _};
use rusqlite::{params, Connection, Result, Row, Transaction}; use rusqlite::{params, Result, Row, Transaction};
pub struct LedgerInternal {} pub struct LedgerInternal {}
@@ -49,6 +49,7 @@ impl LedgerInternal {
mod test_ledger_internal { mod test_ledger_internal {
use super::*; use super::*;
use crate::migration; use crate::migration;
use rusqlite::Connection;
#[test] #[test]
fn test_initial_cookie_secret() -> CustomResult<()> { fn test_initial_cookie_secret() -> CustomResult<()> {
+2 -7
View File
@@ -436,7 +436,6 @@ mod cli_test {
"123abc", "123abc",
]); ]);
let mut logic = TestCommandLineLogic::new(); let mut logic = TestCommandLineLogic::new();
let mut conn = Connection::open_in_memory().unwrap();
process_command_line(SQLiteConnectionFactory::in_memory(), &m, &mut logic)?; process_command_line(SQLiteConnectionFactory::in_memory(), &m, &mut logic)?;
assert_eq!(logic.create_user_count, 1); assert_eq!(logic.create_user_count, 1);
Ok(()) Ok(())
@@ -447,7 +446,6 @@ mod cli_test {
let cmd = command_line_parser(); let cmd = command_line_parser();
let m = cmd.get_matches_from(vec!["test", "users", "ls"]); let m = cmd.get_matches_from(vec!["test", "users", "ls"]);
let mut logic = TestCommandLineLogic::new(); let mut logic = TestCommandLineLogic::new();
let mut conn = Connection::open_in_memory().unwrap();
process_command_line(SQLiteConnectionFactory::in_memory(), &m, &mut logic)?; process_command_line(SQLiteConnectionFactory::in_memory(), &m, &mut logic)?;
assert_eq!(logic.list_user_count, 1); assert_eq!(logic.list_user_count, 1);
Ok(()) Ok(())
@@ -458,7 +456,6 @@ mod cli_test {
let cmd = command_line_parser(); let cmd = command_line_parser();
let m = cmd.get_matches_from(vec!["test", "securities", "ls"]); let m = cmd.get_matches_from(vec!["test", "securities", "ls"]);
let mut logic = TestCommandLineLogic::new(); let mut logic = TestCommandLineLogic::new();
let mut conn = Connection::open_in_memory().unwrap();
process_command_line(SQLiteConnectionFactory::in_memory(), &m, &mut logic)?; process_command_line(SQLiteConnectionFactory::in_memory(), &m, &mut logic)?;
assert_eq!(logic.list_securities_count, 1); assert_eq!(logic.list_securities_count, 1);
Ok(()) Ok(())
@@ -469,7 +466,6 @@ mod cli_test {
let cmd = command_line_parser(); let cmd = command_line_parser();
let m = cmd.get_matches_from(vec!["test", "events", "process", "/dev/null"]); let m = cmd.get_matches_from(vec!["test", "events", "process", "/dev/null"]);
let mut logic = TestCommandLineLogic::new(); let mut logic = TestCommandLineLogic::new();
let mut conn = Connection::open_in_memory().unwrap();
process_command_line(SQLiteConnectionFactory::in_memory(), &m, &mut logic)?; process_command_line(SQLiteConnectionFactory::in_memory(), &m, &mut logic)?;
assert_eq!(logic.process_events_count, 1); assert_eq!(logic.process_events_count, 1);
Ok(()) Ok(())
@@ -480,7 +476,6 @@ mod cli_test {
let cmd = command_line_parser(); let cmd = command_line_parser();
let m = cmd.get_matches_from(vec!["test", "wui", "run"]); let m = cmd.get_matches_from(vec!["test", "wui", "run"]);
let mut logic = TestCommandLineLogic::new(); let mut logic = TestCommandLineLogic::new();
let mut conn = Connection::open_in_memory().unwrap();
process_command_line(SQLiteConnectionFactory::in_memory(), &m, &mut logic)?; process_command_line(SQLiteConnectionFactory::in_memory(), &m, &mut logic)?;
assert_eq!(logic.run_webui_count, 1); assert_eq!(logic.run_webui_count, 1);
Ok(()) Ok(())
@@ -523,8 +518,8 @@ impl CommandLineUserLogic for ProCommandLineLogic {
fn process_events( fn process_events(
&mut self, &mut self,
conn: &mut Connection, _conn: &mut Connection,
files: ValuesRef<PathBuf>, _files: ValuesRef<PathBuf>,
) -> CustomResult<()> { ) -> CustomResult<()> {
// process_event_files(conn, files) // process_event_files(conn, files)
Ok(()) Ok(())
+1 -1
View File
@@ -29,7 +29,7 @@ impl SessionService {
} }
fn _decrypt_cookie(&self, cookie: Cookie<'static>) -> Option<Cookie> { fn _decrypt_cookie(&self, cookie: Cookie<'static>) -> Option<Cookie> {
let mut jar = CookieJar::new(); let jar = CookieJar::new();
jar.private(&self.key).decrypt(cookie) jar.private(&self.key).decrypt(cookie)
} }
+1 -1
View File
@@ -2,7 +2,7 @@ use rusqlite::Connection;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
use crate::db::external_id::UserId;
use crate::db::users::{list_users, User}; use crate::db::users::{list_users, User};
use crate::util::CustomResult; use crate::util::CustomResult;
+1 -1
View File
@@ -1,4 +1,4 @@
use crate::{CustomResult, Error}; use crate::{CustomResult};
use rusqlite::Connection; use rusqlite::Connection;
pub use crate::services::_authentication::SessionService; pub use crate::services::_authentication::SessionService;
+8 -8
View File
@@ -1,18 +1,18 @@
use actix_web::{web, HttpRequest, Responder}; use actix_web::{web, HttpRequest, Responder};
use cookie::time::macros::datetime;
use cookie::time::OffsetDateTime;
use cookie::{Cookie, CookieJar, Key};
use std::time::Instant;
use crate::db::external_id::UserId;
use crate::services::ReadOnlyServiceFactory; use crate::services::ReadOnlyServiceFactory;
use crate::webui::MiniJinjaRenderer; use crate::webui::templates::MiniJinjaRenderer;
use crate::SQLiteConnectionFactory; use crate::SQLiteConnectionFactory;
use minijinja::context; use minijinja::context;
use serde::Deserialize; use serde::Deserialize;
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
struct LoginPayload { pub struct LoginPayload {
username: String, username: String,
password: String, password: String,
} }
@@ -30,7 +30,7 @@ pub async fn login(
let ctx = context! { let ctx = context! {
name => form.username, name => form.username,
}; };
let mut ret = tmpl_env let ret = tmpl_env
.render("partials/index/success.html", ctx)? .render("partials/index/success.html", ctx)?
.customize(); .customize();
Ok(ret.insert_header(("Set-Cookie", cookie.to_string()))) Ok(ret.insert_header(("Set-Cookie", cookie.to_string())))
+7 -46
View File
@@ -1,65 +1,30 @@
#![feature(future_join)]
use std::{env, path::PathBuf}; use std::{env, path::PathBuf};
use actix_files; use actix_files;
use actix_web::{ use actix_web::{
dev::ServiceResponse, dev::ServiceResponse,
error,
http::{header::ContentType, StatusCode}, http::{header::ContentType, StatusCode},
middleware::{ErrorHandlerResponse, ErrorHandlers, Logger}, middleware::{ErrorHandlerResponse, ErrorHandlers, Logger},
web, App, FromRequest, HttpRequest, HttpResponse, HttpServer, Responder, Result, Scope, web, App, FromRequest, HttpResponse, HttpServer, Responder, Result, Scope,
}; };
use actix_web_lab::respond::Html;
use async_channel; use async_channel;
use futures::{pin_mut, select, FutureExt}; use futures::{pin_mut, select, FutureExt};
use minijinja; use minijinja;
use minijinja_autoreload::AutoReloader; use minijinja_autoreload::AutoReloader;
use rusqlite::Connection;
use crate::events::Event; use crate::events::Event;
use crate::util::{CustomResult, Error, SQLiteConnectionFactory}; use crate::util::{CustomResult, Error, SQLiteConnectionFactory};
use crate::webui::templates::MiniJinjaRenderer;
use crate::webui::worker::event_processor_loop; use crate::webui::worker::event_processor_loop;
mod index_views; mod index_views;
mod services; mod services;
mod templates;
mod views; mod views;
mod worker; mod worker;
struct MiniJinjaRenderer {
tmpl_env: web::Data<minijinja_autoreload::AutoReloader>,
}
impl MiniJinjaRenderer {
fn render(&self, tmpl: &str, ctx: impl Into<minijinja::value::Value>) -> Result<Html> {
log::info!("Rendering template {:?}", tmpl);
self.tmpl_env
.acquire_env()
.map_err(|_| error::ErrorInternalServerError("could not acquire template env"))?
.get_template(tmpl)
.map_err(|e| error::ErrorInternalServerError(format!("{:?}", e)))?
.render(ctx.into())
.map(Html)
.map_err(|err| {
log::error!("{err}");
error::ErrorInternalServerError("template error")
})
}
}
impl FromRequest for MiniJinjaRenderer {
type Error = actix_web::Error;
type Future = actix_utils::future::Ready<Result<Self, Self::Error>>;
fn from_request(req: &HttpRequest, _pl: &mut actix_web::dev::Payload) -> Self::Future {
let tmpl_env = <web::Data<minijinja_autoreload::AutoReloader>>::extract(req)
.into_inner()
.unwrap();
actix_utils::future::ready(Ok(Self { tmpl_env }))
}
}
fn create_auto_reloader(enable_template_autoreload: bool) -> AutoReloader { fn create_auto_reloader(enable_template_autoreload: bool) -> AutoReloader {
AutoReloader::new(move |notifier| { AutoReloader::new(move |notifier| {
let mut env: minijinja::Environment<'static> = minijinja::Environment::new(); let mut env: minijinja::Environment<'static> = minijinja::Environment::new();
@@ -102,21 +67,17 @@ pub async fn web_ui_main(
port: u16, port: u16,
enable_template_autoreload: bool, enable_template_autoreload: bool,
) -> CustomResult<()> { ) -> CustomResult<()> {
// The closure is invoked every time the environment is outdated to recreate it.
let tmpl_reloader = create_auto_reloader(enable_template_autoreload);
let (event_sender, event_receiver) = async_channel::unbounded::<Event>(); let (event_sender, event_receiver) = async_channel::unbounded::<Event>();
let tmpl_reloader = web::Data::new(tmpl_reloader);
// use r2d2 for connection pools (https://github.com/sfackler/r2d2 & // use r2d2 for connection pools (https://github.com/sfackler/r2d2 &
// https://github.com/ivanceras/r2d2-sqlite) use // https://github.com/ivanceras/r2d2-sqlite) use
// https://docs.rs/actix-web/4.3.1/actix_web/web/fn.block.html // https://docs.rs/actix-web/4.3.1/actix_web/web/fn.block.html
// in handlers. // in handlers.
let cloned_conn_fact = conn_fact.clone(); let cloned_conn_fact = conn_fact.clone();
let server = HttpServer::new(move || { let server = HttpServer::new(move || {
let template_reloader = create_auto_reloader(enable_template_autoreload);
App::new() App::new()
.app_data(tmpl_reloader.clone()) .app_data(web::Data::new(template_reloader))
.app_data(web::Data::new(event_sender.clone())) .app_data(web::Data::new(event_sender.clone()))
.app_data(web::Data::new(cloned_conn_fact.clone())) .app_data(web::Data::new(cloned_conn_fact.clone()))
.service(create_static_scope()) .service(create_static_scope())
+2 -2
View File
@@ -1,5 +1,5 @@
use crate::services::{ReadOnlyServiceFactory, SessionService, UserService}; use crate::services::{SessionService};
use crate::util::{CustomResult, Error, SQLiteConnectionFactory}; use crate::util::{SQLiteConnectionFactory};
struct ServicesCache { struct ServicesCache {
session_service: SessionService, session_service: SessionService,
+36
View File
@@ -0,0 +1,36 @@
use actix_web::{error, web, FromRequest, HttpRequest, Result};
use actix_web_lab::respond::Html;
pub struct MiniJinjaRenderer {
tmpl_env: web::Data<minijinja_autoreload::AutoReloader>,
}
impl MiniJinjaRenderer {
pub fn render(&self, tmpl: &str, ctx: impl Into<minijinja::value::Value>) -> Result<Html> {
log::info!("Rendering template {:?}", tmpl);
self.tmpl_env
.acquire_env()
.map_err(|_| error::ErrorInternalServerError("could not acquire template env"))?
.get_template(tmpl)
.map_err(|e| error::ErrorInternalServerError(format!("{:?}", e)))?
.render(ctx.into())
.map(Html)
.map_err(|err| {
log::error!("{err}");
error::ErrorInternalServerError("template error")
})
}
}
impl FromRequest for MiniJinjaRenderer {
type Error = actix_web::Error;
type Future = actix_utils::future::Ready<Result<Self, Self::Error>>;
fn from_request(req: &HttpRequest, _pl: &mut actix_web::dev::Payload) -> Self::Future {
let tmpl_env = <web::Data<minijinja_autoreload::AutoReloader>>::extract(req)
.into_inner()
.unwrap();
actix_utils::future::ready(Ok(Self { tmpl_env }))
}
}
+4 -5
View File
@@ -1,17 +1,16 @@
use std::collections::HashMap; use std::collections::HashMap;
use actix_web::{error, web, HttpRequest, Responder}; use actix_web::{error, web, HttpRequest, Responder};
use actix_web_lab::__reexports::futures_util::SinkExt;
use clap::builder::TypedValueParser;
use log::info; use log::info;
use minijinja::context; use minijinja::context;
use serde::Deserialize; use serde::Deserialize;
use crate::db::users::list_users;
use crate::events::Event; use crate::events::Event;
use crate::services::ReadOnlyServiceFactory; use crate::services::ReadOnlyServiceFactory;
use crate::util::SQLiteConnectionFactory; use crate::util::SQLiteConnectionFactory;
use crate::webui::MiniJinjaRenderer; use crate::webui::templates::MiniJinjaRenderer;
#[actix_web::get("/actions")] #[actix_web::get("/actions")]
pub async fn actions(tmpl_env: MiniJinjaRenderer) -> actix_web::Result<impl Responder> { pub async fn actions(tmpl_env: MiniJinjaRenderer) -> actix_web::Result<impl Responder> {
@@ -67,7 +66,7 @@ pub async fn actions_partials(
} }
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug)]
struct CreateEventPayload { pub struct CreateEventPayload {
event: Event, event: Event,
event_type: String, event_type: String,
} }
+4 -4
View File
@@ -1,8 +1,8 @@
use std::io;
use std::time::Duration;
use rusqlite::Connection;
use tokio::time::sleep;
use crate::event_processor::process_event; use crate::event_processor::process_event;
use crate::events::Event; use crate::events::Event;