Files
Code_of_Conquest/api/app/__init__.py
Phillip Tarrant f9e463bfc6 Root Cause
When using combat abilities (like "smite"), the web frontend was calling GET /api/v1/abilities/{ability_id} to fetch ability details for display, but this endpoint didn't exist, causing a 404 error.
  Additionally, after fixing that, the ability would execute but:

  1. Modal onclick issue: The onclick="closeModal()" on ability buttons was removing the button from the DOM before HTMX could fire the request
  2. Field name mismatch: The API returns mana_cost but the frontend expected mp_cost
  3. Duplicate text in combat log: The web view was adding "You" as actor and damage separately, but the API message already contained both
  4. Page not auto-refreshing: Various attempts to use HX-Trigger headers failed due to HTMX overwriting them

  Fixes Made

  1. Created /api/app/api/abilities.py - New abilities API endpoint with GET /api/v1/abilities and GET /api/v1/abilities/<ability_id>
  2. Modified /api/app/__init__.py - Registered the new abilities blueprint
  3. Modified /public_web/templates/game/partials/ability_modal.html - Changed onclick="closeModal()" to hx-on::before-request="closeModal()" so HTMX captures the request before modal closes
  4. Modified /public_web/app/views/combat_views.py:
    - Fixed mp_cost → mana_cost field name lookup
    - Removed duplicate actor/damage from combat log entries (API message is self-contained)
    - Added inline script to trigger page refresh after combat actions
  5. Modified /public_web/templates/game/combat.html - Updated JavaScript for combat action handling (though final fix was server-side script injection)
2025-11-29 19:05:39 -06:00

200 lines
5.9 KiB
Python

"""
Flask application factory for Code of Conquest.
Creates and configures the Flask application instance.
"""
import os
from flask import Flask
from flask_cors import CORS
from app.config import get_config
from app.utils.logging import setup_logging, get_logger
def create_app(environment: str = None) -> Flask:
"""
Application factory pattern for creating Flask app.
Args:
environment: Environment name (development, production, etc.)
If None, uses FLASK_ENV from environment variables.
Returns:
Flask: Configured Flask application instance
Example:
>>> app = create_app('development')
>>> app.run(debug=True)
"""
# Get the path to the project root (parent of 'app' package)
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Create Flask app with correct template and static folders
app = Flask(
__name__,
template_folder=os.path.join(project_root, 'templates'),
static_folder=os.path.join(project_root, 'static')
)
# Load configuration
config = get_config(environment)
# Configure Flask from config object
app.config['SECRET_KEY'] = config.secret_key
app.config['DEBUG'] = config.app.debug
# Set up logging
setup_logging(
log_level=config.logging.level,
log_format=config.logging.format,
log_file=config.logging.file_path if 'file' in config.logging.handlers else None
)
logger = get_logger(__name__)
logger.info(
"Starting Code of Conquest",
version=config.app.version,
environment=config.app.environment
)
# Configure CORS
CORS(app, origins=config.cors.origins)
# Store config in app context
app.config['COC_CONFIG'] = config
# Register error handlers
register_error_handlers(app)
# Register blueprints (when created)
register_blueprints(app)
logger.info("Application initialized successfully")
return app
def register_error_handlers(app: Flask) -> None:
"""
Register global error handlers for the application.
Args:
app: Flask application instance
"""
from app.utils.response import (
error_response,
internal_error_response,
not_found_response
)
logger = get_logger(__name__)
@app.errorhandler(404)
def handle_404(error):
"""Handle 404 Not Found errors."""
logger.warning("404 Not Found", path=error.description)
return not_found_response()
@app.errorhandler(500)
def handle_500(error):
"""Handle 500 Internal Server errors."""
logger.error("500 Internal Server Error", error=str(error), exc_info=True)
return internal_error_response()
@app.errorhandler(Exception)
def handle_exception(error):
"""Handle uncaught exceptions."""
logger.error(
"Uncaught exception",
error=str(error),
error_type=type(error).__name__,
exc_info=True
)
return internal_error_response()
def register_blueprints(app: Flask) -> None:
"""
Register Flask blueprints (API routes and web UI views).
Args:
app: Flask application instance
"""
logger = get_logger(__name__)
# ===== API Blueprints =====
# Import and register health check API blueprint
from app.api.health import health_bp
app.register_blueprint(health_bp)
logger.info("Health API blueprint registered")
# Import and register auth API blueprint
from app.api.auth import auth_bp
app.register_blueprint(auth_bp)
logger.info("Auth API blueprint registered")
# Import and register characters API blueprint
from app.api.characters import characters_bp
app.register_blueprint(characters_bp)
logger.info("Characters API blueprint registered")
# Import and register sessions API blueprint
from app.api.sessions import sessions_bp
app.register_blueprint(sessions_bp)
logger.info("Sessions API blueprint registered")
# Import and register jobs API blueprint
from app.api.jobs import jobs_bp
app.register_blueprint(jobs_bp)
logger.info("Jobs API blueprint registered")
# Import and register game mechanics API blueprint
from app.api.game_mechanics import game_mechanics_bp
app.register_blueprint(game_mechanics_bp)
logger.info("Game Mechanics API blueprint registered")
# Import and register travel API blueprint
from app.api.travel import travel_bp
app.register_blueprint(travel_bp)
logger.info("Travel API blueprint registered")
# Import and register NPCs API blueprint
from app.api.npcs import npcs_bp
app.register_blueprint(npcs_bp)
logger.info("NPCs API blueprint registered")
# Import and register Chat API blueprint
from app.api.chat import chat_bp
app.register_blueprint(chat_bp)
logger.info("Chat API blueprint registered")
# Import and register Combat API blueprint
from app.api.combat import combat_bp
app.register_blueprint(combat_bp)
logger.info("Combat API blueprint registered")
# Import and register Inventory API blueprint
from app.api.inventory import inventory_bp
app.register_blueprint(inventory_bp)
logger.info("Inventory API blueprint registered")
# Import and register Shop API blueprint
from app.api.shop import shop_bp
app.register_blueprint(shop_bp)
logger.info("Shop API blueprint registered")
# Import and register Quests API blueprint
from app.api.quests import quests_bp
app.register_blueprint(quests_bp)
logger.info("Quests API blueprint registered")
# Import and register Abilities API blueprint
from app.api.abilities import abilities_bp
app.register_blueprint(abilities_bp)
logger.info("Abilities API blueprint registered")
# TODO: Register additional blueprints as they are created
# from app.api import marketplace
# app.register_blueprint(marketplace.bp, url_prefix='/api/v1/marketplace')