diff --git a/resources/templates/components/navbar.html b/resources/templates/components/navbar.html
index e69de29..97e6c3e 100644
--- a/resources/templates/components/navbar.html
+++ b/resources/templates/components/navbar.html
@@ -0,0 +1,16 @@
+
\ No newline at end of file
diff --git a/src/db/_ledger_internal.rs b/src/db/_ledger_internal.rs
index 771dbc8..3957f70 100644
--- a/src/db/_ledger_internal.rs
+++ b/src/db/_ledger_internal.rs
@@ -2,7 +2,7 @@ use rusqlite::{Connection, params, Row, Transaction, Result};
use crate::util::{CustomResult, Error};
use base64::{Engine as _, engine::general_purpose};
-struct LedgerInternal {}
+pub struct LedgerInternal {}
impl LedgerInternal {
pub fn new() -> LedgerInternal {
diff --git a/src/db/mod.rs b/src/db/mod.rs
index d36f072..31672e0 100644
--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -7,6 +7,10 @@ mod _test_utils;
mod _users;
mod _ledger_internal;
+pub mod ledger_internal{
+ pub use super::_ledger_internal::*;
+}
+
pub mod external_id {
pub use super::_external_id::*;
}
diff --git a/src/services/_authentication.rs b/src/services/_authentication.rs
index 4b6829c..b95785e 100644
--- a/src/services/_authentication.rs
+++ b/src/services/_authentication.rs
@@ -1,18 +1,25 @@
use actix_web::HttpRequest;
use cookie::{CookieJar, Cookie, Key};
use cookie::time::OffsetDateTime;
+use rusqlite::Connection;
+use crate::db::ledger_internal::LedgerInternal;
+use crate::{CustomResult, Error};
-struct SessionService {
+pub struct SessionService {
key: Key,
}
+
impl SessionService {
- fn new() -> SessionService{
- let super_secret_not_hardcoded_at_all: [u8; 32] = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1];
- SessionService{key: Key::derive_from(&super_secret_not_hardcoded_at_all)}
+
+ pub fn from_conn(conn: &mut Connection) -> CustomResult
{
+ let tx = conn.transaction().map_err(Error::SqlError)?;
+ let secret = LedgerInternal::new().get_cookie_secret(& tx)?;
+ let ret = SessionService{key: Key::derive_from(&secret)};
+ Ok(ret)
}
- fn create_login_cookie(&self, user_id: &String ) -> Cookie{
+ pub fn create_login_cookie(&self, user_id: &String ) -> Cookie{
let mut jar = CookieJar::new();
jar.private_mut(& self.key).add(Cookie::new("ledger-user-id", user_id.clone()));
jar.get("ledger-user-id").unwrap_or(& Cookie::new("ledger-user-id", "")).clone()
@@ -26,12 +33,12 @@ impl SessionService {
// todo: this service should not be aware of http requests.
// basically, it should be easy to migrate of
// web framework
- fn get_login(&self, req: &HttpRequest) -> Option {
+ pub fn get_login(&self, req: &HttpRequest) -> Option {
req.cookie("ledger-user-id")
.and_then(|c|self._decrypt_cookie(c)).map(|c| c.value().to_string())
}
- fn logout(&self) -> Cookie{
+ pub fn logout(&self) -> Cookie{
let mut cookie = Cookie::new("ledger-user-id", "");
let epoch = OffsetDateTime::from_unix_timestamp_nanos(0).unwrap();
cookie.set_expires(epoch);
diff --git a/src/services/_securities.rs b/src/services/_securities.rs
new file mode 100644
index 0000000..c7b3a4e
--- /dev/null
+++ b/src/services/_securities.rs
@@ -0,0 +1,19 @@
+use rusqlite::{Connection};
+
+pub struct SecurityDTO{
+
+}
+
+pub struct SecurityService<'a> {
+ conn: &'a Connection,
+}
+
+impl SecurityService<'_> {
+ pub fn new(conn: &Connection) -> SecurityService {
+ SecurityService { conn }
+ }
+
+ pub fn list_securities(self) -> Vec {
+ vec![]
+ }
+}
diff --git a/src/services/mod.rs b/src/services/mod.rs
index 5612d62..56c78dd 100644
--- a/src/services/mod.rs
+++ b/src/services/mod.rs
@@ -1,20 +1,30 @@
use rusqlite::Connection;
+use crate::{CustomResult, Error};
-use crate::services::_users::UserService;
+pub use crate::services::_users::UserService;
+pub use crate::services::_authentication::SessionService;
mod _transactions;
mod _users;
mod _authentication;
+mod _securities;
-pub struct ServiceFactory<'a> {
- conn: &'a Connection,
+pub use crate::db::ledger_internal::LedgerInternal;
+
+pub struct ReadOnlyServiceFactory<'a> {
+ conn: &'a mut Connection,
}
-impl ServiceFactory<'_> {
- pub fn new(conn: &Connection) -> ServiceFactory {
- ServiceFactory { conn }
+impl ReadOnlyServiceFactory<'_> {
+ pub fn new(conn: &mut Connection) -> ReadOnlyServiceFactory {
+ ReadOnlyServiceFactory { conn }
}
+
pub fn get_user_service(&self) -> UserService {
UserService::new(self.conn)
}
+
+ pub fn get_authentication_service(&mut self) -> CustomResult {
+ SessionService::from_conn(self.conn)
+ }
}
diff --git a/src/webui/index_views.rs b/src/webui/index_views.rs
index 00a9507..2da599c 100644
--- a/src/webui/index_views.rs
+++ b/src/webui/index_views.rs
@@ -8,6 +8,8 @@ use minijinja::context;
use crate::webui::MiniJinjaRenderer;
use serde::Deserialize;
use crate::db::external_id::UserId;
+use crate::services::ReadOnlyServiceFactory;
+use crate::SQLiteConnectionFactory;
struct SessionService {
key: Key,
@@ -53,14 +55,17 @@ struct LoginPayload {
pub async fn login(
tmpl_env: MiniJinjaRenderer,
web::Json(form): web::Json,
+ conn_factory: web::Data,
) -> actix_web::Result {
+ let mut conn = conn_factory.readonly().unwrap(); // todo; to proper 500
+ let mut service_factory = ReadOnlyServiceFactory::new(&mut conn);
+ let authentication_service = service_factory.get_authentication_service().unwrap();
+ let cookie = authentication_service.create_login_cookie(& form.username);
let ctx = context! {
name => form.username,
};
let mut ret = tmpl_env.render("partials/index/success.html", ctx)?.customize();
- let s = SessionService::new();
- let cookie = s.create_login_cookie(& form.username).to_string();
- Ok(ret.insert_header(("Set-Cookie", cookie)))
+ Ok(ret.insert_header(("Set-Cookie", cookie.to_string())))
}
#[actix_web::post("/logout")]
diff --git a/src/webui/mod.rs b/src/webui/mod.rs
index d448044..5290c0b 100644
--- a/src/webui/mod.rs
+++ b/src/webui/mod.rs
@@ -24,6 +24,7 @@ use crate::webui::worker::{bob, event_processor_loop};
mod views;
mod worker;
mod index_views;
+mod services;
struct MiniJinjaRenderer {
@@ -102,6 +103,7 @@ pub async fn web_ui_main(
.service(index_views::login)
.service(index_views::logout)
.service(views::actions)
+ .service(views::accounts)
.service(views::overview)
.service(views::overview_submit_button)
.service(views::actions_partials)
diff --git a/src/webui/services.rs b/src/webui/services.rs
new file mode 100644
index 0000000..2e05d37
--- /dev/null
+++ b/src/webui/services.rs
@@ -0,0 +1,31 @@
+use crate::util::{CustomResult, Error, SQLiteConnectionFactory};
+use crate::services::{SessionService, ReadOnlyServiceFactory, UserService};
+
+struct ServicesCache {
+ session_service: SessionService,
+}
+
+struct Services {
+ conn_fact: SQLiteConnectionFactory,
+ cache: ServicesCache,
+}
+
+impl Services {
+ pub fn new(conn_fact: SQLiteConnectionFactory) -> Services {
+ let mut tmp_conn = conn_fact.connection().unwrap();
+ let session_service = SessionService::from_conn(&mut tmp_conn).unwrap();
+ let cache = ServicesCache{session_service};
+ Services { conn_fact, cache }
+ }
+
+ pub fn get_authentication_service(& self) -> &SessionService {
+ & self.cache.session_service
+ }
+
+ pub fn get_user_service(&self) -> i32 {
+ // let mut conn = self.conn_fact.readonly().unwrap(); // todo; to proper 500
+ // let service_factory = ReadOnlyServiceFactory::new(&mut conn);
+ // service_factory.get_user_service()
+ 88
+ }
+}
\ No newline at end of file
diff --git a/src/webui/views.rs b/src/webui/views.rs
index 3288c1f..ce0528a 100644
--- a/src/webui/views.rs
+++ b/src/webui/views.rs
@@ -1,6 +1,7 @@
use std::collections::HashMap;
use actix_web::{error, web, HttpRequest, Responder};
+use actix_web_lab::__reexports::futures_util::SinkExt;
use clap::builder::TypedValueParser;
use log::info;
use minijinja::context;
@@ -8,7 +9,7 @@ use serde::Deserialize;
use crate::db::users::list_users;
use crate::events::Event;
-use crate::services::ServiceFactory;
+use crate::services::ReadOnlyServiceFactory;
use crate::util::SQLiteConnectionFactory;
use crate::webui::MiniJinjaRenderer;
@@ -17,13 +18,18 @@ pub async fn actions(tmpl_env: MiniJinjaRenderer) -> actix_web::Result actix_web::Result {
+ tmpl_env.render("accounts.html", ())
+}
+
#[actix_web::get("/overview")]
pub async fn overview(
tmpl_env: MiniJinjaRenderer,
conn_factory: web::Data,
) -> actix_web::Result {
- let conn = conn_factory.readonly().unwrap(); // todo; to proper 500
- let service_factory = ServiceFactory::new(&conn);
+ let mut conn = conn_factory.readonly().unwrap(); // todo; to proper 500
+ let service_factory = ReadOnlyServiceFactory::new(&mut conn);
let user_service = service_factory.get_user_service();
let users = user_service.list_users().unwrap();
let ctx = context! {
diff --git a/tools/run-local b/tools/run-local
new file mode 100755
index 0000000..e4869ce
--- /dev/null
+++ b/tools/run-local
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+exec cargo run -- wui run --port 9999 --enable-template-autoreload
\ No newline at end of file