diff --git a/README.md b/README.md
index 38a037c..f12de3d 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@ nix build
### Building dev environment
-#### For ide
+#### For IDE
```shell
nix build .#development-environment
@@ -18,14 +18,20 @@ nix build .#development-environment
Then, in IntelliJ use `result/bin`
-The rust source must be `/nix/store/pmih7jv9r5xfaif92bza8w05876qvnvc-rust-src/`
+The rust source must be `/nix/store/pmih7jv9r5xfaif92bza8w05876qvnvc-rust-src/` or similar.
-#### For shell
+#### For development shell
```shell
nix develop
```
+#### Init Postgres
+
+```shell
+
+```
+
## Technologies
### Front-end
diff --git a/resources/migrations/sql/create_tables_001.sql b/resources/migrations/sql/create_tables_001.sql
index bba12ff..1db0790 100644
--- a/resources/migrations/sql/create_tables_001.sql
+++ b/resources/migrations/sql/create_tables_001.sql
@@ -80,12 +80,13 @@ CREATE TABLE IF NOT EXISTS accounts
CREATE TABLE IF NOT EXISTS accounts_history
(
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
account_id INTEGER NOT NULL,
account_version INTEGER NOT NULL,
amount INTEGER NOT NULL,
timestamp DATETIME NOT NULL,
FOREIGN KEY (account_id) REFERENCES accounts (id),
- PRIMARY KEY (account_id, account_version)
+ UNIQUE (account_id, account_version)
);
CREATE TABLE IF NOT EXISTS account_user_permissions
diff --git a/resources/templates/account.html b/resources/templates/account.html
index abe7213..db44c09 100644
--- a/resources/templates/account.html
+++ b/resources/templates/account.html
@@ -15,60 +15,34 @@
| Account Type | {{ account.account_type | replace("_", " ") | lower}} |
| Last Update | {{ account.last_update | utc_date }} |
| Security | {{ account.security.symbol }} |
+ | Data |
+ data
+ |
-
+
{% endblock %}
\ No newline at end of file
diff --git a/resources/templates/base.html b/resources/templates/base.html
index 4083a3e..8284c94 100644
--- a/resources/templates/base.html
+++ b/resources/templates/base.html
@@ -18,9 +18,10 @@
{% if script_chart_js %}
-
-
-
+
+
+
+
{% endif %}
diff --git a/resources/templates/partials/actions/create_security.html b/resources/templates/partials/actions/create_security.html
index 86a3b32..459501d 100644
--- a/resources/templates/partials/actions/create_security.html
+++ b/resources/templates/partials/actions/create_security.html
@@ -29,7 +29,6 @@
-
{%include "partials/actions/submit_button.html"%}
diff --git a/src/db/_account_history.rs b/src/db/_account_history.rs
deleted file mode 100644
index 34ce46e..0000000
--- a/src/db/_account_history.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-use rusqlite::{Connection, OptionalExtension, params};
-use crate::db::accounts;
-use crate::db::accounts::Account;
-use crate::db::external_id::AccountId;
-use crate::util::{CustomResult, Error};
-
-pub struct AccountHistory {
- account: Account,
- timestamps: Vec,
- amounts: Vec,
-}
-
-impl AccountHistory {
- pub fn account(&self) -> &Account {
- &self.account
- }
- pub fn timestamps(&self) -> &Vec {
- &self.timestamps
- }
- pub fn amount(&self) -> &Vec {
- &self.amounts
- }
-}
-
-pub fn get_account_history(tx: &Connection, account_id: &AccountId) -> CustomResult {
- let q = "
- SELECT amount, UNIXEPOCH(timestamp) AS timestamp
- FROM accounts_history
- WHERE account_id = ?1
- ORDER BY account_version ASC
- ";
-
- let mut stmt = tx.prepare(q).map_err(Error::SqlError)?;
- let rows = stmt
- .query_map(params![account_id], |row| Ok((row.get("amount")?, row.get("timestamp")?)))
- .optional()
- .map_err(Error::SqlError)?;
-
- let ret: Vec<(i64, i64)> = rows.map(|x|
- x.map(Result::unwrap)
- .collect()).unwrap_or(vec![]);
-
- let account = accounts::get_account_by_id(tx, account_id)?;
- let mut amounts: Vec = ret.iter().map(|r| r.0).collect();
- let mut timestamps: Vec = ret.iter().map(|r| r.1).collect();
- amounts.push(account.amount());
- timestamps.push(account.timestamp());
-
- Ok(AccountHistory{account, timestamps, amounts })
-}
-
-#[cfg(test)]
-mod test_account_history {
- use crate::db::test_utils::setup_basic_environment;
- use crate::migration;
- use crate::util::CustomResult;
- use super::*;
-
- fn setup() -> CustomResult<(Connection, Account)> {
- let mut conn = Connection::open_in_memory().unwrap();
-
- migration::apply_migrations(&mut conn).unwrap();
- let ret = {
- let mut tx = conn.transaction().unwrap();
- let (_, _, accounts) = setup_basic_environment(&mut tx)?;
- tx.commit().unwrap();
- accounts.get(0).unwrap().clone()
- };
- Ok((conn, ret))
- }
-
- #[test]
- fn test_get_account_history_trivial() -> CustomResult<()>{
- let (mut conn, acc) = setup()?;
- let acc_hist = get_account_history(&conn, &acc.id())?;
- assert_eq!(acc_hist.amounts, vec![0, 0]);
- assert_eq!(acc_hist.timestamps.len(), 2);
- assert_eq!(acc_hist.account.label(), "acc1");
- Ok(())
- }
-
- #[test]
- fn test_get_account_history_with_transactions() -> CustomResult<()>{
- let (mut conn, acc) = setup()?;
- {
- let tx = conn.transaction().unwrap();
- accounts::add_to_account(&tx, &acc.id(), 1)?;
- tx.commit().unwrap();
- }
-
- let tx = conn.transaction().unwrap();
- let acc_hist = get_account_history(&tx, &acc.id())?;
- assert_eq!(acc_hist.amounts, vec![0, 1, 1]);
- assert_eq!(acc_hist.timestamps.len(), 3);
- assert_eq!(acc_hist.account.label(), "acc1");
- Ok(())
- }
-
-}
\ No newline at end of file
diff --git a/src/db/_accounts.rs b/src/db/_accounts.rs
index 28cbd50..142306d 100644
--- a/src/db/_accounts.rs
+++ b/src/db/_accounts.rs
@@ -120,7 +120,7 @@ impl Clone for Account {
}
}
#[derive(Debug)]
-struct AccountSnapshot {
+pub struct AccountSnapshot {
amount: i64,
version: i64,
timestamp: i64,
@@ -134,9 +134,18 @@ impl AccountSnapshot {
timestamp: row.get("timestamp")?,
})
}
+ pub fn amount(&self) -> i64 {
+ self.amount
+ }
+ pub fn version(&self) -> i64 {
+ self.version
+ }
+ pub fn timestamp(&self) -> i64 {
+ self.timestamp
+ }
}
-struct AccountHistory {
+pub struct AccountHistory {
id: i64,
security: Security,
account_type: AccountType,
@@ -165,6 +174,15 @@ impl AccountHistory {
snapshots,
})
}
+ pub fn security(&self) -> &Security {
+ &self.security
+ }
+ pub fn account_type(&self) -> &AccountType {
+ &self.account_type
+ }
+ pub fn snapshots(&self) -> &Vec {
+ &self.snapshots
+ }
}
pub fn list_accounts<'a>(conn: &Connection) -> CustomResult> {
@@ -289,7 +307,7 @@ fn create_account(
return get_account_by_id(tx, &id);
}
-fn get_account_history(tx: &Connection, id: &AccountId) -> CustomResult {
+pub fn get_account_history(tx: &Connection, id: &AccountId) -> CustomResult {
let q = "
SELECT account_version,
amount,
@@ -361,7 +379,7 @@ impl AccountChangeReceipt {
fn update_account_history(tx: &Connection, account_id: &AccountId) -> CustomResult<()> {
let q = "
- INSERT INTO accounts_history
+ INSERT INTO accounts_history(account_id, account_version, amount, timestamp)
SELECT id AS account_id,
version AS account_version,
amount,
@@ -630,7 +648,6 @@ mod test_accounts {
let (mut conn, users, secs) = setup();
let sec = secs.get(0).unwrap().id();
let user = users.get(0).unwrap().id();
- // let sec_emitter_acc = create_security_emitter_account(&conn, &sec, &user, & "sec emitter acc".to_string())?;
let checking_account =
create_checking_account(&conn, &sec, &user, &"checking acc".to_string())?;
match add_to_account(&conn, &checking_account.id(), -33) {
diff --git a/src/db/mod.rs b/src/db/mod.rs
index dd02678..0c545f9 100644
--- a/src/db/mod.rs
+++ b/src/db/mod.rs
@@ -6,7 +6,6 @@ mod _ledger_internal;
mod _securities;
mod _test_utils;
mod _users;
-mod _account_history;
pub mod ledger_internal {
pub use super::_ledger_internal::*;
@@ -27,16 +26,7 @@ pub mod users {
}
pub mod accounts {
- pub use super::_accounts::{
- add_to_account, create_checking_account, create_security_emitter_account,
- get_account_by_id, is_owner, list_accounts, Account, AccountChangeReceipt,
- list_user_accounts, AccountType, get_checking_accounts_for_sec_id, get_number_of_accounts,
- get_security_market_cap
- };
-}
-
-pub mod account_history{
- pub use super::_account_history::get_account_history;
+ pub use super::_accounts::*;
}
pub mod cheques {
diff --git a/src/services/_accounts.rs b/src/services/_accounts.rs
index 4ca9070..0358f11 100644
--- a/src/services/_accounts.rs
+++ b/src/services/_accounts.rs
@@ -1,10 +1,10 @@
use rusqlite::Connection;
-use crate::db::accounts::{Account, AccountType, get_checking_accounts_for_sec_id, list_user_accounts};
+use crate::db::accounts::{Account, AccountHistory, AccountType, get_checking_accounts_for_sec_id, list_user_accounts};
use crate::db::external_id::{AccountId, Id, SecurityId, UserId};
use crate::util::{CustomResult, Error};
use serde::Deserialize;
use serde::Serialize;
-use crate::db::{account_history, accounts};
+use crate::db::{accounts};
use crate::db::securities::Security;
use crate::services::_securities::SecurityDTO;
@@ -28,9 +28,32 @@ pub struct AccountDTO {
}
#[derive(Serialize, Debug)]
-pub struct AccountHistoryDTO {
- amounts: Vec,
- timestamps: Vec,
+pub struct AccountSnapshotDTO{
+ amount: i64,
+ timestamp: i64,
+}
+
+#[derive(Serialize, Debug)]
+pub struct AccountHistoryDTO2{
+ id: String,
+ security: SecurityDTO,
+ account_type: String,
+ snapshots: Vec
+}
+
+impl AccountHistoryDTO2 {
+ fn from_entity(entity: &AccountHistory) -> AccountHistoryDTO2{
+ let snapshots = entity.snapshots()
+ .iter()
+ .map(|x| AccountSnapshotDTO{amount: x.amount(), timestamp: x.timestamp() * 1000})
+ .collect();
+ AccountHistoryDTO2{
+ id: entity.id().to_string(),
+ security: SecurityDTO::from_entity(entity.security()),
+ account_type: entity.account_type().to_string(),
+ snapshots
+ }
+ }
}
impl AccountDTO {
@@ -76,14 +99,9 @@ impl AccountService<'_> {
Ok(AccountDTO::from_entity(ret))
}
- pub fn get_account_history_by_id(&self, account_id: &AccountId, user_id: &UserId) -> CustomResult {
- let ac = account_history::get_account_history(self.conn, account_id)?;
- // ret.account()
- let ret = AccountHistoryDTO{
- amounts: ac.amount().clone(),
- timestamps: ac.timestamps().clone(),
- };
- Ok(ret)
+ pub fn get_account_history_by_id_2(&self, account_id: &AccountId, user_id: &UserId) -> CustomResult {
+ let ac = accounts::get_account_history(self.conn, account_id)?;
+ Ok(AccountHistoryDTO2::from_entity(&ac))
}
pub fn get_number_of_accounts(&self, sec_id: &SecurityId) -> CustomResult{
diff --git a/src/services/mod.rs b/src/services/mod.rs
index c18a760..c1712e9 100644
--- a/src/services/mod.rs
+++ b/src/services/mod.rs
@@ -1,7 +1,7 @@
pub use crate::services::_authentication::SessionService;
pub use crate::services::_securities::SecurityService;
pub use crate::services::_users::UserService;
-pub use crate::services::_accounts::AccountService;
+pub use crate::services::_accounts::{AccountService};
pub use crate::services::_transactions::cash_wire_transfer_request;
mod _authentication;
diff --git a/src/webui/data_views.rs b/src/webui/data_views.rs
new file mode 100644
index 0000000..db09982
--- /dev/null
+++ b/src/webui/data_views.rs
@@ -0,0 +1,30 @@
+use crate::db::external_id::{AccountId, Id};
+use crate::webui::services::ServicesFactory;
+use crate::webui::templates::MiniJinjaRenderer;
+use actix_web::{error, web, HttpRequest, Responder, Result};
+use serde::Serialize;
+
+
+struct ResponseData{
+
+}
+
+#[actix_web::get("/data/accounts/{account_id}/amount-history.json")]
+pub async fn get_account_amount_history(
+ account_id: web::Path,
+ req: HttpRequest,
+ service_factory: web::Data,
+) -> Result {
+ let account_id = AccountId::from_string(&account_id.to_string()).unwrap();
+
+ let conn = service_factory.get_connection()?;
+ let auth_service = service_factory.get_authentication_service(&conn)?;
+ let conn = service_factory.get_connection()?;
+ let account_service = service_factory.get_account_service(&conn)?;
+ let user_id = auth_service.get_login(&req).unwrap();
+ let ac = account_service
+ .get_account_history_by_id_2(&account_id, &user_id)
+ .map_err(error::ErrorInternalServerError)?;
+
+ Ok(web::Json(ac))
+}
diff --git a/src/webui/mod.rs b/src/webui/mod.rs
index e62ee0d..76be451 100644
--- a/src/webui/mod.rs
+++ b/src/webui/mod.rs
@@ -28,6 +28,7 @@ mod templates;
mod views;
mod worker;
mod minininja_utils;
+mod data_views;
struct ProductionEventProcessor;
@@ -78,6 +79,7 @@ fn create_views_scope() -> Scope {
.service(views::overview_submit_button)
.service(views::actions_partials)
.service(views::get_accounts_by_security_selectors)
+ .service(data_views::get_account_amount_history)
}
#[tokio::main]
diff --git a/src/webui/views.rs b/src/webui/views.rs
index 45c5f18..29fd41c 100644
--- a/src/webui/views.rs
+++ b/src/webui/views.rs
@@ -46,13 +46,10 @@ pub async fn get_account(tmpl_env: MiniJinjaRenderer,
let ctx = context!{
account => account_service.get_account_by_id(&account_id, &user_id).map_err(error::ErrorInternalServerError)?,
- account_history => account_service.get_account_history_by_id(&account_id, &user_id).map_err(error::ErrorInternalServerError)?
};
tmpl_env.render("account.html", ctx)
}
-
-
#[actix_web::get("/securities")]
pub async fn securities(tmpl_env: MiniJinjaRenderer,
service_factory: web::Data) -> actix_web::Result {
diff --git a/tools/init-dev b/tools/init-dev
new file mode 100755
index 0000000..04a09b4
--- /dev/null
+++ b/tools/init-dev
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+cargo run users new --name didier.amyot@gmail.com --public-key fooof