Initial commit: Shop Database Flask Application
Flask backend with Vue 3 frontend for shop floor machine management. Includes database schema export for MySQL shopdb_flask database. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
189
shopdb/__init__.py
Normal file
189
shopdb/__init__.py
Normal file
@@ -0,0 +1,189 @@
|
||||
"""Flask application factory."""
|
||||
|
||||
import os
|
||||
import logging
|
||||
from flask import Flask, send_from_directory
|
||||
|
||||
from .config import config
|
||||
from .extensions import db, migrate, jwt, cors, ma, init_extensions
|
||||
from .plugins import plugin_manager
|
||||
|
||||
|
||||
def create_app(config_name: str = None) -> Flask:
|
||||
"""
|
||||
Application factory.
|
||||
|
||||
Args:
|
||||
config_name: Configuration name ('development', 'production', 'testing')
|
||||
|
||||
Returns:
|
||||
Configured Flask application
|
||||
"""
|
||||
if config_name is None:
|
||||
config_name = os.environ.get('FLASK_ENV', 'development')
|
||||
|
||||
app = Flask(__name__, instance_relative_config=True)
|
||||
|
||||
# Load configuration
|
||||
app.config.from_object(config.get(config_name, config['default']))
|
||||
|
||||
# Load instance config if exists
|
||||
app.config.from_pyfile('config.py', silent=True)
|
||||
|
||||
# Ensure instance folder exists
|
||||
os.makedirs(app.instance_path, exist_ok=True)
|
||||
|
||||
# Configure logging
|
||||
configure_logging(app)
|
||||
|
||||
# Initialize extensions
|
||||
init_extensions(app)
|
||||
|
||||
# Initialize plugin manager
|
||||
with app.app_context():
|
||||
plugin_manager.init_app(app, db)
|
||||
|
||||
# Register core blueprints
|
||||
register_blueprints(app)
|
||||
|
||||
# Register CLI commands
|
||||
register_cli_commands(app)
|
||||
|
||||
# Register error handlers
|
||||
register_error_handlers(app)
|
||||
|
||||
# Serve Vue frontend
|
||||
register_frontend_routes(app)
|
||||
|
||||
# JWT user loader (identity is a string in JWT, convert to int for DB lookup)
|
||||
@jwt.user_lookup_loader
|
||||
def user_lookup_callback(_jwt_header, jwt_data):
|
||||
from .core.models import User
|
||||
identity = jwt_data["sub"]
|
||||
return User.query.get(int(identity))
|
||||
|
||||
return app
|
||||
|
||||
|
||||
def register_blueprints(app: Flask):
|
||||
"""Register core API blueprints."""
|
||||
from .core.api import (
|
||||
auth_bp,
|
||||
machines_bp,
|
||||
machinetypes_bp,
|
||||
pctypes_bp,
|
||||
statuses_bp,
|
||||
vendors_bp,
|
||||
models_bp,
|
||||
businessunits_bp,
|
||||
locations_bp,
|
||||
operatingsystems_bp,
|
||||
dashboard_bp,
|
||||
applications_bp,
|
||||
knowledgebase_bp,
|
||||
search_bp,
|
||||
)
|
||||
|
||||
api_prefix = '/api'
|
||||
|
||||
app.register_blueprint(auth_bp, url_prefix=f'{api_prefix}/auth')
|
||||
app.register_blueprint(machines_bp, url_prefix=f'{api_prefix}/machines')
|
||||
app.register_blueprint(machinetypes_bp, url_prefix=f'{api_prefix}/machinetypes')
|
||||
app.register_blueprint(pctypes_bp, url_prefix=f'{api_prefix}/pctypes')
|
||||
app.register_blueprint(statuses_bp, url_prefix=f'{api_prefix}/statuses')
|
||||
app.register_blueprint(vendors_bp, url_prefix=f'{api_prefix}/vendors')
|
||||
app.register_blueprint(models_bp, url_prefix=f'{api_prefix}/models')
|
||||
app.register_blueprint(businessunits_bp, url_prefix=f'{api_prefix}/businessunits')
|
||||
app.register_blueprint(locations_bp, url_prefix=f'{api_prefix}/locations')
|
||||
app.register_blueprint(operatingsystems_bp, url_prefix=f'{api_prefix}/operatingsystems')
|
||||
app.register_blueprint(dashboard_bp, url_prefix=f'{api_prefix}/dashboard')
|
||||
app.register_blueprint(applications_bp, url_prefix=f'{api_prefix}/applications')
|
||||
app.register_blueprint(knowledgebase_bp, url_prefix=f'{api_prefix}/knowledgebase')
|
||||
app.register_blueprint(search_bp, url_prefix=f'{api_prefix}/search')
|
||||
|
||||
|
||||
def register_cli_commands(app: Flask):
|
||||
"""Register Flask CLI commands."""
|
||||
from .plugins.cli import plugin_cli
|
||||
from .cli import db_cli, seed_cli
|
||||
|
||||
app.cli.add_command(plugin_cli)
|
||||
app.cli.add_command(db_cli)
|
||||
app.cli.add_command(seed_cli)
|
||||
|
||||
|
||||
def register_error_handlers(app: Flask):
|
||||
"""Register error handlers."""
|
||||
from .utils.responses import error_response, ErrorCodes
|
||||
from .exceptions import ShopDBException
|
||||
|
||||
@app.errorhandler(ShopDBException)
|
||||
def handle_shopdb_exception(error):
|
||||
http_codes = {
|
||||
'NOT_FOUND': 404,
|
||||
'UNAUTHORIZED': 401,
|
||||
'FORBIDDEN': 403,
|
||||
'CONFLICT': 409,
|
||||
'VALIDATION_ERROR': 400,
|
||||
}
|
||||
http_code = http_codes.get(error.code, 400)
|
||||
return error_response(
|
||||
error.code,
|
||||
error.message,
|
||||
details=error.details,
|
||||
http_code=http_code
|
||||
)
|
||||
|
||||
@app.errorhandler(404)
|
||||
def not_found_error(error):
|
||||
return error_response(
|
||||
ErrorCodes.NOT_FOUND,
|
||||
'Resource not found',
|
||||
http_code=404
|
||||
)
|
||||
|
||||
@app.errorhandler(500)
|
||||
def internal_error(error):
|
||||
return error_response(
|
||||
ErrorCodes.INTERNAL_ERROR,
|
||||
'An internal error occurred',
|
||||
http_code=500
|
||||
)
|
||||
|
||||
@app.errorhandler(401)
|
||||
def unauthorized_error(error):
|
||||
return error_response(
|
||||
ErrorCodes.UNAUTHORIZED,
|
||||
'Authentication required',
|
||||
http_code=401
|
||||
)
|
||||
|
||||
|
||||
def register_frontend_routes(app: Flask):
|
||||
"""Serve Vue frontend static files."""
|
||||
frontend_dist = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'frontend', 'dist')
|
||||
|
||||
@app.route('/', defaults={'path': ''})
|
||||
@app.route('/<path:path>')
|
||||
def serve_frontend(path):
|
||||
# Don't serve API routes as frontend
|
||||
if path.startswith('api/'):
|
||||
from .utils.responses import error_response, ErrorCodes
|
||||
return error_response(ErrorCodes.NOT_FOUND, 'API endpoint not found', http_code=404)
|
||||
|
||||
# Serve static assets
|
||||
if path and os.path.exists(os.path.join(frontend_dist, path)):
|
||||
return send_from_directory(frontend_dist, path)
|
||||
|
||||
# Serve index.html for SPA routing
|
||||
return send_from_directory(frontend_dist, 'index.html')
|
||||
|
||||
|
||||
def configure_logging(app: Flask):
|
||||
"""Configure application logging."""
|
||||
log_level = app.config.get('LOG_LEVEL', 'INFO')
|
||||
|
||||
logging.basicConfig(
|
||||
level=getattr(logging, log_level),
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
Reference in New Issue
Block a user