From 57a3866ec8d4ea204c2ee2827ebaf7bf18bd97ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Wed, 23 Jul 2025 09:30:27 +0200 Subject: [PATCH] inne bazy z opcjach --- .env.example | 12 +++- add_products.py => _tools/add_products.py | 0 .../add_receipt_to_list.py | 0 _tools/db/migrate.txt | 26 ++++++++ _tools/db/migrate_sqlite_to_pgsql.py | 49 +++++++++++++++ _tools/db/migrate_to_new_db.sh | 14 +++++ .../migrate_to_webp.py | 0 .../update_missing_image_data.py | 0 config.py | 19 +++++- deploy_docker.sh | 4 +- docker-compose.yml | 61 +++++++++++++++---- requirements.txt | 2 +- 12 files changed, 170 insertions(+), 17 deletions(-) rename add_products.py => _tools/add_products.py (100%) rename add_receipt_to_list.py => _tools/add_receipt_to_list.py (100%) create mode 100644 _tools/db/migrate.txt create mode 100644 _tools/db/migrate_sqlite_to_pgsql.py create mode 100644 _tools/db/migrate_to_new_db.sh rename migrate_to_webp.py => _tools/migrate_to_webp.py (100%) rename update_missing_image_data.py => _tools/update_missing_image_data.py (100%) diff --git a/.env.example b/.env.example index ba00eff..5f5f384 100644 --- a/.env.example +++ b/.env.example @@ -23,4 +23,14 @@ AUTH_COOKIE_MAX_AGE=86400 HEALTHCHECK_TOKEN=alamapsaikota123 # sesja zalogowanego usera (domyślnie 7 dni) -SESSION_TIMEOUT_MINUTES=10080 \ No newline at end of file +SESSION_TIMEOUT_MINUTES=10080 + +# Rodzaj bazy: sqlite, pgsql, mysql, firebird +DB_ENGINE=sqlite + +# Wspólne zmienne (dla pgsql, mysql, firebird) +DB_HOST=db +DB_PORT=5432 +DB_NAME=myapp +DB_USER=user +DB_PASSWORD=pass diff --git a/add_products.py b/_tools/add_products.py similarity index 100% rename from add_products.py rename to _tools/add_products.py diff --git a/add_receipt_to_list.py b/_tools/add_receipt_to_list.py similarity index 100% rename from add_receipt_to_list.py rename to _tools/add_receipt_to_list.py diff --git a/_tools/db/migrate.txt b/_tools/db/migrate.txt new file mode 100644 index 0000000..1a93b27 --- /dev/null +++ b/_tools/db/migrate.txt @@ -0,0 +1,26 @@ +Scenariusz migracji + +Zatrzymaj obecny kontener: + + +docker-compose down +Ustaw w .env: + +.env + +DB_ENGINE=pgsql +DB_NAME=myapp +DB_USER=user +DB_PASSWORD=pass +Uruchom bazę i aplikację: + +docker-compose --profile pgsql up -d +Wykonaj migrację danych: + + +bash _tools/db/migrate_to_new_db.sh pgsql + + + +Sprawdź działanie aplikacji. + diff --git a/_tools/db/migrate_sqlite_to_pgsql.py b/_tools/db/migrate_sqlite_to_pgsql.py new file mode 100644 index 0000000..49f94ab --- /dev/null +++ b/_tools/db/migrate_sqlite_to_pgsql.py @@ -0,0 +1,49 @@ +import os +from sqlalchemy import create_engine, MetaData +from sqlalchemy.orm import sessionmaker +from config import Config + +# Źródło: SQLite +sqlite_engine = create_engine("sqlite:///instance/shopping.db") +sqlite_meta = MetaData(bind=sqlite_engine) +sqlite_meta.reflect() + +# Cel: PostgreSQL (czytany z .env przez Config) +pg_engine = create_engine(Config.SQLALCHEMY_DATABASE_URI) +pg_meta = MetaData(bind=pg_engine) +pg_meta.reflect() + +# Sesje +SQLiteSession = sessionmaker(bind=sqlite_engine) +PGSession = sessionmaker(bind=pg_engine) + +sqlite_session = SQLiteSession() +pg_session = PGSession() + +def migrate_table(table_name): + print(f"Migruję tabelę: {table_name}") + source_table = sqlite_meta.tables.get(table_name) + target_table = pg_meta.tables.get(table_name) + + if not source_table or not target_table: + print(f"Pominięto: {table_name} (brak w jednej z baz)") + return + + rows = sqlite_session.execute(source_table.select()).fetchall() + if not rows: + print("Brak danych do migracji.") + return + + insert_data = [dict(row._mapping) for row in rows] + with pg_engine.begin() as conn: + conn.execute(target_table.insert(), insert_data) + + print(f"✅ Przeniesiono: {len(rows)} rekordów") + +def main(): + tables = ["user", "shopping_list", "item", "expense", "receipt", "suggested_product"] + for table in tables: + migrate_table(table) + +if __name__ == "__main__": + main() diff --git a/_tools/db/migrate_to_new_db.sh b/_tools/db/migrate_to_new_db.sh new file mode 100644 index 0000000..32c72fe --- /dev/null +++ b/_tools/db/migrate_to_new_db.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -e + +APP_CONTAINER=web +DB_ENGINE=${1:-pgsql} # domyślnie pgsql + +echo "Migracja z SQLite do $DB_ENGINE..." + +docker-compose run --rm $APP_CONTAINER bash -c " + export FLASK_APP=app.py + flask db upgrade +" + +echo "Migracja zakończona." diff --git a/migrate_to_webp.py b/_tools/migrate_to_webp.py similarity index 100% rename from migrate_to_webp.py rename to _tools/migrate_to_webp.py diff --git a/update_missing_image_data.py b/_tools/update_missing_image_data.py similarity index 100% rename from update_missing_image_data.py rename to _tools/update_missing_image_data.py diff --git a/config.py b/config.py index feb098e..1946569 100644 --- a/config.py +++ b/config.py @@ -3,7 +3,24 @@ import os class Config: SECRET_KEY = os.environ.get("SECRET_KEY", "D8pceNZ8q%YR7^7F&9wAC2") - SQLALCHEMY_DATABASE_URI = os.environ.get("DATABASE_URL", "sqlite:///shopping.db") + + + DB_ENGINE = os.environ.get("DB_ENGINE", "sqlite").lower() + + if DB_ENGINE == "sqlite": + SQLALCHEMY_DATABASE_URI = "sqlite:///instance/shopping.db" + elif DB_ENGINE == "pgsql": + SQLALCHEMY_DATABASE_URI = f"postgresql://{os.environ['DB_USER']}:{os.environ['DB_PASSWORD']}@{os.environ['DB_HOST']}:{os.environ.get('DB_PORT', 5432)}/{os.environ['DB_NAME']}" + elif DB_ENGINE == "mysql": + SQLALCHEMY_DATABASE_URI = f"mysql+pymysql://{os.environ['DB_USER']}:{os.environ['DB_PASSWORD']}@{os.environ['DB_HOST']}:{os.environ.get('DB_PORT', 3306)}/{os.environ['DB_NAME']}" + elif DB_ENGINE == "firebird": + SQLALCHEMY_DATABASE_URI = f"firebird+fdb://{os.environ['DB_USER']}:{os.environ['DB_PASSWORD']}@{os.environ['DB_HOST']}/{os.environ['DB_NAME']}.fdb" + else: + raise ValueError("Nieobsługiwany typ bazy danych.") + + + + SQLALCHEMY_TRACK_MODIFICATIONS = False SYSTEM_PASSWORD = os.environ.get("SYSTEM_PASSWORD", "admin") DEFAULT_ADMIN_USERNAME = os.environ.get("DEFAULT_ADMIN_USERNAME", "admin") diff --git a/deploy_docker.sh b/deploy_docker.sh index 98c64b8..7304eb1 100644 --- a/deploy_docker.sh +++ b/deploy_docker.sh @@ -8,6 +8,8 @@ echo "Pobieram najnowszy kod z repozytorium..." git pull echo "Buduję obrazy i uruchamiam kontenery..." -docker compose up -d --build +#docker compose up -d --build +DB_ENGINE=pgsql docker compose --profile pgsql up -d --build + echo "Gotowe!" diff --git a/docker-compose.yml b/docker-compose.yml index 68eeafa..070eb9e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,18 +10,53 @@ services: timeout: 10s retries: 3 start_period: 10s - environment: - - FLASK_APP=app.py - - FLASK_ENV=production - - SECRET_KEY=${SECRET_KEY} - - SYSTEM_PASSWORD=${SYSTEM_PASSWORD} - - DEFAULT_ADMIN_USERNAME=${DEFAULT_ADMIN_USERNAME} - - DEFAULT_ADMIN_PASSWORD=${DEFAULT_ADMIN_PASSWORD} - - UPLOAD_FOLDER=${UPLOAD_FOLDER} - - AUTHORIZED_COOKIE_VALUE=${AUTHORIZED_COOKIE_VALUE} - - AUTH_COOKIE_MAX_AGE=${AUTH_COOKIE_MAX_AGE} - - HEALTHCHECK_TOKEN=${HEALTHCHECK_TOKEN} - - SESSION_TIMEOUT_MINUTES=${SESSION_TIMEOUT_MINUTES} + env_file: + - .env volumes: - .:/app - restart: unless-stopped \ No newline at end of file + - ./uploads:/app/uploads + - ./instance:/app/instance + restart: unless-stopped + # depends_on: + # - ${DB_ENGINE:-sqlite} + + pgsql: + image: postgres:17 + container_name: pgsql-db + environment: + POSTGRES_DB: ${DB_NAME} + POSTGRES_USER: ${DB_USER} + POSTGRES_PASSWORD: ${DB_PASSWORD} + volumes: + - ./db/pgsql:/var/lib/postgresql/data + ports: + - "5432:5432" + restart: unless-stopped + profiles: ["pgsql"] + + mysql: + image: mysql:8 + container_name: mysql-db + environment: + MYSQL_DATABASE: ${DB_NAME} + MYSQL_USER: ${DB_USER} + MYSQL_PASSWORD: ${DB_PASSWORD} + MYSQL_ROOT_PASSWORD: root + volumes: + - ./db/mysql:/var/lib/mysql + ports: + - "3306:3306" + restart: unless-stopped + profiles: ["mysql"] + + firebird: + image: jacobalberty/firebird + container_name: firebird-db + environment: + ISC_PASSWORD: ${DB_PASSWORD} + volumes: + - ./db/firebird:/firebird/data + ports: + - "3050:3050" + restart: unless-stopped + profiles: ["firebird"] diff --git a/requirements.txt b/requirements.txt index 5957702..147773d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,4 @@ psutil pillow-heif pytesseract -opencv-python-headless \ No newline at end of file +opencv-python-headless