roster.py
1 |
|
2 |
building of the roster. """ |
3 |
from django.shortcuts import render |
4 |
from collections import OrderedDict |
5 |
import datetime |
6 |
from django.urls import reverse # Why? |
7 |
from django.utils.translation import gettext as _ |
8 |
from .models import * |
9 |
import administration |
10 |
|
11 |
def same_day(datetime_a, datetime_b): |
12 |
"""True if both a and b are on the same day, false otherwise.""" |
13 |
return ( |
14 |
datetime_a.day == datetime_b.day and |
15 |
datetime_a.month == datetime_b.month and |
16 |
datetime_a.year == datetime_b.year) |
17 |
|
18 |
|
19 |
def make_quarter_buckets(events): |
20 |
"""Returns a dict with all days that the given events take place. |
21 |
Every quarter between the first and last event will get a bucket in the dict, |
22 |
with the keys in format "dd-mm-yyyy". Also quarters without events will be |
23 |
included, but will simply have empty buckets.""" |
24 |
quarters = OrderedDict() # This is the first time I ever use an OrderedDict and I intend it to be my last one as well. |
25 |
current_quarter = datetime.datetime.now().replace(hour=8, minute=0) |
26 |
while current_quarter.hour != 20 or current_quarter.minute != 00: |
27 |
quarters[current_quarter.strftime("%H:%M")] = list() |
28 |
current_quarter += datetime.timedelta(minutes=15) |
29 |
for event in events: |
30 |
quarters[event.begin_time.strftime("%H:%M")].append(event) |
31 |
|
32 |
return quarters # Yay! ^.^ |
33 |
|
34 |
|
35 |
def create_roster_rows(events): |
36 |
"""Creates the rows for use in the roster table. |
37 |
None of the times in the given events may overlap, and all must start and |
38 |
end at a quarter of the hour (so :00, :15, :30, or :45). If you think you're above this, |
39 |
I'll raise you a ValueError, kind sir. |
40 |
Events must be of administration.models.Event type.""" |
41 |
if len(events) == 0: |
42 |
return [] |
43 |
|
44 |
for event in events: |
45 |
for other_event in events: |
46 |
if other_event is not event and ( |
47 |
(event.begin_time >= other_event.begin_time and event.begin_time < other_event.end_time) |
48 |
or (event.end_time > other_event.begin_time and event.end_time <= other_event.end_time) |
49 |
): |
50 |
raise ValueError("One of the events overlaps with another event.") |
51 |
if event.begin_time.minute not in [0, 15, 30, 45] or event.end_time.minute not in [0, 15, 30, 45]: |
52 |
raise ValueError("One of the events did not begin or end on a quarter.") |
53 |
|
54 |
# XXX: I assume here the given queryset is sorted: |
55 |
first_day = events[0].begin_time |
56 |
last_day = events.last().begin_time |
57 |
# All events validated |
58 |
quarter_buckets = make_quarter_buckets(events) |
59 |
skip_row = dict() |
60 |
table_code = list() |
61 |
|
62 |
for quarter_bucket in quarter_buckets.keys(): |
63 |
# Preparing time column |
64 |
quarter_line = "<tr><td style='font-size: xx-small;'>" |
65 |
if quarter_bucket[3:] == "00": |
66 |
quarter_line += quarter_bucket |
67 |
quarter_line += "</td>" |
68 |
|
69 |
current_day = first_day |
70 |
while not same_day(current_day, last_day+datetime.timedelta(days=1)): |
71 |
for event in quarter_buckets[quarter_bucket]: |
72 |
if same_day(current_day, event.begin_time): |
73 |
quarters = (event.end_time - event.begin_time).seconds // 60 // 15 |
74 |
skip_row[quarter_bucket] = quarters |
75 |
event_line = "<td " |
76 |
if isinstance(event, CourseEvent) and (datetime.datetime.now(datetime.timezone.utc) - event.last_update).days > 1: |
77 |
event_line += "style='background-color: #"+event.course.course.color+"; color: white;' " |
78 |
elif (datetime.datetime.now(datetime.timezone.utc) - event.created).days <= 5 and (event.last_update - event.created).days < 1: |
79 |
event_line += "class='event-new' " |
80 |
elif (datetime.datetime.now(datetime.timezone.utc) - event.last_update).days <= 5: |
81 |
event_line += "class='event-update' " |
82 |
if event.note: |
83 |
event_line +="class='event-note' title='" +event.note+ "' " |
84 |
|
85 |
# FIXME: From here, I just assume the events are all CourseEvents, because |
86 |
# that is the most important one to implement for the prototype. |
87 |
if quarters > 1: |
88 |
event_line += "rowspan='"+str(quarters)+"' " |
89 |
|
90 |
event_line +=">" |
91 |
event_line += str( |
92 |
#"<a href=" + reverse("courses-course-index", args="")+"> " # FIXME so that this links to the course's index page |
93 |
#"<a href=""> " |
94 |
str(event.course.course.name) |
95 |
#+ str(event.course.course.name) |
96 |
+ "<br />" |
97 |
+ str(event.docent) |
98 |
+ "<br />" |
99 |
+ event.begin_time.strftime("%H:%M") + " - " + event.end_time.strftime("%H:%M") |
100 |
+ "<br />" |
101 |
#+ str(event.room) + " (" + str(event.subject) + ")</a></td>") |
102 |
+ str(event.room) + " (" + str(event.subject) + ")</td>") |
103 |
quarter_line += event_line |
104 |
else: |
105 |
"""if quarter_bucket in skip_row: |
106 |
skip_row[quarter_bucket] -= 1 |
107 |
if skip_row[quarter_bucket] == 0: |
108 |
del skip_row[quarter_bucket] |
109 |
quarter_line += "<td></td>" |
110 |
else: |
111 |
quarter_line += "<td></td>""" |
112 |
pass |
113 |
current_day += datetime.timedelta(days=1) |
114 |
quarter_line += "</tr>" |
115 |
table_code.append(quarter_line) |
116 |
return table_code |
117 |