from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify from flask_login import login_required, current_user from datetime import datetime, date from app.models.classroom import Classroom from app.models.user import User from app.forms.classroom import ClassroomForm from app import db from sqlalchemy import text classrooms_bp = Blueprint('classrooms', __name__) @classrooms_bp.route('/add', methods=['GET', 'POST']) @login_required def add_classroom(): """Add a new classroom""" form = ClassroomForm() # TODO: Update when campus model is implemented # form.campus_id.choices = [(1, 'Main Campus')] if form.validate_on_submit(): try: existing_classroom = Classroom.query.filter_by( building=form.building.data, code=form.room_number.data, floor=form.floor.data ).first() if existing_classroom: flash('Classroom with this building, room number, and floor already exists.', 'error') return render_template('classrooms/add.html', form=form, title='Add Classroom') classroom = Classroom( # campus_id=form.campus_id.data, building=form.building.data, code=form.room_number.data, name=f"{form.building.data}-{form.room_number.data}", floor=form.floor.data, capacity=form.capacity.data, description=form.description.data, is_active=form.is_active.data ) db.session.add(classroom) db.session.commit() flash(f'Classroom {classroom.code_display} has been created successfully!', 'success') return redirect(url_for('classrooms.list_classrooms')) except Exception as e: db.session.rollback() flash(f'Error creating classroom: {str(e)}', 'error') return render_template('classrooms/add.html', form=form, title='Add Classroom') @classrooms_bp.route('/list') @login_required def list_classrooms(): """List all classrooms""" try: # Get filters page = request.args.get('page', 1, type=int) active_only = request.args.get('active_only', 'true').lower() == 'true' search = request.args.get('search', '', type=str) # Build query query = Classroom.query if active_only: query = query.filter_by(is_active=True) if search: query = query.filter( db.or_( Classroom.building.ilike(f'%{search}%'), Classroom.code.ilike(f'%{search}%'), Classroom.description.ilike(f'%{search}%') ) ) # Paginate results classrooms = query.order_by(Classroom.building, Classroom.floor, Classroom.code).paginate( page=page, per_page=12, error_out=False ) return render_template('classrooms/list.html', classrooms=classrooms, active_only=active_only, search=search, title='Classrooms') except Exception as e: flash(f'Error loading classrooms: {str(e)}', 'error') return render_template('classrooms/list.html', classrooms=None, title='Classrooms') @classrooms_bp.route('/') @login_required def view_classroom(id): """View classroom details""" try: classroom = Classroom.query.get_or_404(id) # Get upcoming reservations for this classroom from app.models.reservation import Reservation, ReservationStatus upcoming_reservations = Reservation.query.filter( Reservation.classroom_id == id, Reservation.start_time > datetime.utcnow(), Reservation.status == ReservationStatus.CONFIRMED ).order_by(Reservation.start_time).limit(10).all() return render_template('classrooms/view.html', classroom=classroom, upcoming_reservations=upcoming_reservations, title=f'Classroom {classroom.code_display}') except Exception as e: flash(f'Error loading classroom: {str(e)}', 'error') return redirect(url_for('classrooms.list_classrooms')) @classrooms_bp.route('//edit', methods=['GET', 'POST']) @login_required def edit_classroom(id): """Edit classroom""" classroom = Classroom.query.get_or_404(id) form = ClassroomForm(obj=classroom) # TODO: Update when campus model is implemented # form.campus_id.choices = [(1, 'Main Campus')] if form.validate_on_submit(): try: # Check for duplicates (excluding current classroom) existing_classroom = Classroom.query.filter( Classroom.building == form.building.data, Classroom.code == form.room_number.data, Classroom.floor == form.floor.data, Classroom.id != id ).first() if existing_classroom: flash('Classroom with this building, room number, and floor already exists.', 'error') return render_template('classrooms/edit.html', form=form, classroom=classroom, title='Edit Classroom') # Update classroom # classroom.campus_id = form.campus_id.data classroom.building = form.building.data classroom.code = form.room_number.data classroom.name = f"{form.building.data}-{form.room_number.data}" classroom.floor = form.floor.data classroom.capacity = form.capacity.data classroom.description = form.description.data classroom.is_active = form.is_active.data classroom.updated_at = datetime.utcnow() db.session.commit() flash(f'Classroom {classroom.code_display} has been updated successfully!', 'success') return redirect(url_for('classrooms.view_classroom', id=classroom.id)) except Exception as e: db.session.rollback() flash(f'Error updating classroom: {str(e)}', 'error') return render_template('classrooms/edit.html', form=form, classroom=classroom, title='Edit Classroom') @classrooms_bp.route('//toggle', methods=['POST']) @login_required def toggle_classroom(id): """Toggle classroom active status""" classroom = Classroom.query.get_or_404(id) try: classroom.is_active = not classroom.is_active classroom.updated_at = datetime.utcnow() db.session.commit() status = 'activated' if classroom.is_active else 'deactivated' flash(f'Classroom {classroom.code_display} has been {status} successfully!', 'success') except Exception as e: db.session.rollback() flash(f'Error updating classroom status: {str(e)}', 'error') return redirect(request.referrer or url_for('classrooms.list_classrooms')) # API endpoints for AJAX requests @classrooms_bp.route('/api/available') @login_required def get_available_classrooms(): """Get available classrooms for a specific time slot""" start_time = request.args.get('start_time') end_time = request.args.get('end_time') if not start_time or not end_time: return jsonify({'error': 'Start time and end time are required'}), 400 try: from datetime import datetime from app.models.reservation import Reservation, ReservationStatus start_dt = datetime.fromisoformat(start_time) end_dt = datetime.fromisoformat(end_time) # Find all classrooms all_classrooms = Classroom.query.filter_by(is_active=True).all() available_classrooms = [] for classroom in all_classrooms: # Check if classroom has conflicting reservations conflicts = Reservation.query.filter( Reservation.classroom_id == classroom.id, Reservation.status == ReservationStatus.CONFIRMED, Reservation.start_time < end_dt, Reservation.end_time > start_dt ).all() if not conflicts: available_classrooms.append({ 'id': classroom.id, 'code': classroom.code, 'building': classroom.building, 'room_number': classroom.code, 'floor': classroom.floor, 'capacity': classroom.capacity, 'code_display': classroom.code_display }) return jsonify({'classrooms': available_classrooms}) except Exception as e: return jsonify({'error': str(e)}), 500