From 9fb21c4a298c37d85688ed7d9f763f2b5ad298fb Mon Sep 17 00:00:00 2001 From: Alejandro Vazquez Date: Thu, 26 Mar 2026 19:39:31 -0300 Subject: [PATCH] setup update 2 --- app/models/classroom.py | 25 ++++++++++---------- app/models/subject.py | 22 ++++++++++------- app/models/user.py | 14 +++++++++-- app/routes/auth.py | 2 +- app/routes/main.py | 46 ++++++++++++++++++++++++------------ app/templates/base.html | 14 ++++------- app/templates/dashboard.html | 12 +++++++--- requirements.txt | 3 +-- setup.py | 2 +- 9 files changed, 86 insertions(+), 54 deletions(-) diff --git a/app/models/classroom.py b/app/models/classroom.py index 110c20e..049bebf 100644 --- a/app/models/classroom.py +++ b/app/models/classroom.py @@ -5,17 +5,21 @@ class Classroom(db.Model): __tablename__ = 'classrooms' id = db.Column(db.Integer, primary_key=True) - code = db.Column(db.String(20), unique=True, nullable=False, index=True) - name = db.Column(db.String(100), nullable=False) - building = db.Column(db.String(50), nullable=False) + campus_id = db.Column(db.Integer, db.ForeignKey('campuses.id'), nullable=False) + building = db.Column(db.String(100), nullable=False) + room_number = db.Column(db.String(50), nullable=False) floor = db.Column(db.Integer, nullable=False) capacity = db.Column(db.Integer, nullable=False) description = db.Column(db.Text) - campus_location = db.Column(db.String(50), default='Main Campus') is_active = db.Column(db.Boolean, default=True, nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) + # Virtual field for code (combination of building and room_number) + @property + def code(self): + return f"{self.building}-{self.room_number}" + # Relationships reservations = db.relationship('Reservation', backref='classroom', lazy=True, cascade='all, delete-orphan') @@ -27,12 +31,10 @@ class Classroom(db.Model): return { 'id': self.id, 'code': self.code, - 'name': self.name, 'building': self.building, 'floor': self.floor, 'capacity': self.capacity, 'description': self.description, - 'campus_location': self.campus_location, 'is_active': self.is_active, 'created_at': self.created_at.isoformat() if self.created_at else None, 'updated_at': self.updated_at.isoformat() if self.updated_at else None, @@ -55,10 +57,10 @@ class ClassroomResource(db.Model): brand = db.Column(db.String(100)) model = db.Column(db.String(100)) specifications = db.Column(db.Text) - quantity = db.Column(db.Integer, default=1) - is_functional = db.Column(db.Boolean, default=True) - last_maintenance = db.Column(db.DateTime) + functional = db.Column(db.Boolean, default=True) + last_maintenance_date = db.Column(db.DateTime) created_at = db.Column(db.DateTime, default=datetime.utcnow) + updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) def to_dict(self): """Convert resource to dictionary""" @@ -69,9 +71,8 @@ class ClassroomResource(db.Model): 'brand': self.brand, 'model': self.model, 'specifications': self.specifications, - 'quantity': self.quantity, - 'is_functional': self.is_functional, - 'last_maintenance': self.last_maintenance.isoformat() if self.last_maintenance else None, + 'functional': self.functional, + 'last_maintenance_date': self.last_maintenance_date.isoformat() if self.last_maintenance_date else None, 'created_at': self.created_at.isoformat() if self.created_at else None } diff --git a/app/models/subject.py b/app/models/subject.py index 7e6d91b..a89ae36 100644 --- a/app/models/subject.py +++ b/app/models/subject.py @@ -6,11 +6,11 @@ class Subject(db.Model): id = db.Column(db.Integer, primary_key=True) code = db.Column(db.String(20), unique=True, nullable=False, index=True) - name = db.Column(db.String(100), nullable=False) + name = db.Column(db.String(200), nullable=False) description = db.Column(db.Text) department = db.Column(db.String(100), nullable=False) - credits = db.Column(db.Integer) - duration_minutes = db.Column(db.Integer, default=90) + credits = db.Column(db.Integer, nullable=False) + duration_in_minutes = db.Column(db.Integer, nullable=False) is_active = db.Column(db.Boolean, default=True, nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) @@ -27,7 +27,7 @@ class Subject(db.Model): 'description': self.description, 'department': self.department, 'credits': self.credits, - 'duration_minutes': self.duration_minutes, + 'duration_minutes': self.duration_in_minutes, 'is_active': self.is_active, 'created_at': self.created_at.isoformat() if self.created_at else None, 'updated_at': self.updated_at.isoformat() if self.updated_at else None @@ -42,18 +42,24 @@ class Commission(db.Model): id = db.Column(db.Integer, primary_key=True) subject_id = db.Column(db.Integer, db.ForeignKey('subjects.id'), nullable=False) code = db.Column(db.String(50), nullable=False) - semester = db.Column(db.String(20), nullable=False) # Fall, Spring, Summer + semester = db.Column(db.String(20), nullable=False) year = db.Column(db.Integer, nullable=False) - teacher_name = db.Column(db.String(100), nullable=False) - max_students = db.Column(db.Integer, default=50) + teacher_id = db.Column(db.Integer, db.ForeignKey('users.id')) + max_students = db.Column(db.Integer, nullable=False) current_students = db.Column(db.Integer, default=0) - schedule = db.Column(db.String(255)) # e.g., "MWF 9:00-10:30 AM" + schedule = db.Column(db.String(255)) is_active = db.Column(db.Boolean, default=True, nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # Relationships reservations = db.relationship('Reservation', backref='commission', lazy=True, cascade='all, delete-orphan') + teacher = db.relationship('User', backref='teaching_commissions', foreign_keys=[teacher_id]) + + # Virtual field for teacher_name + @property + def teacher_name(self): + return f"{self.teacher.first_name} {self.teacher.last_name}" if self.teacher else "TBD" # Unique constraint __table_args__ = (db.UniqueConstraint('subject_id', 'code', 'semester', 'year'),) diff --git a/app/models/user.py b/app/models/user.py index 019b2f8..b2092be 100644 --- a/app/models/user.py +++ b/app/models/user.py @@ -7,14 +7,24 @@ class User(UserMixin, db.Model): __tablename__ = 'users' id = db.Column(db.Integer, primary_key=True) - email = db.Column(db.String(120), unique=True, nullable=False, index=True) + email = db.Column(db.String(255), unique=True, nullable=False, index=True) password_hash = db.Column(db.String(255), nullable=False) name = db.Column(db.String(100), nullable=False) - role = db.Column(db.String(20), default='admin', nullable=False) # admin, staff + role = db.Column(db.String(50), nullable=False) is_active = db.Column(db.Boolean, default=True, nullable=False) created_at = db.Column(db.DateTime, default=datetime.utcnow) last_login = db.Column(db.DateTime) + # Virtual fields for future compatibility + @property + def first_name(self): + return self.name.split()[0] if self.name else '' + + @property + def last_name(self): + parts = self.name.split() + return ' '.join(parts[1:]) if len(parts) > 1 else '' + # Relationships reservations = db.relationship('Reservation', backref='user', lazy=True, cascade='all, delete-orphan') diff --git a/app/routes/auth.py b/app/routes/auth.py index caf5beb..e5a56a7 100644 --- a/app/routes/auth.py +++ b/app/routes/auth.py @@ -29,7 +29,7 @@ def login(): if not next_page or not next_page.startswith('/'): next_page = url_for('main.dashboard') - flash(f'Welcome back, {user.name}!', 'success') + flash(f'Welcome back, {user.first_name} {user.last_name}!', 'success') return redirect(next_page) else: flash('Invalid email or password.', 'error') diff --git a/app/routes/main.py b/app/routes/main.py index 200341d..46f6d8a 100644 --- a/app/routes/main.py +++ b/app/routes/main.py @@ -3,6 +3,7 @@ from flask_login import login_required, current_user from app.models.reservation import Reservation from app.models.classroom import Classroom from app.models.subject import Subject +from app.models.subject import Commission from datetime import datetime, timedelta from sqlalchemy import func @@ -12,30 +13,45 @@ main_bp = Blueprint('main', __name__) @login_required def dashboard(): """Main dashboard page""" - # Get statistics - total_classrooms = Classroom.query.filter_by(is_active=True).count() - total_subjects = Subject.query.filter_by(is_active=True).count() +# Get statistics + try: + total_classrooms = Classroom.query.filter_by(is_active=True).count() + except: + total_classrooms = 0 + + try: + total_subjects = Subject.query.filter_by(is_active=True).count() + except: + total_subjects = 0 # Get today's reservations today = datetime.utcnow().date() - today_reservations = Reservation.query.filter( - func.date(Reservation.start_time) == today - ).count() + try: + today_reservations = Reservation.query.filter( + func.date(Reservation.start_time) == today + ).count() + except: + today_reservations = 0 # Get this week's reservations week_start = today - timedelta(days=today.weekday()) week_end = week_start + timedelta(days=6) - week_reservations = Reservation.query.filter( - func.date(Reservation.start_time) >= week_start, - func.date(Reservation.start_time) <= week_end - ).count() + try: + week_reservations = Reservation.query.filter( + func.date(Reservation.start_time) >= week_start, + func.date(Reservation.start_time) <= week_end + ).count() + except: + week_reservations = 0 # Get upcoming reservations (next 7 days) - upcoming_reservations = Reservation.query.filter( - Reservation.start_time >= datetime.utcnow(), - Reservation.start_time <= datetime.utcnow() + timedelta(days=7), - Reservation.status.in_(['CONFIRMED', 'PENDING']) - ).join(Classroom).join(Subject).limit(10).all() + try: + upcoming_reservations = Reservation.query.filter( + Reservation.start_time >= datetime.utcnow(), + Reservation.start_time <= datetime.utcnow() + timedelta(days=7) + ).limit(10).all() + except: + upcoming_reservations = [] stats = { 'total_classrooms': total_classrooms, diff --git a/app/templates/base.html b/app/templates/base.html index fec41e4..e25758b 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -71,7 +71,7 @@