From 202f9711ef519a9cc80c67730357c5e0cfbd847d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A1=D0=B5=D1=80=D0=B3=D0=B5=D0=B9=20=D0=9F=D0=BE=D0=BB?=
 =?UTF-8?q?=D0=B5=D0=B2=D0=BE=D0=B9?= <sergpolevoi@yandex.ru>
Date: Wed, 10 May 2023 22:02:30 +0400
Subject: [PATCH 1/2] =?UTF-8?q?=D0=91=D1=8D=D0=BA=D0=B5=D0=BD=D0=B4:=20?=
 =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D1=8B=20=D0=B0?=
 =?UTF-8?q?=D0=B4=D0=BC=D0=B8=D0=BD=D0=B8=D1=81=D1=82=D1=80=D0=B0=D1=82?=
 =?UTF-8?q?=D0=BE=D1=80=D1=8B=20=D0=B8=20=D0=B0=D0=B2=D1=82=D0=BE=D1=80?=
 =?UTF-8?q?=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D1=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 backend/Cargo.lock                            | 22 +++++
 backend/Cargo.toml                            |  5 +-
 backend/src/endpoints/auth.rs                 | 28 ++++++
 backend/src/endpoints/car.rs                  | 72 ++++++++++++--
 backend/src/endpoints/car_station.rs          | 72 ++++++++++++--
 backend/src/endpoints/client.rs               | 72 ++++++++++++--
 backend/src/endpoints/mod.rs                  |  3 +-
 backend/src/endpoints/owner.rs                | 72 ++++++++++++--
 backend/src/endpoints/rent.rs                 | 72 ++++++++++++--
 backend/src/lib.rs                            |  8 +-
 backend/src/main.rs                           | 98 +++++++++++--------
 backend/src/models/administrator.rs           | 12 +++
 backend/src/models/mod.rs                     |  3 +-
 backend/src/services/auth.rs                  | 34 +++++++
 backend/src/services/mod.rs                   |  1 +
 .../src/storages/postgres/administrator.rs    | 52 ++++++++++
 backend/src/storages/postgres/car.rs          |  6 +-
 backend/src/storages/postgres/car_station.rs  |  6 +-
 backend/src/storages/postgres/client.rs       |  6 +-
 backend/src/storages/postgres/mod.rs          |  3 +-
 backend/src/storages/postgres/owner.rs        |  6 +-
 backend/src/storages/postgres/rent.rs         |  6 +-
 backend/src/storages/traits.rs                | 37 ++++---
 23 files changed, 587 insertions(+), 109 deletions(-)
 create mode 100644 backend/src/endpoints/auth.rs
 create mode 100644 backend/src/models/administrator.rs
 create mode 100644 backend/src/services/auth.rs
 create mode 100644 backend/src/services/mod.rs
 create mode 100644 backend/src/storages/postgres/administrator.rs

diff --git a/backend/Cargo.lock b/backend/Cargo.lock
index 57cf057..94a776e 100644
--- a/backend/Cargo.lock
+++ b/backend/Cargo.lock
@@ -271,8 +271,11 @@ dependencies = [
  "chrono",
  "dotenv",
  "dotenv_codegen",
+ "nanoid",
+ "pbkdf2",
  "serde",
  "serde_json",
+ "sha2",
  "tokio",
  "tokio-postgres",
 ]
@@ -884,6 +887,15 @@ dependencies = [
  "windows-sys",
 ]
 
+[[package]]
+name = "nanoid"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ffa00dec017b5b1a8b7cf5e2c008bfda1aa7e0697ac1508b491fdf2622fb4d8"
+dependencies = [
+ "rand",
+]
+
 [[package]]
 name = "num-integer"
 version = "0.1.45"
@@ -948,6 +960,16 @@ version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
 
+[[package]]
+name = "pbkdf2"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0ca0b5a68607598bf3bad68f32227a8164f6254833f84eafaac409cd6746c31"
+dependencies = [
+ "digest",
+ "hmac",
+]
+
 [[package]]
 name = "percent-encoding"
 version = "2.2.0"
diff --git a/backend/Cargo.toml b/backend/Cargo.toml
index 3f2713e..535aa0c 100644
--- a/backend/Cargo.toml
+++ b/backend/Cargo.toml
@@ -14,4 +14,7 @@ chrono = { version = "0.4.24", features = ["serde"] }
 serde_json = "1.0"
 serde = { version = "1.0.159", features = ["derive"] }
 async-trait = "0.1.68"
-dotenv_codegen = "0.15.0"
\ No newline at end of file
+dotenv_codegen = "0.15.0"
+pbkdf2 = "0.12.1"
+nanoid = "0.4.0"
+sha2 = "0.10.6"
\ No newline at end of file
diff --git a/backend/src/endpoints/auth.rs b/backend/src/endpoints/auth.rs
new file mode 100644
index 0000000..38b28c6
--- /dev/null
+++ b/backend/src/endpoints/auth.rs
@@ -0,0 +1,28 @@
+use std::sync::Mutex;
+use actix_web::{web, post, Responder, HttpResponse};
+use crate::State;
+
+#[derive(serde::Deserialize)]
+pub struct LoginInfo {
+    username: String,
+    password: String
+}
+
+#[post("/login")]
+pub async fn login(state: web::Data<Mutex<State>>, json: web::Json<LoginInfo>) -> impl Responder {
+    match state.lock() {
+        Ok(guard) => match guard.auth_service.login(guard.administrator_repository.as_ref(), &json.username, &json.password).await {
+            Ok(token) => HttpResponse::Ok().json(token),
+            Err(error) => HttpResponse::InternalServerError().json(error.to_string())
+        },
+        Err(error) => HttpResponse::InternalServerError().json(error.to_string())
+    }
+}
+
+#[post("/logout")]
+pub async fn logout(state: web::Data<Mutex<State>>, json: web::Json<String>) -> impl Responder {
+    match state.lock() {
+        Ok(guard) => { guard.auth_service.logout(&json.0); HttpResponse::Ok().body("Success") },
+        Err(error) => HttpResponse::InternalServerError().json(error.to_string())
+    }
+}
\ No newline at end of file
diff --git a/backend/src/endpoints/car.rs b/backend/src/endpoints/car.rs
index 4b4c510..b9a49bb 100644
--- a/backend/src/endpoints/car.rs
+++ b/backend/src/endpoints/car.rs
@@ -1,10 +1,22 @@
 use std::sync::Mutex;
 use crate::models::car::*;
-use actix_web::{web, get, post, patch, delete, Responder, HttpResponse};
+use actix_web::{web, get, post, patch, delete, Responder, HttpResponse, HttpRequest};
 use crate::State;
 
 #[get("/")]
-pub async fn get_cars(state: web::Data<Mutex<State>>) -> impl Responder {
+pub async fn get_cars(state: web::Data<Mutex<State>>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.car_repository.read_all().await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -15,7 +27,19 @@ pub async fn get_cars(state: web::Data<Mutex<State>>) -> impl Responder {
 }
 
 #[get("/{id}")]
-pub async fn get_car(state: web::Data<Mutex<State>>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn get_car(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.car_repository.read(path.into_inner().0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -26,7 +50,19 @@ pub async fn get_car(state: web::Data<Mutex<State>>, path: web::Path<(u32, )>) -
 }
 
 #[post("/")]
-pub async fn create_car(state: web::Data<Mutex<State>>, json: web::Json<BindingCar>) -> impl Responder {
+pub async fn create_car(state: web::Data<Mutex<State>>, json: web::Json<BindingCar>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.car_repository.create(json.0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -37,7 +73,19 @@ pub async fn create_car(state: web::Data<Mutex<State>>, json: web::Json<BindingC
 }
 
 #[patch("/{id}")]
-pub async fn update_car(state: web::Data<Mutex<State>>, json: web::Json<BindingCar>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn update_car(state: web::Data<Mutex<State>>, json: web::Json<BindingCar>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.car_repository.update(path.into_inner().0, json.0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -48,7 +96,19 @@ pub async fn update_car(state: web::Data<Mutex<State>>, json: web::Json<BindingC
 }
 
 #[delete("/{id}")]
-pub async fn delete_car(state: web::Data<Mutex<State>>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn delete_car(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.car_repository.delete(path.into_inner().0).await {
             Ok(result) => HttpResponse::Ok().json(result),
diff --git a/backend/src/endpoints/car_station.rs b/backend/src/endpoints/car_station.rs
index 36b3d8e..a9caa11 100644
--- a/backend/src/endpoints/car_station.rs
+++ b/backend/src/endpoints/car_station.rs
@@ -1,10 +1,22 @@
 use std::sync::Mutex;
 use crate::models::car_station::*;
-use actix_web::{web, get, post, patch, delete, Responder, HttpResponse};
+use actix_web::{web, get, post, patch, delete, Responder, HttpResponse, HttpRequest};
 use crate::State;
 
 #[get("/")]
-pub async fn get_car_stations(state: web::Data<Mutex<State>>) -> impl Responder {
+pub async fn get_car_stations(state: web::Data<Mutex<State>>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+
     match state.lock() {
         Ok(guard) => match guard.car_station_repository.read_all().await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -15,7 +27,19 @@ pub async fn get_car_stations(state: web::Data<Mutex<State>>) -> impl Responder
 }
 
 #[get("/{id}")]
-pub async fn get_car_station(state: web::Data<Mutex<State>>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn get_car_station(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+
     match state.lock() {
         Ok(guard) => match guard.car_station_repository.read(path.into_inner().0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -26,7 +50,19 @@ pub async fn get_car_station(state: web::Data<Mutex<State>>, path: web::Path<(u3
 }
 
 #[post("/")]
-pub async fn create_car_station(state: web::Data<Mutex<State>>, json: web::Json<BindingCarStation>) -> impl Responder {
+pub async fn create_car_station(state: web::Data<Mutex<State>>, json: web::Json<BindingCarStation>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.car_station_repository.create(json.0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -37,7 +73,19 @@ pub async fn create_car_station(state: web::Data<Mutex<State>>, json: web::Json<
 }
 
 #[patch("/{id}")]
-pub async fn update_car_station(state: web::Data<Mutex<State>>, json: web::Json<BindingCarStation>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn update_car_station(state: web::Data<Mutex<State>>, json: web::Json<BindingCarStation>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.car_station_repository.update(path.into_inner().0, json.0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -48,7 +96,19 @@ pub async fn update_car_station(state: web::Data<Mutex<State>>, json: web::Json<
 }
 
 #[delete("/{id}")]
-pub async fn delete_car_station(state: web::Data<Mutex<State>>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn delete_car_station(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.car_station_repository.delete(path.into_inner().0).await {
             Ok(result) => HttpResponse::Ok().json(result),
diff --git a/backend/src/endpoints/client.rs b/backend/src/endpoints/client.rs
index d85a862..d1cc189 100644
--- a/backend/src/endpoints/client.rs
+++ b/backend/src/endpoints/client.rs
@@ -1,10 +1,22 @@
 use std::sync::Mutex;
 use crate::models::client::*;
-use actix_web::{web, get, post, patch, delete, Responder, HttpResponse};
+use actix_web::{web, get, post, patch, delete, Responder, HttpResponse, HttpRequest};
 use crate::State;
 
 #[get("/")]
-pub async fn get_clients(state: web::Data<Mutex<State>>) -> impl Responder {
+pub async fn get_clients(state: web::Data<Mutex<State>>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.client_repository.read_all().await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -15,7 +27,19 @@ pub async fn get_clients(state: web::Data<Mutex<State>>) -> impl Responder {
 }
 
 #[get("/{id}")]
-pub async fn get_client(state: web::Data<Mutex<State>>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn get_client(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.client_repository.read(path.into_inner().0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -26,7 +50,19 @@ pub async fn get_client(state: web::Data<Mutex<State>>, path: web::Path<(u32, )>
 }
 
 #[post("/")]
-pub async fn create_client(state: web::Data<Mutex<State>>, json: web::Json<BindingClient>) -> impl Responder {
+pub async fn create_client(state: web::Data<Mutex<State>>, json: web::Json<BindingClient>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.client_repository.create(json.0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -37,7 +73,19 @@ pub async fn create_client(state: web::Data<Mutex<State>>, json: web::Json<Bindi
 }
 
 #[patch("/{id}")]
-pub async fn update_client(state: web::Data<Mutex<State>>, json: web::Json<BindingClient>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn update_client(state: web::Data<Mutex<State>>, json: web::Json<BindingClient>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.client_repository.update(path.into_inner().0, json.0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -48,7 +96,19 @@ pub async fn update_client(state: web::Data<Mutex<State>>, json: web::Json<Bindi
 }
 
 #[delete("/{id}")]
-pub async fn delete_client(state: web::Data<Mutex<State>>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn delete_client(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.client_repository.delete(path.into_inner().0).await {
             Ok(result) => HttpResponse::Ok().json(result),
diff --git a/backend/src/endpoints/mod.rs b/backend/src/endpoints/mod.rs
index 2c3aab9..d4fcc35 100644
--- a/backend/src/endpoints/mod.rs
+++ b/backend/src/endpoints/mod.rs
@@ -2,4 +2,5 @@ pub mod client;
 pub mod car_station;
 pub mod car;
 pub mod rent;
-pub mod owner;
\ No newline at end of file
+pub mod owner;
+pub mod auth;
\ No newline at end of file
diff --git a/backend/src/endpoints/owner.rs b/backend/src/endpoints/owner.rs
index 0c65251..7d70b28 100644
--- a/backend/src/endpoints/owner.rs
+++ b/backend/src/endpoints/owner.rs
@@ -1,10 +1,22 @@
 use std::sync::Mutex;
 use crate::models::client::*;
-use actix_web::{web, get, post, patch, delete, Responder, HttpResponse};
+use actix_web::{web, get, post, patch, delete, Responder, HttpResponse, HttpRequest};
 use crate::State;
 
 #[get("/")]
-pub async fn get_owners(state: web::Data<Mutex<State>>) -> impl Responder {
+pub async fn get_owners(state: web::Data<Mutex<State>>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.owner_repository.read_all().await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -15,7 +27,19 @@ pub async fn get_owners(state: web::Data<Mutex<State>>) -> impl Responder {
 }
 
 #[get("/{id}")]
-pub async fn get_owner(state: web::Data<Mutex<State>>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn get_owner(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.owner_repository.read(path.into_inner().0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -26,7 +50,19 @@ pub async fn get_owner(state: web::Data<Mutex<State>>, path: web::Path<(u32, )>)
 }
 
 #[post("/")]
-pub async fn create_owner(state: web::Data<Mutex<State>>, json: web::Json<BindingClient>) -> impl Responder {
+pub async fn create_owner(state: web::Data<Mutex<State>>, json: web::Json<BindingClient>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.owner_repository.create(json.0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -37,7 +73,19 @@ pub async fn create_owner(state: web::Data<Mutex<State>>, json: web::Json<Bindin
 }
 
 #[patch("/{id}")]
-pub async fn update_owner(state: web::Data<Mutex<State>>, json: web::Json<BindingClient>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn update_owner(state: web::Data<Mutex<State>>, json: web::Json<BindingClient>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.owner_repository.update(path.into_inner().0, json.0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -48,7 +96,19 @@ pub async fn update_owner(state: web::Data<Mutex<State>>, json: web::Json<Bindin
 }
 
 #[delete("/{id}")]
-pub async fn delete_owner(state: web::Data<Mutex<State>>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn delete_owner(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.owner_repository.delete(path.into_inner().0).await {
             Ok(result) => HttpResponse::Ok().json(result),
diff --git a/backend/src/endpoints/rent.rs b/backend/src/endpoints/rent.rs
index 005b843..c6d1b9b 100644
--- a/backend/src/endpoints/rent.rs
+++ b/backend/src/endpoints/rent.rs
@@ -1,10 +1,22 @@
 use std::sync::Mutex;
 use crate::models::rent::*;
-use actix_web::{web, get, post, patch, delete, Responder, HttpResponse};
+use actix_web::{web, get, post, patch, delete, Responder, HttpResponse, HttpRequest};
 use crate::State;
 
 #[get("/")]
-pub async fn get_rents(state: web::Data<Mutex<State>>) -> impl Responder {
+pub async fn get_rents(state: web::Data<Mutex<State>>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.rent_repository.read_all().await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -15,7 +27,19 @@ pub async fn get_rents(state: web::Data<Mutex<State>>) -> impl Responder {
 }
 
 #[get("/{id}")]
-pub async fn get_rent(state: web::Data<Mutex<State>>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn get_rent(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.rent_repository.read(path.into_inner().0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -26,7 +50,19 @@ pub async fn get_rent(state: web::Data<Mutex<State>>, path: web::Path<(u32, )>)
 }
 
 #[post("/")]
-pub async fn create_rent(state: web::Data<Mutex<State>>, json: web::Json<BindingRent>) -> impl Responder {
+pub async fn create_rent(state: web::Data<Mutex<State>>, json: web::Json<BindingRent>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.rent_repository.create(json.0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -37,7 +73,19 @@ pub async fn create_rent(state: web::Data<Mutex<State>>, json: web::Json<Binding
 }
 
 #[patch("/{id}")]
-pub async fn update_rent(state: web::Data<Mutex<State>>, json: web::Json<BindingRent>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn update_rent(state: web::Data<Mutex<State>>, json: web::Json<BindingRent>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.rent_repository.update(path.into_inner().0, json.0).await {
             Ok(result) => HttpResponse::Ok().json(result),
@@ -48,7 +96,19 @@ pub async fn update_rent(state: web::Data<Mutex<State>>, json: web::Json<Binding
 }
 
 #[delete("/{id}")]
-pub async fn delete_rent(state: web::Data<Mutex<State>>, path: web::Path<(u32, )>) -> impl Responder {
+pub async fn delete_rent(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
     match state.lock() {
         Ok(guard) => match guard.rent_repository.delete(path.into_inner().0).await {
             Ok(result) => HttpResponse::Ok().json(result),
diff --git a/backend/src/lib.rs b/backend/src/lib.rs
index 7278f76..c0ffd0f 100644
--- a/backend/src/lib.rs
+++ b/backend/src/lib.rs
@@ -1,15 +1,19 @@
-use storages::traits::OwnerRepository;
+use services::auth::AuthService;
+use storages::traits::{OwnerRepository, AdministratorRepository};
 
 use crate::storages::traits::{CarRepository, CarStationRepository, ClientRepository, RentRepository};
 
 pub mod endpoints;
 pub mod models;
 pub mod storages;
+pub mod services;
 
 pub struct State {
     pub car_repository: Box<dyn CarRepository + Send>,
     pub car_station_repository: Box<dyn CarStationRepository + Send>,
     pub client_repository: Box<dyn ClientRepository + Send>,
     pub owner_repository: Box<dyn OwnerRepository + Send>,
-    pub rent_repository: Box<dyn RentRepository + Send>
+    pub rent_repository: Box<dyn RentRepository + Send>,
+    pub administrator_repository: Box<dyn AdministratorRepository + Send>,
+    pub auth_service: AuthService
 }
\ No newline at end of file
diff --git a/backend/src/main.rs b/backend/src/main.rs
index 7a37b36..99a4afe 100644
--- a/backend/src/main.rs
+++ b/backend/src/main.rs
@@ -1,8 +1,10 @@
 use std::sync::{Arc, Mutex};
 use actix_web::{App, HttpServer, web};
 use actix_web::web::Data;
+use backend::endpoints::auth::*;
+use backend::storages::postgres::administrator::PostgresAdministratorRepository;
 use dotenv_codegen::dotenv;
-use backend::State;
+use backend::{State, services};
 use tokio_postgres::NoTls;
 use backend::storages::postgres::car::PostgresCarRepository;
 use backend::storages::postgres::car_station::PostgresCarStationRepository;
@@ -18,7 +20,7 @@ use backend::endpoints::owner::*;
 #[actix_web::main]
 async fn main() -> std::io::Result<()> {
     let (client, connection) = tokio_postgres::connect(
-        &format!("host={} user={} password={} dbname={}", dotenv!("HOST"), dotenv!("USER"), dotenv!("PASSWORD"), dotenv!("DBNAME")),
+        &format!("host={} user={} password={} dbname={}", dotenv!("HOST"), dotenv!("USER"), dotenv!("PASSWORD"), dotenv!("DBNAMEE")),
         NoTls
     ).await.unwrap();
 
@@ -40,56 +42,66 @@ async fn main() -> std::io::Result<()> {
 
     let rent_repository = PostgresRentRepository { connection: Arc::clone(&client) };
 
+    let administrator_repository = PostgresAdministratorRepository { connection: Arc::clone(&client) };
+    
+    let auth_service = services::auth::AuthService::new();
+
     let state = Data::new(Mutex::new(State {
         car_repository: Box::new(car_repository),
         car_station_repository: Box::new(car_station_repository),
         client_repository: Box::new(client_repository),
         owner_repository: Box::new(owner_repository),
-        rent_repository: Box::new(rent_repository)
+        rent_repository: Box::new(rent_repository),
+        administrator_repository: Box::new(administrator_repository),
+        auth_service
     }));
-
+    
     HttpServer::new(move || {
         App::new()
             .app_data(Data::clone(&state))
-            .service(
-                web::scope("/cars")
-                    .service(get_cars)
-                    .service(get_car)
-                    .service(create_car)
-                    .service(update_car)
-                    .service(delete_car)
-            )
-            .service(
-                web::scope("/clients")
-                    .service(get_clients)
-                    .service(get_client)
-                    .service(create_client)
-                    .service(update_client)
-                    .service(delete_client)
-            )
-            .service(
-                web::scope("/owners")
-                    .service(get_owners)
-                    .service(get_owner)
-                    .service(create_owner)
-                    .service(update_owner)
-                    .service(delete_owner)
-            )
-            .service(
-                web::scope("/car_stations")
-                    .service(get_car_stations)
-                    .service(get_car_station)
-                    .service(create_car_station)
-                    .service(update_car_station)
-                    .service(delete_car_station)
-            )
-            .service(
-                web::scope("/rents")
-                    .service(get_rents)
-                    .service(get_rent)
-                    .service(create_rent)
-                    .service(update_rent)
-                    .service(delete_rent)
+            .service(web::scope("/api")
+                .service(
+                    web::scope("/cars")
+                        .service(get_cars)
+                        .service(get_car)
+                        .service(create_car)
+                        .service(update_car)
+                        .service(delete_car)
+                )
+                .service(
+                    web::scope("/clients")
+                        .service(get_clients)
+                        .service(get_client)
+                        .service(create_client)
+                        .service(update_client)
+                        .service(delete_client)
+                )
+                .service(
+                    web::scope("/owners")
+                        .service(get_owners)
+                        .service(get_owner)
+                        .service(create_owner)
+                        .service(update_owner)
+                        .service(delete_owner)
+                )
+                .service(
+                    web::scope("/car_stations")
+                        .service(get_car_stations)
+                        .service(get_car_station)
+                        .service(create_car_station)
+                        .service(update_car_station)
+                        .service(delete_car_station)
+                )
+                .service(
+                    web::scope("/rents")
+                        .service(get_rents)
+                        .service(get_rent)
+                        .service(create_rent)
+                        .service(update_rent)
+                        .service(delete_rent)
+                )
+                .service(login)
+                .service(logout)
             )
     })
         .bind("127.0.0.1:8080")?
diff --git a/backend/src/models/administrator.rs b/backend/src/models/administrator.rs
new file mode 100644
index 0000000..3ba74cb
--- /dev/null
+++ b/backend/src/models/administrator.rs
@@ -0,0 +1,12 @@
+use serde::{Serialize, Deserialize};
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Administrator {
+    pub id: i32,
+    pub username: String,
+    pub password: String,
+    pub name: String,
+    pub surname: String,
+    pub middlename: String,
+    pub car_station_id: i32
+}
\ No newline at end of file
diff --git a/backend/src/models/mod.rs b/backend/src/models/mod.rs
index 4783b7d..aaa6c7c 100644
--- a/backend/src/models/mod.rs
+++ b/backend/src/models/mod.rs
@@ -1,4 +1,5 @@
 pub mod client;
 pub mod car_station;
 pub mod car;
-pub mod rent;
\ No newline at end of file
+pub mod rent;
+pub mod administrator;
\ No newline at end of file
diff --git a/backend/src/services/auth.rs b/backend/src/services/auth.rs
new file mode 100644
index 0000000..c09811e
--- /dev/null
+++ b/backend/src/services/auth.rs
@@ -0,0 +1,34 @@
+use crate::{storages::traits::AdministratorRepository, models::administrator::Administrator};
+use nanoid::nanoid;
+use sha2::Sha256;
+use std::cell::RefCell;
+
+pub struct AuthService {
+    authed: RefCell<Vec::<(String, i32)>>
+}
+
+impl AuthService {
+    pub fn new() -> Self {
+        AuthService { authed: RefCell::new(Vec::new()) }
+    }
+
+    pub async fn login(&self, storage: &dyn AdministratorRepository, username: &str, password: &str) -> Result<String, String> {
+        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 {
+            Err("Invalid password or login!".to_owned())
+        } else {
+            let token = nanoid!(32);
+            self.authed.borrow_mut().push((token.clone(), administrator.id));
+            Ok(token)
+        }
+    }
+
+    pub fn logout(&self, token: &str) {
+        self.authed.borrow_mut().retain(|x| x.0 != token);
+    }
+
+    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;
+        storage.read(id).await
+    }
+}
\ No newline at end of file
diff --git a/backend/src/services/mod.rs b/backend/src/services/mod.rs
new file mode 100644
index 0000000..5696e21
--- /dev/null
+++ b/backend/src/services/mod.rs
@@ -0,0 +1 @@
+pub mod auth;
\ No newline at end of file
diff --git a/backend/src/storages/postgres/administrator.rs b/backend/src/storages/postgres/administrator.rs
new file mode 100644
index 0000000..68bdf8a
--- /dev/null
+++ b/backend/src/storages/postgres/administrator.rs
@@ -0,0 +1,52 @@
+use tokio_postgres::Client as PgClient;
+use std::sync::Arc;
+use crate::models::administrator::Administrator;
+use crate::storages::traits::AdministratorRepository;
+use async_trait::async_trait;
+
+pub struct PostgresAdministratorRepository {
+    pub connection: Arc<PgClient>
+}
+
+#[async_trait]
+impl AdministratorRepository for PostgresAdministratorRepository {
+    async fn read(&self, id: i32) -> Result<Administrator, String> {
+        let result = self.connection.query(
+            "SELECT * FROM administrator WHERE id = $1", &[&id]
+        ).await;
+
+        if let Ok(rows) = result {
+            let row = rows.get(0).ok_or("Administrator not found".to_owned())?;
+            Ok(Administrator {
+                id: row.get("id"),
+                username: row.get("username"),
+                password: row.get("password"),
+                name: row.get("name"),
+                surname: row.get("surname"),
+                middlename: row.get("middlename"),
+                car_station_id: row.get("car_station_id")
+            })
+        } else {
+            Err("Something gone wrong during reading of Administrator".to_owned())
+        }
+    }
+
+    async fn find_by_username(&self, username: &str) -> Result<Administrator, String> {
+        let result = self.connection.query("SELECT * FROM administrator WHERE username LIKE $1", &[&username]).await;
+        
+        if let Ok(rows) = result {
+            let row = rows.get(0).ok_or("Administrator not found".to_owned())?;
+            Ok(Administrator {
+                id: row.get("id"),
+                username: row.get("username"),
+                password: row.get("password"),
+                name: row.get("name"),
+                surname: row.get("surname"),
+                middlename: row.get("middlename"),
+                car_station_id: row.get("car_station_id")
+            })
+        } else {
+            Err("Something gone wrong during reading of Administrator".to_owned())
+        }
+    }
+}
\ No newline at end of file
diff --git a/backend/src/storages/postgres/car.rs b/backend/src/storages/postgres/car.rs
index c878fd0..92d8b33 100644
--- a/backend/src/storages/postgres/car.rs
+++ b/backend/src/storages/postgres/car.rs
@@ -32,7 +32,7 @@ impl CarRepository for PostgresCarRepository {
         }
     }
 
-    async fn read(&self, id: u32) -> Result<Car, String> {
+    async fn read(&self, id: i32) -> Result<Car, String> {
         let result = self.connection.query(
             "SELECT * FROM Car WHERE id = $1", &[&id]
         ).await;
@@ -73,7 +73,7 @@ impl CarRepository for PostgresCarRepository {
         }
     }
 
-    async fn update(&self, id: u32, car: BindingCar) -> Result<Car, String> {
+    async fn update(&self, id: i32, car: BindingCar) -> Result<Car, String> {
         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 *",
             &[&car.brand, &car.model, &car.price, &car.owner_id, &car.car_station_id, &id]
@@ -94,7 +94,7 @@ impl CarRepository for PostgresCarRepository {
         }
     }
 
-    async fn delete(&self, id: u32) -> Result<(), String> {
+    async fn delete(&self, id: i32) -> Result<(), String> {
         let result = self.connection.execute(
             "DELETE FROM Car WHERE id = $1",
             &[&id]
diff --git a/backend/src/storages/postgres/car_station.rs b/backend/src/storages/postgres/car_station.rs
index 5b57867..e599725 100644
--- a/backend/src/storages/postgres/car_station.rs
+++ b/backend/src/storages/postgres/car_station.rs
@@ -27,7 +27,7 @@ impl CarStationRepository for PostgresCarStationRepository {
         }
     }
 
-    async fn read(&self, id: u32) -> Result<CarStation, String> {
+    async fn read(&self, id: i32) -> Result<CarStation, String> {
         let result = self.connection.query(
             "SELECT * FROM Car_Station WHERE id = $1", &[&id]
         ).await;
@@ -60,7 +60,7 @@ impl CarStationRepository for PostgresCarStationRepository {
         }
     }
 
-    async fn update(&self, id: u32, car_station: BindingCarStation) -> Result<CarStation, String> {
+    async fn update(&self, id: i32, car_station: BindingCarStation) -> Result<CarStation, String> {
         let result = self.connection.query(
             "UPDATE Car_Station SET address = $1 WHERE id = $2 RETURNING *",
             &[&car_station.address, &id]
@@ -77,7 +77,7 @@ impl CarStationRepository for PostgresCarStationRepository {
         }
     }
 
-    async fn delete(&self, id: u32) -> Result<(), String> {
+    async fn delete(&self, id: i32) -> Result<(), String> {
         let result = self.connection.execute(
             "DELETE FROM Car_Station WHERE id = $1",
             &[&id]
diff --git a/backend/src/storages/postgres/client.rs b/backend/src/storages/postgres/client.rs
index 88bfeb0..f5fbe32 100644
--- a/backend/src/storages/postgres/client.rs
+++ b/backend/src/storages/postgres/client.rs
@@ -31,7 +31,7 @@ impl ClientRepository for PostgresClientRepository {
         }
     }
 
-    async fn read(&self, id: u32) -> Result<Client, String> {
+    async fn read(&self, id: i32) -> Result<Client, String> {
         let result= self.connection.query(
             "SELECT * FROM Client WHERE id = $1", &[&id]
         ).await;
@@ -71,7 +71,7 @@ impl ClientRepository for PostgresClientRepository {
         }
     }
 
-    async fn update(&self, id: u32, client: BindingClient) -> Result<Client, String> {
+    async fn update(&self, id: i32, client: BindingClient) -> Result<Client, String> {
         let result = self.connection.query(
             "UPDATE Client SET name = $1, surname = $2, middlename = $3, phone = $4 \
             WHERE id = $5 RETURNING *",
@@ -92,7 +92,7 @@ impl ClientRepository for PostgresClientRepository {
         }
     }
 
-    async fn delete(&self, id: u32) -> Result<(), String> {
+    async fn delete(&self, id: i32) -> Result<(), String> {
         let result = self.connection.execute(
             "DELETE FROM Client WHERE id = $1",
             &[&id]
diff --git a/backend/src/storages/postgres/mod.rs b/backend/src/storages/postgres/mod.rs
index 2c3aab9..ced284f 100644
--- a/backend/src/storages/postgres/mod.rs
+++ b/backend/src/storages/postgres/mod.rs
@@ -2,4 +2,5 @@ pub mod client;
 pub mod car_station;
 pub mod car;
 pub mod rent;
-pub mod owner;
\ No newline at end of file
+pub mod owner;
+pub mod administrator;
\ No newline at end of file
diff --git a/backend/src/storages/postgres/owner.rs b/backend/src/storages/postgres/owner.rs
index 7f63f2d..66794a3 100644
--- a/backend/src/storages/postgres/owner.rs
+++ b/backend/src/storages/postgres/owner.rs
@@ -31,7 +31,7 @@ impl OwnerRepository for PostgresOwnerRepository {
         }
     }
 
-    async fn read(&self, id: u32) -> Result<Client, String> {
+    async fn read(&self, id: i32) -> Result<Client, String> {
         let result= self.connection.query(
             "SELECT * FROM Owner WHERE id = $1", &[&id]
         ).await;
@@ -71,7 +71,7 @@ impl OwnerRepository for PostgresOwnerRepository {
         }
     }
 
-    async fn update(&self, id: u32, client: BindingClient) -> Result<Client, String> {
+    async fn update(&self, id: i32, client: BindingClient) -> Result<Client, String> {
         let result = self.connection.query(
             "UPDATE Owner SET name = $1, surname = $2, middlename = $3, phone = $4 \
             WHERE id = $5 RETURNING *",
@@ -92,7 +92,7 @@ impl OwnerRepository for PostgresOwnerRepository {
         }
     }
 
-    async fn delete(&self, id: u32) -> Result<(), String> {
+    async fn delete(&self, id: i32) -> Result<(), String> {
         let result = self.connection.execute(
             "DELETE FROM Owner WHERE id = $1",
             &[&id]
diff --git a/backend/src/storages/postgres/rent.rs b/backend/src/storages/postgres/rent.rs
index 585a1e1..4cbdee2 100644
--- a/backend/src/storages/postgres/rent.rs
+++ b/backend/src/storages/postgres/rent.rs
@@ -44,7 +44,7 @@ impl RentRepository for PostgresRentRepository {
         }
     }
 
-    async fn read(&self, id: u32) -> Result<Rent, String> {
+    async fn read(&self, id: i32) -> Result<Rent, String> {
         let result = self.connection.query(
             "SELECT * FROM Rent WHERE id = $1", &[&id]
         ).await;
@@ -83,7 +83,7 @@ impl RentRepository for PostgresRentRepository {
         }
     }
 
-    async fn update(&self, id: u32, rent: BindingRent) -> Result<Rent, String> {
+    async fn update(&self, id: i32, rent: BindingRent) -> Result<Rent, String> {
         let result = self.connection.query(
             "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]
@@ -103,7 +103,7 @@ impl RentRepository for PostgresRentRepository {
         }
     }
 
-    async fn delete(&self, id: u32) -> Result<(), String> {
+    async fn delete(&self, id: i32) -> Result<(), String> {
         let result = self.connection.execute(
             "DELETE FROM Rent WHERE id = $1", &[&id]
         ).await;
diff --git a/backend/src/storages/traits.rs b/backend/src/storages/traits.rs
index 5a38418..26f0469 100644
--- a/backend/src/storages/traits.rs
+++ b/backend/src/storages/traits.rs
@@ -1,3 +1,4 @@
+use crate::models::administrator::Administrator;
 use crate::models::client::*;
 use crate::models::car_station::*;
 use crate::models::car::*;
@@ -7,44 +8,50 @@ use async_trait::async_trait;
 #[async_trait]
 pub trait ClientRepository {
     async fn create(&self, client: BindingClient) -> Result<Client, String>;
-    async fn read(&self, id: u32) -> Result<Client, String>;
+    async fn read(&self, id: i32) -> Result<Client, String>;
     async fn read_all(&self) -> Result<Vec<Client>, String>;
-    async fn update(&self, id: u32, client: BindingClient) -> Result<Client, String>;
-    async fn delete(&self, id: u32) -> Result<(), String>;
+    async fn update(&self, id: i32, client: BindingClient) -> Result<Client, String>;
+    async fn delete(&self, id: i32) -> Result<(), String>;
 }
 
 #[async_trait]
 pub trait CarRepository {
     async fn create(&self, car: BindingCar) -> Result<Car, String>;
-    async fn read(&self, id: u32) -> Result<Car, String>;
+    async fn read(&self, id: i32) -> Result<Car, String>;
     async fn read_all(&self) -> Result<Vec<Car>, String>;
-    async fn update(&self, id: u32, car: BindingCar) -> Result<Car, String>;
-    async fn delete(&self, id: u32) -> Result<(), String>;
+    async fn update(&self, id: i32, car: BindingCar) -> Result<Car, String>;
+    async fn delete(&self, id: i32) -> Result<(), String>;
 }
 
 #[async_trait]
 pub trait CarStationRepository {
     async fn create(&self, car_station: BindingCarStation) -> Result<CarStation, String>;
-    async fn read(&self, id: u32) -> Result<CarStation, String>;
+    async fn read(&self, id: i32) -> Result<CarStation, String>;
     async fn read_all(&self) -> Result<Vec<CarStation>, String>;
-    async fn update(&self, id: u32, car_station: BindingCarStation) -> Result<CarStation, String>;
-    async fn delete(&self, id: u32) -> Result<(), String>;
+    async fn update(&self, id: i32, car_station: BindingCarStation) -> Result<CarStation, String>;
+    async fn delete(&self, id: i32) -> Result<(), String>;
 }
 
 #[async_trait]
 pub trait RentRepository {
     async fn create(&self, rent: BindingRent) -> Result<Rent, String>;
-    async fn read(&self, id: u32) -> Result<Rent, String>;
+    async fn read(&self, id: i32) -> Result<Rent, String>;
     async fn read_all(&self) -> Result<Vec<Rent>, String>;
-    async fn update(&self, id: u32, rent: BindingRent) -> Result<Rent, String>;
-    async fn delete(&self, id: u32) -> Result<(), String>;
+    async fn update(&self, id: i32, rent: BindingRent) -> Result<Rent, String>;
+    async fn delete(&self, id: i32) -> Result<(), String>;
 }
 
 #[async_trait]
 pub trait OwnerRepository {
     async fn create(&self, client: BindingClient) -> Result<Client, String>;
-    async fn read(&self, id: u32) -> Result<Client, String>;
+    async fn read(&self, id: i32) -> Result<Client, String>;
     async fn read_all(&self) -> Result<Vec<Client>, String>;
-    async fn update(&self, id: u32, client: BindingClient) -> Result<Client, String>;
-    async fn delete(&self, id: u32) -> Result<(), String>;
+    async fn update(&self, id: i32, client: BindingClient) -> Result<Client, String>;
+    async fn delete(&self, id: i32) -> Result<(), String>;
+}
+
+#[async_trait]
+pub trait AdministratorRepository {
+    async fn read(&self, id: i32) -> Result<Administrator, String>;
+    async fn find_by_username(&self, username: &str) -> Result<Administrator, String>;
 }
\ No newline at end of file
-- 
2.25.1


From f275ca7e27727c32edc1df71a950570872c22d79 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A1=D0=B5=D1=80=D0=B3=D0=B5=D0=B9=20=D0=9F=D0=BE=D0=BB?=
 =?UTF-8?q?=D0=B5=D0=B2=D0=BE=D0=B9?= <sergpolevoi@yandex.ru>
Date: Sun, 14 May 2023 22:28:44 +0400
Subject: [PATCH 2/2] =?UTF-8?q?=D0=91=D1=8D=D0=BA=D0=B5=D0=BD=D0=B4:=20?=
 =?UTF-8?q?=D0=A7=D1=82=D0=BE-=D1=82=D0=BE=20=D1=81=20=D1=87=D0=B5=D0=BC-?=
 =?UTF-8?q?=D1=82=D0=BE.=20=D0=9E=D0=BD=D0=BE=20=D1=80=D0=B5=D0=B0=D0=BB?=
 =?UTF-8?q?=D1=8C=D0=BD=D0=BE=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=B5?=
 =?UTF-8?q?=D1=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 backend/Cargo.lock                            | 254 ++++++++++++++++++
 backend/Cargo.toml                            |   4 +-
 backend/src/endpoints/auth.rs                 |   5 +-
 backend/src/endpoints/benchmark.rs            |  14 +
 backend/src/endpoints/car.rs                  |  23 ++
 backend/src/endpoints/mod.rs                  |   3 +-
 backend/src/endpoints/rent.rs                 |  23 ++
 backend/src/lib.rs                            |   3 +-
 backend/src/main.rs                           |  11 +-
 backend/src/models/car.rs                     |  18 +-
 backend/src/models/rent.rs                    |   8 +-
 backend/src/services/auth.rs                  |   4 +-
 .../src/storages/postgres/administrator.rs    |   4 +-
 backend/src/storages/postgres/benchmark.rs    |  49 ++++
 backend/src/storages/postgres/car.rs          |  43 ++-
 backend/src/storages/postgres/car_station.rs  |  10 +-
 backend/src/storages/postgres/client.rs       |  10 +-
 backend/src/storages/postgres/mod.rs          |   3 +-
 backend/src/storages/postgres/owner.rs        |  10 +-
 backend/src/storages/postgres/rent.rs         |  29 +-
 backend/src/storages/traits.rs                |   7 +
 21 files changed, 487 insertions(+), 48 deletions(-)
 create mode 100644 backend/src/endpoints/benchmark.rs
 create mode 100644 backend/src/storages/postgres/benchmark.rs

diff --git a/backend/Cargo.lock b/backend/Cargo.lock
index 94a776e..d71ffe8 100644
--- a/backend/Cargo.lock
+++ b/backend/Cargo.lock
@@ -245,6 +245,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "arrayvec"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
+
 [[package]]
 name = "async-trait"
 version = "0.1.68"
@@ -273,6 +279,8 @@ dependencies = [
  "dotenv_codegen",
  "nanoid",
  "pbkdf2",
+ "rust_decimal",
+ "rust_decimal_macros",
  "serde",
  "serde_json",
  "sha2",
@@ -292,6 +300,18 @@ version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
+[[package]]
+name = "bitvec"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
+dependencies = [
+ "funty",
+ "radium",
+ "tap",
+ "wyz",
+]
+
 [[package]]
 name = "block-buffer"
 version = "0.10.4"
@@ -301,6 +321,51 @@ dependencies = [
  "generic-array",
 ]
 
+[[package]]
+name = "borsh"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b"
+dependencies = [
+ "borsh-derive",
+ "hashbrown",
+]
+
+[[package]]
+name = "borsh-derive"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7"
+dependencies = [
+ "borsh-derive-internal",
+ "borsh-schema-derive-internal",
+ "proc-macro-crate",
+ "proc-macro2",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "borsh-derive-internal"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "borsh-schema-derive-internal"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "brotli"
 version = "3.3.4"
@@ -328,6 +393,28 @@ version = "3.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
 
+[[package]]
+name = "bytecheck"
+version = "0.6.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627"
+dependencies = [
+ "bytecheck_derive",
+ "ptr_meta",
+ "simdutf8",
+]
+
+[[package]]
+name = "bytecheck_derive"
+version = "0.6.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "byteorder"
 version = "1.4.3"
@@ -578,6 +665,12 @@ dependencies = [
  "percent-encoding",
 ]
 
+[[package]]
+name = "funty"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
+
 [[package]]
 name = "futures-channel"
 version = "0.3.28"
@@ -677,6 +770,9 @@ name = "hashbrown"
 version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+dependencies = [
+ "ahash 0.7.6",
+]
 
 [[package]]
 name = "hermit-abi"
@@ -1012,6 +1108,20 @@ version = "0.3.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
 
+[[package]]
+name = "postgres"
+version = "0.19.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bed5017bc2ff49649c0075d0d7a9d676933c1292480c1d137776fb205b5cd18"
+dependencies = [
+ "bytes",
+ "fallible-iterator",
+ "futures-util",
+ "log",
+ "tokio",
+ "tokio-postgres",
+]
+
 [[package]]
 name = "postgres-protocol"
 version = "0.6.5"
@@ -1048,6 +1158,15 @@ version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
+[[package]]
+name = "proc-macro-crate"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
+dependencies = [
+ "toml",
+]
+
 [[package]]
 name = "proc-macro-hack"
 version = "0.5.20+deprecated"
@@ -1063,6 +1182,26 @@ dependencies = [
  "unicode-ident",
 ]
 
+[[package]]
+name = "ptr_meta"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1"
+dependencies = [
+ "ptr_meta_derive",
+]
+
+[[package]]
+name = "ptr_meta_derive"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "quote"
 version = "1.0.26"
@@ -1072,6 +1211,12 @@ dependencies = [
  "proc-macro2",
 ]
 
+[[package]]
+name = "radium"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
+
 [[package]]
 name = "rand"
 version = "0.8.5"
@@ -1128,6 +1273,73 @@ version = "0.6.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
 
+[[package]]
+name = "rend"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab"
+dependencies = [
+ "bytecheck",
+]
+
+[[package]]
+name = "rkyv"
+version = "0.7.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0200c8230b013893c0b2d6213d6ec64ed2b9be2e0e016682b7224ff82cff5c58"
+dependencies = [
+ "bitvec",
+ "bytecheck",
+ "hashbrown",
+ "ptr_meta",
+ "rend",
+ "rkyv_derive",
+ "seahash",
+ "tinyvec",
+ "uuid",
+]
+
+[[package]]
+name = "rkyv_derive"
+version = "0.7.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2e06b915b5c230a17d7a736d1e2e63ee753c256a8614ef3f5147b13a4f5541d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "rust_decimal"
+version = "1.29.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26bd36b60561ee1fb5ec2817f198b6fd09fa571c897a5e86d1487cfc2b096dfc"
+dependencies = [
+ "arrayvec",
+ "borsh",
+ "bytecheck",
+ "byteorder",
+ "bytes",
+ "num-traits",
+ "postgres",
+ "rand",
+ "rkyv",
+ "serde",
+ "serde_json",
+ "tokio-postgres",
+]
+
+[[package]]
+name = "rust_decimal_macros"
+version = "1.29.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e773fd3da1ed42472fdf3cfdb4972948a555bc3d73f5e0bdb99d17e7b54c687"
+dependencies = [
+ "quote",
+ "rust_decimal",
+]
+
 [[package]]
 name = "rustc_version"
 version = "0.4.0"
@@ -1155,6 +1367,12 @@ version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1"
 
+[[package]]
+name = "seahash"
+version = "4.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
+
 [[package]]
 name = "semver"
 version = "1.0.17"
@@ -1235,6 +1453,12 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "simdutf8"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a"
+
 [[package]]
 name = "siphasher"
 version = "0.3.10"
@@ -1314,6 +1538,12 @@ dependencies = [
  "unicode-ident",
 ]
 
+[[package]]
+name = "tap"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
+
 [[package]]
 name = "termcolor"
 version = "1.2.0"
@@ -1444,6 +1674,15 @@ dependencies = [
  "tracing",
 ]
 
+[[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "tracing"
 version = "0.1.37"
@@ -1509,6 +1748,12 @@ dependencies = [
  "percent-encoding",
 ]
 
+[[package]]
+name = "uuid"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2"
+
 [[package]]
 name = "version_check"
 version = "0.9.4"
@@ -1687,6 +1932,15 @@ version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
 
+[[package]]
+name = "wyz"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
+dependencies = [
+ "tap",
+]
+
 [[package]]
 name = "zstd"
 version = "0.12.3+zstd.1.5.2"
diff --git a/backend/Cargo.toml b/backend/Cargo.toml
index 535aa0c..6ac8bec 100644
--- a/backend/Cargo.toml
+++ b/backend/Cargo.toml
@@ -17,4 +17,6 @@ async-trait = "0.1.68"
 dotenv_codegen = "0.15.0"
 pbkdf2 = "0.12.1"
 nanoid = "0.4.0"
-sha2 = "0.10.6"
\ No newline at end of file
+sha2 = "0.10.6"
+rust_decimal = { version = "1.29", features = ["db-tokio-postgres"] }
+rust_decimal_macros = "1.29"
\ No newline at end of file
diff --git a/backend/src/endpoints/auth.rs b/backend/src/endpoints/auth.rs
index 38b28c6..6690521 100644
--- a/backend/src/endpoints/auth.rs
+++ b/backend/src/endpoints/auth.rs
@@ -1,6 +1,7 @@
 use std::sync::Mutex;
 use actix_web::{web, post, Responder, HttpResponse};
-use crate::State;
+use serde_json::json;
+use crate::{State, models::administrator};
 
 #[derive(serde::Deserialize)]
 pub struct LoginInfo {
@@ -12,7 +13,7 @@ pub struct LoginInfo {
 pub async fn login(state: web::Data<Mutex<State>>, json: web::Json<LoginInfo>) -> impl Responder {
     match state.lock() {
         Ok(guard) => match guard.auth_service.login(guard.administrator_repository.as_ref(), &json.username, &json.password).await {
-            Ok(token) => HttpResponse::Ok().json(token),
+            Ok((token, administrator_id, car_station_id)) => HttpResponse::Ok().json(json!({"token": token, "administrator_id": administrator_id, "car_station_id": car_station_id}) ),
             Err(error) => HttpResponse::InternalServerError().json(error.to_string())
         },
         Err(error) => HttpResponse::InternalServerError().json(error.to_string())
diff --git a/backend/src/endpoints/benchmark.rs b/backend/src/endpoints/benchmark.rs
new file mode 100644
index 0000000..39986a7
--- /dev/null
+++ b/backend/src/endpoints/benchmark.rs
@@ -0,0 +1,14 @@
+use std::sync::Mutex;
+use actix_web::{web, get, post, patch, delete, Responder, HttpResponse, HttpRequest};
+use crate::State;
+
+#[get("/benchmark")]
+async fn benchmark(state: web::Data<Mutex<State>>) -> impl Responder {
+    match state.lock() {
+        Ok(guard) => match guard.benchmark_repository.benchmark().await {
+            Ok(result) => HttpResponse::Ok().json(result),
+            Err(error) => HttpResponse::InternalServerError().json(error.to_string())
+        },
+        Err(error) => HttpResponse::InternalServerError().json(error.to_string())
+    }
+}
\ No newline at end of file
diff --git a/backend/src/endpoints/car.rs b/backend/src/endpoints/car.rs
index b9a49bb..dece7c2 100644
--- a/backend/src/endpoints/car.rs
+++ b/backend/src/endpoints/car.rs
@@ -116,4 +116,27 @@ pub async fn delete_car(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>
         },
         Err(error) => HttpResponse::InternalServerError().json(error.to_string())
     }
+}
+
+#[get("/report")]
+pub async fn get_report(state: web::Data<Mutex<State>>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+
+    match state.lock() {
+        Ok(guard) => match guard.car_repository.get_report().await {
+            Ok(result) => HttpResponse::Ok().json(result),
+            Err(error) => HttpResponse::InternalServerError().json(error.to_string())
+        },
+        Err(error) => HttpResponse::InternalServerError().json(error.to_string())
+    }
 }
\ No newline at end of file
diff --git a/backend/src/endpoints/mod.rs b/backend/src/endpoints/mod.rs
index d4fcc35..69bb70f 100644
--- a/backend/src/endpoints/mod.rs
+++ b/backend/src/endpoints/mod.rs
@@ -3,4 +3,5 @@ pub mod car_station;
 pub mod car;
 pub mod rent;
 pub mod owner;
-pub mod auth;
\ No newline at end of file
+pub mod auth;
+pub mod benchmark;
\ No newline at end of file
diff --git a/backend/src/endpoints/rent.rs b/backend/src/endpoints/rent.rs
index c6d1b9b..d3acf38 100644
--- a/backend/src/endpoints/rent.rs
+++ b/backend/src/endpoints/rent.rs
@@ -116,4 +116,27 @@ pub async fn delete_rent(state: web::Data<Mutex<State>>, path: web::Path<(i32, )
         },
         Err(error) => HttpResponse::InternalServerError().json(error.to_string())
     }
+}
+
+#[get("/{id}/end")]
+pub async fn end_rent(state: web::Data<Mutex<State>>, path: web::Path<(i32, )>, request: HttpRequest) -> impl Responder {
+    let token = request.headers().get("Authorization");
+    if token.is_none() {
+        return HttpResponse::Unauthorized().body("There is no token");
+    }
+    let token = token.unwrap();
+
+    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() {
+            return HttpResponse::Unauthorized().body("Invalid token");
+        }
+    }
+    
+    match state.lock() {
+        Ok(guard) => match guard.rent_repository.end_rent(path.into_inner().0).await {
+            Ok(result) => HttpResponse::Ok().json(result),
+            Err(error) => HttpResponse::InternalServerError().json(error.to_string())
+        },
+        Err(error) => HttpResponse::InternalServerError().json(error.to_string())
+    }
 }
\ No newline at end of file
diff --git a/backend/src/lib.rs b/backend/src/lib.rs
index c0ffd0f..4cbd82c 100644
--- a/backend/src/lib.rs
+++ b/backend/src/lib.rs
@@ -1,5 +1,5 @@
 use services::auth::AuthService;
-use storages::traits::{OwnerRepository, AdministratorRepository};
+use storages::traits::{OwnerRepository, AdministratorRepository, BenchmarkRepository};
 
 use crate::storages::traits::{CarRepository, CarStationRepository, ClientRepository, RentRepository};
 
@@ -15,5 +15,6 @@ pub struct State {
     pub owner_repository: Box<dyn OwnerRepository + Send>,
     pub rent_repository: Box<dyn RentRepository + Send>,
     pub administrator_repository: Box<dyn AdministratorRepository + Send>,
+    pub benchmark_repository: Box<dyn BenchmarkRepository + Send>,
     pub auth_service: AuthService
 }
\ No newline at end of file
diff --git a/backend/src/main.rs b/backend/src/main.rs
index 99a4afe..181d294 100644
--- a/backend/src/main.rs
+++ b/backend/src/main.rs
@@ -1,7 +1,8 @@
 use std::sync::{Arc, Mutex};
 use actix_web::{App, HttpServer, web};
 use actix_web::web::Data;
-use backend::endpoints::auth::*;
+use backend::endpoints::benchmark::benchmark;
+use backend::endpoints::{auth::*};
 use backend::storages::postgres::administrator::PostgresAdministratorRepository;
 use dotenv_codegen::dotenv;
 use backend::{State, services};
@@ -11,6 +12,7 @@ use backend::storages::postgres::car_station::PostgresCarStationRepository;
 use backend::storages::postgres::client::PostgresClientRepository;
 use backend::storages::postgres::rent::PostgresRentRepository;
 use backend::storages::postgres::owner::PostgresOwnerRepository;
+use backend::storages::postgres::benchmark::PostgresBenchmarkRepository;
 use backend::endpoints::car_station::*;
 use backend::endpoints::car::*;
 use backend::endpoints::client::*;
@@ -43,6 +45,8 @@ async fn main() -> std::io::Result<()> {
     let rent_repository = PostgresRentRepository { connection: Arc::clone(&client) };
 
     let administrator_repository = PostgresAdministratorRepository { connection: Arc::clone(&client) };
+
+    let benchmark_repository = PostgresBenchmarkRepository { connection: Arc::clone(&client) };
     
     let auth_service = services::auth::AuthService::new();
 
@@ -53,6 +57,7 @@ async fn main() -> std::io::Result<()> {
         owner_repository: Box::new(owner_repository),
         rent_repository: Box::new(rent_repository),
         administrator_repository: Box::new(administrator_repository),
+        benchmark_repository: Box::new(benchmark_repository),
         auth_service
     }));
     
@@ -63,6 +68,7 @@ async fn main() -> std::io::Result<()> {
                 .service(
                     web::scope("/cars")
                         .service(get_cars)
+                        .service(get_report)
                         .service(get_car)
                         .service(create_car)
                         .service(update_car)
@@ -99,10 +105,11 @@ async fn main() -> std::io::Result<()> {
                         .service(create_rent)
                         .service(update_rent)
                         .service(delete_rent)
+                        .service(end_rent)
                 )
                 .service(login)
                 .service(logout)
-            )
+            ).service(benchmark)
     })
         .bind("127.0.0.1:8080")?
         .run()
diff --git a/backend/src/models/car.rs b/backend/src/models/car.rs
index ec2fa17..8f74de3 100644
--- a/backend/src/models/car.rs
+++ b/backend/src/models/car.rs
@@ -1,3 +1,4 @@
+use rust_decimal::Decimal;
 use serde::{Serialize, Deserialize};
 
 #[derive(Debug, Clone, Serialize, Deserialize)]
@@ -5,7 +6,7 @@ pub struct Car {
     pub id: i32,
     pub brand: String,
     pub model: String,
-    pub price: f64,
+    pub price: Decimal,
     pub owner_id: i32,
     pub car_station_id: i32
 }
@@ -14,7 +15,16 @@ pub struct Car {
 pub struct BindingCar {
     pub brand: String,
     pub model: String,
-    pub price: f64,
-    pub owner_id: u32,
-    pub car_station_id: u32
+    pub price: Decimal,
+    pub owner_id: i32,
+    pub car_station_id: i32
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Report {
+    pub car_id: i32,
+    pub brand: String,
+    pub model: String,
+    pub times: i64,
+    pub income: Decimal
 }
\ No newline at end of file
diff --git a/backend/src/models/rent.rs b/backend/src/models/rent.rs
index 72dec1c..1566902 100644
--- a/backend/src/models/rent.rs
+++ b/backend/src/models/rent.rs
@@ -3,7 +3,7 @@ use serde::{Serialize, Deserialize};
 #[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct Rent {
     pub id: i32,
-    pub start_time: chrono::NaiveTime,
+    pub start_time: chrono::NaiveDateTime,
     pub time_amount: Option<i32>,
     pub client_id: i32,
     pub car_id: i32
@@ -11,7 +11,7 @@ pub struct Rent {
 
 #[derive(Debug, Clone, Serialize, Deserialize)]
 pub struct BindingRent {
-    pub time_amount: Option<u32>,
-    pub client_id: u32,
-    pub car_id: u32
+    pub time_amount: Option<i32>,
+    pub client_id: i32,
+    pub car_id: i32
 }
\ No newline at end of file
diff --git a/backend/src/services/auth.rs b/backend/src/services/auth.rs
index c09811e..184e818 100644
--- a/backend/src/services/auth.rs
+++ b/backend/src/services/auth.rs
@@ -12,14 +12,14 @@ impl AuthService {
         AuthService { authed: RefCell::new(Vec::new()) }
     }
 
-    pub async fn login(&self, storage: &dyn AdministratorRepository, username: &str, password: &str) -> Result<String, String> {
+    pub async fn login(&self, storage: &dyn AdministratorRepository, username: &str, password: &str) -> Result<(String, i32, i32), String> {
         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 {
             Err("Invalid password or login!".to_owned())
         } else {
             let token = nanoid!(32);
             self.authed.borrow_mut().push((token.clone(), administrator.id));
-            Ok(token)
+            Ok((token, administrator.id, administrator.car_station_id))
         }
     }
 
diff --git a/backend/src/storages/postgres/administrator.rs b/backend/src/storages/postgres/administrator.rs
index 68bdf8a..312adda 100644
--- a/backend/src/storages/postgres/administrator.rs
+++ b/backend/src/storages/postgres/administrator.rs
@@ -27,7 +27,7 @@ impl AdministratorRepository for PostgresAdministratorRepository {
                 car_station_id: row.get("car_station_id")
             })
         } else {
-            Err("Something gone wrong during reading of Administrator".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -46,7 +46,7 @@ impl AdministratorRepository for PostgresAdministratorRepository {
                 car_station_id: row.get("car_station_id")
             })
         } else {
-            Err("Something gone wrong during reading of Administrator".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 }
\ No newline at end of file
diff --git a/backend/src/storages/postgres/benchmark.rs b/backend/src/storages/postgres/benchmark.rs
new file mode 100644
index 0000000..1143190
--- /dev/null
+++ b/backend/src/storages/postgres/benchmark.rs
@@ -0,0 +1,49 @@
+use tokio_postgres::Client as PgClient;
+use std::sync::Arc;
+use crate::storages::traits::BenchmarkRepository;
+use async_trait::async_trait;
+
+pub struct PostgresBenchmarkRepository {
+    pub connection: Arc<PgClient>
+}
+
+#[async_trait]
+impl BenchmarkRepository for PostgresBenchmarkRepository {
+    async fn benchmark(&self) -> Result<i64, String> {
+        self.connection.execute("DELETE FROM Rent", &[]).await.unwrap();
+        self.connection.execute("DELETE FROM Car", &[]).await.unwrap();
+        self.connection.execute("DELETE FROM Owner", &[]).await.unwrap();
+        self.connection.execute("DELETE FROM Client", &[]).await.unwrap();
+
+        let start_time = chrono::Utc::now().naive_local();
+
+        for n in 1..201 {
+            let str = format!("INSERT INTO Owner(name, surname, middlename, phone) VALUES ('Иван{0}', 'Иванов{0}', 'Иванович{0}', {0}) RETURNING id", n);
+            let owner_id: i32 = self.connection.query(
+                &str, 
+                &[]
+            ).await.unwrap().get(0).unwrap().get(0);
+
+            let client_id: i32 = self.connection.query(
+                &str.replace("Owner", "Client").replace("Иван", "Петр"),
+                &[]
+            ).await.unwrap().get(0).unwrap().get(0);
+
+            let str = format!("INSERT INTO Car(Brand, Model, Price, owner_id, car_station_id) VALUES ('Лада{0}', 'Гранта{0}', {0}.00, {1}, 2) RETURNING id", n, owner_id);
+            let car_id: i32 = self.connection.query(
+                &str, 
+                &[]
+            ).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 rent_id: i32 = self.connection.query(
+                &str, 
+                &[]
+            ).await.unwrap().get(0).unwrap().get(0);
+        }
+
+        let elapsed = chrono::Utc::now().naive_local() - start_time;
+
+        Ok(elapsed.num_microseconds().unwrap())
+    }
+}
\ No newline at end of file
diff --git a/backend/src/storages/postgres/car.rs b/backend/src/storages/postgres/car.rs
index 92d8b33..0fb80b8 100644
--- a/backend/src/storages/postgres/car.rs
+++ b/backend/src/storages/postgres/car.rs
@@ -1,6 +1,6 @@
 use tokio_postgres::Client as PgClient;
 use std::sync::Arc;
-use crate::models::car::{BindingCar, Car};
+use crate::models::car::{BindingCar, Car, Report};
 use crate::storages::traits::CarRepository;
 use async_trait::async_trait;
 
@@ -28,7 +28,7 @@ impl CarRepository for PostgresCarRepository {
                 car_station_id: row.get("car_station_id")
             })
         } else {
-            Err("Something gone wrong during creation of Car".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -48,7 +48,7 @@ impl CarRepository for PostgresCarRepository {
                 car_station_id: row.get("car_station_id")
             })
         } else {
-            Err("Something gone wrong during reading of Car".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -69,7 +69,7 @@ impl CarRepository for PostgresCarRepository {
                 }).collect()
             )
         } else {
-            Err("Something gone wrong during reading CarStations".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -90,7 +90,7 @@ impl CarRepository for PostgresCarRepository {
                 car_station_id: row.get("car_station_id")
             })
         } else {
-            Err("Something gone wrong during updating of Car".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -107,7 +107,38 @@ impl CarRepository for PostgresCarRepository {
                 Ok(())
             }
         } else {
-            Err("Something gone wrong during deleting of Car".to_owned())
+            Err(result.unwrap_err().to_string())
+        }
+    }
+
+    async fn get_report(&self) -> Result<Vec<Report>, String> {
+        let result = self.connection.query(
+            "SELECT
+                c.id AS \"car_id\",
+                c.brand AS \"brand\",
+                c.model AS \"model\",
+                COUNT(r.id) AS \"times\",
+                ROUND(SUM(c.price * r.time_amount), 2) AS \"income\"
+            FROM car c
+            JOIN rent r ON c.id = r.car_id
+                WHERE date_trunc('month', r.start_time) = date_trunc('month', CURRENT_DATE)
+                GROUP BY c.id;", &[]
+        ).await;
+
+        if let Ok(rows) = result {
+            Ok(
+                rows.into_iter()
+                    .map(|row| Report {
+                        car_id: row.get("car_id"),
+                        brand: row.get("brand"),
+                        model: row.get("model"),
+                        times: row.get("times"),
+                        income: row.get("income")
+                    })
+                    .collect()
+            )
+        } else {
+            Err(result.unwrap_err().to_string())
         }
     }
 }
\ No newline at end of file
diff --git a/backend/src/storages/postgres/car_station.rs b/backend/src/storages/postgres/car_station.rs
index e599725..1fb7805 100644
--- a/backend/src/storages/postgres/car_station.rs
+++ b/backend/src/storages/postgres/car_station.rs
@@ -23,7 +23,7 @@ impl CarStationRepository for PostgresCarStationRepository {
                 address: row.get("address")
             })
         } else {
-            Err("Something gone wrong during creation of CarStation".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -39,7 +39,7 @@ impl CarStationRepository for PostgresCarStationRepository {
                 address: row.get("address")
             })
         } else {
-            Err("Something gone wrong during reading of CarStation".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -56,7 +56,7 @@ impl CarStationRepository for PostgresCarStationRepository {
                 }).collect()
             )
         } else {
-            Err("Something gone wrong during reading CarStations".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -73,7 +73,7 @@ impl CarStationRepository for PostgresCarStationRepository {
                 address: row.get("address")
             })
         } else {
-            Err("Something gone wrong during updating of CarStation".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -90,7 +90,7 @@ impl CarStationRepository for PostgresCarStationRepository {
                 Ok(())
             }
         } else {
-            Err("Something gone wrong during deleting of CarStation".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 }
\ No newline at end of file
diff --git a/backend/src/storages/postgres/client.rs b/backend/src/storages/postgres/client.rs
index f5fbe32..6ad6b23 100644
--- a/backend/src/storages/postgres/client.rs
+++ b/backend/src/storages/postgres/client.rs
@@ -27,7 +27,7 @@ impl ClientRepository for PostgresClientRepository {
                 phone: row.get("phone")
             })
         } else {
-            Err("Something gone wrong during creation of Client".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -47,7 +47,7 @@ impl ClientRepository for PostgresClientRepository {
                 phone: row.get("phone")
             })
         } else {
-            Err("Something gone wrong during reading of Client".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -67,7 +67,7 @@ impl ClientRepository for PostgresClientRepository {
                 }).collect()
             )
         } else {
-            Err("Something gone wrong during reading Clients".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -88,7 +88,7 @@ impl ClientRepository for PostgresClientRepository {
                 phone: row.get("phone")
             })
         } else {
-            Err("Something gone wrong during updating of Client".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -105,7 +105,7 @@ impl ClientRepository for PostgresClientRepository {
                 Ok(())
             }
         } else {
-            Err("Something gone wrong during deleting of Client".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 }
diff --git a/backend/src/storages/postgres/mod.rs b/backend/src/storages/postgres/mod.rs
index ced284f..ec478c8 100644
--- a/backend/src/storages/postgres/mod.rs
+++ b/backend/src/storages/postgres/mod.rs
@@ -3,4 +3,5 @@ pub mod car_station;
 pub mod car;
 pub mod rent;
 pub mod owner;
-pub mod administrator;
\ No newline at end of file
+pub mod administrator;
+pub mod benchmark;
\ No newline at end of file
diff --git a/backend/src/storages/postgres/owner.rs b/backend/src/storages/postgres/owner.rs
index 66794a3..6ae5f1c 100644
--- a/backend/src/storages/postgres/owner.rs
+++ b/backend/src/storages/postgres/owner.rs
@@ -27,7 +27,7 @@ impl OwnerRepository for PostgresOwnerRepository {
                 phone: row.get("phone")
             })
         } else {
-            Err("Something gone wrong during creation of Owner".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -47,7 +47,7 @@ impl OwnerRepository for PostgresOwnerRepository {
                 phone: row.get("phone")
             })
         } else {
-            Err("Something gone wrong during reading of Owner".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -67,7 +67,7 @@ impl OwnerRepository for PostgresOwnerRepository {
                 }).collect()
             )
         } else {
-            Err("Something gone wrong during reading Owner".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -88,7 +88,7 @@ impl OwnerRepository for PostgresOwnerRepository {
                 phone: row.get("phone")
             })
         } else {
-            Err("Something gone wrong during updating of Owner".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -105,7 +105,7 @@ impl OwnerRepository for PostgresOwnerRepository {
                 Ok(())
             }
         } else {
-            Err("Something gone wrong during deleting of Owner".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 }
diff --git a/backend/src/storages/postgres/rent.rs b/backend/src/storages/postgres/rent.rs
index 4cbdee2..84ed6a9 100644
--- a/backend/src/storages/postgres/rent.rs
+++ b/backend/src/storages/postgres/rent.rs
@@ -12,7 +12,7 @@ pub struct PostgresRentRepository {
 impl RentRepository for PostgresRentRepository {
     async fn create(&self, rent: BindingRent) -> Result<Rent, String> {
         let query_result = self.connection.query(
-            "SELECT * FROM Rent WHERE car_id=$1 AND time_amount IS NOT NULL",
+            "SELECT * FROM Rent WHERE car_id=$1 AND time_amount IS NULL",
             &[&rent.car_id]
         ).await;
 
@@ -21,7 +21,7 @@ impl RentRepository for PostgresRentRepository {
                 return Err("The car is already occupied".to_owned());
             }
         } else {
-            return Err("Something gone wrong during checking for existing rents".to_owned());
+            return Err(query_result.unwrap_err().to_string());
         }
 
         let result = self.connection.query(
@@ -40,7 +40,7 @@ impl RentRepository for PostgresRentRepository {
                 car_id: row.get("car_id")
             })
         } else {
-            Err("Something gone wrong during creation of Rent".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -59,7 +59,7 @@ impl RentRepository for PostgresRentRepository {
                 car_id: row.get("car_id")
             })
         } else {
-            Err("Something gone wrong during reading of Rent".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -79,7 +79,7 @@ impl RentRepository for PostgresRentRepository {
                 }).collect()
             )
         } else {
-            Err("Something gone wrong during reading CarStations".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -99,7 +99,7 @@ impl RentRepository for PostgresRentRepository {
                 car_id: row.get("car_id")
             })
         } else {
-            Err("Something gone wrong during updating of Rent".to_owned())
+            Err(result.unwrap_err().to_string())
         }
     }
 
@@ -111,7 +111,22 @@ impl RentRepository for PostgresRentRepository {
         if let Ok(_) = result {
             Ok(())
         } else {
-            Err("Something gone wrong during deletion of Rent".to_owned())
+            Err(result.unwrap_err().to_string())
+        }
+    }
+
+    async fn end_rent(&self, id: i32) -> Result<(), String> {
+        let current_rent = self.read(id).await?;
+
+        if current_rent.time_amount.is_some() {
+            return Err("Rent is already ended".to_owned());
+        }
+
+        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 {
+            Ok(_) => Ok(()),
+            Err(err) => Err(err.to_string())
         }
     }
 }
\ No newline at end of file
diff --git a/backend/src/storages/traits.rs b/backend/src/storages/traits.rs
index 26f0469..bf03e53 100644
--- a/backend/src/storages/traits.rs
+++ b/backend/src/storages/traits.rs
@@ -21,6 +21,7 @@ pub trait CarRepository {
     async fn read_all(&self) -> Result<Vec<Car>, String>;
     async fn update(&self, id: i32, car: BindingCar) -> Result<Car, String>;
     async fn delete(&self, id: i32) -> Result<(), String>;
+    async fn get_report(&self) -> Result<Vec<Report>, String>;
 }
 
 #[async_trait]
@@ -39,6 +40,7 @@ pub trait RentRepository {
     async fn read_all(&self) -> Result<Vec<Rent>, String>;
     async fn update(&self, id: i32, rent: BindingRent) -> Result<Rent, String>;
     async fn delete(&self, id: i32) -> Result<(), String>;
+    async fn end_rent(&self, id: i32) -> Result<(), String>;
 }
 
 #[async_trait]
@@ -54,4 +56,9 @@ pub trait OwnerRepository {
 pub trait AdministratorRepository {
     async fn read(&self, id: i32) -> Result<Administrator, String>;
     async fn find_by_username(&self, username: &str) -> Result<Administrator, String>;
+}
+
+#[async_trait]
+pub trait BenchmarkRepository {
+    async fn benchmark(&self) -> Result<i64, String>;
 }
\ No newline at end of file
-- 
2.25.1