Spaces:
Sleeping
Sleeping
Yujie Chen commited on
Commit ·
871160f
1
Parent(s): a31fc52
Updates
Browse files- Dockerfile +2 -2
- README.md +41 -10
- app.py +23 -7
- data/courses_seed.json +16 -1
- requirements.txt +1 -0
Dockerfile
CHANGED
|
@@ -11,6 +11,6 @@ RUN pip install --no-cache-dir -r requirements.txt
|
|
| 11 |
COPY . .
|
| 12 |
# Expose the port expected by Hugging Face Spaces (default: 7860, but $PORT is set by HF)
|
| 13 |
EXPOSE 7860
|
| 14 |
-
# Use
|
| 15 |
ENV PORT=7860
|
| 16 |
-
CMD
|
|
|
|
| 11 |
COPY . .
|
| 12 |
# Expose the port expected by Hugging Face Spaces (default: 7860, but $PORT is set by HF)
|
| 13 |
EXPOSE 7860
|
| 14 |
+
# Use gunicorn for production WSGI server
|
| 15 |
ENV PORT=7860
|
| 16 |
+
CMD gunicorn -b 0.0.0.0:$PORT app:APP
|
README.md
CHANGED
|
@@ -8,17 +8,48 @@ app_file: app.py
|
|
| 8 |
pinned: false
|
| 9 |
---
|
| 10 |
|
| 11 |
-
# Minerva Lite
|
| 12 |
|
| 13 |
-
|
| 14 |
|
| 15 |
-
## Features
|
| 16 |
-
- Simple course registration and schedule management
|
| 17 |
-
- Minimal dependencies
|
| 18 |
-
- Ready for Hugging Face Spaces deployment
|
| 19 |
|
| 20 |
-
|
| 21 |
-
|
| 22 |
|
| 23 |
-
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
pinned: false
|
| 9 |
---
|
| 10 |
|
| 11 |
+
# Minerva Lite: Registration
|
| 12 |
|
| 13 |
+
Minerva Lite is a simplified web-based simulation of course registration. It is designed for demonstration, testing, and educational purposes.
|
| 14 |
|
| 15 |
+
## Key Features
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
+
- **Term Selection:**
|
| 18 |
+
- Choose from multiple academic terms (Fall 2025, Winter 2026, Summer 2026, Fall 2026).
|
| 19 |
|
| 20 |
+
- **Course Search:**
|
| 21 |
+
- Search for courses by subject, number, title, or campus.
|
| 22 |
+
- View available courses for the selected term, including seat availability and schedule details.
|
| 23 |
+
|
| 24 |
+
- **Add/Drop Courses:**
|
| 25 |
+
- Register for courses by entering a CRN (Course Reference Number).
|
| 26 |
+
- Drop registered courses.
|
| 27 |
+
- Registration is simulated for a single demo student.
|
| 28 |
+
|
| 29 |
+
- **Student Schedule:**
|
| 30 |
+
- View your current course registrations for the selected term.
|
| 31 |
+
- See a weekly grid view of your schedule, with time blocks for each class.
|
| 32 |
+
|
| 33 |
+
- **Accounts:**
|
| 34 |
+
- View a placeholder page for tuition fee and legal status (for demonstration).
|
| 35 |
+
|
| 36 |
+
- **Database Reset:**
|
| 37 |
+
- Use the `/reset` endpoint to reseed the database with demo data (useful for testing or restoring the initial state).
|
| 38 |
+
|
| 39 |
+
## Demo Data
|
| 40 |
+
|
| 41 |
+
- The app comes preloaded with a variety of courses across multiple terms and departments (COMP, MATH, PHYS, ECON, ENGL, etc.).
|
| 42 |
+
- Each course includes details such as subject, number, title, credits, days, time, campus, and seat availability.
|
| 43 |
+
|
| 44 |
+
## Intended Use
|
| 45 |
+
|
| 46 |
+
- This app is for demonstration and educational purposes only.
|
| 47 |
+
- No real student data is used or stored.
|
| 48 |
+
|
| 49 |
+
## How to Use
|
| 50 |
+
|
| 51 |
+
1. **Select a term** to begin.
|
| 52 |
+
2. **Search for courses** or browse available options.
|
| 53 |
+
3. **Add or drop courses** using CRNs.
|
| 54 |
+
4. **View your schedule** in list or weekly grid format.
|
| 55 |
+
5. **Reset the database** if you want to restore the original demo data.
|
app.py
CHANGED
|
@@ -1,10 +1,9 @@
|
|
| 1 |
-
import sqlite3, pathlib
|
| 2 |
-
from functools import wraps
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
#
|
| 6 |
import os
|
|
|
|
|
|
|
|
|
|
| 7 |
from flask import Flask, render_template, request, jsonify, redirect, url_for, session
|
|
|
|
| 8 |
APP = Flask(__name__)
|
| 9 |
# Use environment variable for secret key (required for Spaces)
|
| 10 |
APP.secret_key = os.environ.get("SECRET_KEY", "dev-minerva-lite")
|
|
@@ -46,8 +45,25 @@ def require_term(step_key):
|
|
| 46 |
return wrapper
|
| 47 |
return decorator
|
| 48 |
|
| 49 |
-
|
| 50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
|
| 52 |
def q(sql, *params):
|
| 53 |
con = sqlite3.connect(DB_PATH)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import os
|
| 2 |
+
import sqlite3
|
| 3 |
+
import pathlib
|
| 4 |
+
from functools import wraps
|
| 5 |
from flask import Flask, render_template, request, jsonify, redirect, url_for, session
|
| 6 |
+
|
| 7 |
APP = Flask(__name__)
|
| 8 |
# Use environment variable for secret key (required for Spaces)
|
| 9 |
APP.secret_key = os.environ.get("SECRET_KEY", "dev-minerva-lite")
|
|
|
|
| 45 |
return wrapper
|
| 46 |
return decorator
|
| 47 |
|
| 48 |
+
|
| 49 |
+
# Always ensure DB is seeded: if DB file is missing or 'courses' table is missing, run seed
|
| 50 |
+
def ensure_db_seeded():
|
| 51 |
+
need_seed = False
|
| 52 |
+
if not DB_PATH.exists():
|
| 53 |
+
need_seed = True
|
| 54 |
+
else:
|
| 55 |
+
try:
|
| 56 |
+
con = sqlite3.connect(DB_PATH)
|
| 57 |
+
cur = con.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='courses'")
|
| 58 |
+
if not cur.fetchone():
|
| 59 |
+
need_seed = True
|
| 60 |
+
con.close()
|
| 61 |
+
except Exception:
|
| 62 |
+
need_seed = True
|
| 63 |
+
if need_seed:
|
| 64 |
+
import seed # side effect: creates DB
|
| 65 |
+
|
| 66 |
+
ensure_db_seeded()
|
| 67 |
|
| 68 |
def q(sql, *params):
|
| 69 |
con = sqlite3.connect(DB_PATH)
|
data/courses_seed.json
CHANGED
|
@@ -18,6 +18,21 @@
|
|
| 18 |
{"crn": "10016", "subject": "ECON", "number": "340", "title": "Macroeconomic Theory", "credits": 3, "days": "MW", "time": "15:05-16:25", "campus": "Downtown", "seats_total": 100, "seats_taken": 85},
|
| 19 |
{"crn": "10017", "subject": "HIST", "number": "210", "title": "Modern World History", "credits": 3, "days": "MWF", "time": "13:35-14:25", "campus": "Downtown", "seats_total": 140, "seats_taken": 95},
|
| 20 |
{"crn": "10018", "subject": "PHYS", "number": "230", "title": "Electricity and Magnetism", "credits": 3, "days": "TR", "time": "16:05-17:25", "campus": "Downtown", "seats_total": 110, "seats_taken": 60},
|
| 21 |
-
{"crn": "10019", "subject": "ENGL", "number": "315", "title": "Creative Writing Workshop", "credits": 3, "days": "MW", "time": "09:05-10:25", "campus": "Downtown", "seats_total": 60, "seats_taken": 45}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
]
|
| 23 |
}
|
|
|
|
| 18 |
{"crn": "10016", "subject": "ECON", "number": "340", "title": "Macroeconomic Theory", "credits": 3, "days": "MW", "time": "15:05-16:25", "campus": "Downtown", "seats_total": 100, "seats_taken": 85},
|
| 19 |
{"crn": "10017", "subject": "HIST", "number": "210", "title": "Modern World History", "credits": 3, "days": "MWF", "time": "13:35-14:25", "campus": "Downtown", "seats_total": 140, "seats_taken": 95},
|
| 20 |
{"crn": "10018", "subject": "PHYS", "number": "230", "title": "Electricity and Magnetism", "credits": 3, "days": "TR", "time": "16:05-17:25", "campus": "Downtown", "seats_total": 110, "seats_taken": 60},
|
| 21 |
+
{"crn": "10019", "subject": "ENGL", "number": "315", "title": "Creative Writing Workshop", "credits": 3, "days": "MW", "time": "09:05-10:25", "campus": "Downtown", "seats_total": 60, "seats_taken": 45},
|
| 22 |
+
{"crn": "20001", "subject": "COMP", "number": "303", "title": "Software Engineering", "credits": 3, "days": "TR", "time": "10:00-11:20", "campus": "Downtown", "seats_total": 100, "seats_taken": 80, "term": "Winter 2026"},
|
| 23 |
+
{"crn": "20002", "subject": "MATH", "number": "315", "title": "Ordinary Differential Equations", "credits": 3, "days": "MWF", "time": "12:00-12:50", "campus": "Downtown", "seats_total": 120, "seats_taken": 100, "term": "Winter 2026"},
|
| 24 |
+
{"crn": "20003", "subject": "PHYS", "number": "204", "title": "Waves and Optics", "credits": 3, "days": "TR", "time": "13:00-14:20", "campus": "Downtown", "seats_total": 90, "seats_taken": 60, "term": "Winter 2026"},
|
| 25 |
+
{"crn": "20004", "subject": "ECON", "number": "208", "title": "Microeconomic Theory", "credits": 3, "days": "MWF", "time": "09:00-09:50", "campus": "Downtown", "seats_total": 110, "seats_taken": 90, "term": "Winter 2026"},
|
| 26 |
+
{"crn": "20005", "subject": "ENGL", "number": "220", "title": "Shakespeare", "credits": 3, "days": "TR", "time": "14:00-15:20", "campus": "Downtown", "seats_total": 60, "seats_taken": 40, "term": "Winter 2026"},
|
| 27 |
+
{"crn": "30001", "subject": "COMP", "number": "310", "title": "Computer Systems", "credits": 3, "days": "MWF", "time": "11:00-11:50", "campus": "Downtown", "seats_total": 80, "seats_taken": 50, "term": "Summer 2026"},
|
| 28 |
+
{"crn": "30002", "subject": "MATH", "number": "327", "title": "Probability", "credits": 3, "days": "TR", "time": "13:00-14:20", "campus": "Downtown", "seats_total": 90, "seats_taken": 70, "term": "Summer 2026"},
|
| 29 |
+
{"crn": "30003", "subject": "PHYS", "number": "205", "title": "Modern Physics", "credits": 3, "days": "MW", "time": "15:00-16:20", "campus": "Downtown", "seats_total": 60, "seats_taken": 30, "term": "Summer 2026"},
|
| 30 |
+
{"crn": "30004", "subject": "ECON", "number": "256", "title": "International Economics", "credits": 3, "days": "TR", "time": "10:00-11:20", "campus": "Downtown", "seats_total": 70, "seats_taken": 40, "term": "Summer 2026"},
|
| 31 |
+
{"crn": "30005", "subject": "ENGL", "number": "250", "title": "Canadian Literature", "credits": 3, "days": "MWF", "time": "13:00-13:50", "campus": "Downtown", "seats_total": 50, "seats_taken": 20, "term": "Summer 2026"},
|
| 32 |
+
{"crn": "40001", "subject": "COMP", "number": "302", "title": "Programming Languages and Paradigms", "credits": 3, "days": "TR", "time": "09:00-10:20", "campus": "Downtown", "seats_total": 110, "seats_taken": 80, "term": "Fall 2026"},
|
| 33 |
+
{"crn": "40002", "subject": "MATH", "number": "314", "title": "Advanced Calculus", "credits": 3, "days": "MWF", "time": "10:00-10:50", "campus": "Downtown", "seats_total": 100, "seats_taken": 90, "term": "Fall 2026"},
|
| 34 |
+
{"crn": "40003", "subject": "PHYS", "number": "206", "title": "Thermodynamics", "credits": 3, "days": "TR", "time": "11:00-12:20", "campus": "Downtown", "seats_total": 80, "seats_taken": 60, "term": "Fall 2026"},
|
| 35 |
+
{"crn": "40004", "subject": "ECON", "number": "330", "title": "Public Finance", "credits": 3, "days": "MWF", "time": "12:00-12:50", "campus": "Downtown", "seats_total": 90, "seats_taken": 70, "term": "Fall 2026"},
|
| 36 |
+
{"crn": "40005", "subject": "ENGL", "number": "260", "title": "World Literature", "credits": 3, "days": "TR", "time": "14:00-15:20", "campus": "Downtown", "seats_total": 60, "seats_taken": 30, "term": "Fall 2026"}
|
| 37 |
]
|
| 38 |
}
|
requirements.txt
CHANGED
|
@@ -5,3 +5,4 @@ itsdangerous==2.2.0
|
|
| 5 |
click==8.1.7
|
| 6 |
werkzeug==3.0.1
|
| 7 |
markupsafe==2.1.3
|
|
|
|
|
|
| 5 |
click==8.1.7
|
| 6 |
werkzeug==3.0.1
|
| 7 |
markupsafe==2.1.3
|
| 8 |
+
gunicorn
|