# SPDX-License-Identifier: MIT import json import os import secrets import string import sys import tomllib from flask import Flask, redirect, request, url_for from flask_limiter import Limiter from flask_limiter.util import get_remote_address from flask_sqlalchemy import SQLAlchemy from sqlalchemy.orm import DeclarativeBase from werkzeug.middleware.proxy_fix import ProxyFix root_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '../../') sys.path.append(root_dir) class Base(DeclarativeBase): pass db: SQLAlchemy = SQLAlchemy(model_class=Base, session_options={ # 'autobegin': False, # 'expire_on_commit': False, }) limiter: Limiter = Limiter( key_func=get_remote_address, # Uses client's IP address by default ) def _generate_secret(length=32) -> str: characters = string.ascii_letters + string.digits # A-Z, a-z, 0-9 return ''.join(secrets.choice(characters) for _ in range(length)) def _initialize_app_config(app: Flask): if app.config.get('BEHIND_PROXY', True): app.wsgi_app = ProxyFix( app.wsgi_app, x_for=1, x_proto=1 ) app.json.ensure_ascii = False app.json.mimetype = "application/json; charset=utf-8" secret_key = app.config.get('SECRET_KEY', '') if secret_key: app.secret_key = secret_key else: app.logger.info('Using generated secret') app.secret_key = _generate_secret() app.config["SQLALCHEMY_DATABASE_URI"] = app.config.get('SQLALCHEMY_DATABASE_URI', 'sqlite:///example.db') if app.config["SQLALCHEMY_DATABASE_URI"].startswith('sqlite'): app.config["SQLALCHEMY_ENGINE_OPTIONS"] = { 'isolation_level': 'SERIALIZABLE', # "execution_options": {"autobegin": False} } def create_app(test_config=None) -> Flask: instance_path = os.getenv('INSTANCE_PATH') if instance_path is not None: instance_path = os.path.abspath(instance_path) os.makedirs(instance_path, exist_ok=True) print(f'App instance path: {instance_path}') app = Flask(__name__, instance_path=instance_path, instance_relative_config=True ) app.config.from_file("config.toml", load=tomllib.load, text=False) _initialize_app_config(app) from . import utils from . import models from . import examples from . import editor from . import share db.init_app(app) limiter.init_app(app) with app.app_context(): db.create_all() @app.route('/') def index(): return redirect(url_for('editor.index')) @app.route('/health') def health(): return '', 204 url_prefix = app.config.get('URL_PREFIX', '') app.register_blueprint(editor.bp, url_prefix=f'{url_prefix}/editor') app.register_blueprint(examples.bp, url_prefix=f'{url_prefix}/examples') app.register_blueprint(share.bp, url_prefix=f'{url_prefix}/s') return app __all__ = ['create_app']