setup update 2

This commit is contained in:
Alejandro Vazquez
2026-03-26 19:39:31 -03:00
parent fa76741d50
commit 9fb21c4a29
9 changed files with 86 additions and 54 deletions
+13 -12
View File
@@ -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
}
+14 -8
View File
@@ -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'),)
+12 -2
View File
@@ -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')
+1 -1
View File
@@ -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')
+31 -15
View File
@@ -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,
+4 -10
View File
@@ -71,7 +71,7 @@
<ul class="navbar-nav">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown">
<i class="bi bi-person-circle"></i> {{ current_user.name }}
<i class="bi bi-person-circle"></i> {{ current_user.first_name }} {{ current_user.last_name }}
</a>
<ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="{{ url_for('auth.profile') }}">
@@ -90,15 +90,6 @@
</div>
</div>
</nav>
<!-- Main Content -->
<main class="container-fluid pt-5 mt-4">
{% block content %}{% endblock %}
</main>
{% else %}
<main class="container-fluid">
{% block content %}{% endblock %}
</main>
{% endif %}
<!-- Flash Messages -->
@@ -119,6 +110,9 @@
{% endwith %}
</div>
<!-- Main Content -->
{% block content %}{% endblock %}
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<!-- jQuery -->
+9 -3
View File
@@ -3,6 +3,9 @@
{% block title %}Dashboard - Edu-Space Admin{% endblock %}
{% block content %}
{% if current_user.is_authenticated %}
<div class="container-fluid pt-5 mt-4">
{% endif %}
<div class="row mb-4">
<div class="col-12">
<h1 class="h3 mb-0">
@@ -154,7 +157,7 @@
{% for reservation in upcoming_reservations %}
<tr>
<td>{{ reservation.start_time.strftime('%Y-%m-%d %H:%M') }}</td>
<td>{{ reservation.classroom.code }}</td>
<td>{{ reservation.classroom.code }}</td>
<td>{{ reservation.commission.get_full_code() }}</td>
<td>{{ reservation.commission.teacher_name }}</td>
<td>
@@ -163,9 +166,9 @@
</span>
</td>
<td>
<a href="{{ url_for('schedule.view_reservation', Id=reservation.id) }}"
<a href="{{ url_for('schedule.list_reservations') }}"
class="btn btn-sm btn-outline-primary">
<i class="bi bi-eye"></i>
<i class="bi bi-eye"></i> View
</a>
</td>
</tr>
@@ -183,6 +186,9 @@
</div>
</div>
</div>
{% if current_user.is_authenticated %}
</div>
{% endif %}
{% endblock %}
{% block extra_js %}
+1 -2
View File
@@ -3,7 +3,7 @@ Flask-SQLAlchemy==3.1.1
Flask-Login==0.6.3
Flask-WTF==1.2.1
Flask-Migrate==4.0.5
Flask-CORS==4.0.0
Flask-CORS==6.0.2
WTForms==3.1.0
Werkzeug==3.0.1
SQLAlchemy==2.0.23
@@ -14,4 +14,3 @@ python-dateutil==2.8.2
Pillow==10.1.0
email_validator>=2.0.0
psycopg2-binary==2.9.9
Flask-CORS==6.0.2
+1 -1
View File
@@ -1,4 +1,4 @@
pipfrom setuptools import setup, find_packages
from setuptools import setup, find_packages
setup(
name="edu-space-admin",