Files
AutoMarket/backend/app.py
2026-05-15 20:41:36 +03:00

172 lines
7.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
from flask import Flask
from flask_cors import CORS
from dotenv import load_dotenv
from flasgger import Swagger
from flask_socketio import SocketIO, emit
# Load environment variables from .env
load_dotenv()
app = Flask(__name__)
CORS(app)
socketio = SocketIO(app, cors_allowed_origins="*")
# Swagger setup
# ... (keeping existing swagger config)
app.config['SWAGGER'] = {
'title': 'AutoMarket API',
'uiversion': 3,
'specs_route': '/api/docs/',
'securityDefinitions': {
'APIKeyHeader': {
'type': 'apiKey',
'name': 'Authorization',
'in': 'header',
'description': 'Введите токен в формате: Bearer <ваш_токен>'
}
}
}
swagger = Swagger(app)
# Ensure upload folder exists
# ...
UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'uploads')
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
# Автоматическая инициализация таблиц при старте
def init_db():
try:
from .db import get_db_connection, release_db_connection
conn = get_db_connection()
cur = conn.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY, username VARCHAR(50) UNIQUE NOT NULL,
password_hash TEXT NOT NULL, role VARCHAR(20) DEFAULT 'admin',
parent_id INT REFERENCES users(id) ON DELETE CASCADE,
plan VARCHAR(20) DEFAULT 'free', created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS credentials (
user_id INT REFERENCES users(id) ON DELETE CASCADE, platform VARCHAR(50),
api_key TEXT, client_id TEXT, client_secret TEXT, other_data JSONB,
updated_at TIMESTAMP DEFAULT NOW(), PRIMARY KEY (user_id, platform)
);
CREATE TABLE IF NOT EXISTS cases (
id SERIAL PRIMARY KEY, user_id INT REFERENCES users(id) ON DELETE CASCADE,
platform VARCHAR(50) NOT NULL DEFAULT 'ozon', violator_url TEXT NOT NULL,
violator_article VARCHAR(50) NOT NULL, my_article VARCHAR(50), comment TEXT,
status VARCHAR(20) DEFAULT 'new',
created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS files (
id SERIAL PRIMARY KEY, case_id INT REFERENCES cases(id) ON DELETE CASCADE,
file_path TEXT NOT NULL, uploaded_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS audit_log (
id SERIAL PRIMARY KEY, user_id INT REFERENCES users(id) ON DELETE CASCADE,
action VARCHAR(100) NOT NULL, details JSONB, created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS seo_keywords (
id SERIAL PRIMARY KEY, user_id INT REFERENCES users(id) ON DELETE CASCADE,
keyword VARCHAR(255) NOT NULL, article VARCHAR(100) NOT NULL,
platform VARCHAR(50) NOT NULL, created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS seo_history (
id SERIAL PRIMARY KEY, keyword_id INT REFERENCES seo_keywords(id) ON DELETE CASCADE,
position INT, checked_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS reference_images (
id SERIAL PRIMARY KEY, user_id INT REFERENCES users(id) ON DELETE CASCADE,
file_path TEXT NOT NULL, image_hash VARCHAR(64), article VARCHAR(100),
created_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS repricer_rules (
id SERIAL PRIMARY KEY, user_id INT REFERENCES users(id) ON DELETE CASCADE,
product_name VARCHAR(255) NOT NULL, sku VARCHAR(100) NOT NULL,
min_price DECIMAL(10,2) NOT NULL, max_price DECIMAL(10,2) NOT NULL,
strategy VARCHAR(20) DEFAULT 'follow_competitor',
is_active BOOLEAN DEFAULT TRUE, current_price DECIMAL(10,2),
last_run TIMESTAMP, created_at TIMESTAMP DEFAULT NOW()
);
""")
conn.commit()
release_db_connection(conn)
print("✅ База данных инициализирована успешно")
except Exception as e:
print(f"⚠️ Ошибка инициализации БД: {e}")
init_db()
# Register blueprints
from .routes.cases import cases_blueprint
from .routes.credentials import credentials_blueprint
from .routes.auth import auth_blueprint
from .routes.dashboard import dashboard_blueprint
from .routes.reports import reports_blueprint
from .routes.ai import ai_blueprint
from .routes.seo import seo_blueprint
from .routes.content import content_blueprint
from .routes.finance import finance_blueprint
from .routes.team import team_blueprint
from .routes.repricer import repricer_blueprint
app.register_blueprint(cases_blueprint, url_prefix='/api')
app.register_blueprint(credentials_blueprint, url_prefix='/api')
app.register_blueprint(auth_blueprint, url_prefix='/api')
app.register_blueprint(dashboard_blueprint, url_prefix='/api')
app.register_blueprint(reports_blueprint, url_prefix='/api')
app.register_blueprint(ai_blueprint, url_prefix='/api')
app.register_blueprint(seo_blueprint, url_prefix='/api')
app.register_blueprint(content_blueprint, url_prefix='/api')
app.register_blueprint(finance_blueprint, url_prefix='/api')
app.register_blueprint(team_blueprint, url_prefix='/api')
app.register_blueprint(repricer_blueprint, url_prefix='/api')
# Health check endpoint - проверка состояния приложения и БД
from flask import jsonify
from .db import get_db_connection, release_db_connection
@app.route('/api/health')
def health_check():
db_status = "ok"
db_error = None
try:
conn = get_db_connection()
cur = conn.cursor()
cur.execute("SELECT 1")
release_db_connection(conn)
except Exception as e:
db_status = "error"
db_error = str(e)
status = "ok" if db_status == "ok" else "degraded"
return jsonify({
"status": status,
"backend": "ok",
"database": db_status,
"db_error": db_error
}), 200 if status == "ok" else 503
import threading
import time
def background_scanner():
"""Фоновая задача для имитации сканирования маркетплейсов."""
while True:
# Здесь в будущем будет вызов api.ozon_api и т.д.
print("--- [Scanner] Checking marketplaces for price dumping... ---")
# Эмитируем событие для примера (что сканер что-то нашел)
# socketio.emit('scanner_update', {'message': 'Сканер проверил 10 товаров...'}, namespace='/')
time.sleep(60)
# Start background thread
scanner_thread = threading.Thread(target=background_scanner, daemon=True)
scanner_thread.start()
if __name__ == '__main__':
# Use socketio.run instead of app.run
socketio.run(app, host='0.0.0.0', port=5000, debug=True, allow_unsafe_werkzeug=True)