From f6bb3306ee83d3a67d7af7f810c47e1d06d946f3 Mon Sep 17 00:00:00 2001 From: ultrageese Date: Sat, 6 Jun 2026 19:41:46 +1000 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=B0=D0=BC=D1=8B=D0=B9=20=D0=B4=D0=B5?= =?UTF-8?q?=D0=B3=D1=80=D0=B0=D0=B4=D0=B0=D0=BD=D1=82=D1=81=D0=BA=D0=B8?= =?UTF-8?q?=D0=B9=20=D0=BA=D0=BE=D0=B4=20=D0=BF=D1=80=D0=BE=D0=B2=D0=B5?= =?UTF-8?q?=D1=80=D0=BA=D0=B8=20=D0=BD=D0=B0=20=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=D1=8C=D0=BD=D0=BE=D1=81=D1=82=D1=8C=20=D0=BB=D0=BE?= =?UTF-8?q?=D0=B3=D0=B8=D0=BD=D0=B0=20=D0=B8=20=D0=BF=D0=B0=D1=80=D0=BE?= =?UTF-8?q?=D0=BB=D1=8F,=20=D0=BA=D0=BE=D1=82=D0=BE=D1=80=D1=8B=D0=B9=20?= =?UTF-8?q?=D1=8F=20=D0=BA=D0=BE=D0=B3=D0=B4=D0=B0-=D0=BB=D0=B8=D0=B1?= =?UTF-8?q?=D0=BE=20=D0=BF=D0=B8=D1=81=D0=B0=D0=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/Cargo.lock | 104 +++++++++++++++++++++++----- code/Cargo.toml | 2 + code/src/app.rs | 154 ++++++++++++++++++++++++++++++++--------- code/src/database.rs | 37 ++++++++++ code/src/models.rs | 82 +++++++++++++--------- code/src/recipe_tab.rs | 2 + 6 files changed, 296 insertions(+), 85 deletions(-) diff --git a/code/Cargo.lock b/code/Cargo.lock index 27bf8fe..96f516f 100644 --- a/code/Cargo.lock +++ b/code/Cargo.lock @@ -509,6 +509,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" +dependencies = [ + "hybrid-array", +] + [[package]] name = "block2" version = "0.5.1" @@ -749,7 +758,9 @@ dependencies = [ "egui", "egui_dock", "egui_extras", + "hex", "rust_decimal", + "sha2 0.11.0", "sqlx", "tokio", ] @@ -799,6 +810,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-oid" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + [[package]] name = "core-foundation" version = "0.9.4" @@ -858,6 +875,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "3.4.0" @@ -913,6 +939,15 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + [[package]] name = "cursor-icon" version = "1.2.0" @@ -925,7 +960,7 @@ version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "const-oid", + "const-oid 0.9.6", "pem-rfc7468", "zeroize", ] @@ -936,12 +971,23 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", + "block-buffer 0.10.4", + "const-oid 0.9.6", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.0", + "const-oid 0.10.2", + "crypto-common 0.2.2", +] + [[package]] name = "dispatch" version = "0.2.0" @@ -1815,7 +1861,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest", + "digest 0.10.7", ] [[package]] @@ -1827,6 +1873,15 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "hybrid-array" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +dependencies = [ + "typenum", +] + [[package]] name = "iana-time-zone" version = "0.1.65" @@ -2005,7 +2060,7 @@ dependencies = [ "portable-atomic-util", "serde_core", "wasm-bindgen", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -2239,7 +2294,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", - "digest", + "digest 0.10.7", ] [[package]] @@ -3365,8 +3420,8 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ - "const-oid", - "digest", + "const-oid 0.9.6", + "digest 0.10.7", "num-bigint-dig", "num-integer", "num-traits", @@ -3591,8 +3646,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", ] [[package]] @@ -3602,8 +3657,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", - "digest", + "cpufeatures 0.2.17", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "digest 0.11.3", ] [[package]] @@ -3628,7 +3694,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ - "digest", + "digest 0.10.7", "rand_core", ] @@ -3844,7 +3910,7 @@ dependencies = [ "percent-encoding", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "thiserror 2.0.18", "tokio", @@ -3881,7 +3947,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "sqlx-core", "sqlx-mysql", "sqlx-postgres", @@ -3905,7 +3971,7 @@ dependencies = [ "bytes", "chrono", "crc", - "digest", + "digest 0.10.7", "dotenvy", "either", "futures-channel", @@ -3926,7 +3992,7 @@ dependencies = [ "rsa", "serde", "sha1", - "sha2", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", @@ -3966,7 +4032,7 @@ dependencies = [ "rand", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "smallvec", "sqlx-core", "stringprep", diff --git a/code/Cargo.toml b/code/Cargo.toml index 4829f75..2fab5a0 100644 --- a/code/Cargo.toml +++ b/code/Cargo.toml @@ -12,7 +12,9 @@ eframe = "0.34.2" egui = "0.34.2" egui_dock = "0.19.1" egui_extras = {version = "0.34.2", features = ["datepicker"]} +hex = "0.4.3" rust_decimal = {version = "1.42.0", features = ["macros"]} +sha2 = "0.11.0" sqlx = {version="0.8.6", features = ["runtime-tokio", "mysql","bigdecimal","chrono"]} tokio={version = "1.52.3", features = ["full"]} diff --git a/code/src/app.rs b/code/src/app.rs index 392b75f..227de0b 100644 --- a/code/src/app.rs +++ b/code/src/app.rs @@ -1,22 +1,30 @@ use std::{collections::HashMap, ops::Deref, str::FromStr, sync::Arc}; use crate::{ - database::DBOperator, material_tab::MaterialTabViewer, models::{ - Equipment, Material, MaterialCategory, MaterialRow, ModalStatus, ModalWinState, Position, - Worker, - }, tab::*, worker_tab::* + database::DBOperator, + material_tab::MaterialTabViewer, + models::{ + Equipment, LoginModalState, Material, MaterialCategory, MaterialRow, ModalStatus, + ModalWinState, Position, Worker, + }, + tab::*, + worker_tab::*, }; use egui::{TextBuffer, Vec2, mutex::RwLock}; use egui_dock::{DockArea, Style, TabViewer}; use egui_extras::{Column, TableBuilder}; +use sha2::{Digest, Sha256}; use sqlx::types::BigDecimal; -pub struct App { +pub struct App<'a> { + pub login_modal_state: LoginModalState<'a>, pub tree: egui_dock::DockState, pub main_viewer: MainTabViewer, + pub db_oper: DBOperator, + pub rt: tokio::runtime::Runtime, } -impl Default for App { +impl Default for App<'_> { fn default() -> Self { let tree = egui_dock::DockState::new(vec![ Tab { @@ -49,17 +57,80 @@ impl Default for App { }, ]); let main_viewer = MainTabViewer::default(); - Self { tree, main_viewer } + let rt = tokio::runtime::Runtime::new().unwrap(); + Self { + tree, + main_viewer, + login_modal_state: LoginModalState { + is_open: true, + data: HashMap::from([("login", String::new()), ("password", String::new())]), + status: crate::models::LoginStatus::Login, + ..Default::default() + }, + db_oper: rt.block_on(DBOperator::new()), + rt, + } } } -impl App { +impl App<'_> { pub fn new(_cc: &eframe::CreationContext<'_>) -> Self { Default::default() } } -impl eframe::App for App { +impl eframe::App for App<'_> { fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { + if self.login_modal_state.is_open { + egui::Modal::new(egui::Id::new("login_modal")).show(ui.ctx(), |ui| { + ui.label("Пройдите авторизацию:"); + ui.add( + egui::TextEdit::singleline( + self.login_modal_state.data.get_mut("login").unwrap(), + ) + .hint_text("Введите логин"), + ); + ui.add( + egui::TextEdit::singleline( + self.login_modal_state.data.get_mut("password").unwrap(), + ) + .password(true) + .hint_text("Пароль"), + ); + if self.login_modal_state.fail { + ui.label(&self.login_modal_state.fail_message); + } + ui.vertical_centered(|ui| { + if ui.button("Авторизоваться").clicked() + || ui.input(|i| i.key_pressed(egui::Key::Enter)) + { + let uname = self.login_modal_state.data.get("login").unwrap().clone(); + if self.rt.block_on(async { + self.db_oper.check_username(uname.clone()).await.unwrap() + }) { + self.login_modal_state.fail = false; + let mut hashed_pass = Sha256::new(); + hashed_pass + .update(self.login_modal_state.data.get("password").unwrap()); + let pass_hash = hex::encode(hashed_pass.finalize()); + if self.rt.block_on(async { + self.db_oper.check_password(uname, pass_hash).await.unwrap() + }) { + self.login_modal_state.fail = false; + self.login_modal_state.status = + crate::models::LoginStatus::Finished; + self.login_modal_state.is_open = false; + } else { + self.login_modal_state.fail = true; + self.login_modal_state.fail_message = "Неверный пароль".to_string(); + } + } else { + self.login_modal_state.fail = true; + self.login_modal_state.fail_message = "Неверный логин".to_string(); + } + } + }); + }); + } DockArea::new(&mut self.tree) .style(Style::from_egui(ui.style().as_ref())) .show_inside(ui, &mut self.main_viewer); @@ -205,7 +276,20 @@ impl MainTabViewer { }); row.col(|ui| { if ui.button("Удалить").clicked() { - println!("WOr!k"); + self.equipment_modal_state.is_open = true; + self.equipment_modal_state.status = ModalStatus::Remove; + self.equipment_modal_state + .data + .insert("id".into(), eq.id.to_string()); + self.equipment_modal_state + .data + .insert("name".into(), eq.name.clone()); + self.equipment_modal_state + .data + .insert("inv_numver".into(), eq.inv_number.clone()); + self.equipment_modal_state + .data + .insert("worker_id".into(), eq.worker.id.to_string()); } }); if row.response().double_clicked() { @@ -232,33 +316,35 @@ impl MainTabViewer { if ui.button("Закрыть").clicked() { self.equipment_modal_state.is_open = false; } - egui::Grid::new("process_equipment_grid").show(ui, |ui| { - ui.label("Название"); - let mut name = self.equipment_modal_state.data.get_mut("name").unwrap(); - ui.add_sized(Vec2::new(200.0, 20.0), egui::TextEdit::singleline(name)); - ui.end_row(); + if self.equipment_modal_state.status != ModalStatus::Remove { + egui::Grid::new("process_equipment_grid").show(ui, |ui| { + ui.label("Название"); + let mut name = self.equipment_modal_state.data.get_mut("name").unwrap(); + ui.add_sized(Vec2::new(200.0, 20.0), egui::TextEdit::singleline(name)); + ui.end_row(); - ui.label("Инв. номер"); - let mut inv_num = self - .equipment_modal_state - .data - .get_mut("inv_number") - .unwrap(); - ui.text_edit_singleline(inv_num); - ui.end_row(); + ui.label("Инв. номер"); + let mut inv_num = self + .equipment_modal_state + .data + .get_mut("inv_number") + .unwrap(); + ui.text_edit_singleline(inv_num); + ui.end_row(); - ui.label("Ответственный"); - // egui::ComboBox::new("process_equipment_combobox"); - ui.end_row(); + ui.label("Ответственный"); + // egui::ComboBox::new("process_equipment_combobox"); + ui.end_row(); - ui.label("Дата последнего\nтехобслуживания"); - let mut maintenance = self - .equipment_modal_state - .data - .get_mut("maintenance_date") - .unwrap(); - ui.text_edit_singleline(maintenance); - }); + ui.label("Дата последнего\nтехобслуживания"); + let mut maintenance = self + .equipment_modal_state + .data + .get_mut("maintenance_date") + .unwrap(); + ui.text_edit_singleline(maintenance); + }); + } }); } } diff --git a/code/src/database.rs b/code/src/database.rs index eedfe47..81798e1 100644 --- a/code/src/database.rs +++ b/code/src/database.rs @@ -283,6 +283,43 @@ impl DBOperator { Err(_) => Ok(false), } } + pub async fn check_username(&self, username: String) -> Result { + let ans = sqlx::query("SELECT * FROM Brewery.profile WHERE login=?") + .bind(username) + .fetch_all(&self.pool) + .await; + match ans { + Ok(n) => { + if n.len() > 0 { + return Ok(true); + } else { + return Ok(false); + } + } + Err(_) => Ok(false), + } + } + pub async fn check_password( + &self, + username: String, + password_hash: String, + ) -> Result { + let ans = sqlx::query("SELECT * FROM Brewery.profile WHERE login=? AND password=?") + .bind(username) + .bind(password_hash) + .fetch_all(&self.pool) + .await; + match ans { + Ok(n) => { + if n.len() > 0 { + return Ok(true); + } else { + return Ok(false); + } + } + Err(_) => Ok(false), + } + } } pub async fn estabilish_connection() -> Result<(), sqlx::Error> { diff --git a/code/src/models.rs b/code/src/models.rs index e34d789..816e178 100644 --- a/code/src/models.rs +++ b/code/src/models.rs @@ -3,20 +3,23 @@ use std::{any::TypeId, ops::Deref}; use egui::TextBuffer; use sqlx::types::{BigDecimal, chrono::DateTime}; - #[derive(Clone, Hash, sqlx::FromRow, PartialEq)] -pub struct Position{ +pub struct Position { pub id: i32, pub name: String, pub wage: BigDecimal, } -impl Default for Position{ +impl Default for Position { fn default() -> Self { - Self { id: 1, name: "".into(), wage: 0.into() } + Self { + id: 1, + name: "".into(), + wage: 0.into(), + } } } #[derive(Default, Clone, Hash)] -pub struct Worker{ +pub struct Worker { pub id: i32, pub full_name: String, pub hire_date: DateTime, @@ -24,14 +27,14 @@ pub struct Worker{ pub is_fired: bool, } #[derive(sqlx::FromRow, sqlx::Decode)] -pub struct WorkerRow{ +pub struct WorkerRow { pub id: i32, pub full_name: String, pub hire_date: DateTime, pub position_id: i32, pub is_fired: bool, } -pub struct Salary{ +pub struct Salary { id: i32, worker: Worker, salary_size: rust_decimal::Decimal, @@ -39,7 +42,7 @@ pub struct Salary{ } #[derive(Default, Clone, Hash)] -pub struct Equipment{ +pub struct Equipment { pub id: i32, pub name: String, pub inv_number: String, @@ -47,7 +50,7 @@ pub struct Equipment{ pub worker: Worker, } #[derive(sqlx::FromRow)] -pub struct EquipmentRow{ +pub struct EquipmentRow { pub id: i32, pub name: String, pub inv_number: String, @@ -55,72 +58,87 @@ pub struct EquipmentRow{ pub worker_id: i32, } #[derive(Clone)] -pub struct Material{ +pub struct Material { pub id: i32, pub name: String, pub quantity: i32, - pub category: MaterialCategory + pub category: MaterialCategory, } #[derive(sqlx::FromRow)] -pub struct MaterialRow{ +pub struct MaterialRow { pub id: i32, pub name: String, pub quantity: i32, pub category_id: i32, } #[derive(sqlx::FromRow, Default, Clone, PartialEq)] -pub struct MaterialCategory{ +pub struct MaterialCategory { pub id: i32, pub name: String, } -pub struct RecipeElement{ - id:i32, +pub struct RecipeElement { + id: i32, material: Material, equipment: Equipment, - quantity: i32 + quantity: i32, } -pub struct Recipe{ +pub struct Recipe { id: i32, name: String, elements: std::vec::Vec, } -pub struct Client{ +pub struct Client { id: i32, name: String, - address: String + address: String, } -pub struct Order<'a>{ - id: i32, +pub struct Order<'a> { + id: i32, client: Client, order_date: chrono::DateTime, total_amount: rust_decimal::Decimal, - elements: std::vec::Vec> + elements: std::vec::Vec>, } -pub struct OrderElement<'a>{ +pub struct OrderElement<'a> { id: i32, product: Product<'a>, quantity: i32, - total_amount: rust_decimal::Decimal -} -pub struct Product<'a>{ + total_amount: rust_decimal::Decimal, +} +pub struct Product<'a> { id: i32, recipe: &'a Recipe, volume: f64, price_per_unit: rust_decimal::Decimal, - } #[derive(Default)] -pub struct ModalWinState{ +pub struct ModalWinState { pub is_open: bool, pub can_finish: bool, - pub data: std::collections::HashMap, + pub data: std::collections::HashMap, pub status: ModalStatus, } #[derive(Default, PartialEq)] -pub enum ModalStatus{ +pub enum ModalStatus { #[default] Add, Edit, - Remove -} \ No newline at end of file + Remove, +} + +#[derive(Default)] +pub struct LoginModalState<'a> { + pub is_open: bool, + pub data: std::collections::HashMap<&'a str, String>, + pub status: LoginStatus, + pub fail: bool, + pub fail_message: String, +} + +#[derive(Default)] +pub enum LoginStatus { + #[default] + Login, + Finished, +} diff --git a/code/src/recipe_tab.rs b/code/src/recipe_tab.rs index 6d7ea36..56cc59e 100644 --- a/code/src/recipe_tab.rs +++ b/code/src/recipe_tab.rs @@ -1,3 +1,5 @@ +use crate::tab::{Tab, TabTypes}; + struct RecipeTabViewer {} impl RecipeTabViewer {