advotracker: restructure project using crate tree

* advotracker: the framework crate
* crate/advotrackerdb: crate implementing the database backend
* crate/advotrackerd: the backend daemon
* crate/adovtracker: the application (CLI and GUI)

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
This commit is contained in:
2021-03-07 18:38:50 +01:00
parent 1ce1d029e5
commit 4c88167bef
185 changed files with 2542983 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
RUST_LOG=advotracker=info
DATABASE_URL=./advotracker.sqlite3
#DATABASE_URL=postgres://username:password@localhost/advotracker

4
crates/advotrackerdb/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
/target
**/*.rs.bk
*.sqlite3

View File

@@ -0,0 +1,62 @@
[package]
name = "advotracker_db"
version = "0.1.0"
authors = ["Ralf Zerres <ralf.zerres@networkx.de>"]
description = "Advotracker crate implementing Database handling.\n"
readme = "README.md"
license = "(0BSD OR MIT)"
edition = "2018"
#build = "build.rs"
[profile.release]
panic = "abort"
[profile.dev]
rpath = true
[lib]
name = "advotracker_db"
path = "src/lib.rs"
crate-type = ["dylib"]
[[bin]]
name = "get-harms"
path = "src/bin/get-harms.rs"
advotracker_db = { Path="." }
[[bin]]
name = "get-roles"
path = "src/bin/get-roles.rs"
advotracker_db = { Path="." }
[[bin]]
name = "get-users"
path = "src/bin/get-users.rs"
advotracker_db = { Path="." }
[[bin]]
name = "new-role"
path = "src/bin/new-role.rs"
advotracker_db = { Path="." }
[[bin]]
name = "new-harm"
path = "src/bin/new-harm.rs"
advotracker_db = { Path="." }
[[bin]]
name = "new-user"
path = "src/bin/new-user.rs"
advotracker_db = { Path="." }
[dependencies]
lazy_static = "1.0"
bcrypt = { version = "0.8.2" }
chrono = { version = "0.4.15", features = [ "serde" ] }
diesel = { version = "1.4.5", features = [ "sqlite", "chrono" ] }
dotenv = { version = "0.15.0" }
#ldap3 = { version = "0.6" }
serde = { version = "~1.0", features = [ "derive" ] }
#serde_derive = { version = "1.0" }
serde_json = { version = "~1.0" }

View File

@@ -0,0 +1,12 @@
Copyright (C) 2019 by Ralf Zerres <ralf.zerres@networkx.de>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -0,0 +1,19 @@
Copyright (c) 2019 Ralf Zerres <ralf.zerres@networkx.de>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,6 @@
SPDXVersion: SPDX-2.1
DataLicense: CC0-1.0
PackageName: advotracker
PackageOriginator: Ralf Zerres
PackageHomePage: https://github.com/rzerres/advotracker/
PackageLicenseDeclared: MIT, 0BSD

View File

@@ -0,0 +1,169 @@
<!-- README.md -->
<!-- version: 1.0 -->
<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-generate-toc again -->
<!-- markdown-toc end -->
# advotracker - database handling
`advotracker` make use of [Diesel][^1] to handle all SQL access functionality.
Diesel requires to be compiled with Rust version 1.24 or later.
The actual version is tested with the `sqlite3` backend. All following documentation
will reference to this constellation.
# Diesel
First of all, add the required dependencies to the projects Cargo.toml
```bash
[dependencies]
diesel = { version = "1.4.4", features = ["sqlite" "chrono"] }
dotenv = "0.15.0"
```
## CLI helper
Diesel provides a separate CLI tool to help manage the project.
This CLI should be installed on your system. I you don't have that
already available on you system, go and install it like this:
```bash
cargo install diesel_cli
cargo install diesel_cli --no-default-features --features sqlite3
```
## Database Setup
We do uses `sqlite` for now. Use your distro package for sqlite3.
Now direct diesel to the correct database instance. We can create an
environment variable `DATABASE_URL`, that will point to the instance.
For the test setup, we take advantage of an .env file:
```.env
DATABASE_URL=sqlite://localhost/advotracker
#DATABASE_URL=postgres://username:password@localhost/advotracker
```
- **Instantiate a new database**
In the beginning, there is .... nothing!
We will create an empty database to get started:
```bash
$ sqlite3 <absolute_path_to>/advotracker.sqlite3>
sqlite3 advotracker.sqlite3
```
- **Test availability**
Sqlite will drop us in the CLI shell. Try to get available
databases, which should response a `main` pointing to the
absolute path of the created database.
```bash
SQLite version 3.32.3 2020-06-18 14:00:33
Enter ".help" for usage hints.
sqlite> .databases
main: /<the_absolute_path>/advotracker.sqlite3
.quit
```
All fine.
## Diesel Setup
When managing the database schema, probably it will evolve over the time.
Diesel takes that into account and supports a bundles called `Migrations`.
They allow us to define states, that can be applied (up.sql) or reverted (down.sql).
Applying and immediately reverting a migration is a good test, to make sure you
that the used migration leaves your database schema in the requested state.
- **Instantiate a migration**
The following command will crate the basic `advotracker` structure.
```bash
diesel setup
diesel migration generate advotracker
```
You can review the generated structure in the subfolder `migrations`. It
holds a timestamp based subfolder, named `<timestamp-advotracker`, that provides
to empty files. You'll see output that looks something like this:
```bash
Creating migrations/20200625133000_advotracker/up.sql
Creating migrations/20200625133000_advotracker/down.sql
```
- **Update the SQL-files**
Both files have to be updated to meet our target structure. `up.sql` will
create tables, beside their constraints, indices and views. `down.sql` work
delete the database schema providing a virgin state.
If you leave this scripts empty, diesel can't generate the target `schema` file,
that is used to provide the API consumed by you rust code.
You are free to edit and apply this in a manual fashion, but this is not
recommended.
- **Migration run**
We can apply the new migration like this:
```bash
diesel migration run
```
Using the the `redo` command will prove the expected functionality: Run down and
up scrips in a sequence. This will drop the given schema and create a new one using the
adopted files in the migration path.
```bash
diesel migration run
```
- **Test our generated structure**
As a basic success test, we the CLI interface should respond with a list of indices,
if we call a query. Go ahead an run:
```bash
$ sqlite3 <abolute_path_to>/advotracker.sqlite3>
SQLite version 3.32.3 2020-06-18 14:00:33
Enter ".help" for usage hints.
sqlite> .index
claims_ix_id_user
harms_ix_number_harm
sqlite_autoindex___diesel_schema_migrations_1
sqlite_autoindex_roles_1
sqlite_autoindex_user_roles_1
user_roles_ix_id_role
user_roles_ix_id_user
users_ix_email
.quit
```
You are done. The database is ready to be accessed for the
advotracker rust code.
## Reference
Any further information can be obtained from [Diesel's project page][^1].
---
[Logo-CC_BY]: https://i.creativecommons.org/l/by/4.0/88x31.png "Creative Common Logo"
[License-CC_BY]: https://creativecommons.org/licenses/by/4.0/legalcode "Creative Common License"
This work is licensed under a [Creative Common License 4.0][License-CC_BY]
![Creative Common Logo][Logo-CC_BY]
© 2020 Ralf Zerres, Networkx GmbH
---
Footnotes
[^1]: Diesel Guides: https://diesel.rs/guides/getting-started/

View File

@@ -0,0 +1,6 @@
fn main() {
println!("hey cargo");
//println!("cargo:rustc-link-lib=dylib=advotracker_db.so");
println!("cargo:rustc-link-args=-Wl,-rpath=$ORIGIN");
//println!("cargo:rustc-link-search=native=$ORIGIN");
}

View File

@@ -0,0 +1,8 @@
# For documentation on how to configure this file,
# see https://diesel.rs/guides/configuring-diesel-cli
[print_schema]
file = "src/schema.rs"
#filter = { only_tables = [ "User", "UserRole" ] }
# includes the "#![allow(missing_docs)]"
patch_file = "src/missing_docs.patch"

View File

@@ -0,0 +1,17 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: 0BSD
*/
DROP INDEX IF EXISTS NumberHarm_ix_numberHarm;
DROP TABLE IF EXISTS NumberHarm;
DROP INDEX IF EXISTS UserClaim_ix_userId;
DROP TABLE IF EXISTS UserClaim;
DROP VIEW IF EXISTS View_UserRole;
DROP INDEX IF EXISTS UserUserRole_ix_roleId;
DROP INDEX IF EXISTS UserUserRole_ix_userId;
DROP TABLE IF EXISTS UserUserRole;
DROP TABLE IF EXISTS UserRole;
DROP TABLE IF EXISTS User;

View File

@@ -0,0 +1,94 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD, MIT)
*/
-- echo ".read <this_file> |
-- sqlite3 advotracker.db \
CREATE TABLE IF NOT EXISTS claims (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
id_user INTEGER NOT NULL,
type VARCHAR,
value VARCHAR,
date_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
id_user_changed INTEGER NOT NULL,
date_changed TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-- CONSTRAINTS
CONSTRAINT claims_fk_id_user FOREIGN KEY (id_user)
REFERENCES users (id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE INDEX IF NOT EXISTS claims_ix_id_user ON claims (id_user);
CREATE TABLE IF NOT EXISTS harms (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
harm VARCHAR NOT NULL,
policyholder VARCHAR,
number_callback VARCHAR,
deductible VARCHAR,
date_callback TIMESTAMP,
date_recording TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
id_user INTEGER NOT NULL,
date_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
id_user_changed INTEGER NOT NULL,
date_changed TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS harms_ix_number_harm ON harms (id_harm);
CREATE TABLE IF NOT EXISTS roles (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
name VARCHAR NOT NULL,
date_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
id_user_changed INTEGER NOT NULL,
date_changed TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-- Constraints
CONSTRAINT user_roles_uk_name UNIQUE (name)
);
CREATE TABLE IF NOT EXISTS users (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
last_name VARCHAR NOT NULL,
first_name VARCHAR,
alias_name VARCHAR,
email VARCHAR,
/* email_confirmed boolean NOT NULL DEFAULT 0, */
email_confirmed INTEGER,
initials VARCHAR,
password_hash VARCHAR,
date_created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
id_changed Integer NOT NULL,
date_changed TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-- Constraints
CONSTRAINT users_ck_email_confirmed CHECK (email_confirmed IN (0,1))
);
CREATE INDEX IF NOT EXISTS users_ix_email ON users (email);
CREATE TABLE IF NOT EXISTS user_roles (
/* id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, */
id_user INTEGER NOT NULL,
id_role INTEGER NOT NULL,
-- Constraints
CONSTRAINT user_roles_pk_id_user_id_role PRIMARY KEY (id_user, id_role),
CONSTRAINT user_roles_fk_id_user FOREIGN KEY (id_user)
REFERENCES users (id) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT user_roles_fk_id_role FOREIGN KEY (id_role)
REFERENCES roles (id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE INDEX IF NOT EXISTS user_roles_ix_id_user ON user_roles (id_user);
CREATE INDEX IF NOT EXISTS user_roles_ix_id_role ON user_roles (id_role);
CREATE VIEW IF NOT EXISTS view_user_roles
AS SELECT
users.id_user AS id_user,
users.last_name AS last_name,
users.first_name AS first_name,
users.email AS email,
users.user_initials AS initials,
role.user_rolename AS role_name
FROM user_roles
INNER JOIN users ON users.id_user = user_roles.id_user
INNER JOIN roles ON user_roles.id = user_roles.id_role;
-- end

View File

@@ -0,0 +1,22 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
fn main() {
use advotracker_db::functions::db_connection::establish_connection;
use advotracker_db::models::harms::Harm;
let connection = establish_connection();
// function call
let vec_rows = Harm::get_all(&connection);
let rows = vec_rows.iter();
println!("Matching harms (count: {})", rows.len());
for row in rows {
println!("{:?}: {:?} {:?} {:?} {:?}",
row.id, row.id_harm, row.id_policyholder, row.id_callback, row.date_recording);
}
}

View File

@@ -0,0 +1,88 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
fn main() {
use diesel::RunQueryDsl;
use advotracker_db::functions::db_connection::establish_connection;
use advotracker_db::models::roles::Role;
use advotracker_db::schema::roles::dsl::*;
let connection = establish_connection();
// direct diesel method call
match roles
//.filter(name.eq("Administrator"))
.load::<Role>(&connection)
{
Err(err) => println!("{}", err),
Ok(rows) => {
println!("Matching roles (found: {})", rows.len());
//for row in rows {
// println!("{:?}: {:?}", row.id, row.name);
//}
//for field in role_row {
// println!("{}", field.id);
// println!("{}", field.name);
//}
}
}
// function call
let vec_rows = Role::get_all(&connection);
let rows = vec_rows.iter();
println!("Matching roles (count: {})", rows.len());
for row in rows {
println!("{:?}: {:?}", row.id, row.name);
}
// get a specific role, selected by attribute "name"
//let role_name = "Hacker";
let role_name = "Sekretariat";
println!("\nRole details for: {}", role_name);
let row = Role::get(&role_name, &connection).unwrap();
/*let row = match row {
Err(err) => println!("{}", err),
// will return a vector of matching rows
Ok(row) => {
//println!("\nNumber of matching rows: {}", row.len());
println!("Role id: {:?}", row[0].id);
println!("----------");
//println!("row: {:?}", row);
println!("Role name: {:?}", row[0].name);
println!("Role date_created: {:?}", row[0].date_created);
println!("Role updated by: {:?}", row[0].id_user_changed);
println!("Role date_changed: {:?}", row[0].date_changed);
}
};
*/
if row.len() > 0 {
println!("Role name: {:?}", row[0].name);
println!("Role date_created: {:?}", row[0].date_created);
println!("Role updated by: {:?}", row[0].id_user_changed);
println!("Role date_changed: {:?}", row[0].date_changed);
}
/*
// join tables "roles" and "users"
let join = roles::table.left_join(users::table);
// By default, all columns from both tables are selected
let role_struct = join
.select((roles::name, users::full_name.nullable()))
.load::<(String, Option<String>)>(&connection)?;
println!(
"\nRole id: {} (len: {})",
role_struct.name,
role_struct.len()
);
println!("----------\n");
println!("Role name: {}", role_struct.name);
*/
println!("Finish!");
}

View File

@@ -0,0 +1,59 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
fn main() {
use advotracker_db::functions::db_connection::establish_connection;
use advotracker_db::models::users::User;
let connection = establish_connection();
// function call
let vec_rows = User::get_all(&connection);
let rows = vec_rows.iter();
println!("Matching roles (count: {})", rows.len());
for row in rows {
println!("{:?}: {:?} {:?} {:?} {:?}",
row.id, row.last_name, row.first_name, row.email, row.password_hash);
}
/*
use advotracker_database::models::User;
use advotracker_database::schema::users::dsl::*;
let results = users
.load::<User>(&connection)
.expect("Error loading users");
//.filter(email_confirmed.eq(1))
//.limit(5)
//.filter(email_confirmed.eq(Confirmed))
//.limit(5)
println!("Displaying {} users", results.len());
for user in results {
println!("{}", user.id);
println!("----------\n");
println!("{:?}", user.first_name);
println!("{:?}", user.last_name);
println!("{:?}", user.alias);
println!("{:?}", user.email);
}
*/
/*
use advotracker_database::models::Role;
let results = roles
.load::<Role>(&connection)
.expect("Error loading Roles");
println!("Displaying {} roles", results.len());
for role in results {
println!("{}", role.id);
println!("----------\n");
println!("{:?}", role.name);
}
*/
}

View File

@@ -0,0 +1,71 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
fn main() {
use chrono::Local;
use std::io::{stdin, Read};
use advotracker_db::functions::db_connection::*;
use advotracker_db::models::harms::Harm;
let connection = establish_connection();
let number_harm = "123456789";
let number_policyholder = "110-123456789";
let number_callback = "0221 93123456789";
let date_fallback = Local::now().naive_local();
let date_recording = Local::now().naive_local();
// WIP: there is emptyness in the beginning
// how do we make sure, that there is a 'root' user?
// real world: this needs to be the id of the logged in user
let user_id = 1;
//let user_id_changed = 1;
println!("\nOk! I got the following:\nNumber Harm: {}", number_harm);
println!(
"Policyholder: {}, Number callback: {}",
number_policyholder, number_callback
);
println!(
"If correct, let's create this harm '{}'. (Press {} when finished)",
number_harm, EOF
);
let mut body = String::new();
stdin().read_to_string(&mut body).unwrap();
// insert as multicolon
let ret = Harm::new(
&number_harm,
Some(&number_policyholder),
Some(&number_callback),
Some(date_fallback),
date_recording,
user_id,
&connection,
);
println!("\nCreated new harm {}, returns {:?}", number_harm, ret);
// get a given harm
let harm_vec = Harm::get(number_harm, &connection);
println!("\nHarm: {:?}", harm_vec);
//let json = r#"{ "number_harm": "123456789", "number_policyholder": "110-123456789", "number_callback": "0221 92123456789", "user_id": 102, "user_id_changed": 101}"#;
//let json =
// r#"{ "number_harm": "123456789", "number_policyholder": null, "number_callback": null }"#;
//let harm_struct = serde_json::from_str::<NewHarm>(json);
//insert_into(harms).values(&harm_struct).execute(connection);
}
#[cfg(not(windows))]
const EOF: &str = "CTRL+D";
#[cfg(windows)]
const EOF: &str = "CTRL+Z";

View File

@@ -0,0 +1,78 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
fn main() {
use std::io::{stdin, Read};
use advotracker_db::functions::db_connection::*;
use advotracker_db::models::roles::Role;
let connection = establish_connection();
println!("Role name?");
let mut role_name = String::new();
stdin().read_line(&mut role_name).unwrap();
// Drop the newline character form our String slice
let role_name = &role_name[..(role_name.len() - 1)];
// WIP: there is emptyness in the beginning
// how do we make sure, that there is a 'root' user?
// real world: this needs to be the id of the logged in user
let user_id_changed = 1;
println!("\nOk! I got the following:\nRole Name: {}", role_name);
println!(
"If correct, let's create this role {}. (Press {} when finished)",
role_name, EOF
);
let mut body = String::new();
stdin().read_to_string(&mut body).unwrap();
// insert as multicolon
let ret = Role::new(role_name, user_id_changed, &connection);
println!("\nCreated new role {}, returns {:?}", role_name, ret);
// get a given role_name
let role_vec = Role::get(role_name, &connection);
println!("\nRole: {:?}", role_vec);
//println!(
// "\nRole parameter:\nRole name: {}\nUpdated via: {}",
// role_vec.name, role_vec.id_updated
//);
// update a given role_name
//role_id = 2;
//role_name = "New Freelancer";
//role_vec = Role::update(role_id, role_name, &connection);
//println!("\nRole: {:?}", role_vec);
let role_names = ["Administrator", "Rechtsanwalt", "Sekretariat"];
//let roles = role_names.iter();
for role_name in &role_names {
let _ = Role::new(role_name, user_id_changed, &connection);
}
//role_name = "Sekretariat";
//let _ = Role::new(role_name, user_id_changed, &connection);
/*
let inserted_count = insert_into(user_roles)
.values(&vec![
(id.eq(1), name.eq("Rechtsanwalt")),
(id.eq(2), name.eq("Administrator")),
])
.execute(&connection)?;
*/
println!("Saved Role {}", role_name);
}
#[cfg(not(windows))]
const EOF: &str = "CTRL+D";
#[cfg(windows)]
const EOF: &str = "CTRL+Z";

View File

@@ -0,0 +1,180 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
fn main() {
use std::io::{stdin, Read};
use advotracker_db::functions::db_connection::*;
use advotracker_db::models::users::User;
let connection = establish_connection();
/*
println!("Users first name?");
let mut last_name = String::new();
stdin().read_line(&mut last_name).unwrap();
let last_name = &last_name[..(last_name.len() - 1)]; // Drop the newline character
println!("Users last name?");
let mut first_name = String::new();
stdin().read_line(&mut first_name).unwrap();
let first_name = &first_name[..(first_name.len() - 1)];
println!("Users alias?");
let mut alias = String::new();
stdin().read_line(&mut alias).unwrap();
let alias = &alias[..(alias.len() - 1)];
println!("Users email?");
let mut email = String::new();
stdin().read_line(&mut email).unwrap();
let email = &email[..(email.len() - 1)];
let email_confirmed = 0;
println!("Users password?");
let mut password_hash = String::new();
stdin().read_line(&mut password_hash).unwrap();
let password_hash = &password_hash[..(password_hash.len() - 1)];
println!("Users initials?");
let mut initials = String::new();
stdin().read_line(&mut initials).unwrap();
let initials = &initials[..(initials.len() - 1)];
*/
let first_name = "Ralf";
let last_name = "Zerres";
let alias = "ralf.zerres";
let email = "ralf.zerres@networkx.de";
let initials = "rze";
let email_confirmed = 0;
let password_hash = "testrze";
let id_changed = 1;
println!(
"\nOk! I got the following:\nName: {} {}, Alias: {}",
first_name, last_name, alias
);
println!(
"Email-address: {}, Status: {}\nInitials: {}, Password: {}",
email, email_confirmed, initials, password_hash
);
println!(
"If correct, let's create this user {}. (Press {} when finished)",
last_name, EOF
);
let mut body = String::new();
stdin().read_to_string(&mut body).unwrap();
// insert as multicolon
let ret = User::new(
last_name,
Some(first_name),
Some(alias),
Some(email),
Some(email_confirmed),
password_hash,
Some(initials),
//date_create: null,
//date_updated: null,
id_changed,
&connection,
);
println!("\nCreated new user {}, returns {:?}", last_name, ret);
use serde_json::json;
// prepare full record
let _json_record = json!({
"first_name": "Daniela",
"last_name": "Knocke",
"alias": "Sekretariat",
"email": "knocke@kanzlei.hiedemann.de",
"email_confirmed": 1,
"password_hash": "",
"initials": "dkn",
"date_create": null,
"date_updated": null,
"id_changed": 1,
});
// println!(
// "\nCreate user {} via json record:\n{}",
// json_record["last_name"], json_record
// );
// ret = User::set_user_struct_json_option(&connection);
// println!(
// "Created new user {} via json-struct returns {:?}",
// json_record["last_name"], ret
//);
// insert as vector
/*
//connection.test_transaction::<_, Error, _>(|| {
//use diesel::select;
use schema::users::dsl::*;
//let now = select(diesel::dsl::now).get_result::<NaiveDateTime>(&connection);
//let now = select(diesel::dsl::now).get_result::<NaiveDateTime>(&connection);
let inserted_count = insert_into(users)
.values(&vec![
(last_name.eq("Networkx"), first_name.eq("Admin"), alias.eq("Networkx"),
email.eq("support@networkx.de")),
(last_name.eq("Schlömer"), first_name.eq("Lothar"), alias.eq("lothar.schlömer"),
email.eq("schlömer@kanzlei-hiedemann.de")),
])
.execute(&connection);
//});
*/
// Some data structure.
//use advotracker_db::models::users::User;
println!(
"\nCreate new json stuct representing user: {} {}",
first_name, last_name
);
let user = json!({
"first_name": first_name,
"last_name": last_name,
"alias": alias,
"email": email,
//"email_confirmed": 1,
//"password_hash": "",
"initials": initials,
//"date_create": null,
//"date_updated": null,
"id_changed": 1,
});
// Convert to a string of JSON and print it out
println!(
"json stuct representing user: {} {}",
user["last_name"],
user.to_string()
);
// Serialize it to a JSON string.
let json = serde_json::to_string(&user);
// Print, write to a file, or send to an HTTP server.
println!("Serialized output: {:?}", json);
/*
let user_id = 1;
let role_id = 1;
use advotracker_db::functions::roles::*;
let _ = set_user_role(&connection, &user_id, &role_id);
*/
}
#[cfg(not(windows))]
const EOF: &str = "CTRL+D";
#[cfg(windows)]
const EOF: &str = "CTRL+Z";

View File

@@ -0,0 +1,33 @@
// source: https://github.com/inejge/ldap3
//use std::error::Error;
//use ldap3::{LdapConn, Scope, SearchEntry};
fn main() {
println!("search ldap ...");
/*
match do_search() {
Ok(_) => (),
Err(e) => println!("{}", e),
}
}
fn do_search() -> Result<(), Box<dyn Error>> {
println!("do_search ...");
/*
let ldap = LdapConn::new("ldap://localhost:2389")?;
let (rs, _res) = ldap
.search(
"ou=Places,dc=example,dc=org",
Scope::Subtree,
"(&(objectClass=locality)(l=ma*))",
vec!["l"],
)?
.success()?;
for entry in rs {
println!("{:?}", SearchEntry::construct(entry));
}
*/
Ok(())
*/
}

View File

@@ -0,0 +1,42 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2019 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
//use diesel::debug_query;
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;
use diesel::sqlite::Sqlite;
use dotenv::dotenv;
use std::env;
/// establish a sqlite connection
pub fn establish_connection() -> SqliteConnection {
// load our .env file
dotenv().ok();
// set database_url to the given DATABASE_URL env variable
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
// establish a new SQLite connection (taking the reference from database_url)
SqliteConnection::establish(&database_url)
.unwrap_or_else(|_| panic!("Error connecting to {}", &database_url))
/*
* WIP: integrate tracing!
trace!(
target: "diesel",
type: "Sqlite3",
status: "connected"
);
*/
}
/// show the sql query
pub fn show_query<T>(query: &T)
where
T: diesel::query_builder::QueryFragment<Sqlite>,
{
dbg!(diesel::debug_query::<Sqlite, _>(&query));
}

View File

@@ -0,0 +1,196 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2019 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
//#[cfg(test)]
use chrono::{Local, NaiveDateTime};
use diesel;
use diesel::debug_query;
use diesel::dsl::*;
use diesel::prelude::*;
use diesel::sqlite::{Sqlite, SqliteConnection};
use diesel::{QueryDsl, RunQueryDsl};
use std::error::Error;
use crate::models::harms::{Harm, NewHarm};
use crate::schema::harms;
use crate::schema::harms::dsl::*;
use crate::schema::harms::*;
impl Harm {
// implement CRUD-Functions
// new- -> Create
// get- -> Read
// set- -> Update
// remove- -> Delete
/// create a new harm record
pub fn new(
param_id_harm: &str,
param_id_policyholder: Option<&str>,
param_id_callback: Option<&str>,
param_date_fallback: Option<NaiveDateTime>,
param_date_recording: NaiveDateTime,
param_id_user: i32,
connection: &SqliteConnection,
) -> Result<(), Box<dyn Error>> {
let struct_harm = NewHarm {
id_harm: param_id_harm,
id_policyholder: param_id_policyholder,
id_callback: param_id_callback,
date_fallback: param_date_fallback,
date_recording: param_date_recording,
id_user: param_id_user,
date_created: Some(Local::now().naive_local()),
id_user_changed: param_id_user,
date_changed: Some(Local::now().naive_local()),
};
diesel::insert_into(harms::table)
.values(struct_harm)
.execute(connection)?;
Ok(())
}
/*
pub fn delete(param_hame_id: i32, connection: &SqliteConnection) -> Result<(), Box<dyn Error>> {
diesel::delete(dsl::harms.filter(dsl::id.eq(param_role_id)).find(id)).execute(connection)?;
Ok(())
// alternative:
// let old_count = get_count();
// assert_eq!(old_count.map(|count| count - 1), get_count());
}
*/
/// get list of all harm record
pub fn get_all(connection: &SqliteConnection) -> Box<Vec<Harm>> {
Box::new(
harms
.order(harms::id.asc())
.load::<Harm>(connection)
.expect("Error loading harms"),
)
}
/// get harm record
pub fn get(
param_id_harm: &str,
connection: &SqliteConnection,
) -> Result<Vec<Harm>, Box<dyn Error>> {
let query = harms
.filter(id_harm.eq(param_id_harm))
.load::<Harm>(connection)
.expect("Error loading harm");
debug_query::<Sqlite, _>(&query);
Ok(query)
}
/// update harm record
pub fn update(
param_id: i32,
param_id_harm: &str,
connection: &SqliteConnection,
) -> Result<(), Box<dyn Error>> {
let query = diesel::update(harms.filter(id.eq(param_id)))
.set(id_harm.eq(param_id_harm))
.execute(connection);
debug_query::<Sqlite, _>(&query);
Ok(())
}
}
/// set a test harm record
pub fn set_harms_single_column(connection: &SqliteConnection) -> QueryResult<usize> {
insert_into(harms)
.values(id_harm.eq("123456789"))
.execute(connection)
}
#[test]
/// examine the test harm record
fn examine_set_harms_single_column() {
let query = insert_into(harms).values(id_harm.eq("123456789"));
let sql = "INSERT INTO `harms` (`id_harm`) VALUES (?) \
-- binds: [\"123456789\"]";
assert_eq!(sql, debug_query::<Sqlite, _>(&query).to_string());
}
/// set multiple collumns for the test harm record
pub fn set_harms_multi_column(connection: &SqliteConnection) -> QueryResult<usize> {
insert_into(harms)
.values((
id_harm.eq("123456789"),
id_policyholder.eq("110-123456789"),
id_callback.eq("0221 93123456789"),
))
.execute(connection)
}
// #[test]
// fn examine_set_harms_multi_column() {
// let query = insert_into(harms).values((
// id_harm.eq("123456789"),
// id_policyholder.eq("110-123456789"),
// id_callback.eq("0221 93123456789"),
// ));
// let sql = "INSERT INTO `harms` (`id_harm`, `id_policyholder`, `id_callback`) \
// VALUES (?, ?, ?) \
// -- binds: [\"123456789\", \"110-123456789\", \"0221 93123456789\"]";
// assert_eq!(sql, debug_query::<Sqlite, _>(&query).to_string());
// }
// pub fn set_harms_struct_json(connection: &SqliteConnection) -> Result<(), Box<dyn Error>> {
// let json = r#"{ "id_harm": "123456789", "id_policyholder": "110-123456789", "id_callback": "0221 92123456789", "date_recording": "2019-11-16 20:00:15.114957766"}"#;
// //let harm_struct = serde_json::from_str::<NewHarm>(json)?;
// let harm_struct = serde_json::from_str::<'_>(json)?;
// insert_into(harms)
// .values(&harm_struct)
// .execute(connection)?;
// Ok(())
// }
// #[test]
// fn examine_set_harms_struct_json() {
// let json = r#"{ "id_harm": "123456789", "id_policyholder": "110-123456789", "id_callback": "0221 93123456789", "date_recording": "2019-11-19T00:08:00", "id_user": 102, "id_user_changed": 101 }"#;
// let harm_struct = serde_json::from_str::<NewHarm>(json).unwrap();
// let query = insert_into(harms).values(&harm_struct);
// let sql =
// "INSERT INTO `harms` (`id_harm`, `id_policyholder`, `id_callback`, `date_recording`, `id_user`, `id_user_changed`) \
// VALUES (?, ?, ?, ?, ?, ?) \
// -- binds: [\"123456789\", \"110-123456789\", \"0221 93123456789\", 2019-11-19T00:08:00, 102, 101]";
// assert_eq!(sql, debug_query::<Sqlite, _>(&query).to_string());
// }
// pub fn set_harms_struct_json_option(connection: &SqliteConnection) -> Result<(), Box<dyn Error>> {
// let json = r#"{ "id_harm": "123456789", "id_policyholder": null, "id_callback": null, "date_recording": "2019-11-19T00:08:00", 102, 101 }"#;
// let harm_struct = serde_json::from_str::<'_>(json)?;
// insert_into(harms)
// .values(&harm_struct)
// .execute(connection)?;
// Ok(())
// }
// #[test]
// fn examine_set_harms_struct_json_option() {
// let json = r#"{ "id_harm": "123456789", "id_policyholder": null, "id_callback": null, "date_recording": "2019-11-19T00:08:00", "id_user": 102, "id_user_changed": 101 }"#;
// let harm_struct = serde_json::from_str::<NewHarm>(json).unwrap();
// let query = insert_into(harms).values(&harm_struct);
// let sql = "INSERT INTO `harms` (`id_harm`, `date_recording`, `id_user`, `id_user_changed`) \
// VALUES (?, ?, ?, ?) \
// -- binds: [\"123456789\", 2019-11-19T00:08:00, 102, 101]";
// assert_eq!(sql, debug_query::<Sqlite, _>(&query).to_string());
// }

View File

@@ -0,0 +1,25 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2019 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
// table specific functions
/// module handling database connections
pub mod db_connection;
/// module handling harms
pub mod harms;
/// module handling roles
pub mod roles;
/// module handling user roles
pub mod user_roles;
/// module handling users
pub mod users;
/// module handling functionalty tests
pub mod tests;

View File

@@ -0,0 +1,105 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2019 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
//#[cfg(test)]
use chrono::Local;
use diesel::debug_query;
use diesel::prelude::*;
use diesel::sqlite::{Sqlite, SqliteConnection};
use diesel::{QueryDsl, RunQueryDsl};
use std::error::Error;
//use crate::functions::establish_connection;
//use crate::models::roles::{NewRole, Role, RoleList};
use crate::models::roles::{NewRole, Role};
use crate::schema::roles;
use crate::schema::roles::dsl::*;
use crate::schema::roles::*;
impl Role {
// implement CRUD-Functions for our trait
// new- -> Create
// show- -> Read
// update- -> Update
// delete- -> Delete
/// create a new role record
pub fn new(
param_role_name: &str,
param_id_user_changed: i32,
connection: &SqliteConnection,
) -> Result<(), Box<dyn Error>> {
//let row = Self::get(param_role_name, param_user_id_changed, &connection);
//if row.len() == 0 {
// create a new role row
let struct_role = NewRole {
name: param_role_name,
date_created: Some(Local::now().naive_local()),
id_user_changed: param_id_user_changed,
date_changed: Some(Local::now().naive_local()),
};
diesel::insert_into(roles::table)
.values(struct_role)
.execute(connection)?;
Ok(())
//else {
// Err(("row already exists!"))
//}
}
/*
pub fn delete(param_role_id: i32, connection: &SqliteConnection) -> Result<(), Box<dyn Error>> {
diesel::delete(dsl::roles.filter(dsl::id.eq(param_role_id)).find(id)).execute(connection)?;
Ok(())
// alternative:
// let old_count = get_count();
// assert_eq!(old_count.map(|count| count - 1), get_count());
}
*/
/// get all role records
pub fn get_all(connection: &SqliteConnection) -> Box<Vec<Role>> {
Box::new(
roles
.order(roles::id.asc())
.load::<Role>(connection)
.expect("Error loading roles"),
)
}
/// get a role record
pub fn get(
param_role_name: &str,
connection: &SqliteConnection, //) -> Vec<Role> {
) -> Result<Vec<Role>, Box<dyn Error>> {
let query = roles
.filter(name.eq(param_role_name))
.load::<Role>(connection)
.expect("Error loading roles");
debug_query::<Sqlite, _>(&query);
Ok(query)
}
/// update a role record
pub fn update(
param_id: i32,
param_role_name: &str,
connection: &SqliteConnection,
) -> Result<(), Box<dyn Error>> {
let query = diesel::update(roles.filter(id.eq(param_id)))
.set(name.eq(param_role_name))
.execute(connection);
debug_query::<Sqlite, _>(&query);
Ok(())
}
}

View File

@@ -0,0 +1,192 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2019 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
#[cfg(test)]
use diesel::debug_query;
use diesel::dsl::*;
use diesel::prelude::*;
#[cfg(test)]
use diesel::sqlite::Sqlite;
#[cfg(test)]
use diesel::sqlite::SqliteConnection;
use crate::schema;
/// set user defaults
pub fn set_users_default_values(connection: &SqliteConnection) -> QueryResult<usize> {
use schema::users::dsl::*;
insert_into(users).default_values().execute(connection)
}
#[test]
/// examine results when setting user defaults
fn examine_set_users_default_values() {
use schema::users::dsl::*;
let query = insert_into(users).default_values();
let sql = "INSERT INTO `users` DEFAULT VALUES -- binds: []";
assert_eq!(sql, debug_query::<Sqlite, _>(&query).to_string());
}
/// set user defaults
pub fn set_roles_default_values(connection: &SqliteConnection) -> QueryResult<usize> {
use schema::roles::dsl::*;
insert_into(roles).default_values().execute(connection)
}
#[test]
/// examine results when setting user defaults
fn examine_set_roles_default_values() {
use schema::roles::dsl::*;
let query = insert_into(roles).default_values();
let sql = "INSERT INTO `roles` DEFAULT VALUES -- binds: []";
assert_eq!(sql, debug_query::<Sqlite, _>(&query).to_string());
}
/// set user roles defaults
pub fn set_user_roles_default_values(connection: &SqliteConnection) -> QueryResult<usize> {
use schema::user_roles::dsl::*;
insert_into(user_roles).default_values().execute(connection)
}
#[test]
/// examine results when setting user roles defaults
fn examine_set_user_roles_default_values() {
use schema::user_roles::dsl::*;
let query = insert_into(user_roles).default_values();
let sql = "INSERT INTO `user_roles` DEFAULT VALUES -- binds: []";
assert_eq!(sql, debug_query::<Sqlite, _>(&query).to_string());
}
/// set harm defaults
pub fn set_harms_default_values(connection: &SqliteConnection) -> QueryResult<usize> {
use schema::harms::dsl::*;
insert_into(harms).default_values().execute(connection)
}
#[test]
/// examine results when setting harm defaults
fn examine_set_harms_default_values() {
use schema::harms::dsl::*;
let query = insert_into(harms).default_values();
let sql = "INSERT INTO `harms` DEFAULT VALUES -- binds: []";
assert_eq!(sql, debug_query::<Sqlite, _>(&query).to_string());
}
/// set a users email-confirmed column
pub fn set_users_email_confirmed(connection: &SqliteConnection) -> QueryResult<usize> {
use schema::users::dsl::*;
diesel::update(users)
.set(email_confirmed.eq(1))
.execute(connection)
}
/// set a user column
pub fn set_users_single_column(connection: &SqliteConnection) -> QueryResult<usize> {
use schema::users::dsl::*;
insert_into(users)
.values(alias_name.eq("Hiedemann"))
.execute(connection)
}
#[test]
/// examine results when setting a single user column
fn examine_set_users_single_column() {
use schema::users::dsl::*;
let query = insert_into(users).values(alias_name.eq("Hiedemann"));
let sql = "INSERT INTO `users` (`alias_name`) VALUES (?) \
-- binds: [\"Hiedemann\"]";
assert_eq!(sql, debug_query::<Sqlite, _>(&query).to_string());
}
/// set multiple user columns
pub fn set_users_multiple_columns(connection: &SqliteConnection) -> QueryResult<usize> {
use schema::users::dsl::*;
insert_into(users)
.values((
first_name.eq("Lothar"),
last_name.eq("Schlömer"),
alias_name.eq("102"),
))
.execute(connection)
}
#[test]
/// examine results when setting multiple user columns
fn examine_set_user_multiple_columns() {
use schema::users::dsl::*;
let query = diesel::insert_into(users).values((
first_name.eq("Lothar"),
last_name.eq("Schlömer"),
alias_name.eq("102"),
));
let sql = "INSERT INTO `users` (`first_name`, `last_name`, `alias_name`) \
VALUES (?, ?, ?) \
-- binds: [\"Lothar\", \"Schlömer\", \"102\"]";
assert_eq!(sql, debug_query::<Sqlite, _>(&query).to_string());
}
/*
#[test]
/// examine results when setting user columns via json
fn examine_set_user_struct_json() {
use crate::models::users::NewUser;
use schema::users::dsl::*;
//use serde_json::json;
/*_let json_struct = json!({
"last_name": "Knocke",
"first_name": "Daniela",
"alias_name": "Sekretariat",
"email": "knocke@kanzlei.hiedemann.de",
"email_confirmed": 1,
"password_hash": "",
"initials": "dkn",
"date_create": "2019-11-16 20:00:14.114957766",
"id_changed": 1,
"date_changed": "2019-11-16 20:00:15.114957766",
});*/
let json = r#"{ "last_name": "Knocke", "first_name": "Daniela", "alias_name": "Sekretariat", "email": "knocke@kanzlei.hiedemann.de", "email_confirmed": 1, "initials": "dkn", "password_hash": "testpassword", "date_created": "2019-11-16 20:00:14.114957766", "id_changed": 1", "date_changed": "2019-11-16 20:00:15.114957766" }"#;
let user_struct = serde_json::from_str::<NewUser>(json).unwrap();
let query = diesel::insert_into(users).values(&user_struct);
//let query = serde_json::from_str::<User>(&json_struct);
let sql = "diesel::INSERT INTO `users` (`last_name`, `first_name`, `alias_name`, `email`, `email_confirmed`, `initials`, `password_hash`, `date_create`, `id_changed`, `data_updated`) \
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) \
-- binds: [\"Knocke\", \"Daniela\", \"Sekretariat\", \"knocke@kanzlei.hiedemann.de\", 1, \"dkn\", \"testpassword\", \"2019-11-16 20:00:14.114957766\", 1, \"2019-11-16 20:00:15.114957766\"]";
assert_eq!(sql, debug_query::<Sqlite, _>(&query).to_string());
}
*/
#[test]
/// examine results when setting user columns via json options
fn examine_set_user_struct_json_option() {
//use crate::models::users::NewUser;
use schema::users::dsl::*;
use serde_json;
let json = r#"{ "last_name": "Knocke", "first_name": null, "alias_name": null, "email": "knocke@kanzlei.hiedemann.de", "email_confirmed": 1, "initials": "dkn", "password_hash": "test", "date_created": null, "id_changed": 1, "date_changed": null }"#;
let user_struct = serde_json::from_str::<'_>(json).unwrap();
let query = diesel::insert_into(users).values(&user_struct);
let sql = "INSERT INTO `users` (`last_name`, `email`, `email_confirmed`, `initials`, `password_hash`, `id_changed`) \
VALUES (?, ?, ?, ?, ?, ?) \
-- binds: [\"Knocke\", \"knocke@kanzlei.hiedemann.de\", 1, \"dkn\", \"test\", 1]";
//assert_eq!(sql, debug_query::<Sqlite, _>(&query).to_string());
assert_eq!(sql, debug_query::<Sqlite, _>(&query).to_string());
}

View File

@@ -0,0 +1,79 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2019 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
//#[cfg(test)]
use diesel::debug_query;
use diesel::prelude::*;
use diesel::sqlite::{Sqlite, SqliteConnection};
use diesel::{QueryDsl, RunQueryDsl};
use std::error::Error;
use crate::models::user_roles::{NewUserRole, UserRole};
use crate::schema::user_roles;
use crate::schema::user_roles::dsl::*;
use crate::schema::user_roles::*;
impl UserRole {
/// create a new user role record
pub fn new(
param_id_user: i32,
param_id_role: i32,
connection: &SqliteConnection,
) -> Result<(), Box<dyn Error>> {
let struct_user_role = NewUserRole {
id_user: param_id_user,
id_role: param_id_role,
//date_created: Some(Local::now().naive_local()),
//id_user_changed: param_id_user_changed,
//date_changed: Some(Local::now().naive_local()),
};
diesel::insert_into(user_roles::table)
.values(struct_user_role)
.execute(connection)?;
Ok(())
}
/// get a list of all user role records
pub fn get_all(connection: &SqliteConnection) -> Box<Vec<UserRole>> {
Box::new(
user_roles
.order(user_roles::id_user.asc())
.load::<UserRole>(connection)
.expect("Error loading user_roles"),
)
}
/// get a user role record
pub fn get(
param_id_role: i32,
connection: &SqliteConnection,
) -> Result<Vec<UserRole>, Box<dyn Error>> {
let query = user_roles
.filter(id_role.eq(param_id_role))
.load::<UserRole>(connection)
.expect("Error loading user_roles");
debug_query::<Sqlite, _>(&query);
Ok(query)
}
/// update a user role record
pub fn update(
param_id_user: i32,
param_id_role: i32,
connection: &SqliteConnection,
) -> Result<(), Box<dyn Error>> {
let query = diesel::update(user_roles.filter(id_user.eq(param_id_user)))
.set(id_role.eq(param_id_role))
.execute(connection);
debug_query::<Sqlite, _>(&query);
Ok(())
}
}

View File

@@ -0,0 +1,189 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2019 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use bcrypt::{hash, DEFAULT_COST};
use chrono::Local;
use diesel::debug_query;
use diesel::prelude::*;
use diesel::sqlite::Sqlite;
#[cfg(test)]
use diesel::sqlite::SqliteConnection;
use diesel::{QueryDsl, RunQueryDsl};
// WIP: json functionality need work!
// use serde_json;
use std::error::Error;
//use crate::models::users::{NewUser, RegisterUser, User, UserList};
use crate::models::users::{NewUser, RegisterUser, User};
use crate::schema::users;
use crate::schema::users::dsl::*;
impl User {
// implement CRUD-Functions
// new- -> Create
// get- -> Read
// set- -> Update
// remove- -> Delete
/// create a new user record
pub fn new(
param_last_name: &str,
param_first_name: Option<&str>,
param_alias_name: Option<&str>,
param_email: Option<&str>,
param_email_confirmed: Option<i32>,
param_password_hash: &str,
param_initials: Option<&str>,
param_id_user: i32,
connection: &SqliteConnection,
) -> Result<(), Box<dyn Error>> {
let struct_user = NewUser {
last_name: param_last_name,
first_name: param_first_name,
alias_name: param_alias_name,
email: param_email,
email_confirmed: param_email_confirmed,
password_hash: param_password_hash,
//password_hash: Self::hash_password(param_password_hash.to_string()).unwrap(),
initials: param_initials,
date_created: Some(Local::now().naive_local()),
id_changed: param_id_user,
date_changed: Some(Local::now().naive_local()),
};
diesel::insert_into(users::table)
.values(struct_user)
.execute(connection)?;
Ok(())
}
/// get a list of all user records
pub fn get_all(connection: &SqliteConnection) -> Box<Vec<User>> {
Box::new(
users
.order(users::id.asc())
.load::<User>(connection)
.expect("Error loading users"),
)
}
/*
pub fn get(
param_last_name: &str,
connection: &SqliteConnection,
) -> Result<Vec<User>, Box<dyn Error>> {
let query = users
.filter(last_name.eq(param_last_name))
.load::<User>(connection)
.expect("Error loading users");
debug_query::<Sqlite, _>(&query);
Ok(query)
}
*/
/// update a user record
pub fn update(param_id: i32, connection: &SqliteConnection) -> Result<(), Box<dyn Error>> {
let query = users.filter(id.eq(param_id)).execute(connection)?;
debug_query::<Sqlite, _>(&query);
Ok(())
}
/// create a hash value for the user password
pub fn hash_password(plain: &str) -> Result<String, Box<dyn Error>> {
Ok(hash(plain, DEFAULT_COST)?)
}
/// update the confirmation status of a user emak address
pub fn set_users_email_confirmed(connection: &SqliteConnection) -> QueryResult<usize> {
diesel::update(users)
.set(email_confirmed.eq(1))
.execute(connection)
}
/// update a singel column of a given user record
pub fn set_users_single_column(connection: &SqliteConnection) -> QueryResult<usize> {
diesel::insert_into(users)
.values(alias_name.eq("Hiedemann"))
.execute(connection)
}
/// update multiple columns of a given user record
pub fn set_users_multiple_columns(connection: &SqliteConnection) -> QueryResult<usize> {
diesel::insert_into(users)
.values((
first_name.eq("Lothar"),
last_name.eq("Schlömer"),
alias_name.eq("102"),
))
.execute(connection)
}
// /// update multiple columns of a given user record with a json string
// pub fn set_user_struct_json(connection: &SqliteConnection) -> Result<(), Box<dyn Error>> {
// let json = r#"{ "first_name": "Daniela", "last_name": "Knocke", "alias_name": "Sekretariat", "email": "knocke@kanzlei.hiedemann.de", "email_confirmed": 1, "password_hash": "", "initials": "dkn" }"#;
// //let user_struct = serde_json::from_str::<NewUser>(json)?;
// let user_struct = serde_json::from_str::<'_>(json)?;
// diesel::insert_into(users)
// .values(&user_struct)
// .execute(connection)?;
// Ok(())
// }
// pub fn set_user_struct_json_option(
// connection: &SqliteConnection,
// ) -> Result<(), Box<dyn Error>> {
// let json = r#"{ "first_name": null, "last_name": "Knocke", "alias_name": null, "email": "knocke@kanzlei.hiedemann.de", "email_confirmed": 1, "password_hash": "", "initials": "dkn", "id_changed": 1 }"#;
// let user_form = serde_json::from_str::<'_>(json)?;
// diesel::insert_into(users)
// .values(&user_form)
// .execute(connection)?;
// Ok(())
//}
}
impl<'a> RegisterUser<'a> {
//pub fn validates(self) -> Result<(), Error> {
/// validate the password hash
pub fn validates(self) -> Result<RegisterUser<'a>, &'static str> {
let password_are_equal = self.password_hash == self.password_confirmation;
let password_not_empty = self.password_hash.len() > 0;
if password_are_equal && password_not_empty {
Ok(self)
//else if !password_are_equal {
// Err("Password and Password Confirmation does not match")
} else {
Err("Wrong Password, check it is not empty")
}
}
/*
pub fn get_all(
connection: &SqliteConnection,
//) -> Product {
//) -> Box<Vec<User>> {
) -> Result<Vec<User>, Box<dyn Error>> {
let data = users
.filter(last_name.like("H%"))
//.order(users::id.desc())
.load(connection)?;
debug_query::<Sqlite, _>(&data);
Ok(data)
// We return a value by leaving it without a comma
//UserList(all_users)
}
*/
}

View File

@@ -0,0 +1,139 @@
// WIP
use diesel::dsl::*;
use diesel::prelude::*;
//#[cfg(test)]
//use diesel::sqlite::Sqlite;
//#[cfg(test)]
//use diesel::sqlite::SqliteConnection;
//use serde_derive;
//use std::error::Error;
use crate::schema;
pub fn set_users_single_column_batch(conn: &SqliteConnection) -> QueryResult<usize> {
use schema::users::dsl::*;
insert_into(users)
.values(&vec![last_name.eq("Zerres"), last_name.eq("Plank")])
.execute(conn)
}
/*
#[test]
fn examine_sql_users_insert_get_results() {
use diesel::result::Error;
let connection = establish_connection();
connection.test_transaction::<_, Error, _>(|| {
use diesel::select;
use diesel::dsl;
use chrono::NaiveDateTime;
use schema::users::dsl::*;
use models::insert::NewUser;
//use models::User;
//let now = select(dsl::now).get_result::<NaiveDateTime>(&connection)?;
let inserted_users = connection.transaction::<_, Error, _>(|| {
let inserted_count = insert_into(users)
.values(&vec![
(id.eq(1), last_name.eq("Hiedemann"), first_name.eq("Eric"),
alias.eq("Eric.Hiedemann"), email_confirmed.eq(0),initials.eq("EH")),
(id.eq(2), last_name.eq("Schlömer"), first_name.eq("Lothar"),
alias.eq("Lothar.Schlömer"), email_confirmed.eq(0), initials.eq("LS")),
])
.execute(&connection)?;
Ok(users
.order(id.desc())
.limit(inserted_count as i64)
.load(&connection)?
.into_iter()
.rev()
.collect::<Vec<_>>())
})?;
let expected_users = vec![
NewUser {
//id: 1,
last_name: "Hiedemann".into(),
first_name: "Eric".into(),
alias: "Eric.Hiedemann".into(),
email: "".into(),
email_confirmed: 0,
password_hash: "".into(),
initials: "EH".into(),
//date_created: now,
//date_updated: now,
},
NewUser {
//id: 2,
last_name: "Schlömer".into(),
first_name: "Lothar".into(),
alias: "Lothar.Schlömer".into(),
email: "".into(),
email_confirmed: 0,
password_hash: "".into(),
initials: ("LS").into(),
//date_created: now,
//date_updated: now,
},
];
//assert_eq!(expected_users, inserted_users);
Ok(())
});
}
*/
/*
pub fn create_numberharm<'a>(connection: &SqliteConnection, NumberHarm: &'a str) {
let numberHarm = models::NewNumberHarm { NumberHarm };
diesel::insert_into(schema::NumberHarm::table)
.values(&numberHarm)
.execute(connection)
.expect("Error inserting new task");
}
*/
/*
pub fn create_userid<'a>(connection: &SqliteConnection, User: &'a str) {
let user = models::NewUser { User };
diesel::insert_into(schema::User::table)
.values(&user)
.execute(connection)
.expect("Error inserting new task");
}
*/
/*
pub fn create_userclaimid<'a>(connection: &SqliteConnection, UserClaim: &'a str) {
let userClaim = models::NewUserClaim { UserClaim };
diesel::insert_into(schema::UserClaim::table)
.values(&userClaim)
.execute(connection)
.expect("Error inserting new task");
}
pub fn create_userrole<'a>(connection: &SqliteConnection, UserRole: &'a str) {
let userRole = models::NewUserRole { UserRole };
diesel::insert_into(schema::UserRole::table)
.values(&userRole)
.execute(connection)
.expect("Error inserting new task");
}
pub fn create_useruserrole<'a>(connection: &SqliteConnection, UserUserRole: &'a str) {
let userUserRole = models::NewUserUserRole { UserUserRole };
diesel::insert_into(schema::UserUserRole::table)
.values(&userUserRole)
.execute(connection)
.expect("Error inserting new task");
}
*/

View File

@@ -0,0 +1,31 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2019 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
#![warn(missing_docs, rust_2018_idioms, rust_2018_compatibility)]
#![recursion_limit="256"]
#![warn(clippy::pedantic)]
//#![warn(clippy::nursery)]
//! advotracker database
//! Supports lawyers to capture relevant data encountered during an
//! online legal advice.
//! This SQL database backend will consuming Diesel to make use of
//! sql features.
// ?? is this needed in edition 2018 anymore ??
#[macro_use]
extern crate diesel;
/// SQL functions and methods
pub mod functions;
/// SQL models definitions
pub mod models;
/// SQL schema definitions
pub mod schema;

View File

@@ -0,0 +1,8 @@
--- src/schema.rs.orig 2020-06-30 13:35:01.826955973 +0200
+++ src/schema.rs 2020-06-30 13:35:26.640286611 +0200
@@ -1,3 +1,5 @@
+#![allow(missing_docs)]
+
table! {
claims (id) {
id -> Integer,

View File

@@ -0,0 +1,32 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use crate::schema::claim;
/// Stucture of a claim record
#[derive(Debug, Queryable)]
pub struct Claim {
/// the auto incremented primary index
pub id: i32,
/// the user id
pub user_id: i32,
/// the type of the user
pub type_: Option<String>,
/// the name string of the claim type
pub value: Option<String>,
}
/// Structure of a new claim record
#[derive(Debug, Deserialize, Insertable)]
#[table_name = "claims"]
pub struct NewClaim<'a> {
//pub user_id: &'a i32,
/// Lifetime to the claim type
pub type_: Option<&'a str>,
/// Lifetime to the name of the claim type
pub value: Option<&'a str>,
}

View File

@@ -0,0 +1,60 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};
use crate::schema::harms;
/// Manage harm records (SELECT, UPDATE, DELETE)
#[derive(AsChangeset, Debug, Deserialize, Identifiable, PartialEq, Queryable)]
pub struct Harm {
/// the auto incremented primary index
pub id: i32,
/// the harm name
pub id_harm: String,
/// the policy holder name
pub id_policyholder: Option<String>,
/// the callback number
pub id_callback: Option<String>,
/// the fallback date
pub date_fallback: Option<NaiveDateTime>,
/// the date the record was recorded
pub date_recording: NaiveDateTime,
/// the user id
pub id_user: i32,
/// the date the record was created
pub date_created: NaiveDateTime,
/// the user id that has chanced the record
pub id_user_changed: i32,
/// the date the record was changed
pub date_changed: NaiveDateTime,
}
/// Structure of a new harm
#[derive(Debug, Deserialize, Insertable, Serialize)]
#[table_name = "harms"]
pub struct NewHarm<'a> {
/// Lifetime to the harm name
pub id_harm: &'a str,
/// Lifetime to the policyholder
pub id_policyholder: Option<&'a str>,
/// Lifetime to the callback number
pub id_callback: Option<&'a str>,
/// the fallback date
pub date_fallback: Option<NaiveDateTime>,
/// the date the record was recorded
pub date_recording: NaiveDateTime,
/// the user id that has chanced the record
pub id_user: i32,
/// the date the record was created
pub date_created: Option<NaiveDateTime>,
/// the user id that has chanced the record
pub id_user_changed: i32,
/// Lifetime to the date the record was changed
pub date_changed: Option<NaiveDateTime>,
}

View File

@@ -0,0 +1,15 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use crate::schema::*;
//use chrono::NaiveDateTime;
use serde_derive::*;
//use types::*;
//use crate::models::types::*;
//use serde::*;
pub mod types;

View File

@@ -0,0 +1,22 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
/// defining roles
pub mod roles;
/// defining harms
pub mod harms;
/// defining users
pub mod users;
/// defining user roles
pub mod user_roles;
// methods used for: INSERT
//pub mod insert;
//use insert::types::*;

View File

@@ -0,0 +1,47 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};
use crate::schema::roles;
/// Structure of a role record
#[derive(AsChangeset, Debug, Deserialize, Identifiable, PartialEq, Queryable)]
#[table_name = "roles"]
pub struct Role {
/// The auto incremented primary index
pub id: i32,
/// The role name
pub name: String,
/// Creation date of the role
pub date_created: NaiveDateTime,
/// The user id, that has changed the record
pub id_user_changed: i32,
/// The timestamp, when the record was changed
pub date_changed: NaiveDateTime,
}
/// Structure of a new claim record
#[derive(Debug, Deserialize, Insertable, Serialize)]
#[table_name = "roles"]
pub struct NewRole<'a> {
/// Lifetime of the role name
pub name: &'a str,
/// Creation date of the role
pub date_created: Option<NaiveDateTime>,
/// The user id, that has changed the record
pub id_user_changed: i32,
/// The timestamp, when the record was changed
pub date_changed: Option<NaiveDateTime>,
}
// we couldn't do a RoleList implementation for a Vector
// because we don't own it, RoleList is using the newtype pattern
//#[derive(Debug, Deserialize, Serialize)]
//pub struct RoleList(pub Vec<Role>);

View File

@@ -0,0 +1,10 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
// WIP
// /// traits for the user model
// pub mod traits;

View File

@@ -0,0 +1,192 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
// bring models into scope
use diesel::backend::Backend;
use diesel::deserialize;
use diesel::deserialize::FromSql;
use diesel::serialize;
use diesel::serialize::{Output, ToSql};
use diesel::sql_types::Integer;
//use serde::Serializer;
use serde;
//use super::models::ConfirmState;
//use crate::db::models::ConfirmState;
// trait: meaningful enum/types for email confirmation states
// in analogy: https://noyez.gitlab.io/post/2018-08-05-a-small-custom-bool-type-in-diesel/
//#[repr(i32)]
#[derive(AsExpression, Copy, Clone, Debug, PartialEq, FromSqlRow)]
#[sql_type = "Integer"]
pub enum ConfirmState {
Unconfirmed = 0,
Confirmed = 1,
Authorized = 2,
Blocked = 3,
}
impl<DB> ToSql<Integer, DB> for ConfirmState
where
DB: Backend,
i32: ToSql<Integer, DB>,
{
fn to_sql<W: std::io::Write>(&self, out: &mut Output<W, DB>) -> serialize::Result {
let int_value;
match &self {
ConfirmState::Unconfirmed => int_value = 0,
ConfirmState::Confirmed => int_value = 1,
ConfirmState::Authorized => int_value = 2,
ConfirmState::Blocked => int_value = 3,
}
println!("Writing to sql: i32:{:?}", &int_value);
<i32 as ToSql<Integer, DB>>::to_sql(&int_value, out)
}
}
/*
impl FromSql<Integer, Sqlite>
for ConfirmState
{
fn from_sql(
bytes: Option<&<diesel::sqlite::Sqlite as diesel::backend::Backend>::RawValue>,
) -> diesel::deserialize::Result<Self> {
<i32 as diesel::deserialize::FromSql<
diesel::sql_types::Integer, diesel::sqlite::Sqlite>>::from_sql()
.map(ConfirmState::Confirmed)
}
}
*/
impl<DB> FromSql<Integer, DB> for ConfirmState
where
DB: Backend<RawValue = [u8]>,
i32: FromSql<Integer, DB>,
{
fn from_sql(bytes: Option<&DB::RawValue>) -> deserialize::Result<Self> {
match <i32 as FromSql<Integer, DB>>::from_sql(bytes)? {
0 => Ok(ConfirmState::Unconfirmed),
1 => Ok(ConfirmState::Confirmed),
2 => Ok(ConfirmState::Authorized),
3 => Ok(ConfirmState::Blocked),
x => Err(format!("Unrecognized variant {}", x).into()),
}
}
}
/*
// WIP
impl<DB> FromSql<Integer, DB> for ConfirmState
where
DB: Backend,
i32: FromSql<Bool, DB> {
//fn from_sql(bytes: Option<diesel::backend::Backend>::RawValue<DB>) -> diesel::deserialize::Result<Self> {
fn from_sql(
bytes: Option<&<DB>::RawValue>,
) -> diesel::deserialize::Result<Self> {
//println!("Reading from sql: bytes:{:?}", bytes);
match bytes {
<i32 as diesel::deserialize::FromSql<Integer, DB>>::from_sql(bytes)
.map(ConfirmState::Confirmed)
}
/*
Some(bytes) => if bytes[0] != 0 {
Ok(ConfirmState::Confirmed) }
else { Ok(ConfirmState::Unconfirmed) }
}
//<i32 as diesel::deserialize::FromSql<Integer, DB>>::from_sql(bytes).map(ConfirmState::Confirmed)
//fn from_sql(bytes: Option<Bool>) -> diesel::deserialize::Result<Self> {
// println!("Reading from sql: bytes:{:?}", bytes);
// match bytes {
// Some(bytes) => if bytes[0] != 0 {
// Ok(ConfirmState::Confirmed) }
// else { Ok(ConfirmState::Unconfirmed) },
// None => Ok(ConfirmState::Unconfirmed),
// }
*/
}
}
*/
/*
impl<DB: diesel::backend::Backend<RawValue = [u8]>>
diesel::deserialize::FromSql<diesel::sql_types::Integer, DB> for ConfirmState
{
fn from_sql(bytes: Option<&[u8]>) -> diesel::deserialize::Result<Self> {
<i32 as diesel::deserialize::FromSql<diesel::sql_types::Integer, DB>>::from_sql(
bytes,
)
.map($name)
}
}
*/
struct ConfirmStateVisitor;
use serde::de::Deserialize;
use serde::de::{self, Visitor};
impl<'de> Visitor<'de> for ConfirmStateVisitor {
type Value = ConfirmState;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("an integer or string of ",
"\"Unconfirmed (0)\",",
"\"Confirmed (1)\"",
"\"Authorized (2)\"",
"\"Blocked (3)\".");
}
//fn visit_bool<E>(self, value: bool) -> Result<ConfirmState, E>
//where
// E: de::Error,
//{
// match value {
// true => Ok(ConfirmState::Confirmed),
// false => Ok(ConfirmState::Unconfirmed),
// }
//}
fn visit_i32<E>(self, value: &'a i32) -> Result<self::Value, E>
where
E: de::Error,
{
match <i32 as FromSql<Integer, DB>>::from_sql(bytes)? {
0 => Ok(ConfirmState::Unconfirmed),
1 => Ok(ConfirmState::Confirmed),
2 => Ok(ConfirmState::Authorized),
3 => Ok(ConfirmState::Blocked),
x => Err(format!("Unrecognized variant {}", x).into()),
0 => Ok(ConfirmState::Confirmed),
false => Ok(ConfirmState::Unconfirmed),
}
}
fn visit_str<E>(self, value: &str) -> Result<self::Value, E>
where
E: de::Error,
{
match value {
//"Confirmed" | "Authorized" => Ok(ConfirmState::Confirmed),
//"Unconfirmed" | "Unauthorized" => Ok(ConfirmState::Unconfirmed),
"Unconfirmed" => Ok(ConfirmState::Unconfirmed),
"Confirmed" => Ok(ConfirmState::Confirmed),
"Authorized" => Ok(ConfirmState::Authorized),
"Bolcked" => Ok(ConfirmState::Blocked),
_s => Err(E::custom(format!("Unknown string value: {}", _s))),
}
}
}
impl<'de> Deserialize<'de> for ConfirmState {
fn deserialize<D>(deserializer: D) -> Result<self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(ConfirmStateVisitor)
}
}

View File

@@ -0,0 +1,28 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use crate::schema::user_roles;
use serde::Deserialize;
/// Structure of a user role record
#[derive(Debug, Queryable, PartialEq)]
pub struct UserRole {
/// id of the referenced user
pub id_user: i32,
/// id of the referenced role
pub id_role: i32,
}
/// Structure of a new user role record
#[derive(Deserialize, Insertable)]
#[table_name = "user_roles"]
pub struct NewUserRole {
/// id of the referenced user
pub id_user: i32,
/// id of the referenced role
pub id_role: i32,
}

View File

@@ -0,0 +1,98 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use chrono::NaiveDateTime;
use serde::{Deserialize, Serialize};
use crate::schema::users;
/// Structure of a user record
#[derive(AsChangeset, Debug, Deserialize, Identifiable, PartialEq, Queryable, Serialize)]
pub struct User {
/// the auto incremented primary index
pub id: i32,
/// last name of the user
pub last_name: String,
// Option -> returns "None", if db value is null
/// first name of the user
pub first_name: Option<String>,
/// alias of the user name
pub alias_name: Option<String>,
/// users email address
pub email: Option<String>,
/// confirmation state of users email address
pub email_confirmed: Option<i32>,
/// users initials
pub initials: Option<String>,
/// users password hash
pub password_hash: Option<String>,
/// timestamp when the record was created
pub date_created: NaiveDateTime,
/// user id that has changed the record
pub id_changed: i32,
/// timestamp when the record was changed
pub date_changed: NaiveDateTime,
}
/// Structure of a new user record
#[derive(Debug, Deserialize, Insertable, Serialize)]
#[table_name = "users"]
pub struct NewUser<'a> {
/// Lifetime for users last name
pub last_name: &'a str,
/// Lifetime for users first name
pub first_name: Option<&'a str>,
/// Lifetime for users alias name
pub alias_name: Option<&'a str>,
/// Lifetime for users users email
pub email: Option<&'a str>,
/// Lifetime for users email-confirmed
pub email_confirmed: Option<i32>,
/// Lifetime for users initials
pub initials: Option<&'a str>,
/// Lifetime for users password hash
pub password_hash: &'a str,
/// Optional timestamp for cration date
pub date_created: Option<NaiveDateTime>,
/// Optional userid that changed the record
pub id_changed: i32,
/// Optional timestamp for the change date
pub date_changed: Option<NaiveDateTime>,
}
/// Structure of a user registration
#[derive(Debug, Deserialize, Queryable)]
pub struct RegisterUser<'a> {
/// Lifetime of users last name
pub last_name: &'a str,
/// Lifetime of users first name
pub first_name: Option<&'a str>,
/// Lifetime for users alias name column
pub alias: Option<&'a str>,
/// Lifetime for users email column
pub email: Option<&'a str>,
/// Lifetime for users email confirmed column
pub email_confirmed: Option<i32>,
/// Lifetime for users initials
pub initials: Option<&'a str>,
/// Lifetime for users password hash
pub password_hash: &'a str,
/// Lifetime for users password confirmation
pub password_confirmation: &'a str,
/// Optional userid that changed the record
pub id_changed: i32,
}
// WIP
//pub mod traits;
//use types::ConfirmState;
//use crate::types::ConfirmStateVisitor;
//#[serde(skip)]
//#[derive(Serialize, Deserialize)]
//pub struct UserList(pub Vec<User>);

View File

@@ -0,0 +1,74 @@
#![allow(missing_docs)]
table! {
claims (id) {
id -> Integer,
id_user -> Integer,
#[sql_name = "type"]
type_ -> Nullable<Text>,
value -> Nullable<Text>,
date_created -> Timestamp,
id_user_changed -> Integer,
date_changed -> Timestamp,
}
}
table! {
harms (id) {
id -> Integer,
id_harm -> Text,
id_policyholder -> Nullable<Text>,
id_callback -> Nullable<Text>,
date_fallback -> Nullable<Timestamp>,
date_recording -> Timestamp,
id_user -> Integer,
date_created -> Timestamp,
id_user_changed -> Integer,
date_changed -> Timestamp,
}
}
table! {
roles (id) {
id -> Integer,
name -> Text,
date_created -> Timestamp,
id_user_changed -> Integer,
date_changed -> Timestamp,
}
}
table! {
user_roles (id_user, id_role) {
id_user -> Integer,
id_role -> Integer,
}
}
table! {
users (id) {
id -> Integer,
last_name -> Text,
first_name -> Nullable<Text>,
alias_name -> Nullable<Text>,
email -> Nullable<Text>,
email_confirmed -> Nullable<Integer>,
initials -> Nullable<Text>,
password_hash -> Nullable<Text>,
date_created -> Timestamp,
id_changed -> Integer,
date_changed -> Timestamp,
}
}
joinable!(claims -> users (id_user));
joinable!(user_roles -> roles (id_role));
joinable!(user_roles -> users (id_user));
allow_tables_to_appear_in_same_query!(
claims,
harms,
roles,
user_roles,
users,
);