From a87656274babe838d1aa06248902f3aa046d0f75 Mon Sep 17 00:00:00 2001 From: Kirill Date: Thu, 23 Oct 2025 22:55:05 +0300 Subject: [PATCH 01/25] feat(dependencies.txt): Lib fix Added libs for working with PSQL and dot-env --- dependencies.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dependencies.txt b/dependencies.txt index eabd61c..62c9803 100644 --- a/dependencies.txt +++ b/dependencies.txt @@ -1 +1,3 @@ flask==3.1.2 +python-dotenv +psycopg-binary==3.2.10 -- 2.52.0 From a062d24b247eb8bc9074a45ad3bc3074b8927bd5 Mon Sep 17 00:00:00 2001 From: Kirill Date: Thu, 23 Oct 2025 22:56:41 +0300 Subject: [PATCH 02/25] feat(utils/loadDotEnv.py): Enviroment Function for download enviroment variables from .env to Enviroment --- utils/loadDotEnv.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 utils/loadDotEnv.py diff --git a/utils/loadDotEnv.py b/utils/loadDotEnv.py new file mode 100644 index 0000000..1edf728 --- /dev/null +++ b/utils/loadDotEnv.py @@ -0,0 +1,12 @@ +import os +from dotenv import load_dotenv + +def initializeENV(): + dotenv_path = '../.env' + if os.path.exists(dotenv_path): + load_dotenv(dotenv_path) + print('.env is loaded') + return 1 + else: + print('.env isn`t loaded') + return 0 -- 2.52.0 From 35f18853fc91bb41b1817aec9ce45d1201f22ed6 Mon Sep 17 00:00:00 2001 From: Kirill Date: Thu, 23 Oct 2025 23:00:00 +0300 Subject: [PATCH 03/25] feat(utils/PostgressConnect.py): Postgress connect Functional Added Functions with connect to postgress db by link from enviroment --- utils/PostgressConnect.py | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 utils/PostgressConnect.py diff --git a/utils/PostgressConnect.py b/utils/PostgressConnect.py new file mode 100644 index 0000000..6bc71a7 --- /dev/null +++ b/utils/PostgressConnect.py @@ -0,0 +1,10 @@ +import psycopg +import os + +def PSQLConnect(): + conn = psycopg.connect(os.getenv('POSTDRESS_CONNECTION')) + return conn + +def PSQLCursor(conn): + cur = conn.cursor() + return cur -- 2.52.0 From eabc193d8b64e38afc48a0cb5c9a62ef3a4651a2 Mon Sep 17 00:00:00 2001 From: Kirill Date: Thu, 23 Oct 2025 23:01:22 +0300 Subject: [PATCH 04/25] feat(utils/InitalizeDB.py): PSQL initializing Add script with is connected to db and initialize it --- utils/InitalizeDB.py | 79 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 utils/InitalizeDB.py diff --git a/utils/InitalizeDB.py b/utils/InitalizeDB.py new file mode 100644 index 0000000..b70ab13 --- /dev/null +++ b/utils/InitalizeDB.py @@ -0,0 +1,79 @@ +import psycopg +from PostgressConnect import PSQLConnect, PSQLCursor +from loadDotEnv import initializeENV + +state = initializeENV() +conn = PSQLConnect() +cur = PSQLCursor(conn) + +cur.execute(''' + -- Пользователи системы +CREATE TABLE users ( + id SERIAL PRIMARY KEY, + email VARCHAR(255) UNIQUE NOT NULL, + password_hash VARCHAR(255) NOT NULL, + name VARCHAR(255) NOT NULL, + role VARCHAR(50) NOT NULL, -- 'operator', 'admin', 'viewer' + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Роботы +CREATE TABLE robots ( + id VARCHAR(50) PRIMARY KEY, -- 'RB-001' + status VARCHAR(50) DEFAULT 'active', + battery_level INTEGER, + last_update TIMESTAMP, + current_zone VARCHAR(10), + current_row INTEGER, + current_shelf INTEGER +); + + +-- Товары + +CREATE TABLE products ( + id VARCHAR(50) PRIMARY KEY, -- 'TEL-4567' + name VARCHAR(255) NOT NULL, + category VARCHAR(100), + min_stock INTEGER DEFAULT 10, + optimal_stock INTEGER DEFAULT 100 +); + + +-- История инвентаризации +CREATE TABLE inventory_history ( + id SERIAL PRIMARY KEY, + robot_id VARCHAR(50) REFERENCES robots(id), + product_id VARCHAR(50) REFERENCES productsuid), + quantity INTEGER NOT NULL, + zone VARCHAR(10) NOT NULL, + row_number INTEGER, + shelf_number INTEGER, + status VARCHAR(50), -- 'OK', 'LOW_STOCK', 'CRITICAL' + scanned_at TIMESTAMP NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + + +-- Прогнозы ИИ +CREATE TABLE ai_predictions ( + id SERIAL PRIMARY KEY, + product_id VARCHAR(50) REFERENCES products(id), + prediction_date DATE NOT NULL, + days_until_stockout INTEGER, + recommended_order INTEGER, + confidence_score DECIMAL(3,2), + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Индексы для оптимизации +REATE INDEX idx_inventory_scanned ON inventory_history(scanned_at DESC); +CREATE INDEX idx_inventory_product ON inventory_history(product_id); +CREATE INDEX idx_inventory_zone ON inventory_history(zone); + ''') +conn.commit() + +cur.close() +conn.close() + +print("DB is Initialized") -- 2.52.0 From 061b7a86a33bb533bfba8e06794e2610aacea290 Mon Sep 17 00:00:00 2001 From: Kirill Date: Sat, 25 Oct 2025 11:18:06 +0300 Subject: [PATCH 05/25] fix(dependencies.txt): JVT tocken libs --- dependencies.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dependencies.txt b/dependencies.txt index 62c9803..5758f3e 100644 --- a/dependencies.txt +++ b/dependencies.txt @@ -1,3 +1,4 @@ flask==3.1.2 python-dotenv -psycopg-binary==3.2.10 +psycopg-binary +pyjwt -- 2.52.0 From da05ae96d2a9b26f5dc362a3ac3fcfe68e918c57 Mon Sep 17 00:00:00 2001 From: Kirill Date: Sat, 25 Oct 2025 11:19:20 +0300 Subject: [PATCH 06/25] fix(controllers/controller.py; model/example.py; utils/InitalizeDB.py): deleted exaple files --- controllers/controller.py | 0 model/example.py | 0 utils/InitalizeDB.py | 79 --------------------------------------- 3 files changed, 79 deletions(-) delete mode 100644 controllers/controller.py delete mode 100644 model/example.py delete mode 100644 utils/InitalizeDB.py diff --git a/controllers/controller.py b/controllers/controller.py deleted file mode 100644 index e69de29..0000000 diff --git a/model/example.py b/model/example.py deleted file mode 100644 index e69de29..0000000 diff --git a/utils/InitalizeDB.py b/utils/InitalizeDB.py deleted file mode 100644 index b70ab13..0000000 --- a/utils/InitalizeDB.py +++ /dev/null @@ -1,79 +0,0 @@ -import psycopg -from PostgressConnect import PSQLConnect, PSQLCursor -from loadDotEnv import initializeENV - -state = initializeENV() -conn = PSQLConnect() -cur = PSQLCursor(conn) - -cur.execute(''' - -- Пользователи системы -CREATE TABLE users ( - id SERIAL PRIMARY KEY, - email VARCHAR(255) UNIQUE NOT NULL, - password_hash VARCHAR(255) NOT NULL, - name VARCHAR(255) NOT NULL, - role VARCHAR(50) NOT NULL, -- 'operator', 'admin', 'viewer' - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); - --- Роботы -CREATE TABLE robots ( - id VARCHAR(50) PRIMARY KEY, -- 'RB-001' - status VARCHAR(50) DEFAULT 'active', - battery_level INTEGER, - last_update TIMESTAMP, - current_zone VARCHAR(10), - current_row INTEGER, - current_shelf INTEGER -); - - --- Товары - -CREATE TABLE products ( - id VARCHAR(50) PRIMARY KEY, -- 'TEL-4567' - name VARCHAR(255) NOT NULL, - category VARCHAR(100), - min_stock INTEGER DEFAULT 10, - optimal_stock INTEGER DEFAULT 100 -); - - --- История инвентаризации -CREATE TABLE inventory_history ( - id SERIAL PRIMARY KEY, - robot_id VARCHAR(50) REFERENCES robots(id), - product_id VARCHAR(50) REFERENCES productsuid), - quantity INTEGER NOT NULL, - zone VARCHAR(10) NOT NULL, - row_number INTEGER, - shelf_number INTEGER, - status VARCHAR(50), -- 'OK', 'LOW_STOCK', 'CRITICAL' - scanned_at TIMESTAMP NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); - - --- Прогнозы ИИ -CREATE TABLE ai_predictions ( - id SERIAL PRIMARY KEY, - product_id VARCHAR(50) REFERENCES products(id), - prediction_date DATE NOT NULL, - days_until_stockout INTEGER, - recommended_order INTEGER, - confidence_score DECIMAL(3,2), - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); - --- Индексы для оптимизации -REATE INDEX idx_inventory_scanned ON inventory_history(scanned_at DESC); -CREATE INDEX idx_inventory_product ON inventory_history(product_id); -CREATE INDEX idx_inventory_zone ON inventory_history(zone); - ''') -conn.commit() - -cur.close() -conn.close() - -print("DB is Initialized") -- 2.52.0 From 0e668e1993ab8067ce917549a25b9507580a5853 Mon Sep 17 00:00:00 2001 From: Kirill Date: Sat, 25 Oct 2025 11:21:32 +0300 Subject: [PATCH 07/25] feat(utils/token.py): Create JVT token Added function with is creating jvt tocken for user --- utils/token.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 utils/token.py diff --git a/utils/token.py b/utils/token.py new file mode 100644 index 0000000..5a3468d --- /dev/null +++ b/utils/token.py @@ -0,0 +1,7 @@ +import jwt +import os + +def generateKey(email, passwd): + key = os.getenv('KEY') + encoded = jwt.encode({f"{email}": f"{passwd}"}, key, algorithm="HS256") + return encoded -- 2.52.0 From 2098719c82d15df9cfd697f3cb6af85a3379a94e Mon Sep 17 00:00:00 2001 From: Kirill Date: Sat, 25 Oct 2025 11:23:01 +0300 Subject: [PATCH 08/25] feat(model/user.py): User model User Dataclass with is get all user respons data --- model/user.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 model/user.py diff --git a/model/user.py b/model/user.py new file mode 100644 index 0000000..ad41017 --- /dev/null +++ b/model/user.py @@ -0,0 +1,22 @@ +from dataclasses import dataclass +import json +from utils.token import generateKey + +@dataclass +class user: + id: int + name: str + role: str + token: str + + @classmethod + def initialize(cls, email:str, passwd:str): + #us = getUsModel() #возвращает словарь + id = 1#us['id'] + name = 'Bob'#us['name'] + role = 'Backend'#us['role'] + token = generateKey(email, passwd) + return cls(id=id, name=name, role=role, token=token) + + def toJSON(self): + return json.dumps({"token": f'{self.token}', "user": {"id": self.id, "role": f'{self.role}', "name": f'{self.name}'}}) -- 2.52.0 From 1bf9c69c2bc8fefb3629111f80c1990d75f36c81 Mon Sep 17 00:00:00 2001 From: Kirill Date: Sat, 25 Oct 2025 11:24:31 +0300 Subject: [PATCH 09/25] feat(api/loginapi.py): Login Api Blueprint with api login page with is get respons (form-data) and send JVT token and user id name and role --- api/loginapi.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 api/loginapi.py diff --git a/api/loginapi.py b/api/loginapi.py new file mode 100644 index 0000000..3ca2e88 --- /dev/null +++ b/api/loginapi.py @@ -0,0 +1,12 @@ +from flask import Blueprint, request +from model.user import user + +loginBP = Blueprint("loginapi", __name__) + +@loginBP.route('/api/login', methods = ['POST']) +def login(): + email = request.form['email'] + password = request.form['password'] + #if(isvalid(email, password)): + us = user.initialize(email, password) + return us.toJSON() -- 2.52.0 From 7ccc9385e6b9214a53940f5d5dd588a4692f917e Mon Sep 17 00:00:00 2001 From: Kirill Date: Sat, 25 Oct 2025 11:26:46 +0300 Subject: [PATCH 10/25] feat(app.py): Include Blueprint to app --- app.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app.py b/app.py index 811f514..90e60b3 100644 --- a/app.py +++ b/app.py @@ -1,4 +1,6 @@ from flask import Flask +from api.loginapi import loginBP app = Flask(__name__) +app.register_blueprint(loginBP) -- 2.52.0 From 3a118c51b594f13c5df43f3157bb18656814975b Mon Sep 17 00:00:00 2001 From: Kirill Date: Sat, 25 Oct 2025 20:53:48 +0300 Subject: [PATCH 11/25] fix(api/auth/loginapi.py): Pull request review https://g.codrs.ru/Hackaton/Backend/pulls/2#issuecomment-26 https://g.codrs.ru/Hackaton/Backend/pulls/2#issuecomment-20 https://g.codrs.ru/Hackaton/Backend/pulls/2#issuecomment-35 --- api/{ => auth}/loginapi.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename api/{ => auth}/loginapi.py (67%) diff --git a/api/loginapi.py b/api/auth/loginapi.py similarity index 67% rename from api/loginapi.py rename to api/auth/loginapi.py index 3ca2e88..791432f 100644 --- a/api/loginapi.py +++ b/api/auth/loginapi.py @@ -1,4 +1,4 @@ -from flask import Blueprint, request +from flask import Blueprint, request, jsonify from model.user import user loginBP = Blueprint("loginapi", __name__) @@ -8,5 +8,5 @@ def login(): email = request.form['email'] password = request.form['password'] #if(isvalid(email, password)): - us = user.initialize(email, password) - return us.toJSON() + us = user(email, password) + return jsonify(us.toDictionary()) -- 2.52.0 From 5058df8b7da897db15a02e2856fa6c7cd9133054 Mon Sep 17 00:00:00 2001 From: Kirill Date: Sat, 25 Oct 2025 20:57:23 +0300 Subject: [PATCH 12/25] fix(model/user.py): Code review fix https://g.codrs.ru/Hackaton/Backend/pulls/2#issuecomment-20 https://g.codrs.ru/Hackaton/Backend/pulls/2#issuecomment-25 https://g.codrs.ru/Hackaton/Backend/pulls/2#issuecomment-21 --- model/user.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/model/user.py b/model/user.py index ad41017..fcf8e0a 100644 --- a/model/user.py +++ b/model/user.py @@ -9,14 +9,12 @@ class user: role: str token: str - @classmethod - def initialize(cls, email:str, passwd:str): + def __init__(self, email: str, passwd: str): #us = getUsModel() #возвращает словарь - id = 1#us['id'] - name = 'Bob'#us['name'] - role = 'Backend'#us['role'] - token = generateKey(email, passwd) - return cls(id=id, name=name, role=role, token=token) + self.id = 1#us['id'] + self.name = 'Bob'#us['name'] + self.role = 'Backend'#us['role'] + self.token = generateKey(email, passwd) - def toJSON(self): - return json.dumps({"token": f'{self.token}', "user": {"id": self.id, "role": f'{self.role}', "name": f'{self.name}'}}) + def toDictionary(self): + return {"user": {"id": self.id, "name": self.name, "role": self.role}, "token": self.token} -- 2.52.0 From 22da586aec15e7617e2d4484ae240dbc699a2e2b Mon Sep 17 00:00:00 2001 From: Kirill Date: Sat, 25 Oct 2025 20:59:41 +0300 Subject: [PATCH 13/25] fix(app.py): Code review fix https://g.codrs.ru/Hackaton/Backend/pulls/2#issuecomment-30 --- app.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app.py b/app.py index 90e60b3..0d141d5 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,8 @@ from flask import Flask -from api.loginapi import loginBP +from api.auth.loginapi import loginBP +from utils.loadDotEnv import initializeENV + +state = initializeENV() app = Flask(__name__) -- 2.52.0 From f93b94531cbde4531f893ed3fc21fd0b5611fccc Mon Sep 17 00:00:00 2001 From: Kirill Date: Sat, 25 Oct 2025 21:01:45 +0300 Subject: [PATCH 14/25] fix(utils/token.py): Code review fix https://g.codrs.ru/Hackaton/Backend/pulls/2#issuecomment-24 --- utils/token.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/token.py b/utils/token.py index 5a3468d..90a69a9 100644 --- a/utils/token.py +++ b/utils/token.py @@ -3,5 +3,5 @@ import os def generateKey(email, passwd): key = os.getenv('KEY') - encoded = jwt.encode({f"{email}": f"{passwd}"}, key, algorithm="HS256") + encoded = jwt.encode({email: passwd}, key, algorithm="HS256") return encoded -- 2.52.0 From ce4885907971eae692c2c4d50b64cdf7bd22bdee Mon Sep 17 00:00:00 2001 From: Kirill Date: Sun, 26 Oct 2025 14:10:10 +0300 Subject: [PATCH 15/25] fix(api/auth/loginapi.py, app.py, utils/PostgressConnect.py, utils/createLogger.py, utils/loadDotEnv.py): Review fix https://g.codrs.ru/Hackaton/Backend/pulls/2#issuecomment-23 https://g.codrs.ru/Hackaton/Backend/pulls/2#issuecomment-31 --- api/auth/loginapi.py | 19 +++++++++++++------ app.py | 3 +++ utils/PostgressConnect.py | 6 +++--- utils/createLogger.py | 6 ++++++ utils/loadDotEnv.py | 7 +++++-- 5 files changed, 30 insertions(+), 11 deletions(-) create mode 100644 utils/createLogger.py diff --git a/api/auth/loginapi.py b/api/auth/loginapi.py index 791432f..36dea16 100644 --- a/api/auth/loginapi.py +++ b/api/auth/loginapi.py @@ -1,12 +1,19 @@ from flask import Blueprint, request, jsonify from model.user import user +from utils.createLogger import createLogger loginBP = Blueprint("loginapi", __name__) - +log = createLogger("LoginAPI") @loginBP.route('/api/login', methods = ['POST']) def login(): - email = request.form['email'] - password = request.form['password'] - #if(isvalid(email, password)): - us = user(email, password) - return jsonify(us.toDictionary()) + if request.is_json: + req = request.json + email = req['email'] + password = req['password'] + #if(isvalid(email, password)): + us = user(email, password) + log.debug("Respons is sended") + return jsonify(us.toDictionary()) + else: + log.error("Request is not a JSON") + return "Request is not a json", 500 diff --git a/app.py b/app.py index 0d141d5..0f7ae34 100644 --- a/app.py +++ b/app.py @@ -1,8 +1,11 @@ from flask import Flask from api.auth.loginapi import loginBP from utils.loadDotEnv import initializeENV +from utils.PostgressConnect import PSQLConnect, PSQLCursor state = initializeENV() +#conn = PSQLConnect() +#cur = PSQLCursor(conn) app = Flask(__name__) diff --git a/utils/PostgressConnect.py b/utils/PostgressConnect.py index 6bc71a7..d420fbf 100644 --- a/utils/PostgressConnect.py +++ b/utils/PostgressConnect.py @@ -1,10 +1,10 @@ -import psycopg +import psycopg2 import os def PSQLConnect(): - conn = psycopg.connect(os.getenv('POSTDRESS_CONNECTION')) + conn = psycopg2.connect(os.getenv('POSTDRESS_CONNECTION')) return conn def PSQLCursor(conn): - cur = conn.cursor() + cur = conn.cursor() return cur diff --git a/utils/createLogger.py b/utils/createLogger.py new file mode 100644 index 0000000..7071f0e --- /dev/null +++ b/utils/createLogger.py @@ -0,0 +1,6 @@ +import logging + +def createLogger(name: str): + logger = logging.getLogger() + logger.propagate = False + return logger diff --git a/utils/loadDotEnv.py b/utils/loadDotEnv.py index 1edf728..ec6c9d5 100644 --- a/utils/loadDotEnv.py +++ b/utils/loadDotEnv.py @@ -1,12 +1,15 @@ import os from dotenv import load_dotenv +from .createLogger import createLogger + +log = createLogger("ENV") def initializeENV(): dotenv_path = '../.env' if os.path.exists(dotenv_path): load_dotenv(dotenv_path) - print('.env is loaded') + log.info('.env is loaded') return 1 else: - print('.env isn`t loaded') + log.error('.env isn`t loaded') return 0 -- 2.52.0 From 2b7fecb2487b4d3c5b9abb41a2b3390d9310b5bc Mon Sep 17 00:00:00 2001 From: Sweetbread Date: Sun, 26 Oct 2025 14:55:43 +0300 Subject: [PATCH 16/25] fix(env): ensure the .env is loaded --- .env.tmp | 2 ++ app.py | 5 ++++- dependencies.txt | 2 +- utils/PostgressConnect.py | 2 +- utils/loadDotEnv.py | 12 ++++++------ 5 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 .env.tmp diff --git a/.env.tmp b/.env.tmp new file mode 100644 index 0000000..d121f85 --- /dev/null +++ b/.env.tmp @@ -0,0 +1,2 @@ +KEY= # Key for JWT token +POSTGRES_URL=postgresql:// diff --git a/app.py b/app.py index 0f7ae34..f225ca0 100644 --- a/app.py +++ b/app.py @@ -1,9 +1,12 @@ +from sys import exit from flask import Flask from api.auth.loginapi import loginBP from utils.loadDotEnv import initializeENV from utils.PostgressConnect import PSQLConnect, PSQLCursor -state = initializeENV() +if not initializeENV(): + exit(-1) + #conn = PSQLConnect() #cur = PSQLCursor(conn) diff --git a/dependencies.txt b/dependencies.txt index 5758f3e..4fc4ead 100644 --- a/dependencies.txt +++ b/dependencies.txt @@ -1,4 +1,4 @@ flask==3.1.2 python-dotenv -psycopg-binary +psycopg2-binary pyjwt diff --git a/utils/PostgressConnect.py b/utils/PostgressConnect.py index d420fbf..ea6a485 100644 --- a/utils/PostgressConnect.py +++ b/utils/PostgressConnect.py @@ -2,7 +2,7 @@ import psycopg2 import os def PSQLConnect(): - conn = psycopg2.connect(os.getenv('POSTDRESS_CONNECTION')) + conn = psycopg2.connect(os.getenv('POSTGRES_URL')) return conn def PSQLCursor(conn): diff --git a/utils/loadDotEnv.py b/utils/loadDotEnv.py index ec6c9d5..85bbc72 100644 --- a/utils/loadDotEnv.py +++ b/utils/loadDotEnv.py @@ -2,14 +2,14 @@ import os from dotenv import load_dotenv from .createLogger import createLogger +DOTENV_PATH = '.env' log = createLogger("ENV") -def initializeENV(): - dotenv_path = '../.env' - if os.path.exists(dotenv_path): - load_dotenv(dotenv_path) +def initializeENV() -> bool: + if os.path.exists(DOTENV_PATH): + load_dotenv(DOTENV_PATH) log.info('.env is loaded') - return 1 + return True else: log.error('.env isn`t loaded') - return 0 + return False -- 2.52.0 From 920c51b4f0bf5787cfce19cc7ed8ebe7fc7178a2 Mon Sep 17 00:00:00 2001 From: Sweetbread Date: Sun, 26 Oct 2025 14:57:49 +0300 Subject: [PATCH 17/25] refactor(user): change class name to uppercase --- api/auth/loginapi.py | 6 +++--- model/user.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/api/auth/loginapi.py b/api/auth/loginapi.py index 36dea16..eaa0ca8 100644 --- a/api/auth/loginapi.py +++ b/api/auth/loginapi.py @@ -1,5 +1,5 @@ from flask import Blueprint, request, jsonify -from model.user import user +from model.user import User from utils.createLogger import createLogger loginBP = Blueprint("loginapi", __name__) @@ -11,9 +11,9 @@ def login(): email = req['email'] password = req['password'] #if(isvalid(email, password)): - us = user(email, password) + user = User(email, password) log.debug("Respons is sended") - return jsonify(us.toDictionary()) + return jsonify(user.toDictionary()) else: log.error("Request is not a JSON") return "Request is not a json", 500 diff --git a/model/user.py b/model/user.py index fcf8e0a..6ad8c5d 100644 --- a/model/user.py +++ b/model/user.py @@ -3,7 +3,7 @@ import json from utils.token import generateKey @dataclass -class user: +class User: id: int name: str role: str -- 2.52.0 From 2a7c74286c52e16113dcb3a70d98fe3e44fde476 Mon Sep 17 00:00:00 2001 From: Sweetbread Date: Sun, 26 Oct 2025 15:08:14 +0300 Subject: [PATCH 18/25] feat(auth): add data validation --- api/auth/loginapi.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/api/auth/loginapi.py b/api/auth/loginapi.py index eaa0ca8..27ffbea 100644 --- a/api/auth/loginapi.py +++ b/api/auth/loginapi.py @@ -1,19 +1,28 @@ from flask import Blueprint, request, jsonify from model.user import User -from utils.createLogger import createLogger loginBP = Blueprint("loginapi", __name__) -log = createLogger("LoginAPI") -@loginBP.route('/api/login', methods = ['POST']) + + +@loginBP.route('/api/auth/login', methods = ['POST']) def login(): if request.is_json: req = request.json - email = req['email'] - password = req['password'] - #if(isvalid(email, password)): + + email = req.get('email') + password = req.get('password') + + if not email or not password: + return "Request must have email and password", 400 + + if len(email.strip()) < 4 or '@' not in email or '.' not in email: + return "Email is incorrect", 400 + + if len(password.strip()) < 8: + return "Password is too short", 400 + user = User(email, password) - log.debug("Respons is sended") return jsonify(user.toDictionary()) + else: - log.error("Request is not a JSON") - return "Request is not a json", 500 + return "Request is not a json", 400 -- 2.52.0 From f99c0e8148a359968ef6030416d0f2f6007981a2 Mon Sep 17 00:00:00 2001 From: Sweetbread Date: Sun, 26 Oct 2025 15:23:06 +0300 Subject: [PATCH 19/25] refactor(user): rename to toJson back --- api/auth/loginapi.py | 2 +- model/user.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/auth/loginapi.py b/api/auth/loginapi.py index 27ffbea..ab095e9 100644 --- a/api/auth/loginapi.py +++ b/api/auth/loginapi.py @@ -22,7 +22,7 @@ def login(): return "Password is too short", 400 user = User(email, password) - return jsonify(user.toDictionary()) + return jsonify(user.toJson()) else: return "Request is not a json", 400 diff --git a/model/user.py b/model/user.py index 6ad8c5d..03d51fa 100644 --- a/model/user.py +++ b/model/user.py @@ -16,5 +16,5 @@ class User: self.role = 'Backend'#us['role'] self.token = generateKey(email, passwd) - def toDictionary(self): + def toJson(self): return {"user": {"id": self.id, "name": self.name, "role": self.role}, "token": self.token} -- 2.52.0 From 532266c98e6f1c9c54870f6ec0fd0dde4e8b220b Mon Sep 17 00:00:00 2001 From: Sweetbread Date: Sun, 26 Oct 2025 15:21:48 +0300 Subject: [PATCH 20/25] refactor(auth): remove /api/auth/* handlers to api/auth.py --- api/{auth/loginapi.py => auth.py} | 4 ++-- app.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename api/{auth/loginapi.py => auth.py} (87%) diff --git a/api/auth/loginapi.py b/api/auth.py similarity index 87% rename from api/auth/loginapi.py rename to api/auth.py index ab095e9..0c357e8 100644 --- a/api/auth/loginapi.py +++ b/api/auth.py @@ -1,10 +1,10 @@ from flask import Blueprint, request, jsonify from model.user import User -loginBP = Blueprint("loginapi", __name__) +auth = Blueprint("auth", __name__) -@loginBP.route('/api/auth/login', methods = ['POST']) +@auth.route('/login', methods = ['POST']) def login(): if request.is_json: req = request.json diff --git a/app.py b/app.py index f225ca0..b7752b6 100644 --- a/app.py +++ b/app.py @@ -1,6 +1,6 @@ from sys import exit from flask import Flask -from api.auth.loginapi import loginBP +from api.auth import auth from utils.loadDotEnv import initializeENV from utils.PostgressConnect import PSQLConnect, PSQLCursor @@ -12,4 +12,4 @@ if not initializeENV(): app = Flask(__name__) -app.register_blueprint(loginBP) +app.register_blueprint(auth, url_prefix='/api/auth') -- 2.52.0 From 90f1a6245ce1467c3d2797a7f76819f362309e25 Mon Sep 17 00:00:00 2001 From: Sweetbread Date: Sun, 26 Oct 2025 15:57:45 +0300 Subject: [PATCH 21/25] feat(log): use loguru --- dependencies.txt | 1 + utils/createLogger.py | 6 ------ utils/loadDotEnv.py | 3 +-- 3 files changed, 2 insertions(+), 8 deletions(-) delete mode 100644 utils/createLogger.py diff --git a/dependencies.txt b/dependencies.txt index 4fc4ead..69c3592 100644 --- a/dependencies.txt +++ b/dependencies.txt @@ -2,3 +2,4 @@ flask==3.1.2 python-dotenv psycopg2-binary pyjwt +loguru diff --git a/utils/createLogger.py b/utils/createLogger.py deleted file mode 100644 index 7071f0e..0000000 --- a/utils/createLogger.py +++ /dev/null @@ -1,6 +0,0 @@ -import logging - -def createLogger(name: str): - logger = logging.getLogger() - logger.propagate = False - return logger diff --git a/utils/loadDotEnv.py b/utils/loadDotEnv.py index 85bbc72..0d6c510 100644 --- a/utils/loadDotEnv.py +++ b/utils/loadDotEnv.py @@ -1,9 +1,8 @@ import os from dotenv import load_dotenv -from .createLogger import createLogger +from loguru import logger as log DOTENV_PATH = '.env' -log = createLogger("ENV") def initializeENV() -> bool: if os.path.exists(DOTENV_PATH): -- 2.52.0 From cdf195306e3fd3d3318f6f93b686850ac50da14a Mon Sep 17 00:00:00 2001 From: Sweetbread Date: Sun, 26 Oct 2025 17:27:24 +0300 Subject: [PATCH 22/25] feat(jwt): add iat field --- utils/token.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/token.py b/utils/token.py index 90a69a9..d20cea4 100644 --- a/utils/token.py +++ b/utils/token.py @@ -1,7 +1,8 @@ import jwt import os +from time import time def generateKey(email, passwd): key = os.getenv('KEY') - encoded = jwt.encode({email: passwd}, key, algorithm="HS256") + encoded = jwt.encode({email: passwd, 'iat': time()}, key, algorithm="HS256") return encoded -- 2.52.0 From 5bac4c720b56dca259ee96672ab5adb219e1dfce Mon Sep 17 00:00:00 2001 From: Kirill Date: Fri, 31 Oct 2025 13:45:30 +0300 Subject: [PATCH 23/25] feat(api/robots.py): Robots Api --- api/robots.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 api/robots.py diff --git a/api/robots.py b/api/robots.py new file mode 100644 index 0000000..2325dee --- /dev/null +++ b/api/robots.py @@ -0,0 +1,24 @@ +from flask import Blueprint, request, jsonify +from model.user import User +#from module.db.repositories.robot_reposytory import update_robot get_by_id +from loguru import logger as log +robots = Blueprint("robots", __name__) + +robots.route('/data', methods = ['POST']) +def data(): + if request.headers.get("Authorization"): + if request.is_json: + req = request.json + + id = req.get('robot_id') + tms = req.get('timestamp') + loc = req.get('location') + scanRes = req.get('scan_results') + battery = req.get('battery_level') + + if update_robot(id, "received", battery, loc["zone"], loc["row"], loc["self"]): + res = {"status": "received", "message_id": "123"} #for that moment i don`t now what is message + return jsonify(res) + else: + log.error('failed to update robot data') + return("Server error") -- 2.52.0 From 9d01ead120ddab1908726095a2b3d0852649520a Mon Sep 17 00:00:00 2001 From: Kirill Date: Fri, 31 Oct 2025 13:46:23 +0300 Subject: [PATCH 24/25] feat(dependencies.txt): Update libs Added Libs for work with webSockets --- dependencies.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/dependencies.txt b/dependencies.txt index 69c3592..c0a8c31 100644 --- a/dependencies.txt +++ b/dependencies.txt @@ -1,4 +1,5 @@ flask==3.1.2 +flask-socketio python-dotenv psycopg2-binary pyjwt -- 2.52.0 From 12be29340ba87ef07dc94de5b52355767308549d Mon Sep 17 00:00:00 2001 From: Kirill Date: Fri, 31 Oct 2025 13:47:55 +0300 Subject: [PATCH 25/25] feat(api/ws.py): WebSoket --- api/ws.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 api/ws.py diff --git a/api/ws.py b/api/ws.py new file mode 100644 index 0000000..a6c87a3 --- /dev/null +++ b/api/ws.py @@ -0,0 +1,26 @@ +from app import app +from flask_socketio import SocketIO, emit +from loguru import logger as log +#from module.db.repositories.robot_reposytory import update_robot get_by_id get_all +#from module.db.repositories.inventory_repository import get_all as getRecords +ws = socketIO(app) + +@ws.on('connect') +def is_connect(): + log.info('client is connected') + +@ws.on('disconnect') +def is_disconnect(): + log.info('client is disconnected') + +@ws.on('robot_update') +def robotUpdate(): + robots = get_all() + emit('response', jsonify({"type": "robot_update", "data": {robots.toJSON()}}) + +@ws.on('inventory_alert') +def robotUpdate(): + records = getRecords() + emit('response', jsonify({"type": "inventory_alert", "data": {records.toJSON()}}) + + -- 2.52.0