advotracker-framework: Rename 'frontend' to advotracker

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
This commit is contained in:
2020-06-29 01:13:08 +02:00
parent 0582c1be43
commit b7e6d269dc
74 changed files with 292 additions and 113 deletions

View File

@@ -0,0 +1,7 @@
# set the language variable used in test-runs
#test lang=it
TEST_LANG=en
#RUST_LOG=csv-import=trace
LOG=debug
USERNAME=ralf
DB_DRIVER=sqlite

View File

@@ -0,0 +1,478 @@
use std::collections::HashSet;
use orbtk::prelude::*;
#[derive(Debug, Copy, Clone)]
enum Action {
AddItem,
ClearText,
EntryActivated(Entity),
EntryChanged(Entity),
ValueChanged(Entity),
IncrementCounter,
RemoveItem,
}
#[derive(AsAny)]
pub struct MainViewState {
action: Option<Action>,
}
impl Default for MainViewState {
fn default() -> Self {
MainViewState { action: None }
}
}
impl MainViewState {
fn action(&mut self, action: impl Into<Option<Action>>) {
self.action = action.into();
}
}
impl State for MainViewState {
fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
if let Some(action) = self.action {
match action {
Action::AddItem => {
let len = ctx.widget().get::<List>("list").len();
if len < 5 {
ctx.widget()
.get_mut::<List>("list")
.push(format!("Item {}", len + 1));
ctx.child("items").set("count", len + 1);
ctx.child("remove-item-button").set("enabled", true);
if len == 4 {
ctx.child("add-item-button").set("enabled", false);
}
}
}
Action::RemoveItem => {
let len = ctx.widget().get::<List>("list").len();
if len > 0 {
ctx.widget().get_mut::<List>("list").remove(len - 1);
ctx.child("items").set("count", len - 1);
ctx.child("add-item-button").set("enabled", true);
if len == 1 {
ctx.child("remove-item-button").set("enabled", false);
}
}
}
Action::IncrementCounter => {
*ctx.widget().get_mut::<usize>("counter") += 1;
let counter = *ctx.widget().get::<usize>("counter");
ctx.widget().set(
"result",
String16::from(format!("Button count: {}", counter)),
);
}
Action::ClearText => {
ctx.widget().set("text_one", String16::from(""));
ctx.widget().set("text_two", String16::from(""));
}
Action::EntryActivated(entity) => {
let mut widget = ctx.get_widget(entity);
let text = widget.get_mut::<String16>("text");
println!("submitting {}", text);
text.clear();
}
Action::EntryChanged(entity) => {
let widget = ctx.get_widget(entity);
let text = widget.get::<String16>("text");
println!("entry changed: {}", text);
}
Action::ValueChanged(entity) => {
let val =
((*ctx.get_widget(entity).get::<f64>("val")).floor() as i32).to_string();
ctx.child("value_text").set("text", String16::from(val));
}
}
self.action = None;
}
}
fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
let mut selection_string = "Selected:".to_string();
for index in &ctx.widget().get::<SelectedIndices>("selected_indices").0 {
selection_string = format!("{} {}", selection_string, index);
}
ctx.child("selection")
.set("text", String16::from(selection_string));
}
}
fn create_header(ctx: &mut BuildContext, text: &str) -> Entity {
TextBlock::new()
.text(text)
.element("text-block")
.class("h1")
.build(ctx)
}
type List = Vec<String>;
widget!(
MainView<MainViewState> {
selected_indices: SelectedIndices,
counter: usize,
list_count: usize,
combo_box_list_count: usize,
list: List,
selection_list: List,
combo_box_list: List,
selection_list_count: usize,
text_one: String16,
text_two: String16,
result: String16
}
);
impl Template for MainView {
fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
self.name("MainView")
.result("Button count: 0")
.counter(0)
.selected_indices(HashSet::new())
.list(vec![
"Item 1".to_string(),
"Item 2".to_string(),
"Item 3".to_string(),
])
.list_count(3)
.selection_list(vec![
"Item 1".to_string(),
"Item 2".to_string(),
"Item 3".to_string(),
"Item 4".to_string(),
"Item 5".to_string(),
"Item 6".to_string(),
"Item 7".to_string(),
"Item 8".to_string(),
"Item 9".to_string(),
"Item 10".to_string(),
])
.combo_box_list(vec![
"CB 1".to_string(),
"CB 2".to_string(),
"CB 3".to_string(),
"CB 4".to_string(),
"CB 5".to_string(),
"CB 6".to_string(),
"CB 7".to_string(),
"CB 8".to_string(),
"CB 9".to_string(),
"CB 10".to_string(),
])
.selection_list_count(10)
.combo_box_list_count(10)
.child(
Grid::new()
.margin(8.0)
.columns(
Columns::new()
.add(132.0)
.add(16.0)
.add(132.0)
.add(16.0)
.add(132.0),
)
.child(
Stack::new()
.attach(Grid::column(0))
// Column 0
.child(create_header(ctx, "Buttons"))
.child(
Button::new()
.text("Button")
.margin((0.0, 8.0, 0.0, 0.0))
.icon(material_font_icons::CHECK_FONT_ICON)
.attach(Grid::column(0))
.attach(Grid::row(1))
.on_click(move |states, _| {
state(id, states).action(Action::IncrementCounter);
true
})
.build(ctx),
)
.child(
Button::new()
.text("Primary")
.element("button")
.class("primary")
.margin((0.0, 8.0, 0.0, 0.0))
.icon(material_font_icons::CHECK_FONT_ICON)
.attach(Grid::column(0))
.attach(Grid::row(2))
.build(ctx),
)
.child(
ToggleButton::new()
.class("single_content")
.text("ToggleButton")
.margin((0.0, 8.0, 0.0, 0.0))
.attach(Grid::column(0))
.attach(Grid::row(3))
.build(ctx),
)
.child(
CheckBox::new()
.text("CheckBox")
.margin((0.0, 8.0, 0.0, 0.0))
.attach(Grid::column(0))
.attach(Grid::row(4))
.build(ctx),
)
.child(
Switch::new()
.margin((0.0, 8.0, 0.0, 0.0))
.attach(Grid::column(0))
.attach(Grid::row(5))
.build(ctx),
)
.child(
TextBlock::new()
.margin((0.0, 8.0, 0.0, 0.0))
.element("h1")
.id("value_text")
.text("0")
.h_align("center")
.build(ctx),
)
.child(
Slider::new()
.on_changed(move |states, entity| {
state(id, states).action(Action::ValueChanged(entity));
})
.build(ctx),
)
.build(ctx),
)
.child(
Stack::new()
.attach(Grid::column(2))
.child(create_header(ctx, "Text"))
.child(
TextBlock::new()
.class("body")
.text(("result", id))
.margin((0.0, 8.0, 0.0, 0.0))
.attach(Grid::column(2))
.attach(Grid::row(1))
.build(ctx),
)
.child(
TextBox::new()
.water_mark("TextBox...")
.text(("text_one", id))
.margin((0.0, 8.0, 0.0, 0.0))
.attach(Grid::column(2))
.attach(Grid::row(2))
.on_activate(move |states, entity| {
state(id, states).action(Action::EntryActivated(entity));
})
.on_changed(move |states, entity| {
state(id, states).action(Action::EntryChanged(entity));
})
.build(ctx),
)
.child(
TextBox::new()
.water_mark("TextBox...")
.text(("text_two", id))
.margin((0.0, 8.0, 0.0, 0.0))
.attach(Grid::column(2))
.attach(Grid::row(2))
.on_activate(move |states, entity| {
state(id, states).action(Action::EntryActivated(entity));
})
.on_changed(move |states, entity| {
state(id, states).action(Action::EntryChanged(entity));
})
.build(ctx),
)
.child(
Button::new()
.margin((0.0, 8.0, 0.0, 0.0))
.class("single_content")
.text("clear text")
.on_click(move |states, _| {
state(id, states).action(Action::ClearText);
true
})
.build(ctx),
)
.child(
NumericBox::new()
.margin((0.0, 8.0, 0.0, 0.0))
.max(123.0)
.step(0.123)
.val(0.123)
.build(ctx),
)
.build(ctx),
)
.child(
Grid::new()
.rows(
Rows::new()
.add("auto")
.add(32.0)
.add(16.0)
.add(204.0)
.add("auto")
.add(192.0)
.add("auto"),
)
.columns(Columns::new().add("*").add(4.0).add("*"))
.attach(Grid::column(4))
.child(
TextBlock::new()
.text("Items")
.element("text-block")
.class("h1")
.attach(Grid::column(0))
.attach(Grid::column_span(3))
.attach(Grid::row(0))
.build(ctx),
)
.child(
ComboBox::new()
.items_builder(move |bc, index| {
let text = bc
.get_widget(id)
.get::<Vec<String>>("combo_box_list")[index]
.clone();
TextBlock::new()
.margin((0.0, 0.0, 0.0, 2.0))
.v_align("center")
.text(text)
.build(bc)
})
.selected_index(0)
.attach(Grid::column(0))
.attach(Grid::column_span(3))
.attach(Grid::row(1))
.margin((0.0, 8.0, 0.0, 0.0))
.count(("combo_box_list_count", id))
.build(ctx),
)
.child(
ItemsWidget::new()
.element("items-widget")
.id("items")
.padding((4.0, 4.0, 4.0, 2.0))
.attach(Grid::column(0))
.attach(Grid::column_span(3))
.attach(Grid::row(3))
.margin((0.0, 0.0, 0.0, 8.0))
.items_builder(move |bc, index| {
let text = bc.get_widget(id).get::<Vec<String>>("list")
[index]
.clone();
Button::new()
.margin((0.0, 0.0, 0.0, 2.0))
.text(text)
.build(bc)
})
.count(("list_count", id))
.build(ctx),
)
.child(
Button::new()
.element("button")
.class("single_content")
.id("remove-item-button")
.icon(material_font_icons::MINUS_FONT_ICON)
.on_click(move |states, _| {
state(id, states).action(Action::RemoveItem);
true
})
.min_width(0.0)
.attach(Grid::column(0))
.attach(Grid::row(4))
.build(ctx),
)
.child(
Button::new()
.element("button")
.class("single_content")
.id("add-item-button")
.icon(material_font_icons::ADD_FONT_ICON)
.on_click(move |states, _| {
state(id, states).action(Action::AddItem);
true
})
.min_width(0.0)
.attach(Grid::column(2))
.attach(Grid::row(4))
.build(ctx),
)
.child(
ListView::new()
.attach(Grid::column(0))
.attach(Grid::column_span(3))
.attach(Grid::row(5))
.selected_indices(id)
.margin((0.0, 16.0, 0.0, 8.0))
.items_builder(move |bc, index| {
let text = bc
.get_widget(id)
.get::<Vec<String>>("selection_list")[index]
.clone();
TextBlock::new()
.margin((0.0, 0.0, 0.0, 2.0))
.v_align("center")
.text(text)
.build(bc)
})
.count(("selection_list_count", id))
.build(ctx),
)
.child(
// todo: wrong text width????
TextBlock::new()
.element("text-block")
.id("selection")
.max_width(120.0)
.attach(Grid::column(0))
.attach(Grid::column_span(3))
.attach(Grid::row(6))
.text("Selected:")
.build(ctx),
)
.build(ctx),
)
.build(ctx),
)
}
}
fn main() {
// use this only if you want to run it as web application.
//orbtk::initialize();
Application::new()
.window(|ctx| {
Window::new()
.title("OrbTk - widgets example")
.position((100.0, 100.0))
.size(468.0, 730.0)
.resizeable(true)
.child(MainView::new().build(ctx))
.build(ctx)
})
.run();
}
// helper to request MainViewState
fn state<'a>(id: Entity, states: &'a mut StatesContext) -> &'a mut MainViewState {
states.get_mut(id)
}

View File

@@ -0,0 +1 @@
../../../backend/data/POLLFNR_WOECHENTLICH.txt

View File

@@ -0,0 +1,98 @@
{
"err.lang.not_found": {
"de_DE.UTF-8": "Konnte die Umgebungsvarialbe LANG nicht auslesen",
"de": "Konnte die Umgebungsvarialbe LANG nicht auslesen",
"en": "Couldn't read LANG"
},
"err.user.not_found": {
"fr": "Utilisateur introuvable: $email, $id",
"de-DE.UTF-8": "Anwender nicht gefunden: $email, $id",
"de": "Anwender nicht gefunden: $email, $id",
"en": "User not found: $email, $id"
},
"main.started": {
"de_DE.UTF-8": "Programmlogik starten",
"de": "Programmlogik starten",
"en": "Program logic started"
},
"main.finished": {
"de_DE.UTF-8": "Programmlogik beendet",
"de": "Programmlogik beendet",
"en": "Program logic finished"
},
"parse.arguments": {
"de_DE.UTF-8": "Programmargumente prüfen",
"de": "Programmargumente prüfen",
"en": "Parsing arguments"
},
"parse.environment": {
"de_DE.UTF-8": "Umgebungsvariablen prüfen",
"de": "Umgebungsvariablen prüfen",
"en": "Parsing environment"
},
"parse.results": {
"de_DE.UTF-8": "Ergebnisse der Konfigurations-Parameterprüfung",
"de": "Ergebnisse der Konfigurationsparameterprüfung",
"en": "Config parsing results"
},
"config.name": {
"de_DE.UTF-8": "Konfigurationswert für",
"de": "Konfigurationswert für",
"en": "Config Value for"
},
"config.name.lang": {
"de_DE.UTF-8": "Sprach-Code",
"de": "Sprach-Code",
"en": "Language code"
},
"config.name.verbositylevel": {
"de_DE.UTF-8": "Ausgabe-Ebene",
"de": "Ausgabe-Ebene",
"en": "verbosity level"
},
"config.name.environment": {
"de_DE.UTF-8": "Umgebungsvariablen",
"de": "Umgebungsvariablen",
"en": "environment"
},
"config.name.configfile": {
"de_DE.UTF-8": "Konfigurations-Datei",
"de": "Konfigurations-Datei",
"en": "config file"
},
"config.name.dbdriver": {
"de_DE.UTF-8": "Datenbank-Treiber",
"de": "Datenbank-Treiber",
"en": "database driver"
},
"csv_import.started": {
"de_DE.UTF-8": "importieren von einer csv-datei gestartet",
"de": "importieren von einer csv-datei gestartet",
"en": "import from a csv-file started"
},
"csv_import.finished": {
"de_DE.UTF-8": "importieren von einer csv-datei beendet",
"de": "importieren von einer csv-datei beendet",
"en": "import from a csv-file finished"
},
"csv_export.started": {
"de_DE.UTF-8": "exportieren in eine csv-datei gestartet",
"de": "exportieren in eine csv-datei gestartet",
"en": "export to csv-file started"
},
"csv_export.finished": {
"de_DE.UTF-8": "exportieren in eine csv-datei beendet",
"de": "exportieren in eine csv-datei beendet",
"en": "export to csv-file finished"
},
"state.started": {
"de_DE.UTF-8": "gestartet",
"de": "gestartet",
"en": "started"
},
"state.finished": {
"de_DE.UTF-8": "beendet",
"de": "beended",
"en": "finished"
}
}

View File

@@ -0,0 +1,316 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use chrono::{Local, DateTime};
use locales::t;
//use serde::{Deserialize, Serialize};
use serde::Deserialize;
use std::env;
use std::{error::Error, process};
use tracing::{debug, trace, Level};
use advotracker::data::{PolicyList, PolicyDataList, PolicyData};
// include modules
mod parse_args;
/// respect environment variables set in .env files
/// located in the current call directory
/// this is primarily used in testing scenarios (eg. debugging)
#[derive(Debug, Deserialize)]
struct Environment {
test_lang: String,
log: String,
}
/// export as csv format
/// https://docs.rs/csv/1.1.3/csv/cookbook/index.html
/// https://blog.burntsushi.net/csv/
fn export(p: &mut String, lang: &String) -> Result<usize, Box<dyn Error>> {
use std::fs::File;
use std::path::Path;
//use std::ffi::OsStr;
use std::io::prelude::*;
let mut res = t!("csv_export.started", lang);
let mut state = t!("state.started", lang);
let dt_start: DateTime<Local> = Local::now();
trace!(target: "csv-test",
process = ?res,
state = ?state,
date_start = ?dt_start.to_string());
// Note: slash syntax also works on Windows!
let path = Path::new(p);
// only create files with a '.txt' extensions
//let extension = path.extension();
// match extension {
// //Some(String) => println!("file extension ok!"),
// //_ => extension = OsStr::new("txt")
// _ => println!("got file extension {:?}", extension)
// };
// open the file descriptor
let mut file = File::create(path)?;
trace!(target: "csv-export", extension = ?path.extension(), file = ?file);
// Build the CSV writer and push selected records.
//for result in csv_reader.records() {
let mut count = 0;
file.write_all(b"Allianz DirectCall Protokoll!")?;
count += 1;
let dt_end: DateTime<Local> = Local::now();
let duration = dt_end.signed_duration_since(dt_start);
println!("Duration: {:#?}", duration);
trace!(target: "csv-test", record_count = ?count, duration = ?duration);
state = t!("state.finished", lang);
res = t!("csv_import.finished", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
Ok(count)
}
/// import from csv format
/// https://docs.rs/csv/1.1.3/csv/cookbook/index.html
/// https://blog.burntsushi.net/csv/
fn import(p: &mut String, data_list: &mut PolicyDataList, lang: &String) -> Result<usize, Box<dyn Error>> {
use std::fs::File;
use std::path::Path;
use std::ffi::OsStr;
let mut res = t!("csv_import.started", lang);
let mut state = t!("state.started", lang);
let dt_start: DateTime<Local> = Local::now();
trace!(target: "csv-test",
process = ?res,
state = ?state,
date_start = ?dt_start.to_string());
// Note: slash syntax also workd on Windows!
let path = Path::new(p);
// must be a readable file
trace!(target: "csv-test", path = ?path);
let valid = path.is_file();
println!("is_file: {}", valid);
//if let Some(res) = valid
assert_eq!(path.is_file(), true);
// only accept files with '.txt' extensions
let extension = path.extension();
assert_eq!(extension, Some(OsStr::new("txt")));
// open the file
let file = File::open(path)?;
trace!(target: "csv-test",
extension = ?extension,
file = ?file,
data_list = ?data_list.name);
// Build the CSV reader and iterate over each record.
let mut csv_reader = csv::ReaderBuilder::new()
.has_headers(true)
.delimiter(b' ')
.flexible(true)
//.comment(Some(b'#'))
//.from_reader(io::stdin());
//.from_path(path);
.from_reader(file);
{
// We nest this call in its own scope because of lifetimes.
let headers = csv_reader.headers()?;
trace!(target: "csv-test", header = ?headers);
}
// Deserialize the input data and push result to target vector
let mut count = 0;
for result in csv_reader.deserialize() {
// The iterator yields Result<StringRecord, Error>, so we check the
// error here.
let record: PolicyData = result?;
println!("{:?}", record);
// WIP: write to redis backend
// push record as new vector elements
data_list.push(record);
count +=1;
}
let dt_end: DateTime<Local> = Local::now();
let duration = dt_end.signed_duration_since(dt_start);
println!("Duration: {:#?}", duration);
//let seconds = duration.secs;
//println!("Seconds: {:#?}", seconds);
trace!(target: "csv-test", record_count = ?count, duration = ?duration);
state = t!("state.finished", lang);
res = t!("csv_import.finished", lang);
trace!(target: "csv-test",
process = ?res,
state = ?state,
date_stop = ?dt_end.to_string());
//Ok(count, duration.seconds())
Ok(count)
}
/// validate a given policy number
/// result will return true or false
fn is_valid(policy_number: &usize, policy_list: &PolicyDataList, lang: &String) -> Result<(), Box<dyn std::error::Error>> {
let mut res = t!("policy.validation.started", lang);
let mut state = t!("state.started", lang);
let dt_start: DateTime<Local> = Local::now();
trace!(target: "csv-test",
process = ?res,
state = ?state,
policy_number = ?policy_number,
policy_list = ?policy_list.name,
elements = ?policy_list.policy_data.len(),
date_start = ?dt_start.to_string());
// println!("policy_number: {:?}", policy_number);
// println!("policy_list: {:?} (with {:?} elements)",
// policy_list.name, policy_list.policy_data.len());
let test: Vec<_> = vec!["one", "two", "three"];
let index: usize = test.iter().enumerate().find(|&r| r.1.to_string() == "two".to_string()).unwrap().0;
println!("index: {:?} -> {:?}", index, test[index]);
//let index: usize = test.iter().enumerate().find(|&r| r.policy_number == "two".to_string()).unwrap().0;
let dt_end: DateTime<Local> = Local::now();
let duration = dt_end.signed_duration_since(dt_start);
res = t!("policy.validation.finished", lang);
state = t!("state.finished", lang);
trace!(target: "csv-test",
process = ?res,
state = ?state,
date_stop = ?dt_end.to_string());
trace!(target: "csv-test", duration = ?duration);
Ok(())
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
use dotenv::dotenv;
use parse_args::parse_args;
//use std::process;
//use std::sync::Arc;
use tracing_subscriber::fmt;
use viperus::Viperus;
//static DEFAULT_FILTER: &str = concat!(module_path!(), "=", "trace");
// initialize the tracing subsystem
// a drop in replacement for classical logging
// reference: https://tokio.rs/blog/2019-08-tracing/
let span = tracing::span!(Level::TRACE, "csv-test");
let _enter = span.enter();
let subscriber = fmt::Subscriber::builder()
.with_env_filter("trace")
//.with_max_level(tracing::Level::DEBUG)
.finish();
// initialize logger
//env_logger::init();
//info!("Commencing the import Test-Run!");
tracing::subscriber::with_default(subscriber, || {
// get system environment
let mut lang = env::var("LANG").unwrap_or("en".to_string());
let mut res = t!("parse.environment", lang);
let mut state = t!("state.started", lang);
trace!(target: "csv-test", message = ?res, state = ?state);
//debug!(message = ?res, state = ?state);
trace!(target: "csv-test", environment = "system", lang = ?lang);
// testing environment: read from .env file
dotenv().ok();
match envy::from_env::<Environment>() {
Ok(environment) => {
if environment.test_lang != lang { lang = environment.test_lang; }
},
Err(e) => { debug!(target: "csv-test", "{}", e); }
}
// how to handle unumplemented lang resources??
res = t!("parse.environment", lang);
trace!(target: "csv-test", environment = "envy", lang = ?lang);
state = t!("state.finished", lang);
trace!(target: "csv-test", message = ?res, state = ?state);
// initialize viperus structure
let mut v = Viperus::new();
// parse commandline arguments
res = t!("parse.arguments", lang);
state = t!("state.started", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
let _ = parse_args(&mut v);
state = t!("state.finished", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
//trace!(target: "Viperus", "Config results: {:?}", v);
// main tasks
res = t!("main.started", lang);
state = t!("state.started", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
// importing policy code elements from csv-file
let policy_list = PolicyList::new("Allianz Versicherungsnummen-List");
println!("Policy List {:?} ", policy_list.name);
let mut policy_data = PolicyDataList::new("Allianz-Import 20200628");
println!("Policy Data List {:?} ", policy_data.name);
let mut csv_import_path = v.get::<String>("import_file").unwrap();
match import(&mut csv_import_path, &mut policy_data, &lang) {
Ok(count) => {
println!("Imported {:?} records", count);
}
Err(err) => {
println!("error running Csv-Test: {}", err);
process::exit(1);
}
}
// test if policy_number is_valid
let policy_number : usize = 9999999999;
let _res = is_valid(&policy_number, &policy_data, &lang);
println!("given policy_number {:?} is valid!", policy_number);
// export policy code elements to csv-file
let mut csv_export_path = v.get::<String>("export_file").unwrap();
match export(&mut csv_export_path, &lang) {
Ok(count) => {
println!("Exported {:?} records", count);
}
Err(err) => {
println!("error running CSV-Export: {}", err);
process::exit(1);
}
}
state = t!("state.finished", lang);
res = t!("main.finished", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
});
Ok(())
}

View File

@@ -0,0 +1,203 @@
/// The given Viperus structure will be muted according to the
/// processed default, environment and commandline arguments
// parse CLI commandline arguments with clap
use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
//use log::{debug, info, trace, warn};
use std::env;
use tracing::trace;
use viperus::Viperus;
// Parse the commandline arguments and preset default values
// Precedence: defaults -> config-file -> environment -> commandline
pub fn parse_args(v: &mut Viperus) -> Result<(), Box<dyn std::error::Error>> {
if cfg!(feature = "fmt-clap") {
trace!(target: "Viperus", "Viperus feature 'fmt-clap' enabled.");
println!("Using feature fmt-clap");
}
// preset default key/value pairs (lowest priority)
v.add_default("config_file", String::from("csv_import.ron"));
//v.add_default("import_file", String::from("POLLFNR_WOECHENTLICH.txt"));
v.add_default("import_file", String::from("POLLFNR_TEST.txt"));
v.add_default("export_file", String::from(""));
v.add_default("to_email_address_file", String::from("Allianz RA-Hotline <smr-rahotline@allianz.de>"));
v.add_default("from_email_address_file", String::from("Allianz-Hotline RA-Hiedemann <azhotline@hiedemann.de>"));
//v.add_default("username", String::from("nctalkbot"));
//v.add_default("password", String::from("botpassword"));
v.add_default("verbose", 0);
// CLI arguments are defined inline
let matches = App::new("csv-test")
.name(crate_name!())
.version(crate_version!())
.author(crate_authors!())
.about(crate_description!())
.after_help("
Testprogramm: Allianz Online-Beratung Im/Export CSV-Daten
Direct-Call via IVR-System (Interactive Voice Response)
SMR Deckungssummen-Prüfung: 089 92529 60211
SMR Unerledigt: 089 92529 60222")
.template(
"\
{bin} v{version}
{about}
{all-args}
(C) 2020 {author}
{after-help}",
)
.arg(
Arg::with_name("configFile")
.short("c")
.long("configFile")
.value_name("FILE")
.help("Select a config file")
.default_value("csv_import.ron")
.takes_value(true),
)
.arg(
Arg::with_name("importFile")
.short("i")
.long("importFile")
.help("Select source file for the csv-import")
//.default_value("POLLFNR_WOECHENTLICH.txt")
.default_value("POLLFNR_TEST.txt")
.takes_value(true),
)
.arg(
Arg::with_name("exportFile")
.short("e")
.long("exportFile")
.help("Select target file for the csv-export")
.default_value("RA-Hiedemann_DirectCall.txt")
.takes_value(true),
)
.arg(
Arg::with_name("toEmailAddress")
.short("t")
.long("toEmailAddress")
.help("Select the target email-address (To:)")
.default_value("Allianz RA-Hotline <smr-rahotline@allianz.de>")
.takes_value(true),
)
.arg(
Arg::with_name("fromEmailAddress")
.short("f")
.long("fromEmailAddress")
.help("Select the sender email-address (From:)")
.default_value("Allianz-Hotline RA-Hiedemann <azhotline@hiedemann.de>")
.takes_value(true),
)
// .arg(
// Arg::with_name("username")
// .short("u")
// .long("username")
// .help("Sets username")
// .takes_value(true),
// )
// .arg(
// Arg::with_name("password")
// .short("P")
// .long("password")
// .help("Sets password")
// .takes_value(true),
// )
.arg(
Arg::with_name("verbose")
.short("v")
.long("verbose")
.help("Sets verbosity level")
.multiple(true),
)
.get_matches();
if matches.occurrences_of("verbose") > 0 {
// clap is using i64, viperus i32
let n = matches.occurrences_of("verbose") as i32;
v.add("verbose", n);
}
// preset the prefix for relevant environment variables ("ADVOTRACKER_")
let mut env_prefix: String = crate_name!().to_uppercase();
env_prefix.push_str("_");
v.set_env_prefix(&env_prefix);
// respect dotenv environment (e.g for testing)
// -> overwrites the preset default values
println!(
"RUST_LOG={}",
dotenv::var("RUST_LOG").unwrap_or_else(|_| String::from("None"))
);
// enable caching and automatic update of environment values
if cfg!(feature = "fmt-cache") {
v.cache(true);
}
if cfg!(feature = "fmt-env") {
v.automatic_env(true);
}
// load user selected call arguments
// -> overwrites values given via environment variables
v.load_clap(matches)?;
// bond the clap names to camel_case rust variable names
v.bond_clap("configFile", "config_file");
v.bond_clap("importFile", "import_file");
v.bond_clap("exportFile", "export_file");
v.bond_clap("toEmailAddress", "to_email_address");
v.bond_clap("fromEmailAddress", "from_email_address");
//v.bond_clap("username", "username");
//v.bond_clap("password", "password");
v.bond_clap("verbose", "verbose");
trace!("verbose {:?}", v.get::<i32>("verbose").unwrap());
if v.get::<i32>("verbose").unwrap() > 0 {
println!(
"config_file: {:?}",
v.get::<String>("config_file").unwrap_or_default()
);
println!(
"import_file: {:?}",
v.get::<String>("import_file").unwrap_or_default()
);
println!(
"export_file: {:?}",
v.get::<String>("export_file").unwrap_or_default()
);
println!(
"to_email_address: {:?}",
v.get::<String>("to_email_address").unwrap_or_default()
);
println!(
"from_email_address: {:?}",
v.get::<String>("from_email_address").unwrap_or_default()
);
// println!(
// "username: {:?}",
// v.get::<String>("username").unwrap_or_default()
// );
// println!(
// "password: {:?}",
// v.get::<String>("password").unwrap_or_default()
// ); // only for testing now
println!(
"verbosity level: {:?}",
v.get::<i32>("verbose").unwrap_or_default()
);
}
if v.get::<i32>("verbose").unwrap() > 1 {
println!("\nEnvironment:");
for (key, value) in env::vars() {
println!("{}={}", key, value);
}
}
Ok(())
}

View File

@@ -0,0 +1,37 @@
extern crate pdf_extract;
extern crate lopdf;
use std::env;
use std::path::PathBuf;
use std::path;
use std::io::BufWriter;
use std::fs::File;
use pdf_extract::*;
use lopdf::*;
fn main() {
//let output_kind = "html";
//let output_kind = "txt";
//let output_kind = "svg";
let file = env::args().nth(1).unwrap();
let output_kind = env::args().nth(2).unwrap_or_else(|| "txt".to_owned());
println!("{}", file);
let path = path::Path::new(&file);
let filename = path.file_name().expect("expected a filename");
let mut output_file = PathBuf::new();
output_file.push(filename);
output_file.set_extension(&output_kind);
let mut output_file = BufWriter::new(File::create(output_file).expect("could not create output"));
let doc = Document::load(path).unwrap();
print_metadata(&doc);
let mut output: Box<dyn OutputDev> = match output_kind.as_ref() {
"txt" => Box::new(PlainTextOutput::new(&mut output_file as &mut dyn std::io::Write)),
"html" => Box::new(HTMLOutput::new(&mut output_file)),
"svg" => Box::new(SVGOutput::new(&mut output_file)),
_ => panic!(),
};
output_doc(&doc, output.as_mut());
}

View File

@@ -0,0 +1,235 @@
use orbtk::prelude::*;
use orbtk::theme::DEFAULT_THEME_CSS;
//use orbtk::theme::LIGHT_THEME_EXTENSION_CSS;
//#[cfg(feature = "light-theme")]
static WIDGET_EXT: &'static str = include_str!("../resources/stylesheets/policyholder_check.css");
fn get_theme() -> ThemeValue {
//ThemeValue::create_from_css(LIGHT_THEME_EXTENSION_CSS)
ThemeValue::create_from_css(DEFAULT_THEME_CSS)
.extension_css(WIDGET_EXT)
.build()
}
#[derive(Debug, Copy, Clone)]
enum Action {
ClearText,
EntryActivated(Entity),
EntryChanged(Entity),
//ValueChanged(Entity),
ValueOk,
ValueNone,
}
#[derive(AsAny)]
pub struct MainViewState {
action: Option<Action>,
}
impl Default for MainViewState {
fn default() -> Self {
MainViewState { action: None }
}
}
impl MainViewState {
fn action(&mut self, action: impl Into<Option<Action>>) {
self.action = action.into();
}
}
impl State for MainViewState {
fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
if let Some(action) = self.action {
match action {
Action::ClearText => {
ctx.widget().set("policynumber", String16::from(""));
}
Action::ValueOk => {
//let mut text_box = TextBox::get(ctx.get_widget(entity));
//let text = text_box.text_mut();
//ctx.widget().set("policynumber", background("#4d4c4c"));
}
Action::ValueNone => {
//let mut text_box = TextBox::get(ctx.get_widget(entity));
//let text = text_box.text_mut();
//ctx.widget().set("policynumber", background("#5b0f22"));
}
Action::EntryActivated(entity) => {
let mut text_box = TextBox::get(ctx.get_widget(entity));
let text = text_box.text_mut();
//let mut widget = ctx.get_widget(entity);
//let text = widget.get_mut::<String16>("text");
println!("got value policynumber: {}", text);
//text.clear();
}
Action::EntryChanged(entity) => {
let widget = ctx.get_widget(entity);
let text = widget.get::<String16>("text");
println!("entry changed: {}", text);
}
// Action::ValueChanged(entity) => {
// let val =
// ((*ctx.get_widget(entity).get::<f64>("val")).floor() as i32).to_string();
// ctx.child("value_text").set("text", String16::from(val));
//}
}
self.action = None;
}
}
}
fn create_header(ctx: &mut BuildContext, text: &str) -> Entity {
TextBlock::new()
.text(text)
.element("text-block")
.class("h1")
.build(ctx)
}
widget!(
MainView<MainViewState> {
sum_policynumbers: usize,
policynumber: String16,
result: String16
}
);
impl Template for MainView {
fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
self.name("MainView").child(
//.result("Anzahl Versicherungsnummern: 0")
//.result("Policyholders count: 0").sum_policynumbers(0)
//.sum_policynumbers(0)
Grid::new()
.background("#fafafa")
//.width(200.0)
//.height(360.0)
.columns(
Columns::new()
.add(150.0)
.add("*")
//.add(120.0)
//.add("auto")
.add(150.0)
.build(),
)
.rows(
Rows::new()
.add("*")
.add("*")
.build(),
)
.child(
Grid::new()
.element("policyholder_check")
.margin((4.0, 24.0, 24.0, 4.0))
.min_width(180.0)
.min_height(80.0)
.attach(Grid::column(1))
.attach(Grid::row(0))
.child(
Stack::new()
.spacing(8.0)
.orientation("vertical")
.h_align("center")
//.child(create_header(ctx, "Validation number policyholder"))
.child(create_header(ctx, "Validierung Versicherungsnummer"))
.child(
TextBox::new()
//.class("text_box")
// overwriting the class defaults
/* .background("transparent")
.foreground("#9dafbf")
.background("#fafafa")
/* .foreground(colors::LINK_WATER_COLOR) */
.border_brush("#5b0f22")
.border_width(5)
.border_radius(15) */
//.name("policynumber")
.focused(true)
.water_mark("Versicherungs-Nr...")
//.text("Number policyholder", id)
.text(("policynumber", id))
.font_size(24.0)
.h_align("stretch")
.on_activate(move |states, entity| {
state(id, states).action(Action::EntryActivated(entity));
})
.on_changed(move |states, entity| {
state(id, states).action(Action::EntryChanged(entity));
})
.build(ctx),
)
.child(
TextBlock::new()
.element("text-block")
.id("result")
.min_width(80.0)
.max_width(180.0)
//.text("Result:")
.text("Ergebnis:")
.build(ctx),
)
.build(ctx),
)
.build(ctx)
)
.child(
Grid::new()
.element("logo_customer")
.margin((9.0, 16.0, 16.0, 9.0))
.attach(Grid::column(0))
.attach(Grid::row(1))
.v_align("end")
.child(
ImageWidget::new()
.image("./resources/images/hiedemann_logo.png")
.build(ctx),
)
.build(ctx),
)
.child(
Grid::new()
.element("logo_vendor")
.margin((9.0, 16.0, 16.0, 9.0))
.attach(Grid::column(2))
.attach(Grid::row(1))
.v_align("end")
.child(
ImageWidget::new()
.image("./resources/images/networkx_logo.png")
.build(ctx),
)
.build(ctx),
)
.build(ctx),
) // MainView
}
}
fn main() {
Application::new()
.window(|ctx| {
Window::new()
//.title("OrbTk - Policyholder checker example")
.name("MainWindow")
.title("AdvoTracker - Versicherungsnummern")
.position((-500.0, -100.0))
.size(480.0, 260.0)
.min_width(460.0)
.min_height(180.0)
.resizeable(true)
.theme(get_theme())
.child(MainView::new().build(ctx))
.build(ctx)
})
.run();
}
// helper to request MainViewState
fn state<'a>(id: Entity, states: &'a mut StatesContext) -> &'a mut MainViewState {
states.get_mut(id)
}