tienhiep-api / viewer_server.py
Cong123779
deploy: update backend production to new Space
d9bfc2d
Raw
History Blame Contribute Delete
5.18 kB
"""
viewer_server.py β€” Application Entrypoint
This file was refactored from a 2800-line monolith into a clean entrypoint.
All business logic has been moved to the `backend/` package:
backend/
β”œβ”€β”€ __init__.py ← App Factory (create_app)
β”œβ”€β”€ config.py ← All config & environment variables
β”œβ”€β”€ api/ ← Flask Blueprints (routes/controllers)
β”‚ β”œβ”€β”€ auth.py
β”‚ β”œβ”€β”€ books.py
β”‚ β”œβ”€β”€ payment.py
β”‚ β”œβ”€β”€ translate.py
β”‚ β”œβ”€β”€ epub.py
β”‚ └── developer.py
β”œβ”€β”€ services/ ← Business logic layer
β”‚ β”œβ”€β”€ auth_service.py
β”‚ β”œβ”€β”€ book_service.py
β”‚ β”œβ”€β”€ payment_service.py
β”‚ β”œβ”€β”€ email_service.py
β”‚ β”œβ”€β”€ epub_service.py
β”‚ └── translation.py
β”œβ”€β”€ database/
β”‚ └── db_manager.py ← DB connections, circuit breaker, caches
β”œβ”€β”€ core/
β”‚ β”œβ”€β”€ security.py ← JWT, bcrypt helpers
β”‚ β”œβ”€β”€ decorators.py ← @jwt_required, @require_api_key_auth
β”‚ └── rate_limit.py ← IP rate limiters
└── workers/
└── email_worker.py ← Background IMAP/Gmail email polling
To run the server:
python viewer_server.py
Or with gunicorn:
gunicorn -w 4 -b 0.0.0.0:5051 "viewer_server:app"
"""
import logging
import sys
import traceback
from flask import jsonify
from backend.core.logger import setup_logger
logger = setup_logger("server")
from backend import create_app
app = create_app()
@app.errorhandler(Exception)
def handle_exception(e):
"""Global unhandled exception handler to output clean JSON in production."""
# Log the complete stack trace
error_msg = f"Unhandled exception encountered: {str(e)}"
stack_trace = traceback.format_exc()
logger.error(error_msg)
logger.error(stack_trace)
# Trigger asynchronous alert email to Admin
try:
from backend.services.alert_service import send_alert_to_admin
subject = f"Lα»—i nghiΓͺm trọng (500 Internal Error): {str(e)[:50]}"
body = f"Đã xαΊ£y ra lα»—i chΖ°a xα»­ lΓ½ trΓͺn server:<br><strong>Lα»—i:</strong> {str(e)}<br><br><strong>Stack Trace:</strong><br>{stack_trace.replace(chr(10), '<br>')}"
send_alert_to_admin("critical_error", subject, body)
except Exception as alert_err:
logger.error(f"Failed to trigger alert email for exception: {alert_err}")
# Return JSON response instead of HTML traceback page
return jsonify({
"error": "Internal Server Error. Please contact administrator.",
"success": False
}), 500
@app.route("/api/temp-db-fix", methods=["GET"])
def temp_db_fix():
from flask import request
secret = request.args.get("secret")
if secret != "super_secret_db_fix_2026":
return "Unauthorized", 403
import os
import psycopg2
url = os.environ.get("DATABASE_URL")
if not url:
return "DATABASE_URL environment variable is missing", 500
logs = []
try:
conn = psycopg2.connect(url)
cursor = conn.cursor()
# 1. Clean up user 75
tables_to_clean = [
"refresh_tokens", "bookshelf", "reading_history", "password_reset_tokens",
"api_keys", "api_usage", "translation_history", "vocabulary",
"user_settings", "usage_tracking", "personal_notifications", "login_history"
]
for tbl in tables_to_clean:
try:
cursor.execute(f"DELETE FROM {tbl} WHERE user_id = 75")
logs.append(f"βœ” Cleaned {tbl} for user_id = 75")
except Exception as e:
logs.append(f"β„Ή Could not clean {tbl} for user_id = 75: {e}")
try:
cursor.execute("DELETE FROM users WHERE id = 75")
logs.append("βœ” Deleted user 75 from users table")
except Exception as e:
logs.append(f"❌ Failed to delete user 75: {e}")
# 2. Link VIP user congkx123789 to Gmail
cursor.execute("SELECT id, username, email, vip_status FROM users WHERE username = %s OR id = 100", ("congkx123789",))
vip_user = cursor.fetchone()
if vip_user:
vip_id = vip_user[0]
cursor.execute("""
UPDATE users
SET email = %s,
google_id = NULL,
email_verified = 1
WHERE id = %s
""", ("havucong25@gmail.com", vip_id))
logs.append(f"βœ” Linked VIP user {vip_user[1]} (ID {vip_id}) to havucong25@gmail.com")
else:
logs.append("❌ VIP user congkx123789 not found in database")
conn.commit()
conn.close()
return jsonify({"success": True, "logs": logs})
except Exception as e:
return jsonify({"success": False, "error": str(e), "logs": logs})
if __name__ == "__main__":
logger.info("πŸš€ Server Δ‘ang khởi Δ‘α»™ng tαΊ‘i: http://localhost:5051")
app.run(host="0.0.0.0", port=5051, debug=False, threaded=True)