add license

This commit is contained in:
Alejandro Vazquez
2026-03-26 10:14:40 -03:00
commit 48bace5167
29 changed files with 2802 additions and 0 deletions
+214
View File
@@ -0,0 +1,214 @@
from flask import Blueprint, render_template, request, redirect, url_for, flash, jsonify
from flask_login import login_required
from app import db
from app.models.classroom import Classroom, ClassroomResource
from app.models.reservation import Reservation, ReservationStatus
from app.forms.classroom import ClassroomForm, ClassroomResourceForm
from datetime import datetime
classrooms_bp = Blueprint('classrooms', __name__, url_prefix='/classrooms')
@classrooms_bp.route('/')
@login_required
def list_classrooms():
"""List all classrooms"""
page = request.args.get('page', 1, type=int)
search = request.args.get('search', '')
campus = request.args.get('campus', '')
query = Classroom.query.filter_by(is_active=True)
if search:
query = query.filter(
Classroom.code.contains(search) |
Classroom.name.contains(search) |
Classroom.building.contains(search)
)
if campus:
query = query.filter(Classroom.campus_location == campus)
classrooms = query.paginate(
page=page,
per_page=20,
error_out=False
)
return render_template('classrooms/list.html',
classrooms=classrooms,
search=search,
campus=campus)
@classrooms_bp.route('/add', methods=['GET', 'POST'])
@login_required
def add_classroom():
"""Add new classroom"""
form = ClassroomForm()
if form.validate_on_submit():
classroom = Classroom(
code=form.code.data,
name=form.name.data,
building=form.building.data,
floor=form.floor.data,
capacity=form.capacity.data,
description=form.description.data,
campus_location=form.campus_location.data
)
try:
db.session.add(classroom)
db.session.commit()
flash(f'Classroom {classroom.code} added successfully!', 'success')
return redirect(url_for('classrooms.list_classrooms'))
except Exception as e:
db.session.rollback()
flash('Error adding classroom. Classroom code might already exist.', 'error')
return render_template('classrooms/add.html', form=form)
@classrooms_bp.route('/edit/<int:Id>', methods=['GET', 'POST'])
@login_required
def edit_classroom(Id):
"""Edit classroom"""
classroom = Classroom.query.get_or_404(Id)
if not classroom.is_active:
flash('This classroom has been deactivated.', 'warning')
return redirect(url_for('classrooms.list_classrooms'))
form = ClassroomForm(obj=classroom)
if form.validate_on_submit():
try:
classroom.code = form.code.data
classroom.name = form.name.data
classroom.building = form.building.data
classroom.floor = form.floor.data
classroom.capacity = form.capacity.data
classroom.description = form.description.data
classroom.campus_location = form.campus_location.data
classroom.updated_at = datetime.utcnow()
db.session.commit()
flash(f'Classroom {classroom.code} updated successfully!', 'success')
return redirect(url_for('classrooms.view_classroom', Id=classroom.id))
except Exception as e:
db.session.rollback()
flash('Error updating classroom.', 'error')
return render_template('classrooms/edit.html', form=form, classroom=classroom)
@classrooms_bp.route('/view/<int:Id>')
@login_required
def view_classroom(Id):
"""View classroom details"""
classroom = Classroom.query.get_or_404(Id)
if not classroom.is_active:
flash('This classroom has been deactivated.', 'warning')
return redirect(url_for('classrooms.list_classrooms'))
# Get classroom resources
resources = ClassroomResource.query.filter_by(classroom_id=Id).all()
# Get upcoming reservations
upcoming_reservations = Reservation.query.filter(
Reservation.classroom_id == Id,
Reservation.start_time >= datetime.utcnow(),
Reservation.status.in_([ReservationStatus.CONFIRMED, ReservationStatus.PENDING])
).order_by(Reservation.start_time).limit(10).all()
return render_template('classrooms/view.html',
classroom=classroom,
resources=resources,
upcoming_reservations=upcoming_reservations)
@classrooms_bp.route('/delete/<int:Id>')
@login_required
def delete_classroom(Id):
"""Delete/deactivate classroom"""
classroom = Classroom.query.get_or_404(Id)
# Check for active reservations
active_reservations = Reservation.query.filter(
Reservation.classroom_id == Id,
Reservation.status.in_([ReservationStatus.CONFIRMED, ReservationStatus.PENDING])
).count()
if active_reservations > 0:
flash('Cannot delete classroom with active reservations.', 'error')
return redirect(url_for('classrooms.view_classroom', Id=Id))
try:
classroom.is_active = False
classroom.updated_at = datetime.utcnow()
db.session.commit()
flash(f'Classroom {classroom.code} has been deactivated.', 'success')
except Exception as e:
db.session.rollback()
flash('Error deactivating classroom.', 'error')
return redirect(url_for('classrooms.list_classrooms'))
@classrooms_bp.route('/<int:classroom_id>/add_resource', methods=['GET', 'POST'])
@login_required
def add_resource(classroom_id):
"""Add resource to classroom"""
classroom = Classroom.query.get_or_404(classroom_id)
form = ClassroomResourceForm()
if form.validate_on_submit():
resource = ClassroomResource(
classroom_id=classroom_id,
resource_type=form.resource_type.data,
brand=form.brand.data,
model=form.model.data,
specifications=form.specifications.data,
quantity=form.quantity.data
)
try:
db.session.add(resource)
db.session.commit()
flash(f'{resource.resource_type} added to {classroom.code} successfully!', 'success')
return redirect(url_for('classrooms.view_classroom', Id=classroom_id))
except Exception as e:
db.session.rollback()
flash('Error adding resource.', 'error')
return render_template('classrooms/add_resource.html', form=form, classroom=classroom)
@classrooms_bp.route('/api/available')
@login_required
def api_available_classrooms():
"""API endpoint to get available classrooms"""
start_time = request.args.get('start_time')
end_time = request.args.get('end_time')
min_capacity = request.args.get('min_capacity', 0, type=int)
if not start_time or not end_time:
return jsonify({'error': 'start_time and end_time are required'}), 400
try:
start_dt = datetime.fromisoformat(start_time)
end_dt = datetime.fromisoformat(end_time)
except ValueError:
return jsonify({'error': 'Invalid datetime format'}), 400
# Find available classrooms (without conflicts)
conflicting_classroom_ids = [
r.classroom_id for r in Reservation.query.filter(
Reservation.start_time < end_dt,
Reservation.end_time > start_dt,
Reservation.status == ReservationStatus.CONFIRMED
).all()
]
available_classrooms = Classroom.query.filter(
Classroom.is_active == True,
Classroom.capacity >= min_capacity,
~Classroom.id.in_(conflicting_classroom_ids)
).all()
return jsonify([classroom.to_dict() for classroom in available_classrooms])