Compare commits

...

2 Commits

23 changed files with 139 additions and 138 deletions

View File

@ -1,7 +1,7 @@
use std::sync::Mutex; use std::sync::Mutex;
use actix_web::{web, post, Responder, HttpResponse}; use actix_web::{web, post, Responder, HttpResponse};
use serde_json::json; use serde_json::json;
use crate::{State, models::administrator}; use crate::State;
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct LoginInfo { pub struct LoginInfo {

View File

@ -1,5 +1,5 @@
use std::sync::Mutex; use std::sync::Mutex;
use actix_web::{web, get, post, patch, delete, Responder, HttpResponse, HttpRequest}; use actix_web::{web, get, Responder, HttpResponse};
use crate::State; use crate::State;
#[get("/benchmark")] #[get("/benchmark")]

View File

@ -27,7 +27,7 @@ pub async fn get_cars(state: web::Data<Mutex<State>>, request: HttpRequest) -> i
} }
#[get("/{id}")] #[get("/{id}")]
pub async fn get_car(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn get_car(state: web::Data<Mutex<State>>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");
@ -73,7 +73,7 @@ pub async fn create_car(state: web::Data<Mutex<State>>, json: web::Json<BindingC
} }
#[patch("/{id}")] #[patch("/{id}")]
pub async fn update_car(state: web::Data<Mutex<State>>, json: web::Json<BindingCar>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn update_car(state: web::Data<Mutex<State>>, json: web::Json<BindingCar>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");
@ -96,7 +96,7 @@ pub async fn update_car(state: web::Data<Mutex<State>>, json: web::Json<BindingC
} }
#[delete("/{id}")] #[delete("/{id}")]
pub async fn delete_car(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn delete_car(state: web::Data<Mutex<State>>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");

View File

@ -27,7 +27,7 @@ pub async fn get_car_stations(state: web::Data<Mutex<State>>, request: HttpReque
} }
#[get("/{id}")] #[get("/{id}")]
pub async fn get_car_station(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn get_car_station(state: web::Data<Mutex<State>>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");
@ -73,7 +73,7 @@ pub async fn create_car_station(state: web::Data<Mutex<State>>, json: web::Json<
} }
#[patch("/{id}")] #[patch("/{id}")]
pub async fn update_car_station(state: web::Data<Mutex<State>>, json: web::Json<BindingCarStation>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn update_car_station(state: web::Data<Mutex<State>>, json: web::Json<BindingCarStation>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");
@ -96,7 +96,7 @@ pub async fn update_car_station(state: web::Data<Mutex<State>>, json: web::Json<
} }
#[delete("/{id}")] #[delete("/{id}")]
pub async fn delete_car_station(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn delete_car_station(state: web::Data<Mutex<State>>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");

View File

@ -27,7 +27,7 @@ pub async fn get_clients(state: web::Data<Mutex<State>>, request: HttpRequest) -
} }
#[get("/{id}")] #[get("/{id}")]
pub async fn get_client(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn get_client(state: web::Data<Mutex<State>>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");
@ -73,7 +73,7 @@ pub async fn create_client(state: web::Data<Mutex<State>>, json: web::Json<Bindi
} }
#[patch("/{id}")] #[patch("/{id}")]
pub async fn update_client(state: web::Data<Mutex<State>>, json: web::Json<BindingClient>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn update_client(state: web::Data<Mutex<State>>, json: web::Json<BindingClient>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");
@ -96,7 +96,7 @@ pub async fn update_client(state: web::Data<Mutex<State>>, json: web::Json<Bindi
} }
#[delete("/{id}")] #[delete("/{id}")]
pub async fn delete_client(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn delete_client(state: web::Data<Mutex<State>>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");

View File

@ -27,7 +27,7 @@ pub async fn get_owners(state: web::Data<Mutex<State>>, request: HttpRequest) ->
} }
#[get("/{id}")] #[get("/{id}")]
pub async fn get_owner(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn get_owner(state: web::Data<Mutex<State>>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");
@ -73,7 +73,7 @@ pub async fn create_owner(state: web::Data<Mutex<State>>, json: web::Json<Bindin
} }
#[patch("/{id}")] #[patch("/{id}")]
pub async fn update_owner(state: web::Data<Mutex<State>>, json: web::Json<BindingClient>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn update_owner(state: web::Data<Mutex<State>>, json: web::Json<BindingClient>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");
@ -96,7 +96,7 @@ pub async fn update_owner(state: web::Data<Mutex<State>>, json: web::Json<Bindin
} }
#[delete("/{id}")] #[delete("/{id}")]
pub async fn delete_owner(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn delete_owner(state: web::Data<Mutex<State>>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");

View File

@ -12,8 +12,8 @@ pub async fn get_rents(state: web::Data<Mutex<State>>, request: HttpRequest) ->
let token = token.unwrap(); let token = token.unwrap();
if let Ok(guard) = state.lock() { if let Ok(guard) = state.lock() {
if guard.auth_service.administrator_by_token(guard.administrator_repository.as_ref(), token.to_str().unwrap()).await.is_err() { if let Err(error) = guard.auth_service.administrator_by_token(guard.administrator_repository.as_ref(), token.to_str().unwrap()).await {
return HttpResponse::Unauthorized().body("Invalid token"); return HttpResponse::Unauthorized().body("Invalid token: ".to_owned() + error.as_str());
} }
} }
@ -27,7 +27,7 @@ pub async fn get_rents(state: web::Data<Mutex<State>>, request: HttpRequest) ->
} }
#[get("/{id}")] #[get("/{id}")]
pub async fn get_rent(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn get_rent(state: web::Data<Mutex<State>>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");
@ -73,7 +73,7 @@ pub async fn create_rent(state: web::Data<Mutex<State>>, json: web::Json<Binding
} }
#[patch("/{id}")] #[patch("/{id}")]
pub async fn update_rent(state: web::Data<Mutex<State>>, json: web::Json<BindingRent>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn update_rent(state: web::Data<Mutex<State>>, json: web::Json<BindingRent>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");
@ -96,7 +96,7 @@ pub async fn update_rent(state: web::Data<Mutex<State>>, json: web::Json<Binding
} }
#[delete("/{id}")] #[delete("/{id}")]
pub async fn delete_rent(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn delete_rent(state: web::Data<Mutex<State>>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");
@ -119,7 +119,7 @@ pub async fn delete_rent(state: web::Data<Mutex<State>>, path: web::Path<(i32, )
} }
#[get("/{id}/end")] #[get("/{id}/end")]
pub async fn end_rent(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder { pub async fn end_rent(state: web::Data<Mutex<State>>, path: web::Path<(String, )>, request: HttpRequest) -> impl Responder {
let token = request.headers().get("Authorization"); let token = request.headers().get("Authorization");
if token.is_none() { if token.is_none() {
return HttpResponse::Unauthorized().body("There is no token"); return HttpResponse::Unauthorized().body("There is no token");

View File

@ -2,11 +2,11 @@ use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Administrator { pub struct Administrator {
pub id: i32, pub id: String,
pub username: String, pub username: String,
pub password: String, pub password: String,
pub name: String, pub name: String,
pub surname: String, pub surname: String,
pub middlename: String, pub middlename: String,
pub car_station_id: i32 pub car_station_id: String
} }

View File

@ -3,12 +3,12 @@ use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Car { pub struct Car {
pub id: i32, pub id: String,
pub brand: String, pub brand: String,
pub model: String, pub model: String,
pub price: Decimal, pub price: Decimal,
pub owner_id: i32, pub owner_id: String,
pub car_station_id: i32 pub car_station_id: String
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@ -16,13 +16,13 @@ pub struct BindingCar {
pub brand: String, pub brand: String,
pub model: String, pub model: String,
pub price: Decimal, pub price: Decimal,
pub owner_id: i32, pub owner_id: String,
pub car_station_id: i32 pub car_station_id: String
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Report { pub struct Report {
pub car_id: i32, pub car_id: String,
pub brand: String, pub brand: String,
pub model: String, pub model: String,
pub times: i64, pub times: i64,

View File

@ -2,7 +2,7 @@ use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CarStation { pub struct CarStation {
pub id: i32, pub id: String,
pub address: String pub address: String
} }

View File

@ -2,7 +2,7 @@ use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Client { pub struct Client {
pub id: i32, pub id: String,
pub name: String, pub name: String,
pub surname: String, pub surname: String,
pub middlename: Option<String>, pub middlename: Option<String>,

View File

@ -2,16 +2,16 @@ use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Rent { pub struct Rent {
pub id: i32, pub id: String,
pub start_time: chrono::NaiveDateTime, pub start_time: chrono::NaiveDateTime,
pub time_amount: Option<i32>, pub time_amount: Option<i32>,
pub client_id: i32, pub client_id: String,
pub car_id: i32 pub car_id: String
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BindingRent { pub struct BindingRent {
pub time_amount: Option<i32>, pub time_amount: Option<i32>,
pub client_id: i32, pub client_id: String,
pub car_id: i32 pub car_id: String
} }

View File

@ -4,7 +4,7 @@ use sha2::Sha256;
use std::cell::RefCell; use std::cell::RefCell;
pub struct AuthService { pub struct AuthService {
authed: RefCell<Vec::<(String, i32)>> authed: RefCell<Vec::<(String, String)>>
} }
impl AuthService { impl AuthService {
@ -12,14 +12,14 @@ impl AuthService {
AuthService { authed: RefCell::new(Vec::new()) } AuthService { authed: RefCell::new(Vec::new()) }
} }
pub async fn login(&self, storage: &dyn AdministratorRepository, username: &str, password: &str) -> Result<(String, i32, i32), String> { pub async fn login(&self, storage: &dyn AdministratorRepository, username: &str, password: &str) -> Result<(String, String, String), String> {
let administrator = storage.find_by_username(&username).await?; let administrator = storage.find_by_username(&username).await?;
if pbkdf2::pbkdf2_hmac_array::<Sha256, 32>(password.as_bytes(), dotenv_codegen::dotenv!("SALT").as_bytes(), 4096).iter().map(|x| format!("{:x}", x)).collect::<String>() != administrator.password { if pbkdf2::pbkdf2_hmac_array::<Sha256, 32>(password.as_bytes(), dotenv_codegen::dotenv!("SALT").as_bytes(), 4096).iter().map(|x| format!("{:x}", x)).collect::<String>() != administrator.password {
Err("Invalid password or login!".to_owned()) Err("Invalid password or login!".to_owned())
} else { } else {
let token = nanoid!(32); let token = nanoid!(32);
self.authed.borrow_mut().push((token.clone(), administrator.id)); self.authed.borrow_mut().push((token.clone(), administrator.id.clone()));
Ok((token, administrator.id, administrator.car_station_id)) Ok((token, administrator.id.clone(), administrator.car_station_id))
} }
} }
@ -28,7 +28,7 @@ impl AuthService {
} }
pub async fn administrator_by_token(&self, storage: &dyn AdministratorRepository, token: &str) -> Result<Administrator, String> { pub async fn administrator_by_token(&self, storage: &dyn AdministratorRepository, token: &str) -> Result<Administrator, String> {
let id = self.authed.borrow().iter().find(|&x| x.0.starts_with(token)).ok_or("Invalid token")?.1; let id = self.authed.borrow().iter().find(|&x| x.0.starts_with(token)).ok_or("Invalid token")?.1.clone();
storage.read(id).await storage.read(id).await
} }
} }

View File

@ -1,2 +1,3 @@
pub mod traits; pub mod traits;
pub mod postgres; pub mod postgres;
pub mod mongo;

View File

View File

@ -10,21 +10,21 @@ pub struct PostgresAdministratorRepository {
#[async_trait] #[async_trait]
impl AdministratorRepository for PostgresAdministratorRepository { impl AdministratorRepository for PostgresAdministratorRepository {
async fn read(&self, id: i32) -> Result<Administrator, String> { async fn read(&self, id: String) -> Result<Administrator, String> {
let result = self.connection.query( let result = self.connection.query(
"SELECT * FROM administrator WHERE id = $1", &[&id] "SELECT * FROM administrator WHERE id = $1", &[&id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {
let row = rows.get(0).ok_or("Administrator not found".to_owned())?; let row = rows.get(0).ok_or("Administrator not found".to_owned())?;
Ok(Administrator { Ok(Administrator {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
username: row.get("username"), username: row.get("username"),
password: row.get("password"), password: row.get("password"),
name: row.get("name"), name: row.get("name"),
surname: row.get("surname"), surname: row.get("surname"),
middlename: row.get("middlename"), middlename: row.get("middlename"),
car_station_id: row.get("car_station_id") car_station_id: row.get::<&str, i32>("car_station_id").to_string()
}) })
} else { } else {
Err(result.unwrap_err().to_string()) Err(result.unwrap_err().to_string())
@ -37,13 +37,13 @@ impl AdministratorRepository for PostgresAdministratorRepository {
if let Ok(rows) = result { if let Ok(rows) = result {
let row = rows.get(0).ok_or("Administrator not found".to_owned())?; let row = rows.get(0).ok_or("Administrator not found".to_owned())?;
Ok(Administrator { Ok(Administrator {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
username: row.get("username"), username: row.get("username"),
password: row.get("password"), password: row.get("password"),
name: row.get("name"), name: row.get("name"),
surname: row.get("surname"), surname: row.get("surname"),
middlename: row.get("middlename"), middlename: row.get("middlename"),
car_station_id: row.get("car_station_id") car_station_id: row.get::<&str, i32>("car_station_id").to_string()
}) })
} else { } else {
Err(result.unwrap_err().to_string()) Err(result.unwrap_err().to_string())

View File

@ -36,7 +36,7 @@ impl BenchmarkRepository for PostgresBenchmarkRepository {
).await.unwrap().get(0).unwrap().get(0); ).await.unwrap().get(0).unwrap().get(0);
let str = format!("INSERT INTO Rent(car_id, client_id, start_time, time_amount) VALUES ({1}, {2}, now()::timestamp, {0}) RETURNING id", n, car_id, client_id); let str = format!("INSERT INTO Rent(car_id, client_id, start_time, time_amount) VALUES ({1}, {2}, now()::timestamp, {0}) RETURNING id", n, car_id, client_id);
let rent_id: i32 = self.connection.query( let _: i32 = self.connection.query(
&str, &str,
&[] &[]
).await.unwrap().get(0).unwrap().get(0); ).await.unwrap().get(0).unwrap().get(0);

View File

@ -14,38 +14,38 @@ impl CarRepository for PostgresCarRepository {
let result = self.connection.query( let result = self.connection.query(
"INSERT INTO Car(brand, model, price, owner_id, car_station_id) \ "INSERT INTO Car(brand, model, price, owner_id, car_station_id) \
VALUES ($1, $2, $3, $4, $5) RETURNING *", VALUES ($1, $2, $3, $4, $5) RETURNING *",
&[&car.brand, &car.model, &car.price, &car.owner_id, &car.car_station_id] &[&car.brand, &car.model, &car.price, &car.owner_id.parse::<i32>().unwrap(), &car.car_station_id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {
let row = rows.get(0).unwrap(); let row = rows.get(0).unwrap();
Ok(Car { Ok(Car {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
brand: row.get("brand"), brand: row.get("brand"),
model: row.get("model"), model: row.get("model"),
price: row.get("price"), price: row.get("price"),
owner_id: row.get("owner_id"), owner_id: row.get::<&str, i32>("owner_id").to_string(),
car_station_id: row.get("car_station_id") car_station_id: row.get::<&str, i32>("car_station_id").to_string()
}) })
} else { } else {
Err(result.unwrap_err().to_string()) Err(result.unwrap_err().to_string())
} }
} }
async fn read(&self, id: i32) -> Result<Car, String> { async fn read(&self, id: String) -> Result<Car, String> {
let result = self.connection.query( let result = self.connection.query(
"SELECT * FROM Car WHERE id = $1", &[&id] "SELECT * FROM Car WHERE id = $1", &[&id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {
let row = rows.get(0).ok_or("Car not found".to_owned())?; let row = rows.get(0).ok_or("Car not found".to_owned())?;
Ok(Car { Ok(Car {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
brand: row.get("brand"), brand: row.get("brand"),
model: row.get("model"), model: row.get("model"),
price: row.get("price"), price: row.get("price"),
owner_id: row.get("owner_id"), owner_id: row.get::<&str, i32>("owner_id").to_string(),
car_station_id: row.get("car_station_id") car_station_id: row.get::<&str, i32>("car_station_id").to_string()
}) })
} else { } else {
Err(result.unwrap_err().to_string()) Err(result.unwrap_err().to_string())
@ -60,12 +60,12 @@ impl CarRepository for PostgresCarRepository {
if let Ok(rows) = result { if let Ok(rows) = result {
Ok( Ok(
rows.into_iter().map(|r| Car { rows.into_iter().map(|r| Car {
id: r.get("id"), id: r.get::<&str, i32>("id").to_string(),
brand: r.get("brand"), brand: r.get("brand"),
model: r.get("model"), model: r.get("model"),
price: r.get("price"), price: r.get("price"),
owner_id: r.get("owner_id"), owner_id: r.get::<&str, i32>("owner_id").to_string(),
car_station_id: r.get("car_station_id") car_station_id: r.get::<&str, i32>("car_station_id").to_string()
}).collect() }).collect()
) )
} else { } else {
@ -73,31 +73,31 @@ impl CarRepository for PostgresCarRepository {
} }
} }
async fn update(&self, id: i32, car: BindingCar) -> Result<Car, String> { async fn update(&self, id: String, car: BindingCar) -> Result<Car, String> {
let result = self.connection.query( let result = self.connection.query(
"UPDATE Car SET brand = $1, model = $2, price = $3, owner_id = $4, car_station_id = $5 WHERE id = $6 RETURNING *", "UPDATE Car SET brand = $1, model = $2, price = $3, owner_id = $4, car_station_id = $5 WHERE id = $6 RETURNING *",
&[&car.brand, &car.model, &car.price, &car.owner_id, &car.car_station_id, &id] &[&car.brand, &car.model, &car.price, &car.owner_id.parse::<i32>().unwrap(), &car.car_station_id.parse::<i32>().unwrap(), &id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = &result { if let Ok(rows) = &result {
let row = rows.get(0).unwrap(); let row = rows.get(0).unwrap();
Ok(Car { Ok(Car {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
brand: row.get("brand"), brand: row.get("brand"),
model: row.get("model"), model: row.get("model"),
price: row.get("price"), price: row.get("price"),
owner_id: row.get("owner_id"), owner_id: row.get::<&str, i32>("owner_id").to_string(),
car_station_id: row.get("car_station_id") car_station_id: row.get::<&str, i32>("car_station_id").to_string()
}) })
} else { } else {
Err(result.unwrap_err().to_string()) Err(result.unwrap_err().to_string())
} }
} }
async fn delete(&self, id: i32) -> Result<(), String> { async fn delete(&self, id: String) -> Result<(), String> {
let result = self.connection.execute( let result = self.connection.execute(
"DELETE FROM Car WHERE id = $1", "DELETE FROM Car WHERE id = $1",
&[&id] &[&id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {
@ -129,7 +129,7 @@ impl CarRepository for PostgresCarRepository {
Ok( Ok(
rows.into_iter() rows.into_iter()
.map(|row| Report { .map(|row| Report {
car_id: row.get("car_id"), car_id: row.get::<&str, i32>("car_id").to_string(),
brand: row.get("brand"), brand: row.get("brand"),
model: row.get("model"), model: row.get("model"),
times: row.get("times"), times: row.get("times"),

View File

@ -19,7 +19,7 @@ impl CarStationRepository for PostgresCarStationRepository {
if let Ok(rows) = result { if let Ok(rows) = result {
let row = rows.get(0).unwrap(); let row = rows.get(0).unwrap();
Ok(CarStation { Ok(CarStation {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
address: row.get("address") address: row.get("address")
}) })
} else { } else {
@ -27,15 +27,15 @@ impl CarStationRepository for PostgresCarStationRepository {
} }
} }
async fn read(&self, id: i32) -> Result<CarStation, String> { async fn read(&self, id: String) -> Result<CarStation, String> {
let result = self.connection.query( let result = self.connection.query(
"SELECT * FROM Car_Station WHERE id = $1", &[&id] "SELECT * FROM Car_Station WHERE id = $1", &[&id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {
let row = rows.get(0).ok_or("CarStation not found".to_owned())?; let row = rows.get(0).ok_or("CarStation not found".to_owned())?;
Ok(CarStation { Ok(CarStation {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
address: row.get("address") address: row.get("address")
}) })
} else { } else {
@ -51,7 +51,7 @@ impl CarStationRepository for PostgresCarStationRepository {
if let Ok(rows) = result { if let Ok(rows) = result {
Ok( Ok(
rows.into_iter().map(|r| CarStation { rows.into_iter().map(|r| CarStation {
id: r.get("id"), id: r.get::<&str, i32>("id").to_string(),
address: r.get("address") address: r.get("address")
}).collect() }).collect()
) )
@ -60,16 +60,16 @@ impl CarStationRepository for PostgresCarStationRepository {
} }
} }
async fn update(&self, id: i32, car_station: BindingCarStation) -> Result<CarStation, String> { async fn update(&self, id: String, car_station: BindingCarStation) -> Result<CarStation, String> {
let result = self.connection.query( let result = self.connection.query(
"UPDATE Car_Station SET address = $1 WHERE id = $2 RETURNING *", "UPDATE Car_Station SET address = $1 WHERE id = $2 RETURNING *",
&[&car_station.address, &id] &[&car_station.address, &id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {
let row = rows.get(0).unwrap(); let row = rows.get(0).unwrap();
Ok(CarStation { Ok(CarStation {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
address: row.get("address") address: row.get("address")
}) })
} else { } else {
@ -77,10 +77,10 @@ impl CarStationRepository for PostgresCarStationRepository {
} }
} }
async fn delete(&self, id: i32) -> Result<(), String> { async fn delete(&self, id: String) -> Result<(), String> {
let result = self.connection.execute( let result = self.connection.execute(
"DELETE FROM Car_Station WHERE id = $1", "DELETE FROM Car_Station WHERE id = $1",
&[&id] &[&id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {

View File

@ -20,7 +20,7 @@ impl ClientRepository for PostgresClientRepository {
if let Ok(rows) = &result { if let Ok(rows) = &result {
let row = rows.get(0).unwrap(); let row = rows.get(0).unwrap();
Ok(Client { Ok(Client {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
name: row.get("name"), name: row.get("name"),
surname: row.get("surname"), surname: row.get("surname"),
middlename: row.get("middlename"), middlename: row.get("middlename"),
@ -31,16 +31,16 @@ impl ClientRepository for PostgresClientRepository {
} }
} }
async fn read(&self, id: i32) -> Result<Client, String> { async fn read(&self, id: String) -> Result<Client, String> {
let result= self.connection.query( let result= self.connection.query(
"SELECT * FROM Client WHERE id = $1", &[&id] "SELECT * FROM Client WHERE id = $1", &[&id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {
let row = rows.get(0).ok_or("Client not found".to_owned())?; let row = rows.get(0).ok_or("Client not found".to_owned())?;
Ok(Client { Ok(Client {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
name: row.get("name"), name: row.get("name"),
surname: row.get("surname"), surname: row.get("surname"),
middlename: row.get("middlename"), middlename: row.get("middlename"),
@ -59,7 +59,7 @@ impl ClientRepository for PostgresClientRepository {
if let Ok(rows) = result { if let Ok(rows) = result {
Ok( Ok(
rows.into_iter().map(|r| Client { rows.into_iter().map(|r| Client {
id: r.get("id"), id: r.get::<&str, i32>("id").to_string(),
name: r.get("name"), name: r.get("name"),
surname: r.get("surname"), surname: r.get("surname"),
middlename: r.get("middlename"), middlename: r.get("middlename"),
@ -71,17 +71,17 @@ impl ClientRepository for PostgresClientRepository {
} }
} }
async fn update(&self, id: i32, client: BindingClient) -> Result<Client, String> { async fn update(&self, id: String, client: BindingClient) -> Result<Client, String> {
let result = self.connection.query( let result = self.connection.query(
"UPDATE Client SET name = $1, surname = $2, middlename = $3, phone = $4 \ "UPDATE Client SET name = $1, surname = $2, middlename = $3, phone = $4 \
WHERE id = $5 RETURNING *", WHERE id = $5 RETURNING *",
&[&client.name, &client.surname, &client.middlename, &client.phone, &id] &[&client.name, &client.surname, &client.middlename, &client.phone, &id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {
let row = rows.get(0).unwrap(); let row = rows.get(0).unwrap();
Ok(Client { Ok(Client {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
name: row.get("name"), name: row.get("name"),
surname: row.get("surname"), surname: row.get("surname"),
middlename: row.get("middlename"), middlename: row.get("middlename"),
@ -92,10 +92,10 @@ impl ClientRepository for PostgresClientRepository {
} }
} }
async fn delete(&self, id: i32) -> Result<(), String> { async fn delete(&self, id: String) -> Result<(), String> {
let result = self.connection.execute( let result = self.connection.execute(
"DELETE FROM Client WHERE id = $1", "DELETE FROM Client WHERE id = $1",
&[&id] &[&id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {

View File

@ -20,7 +20,7 @@ impl OwnerRepository for PostgresOwnerRepository {
if let Ok(rows) = &result { if let Ok(rows) = &result {
let row = rows.get(0).unwrap(); let row = rows.get(0).unwrap();
Ok(Client { Ok(Client {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
name: row.get("name"), name: row.get("name"),
surname: row.get("surname"), surname: row.get("surname"),
middlename: row.get("middlename"), middlename: row.get("middlename"),
@ -31,16 +31,16 @@ impl OwnerRepository for PostgresOwnerRepository {
} }
} }
async fn read(&self, id: i32) -> Result<Client, String> { async fn read(&self, id: String) -> Result<Client, String> {
let result= self.connection.query( let result= self.connection.query(
"SELECT * FROM Owner WHERE id = $1", &[&id] "SELECT * FROM Owner WHERE id = $1", &[&id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {
let row = rows.get(0).ok_or("Owner not found".to_owned())?; let row = rows.get(0).ok_or("Owner not found".to_owned())?;
Ok(Client { Ok(Client {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
name: row.get("name"), name: row.get("name"),
surname: row.get("surname"), surname: row.get("surname"),
middlename: row.get("middlename"), middlename: row.get("middlename"),
@ -59,7 +59,7 @@ impl OwnerRepository for PostgresOwnerRepository {
if let Ok(rows) = result { if let Ok(rows) = result {
Ok( Ok(
rows.into_iter().map(|r| Client { rows.into_iter().map(|r| Client {
id: r.get("id"), id: r.get::<&str, i32>("id").to_string(),
name: r.get("name"), name: r.get("name"),
surname: r.get("surname"), surname: r.get("surname"),
middlename: r.get("middlename"), middlename: r.get("middlename"),
@ -71,17 +71,17 @@ impl OwnerRepository for PostgresOwnerRepository {
} }
} }
async fn update(&self, id: i32, client: BindingClient) -> Result<Client, String> { async fn update(&self, id: String, client: BindingClient) -> Result<Client, String> {
let result = self.connection.query( let result = self.connection.query(
"UPDATE Owner SET name = $1, surname = $2, middlename = $3, phone = $4 \ "UPDATE Owner SET name = $1, surname = $2, middlename = $3, phone = $4 \
WHERE id = $5 RETURNING *", WHERE id = $5 RETURNING *",
&[&client.name, &client.surname, &client.middlename, &client.phone, &id] &[&client.name, &client.surname, &client.middlename, &client.phone, &id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {
let row = rows.get(0).unwrap(); let row = rows.get(0).unwrap();
Ok(Client { Ok(Client {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
name: row.get("name"), name: row.get("name"),
surname: row.get("surname"), surname: row.get("surname"),
middlename: row.get("middlename"), middlename: row.get("middlename"),
@ -92,10 +92,10 @@ impl OwnerRepository for PostgresOwnerRepository {
} }
} }
async fn delete(&self, id: i32) -> Result<(), String> { async fn delete(&self, id: String) -> Result<(), String> {
let result = self.connection.execute( let result = self.connection.execute(
"DELETE FROM Owner WHERE id = $1", "DELETE FROM Owner WHERE id = $1",
&[&id] &[&id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {

View File

@ -13,7 +13,7 @@ impl RentRepository for PostgresRentRepository {
async fn create(&self, rent: BindingRent) -> Result<Rent, String> { async fn create(&self, rent: BindingRent) -> Result<Rent, String> {
let query_result = self.connection.query( let query_result = self.connection.query(
"SELECT * FROM Rent WHERE car_id=$1 AND time_amount IS NULL", "SELECT * FROM Rent WHERE car_id=$1 AND time_amount IS NULL",
&[&rent.car_id] &[&rent.car_id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = query_result { if let Ok(rows) = query_result {
@ -27,36 +27,36 @@ impl RentRepository for PostgresRentRepository {
let result = self.connection.query( let result = self.connection.query(
"INSERT INTO Rent(time_amount, client_id, car_id) \ "INSERT INTO Rent(time_amount, client_id, car_id) \
VALUES ($1, $2, $3) RETURNING *", VALUES ($1, $2, $3) RETURNING *",
&[&rent.time_amount, &rent.client_id, &rent.car_id] &[&rent.time_amount, &rent.client_id.parse::<i32>().unwrap(), &rent.car_id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {
let row = rows.get(0).unwrap(); let row = rows.get(0).unwrap();
Ok(Rent { Ok(Rent {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
start_time: row.get("start_time"), start_time: row.get("start_time"),
time_amount: row.get("time_amount"), time_amount: row.get("time_amount"),
client_id: row.get("client_id"), client_id: row.get::<&str, i32>("client_id").to_string(),
car_id: row.get("car_id") car_id: row.get::<&str, i32>("car_id").to_string()
}) })
} else { } else {
Err(result.unwrap_err().to_string()) Err(result.unwrap_err().to_string())
} }
} }
async fn read(&self, id: i32) -> Result<Rent, String> { async fn read(&self, id: String) -> Result<Rent, String> {
let result = self.connection.query( let result = self.connection.query(
"SELECT * FROM Rent WHERE id = $1", &[&id] "SELECT * FROM Rent WHERE id = $1", &[&id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {
let row = rows.get(0).ok_or("Rent not found".to_owned())?; let row = rows.get(0).ok_or("Rent not found".to_owned())?;
Ok(Rent { Ok(Rent {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
start_time: row.get("start_time"), start_time: row.get("start_time"),
time_amount: row.get("time_amount"), time_amount: row.get("time_amount"),
client_id: row.get("client_id"), client_id: row.get::<&str, i32>("client_id").to_string(),
car_id: row.get("car_id") car_id: row.get::<&str, i32>("car_id").to_string()
}) })
} else { } else {
Err(result.unwrap_err().to_string()) Err(result.unwrap_err().to_string())
@ -71,11 +71,11 @@ impl RentRepository for PostgresRentRepository {
if let Ok(rows) = result { if let Ok(rows) = result {
Ok( Ok(
rows.into_iter().map(|r| Rent { rows.into_iter().map(|r| Rent {
id: r.get("id"), id: r.get::<&str, i32>("id").to_string(),
start_time: r.get("start_time"), start_time: r.get("start_time"),
time_amount: r.get("time_amount"), time_amount: r.get("time_amount"),
client_id: r.get("client_id"), client_id: r.get::<&str, i32>("client_id").to_string(),
car_id: r.get("car_id") car_id: r.get::<&str, i32>("car_id").to_string()
}).collect() }).collect()
) )
} else { } else {
@ -83,29 +83,29 @@ impl RentRepository for PostgresRentRepository {
} }
} }
async fn update(&self, id: i32, rent: BindingRent) -> Result<Rent, String> { async fn update(&self, id: String, rent: BindingRent) -> Result<Rent, String> {
let result = self.connection.query( let result = self.connection.query(
"UPDATE Rent SET time_amount = $2, client_id = $3, car_id = $4 WHERE id = $5 RETURNING *", "UPDATE Rent SET time_amount = $2, client_id = $3, car_id = $4 WHERE id = $5 RETURNING *",
&[&rent.time_amount, &rent.client_id, &rent.car_id, &id] &[&rent.time_amount, &rent.client_id.parse::<i32>().unwrap(), &rent.car_id.parse::<i32>().unwrap(), &id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(rows) = result { if let Ok(rows) = result {
let row = rows.get(0).unwrap(); let row = rows.get(0).unwrap();
Ok(Rent { Ok(Rent {
id: row.get("id"), id: row.get::<&str, i32>("id").to_string(),
start_time: row.get("start_time"), start_time: row.get("start_time"),
time_amount: row.get("time_amount"), time_amount: row.get("time_amount"),
client_id: row.get("client_id"), client_id: row.get::<&str, i32>("client_id").to_string(),
car_id: row.get("car_id") car_id: row.get::<&str, i32>("car_id").to_string()
}) })
} else { } else {
Err(result.unwrap_err().to_string()) Err(result.unwrap_err().to_string())
} }
} }
async fn delete(&self, id: i32) -> Result<(), String> { async fn delete(&self, id: String) -> Result<(), String> {
let result = self.connection.execute( let result = self.connection.execute(
"DELETE FROM Rent WHERE id = $1", &[&id] "DELETE FROM Rent WHERE id = $1", &[&id.parse::<i32>().unwrap()]
).await; ).await;
if let Ok(_) = result { if let Ok(_) = result {
@ -115,8 +115,8 @@ impl RentRepository for PostgresRentRepository {
} }
} }
async fn end_rent(&self, id: i32) -> Result<(), String> { async fn end_rent(&self, id: String) -> Result<(), String> {
let current_rent = self.read(id).await?; let current_rent = self.read(id.clone()).await?;
if current_rent.time_amount.is_some() { if current_rent.time_amount.is_some() {
return Err("Rent is already ended".to_owned()); return Err("Rent is already ended".to_owned());
@ -124,7 +124,7 @@ impl RentRepository for PostgresRentRepository {
let time_amount = (self.connection.query("SELECT now()::timestamp", &[]).await.unwrap().get(0).unwrap().get::<usize, chrono::NaiveDateTime>(0) - current_rent.start_time).num_minutes() as i32; let time_amount = (self.connection.query("SELECT now()::timestamp", &[]).await.unwrap().get(0).unwrap().get::<usize, chrono::NaiveDateTime>(0) - current_rent.start_time).num_minutes() as i32;
match self.connection.execute("UPDATE Rent SET time_amount = $2 WHERE id = $1", &[&id, &time_amount]).await { match self.connection.execute("UPDATE Rent SET time_amount = $2 WHERE id = $1", &[&id.parse::<i32>().unwrap(), &time_amount]).await {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(err) => Err(err.to_string()) Err(err) => Err(err.to_string())
} }

View File

@ -8,53 +8,53 @@ use async_trait::async_trait;
#[async_trait] #[async_trait]
pub trait ClientRepository { pub trait ClientRepository {
async fn create(&self, client: BindingClient) -> Result<Client, String>; async fn create(&self, client: BindingClient) -> Result<Client, String>;
async fn read(&self, id: i32) -> Result<Client, String>; async fn read(&self, id: String) -> Result<Client, String>;
async fn read_all(&self) -> Result<Vec<Client>, String>; async fn read_all(&self) -> Result<Vec<Client>, String>;
async fn update(&self, id: i32, client: BindingClient) -> Result<Client, String>; async fn update(&self, id: String, client: BindingClient) -> Result<Client, String>;
async fn delete(&self, id: i32) -> Result<(), String>; async fn delete(&self, id: String) -> Result<(), String>;
} }
#[async_trait] #[async_trait]
pub trait CarRepository { pub trait CarRepository {
async fn create(&self, car: BindingCar) -> Result<Car, String>; async fn create(&self, car: BindingCar) -> Result<Car, String>;
async fn read(&self, id: i32) -> Result<Car, String>; async fn read(&self, id: String) -> Result<Car, String>;
async fn read_all(&self) -> Result<Vec<Car>, String>; async fn read_all(&self) -> Result<Vec<Car>, String>;
async fn update(&self, id: i32, car: BindingCar) -> Result<Car, String>; async fn update(&self, id: String, car: BindingCar) -> Result<Car, String>;
async fn delete(&self, id: i32) -> Result<(), String>; async fn delete(&self, id: String) -> Result<(), String>;
async fn get_report(&self) -> Result<Vec<Report>, String>; async fn get_report(&self) -> Result<Vec<Report>, String>;
} }
#[async_trait] #[async_trait]
pub trait CarStationRepository { pub trait CarStationRepository {
async fn create(&self, car_station: BindingCarStation) -> Result<CarStation, String>; async fn create(&self, car_station: BindingCarStation) -> Result<CarStation, String>;
async fn read(&self, id: i32) -> Result<CarStation, String>; async fn read(&self, id: String) -> Result<CarStation, String>;
async fn read_all(&self) -> Result<Vec<CarStation>, String>; async fn read_all(&self) -> Result<Vec<CarStation>, String>;
async fn update(&self, id: i32, car_station: BindingCarStation) -> Result<CarStation, String>; async fn update(&self, id: String, car_station: BindingCarStation) -> Result<CarStation, String>;
async fn delete(&self, id: i32) -> Result<(), String>; async fn delete(&self, id: String) -> Result<(), String>;
} }
#[async_trait] #[async_trait]
pub trait RentRepository { pub trait RentRepository {
async fn create(&self, rent: BindingRent) -> Result<Rent, String>; async fn create(&self, rent: BindingRent) -> Result<Rent, String>;
async fn read(&self, id: i32) -> Result<Rent, String>; async fn read(&self, id: String) -> Result<Rent, String>;
async fn read_all(&self) -> Result<Vec<Rent>, String>; async fn read_all(&self) -> Result<Vec<Rent>, String>;
async fn update(&self, id: i32, rent: BindingRent) -> Result<Rent, String>; async fn update(&self, id: String, rent: BindingRent) -> Result<Rent, String>;
async fn delete(&self, id: i32) -> Result<(), String>; async fn delete(&self, id: String) -> Result<(), String>;
async fn end_rent(&self, id: i32) -> Result<(), String>; async fn end_rent(&self, id: String) -> Result<(), String>;
} }
#[async_trait] #[async_trait]
pub trait OwnerRepository { pub trait OwnerRepository {
async fn create(&self, client: BindingClient) -> Result<Client, String>; async fn create(&self, client: BindingClient) -> Result<Client, String>;
async fn read(&self, id: i32) -> Result<Client, String>; async fn read(&self, id: String) -> Result<Client, String>;
async fn read_all(&self) -> Result<Vec<Client>, String>; async fn read_all(&self) -> Result<Vec<Client>, String>;
async fn update(&self, id: i32, client: BindingClient) -> Result<Client, String>; async fn update(&self, id: String, client: BindingClient) -> Result<Client, String>;
async fn delete(&self, id: i32) -> Result<(), String>; async fn delete(&self, id: String) -> Result<(), String>;
} }
#[async_trait] #[async_trait]
pub trait AdministratorRepository { pub trait AdministratorRepository {
async fn read(&self, id: i32) -> Result<Administrator, String>; async fn read(&self, id: String) -> Result<Administrator, String>;
async fn find_by_username(&self, username: &str) -> Result<Administrator, String>; async fn find_by_username(&self, username: &str) -> Result<Administrator, String>;
} }