Files

75 lines
2.4 KiB
Python
Raw Permalink Normal View History

2026-03-05 12:13:22 -06:00
import os
2026-03-06 00:03:06 -06:00
2026-03-12 10:23:22 -05:00
from flask import Flask, send_from_directory, jsonify
from werkzeug.exceptions import HTTPException, NotFound, BadRequest
2026-03-05 14:05:41 -06:00
from sqlalchemy import text
2026-03-06 00:03:06 -06:00
2026-03-05 12:13:22 -06:00
from .extensions import db, migrate, cors
from config import config
2026-03-06 00:03:06 -06:00
2026-03-05 12:13:22 -06:00
def create_app(config_name=None):
if config_name is None:
config_name = os.environ.get('FLASK_ENV', 'production')
app = Flask(__name__, static_folder='static', static_url_path='')
app.config.from_object(config.get(config_name, config['default']))
db.init_app(app)
migrate.init_app(app, db)
cors.init_app(app, resources={r'/api/*': {'origins': '*'}})
from .routes.projects import projects_bp
from .routes.deliverables import deliverables_bp
2026-03-06 00:03:06 -06:00
2026-03-05 12:13:22 -06:00
app.register_blueprint(projects_bp, url_prefix='/api')
app.register_blueprint(deliverables_bp, url_prefix='/api')
with app.app_context():
db.create_all()
2026-03-05 14:05:41 -06:00
_run_migrations()
2026-03-05 12:13:22 -06:00
2026-03-12 10:36:02 -05:00
@app.route('/')
def index():
return send_from_directory(app.static_folder, 'index.html')
2026-03-12 10:23:22 -05:00
@app.errorhandler(404)
2026-03-12 10:36:02 -05:00
def handle_404(e):
if request.path.startswith('/api/'):
return jsonify({'error': 'Resource not found', 'message': str(e)}), 404
return send_from_directory(app.static_folder, 'index.html')
2026-03-12 10:23:22 -05:00
@app.errorhandler(400)
def bad_request(e):
return jsonify({'error': 'Bad request', 'message': str(e)}), 400
@app.errorhandler(Exception)
def handle_exception(e):
if isinstance(e, HTTPException):
return jsonify({'error': e.name, 'message': e.description}), e.code
app.logger.error(f"Unhandled exception: {str(e)}", exc_info=True)
return jsonify({'error': 'Internal server error', 'message': 'An unexpected error occurred'}), 500
2026-03-05 12:13:22 -06:00
return app
2026-03-05 14:05:41 -06:00
def _run_migrations():
"""
Safe idempotent migrations for existing databases.
ALTER TABLE is a no-op if the column already exists (exception silently caught).
Add new columns here as the schema evolves.
"""
migrations = [
'ALTER TABLE projects ADD COLUMN drive_url VARCHAR(500)',
2026-03-06 00:03:06 -06:00
'ALTER TABLE projects ADD COLUMN archived_at DATETIME',
2026-03-05 14:05:41 -06:00
]
2026-03-06 00:03:06 -06:00
2026-03-05 14:05:41 -06:00
with db.engine.connect() as conn:
for stmt in migrations:
try:
conn.execute(text(stmt))
conn.commit()
except Exception:
# Column already exists — safe to ignore
pass