06/15 Phase 1 + 2 codes

This commit is contained in:
2026-06-15 11:23:05 -04:00
commit c2064b84b4
62 changed files with 2937 additions and 0 deletions
+100
View File
@@ -0,0 +1,100 @@
"""Application factory."""
from flask import Flask, render_template
from app.config import get_config
from app.extensions import (db, migrate, login_manager, csrf, babel, limiter)
def create_app(config_object=None):
app = Flask(__name__)
app.config.from_object(config_object or get_config())
_init_extensions(app)
_init_login(app)
_init_babel(app)
_register_blueprints(app)
_register_errorhandlers(app)
_register_context(app)
_register_cli(app)
return app
def _init_extensions(app):
# Honor X-Forwarded-* from the Nginx reverse proxy (scheme, host, client IP).
# Correct is_secure, secure cookies, and rate-limit keying behind the proxy.
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)
db.init_app(app)
migrate.init_app(app, db)
csrf.init_app(app)
limiter.init_app(app)
# ensure models are imported so migrations see them
from app import models # noqa: F401
def _init_login(app):
login_manager.init_app(app)
@login_manager.user_loader
def load_user(user_id):
from app.models.user import User
return User.query.get(int(user_id))
def _init_babel(app):
from app.blueprints.i18n.routes import select_locale
babel.init_app(app, locale_selector=select_locale)
def _register_blueprints(app):
from app.blueprints.main.routes import main_bp
from app.blueprints.auth.routes import auth_bp
from app.blueprints.i18n.routes import i18n_bp
from app.blueprints.listings.routes import listings_bp
app.register_blueprint(main_bp)
app.register_blueprint(auth_bp)
app.register_blueprint(i18n_bp)
app.register_blueprint(listings_bp)
def _register_errorhandlers(app):
@app.errorhandler(403)
def forbidden(e):
return render_template("errors/403.html"), 403
@app.errorhandler(404)
def not_found(e):
return render_template("errors/404.html"), 404
@app.errorhandler(500)
def server_error(e):
return render_template("errors/500.html"), 500
def _register_context(app):
from flask_babel import get_locale
from flask import request
def merge_query(**overrides):
merged = request.args.to_dict()
merged.update({k: v for k, v in overrides.items() if v is not None})
return merged
@app.context_processor
def inject_globals():
return {
"get_locale": get_locale,
"merge_query": merge_query,
"SUPPORTED_LOCALES": app.config["SUPPORTED_LOCALES"],
"TURNSTILE_SITE_KEY": app.config.get("TURNSTILE_SITE_KEY", ""),
}
def _register_cli(app):
@app.cli.command("expire-listings")
def expire_listings():
"""Sweep: flip past-due active listings to expired."""
from app.services.listings import expire_due_listings
n = expire_due_listings()
print(f"Expired {n} listing(s).")