#!/usr/bin/env python # -*- coding: utf-8 -*- # Dashboard Routes (Admin) from quart import Blueprint, request, render_template, redirect, url_for, jsonify, session from models.user import User from models.project import Project from models.category import Category from utils.auth import admin_required, get_current_user from utils.helpers import flash_message, generate_slug, calculate_pagination from utils.validators import validate_project_data dashboard_bp = Blueprint('dashboard', __name__, url_prefix='/dashboard') # Debug route to check authentication status @dashboard_bp.route('/debug/auth') async def debug_auth(): """Debug route to check authentication status""" current_user = await get_current_user() session_data = dict(session) debug_info = { 'session_exists': 'user_id' in session, 'user_id_in_session': session.get('user_id'), 'username_in_session': session.get('username'), 'is_admin_in_session': session.get('is_admin'), 'current_user_found': current_user is not None, 'current_user_is_admin': current_user.is_admin if current_user else None, 'current_user_details': { 'id': current_user.id, 'username': current_user.username, 'email': current_user.email, 'role': current_user.role, 'is_admin': current_user.is_admin } if current_user else None, 'session_data': session_data } return jsonify(debug_info) # Public route to check dashboard access without admin_required decorator @dashboard_bp.route('/debug/access') async def debug_access(): """Debug route to check dashboard access requirements""" try: current_user = await get_current_user() if not current_user: return jsonify({ 'status': 'error', 'message': 'Nessun utente loggato', 'redirect': url_for('auth.login') }), 401 if not current_user.is_admin: return jsonify({ 'status': 'error', 'message': f'Utente {current_user.username} non ha privilegi di amministratore', 'user_role': current_user.role, 'is_admin': current_user.is_admin, 'redirect': url_for('home.index') }), 403 return jsonify({ 'status': 'success', 'message': f'Accesso consentito per {current_user.username}', 'user': { 'id': current_user.id, 'username': current_user.username, 'role': current_user.role, 'is_admin': current_user.is_admin }, 'dashboard_url': url_for('dashboard.index') }) except Exception as e: return jsonify({ 'status': 'error', 'message': f'Errore durante il controllo accesso: {str(e)}' }), 500 @dashboard_bp.route('/') @admin_required async def index(): """Dashboard home""" try: current_user = await get_current_user() # Get statistics with error handling stats = { 'total_users': 0, 'total_projects': 0, 'published_projects': 0, 'featured_projects': 0 } try: stats['total_users'] = await User.count() except Exception as e: print(f"Error getting user count: {e}") try: stats['total_projects'] = await Project.count(published_only=False) stats['published_projects'] = await Project.count(published_only=True) featured_projects = await Project.get_featured() stats['featured_projects'] = len(featured_projects) if featured_projects else 0 except Exception as e: print(f"Error getting project stats: {e}") # Get recent projects with error handling recent_projects = [] try: recent_projects = await Project.get_all(published_only=False, limit=5) except Exception as e: print(f"Error getting recent projects: {e}") return await render_template('dashboard/index.html', user=current_user, stats=stats, recent_projects=recent_projects) except Exception as e: flash_message(f'Errore nel caricamento della dashboard: {str(e)}', 'error') return redirect(url_for('home.index')) @dashboard_bp.route('/projects') @admin_required async def projects(): """Projects management""" page = int(request.args.get('page', 1)) per_page = 10 try: # Get projects with pagination projects = await Project.get_all(published_only=False, limit=per_page, offset=(page-1)*per_page) total_projects = await Project.count(published_only=False) pagination = calculate_pagination(total_projects, page, per_page) return await render_template('dashboard/projects.html', projects=projects, pagination=pagination) except Exception as e: flash_message(f'Errore nel caricamento dei progetti: {str(e)}', 'error') return redirect(url_for('dashboard.index')) @dashboard_bp.route('/projects/new', methods=['GET', 'POST']) @admin_required async def new_project(): """Create new project""" if request.method == 'GET': try: categories = await Category.get_all() return await render_template('dashboard/project_form.html', project=None, categories=categories, action='create') except Exception as e: flash_message(f'Errore nel caricamento delle categorie: {str(e)}', 'error') return redirect(url_for('dashboard.projects')) form_data = await request.form data = { 'title': form_data.get('title', '').strip(), 'description': form_data.get('description', '').strip(), 'content': form_data.get('content', '').strip(), 'github_url': form_data.get('github_url', '').strip(), 'demo_url': form_data.get('demo_url', '').strip(), 'image_url': form_data.get('image_url', '').strip(), 'technologies': form_data.getlist('technologies'), 'category_id': int(form_data.get('category_id')) if form_data.get('category_id') else None, 'is_featured': bool(form_data.get('is_featured')), 'is_published': bool(form_data.get('is_published')) } # Validate data is_valid, errors = validate_project_data(data) if not is_valid: for field, error in errors.items(): flash_message(error, 'error') categories = await Category.get_all() return await render_template('dashboard/project_form.html', project=data, categories=categories, action='create') # Create project current_user = await get_current_user() project = Project( title=data['title'], slug=generate_slug(data['title']), description=data['description'], content=data['content'], github_url=data['github_url'], demo_url=data['demo_url'], image_url=data['image_url'], technologies=data['technologies'], category_id=data['category_id'], is_featured=data['is_featured'], is_published=data['is_published'], created_by=current_user.id ) try: await project.save() flash_message('Progetto creato con successo!', 'success') return redirect(url_for('dashboard.projects')) except Exception as e: flash_message('Errore durante la creazione del progetto', 'error') categories = await Category.get_all() return await render_template('dashboard/project_form.html', project=data, categories=categories, action='create') @dashboard_bp.route('/projects//edit', methods=['GET', 'POST']) @admin_required async def edit_project(project_id): """Edit project""" project = await Project.find_by_id(project_id) if not project: flash_message('Progetto non trovato', 'error') return redirect(url_for('dashboard.projects')) if request.method == 'GET': categories = await Category.get_all() return await render_template('dashboard/project_form.html', project=project, categories=categories, action='edit') form_data = await request.form data = { 'title': form_data.get('title', '').strip(), 'description': form_data.get('description', '').strip(), 'content': form_data.get('content', '').strip(), 'github_url': form_data.get('github_url', '').strip(), 'demo_url': form_data.get('demo_url', '').strip(), 'image_url': form_data.get('image_url', '').strip(), 'technologies': form_data.getlist('technologies'), 'category_id': int(form_data.get('category_id')) if form_data.get('category_id') else None, 'is_featured': bool(form_data.get('is_featured')), 'is_published': bool(form_data.get('is_published')) } # Validate data is_valid, errors = validate_project_data(data) if not is_valid: for field, error in errors.items(): flash_message(error, 'error') categories = await Category.get_all() return await render_template('dashboard/project_form.html', project=project, categories=categories, action='edit') # Update project project.title = data['title'] project.slug = generate_slug(data['title']) project.description = data['description'] project.content = data['content'] project.github_url = data['github_url'] project.demo_url = data['demo_url'] project.image_url = data['image_url'] project.technologies = data['technologies'] project.category_id = data['category_id'] project.is_featured = data['is_featured'] project.is_published = data['is_published'] try: await project.save() flash_message('Progetto aggiornato con successo!', 'success') return redirect(url_for('dashboard.projects')) except Exception as e: flash_message('Errore durante l\'aggiornamento del progetto', 'error') categories = await Category.get_all() return await render_template('dashboard/project_form.html', project=project, categories=categories, action='edit') @dashboard_bp.route('/projects//delete', methods=['POST']) @admin_required async def delete_project(project_id): """Delete project""" project = await Project.find_by_id(project_id) if not project: return jsonify({'error': 'Progetto non trovato'}), 404 try: await project.delete() flash_message('Progetto eliminato con successo!', 'success') return redirect(url_for('dashboard.projects')) except Exception as e: flash_message('Errore durante l\'eliminazione del progetto', 'error') return redirect(url_for('dashboard.projects')) @dashboard_bp.route('/users') @admin_required async def users(): """Users management""" page = int(request.args.get('page', 1)) per_page = 10 try: users = await User.get_all(limit=per_page, offset=(page-1)*per_page) total_users = await User.count() pagination = calculate_pagination(total_users, page, per_page) return await render_template('dashboard/users.html', users=users, pagination=pagination) except Exception as e: flash_message(f'Errore nel caricamento degli utenti: {str(e)}', 'error') return redirect(url_for('dashboard.index'))