2023-09-22 21:26:13 +02:00
|
|
|
//use chrono::{NaiveDate, NaiveTime, Weekday};
|
|
|
|
|
//use rust_decimal::Decimal;
|
2023-10-09 17:33:20 +02:00
|
|
|
#![allow(unused_variables)]
|
2023-11-11 16:27:40 +01:00
|
|
|
|
|
|
|
|
use chrono::{NaiveTime, Weekday};
|
|
|
|
|
use lazy_static::lazy_static;
|
|
|
|
|
use regex::Regex;
|
2023-09-08 11:53:08 +02:00
|
|
|
use serde::{Deserialize, Serialize};
|
2023-09-22 21:26:13 +02:00
|
|
|
//use uuid::Uuid;
|
2023-11-11 16:27:40 +01:00
|
|
|
use validator::{Validate, ValidationError};
|
|
|
|
|
use crate::error::AppError;
|
2023-08-24 22:06:37 +02:00
|
|
|
|
2023-09-22 21:26:13 +02:00
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
|
|
|
pub enum ApiResponse<T> {
|
|
|
|
|
Data(T),
|
|
|
|
|
Error(String)
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-15 13:55:01 +02:00
|
|
|
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Validate, Default)]
|
2023-09-08 11:53:08 +02:00
|
|
|
#[cfg_attr(feature = "ssr", derive(sqlx::FromRow))]
|
2023-08-24 22:06:37 +02:00
|
|
|
pub struct Company {
|
2023-09-08 11:53:08 +02:00
|
|
|
id: i32,
|
|
|
|
|
#[validate(length(min = 1,message = "Name cannot be empty"))]
|
|
|
|
|
pub name: String,
|
|
|
|
|
#[validate(length(min = 1,message = "Street cannot be empty"))]
|
|
|
|
|
pub street: String,
|
|
|
|
|
#[validate(length(min = 1,message = "House number cannot be empty"))]
|
|
|
|
|
pub house_number: String,
|
|
|
|
|
pub zip_code: String,
|
|
|
|
|
pub city: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Company {
|
|
|
|
|
pub fn id(&self) -> i32 {
|
|
|
|
|
self.id
|
|
|
|
|
}
|
2023-08-24 22:06:37 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-22 21:26:13 +02:00
|
|
|
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Validate, Default)]
|
|
|
|
|
#[cfg_attr(feature = "ssr", derive(sqlx::FromRow))]
|
2023-08-24 22:06:37 +02:00
|
|
|
pub struct User {
|
2023-09-22 21:26:13 +02:00
|
|
|
id: i32,
|
|
|
|
|
pub login: String,
|
|
|
|
|
pub password: String,
|
|
|
|
|
pub full_name: Option<String>,
|
2023-09-27 11:36:52 +02:00
|
|
|
#[validate(email(message = "Enter valid email address"))]
|
2023-09-22 21:26:13 +02:00
|
|
|
pub email: Option<String>,
|
|
|
|
|
pub admin: bool,
|
|
|
|
|
pub get_emails: bool,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl User {
|
|
|
|
|
pub fn id(&self) -> i32 {
|
|
|
|
|
self.id
|
|
|
|
|
}
|
2023-08-24 22:06:37 +02:00
|
|
|
}
|
|
|
|
|
|
2023-09-27 11:36:52 +02:00
|
|
|
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Validate, Default)]
|
|
|
|
|
pub struct UserProfile {
|
2023-10-09 17:33:20 +02:00
|
|
|
#[validate(length(min = 1,message = "Username cannot be empty"))]
|
2023-09-27 11:36:52 +02:00
|
|
|
login: String,
|
2023-10-09 17:33:20 +02:00
|
|
|
#[validate(must_match(other = "password_ver", message = "Passwords doesn't match"))]
|
|
|
|
|
password: Option<String>,
|
|
|
|
|
password_ver: Option<String>,
|
2023-09-27 11:36:52 +02:00
|
|
|
full_name: String,
|
|
|
|
|
#[validate(email(message = "Enter valid email address"))]
|
|
|
|
|
email: String,
|
2023-10-09 17:33:20 +02:00
|
|
|
get_emails: Option<String>,
|
|
|
|
|
admin: Option<String>
|
2023-09-27 11:36:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl UserProfile {
|
|
|
|
|
|
|
|
|
|
pub fn login(&self) -> &str {
|
|
|
|
|
&self.login
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn full_name(&self) -> &str {
|
|
|
|
|
&self.full_name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn email(&self) -> &str {
|
|
|
|
|
&self.email
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_emails(&self) -> bool {
|
|
|
|
|
self.get_emails.is_some()
|
|
|
|
|
}
|
2023-10-09 17:33:20 +02:00
|
|
|
pub fn admin(&self) -> bool {
|
|
|
|
|
self.admin.is_some()
|
|
|
|
|
}
|
|
|
|
|
pub fn password(&self) -> &Option<String> {
|
|
|
|
|
&self.password
|
|
|
|
|
}
|
2023-09-27 11:36:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Validate, Default)]
|
|
|
|
|
pub struct PwdChange {
|
|
|
|
|
login: String,
|
|
|
|
|
old_password: String,
|
|
|
|
|
#[validate(length(min = 1, message = "Enter new password"),
|
|
|
|
|
must_match(other = "password_ver", message = "Passwords doesn't match"))]
|
|
|
|
|
password: String,
|
|
|
|
|
password_ver: String
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl PwdChange {
|
|
|
|
|
pub fn login(&self) -> &str {
|
|
|
|
|
&self.login
|
|
|
|
|
}
|
|
|
|
|
pub fn old_password(&self) -> &str {
|
|
|
|
|
&self.old_password
|
|
|
|
|
}
|
|
|
|
|
pub fn password(&self) -> &str {
|
|
|
|
|
&self.password
|
|
|
|
|
}
|
|
|
|
|
pub fn password_ver(&self) -> &str {
|
|
|
|
|
&self.password_ver
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-11 16:27:40 +01:00
|
|
|
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Default)]
|
|
|
|
|
#[cfg_attr(feature = "ssr", derive(sqlx::FromRow))]
|
|
|
|
|
pub struct OpeningHour {
|
|
|
|
|
id: i32,
|
|
|
|
|
pub day: i32,
|
|
|
|
|
pub from: NaiveTime,
|
|
|
|
|
pub to: NaiveTime,
|
|
|
|
|
pub discount: Option<i32>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl OpeningHour {
|
|
|
|
|
pub fn id(&self) -> i32 {
|
|
|
|
|
self.id
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
|
|
|
pub struct DayHours(pub Vec<DayHour>);
|
|
|
|
|
|
|
|
|
|
impl DayHours {
|
|
|
|
|
|
|
|
|
|
pub fn try_new(hours: &str) -> Result<Self, AppError> {
|
|
|
|
|
if hours.is_empty() {
|
|
|
|
|
return Ok(Self(Vec::new()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let times = hours.split(",")
|
|
|
|
|
.map(|h| h.trim())
|
|
|
|
|
.map(|h| DayHour::try_from(h))
|
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
|
|
|
|
|
|
if times.contains(&Err(AppError::HourParseError)) {
|
|
|
|
|
return Err(AppError::HourParseError)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(Self(times.into_iter().map(|h| h.unwrap()).collect()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn hours(&self) -> &Vec<DayHour> {
|
|
|
|
|
&self.0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ToString for DayHours {
|
|
|
|
|
fn to_string(&self) -> String {
|
|
|
|
|
if self.0.is_empty() {
|
|
|
|
|
return "".to_string()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.0.iter().map(|h| {
|
|
|
|
|
let discount = if let Some(d) = h.discount() {
|
|
|
|
|
format!(" ({})", d).to_string()
|
|
|
|
|
} else { "".to_string() };
|
|
|
|
|
format!("{} - {}{}", h.from().format("%H:%M"), h.to().format("%H:%M"), discount).to_string()})
|
|
|
|
|
.collect::<Vec<String>>()
|
|
|
|
|
.join(", ")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Eq, PartialEq, Serialize, Deserialize, Clone, Debug)]
|
|
|
|
|
pub struct DayHour {
|
|
|
|
|
from: NaiveTime,
|
|
|
|
|
to: NaiveTime,
|
|
|
|
|
discount: Option<i32>
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl DayHour {
|
|
|
|
|
pub fn new(from: NaiveTime, to: NaiveTime, discount: Option<i32>) -> Self {
|
|
|
|
|
Self { from, to, discount }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn from(&self) -> NaiveTime {
|
|
|
|
|
self.from
|
|
|
|
|
}
|
|
|
|
|
pub fn to(&self) -> NaiveTime {
|
|
|
|
|
self.to
|
|
|
|
|
}
|
|
|
|
|
pub fn discount(&self) -> Option<i32> {
|
|
|
|
|
self.discount
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TryFrom<String> for DayHour {
|
|
|
|
|
type Error = AppError;
|
|
|
|
|
|
|
|
|
|
fn try_from(value: String) -> Result<Self, Self::Error> {
|
|
|
|
|
value.as_str().try_into()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TryFrom<&str> for DayHour {
|
|
|
|
|
type Error = AppError;
|
|
|
|
|
|
|
|
|
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
|
|
|
|
if value.is_empty() {
|
|
|
|
|
return Err(AppError::HourParseError)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let times = value.split("-")
|
|
|
|
|
.map(|t| t.trim()).collect::<Vec<_>>();
|
|
|
|
|
|
|
|
|
|
if times.len() != 2 {
|
|
|
|
|
return Err(AppError::HourParseError)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let from = NaiveTime::parse_from_str(times.get(0).unwrap(), "%H:%M");
|
|
|
|
|
let to = NaiveTime::parse_from_str(times.get(1).unwrap(), "%H:%M");
|
|
|
|
|
|
|
|
|
|
if from.is_err() || to.is_err() {
|
|
|
|
|
return Err(AppError::HourParseError)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(DayHour {
|
|
|
|
|
from: from.unwrap(),
|
|
|
|
|
to: to.unwrap(),
|
|
|
|
|
discount: None
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn validate_hours(value: &WeekHours) -> Result<(), ValidationError> {
|
|
|
|
|
if value.hours().is_empty() {
|
|
|
|
|
return Ok(())
|
|
|
|
|
}
|
|
|
|
|
if let Ok(h) = DayHours::try_new(value.hours()) {
|
|
|
|
|
for hr in h.hours() {
|
|
|
|
|
if hr.from() >= hr.to() { return Err(ValidationError::new("TO_BEFORE_FROM")) }
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
} else {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
|
static ref RE_HOURS: Regex = Regex::new(r"^$|(^\d{2}:\d{2} ?- ?\d{2}:\d{2} ?(\(\d+\))?,? ?)+").unwrap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Serialize, Deserialize, Debug, Validate)]
|
|
|
|
|
#[validate(schema(function = "validate_hours", message = "Time 'to' must be after time 'from'"))]
|
|
|
|
|
pub struct WeekHours {
|
|
|
|
|
day: Weekday,
|
|
|
|
|
#[validate(regex(path = "RE_HOURS", message = "Hours must be in HH:MM - HH:MM format"))]
|
|
|
|
|
hours: String
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for WeekHours {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
day: Weekday::Mon,
|
|
|
|
|
hours: String::default()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl WeekHours {
|
|
|
|
|
pub fn new(day: Weekday, hours: Vec<DayHour>) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
day,
|
|
|
|
|
hours: DayHours(hours).to_string()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pub fn day(&self) -> Weekday {
|
|
|
|
|
self.day
|
|
|
|
|
}
|
|
|
|
|
pub fn hours(&self) -> &str {
|
|
|
|
|
&self.hours
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-09-22 21:26:13 +02:00
|
|
|
/*pub struct Property {
|
2023-08-24 22:06:37 +02:00
|
|
|
id: u16,
|
|
|
|
|
name: String,
|
|
|
|
|
description: String,
|
|
|
|
|
price: Decimal
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub enum MessageType {
|
|
|
|
|
NewReservation,
|
|
|
|
|
NewReservationCust,
|
|
|
|
|
ReservationApp,
|
|
|
|
|
ReservationCanceled,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct Message {
|
|
|
|
|
id: u16,
|
|
|
|
|
msg_type: MessageType,
|
|
|
|
|
subject: String,
|
|
|
|
|
text: String,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct Customer {
|
|
|
|
|
id: u128,
|
|
|
|
|
full_name: String,
|
|
|
|
|
email: String,
|
|
|
|
|
phone: String,
|
|
|
|
|
discount: u8
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub enum ReservationState {
|
|
|
|
|
New,
|
|
|
|
|
Approved,
|
|
|
|
|
Canceled,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct Reservation {
|
|
|
|
|
id: u128,
|
|
|
|
|
from: NaiveTime,
|
|
|
|
|
to: NaiveTime,
|
|
|
|
|
property: Property,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub struct ReservationSum {
|
|
|
|
|
id: u128,
|
|
|
|
|
uuid: Uuid,
|
|
|
|
|
date: NaiveDate,
|
|
|
|
|
items: Vec<Reservation>,
|
|
|
|
|
customer: Customer,
|
|
|
|
|
price: Decimal,
|
|
|
|
|
state: ReservationState,
|
2023-09-22 21:26:13 +02:00
|
|
|
}*/
|