diff --git a/site/__init__.py b/site/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/site/app.py b/site/app.py index 431818f..f84eae8 100644 --- a/site/app.py +++ b/site/app.py @@ -1,37 +1,24 @@ import os -import psycopg2 from dotenv import load_dotenv from flask import Flask, render_template +from . import db +from .test_routes import test_bp load_dotenv() class ContractsApp: def __init__(self): self.app = Flask(__name__) - self.db = self._connect_db() self.add_routes() - def _connect_db(self): - try: - conn = psycopg2.connect( - host=os.getenv("DB_HOST"), - port=os.getenv("DB_PORT", 5432), - dbname=os.getenv("DB_NAME"), - user=os.getenv("DB_USER"), - password=os.getenv("DB_PASS"), - sslmode=os.getenv("DB_SSLMODE", "disable"), - ) - return conn - except Exception as e: - print(f"DB connect error: {e}") - return None - def add_routes(self): self.app.add_url_rule("/", "index", self.index) self.app.add_url_rule("/health", "health", self.health) + self.app.register_blueprint(test_bp) def index(self): - db_status = "connected" if self.db else "no DB" + conn = db.connect() + db_status = "connected" if conn else "no DB" return render_template("index.html", db_status=db_status) def health(self): diff --git a/site/db.py b/site/db.py new file mode 100644 index 0000000..a4db369 --- /dev/null +++ b/site/db.py @@ -0,0 +1,36 @@ +import os +import psycopg2 +from psycopg2 import sql + + +def connect(): + """Подключение к БД. Возвращает connection или None.""" + try: + return psycopg2.connect( + host=os.getenv("DB_HOST"), + port=os.getenv("DB_PORT", 5432), + dbname=os.getenv("DB_NAME"), + user=os.getenv("DB_USER"), + password=os.getenv("DB_PASS"), + sslmode=os.getenv("DB_SSLMODE", "disable"), + ) + except Exception: + return None + + +def query(sql_text, params=None): + """Выполнить запрос, вернуть (rows, columns) или (None, error).""" + conn = connect() + if not conn: + return None, "no connection" + try: + cur = conn.cursor() + cur.execute(sql_text, params) + rows = cur.fetchall() + cols = [desc[0] for desc in cur.description] if cur.description else [] + cur.close() + conn.close() + return {"columns": cols, "rows": [list(r) for r in rows]}, None + except Exception as e: + conn.close() + return None, str(e) diff --git a/site/test_routes.py b/site/test_routes.py new file mode 100644 index 0000000..2e3aa9c --- /dev/null +++ b/site/test_routes.py @@ -0,0 +1,48 @@ +from flask import Blueprint, jsonify, request +from . import db + +test_bp = Blueprint("test", __name__) + + +@test_bp.route("/test", methods=["GET", "POST"]) +def test(): + """Тестовый слой: проверка БД и выполнение запросов.""" + + # GET — статус + if request.method == "GET": + conn = db.connect() + return jsonify({ + "db": "ok" if conn else "fail", + "actions": [ + "GET /test — статус БД", + "POST /test SQL:... — выполнить запрос", + "POST /test tables — список таблиц", + ], + }) + + # POST — выполнить действие + data = request.get_json(silent=True) or {} + action = data.get("action", "status") + + if action == "status": + conn = db.connect() + return jsonify({"db": "ok" if conn else "fail"}) + + if action == "tables": + result, err = db.query( + "SELECT table_name FROM information_schema.tables WHERE table_schema='public' ORDER BY table_name" + ) + if err: + return jsonify({"error": err}), 500 + return jsonify({"tables": [r[0] for r in result["rows"]]}) + + if action == "sql": + sql_text = data.get("sql", "") + if not sql_text: + return jsonify({"error": "no sql"}), 400 + result, err = db.query(sql_text) + if err: + return jsonify({"error": err}), 500 + return jsonify(result) + + return jsonify({"error": f"unknown action: {action}"}), 400