diff --git a/schoolapps/static/common/style.css b/schoolapps/static/common/style.css index a15ef98eb96f0be5f195f8dbadd51d8ca1796de2..dbdab4f2daebfbd971da75ca4db736115cf3d952 100755 --- a/schoolapps/static/common/style.css +++ b/schoolapps/static/common/style.css @@ -131,6 +131,7 @@ span.badge.new::after { } .lesson-card .card-content div { + padding: 5px; height: 100%; width: 100%; display: flex; @@ -148,6 +149,15 @@ table.substitutions td, table.substitutions th { padding: 10px 5px; } +.lesson-with-sub { + border: 3px solid red; + border-radius: 3px; +} + +.lesson-with-sub .badge { + margin: 0; +} + /*.timetable-time {*/ /*margin-right: 20px;*/ /*}*/ diff --git a/schoolapps/timetable/templates/timetable/plan.html b/schoolapps/timetable/templates/timetable/plan.html index 998e3369d22247e2b5bc18b04cfe7ab1aa89bc02..50acca0b450bc0e68311c08cfda058905d016db6 100755 --- a/schoolapps/timetable/templates/timetable/plan.html +++ b/schoolapps/timetable/templates/timetable/plan.html @@ -134,21 +134,56 @@ <div class="card lesson-card"> <div class="card-content"> {% for element_container in col.elements %} - <div style="background-color: {{ element_container.element.subject.hex_color }};"> + <div style=" + {% if not element_container.substitution.table.badge %} + {% if not element_container.is_old or type != 1 %} + background-color: {{ element_container.element.subject.hex_color }}; + {% endif %} + {% endif %}" + class="{% if element_container.substitution %}lesson-with-sub{% endif %}"> <p> - {% if type == 0 or type == 1 %} - {% for class in element_container.element.classes %} - {{ class.name }} - {% endfor %} - {% endif %} - {% if type == 2 or type == 1 %} - <span data-position="bottom" class="tooltipped" - data-tooltip="{{ element_container.element.teacher }}">{{ element_container.element.teacher.shortcode }}</span> - {% endif %} - <strong>{{ element_container.element.subject.shortcode }}</strong> - {% if type == 0 or type == 2 %} - <span class="tooltipped" data-position="bottom" - data-tooltip="{{ element_container.room.name }}">{{ element_container.room.shortcode }}</span> + {% if element_container.substitution %} + {% if type == 1 and element_container.is_old %} + + {% elif element_container.substitution.table.badge %} + <span class="badge new green darken-2">{{ element_container.substitution.table.badge }}</span> + {% else %} + {% if type == 0 or type == 1 %} + {{ element_container.substitution.table.classes }} + {% endif %} + + <span class="tooltipped" data-position="bottom" + data-tooltip="{{ element_container.substitution.table.teacher_full|safe }}">{{ element_container.substitution.table.teacher|safe }}</span> + + + {{ element_container.substitution.table.subject|safe }} + + {% if type == 0 or type == 2 %} + <span class="tooltipped" data-position="bottom" + data-tooltip="{{ element_container.substitution.table.room_full|safe }}">{{ element_container.substitution.table.room|safe }}</span> + {% endif %} + {% endif %}<br> + {% if not type == 1 and not element_container.is_old %} + + <small> + <em>{{ element_container.substitution.table.text|default:"" }}</em> + </small> + {% endif %} + {% else %} + {% if type == 0 or type == 1 %} + {% for class in element_container.element.classes %} + {{ class.name }} + {% endfor %} + {% endif %} + {% if type == 2 or type == 1 %} + <span data-position="bottom" class="tooltipped" + data-tooltip="{{ element_container.element.teacher }}">{{ element_container.element.teacher.shortcode }}</span> + {% endif %} + <strong>{{ element_container.element.subject.shortcode }}</strong> + {% if type == 0 or type == 2 %} + <span class="tooltipped" data-position="bottom" + data-tooltip="{{ element_container.room.name }}">{{ element_container.room.shortcode }}</span> + {% endif %} {% endif %} </p> </div> diff --git a/schoolapps/timetable/views.py b/schoolapps/timetable/views.py index 3b6be7f1f2ab173c35bb6d8742c5ad7e6e9d1d33..87a63b78157e2b851d43c9ebb6e1c91b5d0467b9 100755 --- a/schoolapps/timetable/views.py +++ b/schoolapps/timetable/views.py @@ -7,15 +7,10 @@ from django.shortcuts import render from django.utils import timezone from timetable.pdf import generate_class_tex, generate_pdf -from schoolapps.settings import LESSONS -from untisconnect.parse import * -from untisconnect.sub import get_substitutions_by_date, date_to_untis_date, untis_date_to_date, generate_sub_table - -try: - from schoolapps.untisconnect.api import * -except Exception: - pass +from untisconnect.plan import get_plan, TYPE_TEACHER, TYPE_CLASS, TYPE_ROOM, parse_lesson_times +from untisconnect.sub import get_substitutions_by_date, generate_sub_table +from untisconnect.api import * def get_all_context(): @@ -46,11 +41,11 @@ def quicklaunch(request): return render(request, 'timetable/quicklaunch.html', context) -def get_calendar_weeks(): +def get_calendar_weeks(year=timezone.datetime.now().year): weeks = [] # Get first day of year > first calendar week - first_day_of_year = timezone.datetime(year=timezone.datetime.now().year, month=1, day=1) + first_day_of_year = timezone.datetime(year=year, month=1, day=1) if first_day_of_year.isoweekday() != 1: days_to_next_monday = 1 - first_day_of_year.isoweekday() first_day_of_year += datetime.timedelta(days=days_to_next_monday) @@ -70,17 +65,26 @@ def get_calendar_weeks(): return weeks +def get_calendar_week(calendar_week, year=timezone.datetime.now().year): + weeks = get_calendar_weeks(year=year) + for week in weeks: + if week["calendar_week"] == calendar_week: + return week + return None + + @login_required @permission_required("timetable.show_plan") -def plan(request, plan_type, plan_id, smart="", year=None, calendar_week=None): +def plan(request, plan_type, plan_id, smart="", year=timezone.datetime.now().year, + calendar_week=timezone.datetime.now().isocalendar()[1]): if smart == "smart": smart = True - year = timezone.datetime.now().year if year is None else year - calendar_week = timezone.datetime.now().isocalendar()[1] if calendar_week is None else calendar_week - print(get_calendar_weeks()) else: smart = False + monday_of_week = get_calendar_week(calendar_week, year)["first_day"] + print(monday_of_week) + if plan_type == 'teacher': _type = TYPE_TEACHER el = get_teacher_by_id(plan_id) @@ -93,8 +97,8 @@ def plan(request, plan_type, plan_id, smart="", year=None, calendar_week=None): else: raise Http404('Plan not found.') - plan = get_plan(_type, plan_id) - print(parse_lesson_times()) + plan = get_plan(_type, plan_id, smart=smart, monday_of_week=monday_of_week) + # print(parse_lesson_times()) context = { "smart": smart, @@ -104,7 +108,7 @@ def plan(request, plan_type, plan_id, smart="", year=None, calendar_week=None): "plan": plan, "el": el, "times": parse_lesson_times(), - "weeks": get_calendar_weeks(), + "weeks": get_calendar_weeks(year=year), "selected_week": calendar_week, "selected_year": year } diff --git a/schoolapps/untisconnect/parse.py b/schoolapps/untisconnect/parse.py index ba0f7fa495770ca65e27229e39c446d40c418eb4..95cceae8cd514e4cdc7468b94c28132e4d0d608c 100755 --- a/schoolapps/untisconnect/parse.py +++ b/schoolapps/untisconnect/parse.py @@ -1,9 +1,3 @@ -from django.conf import settings -from django.utils import timezone - -from schoolapps.settings import LESSONS - - class Lesson(object): def __init__(self): self.filled = False @@ -26,6 +20,7 @@ class Lesson(object): # Split data (,) lesson_id = raw_lesson.lesson_id + self.id = lesson_id raw_lesson_data = raw_lesson.lessonelement1.split(",") raw_time_data = raw_lesson.lesson_tt.split(",") @@ -80,9 +75,9 @@ class Lesson(object): # r = drive["rooms"][room_id] # rooms.append(r) rooms = [] - for room in rooms: - print(room) - print("--") + # for room in rooms: + # print(room) + # print("--") classes = [] for class_id in class_ids: @@ -146,7 +141,7 @@ def build_drive(): id = el.id drive[key][id] = el - print(drive) + # print(drive) return drive @@ -174,40 +169,6 @@ def parse(): return lessons -TYPE_TEACHER = 0 -TYPE_ROOM = 1 -TYPE_CLASS = 2 - - -class LessonContainer(object): - """ - Needed for Django template because template language does not support dictionaries - Saves the time object and the lesson elements - """ - - def __init__(self, ): - self.time = None - self.elements = [] - - def set_time(self, time): - self.time = time - - def append(self, element): - self.elements.append(element) - - -class LessonElementContainer(object): - """ - Needed for Django template because template language does not support dictionaries - Saves the lesson element object and the room (from time object) - """ - - def __init__(self, element, room, substitution=None): - self.element = element - self.room = room - self.substitution = substitution - - def get_lesson_by_id(id): global drive lesson = Lesson() @@ -217,29 +178,29 @@ def get_lesson_by_id(id): def get_lesson_element_by_id_and_teacher(lesson_id, teacher, hour=None, weekday=None): - print(lesson_id) - print(hour, "LEWE", weekday) + # print(lesson_id) + #print(hour, "LEWE", weekday) try: lesson = get_lesson_by_id(lesson_id) except Exception: return None, None el = None i = 0 - print(lesson.elements) + #print(lesson.elements) for i, element in enumerate(lesson.elements): - print(element.teacher.shortcode) + #print(element.teacher.shortcode) if element.teacher.id == teacher.id: el = element break t = None - print(lesson.times) - print(weekday) - print(hour) + # print(lesson.times) + # print(weekday) + #print(hour) for time in lesson.times: - print("DAY", time.day, time.hour) + #print("DAY", time.day, time.hour) if time.day == weekday and time.hour == hour: t = time - print(t) + #print(t) room = None if t is not None: room = t.rooms[i] @@ -247,100 +208,3 @@ def get_lesson_element_by_id_and_teacher(lesson_id, teacher, hour=None, weekday= if el is not None: return el, room return None, None - - -def parse_lesson_times(): - times = [] - for i, t in enumerate(LESSONS): - start_split = t[0].split(":") - start_time = timezone.datetime(year=2000, day=1, month=1, hour=int(start_split[0]), minute=int(start_split[1])) - end_time = start_time + timezone.timedelta(minutes=45) - print(start_time) - print(end_time) - times.append({ - "number": i + 1, - "number_format": t[1], - "start": start_time, - "end": end_time, - }) - return times - - -def get_plan(type, id): - """ Generates a plan for type (TYPE_TEACHE, TYPE_CLASS, TYPE_ROOM) and a id of the teacher (class, room)""" - - # Get parsed lessons - lessons = parse() - times_parsed = parse_lesson_times() - - # Init plan array - plan = [] - - # Fill plan array with LessonContainers (show upside), WIDTH and HEIGHT are defined by Django settings - for hour_idx in range(settings.TIMETABLE_HEIGHT): - plan.append(([], times_parsed[hour_idx] if len(times_parsed) > hour_idx else None)) - for day_idx in range(settings.TIMETABLE_WIDTH): - plan[hour_idx][0].append(LessonContainer()) - - # Fill plan with lessons - for lesson in lessons: - for i, element in enumerate(lesson.elements): - - # Check if the lesson element is important for that plan (look by type and id) - found = False - if type == TYPE_CLASS: - for lclass in element.classes: - if lclass.id == id: - found = True - - elif type == TYPE_TEACHER: - if element.teacher: - if element.teacher.id == id: - found = True - - elif type == TYPE_ROOM: - for time in lesson.times: - for j, lroom in enumerate(time.rooms): - if lroom.id == id: - print(lroom.name) - found = True - - # If the lesson element is important then add it to plan array - if found: - for time in lesson.times: # Go for every time the lesson is thought - # print(time.hour, " ", time.day) - # print(element.subject.shortcode) - room_index = None - for j, lroom in enumerate(time.rooms): - if lroom.id == id: - room_index = j - - # Add the time object to the matching LessonContainer on the right position in the plan array - plan[time.hour - 1][0][time.day - 1].set_time(time) - - # Check if there is an room for this time and lesson - try: - room = time.rooms[i] - except IndexError: - room = None - - # print(element) - # print(room.name) - - # Create a LessonElementContainer with room and lesson element - element_container = LessonElementContainer(element, room) - - if type != TYPE_ROOM or i == room_index: - # Add this container object to the LessonContainer object in the plan array - plan[time.hour - 1][0][time.day - 1].append(element_container) - - # print(plan) - # - # for hour in plan: - # for day in hour: - # print(day.elements) - # for c in day.elements: - # # print(c.element) - # pass - - return plan diff --git a/schoolapps/untisconnect/plan.py b/schoolapps/untisconnect/plan.py new file mode 100644 index 0000000000000000000000000000000000000000..ef54bc66fa2c5862d4f8844f00d9fad5ccf69a73 --- /dev/null +++ b/schoolapps/untisconnect/plan.py @@ -0,0 +1,220 @@ +import datetime + +from django.utils import timezone + +from schoolapps import settings +from schoolapps.settings import LESSONS +from untisconnect.parse import parse +from untisconnect.sub import get_substitutions_by_date_as_dict, TYPE_CANCELLATION + +TYPE_TEACHER = 0 +TYPE_ROOM = 1 +TYPE_CLASS = 2 + + +class LessonContainer(object): + """ + Needed for Django template because template language does not support dictionaries + Saves the time object and the lesson elements + """ + + def __init__(self, ): + self.time = None + self.elements = [] + + def set_time(self, time): + self.time = time + + def append(self, element): + self.elements.append(element) + + +class LessonElementContainer(object): + """ + Needed for Django template because template language does not support dictionaries + Saves the lesson element object and the room (from time object) + """ + + def __init__(self, element, room, substitution=None): + self.element = element + self.room = room + self.substitution = substitution + self.is_old = False + + +def parse_lesson_times(): + times = [] + for i, t in enumerate(LESSONS): + start_split = t[0].split(":") + start_time = timezone.datetime(year=2000, day=1, month=1, hour=int(start_split[0]), minute=int(start_split[1])) + end_time = start_time + timezone.timedelta(minutes=45) + # print(start_time) + # print(end_time) + times.append({ + "number": i + 1, + "number_format": t[1], + "start": start_time, + "end": end_time, + }) + return times + + +def get_plan(type, id, smart=False, monday_of_week=None): + """ Generates a plan for type (TYPE_TEACHE, TYPE_CLASS, TYPE_ROOM) and a id of the teacher (class, room)""" + + # Get parsed lessons + lessons = parse() + times_parsed = parse_lesson_times() + + if smart: + print("Get substitutions for smart plan") + week_days = [monday_of_week + datetime.timedelta(days=i) for i in range(5)] + print(week_days) + subs_for_weekday = [] + for week_day in week_days: + print(week_day) + subs = get_substitutions_by_date_as_dict(week_day) + subs_for_weekday.append(subs) + print(subs) + print(len(subs)) + # Init plan array + plan = [] + already_added_subs_as_ids = [] + + # Fill plan array with LessonContainers (show upside), WIDTH and HEIGHT are defined by Django settings + for hour_idx in range(settings.TIMETABLE_HEIGHT): + plan.append(([], times_parsed[hour_idx] if len(times_parsed) > hour_idx else None)) + for day_idx in range(settings.TIMETABLE_WIDTH): + plan[hour_idx][0].append(LessonContainer()) + + # Fill plan with lessons + for lesson in lessons: + for i, element in enumerate(lesson.elements): + + # Check if the lesson element is important for that plan (look by type and id) + found = False + if type == TYPE_CLASS: + for lclass in element.classes: + if lclass.id == id: + found = True + + elif type == TYPE_TEACHER: + if element.teacher: + if element.teacher.id == id: + found = True + + elif type == TYPE_ROOM: + for time in lesson.times: + for j, lroom in enumerate(time.rooms): + if lroom.id == id: + print(lroom.name) + found = True + + # If the lesson element is important then add it to plan array + if found: + for time in lesson.times: # Go for every time the lesson is thought + # print(time.hour, " ", time.day) + # print(element.subject.shortcode) + room_index = None + for j, lroom in enumerate(time.rooms): + if lroom.id == id: + room_index = j + + # Add the time object to the matching LessonContainer on the right position in the plan array + plan[time.hour - 1][0][time.day - 1].set_time(time) + + # Check if there is an room for this time and lesson + try: + room = time.rooms[i] + except IndexError: + room = None + + # print(element) + # print(room.name) + matching_sub = None + + if smart: + current_weekday = week_days[time.day - 1] + current_lesson = time.hour + print(current_weekday, current_lesson) + print(lesson.id) + if subs_for_weekday[time.day - 1].get(lesson.id, None) is not None: + for sub in subs_for_weekday[time.day - 1][lesson.id]: + # sub = subs_for_weekday[time.day - 1][lesson.id] + if sub["sub"].teacher_old.id == element.teacher.id: + matching_sub = sub + # print(sub.keys()) + # print(sub["sub"].type) + + print("SUB") + + if matching_sub: + already_added_subs_as_ids.append(matching_sub["sub"].id) + + # Create a LessonElementContainer with room and lesson element + element_container = LessonElementContainer(element, room, substitution=matching_sub) + if smart and matching_sub is not None: + print(matching_sub["sub"].teacher_old.name) + print(matching_sub["sub"].room_old) + print(matching_sub["sub"].room_new) + if matching_sub["sub"].room_new is not None: + if matching_sub["sub"].room_old is not None: + if matching_sub["sub"].room_old != matching_sub["sub"].room_new: + element_container.is_old = True + else: + element_container.is_old = True + if matching_sub["sub"].type == TYPE_CANCELLATION: + element_container.is_old = True + print(element_container.is_old) + + if type != TYPE_ROOM or i == room_index: + # Add this container object to the LessonContainer object in the plan array + plan[time.hour - 1][0][time.day - 1].append(element_container) + + if smart: + for i, week_day in enumerate(week_days): + print(i, week_day) + subs_for_this_weekday = subs_for_weekday[i] + for lesson_id, subs in subs_for_this_weekday.items(): + for sub in subs: + print(sub["sub"].id) + # print(sub) + # print(sub["sub"].room_new) + found = False + room = sub["sub"].room_old + if type == TYPE_CLASS: + if sub["sub"].classes: + for _class in sub["sub"].classes: + # print(_class) + if _class.id == id: + # print("Hi") + found = True + elif type == TYPE_TEACHER: + if sub["sub"].teacher_new: + if sub["sub"].teacher_new.id == id: + found = True + + elif type == TYPE_ROOM: + if sub["sub"].room_new: + if sub["sub"].room_new.id == id: + found = True + if found: + element_container = LessonElementContainer(sub["sub"].lesson_element, room, substitution=sub) + if sub["sub"].id not in already_added_subs_as_ids: + # if len(plan[sub["sub"].lesson - 1][0][i]) > 0: + # for elc in plan[sub["sub"].lesson - 1][0][i]: + # if elc.substitution is not None: + # if elc.substitution.id == elc.substitutio + plan[sub["sub"].lesson - 1][0][i].append(element_container) + # print(plan[sub["sub"].lesson - 1][0][i].elements) + # print(len(plan[sub["sub"].lesson - 1][0][i].elements)) + # print(plan) + # + # for hour in plan: + # for day in hour: + # print(day.elements) + # for c in day.elements: + # # print(c.element) + # pass + + return plan diff --git a/schoolapps/untisconnect/sub.py b/schoolapps/untisconnect/sub.py index cb195b93b04a49db57db96f0185d254ac7bb3eb9..f53ca05ae761d1887a0b222f03234286baf36dc5 100644 --- a/schoolapps/untisconnect/sub.py +++ b/schoolapps/untisconnect/sub.py @@ -1,10 +1,9 @@ from django.utils import timezone from untisconnect import models -from untisconnect.api import run_default_filter, row_by_row_helper, get_teacher_by_id, get_subject_by_id, \ - get_room_by_id, get_class_by_id, get_corridor_by_id +from untisconnect.api import run_default_filter, row_by_row_helper from untisconnect.api_helper import run_using, untis_split_first -from untisconnect.parse import get_lesson_by_id, get_lesson_element_by_id_and_teacher, build_drive +from untisconnect.parse import get_lesson_element_by_id_and_teacher, build_drive DATE_FORMAT = "%Y%m%d" @@ -85,7 +84,7 @@ class Substitution(object): self.lesson_element, self.room_old = get_lesson_element_by_id_and_teacher(self.lesson_id, self.teacher_old, self.lesson, self.date.weekday() + 1) # print(self.lesson) - print(self.room_old) + # print(self.room_old) # Subject self.subject_old = self.lesson_element.subject if self.lesson_element is not None else None if db_obj.subject_idsubst != 0: @@ -117,10 +116,10 @@ class Substitution(object): self.classes = [] class_ids = untis_split_first(db_obj.classids, conv=int) - print(class_ids) + # print(class_ids) for id in class_ids: self.classes.append(drive["classes"][id]) - print(self.classes) + # print(self.classes) def substitutions_sorter(sub): @@ -264,3 +263,19 @@ def get_substitutions_by_date(date): # print(class_.name) subs.sort(key=substitutions_sorter) return subs + + +def get_substitutions_by_date_as_dict(date): + subs_raw = get_substitutions_by_date(date) + sub_table = generate_sub_table(subs_raw) + print("SUB RAW LEN", len(sub_table)) + subs = {} + for i, sub_raw in enumerate(subs_raw): + print(i) + if sub_raw.lesson_id not in subs.keys(): + subs[sub_raw.lesson_id] = [] + subs[sub_raw.lesson_id].append({"sub": sub_raw, "table": sub_table[i]}) + # print(sub_raw.teacher_old) + # print(sub_table[i].teacher) + print(len(subs)) + return subs