Skip to content

Commit

Permalink
Feat: Better Course Offering List (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
Reimirno authored Nov 30, 2023
1 parent 73c76f4 commit 53f0a38
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 16 deletions.
6 changes: 6 additions & 0 deletions server/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from sqlalchemy.ext.associationproxy import association_proxy

from server import app
from server.utils.date import parse_ISO8601

db = SQLAlchemy(app=app)

Expand Down Expand Up @@ -43,11 +44,16 @@ class Offering(db.Model):
canvas_id = db.Column(db.String(255), nullable=False, index=True, unique=True)
name = db.Column(db.String(255), nullable=False)
code = db.Column(db.String(255), nullable=False)
start_at = db.Column(db.String(255), nullable=False)

exams = db.relationship('Exam', uselist=True, cascade='all, delete-orphan',
order_by='Exam.display_name',
backref=backref('offering', uselist=False, single_parent=True))

@property
def start_at_date(self):
return parse_ISO8601(self.start_at)

def __repr__(self):
return '<Offering {}>'.format(self.name)

Expand Down
30 changes: 23 additions & 7 deletions server/services/canvas/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from canvasapi import Canvas
from canvasapi.user import User
from canvasapi.course import Course
from canvasapi.enrollment import Enrollment

from server import app
from server.models import Offering
Expand Down Expand Up @@ -38,7 +37,9 @@ def is_course_valid(c) -> bool:
return not (not c) and \
hasattr(c, 'id') and \
hasattr(c, 'name') and \
hasattr(c, 'course_code')
hasattr(c, 'course_code') and \
hasattr(c, 'start_at') and \
hasattr(c, 'start_at_date')


def get_user_courses_categorized(user: FakeUser | User) \
Expand All @@ -55,19 +56,34 @@ def get_user_courses_categorized(user: FakeUser | User) \
student_courses.add(c)
else:
other.add(c)

# a course should not appear in more than one category
student_courses -= set(staff_courses)
other = other - set(staff_courses) - set(student_courses)
# sorted by course name
staff_courses: list[FakeCourse | Course] = sorted(staff_courses, key=lambda c: c.name)
student_courses: list[FakeCourse | Course] = sorted(student_courses, key=lambda c: c.name)
other: list[FakeCourse | Course] = sorted(other, key=lambda c: c.name)

# convert to list because order matters
staff_courses: list[FakeCourse | Course] = list(staff_courses)
student_courses: list[FakeCourse | Course] = list(student_courses)
other: list[FakeCourse | Course] = list(other)

# sorted by start_at_date DESC and then by name ASC
def _sort_courses(courses: list[FakeCourse | Course]):
# Cannot do courses.sort(key=lambda c: (c.start_at_date, c.name))
# String or Datetime object cannot be negated to reverse the order
courses.sort(key=lambda c: c.name)
courses.sort(key=lambda c: c.start_at_date, reverse=True)

_sort_courses(staff_courses)
_sort_courses(student_courses)
_sort_courses(other)

return list(staff_courses), list(student_courses), list(other)


def api_course_to_model(course: Course | FakeCourse) -> Offering:
return Offering(
canvas_id=course.id,
name=course.name,
code=course.course_code
code=course.course_code,
start_at=course.start_at,
)
7 changes: 7 additions & 0 deletions server/services/canvas/fake_canvas.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from __future__ import annotations
from datetime import datetime

from server.services.canvas.fake_data import FAKE_USERS, FAKE_COURSES, FAKE_ENROLLMENTS


Expand Down Expand Up @@ -37,6 +39,11 @@ def __init__(self, canvas_id, enrollments=[]):
self.course_code = FAKE_COURSES[str(canvas_id)]['course_code']
self.sis_course_id = FAKE_COURSES[str(canvas_id)]['sis_course_id']
self.enrollments = enrollments
# canvasapi.course.Course.start_at is a n ISO8601 date string
# canvasapi.course.Course.start_at_date is a datetime.datetime object
# so, we do the same here
self.start_at = FAKE_COURSES[str(canvas_id)]['start_at']
self.start_at_date = datetime.strptime(self.start_at, '%Y-%m-%dT%H:%M:%SZ')

def get_users(self, *, enrollment_type) -> list[FakeUser]:
users = []
Expand Down
12 changes: 8 additions & 4 deletions server/services/canvas/fake_data/fake_courses.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,28 @@
"id": 1234567,
"name": "Introduction to Software Engineering (Fall 2023)",
"sis_course_id": "CRS:COMPSCI-169A-2023-D",
"course_code": "COMPSCI 169A"
"course_code": "COMPSCI 169A",
"start_at": "2023-08-16T07:00:00Z"
},
"2345678": {
"id": 2345678,
"name": "Introduction to the Internet: Architecture and Protocols (Fall 2022)",
"sis_course_id": "",
"course_code": "COMPSCI 168"
"course_code": "COMPSCI 168",
"start_at": "2022-08-16T07:00:00Z"
},
"3456789": {
"id": 3456789,
"name": "Introduction to Computer Security (Fall 2022)",
"sis_course_id": "",
"course_code": "COMPSCI 161"
"course_code": "COMPSCI 161",
"start_at": "2022-08-16T07:00:00Z"
},
"4567890": {
"id": 4567890,
"name": "Computer Architecture (Fall 2022)",
"sis_course_id": "",
"course_code": "COMPSCI 150"
"course_code": "COMPSCI 150",
"start_at": "2022-08-16T07:00:00Z"
}
}
5 changes: 4 additions & 1 deletion server/templates/select_offering.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<ul class="mdl-list">
{% for offering in staff_offerings %}
<li class="mdl-list__item">
<span style="margin-right: 10px; color: #424242; font-weight: bold;"><small>{{ offering.start_at_date.strftime('%Y-%m') }}</small></span>
<a class="mdl-list__item-primary-content" href="{{ url_for('offering', offering=offering) }}">
{{ offering.name }}
</a>
Expand All @@ -18,8 +19,9 @@
<ul class="mdl-list">
{% for offering in student_offerings %}
<li class="mdl-list__item">
<span style="margin-right: 10px; color: #424242; font-weight: bold;"><small>{{ offering.start_at_date.strftime('%Y-%m') }}</small></span>
<a class="mdl-list__item-primary-content" href="{{ url_for('offering', offering=offering) }}">
{{ offering.name }}
{{ offering.name }}
</a>
</li>
{% endfor %}
Expand All @@ -28,6 +30,7 @@
<ul class="mdl-list">
{% for offering in other_offerings %}
<li class="mdl-list__item">
<span style="margin-right: 10px; color: #424242; font-weight: bold;"><small>{{ offering.start_at_date.strftime('%Y-%m') }}</small></span>
{{ offering.name }}
</li>
{% endfor %}
Expand Down
Empty file added server/utils/__init__.py
Empty file.
12 changes: 12 additions & 0 deletions server/utils/date.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from datetime import datetime


def parse_ISO8601(s: str) -> datetime:
"""
Parse an ISO8601 date string and return a datetime.datetime object.
datetime.fromisoformat cannot properly parse ISO 8601 format until 3.11
so we use datetime.strptime instead
in 3.11 you can do: datetime.fromisoformat(s)
"""
return datetime.strptime(s, '%Y-%m-%dT%H:%M:%SZ')
12 changes: 8 additions & 4 deletions tests/fixtures/offering.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,29 @@
"id": 1,
"canvas_id": "1234567",
"name": "Introduction to Software Engineering (Fall 2023)",
"code": "COMPSCI 169A-LEC-001"
"code": "COMPSCI 169A-LEC-001",
"start_at": "2023-08-16T00:00:00Z"
},
{
"id": 2,
"canvas_id": "2345678",
"name": "Introduction to the Internet: Architecture and Protocols (Fall 2022)",
"code": "COMPSCI 168-LEC-001"
"code": "COMPSCI 168-LEC-001",
"start_at": "2022-08-16T00:00:00Z"
},
{
"id": 3,
"canvas_id": "3456789",
"name": "Introduction to Computer Security (Fall 2022)",
"code": "COMPSCI 161-LEC-001"
"code": "COMPSCI 161-LEC-001",
"start_at": "2022-08-16T00:00:00Z"
},
{
"id": 4,
"canvas_id": "4567890",
"name": "Computer Architecture (Fall 2022)",
"code": "COMPSCI 150-LEC-001"
"code": "COMPSCI 150-LEC-001",
"start_at": "2022-08-16T00:00:00Z"
}
]
}
Expand Down

0 comments on commit 53f0a38

Please sign in to comment.