advotracker-client: more twine adaptions
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
This commit is contained in:
@@ -39,7 +39,8 @@ viperus = { git = "https://github.com/maurocordioli/viperus", features = ["cach
|
|||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
winres = { version = "0.1.11" }
|
winres = { version = "0.1.11" }
|
||||||
twine = { version = "~0.3.8", features = ["serde"] }
|
#twine = { version = "0.3.8" }
|
||||||
|
twine = { path = "../../../twine", features = ["serde"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|||||||
@@ -7,11 +7,11 @@
|
|||||||
|
|
||||||
extern crate winres;
|
extern crate winres;
|
||||||
|
|
||||||
use twine;
|
use twine::build_translations;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
twine::build_translations(&["./src/i18n/localization.ini"], "i18n.rs").unwrap();
|
build_translations(&["./src/i18n/localization.ini"], "i18n.rs").unwrap();
|
||||||
|
|
||||||
if cfg!(target_os = "windows") {
|
if cfg!(target_os = "windows") {
|
||||||
let mut res = winres::WindowsResource::new();
|
let mut res = winres::WindowsResource::new();
|
||||||
|
|||||||
@@ -26,6 +26,9 @@
|
|||||||
//! WIP: provide a workflow image
|
//! WIP: provide a workflow image
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
// i18n: get the macro (t!) accessing translated strings
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/i18n.rs"));
|
||||||
|
|
||||||
// /// The client specific services
|
// /// The client specific services
|
||||||
// pub mod clients;
|
// pub mod clients;
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ use std::env;
|
|||||||
//use std::process;
|
//use std::process;
|
||||||
use substring::Substring;
|
use substring::Substring;
|
||||||
use tracing::{info, trace, Level};
|
use tracing::{info, trace, Level};
|
||||||
use twine::t;
|
|
||||||
|
|
||||||
use orbtk::{
|
use orbtk::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
@@ -30,6 +29,9 @@ use orbtk::theme_fluent::{THEME_FLUENT, THEME_FLUENT_COLORS_DARK, THEME_FLUENT_F
|
|||||||
// The Main view
|
// The Main view
|
||||||
use advotracker_client::widgets::main_view;
|
use advotracker_client::widgets::main_view;
|
||||||
|
|
||||||
|
// get the macro (t!) accessing the internationalization strings
|
||||||
|
include!(concat!(env!("OUT_DIR"), "/i18n.rs"));
|
||||||
|
|
||||||
mod parse_args;
|
mod parse_args;
|
||||||
|
|
||||||
/// define valid environment variables provided via .env files
|
/// define valid environment variables provided via .env files
|
||||||
@@ -37,7 +39,7 @@ mod parse_args;
|
|||||||
/// this is primarily used in testing scenarios (eg. debugging)
|
/// this is primarily used in testing scenarios (eg. debugging)
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct Environment {
|
struct Environment {
|
||||||
lang: String,
|
lang: Lang,
|
||||||
test_lang: String,
|
test_lang: String,
|
||||||
rust_log: String,
|
rust_log: String,
|
||||||
}
|
}
|
||||||
@@ -46,8 +48,8 @@ struct Environment {
|
|||||||
static DEFAULT_DARK_EXT: &str = include_str!("../assets/advotracker/default_dark.ron");
|
static DEFAULT_DARK_EXT: &str = include_str!("../assets/advotracker/default_dark.ron");
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(windows)] {
|
if #[cfg(windows)] {
|
||||||
static FLUENT_DARK_EXT: &str = include_str!("../assets/advotracker/fluent_dark.ron");
|
static FLUENT_DARK_EXT: &str = include_str!("../assets/advotracker/fluent_dark.ron");
|
||||||
static FLUENT_LIGHT_EXT: &str = include_str!("../assets/advotracker/fluent_light.ron");
|
static FLUENT_LIGHT_EXT: &str = include_str!("../assets/advotracker/fluent_light.ron");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,10 +66,10 @@ fn get_lang() -> String {
|
|||||||
// testing environment: read from .env file
|
// testing environment: read from .env file
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
match envy::from_env::<Environment>() {
|
match envy::from_env::<Environment>() {
|
||||||
Ok(environment) => {
|
Ok(environment) => {
|
||||||
if environment.test_lang != lang { lang = environment.test_lang; }
|
if environment.test_lang != lang { lang = environment.test_lang; }
|
||||||
},
|
},
|
||||||
Err(e) => { info!(target: "advotracker", "{}", e) }
|
Err(e) => { info!(target: "advotracker", "{}", e) }
|
||||||
}
|
}
|
||||||
trace!(target: "advotracker", lang = ?lang);
|
trace!(target: "advotracker", lang = ?lang);
|
||||||
|
|
||||||
@@ -77,38 +79,38 @@ fn get_lang() -> String {
|
|||||||
|
|
||||||
cfg_if! {
|
cfg_if! {
|
||||||
if #[cfg(windows)] {
|
if #[cfg(windows)] {
|
||||||
/// Extend and register theme assets.
|
/// Extend and register theme assets.
|
||||||
fn theme() -> Theme {
|
fn theme() -> Theme {
|
||||||
register_default_fonts(Theme::from_config(
|
register_default_fonts(Theme::from_config(
|
||||||
ThemeConfig::from(DEFAULT_DARK_EXT)
|
ThemeConfig::from(DEFAULT_DARK_EXT)
|
||||||
.extend(ThemeConfig::from(THEME_DEFAULT))
|
.extend(ThemeConfig::from(THEME_DEFAULT))
|
||||||
.extend(ThemeConfig::from(THEME_DEFAULT_COLORS_DARK))
|
.extend(ThemeConfig::from(THEME_DEFAULT_COLORS_DARK))
|
||||||
.extend(ThemeConfig::from(THEME_DEFAULT_FONTS)),
|
.extend(ThemeConfig::from(THEME_DEFAULT_FONTS)),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
fn theme_fluent() -> Theme {
|
fn theme_fluent() -> Theme {
|
||||||
register_fluent_fonts(Theme::from_config(
|
register_fluent_fonts(Theme::from_config(
|
||||||
ThemeConfig::from(FLUENT_DARK_EXT)
|
ThemeConfig::from(FLUENT_DARK_EXT)
|
||||||
.extend(ThemeConfig::from(THEME_FLUENT))
|
.extend(ThemeConfig::from(THEME_FLUENT))
|
||||||
.extend(ThemeConfig::from(THEME_FLUENT_COLORS_DARK))
|
.extend(ThemeConfig::from(THEME_FLUENT_COLORS_DARK))
|
||||||
.extend(ThemeConfig::from(THEME_FLUENT_FONTS)),
|
.extend(ThemeConfig::from(THEME_FLUENT_FONTS)),
|
||||||
))
|
))
|
||||||
// register_fluent_fonts(Theme::from_config(
|
// register_fluent_fonts(Theme::from_config(
|
||||||
// ThemeConfig::from(FLUENT_LIGHT_EXT)
|
// ThemeConfig::from(FLUENT_LIGHT_EXT)
|
||||||
// .extend(ThemeConfig::from(THEME_FLUENT))
|
// .extend(ThemeConfig::from(THEME_FLUENT))
|
||||||
// .extend(ThemeConfig::from(THEME_FLUENT_COLORS_DARK))
|
// .extend(ThemeConfig::from(THEME_FLUENT_COLORS_DARK))
|
||||||
// .extend(ThemeConfig::from(THEME_FLUENT_FONTS)),
|
// .extend(ThemeConfig::from(THEME_FLUENT_FONTS)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/// Extend and register theme assets.
|
/// Extend and register theme assets.
|
||||||
fn theme() -> Theme {
|
fn theme() -> Theme {
|
||||||
register_default_fonts(Theme::from_config(
|
register_default_fonts(Theme::from_config(
|
||||||
ThemeConfig::from(DEFAULT_DARK_EXT)
|
ThemeConfig::from(DEFAULT_DARK_EXT)
|
||||||
.extend(ThemeConfig::from(THEME_DEFAULT))
|
.extend(ThemeConfig::from(THEME_DEFAULT))
|
||||||
.extend(ThemeConfig::from(THEME_DEFAULT_COLORS_DARK))
|
.extend(ThemeConfig::from(THEME_DEFAULT_COLORS_DARK))
|
||||||
.extend(ThemeConfig::from(THEME_DEFAULT_FONTS)),
|
.extend(ThemeConfig::from(THEME_DEFAULT_FONTS)),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,11 +120,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
use viperus::Viperus;
|
use viperus::Viperus;
|
||||||
|
|
||||||
let machine_kind = if cfg!(unix) {
|
let machine_kind = if cfg!(unix) {
|
||||||
"unix"
|
"unix"
|
||||||
} else if cfg!(windows) {
|
} else if cfg!(windows) {
|
||||||
"windows"
|
"windows"
|
||||||
} else {
|
} else {
|
||||||
"unknown/unsupported"
|
"unknown/unsupported"
|
||||||
};
|
};
|
||||||
|
|
||||||
// respect dotenv environment (e.g for testing)
|
// respect dotenv environment (e.g for testing)
|
||||||
@@ -134,81 +136,79 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
// reference: https://tokio.rs/blog/2019-08-tracing/
|
// reference: https://tokio.rs/blog/2019-08-tracing/
|
||||||
let span = tracing::span!(Level::TRACE, "advotracker");
|
let span = tracing::span!(Level::TRACE, "advotracker");
|
||||||
let _enter = span.enter();
|
let _enter = span.enter();
|
||||||
let subscriber = fmt::Subscriber::builder()
|
let collector = fmt::Subscriber::builder()
|
||||||
.with_env_filter(&rust_log)
|
.with_env_filter(&rust_log)
|
||||||
//.with_max_level(tracing::Level::DEBUG)
|
//.with_max_level(tracing::Level::DEBUG)
|
||||||
.finish();
|
.finish();
|
||||||
|
|
||||||
tracing::subscriber::with_default(subscriber, || {
|
tracing::subscriber::with_default(collector, || {
|
||||||
// get system environment
|
// get system environment
|
||||||
let lang = get_lang();
|
//let lang = get_lang();
|
||||||
|
let lang = Lang::De("de");
|
||||||
|
|
||||||
// include localization strings
|
let mut state = t!(state_started => lang);
|
||||||
include!(concat!(env!("OUTDIR"), "/i18n.rs"));
|
let mut res = t!(parse_environment => lang);
|
||||||
|
trace!(target: "advotracker", process = ?res, state = ?state);
|
||||||
|
trace!(target: "advotracker", environment = "system", lang = ?lang);
|
||||||
|
trace!(target: "advotracker", machine = ?&machine_kind);
|
||||||
|
|
||||||
let mut state = t!(state_started => lang);
|
// how to handle unimplemented lang resources??
|
||||||
let mut res = t!(parse_environment => lang);
|
res = t!(parse_environment => lang);
|
||||||
trace!(target: "advotracker", process = ?res, state = ?state);
|
trace!(target: "advotracker", environment = "envy", lang = ?lang);
|
||||||
trace!(target: "advotracker", environment = "system", lang = ?lang);
|
state = t!(state_finished => lang);
|
||||||
trace!(target: "advotracker", machine = ?&machine_kind);
|
trace!(target: "advotracker", process = ?res, state = ?state);
|
||||||
|
|
||||||
// how to handle unimplemented lang resources??
|
// initialize viperus structure
|
||||||
res = t!(parse_environment => lang);
|
let mut viperus = Viperus::new();
|
||||||
trace!(target: "advotracker", environment = "envy", lang = ?lang);
|
|
||||||
state = t!(state_finished => lang);
|
|
||||||
trace!(target: "advotracker", process = ?res, state = ?state);
|
|
||||||
|
|
||||||
// initialize viperus structure
|
// parse commandline arguments
|
||||||
let mut viperus = Viperus::new();
|
res = t!(parse_arguments => lang);
|
||||||
|
state = t!(state_started => lang);
|
||||||
|
trace!(target: "advotracker", process = ?res, state = ?state);
|
||||||
|
|
||||||
// parse commandline arguments
|
let _ = parse_args(&mut viperus);
|
||||||
res = t!(parse_arguments => lang);
|
state = t!(state_finished => lang);
|
||||||
state = t!(state_started => lang);
|
trace!(target: "advotracker", process = ?res, state = ?state);
|
||||||
trace!(target: "advotracker", process = ?res, state = ?state);
|
|
||||||
|
|
||||||
let _ = parse_args(&mut viperus);
|
// type conversion (viperus String -> u64)
|
||||||
state = t!(state_finished => lang);
|
let test_policy_number = viperus.get::<String>("test_policy_number").unwrap().parse::<u64>().unwrap();
|
||||||
trace!(target: "advotracker", process = ?res, state = ?state);
|
trace!(target: "advotracker", test_policy_number = ?test_policy_number);
|
||||||
|
|
||||||
// type conversion (viperus String -> u64)
|
// main tasks
|
||||||
let test_policy_number = viperus.get::<String>("test_policy_number").unwrap().parse::<u64>().unwrap();
|
res = t!(main_started => lang);
|
||||||
trace!(target: "advotracker", test_policy_number = ?test_policy_number);
|
state = t!(state_started => lang);
|
||||||
|
trace!(target: "advotracker", process = ?res, state = ?state);
|
||||||
|
|
||||||
// main tasks
|
// use this only if you want to run it as web application.
|
||||||
res = t!(main_started => lang);
|
orbtk::initialize();
|
||||||
state = t!(state_started => lang);
|
|
||||||
trace!(target: "advotracker", process = ?res, state = ?state);
|
|
||||||
|
|
||||||
// use this only if you want to run it as web application.
|
// Preset localization and language from given environment.
|
||||||
orbtk::initialize();
|
// if no dictionary is set for the chosen default language
|
||||||
|
// the content of the text property will be drawn.
|
||||||
|
let localization = RonLocalization::create()
|
||||||
|
.language("de")
|
||||||
|
.dictionary("de_DE", ADVOTRACKER_DE_DE)
|
||||||
|
.build();
|
||||||
|
|
||||||
// Preset localization and language from given environment.
|
Application::from_name("nwx.advotracker")
|
||||||
// if no dictionary is set for the chosen default language
|
.localization(localization)
|
||||||
// the content of the text property will be drawn.
|
.theme(theme())
|
||||||
let localization = RonLocalization::create()
|
.window(|ctx| {
|
||||||
.language(&lang)
|
Window::new()
|
||||||
.dictionary("de_DE", ADVOTRACKER_DE_DE)
|
.title("AdvoTracker - DirectCall")
|
||||||
.build();
|
.position((500.0, 100.0))
|
||||||
|
.size(800.0, 620.0)
|
||||||
|
//.min_width(460.0)
|
||||||
|
//.min_height(380.0)
|
||||||
|
.resizeable(true)
|
||||||
|
.child(main_view::MainView::new().build(ctx))
|
||||||
|
.build(ctx)
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
|
||||||
Application::from_name("nwx.advotracker")
|
state = t!(state_finished => lang);
|
||||||
.localization(localization)
|
res = t!(main_finished => lang);
|
||||||
.theme(theme())
|
trace!(target: "advotracker", process = ?res, state = ?state);
|
||||||
.window(|ctx| {
|
|
||||||
Window::new()
|
|
||||||
.title("AdvoTracker - DirectCall")
|
|
||||||
.position((500.0, 100.0))
|
|
||||||
.size(800.0, 620.0)
|
|
||||||
//.min_width(460.0)
|
|
||||||
//.min_height(380.0)
|
|
||||||
.resizeable(true)
|
|
||||||
.child(main_view::MainView::new().build(ctx))
|
|
||||||
.build(ctx)
|
|
||||||
})
|
|
||||||
.run();
|
|
||||||
|
|
||||||
state = t!(state_finished => lang);
|
|
||||||
res = t!(main_finished => lang);
|
|
||||||
trace!(target: "advotracker", process = ?res, state = ?state);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -218,6 +218,6 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn it_works() {
|
fn it_works() {
|
||||||
assert_eq!(2 + 2, 4);
|
assert_eq!(2 + 2, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,21 +6,19 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//use chrono::{Local, DateTime};
|
//use chrono::{Local, DateTime};
|
||||||
use locales::t;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
|
use crate::Lang;
|
||||||
|
|
||||||
/// export as csv format
|
/// export as csv format
|
||||||
/// https://docs.rs/csv/1.1.3/csv/cookbook/index.html
|
/// https://docs.rs/csv/1.1.3/csv/cookbook/index.html
|
||||||
/// https://blog.burntsushi.net/csv/
|
/// https://blog.burntsushi.net/csv/
|
||||||
pub fn export(p: &mut String, lang: &str) -> Result<(), Box<dyn Error>> {
|
pub fn export(p: &mut String, lang: &Lang) -> Result<(), Box<dyn Error>> {
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
//use std::ffi::OsStr;
|
//use std::ffi::OsStr;
|
||||||
|
|
||||||
// include localization strings
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/i18n.rs"));
|
|
||||||
|
|
||||||
let mut res = t!(csv_export_started => lang);
|
let mut res = t!(csv_export_started => lang);
|
||||||
let mut state = t!(state_started => lang);
|
let mut state = t!(state_started => lang);
|
||||||
trace!(target: "csv-export", process = ?res, state = ?state);
|
trace!(target: "csv-export", process = ?res, state = ?state);
|
||||||
@@ -33,7 +31,7 @@ pub fn export(p: &mut String, lang: &str) -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
trace!(target: "csv.export", extension = ?path.extension(), file = ?file);
|
trace!(target: "csv.export", extension = ?path.extension(), file = ?file);
|
||||||
state = t!(state_finished => lang);
|
state = t!(state_finished => lang);
|
||||||
res = t!(csv_export_finished", lang);
|
res = t!(csv_export_finished => lang);
|
||||||
trace!(target: "csv-export", process = ?res, state = ?state);
|
trace!(target: "csv-export", process = ?res, state = ?state);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -10,19 +10,18 @@ use lettre::{
|
|||||||
Message, SmtpTransport, Transport,
|
Message, SmtpTransport, Transport,
|
||||||
transport::smtp::authentication::Credentials,
|
transport::smtp::authentication::Credentials,
|
||||||
};
|
};
|
||||||
use locales::t;
|
|
||||||
use maud::html;
|
use maud::html;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
//use std::process;
|
//use std::process;
|
||||||
use tracing::{info, trace};
|
use tracing::{info, trace};
|
||||||
|
|
||||||
use crate::data::structures::Email;
|
use crate::{
|
||||||
|
data::structures::Email,
|
||||||
|
Lang,
|
||||||
|
};
|
||||||
|
|
||||||
/// send ticket data via eMail
|
/// send ticket data via eMail
|
||||||
pub fn sendticketdata(email: &Email, lang: &str) -> Result<(), Box<dyn Error>> {
|
pub fn sendticketdata(email: &Email, lang: &Lang) -> Result<(), Box<dyn Error>> {
|
||||||
// include localization strings
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/i18n.rs"));
|
|
||||||
|
|
||||||
let mut res = t!(sendticketdata_export_started => lang);
|
let mut res = t!(sendticketdata_export_started => lang);
|
||||||
let mut state = t!(state_started =>lang);
|
let mut state = t!(state_started =>lang);
|
||||||
trace!(target: "sendticketdata", process = ?res, state = ?state);
|
trace!(target: "sendticketdata", process = ?res, state = ?state);
|
||||||
@@ -30,67 +29,67 @@ pub fn sendticketdata(email: &Email, lang: &str) -> Result<(), Box<dyn Error>> {
|
|||||||
// The html we want to send.
|
// The html we want to send.
|
||||||
// It uses https://crates.io/crates/maud
|
// It uses https://crates.io/crates/maud
|
||||||
let html = html! {
|
let html = html! {
|
||||||
head {
|
head {
|
||||||
title { (email.subject) " (" (email.policy_code) ")" }
|
title { (email.subject) " (" (email.policy_code) ")" }
|
||||||
style type="text/css" {
|
style type="text/css" {
|
||||||
"h2, h4 { font-family: Arial, Helvetica, sans-serif; }"
|
"h2, h4 { font-family: Arial, Helvetica, sans-serif; }"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
div style="display: flex; flex-direction: column; align-items: left;" {
|
div style="display: flex; flex-direction: column; align-items: left;" {
|
||||||
// compose with variables and strings
|
// compose with variables and strings
|
||||||
h2 { (email.subject) " (" (email.policy_code) ")" }
|
h2 { (email.subject) " (" (email.policy_code) ")" }
|
||||||
p { "Vers.-Schein/Schadennummer: " (email.policy_code) }
|
p { "Vers.-Schein/Schadennummer: " (email.policy_code) }
|
||||||
p { "Versicherungsnehmer: " (email.policy_holder) }
|
p { "Versicherungsnehmer: " (email.policy_holder) }
|
||||||
p { "Selbstbehalt: " (email.deductible) }
|
p { "Selbstbehalt: " (email.deductible) }
|
||||||
p { "Rückrufnummer: " (email.callback_number) }
|
p { "Rückrufnummer: " (email.callback_number) }
|
||||||
p { "Erreichbarkeit: " (email.callback_date) }
|
p { "Erreichbarkeit: " (email.callback_date) }
|
||||||
p { "Rechtsproblem: " (email.harm_type) }
|
p { "Rechtsproblem: " (email.harm_type) }
|
||||||
p { "Rechtsrat: " (email.ivr_comment) }
|
p { "Rechtsrat: " (email.ivr_comment) }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let ascii_body = String::new()
|
let ascii_body = String::new()
|
||||||
+ &"Vers.-Schein/Schadennummer".to_string() + &(email.policy_code) + &"\n"
|
+ &"Vers.-Schein/Schadennummer".to_string() + &(email.policy_code) + &"\n"
|
||||||
+ &"Versicherungsnehmer: ".to_string() + &(email.policy_holder) + &"\n"
|
+ &"Versicherungsnehmer: ".to_string() + &(email.policy_holder) + &"\n"
|
||||||
+ &"Selbstbehalt: ".to_string() + &(email.deductible) + &"\n"
|
+ &"Selbstbehalt: ".to_string() + &(email.deductible) + &"\n"
|
||||||
+ &"Rückrufnummer: ".to_string()+ &(email.callback_number) + &"\n"
|
+ &"Rückrufnummer: ".to_string()+ &(email.callback_number) + &"\n"
|
||||||
+ &"Erreichbarkeit: ".to_string() + &(email.callback_date) + &"\n"
|
+ &"Erreichbarkeit: ".to_string() + &(email.callback_date) + &"\n"
|
||||||
+ &"Rechtsproblem: ".to_string() + &(email.harm_type) + &"\n"
|
+ &"Rechtsproblem: ".to_string() + &(email.harm_type) + &"\n"
|
||||||
+ &"Rechtsrat: ".to_string() + &(email.ivr_comment) + &"\n";
|
+ &"Rechtsrat: ".to_string() + &(email.ivr_comment) + &"\n";
|
||||||
|
|
||||||
info!("email body: {:?}", ascii_body);
|
info!("email body: {:?}", ascii_body);
|
||||||
|
|
||||||
let message = Message::builder()
|
let message = Message::builder()
|
||||||
.from((email.mail_from).parse().unwrap())
|
.from((email.mail_from).parse().unwrap())
|
||||||
.reply_to((email.mail_reply).parse().unwrap())
|
.reply_to((email.mail_reply).parse().unwrap())
|
||||||
.to((email.mail_to).parse().unwrap())
|
.to((email.mail_to).parse().unwrap())
|
||||||
.cc((email.mail_cc).parse().unwrap())
|
.cc((email.mail_cc).parse().unwrap())
|
||||||
// we do not use bcc yet
|
// we do not use bcc yet
|
||||||
//.bcc((email.mail_bcc).parse().unwrap())
|
//.bcc((email.mail_bcc).parse().unwrap())
|
||||||
.subject(String::new()
|
.subject(String::new()
|
||||||
+ &email.subject.to_string()
|
+ &email.subject.to_string()
|
||||||
+ &" (".to_string()
|
+ &" (".to_string()
|
||||||
+ &email.policy_code.to_string()
|
+ &email.policy_code.to_string()
|
||||||
+ &")".to_string()
|
+ &")".to_string()
|
||||||
)
|
)
|
||||||
.multipart(
|
.multipart(
|
||||||
MultiPart::alternative() // This is composed of two parts.
|
MultiPart::alternative() // This is composed of two parts.
|
||||||
.singlepart(
|
.singlepart(
|
||||||
SinglePart::builder()
|
SinglePart::builder()
|
||||||
.header(header::ContentType(
|
.header(header::ContentType(
|
||||||
"text/plain; charset=utf8".parse().unwrap(),
|
"text/plain; charset=utf8".parse().unwrap(),
|
||||||
))
|
))
|
||||||
.body(String::from(ascii_body)),
|
.body(String::from(ascii_body)),
|
||||||
)
|
)
|
||||||
.singlepart(
|
.singlepart(
|
||||||
SinglePart::builder()
|
SinglePart::builder()
|
||||||
.header(header::ContentType(
|
.header(header::ContentType(
|
||||||
"text/html; charset=utf8".parse().unwrap(),
|
"text/html; charset=utf8".parse().unwrap(),
|
||||||
))
|
))
|
||||||
.body(html.into_string()),
|
.body(html.into_string()),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.expect("failed to build email");
|
.expect("failed to build email");
|
||||||
|
|
||||||
|
|
||||||
info!("message: {:?}", message);
|
info!("message: {:?}", message);
|
||||||
@@ -108,9 +107,9 @@ pub fn sendticketdata(email: &Email, lang: &str) -> Result<(), Box<dyn Error>> {
|
|||||||
let relay = "smtp.strato.de";
|
let relay = "smtp.strato.de";
|
||||||
|
|
||||||
let mailer = SmtpTransport::relay(relay)
|
let mailer = SmtpTransport::relay(relay)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.credentials(credentials)
|
.credentials(credentials)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
trace!(target: "sendticketdata", email = ?email);
|
trace!(target: "sendticketdata", email = ?email);
|
||||||
|
|
||||||
|
|||||||
@@ -6,34 +6,32 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
use chrono::{Local, DateTime};
|
use chrono::{Local, DateTime};
|
||||||
use locales::t;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
//use crate::db::redis;
|
//use crate::db::redis;
|
||||||
use crate::data::structures::{PolicyCode, PolicyDataList, PolicyData};
|
use crate::{
|
||||||
//use crate::data::structures::PolicyDataList;
|
data::structures::{PolicyCode, PolicyDataList, PolicyData},
|
||||||
|
Lang,
|
||||||
|
};
|
||||||
|
|
||||||
/// import AllianzDirectCall data from a csv delimeted file
|
/// import AllianzDirectCall data from a csv delimeted file
|
||||||
/// save records to redis backend
|
/// save records to redis backend
|
||||||
/// https://docs.rs/csv/1.1.3/csv/cookbook/index.html
|
/// https://docs.rs/csv/1.1.3/csv/cookbook/index.html
|
||||||
/// https://blog.burntsushi.net/csv/
|
/// https://blog.burntsushi.net/csv/
|
||||||
pub fn import(p: &mut String, data_list: &mut PolicyDataList,
|
pub fn import(p: &mut String, data_list: &mut PolicyDataList,
|
||||||
policy_numbers: &mut HashMap<u64, PolicyCode>,
|
policy_numbers: &mut HashMap<u64, PolicyCode>,
|
||||||
policy_data_count: &mut u64,
|
policy_data_count: &mut u64)
|
||||||
lang: &str)
|
-> Result<(u64, Duration), Box<dyn Error>> {
|
||||||
-> Result<(u64, Duration), Box<dyn Error>> {
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
// include localization strings
|
let lang = Lang::De("");
|
||||||
include!(concat!(env!("OUT_DIR"), "/i18n.rs"));
|
let mut res = t!(csv_import_started => lang);
|
||||||
|
let mut state = t!(state_started => lang);
|
||||||
let mut res = t!("csv.import.started", lang);
|
|
||||||
let mut state = t!("state.started", lang);
|
|
||||||
let time_start = SystemTime::now();
|
let time_start = SystemTime::now();
|
||||||
let datetime: DateTime<Local> = time_start.into();
|
let datetime: DateTime<Local> = time_start.into();
|
||||||
|
|
||||||
@@ -56,45 +54,45 @@ pub fn import(p: &mut String, data_list: &mut PolicyDataList,
|
|||||||
|
|
||||||
// Build the CSV reader
|
// Build the CSV reader
|
||||||
let mut csv_reader = csv::ReaderBuilder::new()
|
let mut csv_reader = csv::ReaderBuilder::new()
|
||||||
.has_headers(true)
|
.has_headers(true)
|
||||||
.delimiter(b' ')
|
.delimiter(b' ')
|
||||||
//.comment(Some(b'#'))
|
//.comment(Some(b'#'))
|
||||||
//.flexible(true)
|
//.flexible(true)
|
||||||
.from_reader(file);
|
.from_reader(file);
|
||||||
{
|
{
|
||||||
// We nest this call in its own scope because of lifetimes.
|
// We nest this call in its own scope because of lifetimes.
|
||||||
let headers = csv_reader.headers()?;
|
let headers = csv_reader.headers()?;
|
||||||
trace!(target: "csv-import", header = ?headers);
|
trace!(target: "csv-import", header = ?headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over each record, deserialize und write to our structures
|
// Iterate over each record, deserialize und write to our structures
|
||||||
let mut count : u64 = 0;
|
let mut count : u64 = 0;
|
||||||
for result in csv_reader.deserialize() {
|
for result in csv_reader.deserialize() {
|
||||||
// The iterator yields Result<StringRecord, Error>, so we check the
|
// The iterator yields Result<StringRecord, Error>, so we check the
|
||||||
// error here.
|
// error here.
|
||||||
let record: PolicyData = result?;
|
let record: PolicyData = result?;
|
||||||
//if verbose > 3 {
|
//if verbose > 3 {
|
||||||
// println!("{:?}", record);
|
// println!("{:?}", record);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// WIP: write to redis backend
|
// WIP: write to redis backend
|
||||||
// for now: append the policy_number to the HashMap
|
// for now: append the policy_number to the HashMap
|
||||||
policy_numbers.insert(record.policy_number, record.policy_code);
|
policy_numbers.insert(record.policy_number, record.policy_code);
|
||||||
|
|
||||||
// push record as new vector elements
|
// push record as new vector elements
|
||||||
data_list.push(record);
|
data_list.push(record);
|
||||||
|
|
||||||
count +=1;
|
count +=1;
|
||||||
*policy_data_count = count;
|
*policy_data_count = count;
|
||||||
};
|
};
|
||||||
|
|
||||||
let time_end = SystemTime::now();
|
let time_end = SystemTime::now();
|
||||||
let duration = time_end.duration_since(time_start)
|
let duration = time_end.duration_since(time_start)
|
||||||
.expect("Clock may have gone backwards");
|
.expect("Clock may have gone backwards");
|
||||||
trace!(target: "csv-import", record_count = ?count, duration = ?duration);
|
trace!(target: "csv-import", record_count = ?count, duration = ?duration);
|
||||||
|
|
||||||
state = t!("state.finished", lang);
|
state = t!(state_finished => lang);
|
||||||
res = t!("csv.import.finished", lang);
|
res = t!(csv_import_finished => lang);
|
||||||
let datetime: DateTime<Local> = time_end.into();
|
let datetime: DateTime<Local> = time_end.into();
|
||||||
trace!(target: "csv-import", process = ?res, state = ?state, date_stop = ?datetime.to_string());
|
trace!(target: "csv-import", process = ?res, state = ?state, date_stop = ?datetime.to_string());
|
||||||
|
|
||||||
@@ -114,23 +112,23 @@ fn test_import() {
|
|||||||
let lang = "en".to_string();
|
let lang = "en".to_string();
|
||||||
|
|
||||||
match import(&mut csv_import_path, &mut policy_data,
|
match import(&mut csv_import_path, &mut policy_data,
|
||||||
&mut policy_numbers, &mut policy_data_count,
|
&mut policy_numbers, &mut policy_data_count,
|
||||||
&lang) {
|
&lang) {
|
||||||
Ok((count, duration)) => {
|
Ok((count, duration)) => {
|
||||||
println!("import {:?} records. Duration: {:?}", count, duration);
|
println!("import {:?} records. Duration: {:?}", count, duration);
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("error running CSV-Import: {}", err);
|
println!("error running CSV-Import: {}", err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
for p in &my_policy_numbers {
|
for p in &my_policy_numbers {
|
||||||
match policy_numbers.get(&p) {
|
match policy_numbers.get(&p) {
|
||||||
Some(policy_code) => {
|
Some(policy_code) => {
|
||||||
println!("Test: Policy-Number {:?} => Policy-Type {:?}, as expected!",
|
println!("Test: Policy-Number {:?} => Policy-Type {:?}, as expected!",
|
||||||
p, policy_code);
|
p, policy_code);
|
||||||
},
|
},
|
||||||
_ => println!("Test: Policy-Number {:?} => not valid, can't dereference the Policy-Type as expected", p),
|
_ => println!("Test: Policy-Number {:?} => not valid, can't dereference the Policy-Type as expected", p),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@ use crate::{
|
|||||||
services::exports::send_ticketdata::sendticketdata,
|
services::exports::send_ticketdata::sendticketdata,
|
||||||
widgets::ticketdata::ticketdata_view::TicketdataView,
|
widgets::ticketdata::ticketdata_view::TicketdataView,
|
||||||
//widgets::policycheck::policycheck_state::PolicycheckAction,
|
//widgets::policycheck::policycheck_state::PolicycheckAction,
|
||||||
|
Lang,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Valid `actions` that are handled as state changes in the `Ticketdata` widget.
|
/// Valid `actions` that are handled as state changes in the `Ticketdata` widget.
|
||||||
@@ -47,7 +48,7 @@ struct Environment {
|
|||||||
pub struct TicketdataState {
|
pub struct TicketdataState {
|
||||||
actions: Vec<TicketdataAction>,
|
actions: Vec<TicketdataAction>,
|
||||||
button_menu: Entity,
|
button_menu: Entity,
|
||||||
lang: String,
|
lang: Lang,
|
||||||
target: Entity
|
target: Entity
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +114,7 @@ impl TicketdataState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn send_form(entity: Entity, ctx: &mut Context<'_>, lang: &str) {
|
pub fn send_form(entity: Entity, ctx: &mut Context<'_>, _lang: Lang) {
|
||||||
info!("TicketdataState: processing entity[{:?}]", entity);
|
info!("TicketdataState: processing entity[{:?}]", entity);
|
||||||
|
|
||||||
let mail_to_index = *TicketdataView::selected_index_ref(&ctx.widget()) as usize;
|
let mail_to_index = *TicketdataView::selected_index_ref(&ctx.widget()) as usize;
|
||||||
@@ -139,6 +140,7 @@ impl TicketdataState {
|
|||||||
trace!("eMail fields: {:?}", email);
|
trace!("eMail fields: {:?}", email);
|
||||||
|
|
||||||
// send email via service
|
// send email via service
|
||||||
|
let lang = Lang::De("");
|
||||||
if let Err(err) = sendticketdata(&email, &lang) {
|
if let Err(err) = sendticketdata(&email, &lang) {
|
||||||
error!("sendticketdata error: {:?}", err);
|
error!("sendticketdata error: {:?}", err);
|
||||||
Button::icon_brush_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), String::from("#008000"));
|
Button::icon_brush_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), String::from("#008000"));
|
||||||
@@ -178,7 +180,8 @@ impl State for TicketdataState {
|
|||||||
.expect("TicketState.init: Can't find resource entity 'target'."));
|
.expect("TicketState.init: Can't find resource entity 'target'."));
|
||||||
|
|
||||||
// Get language from environment
|
// Get language from environment
|
||||||
self.lang = TicketdataState::get_lang();
|
//self.lang = TicketdataState::get_lang();
|
||||||
|
//let self.lang = Lang::De("");
|
||||||
|
|
||||||
Stack::visibility_set(&mut ctx.child(ID_TICKET_DATA_ACTION_STACK), Visibility::Collapsed);
|
Stack::visibility_set(&mut ctx.child(ID_TICKET_DATA_ACTION_STACK), Visibility::Collapsed);
|
||||||
Button::icon_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_CLEAR), material_icons_font::MD_CLEAR);
|
Button::icon_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_CLEAR), material_icons_font::MD_CLEAR);
|
||||||
@@ -203,7 +206,7 @@ impl State for TicketdataState {
|
|||||||
TicketdataState::clear_form(ctx.entity(), &id, ctx);
|
TicketdataState::clear_form(ctx.entity(), &id, ctx);
|
||||||
}
|
}
|
||||||
TicketdataAction::SendForm() => {
|
TicketdataAction::SendForm() => {
|
||||||
TicketdataState::send_form(ctx.entity(), ctx, &self.lang);
|
TicketdataState::send_form(ctx.entity(), ctx, self.lang);
|
||||||
}
|
}
|
||||||
TicketdataAction::UpdatePolicyCode(id) => {
|
TicketdataAction::UpdatePolicyCode(id) => {
|
||||||
TicketdataState::update_policy_code(ctx.entity(), &id, ctx);
|
TicketdataState::update_policy_code(ctx.entity(), &id, ctx);
|
||||||
|
|||||||
Reference in New Issue
Block a user