use reqwest;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct AuthInput {
pub username: String,
pub password: String,
}
#[derive(Serialize, Deserialize)]
pub struct RegisterInput {
pub username: String,
pub email: String,
pub password: String,
}
#[derive(Serialize, Deserialize)]
pub struct AuthResponse {
pub success: bool,
pub message: String,
}
impl Default for AuthResponse {
fn default() -> Self {
AuthResponse {
success: false,
message: String::new(),
}
}
}
#[derive(Serialize, Deserialize)]
pub struct HourEntryInsertInput {
pub email: String,
pub hours: i32,
pub date_worked: String,
}
#[derive(Serialize, Deserialize)]
pub struct HourEntryDeleteInput {
pub email: String,
pub id: i32,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct HourEntry {
pub id: i32,
pub user_id: i32,
pub hours: i32,
pub date_worked: String,
pub date_entered: String,
}
impl Default for HourEntry {
fn default() -> Self {
HourEntry {
id: 0,
user_id: 0,
hours: 0,
date_worked: String::new(),
date_entered: String::new(),
}
}
}
#[derive(Serialize, Deserialize, Clone)]
pub struct UserInfoInput {
pub email: String,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct UserInfoResponse {
pub success: bool,
pub message: String,
}
impl Default for UserInfoResponse {
fn default() -> Self {
UserInfoResponse {
success: false,
message: String::new(),
}
}
}
pub async fn auth(username: String, password: String, api_address: String) -> AuthResponse {
// Connect to env!("WEB_API_ADDRESS")/api/auth/login and return AuthResponse
let client = reqwest::Client::new();
let response = client
.post(&format!("{}/api/auth/login", api_address))
.json(&AuthInput {
username: username.to_string(),
password: password.to_string(),
})
.send()
.await
.unwrap();
response.json().await.unwrap()
}
pub async fn register(
username: String,
email: String,
password: String,
api_address: String,
) -> AuthResponse {
// Connect to env!("WEB_API_ADDRESS")/api/auth/register and return AuthResponse
let client = reqwest::Client::new();
let response = client
.post(&format!("{}/api/auth/register", api_address))
.json(&RegisterInput {
username: username.to_string(),
email: email.to_string(),
password: password.to_string(),
})
.send()
.await
.unwrap();
response.json().await.unwrap()
}
pub async fn get_user_info(api_key: String, api_address: String) -> UserInfoResponse {
// Connect to env!("WEB_API_ADDRESS")/api/user/info and return UserInfo
let client = reqwest::Client::new();
let response = client
.get(&format!("{}/api/user/info", api_address))
.header("Authentication", api_key)
.send()
.await
.unwrap();
response.json().await.unwrap()
}
pub async fn get_hour_entries(api_key: String, api_address: String) -> Vec<HourEntry> {
// Connect to env!("WEB_API_ADDRESS")/api/hours/all and return Vec<HourEntry>
let email = get_user_info(api_key.clone(), api_address.clone())
.await
.message;
let client = reqwest::Client::new();
let response = client
.post(&format!("{}/api/hours/all", api_address))
.header("Authentication", api_key)
.json(&UserInfoInput {
email: email.to_string(),
})
.send()
.await
.unwrap();
response.json().await.unwrap()
}
pub async fn insert_hour_entry(
hours: i32,
date_worked: String,
api_key: String,
api_address: String,
) -> HourEntry {
// Connect to env!("WEB_API_ADDRESS")/api/hours/insert and return HourEntry
let email = get_user_info(api_key.clone(), api_address.clone())
.await
.message;
let client = reqwest::Client::new();
let response = client
.post(&format!("{}/api/hours/insert", api_address))
.header("Authentication", api_key)
.json(&HourEntryInsertInput {
email: email.to_string(),
hours: hours,
date_worked: date_worked.to_string(),
})
.send()
.await
.unwrap();
response.json().await.unwrap()
}
pub async fn delete_hour_entry(id: i32, api_key: String, api_address: String) {
// Connect to env!("WEB_API_ADDRESS")/api/hours/delete and return ()
let email = get_user_info(api_key.clone(), api_address.clone())
.await
.message;
let client = reqwest::Client::new();
client
.post(&format!("{}/api/hours/delete", api_address))
.header("Authentication", api_key)
.json(&HourEntryDeleteInput {
email: email.to_string(),
id: id,
})
.send()
.await
.unwrap();
}
/* All the nice old things!
use mysql::prelude::*;
use mysql::*;
use argon2::{
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Argon2,
};
// Different exit contituons for verify_user
#[derive(Debug, PartialEq, Eq)]
pub enum VerifyExit {
EmptyArg,
Success,
WrongPassword,
UserNotFound,
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct User {
pub id: i32,
pub username: String,
pub password: String,
}
impl User {
pub fn new() -> User {
User {
id: 0,
username: "".to_owned(),
password: "".to_owned(),
}
}
}
// Time entry struct
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct TimeEntry {
pub id: i32,
pub user_id: i32,
pub hours: i32,
pub date_worked: String,
pub date_entered: String,
}
// Role struct
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Role {
pub id: i32,
pub name: String,
}
#[derive(Debug, PartialEq, Eq)]
pub enum Roles {
Member,
Leader,
}
// UserRole struct
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct UserRole {
pub user_id: i32,
pub role_id: i32,
}
pub struct DatabaseManager {
pub pool: Pool,
}
impl DatabaseManager {
pub fn new() -> DatabaseManager {
DatabaseManager {
pool: Pool::new(Opts::from_url("mysql://root:QXSrgXhclUKrC6jl37qQ5ytRVbthtyJSCvFR23ZhYvlbAGwysvqecSsg1eeLPkLP3J9YrSinM192JmcgjrIPdLAhDc5wpU1im1ocNV7oU01CWL4GYgfNdMFx9mMlKZOc@172.104.253.237:3306/tuntikirjanpito").unwrap()).unwrap(),
}
}
pub fn init_connection(&mut self) {
println!("Connected to mysql");
}
pub fn register_user(&mut self, username: &str, password: &str) -> bool {
if username.is_empty() || password.is_empty() {
println!("Username or password is empty");
return false;
}
let password = password.as_bytes();
let salt = SaltString::generate(&mut OsRng);
// Argon2 with default params (Argon2id v19)
let argon2 = Argon2::default();
// Hash password to PHC string
let password_hash = argon2.hash_password(password, &salt).unwrap().to_string();
self.pool
.get_conn()
.ok()
.unwrap()
.exec_drop(
"INSERT INTO users (username, password) values (:username, :password)",
params! {
"username" => username,
"password" => password_hash,
},
)
.unwrap();
println!("User {} registered", username);
return true;
}
pub fn verify_user(&mut self, username: &str, password: &str) -> VerifyExit {
if username.is_empty() || password.is_empty() {
println!("Username or password is empty");
return VerifyExit::EmptyArg;
}
let res = self
.pool
.get_conn()
.ok()
.unwrap()
.query_first(format!(
"SELECT id, username, password FROM users WHERE username='{un}'",
un = username
))
//Unpack Result
.map(|row| {
//Unpack Option
row.map(|(id, username, password)| User {
id: id,
username: username,
password: password,
})
});
match res.unwrap() {
Some(user) => {
let parsed_hash = PasswordHash::new(&user.password);
if Argon2::default()
.verify_password(password.as_bytes(), &parsed_hash.unwrap())
.is_ok()
{
println!("Password verified");
return VerifyExit::Success;
} else {
println!("Password not verified");
return VerifyExit::WrongPassword;
}
}
None => return VerifyExit::UserNotFound,
}
}
pub fn get_user(&mut self, username: &str) -> User {
let res = self
.pool
.get_conn()
.ok()
.unwrap()
.query_first(format!(
"SELECT id, username, password FROM users WHERE username='{un}'",
un = username
))
//Unpack Result
.map(|row| {
//Unpack Option
row.map(|(id, username, password)| User {
id: id,
username: username,
password: password,
})
});
match res.unwrap() {
Some(mut user) => {
println!("User {} found", user.username);
user.password = "".to_owned();
return user.clone();
}
None => {
return User {
id: -1,
username: "".to_owned(),
password: "".to_owned(),
}
}
}
}
pub fn add_time_entry(&mut self, user_id: i32, hours: i32, date_worked: &str) {
self.pool
.get_conn()
.ok()
.unwrap()
.exec_drop(
"INSERT INTO entries (user_id, hours, date_worked, date_entered) values (:user_id, :hours, :date_worked, CURDATE())",
params! {
"user_id" => user_id,
"hours" => hours,
"date_worked" => date_worked,
},
)
.unwrap();
}
pub fn delete_time_entry(&mut self, id: i32) {
self.pool
.get_conn()
.ok()
.unwrap()
.exec_drop(
"DELETE FROM entries WHERE id=:id",
params! {
"id" => id,
},
)
.unwrap();
}
pub fn get_time_entries(&mut self, user_id: i32) -> Vec<TimeEntry> {
self.pool
.get_conn()
.ok()
.unwrap()
.query_map(
format!(
"SELECT id, user_id, hours, date_worked, date_entered FROM entries WHERE user_id={uid}",
uid = user_id
),
|(id, user_id, hours, date_worked, date_entered)| TimeEntry {
id,
user_id,
hours,
date_worked,
date_entered,
},
)
.unwrap()
}
pub fn get_roles(&mut self) -> Vec<Role> {
self.pool
.get_conn()
.ok()
.unwrap()
.query_map("SELECT id, name FROM roles", |(id, name)| Role { id, name })
.unwrap()
}
pub fn get_user_role_pairs(&mut self) -> Vec<UserRole> {
self.pool
.get_conn()
.ok()
.unwrap()
.query_map(
"SELECT user_id, role_id FROM users_roles",
|(user_id, role_id)| UserRole { user_id, role_id },
)
.unwrap()
}
}
*/