commit 56792b892d5ae3a02a05e19062e1b352ede4496a Author: fakz9 Date: Thu Oct 12 23:51:14 2023 +0300 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cda00b8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +venv/ +migrations/ +__pycache__/ +.idea/ +.git/ +.env +test.* diff --git a/app.py b/app.py new file mode 100644 index 0000000..e597f91 --- /dev/null +++ b/app.py @@ -0,0 +1,33 @@ +from flask import Flask +from flask_cors import CORS +from flask_jwt_extended import JWTManager +from flask_migrate import Migrate +from flask_session import Session + +import config +import database +import routes + +# Flask config +app = Flask(__name__) +app.config.from_object(config.FlaskConfig) + +# Database config +database.db.init_app(app) +migrate = Migrate(app, database.db) + +# Session config +server_session = Session(app) + +# CORS config +CORS(app, supports_credentials=True) +jwt = JWTManager(app) +blueprints = [ + (routes.auth_blueprint, '/auth') +] + +for blueprint, url_prefix in blueprints: + app.register_blueprint(blueprint, url_prefix=url_prefix) + +if __name__ == '__main__': + app.run() diff --git a/config.py b/config.py new file mode 100644 index 0000000..7a5380e --- /dev/null +++ b/config.py @@ -0,0 +1,21 @@ +import redis + +import settings + + +class FlaskConfig: + # Flask settings + SECRET_KEY = settings.SECRET_KEY + TEMPLATES_AUTO_RELOAD = True + + # Database setting + SQLALCHEMY_TRACK_MODIFICATIONS = True + SQLALCHEMY_DATABASE_URI = f'postgresql://{settings.PG_LOGIN}:{settings.PG_PASSWORD}@{settings.PG_HOST}:{settings.PG_PORT}/{settings.PG_DATABASE}' + + # Session settings + SESSION_TYPE = 'redis' + SESSION_PERMANENT = False + SESSION_USE_SIGNER = True + SESSION_REDIS = redis.from_url('redis://127.0.0.1:6379') + + # SQLALCHEMY_ECHO = True diff --git a/database/__init__.py b/database/__init__.py new file mode 100644 index 0000000..70cdde6 --- /dev/null +++ b/database/__init__.py @@ -0,0 +1 @@ +from database.models import * diff --git a/database/mariadb.py b/database/mariadb.py new file mode 100644 index 0000000..f56740a --- /dev/null +++ b/database/mariadb.py @@ -0,0 +1,40 @@ +import mariadb + +import settings + + +class MariadbConnector: + def __init__(self): + # Settings + self.user = settings.MY_LOGIN + self.password = settings.MY_PASSWORD + self.host = settings.MY_HOST + self.port = int(settings.MY_PORT) + self.database = settings.MY_DATABASE + + self.conn = self._get_connection() + self.cursor = self._get_cursor() + + def _get_connection(self) -> mariadb.connections.Connection: + return mariadb.connect(user=self.user, + password=self.password, + host=self.host, + port=self.port, + database=self.database) + + def _get_cursor(self) -> mariadb.cursors.Cursor: + return self.conn.cursor() + + def select(self, query_string: str, as_list=True): + cursor = self.cursor + + cursor.execute(query_string) + if not as_list: + return cursor.fetchone() + return cursor.fetchall() + + def insert(self, query_string) -> int: + cursor = self.cursor + + cursor.execute(query_string) + return cursor.insert_id diff --git a/database/models.py b/database/models.py new file mode 100644 index 0000000..22db4a5 --- /dev/null +++ b/database/models.py @@ -0,0 +1,20 @@ +from flask_sqlalchemy import SQLAlchemy + +db = SQLAlchemy() + + +class User(db.Model): + __tablename__ = 'users' + id = db.Column(db.Integer, primary_key=True, comment='ID пользователя') + + login = db.Column(db.String, nullable=False, comment='Логин') + password_hash = db.Column(db.String, nullable=False, comment='Пароль') + + sipro_id = db.Column(db.Integer, nullable=True, comment='ID пользователя в SIPRO') + + +class Barcode(db.Model): + __tablename__ = 'barcodes' + id = db.Column(db.Integer, primary_key=True, comment='ID пользователя') + denco_article = db.Column(db.Integer, nullable=False, comment='Артикул', index=True) + barcode = db.Column(db.String, nullable=False, comment='Баркод', index=True) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..65f8717 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,16 @@ +flask +flask-sqlalchemy +flask-session +flask-cors +flask-migrate +Flask-JWT-Extended + +# Working with database +redis +psycopg2 +mariadb + + +# Other stuff +requests +python-dotenv \ No newline at end of file diff --git a/routes/__init__.py b/routes/__init__.py new file mode 100644 index 0000000..f88a74b --- /dev/null +++ b/routes/__init__.py @@ -0,0 +1 @@ +from routes.auth import auth_blueprint diff --git a/routes/auth.py b/routes/auth.py new file mode 100644 index 0000000..5247442 --- /dev/null +++ b/routes/auth.py @@ -0,0 +1,44 @@ +from flask import Blueprint, request, jsonify +from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity +from werkzeug.security import generate_password_hash, check_password_hash + +from database import User, db + +auth_blueprint = Blueprint('auth', __name__) + + +@auth_blueprint.post('/register') +def register_endpoint(): + data = request.json + login = data.get('login') + password = data.get('password') + password_hash = generate_password_hash(password, method='sha256') + + new_user = User(login=login, + password_hash=password_hash) + db.session.add(new_user) + db.session.commit() + + return jsonify(ok=True) + + +@auth_blueprint.post('/login') +def login_endpoint(): + data = request.json + print(data) + login = data.get('login') + user = User.query.filter_by(login=login).first() + if not user: + return jsonify(ok=False), 401 + password = data.get('password') + if not check_password_hash(user.password_hash, password): + return jsonify(ok=False), 401 + access_token = create_access_token(identity=user.id) + return jsonify(access_token=access_token) + + +@auth_blueprint.get('/protected') +@jwt_required() +def protected_endpoint(): + print(type(get_jwt_identity())) + return 'test' diff --git a/scanner/__init__.py b/scanner/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scanner/enums.py b/scanner/enums.py new file mode 100644 index 0000000..79722af --- /dev/null +++ b/scanner/enums.py @@ -0,0 +1,13 @@ +from enum import unique, IntEnum + + +@unique +class CodeType(IntEnum): + BARCODE = 0 + QRCODE = 1 + INVALID = 2 + + +@unique +class SearchType(IntEnum): + PRODUCT = 0 diff --git a/scanner/search.py b/scanner/search.py new file mode 100644 index 0000000..5b14dcb --- /dev/null +++ b/scanner/search.py @@ -0,0 +1,11 @@ +from scanner.enums import CodeType +from scanner.utils import guess_code_type + + +class ScannerSearch: + def __init__(self, string_value: str): + self.string_value = string_value + self._code_type = guess_code_type(self.string_value) + + def get_code_type(self) -> CodeType: + return self._code_type diff --git a/scanner/utils.py b/scanner/utils.py new file mode 100644 index 0000000..9acef23 --- /dev/null +++ b/scanner/utils.py @@ -0,0 +1,9 @@ +from scanner.enums import CodeType + + +def guess_code_type(string_value: str) -> CodeType: + if string_value.isdigit(): + return CodeType.BARCODE + if string_value: + return CodeType.QRCODE + return CodeType.INVALID diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..90ea6fc --- /dev/null +++ b/settings.py @@ -0,0 +1,21 @@ +import os +from dotenv import load_dotenv, find_dotenv + +load_dotenv(find_dotenv()) + +# PostgreSQL database settings +PG_LOGIN = os.environ.get('PG_LOGIN') +PG_PASSWORD = os.environ.get('PG_PASSWORD') +PG_PORT = os.environ.get('PG_PORT') +PG_HOST = os.environ.get('PG_HOST') +PG_DATABASE = os.environ.get('PG_DATABASE') + +# MySQL database settings +MY_LOGIN = os.environ.get('MY_LOGIN') +MY_PASSWORD = os.environ.get('MY_PASSWORD') +MY_PORT = os.environ.get('MY_PORT') +MY_DATABASE = os.environ.get('MY_DATABASE') +MY_HOST = os.environ.get('MY_HOST') + +# Flask settings +SECRET_KEY = os.environ.get('SECRET_KEY') diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/barcodes_synchronizer.py b/utils/barcodes_synchronizer.py new file mode 100644 index 0000000..f3b85d9 --- /dev/null +++ b/utils/barcodes_synchronizer.py @@ -0,0 +1,17 @@ +import database +from database.mariadb import MariadbConnector + + +class BarcodesSynchronizer: + def __init__(self): + self.mariadb_connector = MariadbConnector() + + def synchronize(self): + existing_barcodes = database.Barcode.query.all() + denco_articles = list(set([barcode.denco_article for barcode in existing_barcodes])) + + + query_string = 'SELECT product, barcode FROM modx_0_connections WHERE barcode != "" LIMIT 100' + for denco_article, barcodes_string in self.mariadb_connector.select(query_string): + barcodes = barcodes_string.split(',') + print(denco_article, barcodes)