""" Flask routes for INDEX-SISTEM-JOCURI v2.0 Clean, minimalist web interface with dynamic filters """ from flask import Blueprint, request, render_template, jsonify, current_app from app.models.database import DatabaseManager from app.models.activity import Activity from app.services.search import SearchService import os from pathlib import Path bp = Blueprint('main', __name__) # Initialize database manager (will be configured in application factory) def get_db_manager(): """Get database manager instance""" db_path = current_app.config.get('DATABASE_URL', 'sqlite:///data/activities.db') if db_path.startswith('sqlite:///'): db_path = db_path[10:] return DatabaseManager(db_path) def get_search_service(): """Get search service instance""" return SearchService(get_db_manager()) @bp.route('/') def index(): """Main search page with dynamic filters""" try: db = get_db_manager() # Get dynamic filter options from database filter_options = db.get_filter_options() # Get database statistics for the interface stats = db.get_statistics() return render_template('index.html', filters=filter_options, stats=stats) except Exception as e: print(f"Error loading main page: {e}") # Fallback with empty filters return render_template('index.html', filters={}, stats={'total_activities': 0}) @bp.route('/search', methods=['GET', 'POST']) def search(): """Search activities with filters""" try: search_service = get_search_service() # Get search parameters if request.method == 'POST': search_query = request.form.get('search_query', '').strip() filters = {k: v for k, v in request.form.items() if k != 'search_query' and v and v.strip()} else: search_query = request.args.get('q', '').strip() filters = {k: v for k, v in request.args.items() if k != 'q' and v and v.strip()} # Perform search results = search_service.search_activities( search_text=search_query if search_query else None, filters=filters, limit=current_app.config.get('SEARCH_RESULTS_LIMIT', 100) ) # Convert results to Activity objects for better template handling activities = [Activity.from_dict(result) for result in results] # Get filter options for the form db = get_db_manager() filter_options = db.get_filter_options() return render_template('results.html', activities=activities, search_query=search_query, applied_filters=filters, filters=filter_options, results_count=len(activities)) except Exception as e: print(f"Search error: {e}") return render_template('results.html', activities=[], search_query='', applied_filters={}, filters={}, results_count=0, error=str(e)) @bp.route('/activity/') def activity_detail(activity_id): """Show detailed activity information""" try: db = get_db_manager() # Get activity activity_data = db.get_activity_by_id(activity_id) if not activity_data: return render_template('404.html'), 404 activity = Activity.from_dict(activity_data) # Get similar activities (same category) similar_results = db.search_activities( category=activity.category, limit=5 ) # Filter out current activity and convert to Activity objects similar_activities = [ Activity.from_dict(result) for result in similar_results if result['id'] != activity_id ][:3] # Limit to 3 recommendations return render_template('activity.html', activity=activity, similar_activities=similar_activities) except Exception as e: print(f"Error loading activity {activity_id}: {e}") return render_template('404.html'), 404 @bp.route('/health') def health_check(): """Health check endpoint for Docker""" try: db = get_db_manager() stats = db.get_statistics() return jsonify({ 'status': 'healthy', 'database': 'connected', 'activities_count': stats.get('total_activities', 0), 'timestamp': stats.get('timestamp', 'unknown') }) except Exception as e: return jsonify({ 'status': 'unhealthy', 'error': str(e) }), 500 @bp.route('/api/statistics') def api_statistics(): """API endpoint for database statistics""" try: db = get_db_manager() stats = db.get_statistics() return jsonify(stats) except Exception as e: return jsonify({'error': str(e)}), 500 @bp.route('/api/filters') def api_filters(): """API endpoint for dynamic filter options""" try: db = get_db_manager() filters = db.get_filter_options() return jsonify(filters) except Exception as e: return jsonify({'error': str(e)}), 500 @bp.route('/api/search') def api_search(): """JSON API for search (for AJAX requests)""" try: search_service = get_search_service() # Get search parameters from query string search_query = request.args.get('q', '').strip() filters = {k: v for k, v in request.args.items() if k not in ['q', 'limit', 'format'] and v and v.strip()} limit = min(int(request.args.get('limit', 50)), 100) # Max 100 results # Perform search results = search_service.search_activities( search_text=search_query if search_query else None, filters=filters, limit=limit ) # Format results for JSON response formatted_results = [] for result in results: activity = Activity.from_dict(result) formatted_results.append({ 'id': activity.id, 'name': activity.name, 'description': activity.description[:200] + '...' if len(activity.description) > 200 else activity.description, 'category': activity.category, 'age_range': activity.get_age_range_display(), 'participants': activity.get_participants_display(), 'duration': activity.get_duration_display(), 'materials': activity.get_materials_display(), 'source_file': activity.source_file, 'url': f'/activity/{activity.id}' }) return jsonify({ 'results': formatted_results, 'count': len(formatted_results), 'query': search_query, 'filters': filters }) except Exception as e: return jsonify({'error': str(e)}), 500 @bp.errorhandler(404) def not_found(error): """404 error handler""" return render_template('404.html'), 404 @bp.errorhandler(500) def internal_error(error): """500 error handler""" return render_template('500.html'), 500