<commit_before>import datetime
import json

import redis
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q

from roombookings.models import (
    Lock as RBLock,
    BookingA,
    BookingB
)

from .models import (DeptsA, DeptsB, LecturerA, LecturerB, Lock, ModuleA,
                     ModuleB, RoomsA, RoomsB, SitesA, SitesB, StudentsA,
                     StudentsB, Stumodules, TimetableA, TimetableB,
                     WeekmapnumericA, WeekmapnumericB, WeekstructureA,
                     WeekstructureB)
from .tasks import cache_student_timetable

_SETID = settings.ROOMBOOKINGS_SETID

_week_map = {}
_week_num_date_map = {}

_session_type_map = {
    "EX": "Examination",
    "L": "Lecture",
    "P": "Practical",
    "PBL": "Problem Based Learning",
}

_rooms_cache = {}

_department_name_cache = {}


def _get_cache(model_name):
    """Returns the cache bucket for the requested model name"""
    timetable_models = {
        "module": [ModuleA, ModuleB],
        "students": [StudentsA, StudentsB],
        "timetable": [TimetableA, TimetableB],
        "weekmapnumeric": [WeekmapnumericA, WeekmapnumericB],
        "weekstructure": [WeekstructureA, WeekstructureB],
        "lecturer": [LecturerA, LecturerB],
        "rooms": [RoomsA, RoomsB],
        "sites": [SitesA, SitesB],
        "departments": [DeptsA, DeptsB]
    }
    roombookings_models = {
        "booking": [BookingA, BookingB]
    }
    if model_name in timetable_models:
        timetable_lock = Lock.objects.all()[0]
        if timetable_lock.a:
            model = timetable_models[model_name][0]
        else:
            model = timetable_models[model_name][1]
    elif model_name in roombookings_models:
        roombooking_lock = RBLock.objects.all()[0]
        if roombooking_lock.bookingA:
            model = roombookings_models[model_name][0]
        else:
            model = roombookings_models[model_name][1]
    else:
        raise Exception("Unknown model requested from cache")

    return model


def _get_student_by_upi(upi):
    """Returns a StudentA or StudentB object by UPI"""
    students = _get_cache("students")
    # Assume the current Set ID due to caching
    upi_upper = upi.upper()
    student = students.objects.filter(
        qtype2=upi_upper
    )[0]
    return student


def _get_student_modules(student):
    """Returns all Stumodules object by for a given student"""
    raw_query = 'SELECT * FROM CMIS_OWNER.STUMODULES WHERE SETID=\'LIVE-17-18\' AND studentid=\'{}\''.format(  # NOQA
        student.studentid
    )
    student_modules = list(Stumodules.objects.raw(raw_query))
    return student_modules


def _get_full_department_name(department_code):
    """Converts a department code, such as COMPS_ENG, into a full name
    such as Computer Science"""
    if department_code in _department_name_cache:
        return _department_name_cache[department_code]
    else:
        departments = _get_cache("departments")
        try:
            dept = departments.objects.get(deptid=department_code)
            _department_name_cache[department_code] = dept.name
            return dept.name
        except ObjectDoesNotExist:
            return "Unknown"


def _get_lecturer_details(lecturer_upi):
    """Returns a lecturer's name and email address from their UPI"""
    lecturers = _get_cache("lecturer")
    details = {
        "name": "Unknown",
        "email": "Unknown",
        "department_id": "Unknown",
        "department_name": "Unknown"
    }
    try:
        lecturer = lecturers.objects.get(lecturerid=lecturer_upi)
    except ObjectDoesNotExist:
        pass

    details["name"] = lecturer.name
    details["email"] = lecturer.linkcode + "@<EMAIL>"

    if lecturer.owner:
        details["department_id"] = lecturer.owner
        details["department_name"] = _get_full_department_name(lecturer.owner)

    return details


def _get_timetable_events(full_modules, stumodules):
    """
    Gets a dictionary of timetabled events.
    If stumodules=True then assume full_modules = [Stumodules]
    If stumodules=False then assume full_modules [ModuleA] or [ModuleB]
    """
    if not _week_map:
        _map_weeks()

    timetable = _get_cache("timetable")
    modules = _get_cache("module")

    bookings = _get_cache("booking")

    full_timetable = {}
    for module in full_modules:
        if stumodules:
            # Get events for the lab group assigned
            # Also include general lecture events (via the or operator)
            events_data = timetable.objects.filter(
                Q(modgrpcode=module.modgrpcode) | Q(modgrpcode=''),
                moduleid=module.moduleid
            )
            module_data = modules.objects.get(moduleid=module.moduleid)
        else:
            events_data = timetable.objects.filter(
                moduleid=module.moduleid
            )
            module_data = module
        for event in events_data:
            event_bookings = bookings.objects.filter(slotid=event.slotid)
            if len(event_bookings) == 0:
                # We have to trust the data in the event because
                # no rooms are booked for some weird reason.
                for date in _get_real_dates(event):
                    event_data = {
                        "start_time": event.starttime,
                        "end_time": event.finishtime,
                        "duration": event.duration,
                        "module": {
                            "module_id": module_data.moduleid,
                            "department_id": event.owner,
                            "department_name": _get_full_department_name(
                                event.owner
                            ),
                            "name": module_data.name
                        },
                        "location": _get_location_details(
                            event.siteid,
                            event.roomid
                        ),
                        "session_title": module_data.name,
                        "session_type": event.moduletype,
                        "session_type_str": _get_session_type_str(
                            event.moduletype
                        ),
                        "contact": "Unknown"
                    }

                    # If this is student module data, add in the group code
                    # because we have that field in Stumodules
                    if stumodules:
                        event_data["session_group"] = event.modgrpcode
                        if module.modgrpcode != '':
                            event_data["session_title"] = "{} ({})".format(
                                module_data.name,
                                module_data.modgrpcode
                            )

                    # Check if the module timetable event's Lecturer ID
                    # exists. If not, we use the Lecturer ID associated
                    # with the module as a whole. It's an ugly hack, but
                    # it works around not all timetabled lectures having
                    # the Lecturer ID field filled as they should.
                    # We assume therefore that if the lecturer isn't<commit_msg>Fixes a 500 because of a derp<commit_after>import datetime
import json

import redis
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q

from roombookings.models import (
    Lock as RBLock,
    BookingA,
    BookingB
)

from .models import (DeptsA, DeptsB, LecturerA, LecturerB, Lock, ModuleA,
                     ModuleB, RoomsA, RoomsB, SitesA, SitesB, StudentsA,
                     StudentsB, Stumodules, TimetableA, TimetableB,
                     WeekmapnumericA, WeekmapnumericB, WeekstructureA,
                     WeekstructureB)
from .tasks import cache_student_timetable

_SETID = settings.ROOMBOOKINGS_SETID

_week_map = {}
_week_num_date_map = {}

_session_type_map = {
    "EX": "Examination",
    "L": "Lecture",
    "P": "Practical",
    "PBL": "Problem Based Learning",
}

_rooms_cache = {}

_department_name_cache = {}


def _get_cache(model_name):
    """Returns the cache bucket for the requested model name"""
    timetable_models = {
        "module": [ModuleA, ModuleB],
        "students": [StudentsA, StudentsB],
        "timetable": [TimetableA, TimetableB],
        "weekmapnumeric": [WeekmapnumericA, WeekmapnumericB],
        "weekstructure": [WeekstructureA, WeekstructureB],
        "lecturer": [LecturerA, LecturerB],
        "rooms": [RoomsA, RoomsB],
        "sites": [SitesA, SitesB],
        "departments": [DeptsA, DeptsB]
    }
    roombookings_models = {
        "booking": [BookingA, BookingB]
    }
    if model_name in timetable_models:
        timetable_lock = Lock.objects.all()[0]
        if timetable_lock.a:
            model = timetable_models[model_name][0]
        else:
            model = timetable_models[model_name][1]
    elif model_name in roombookings_models:
        roombooking_lock = RBLock.objects.all()[0]
        if roombooking_lock.bookingA:
            model = roombookings_models[model_name][0]
        else:
            model = roombookings_models[model_name][1]
    else:
        raise Exception("Unknown model requested from cache")

    return model


def _get_student_by_upi(upi):
    """Returns a StudentA or StudentB object by UPI"""
    students = _get_cache("students")
    # Assume the current Set ID due to caching
    upi_upper = upi.upper()
    student = students.objects.filter(
        qtype2=upi_upper
    )[0]
    return student


def _get_student_modules(student):
    """Returns all Stumodules object by for a given student"""
    raw_query = 'SELECT * FROM CMIS_OWNER.STUMODULES WHERE SETID=\'LIVE-17-18\' AND studentid=\'{}\''.format(  # NOQA
        student.studentid
    )
    student_modules = list(Stumodules.objects.raw(raw_query))
    return student_modules


def _get_full_department_name(department_code):
    """Converts a department code, such as COMPS_ENG, into a full name
    such as Computer Science"""
    if department_code in _department_name_cache:
        return _department_name_cache[department_code]
    else:
        departments = _get_cache("departments")
        try:
            dept = departments.objects.get(deptid=department_code)
            _department_name_cache[department_code] = dept.name
            return dept.name
        except ObjectDoesNotExist:
            return "Unknown"


def _get_lecturer_details(lecturer_upi):
    """Returns a lecturer's name and email address from their UPI"""
    lecturers = _get_cache("lecturer")
    details = {
        "name": "Unknown",
        "email": "Unknown",
        "department_id": "Unknown",
        "department_name": "Unknown"
    }
    try:
        lecturer = lecturers.objects.get(lecturerid=lecturer_upi)
    except ObjectDoesNotExist:
        pass

    details["name"] = lecturer.name
    details["email"] = lecturer.linkcode + "@ucl.ac.uk"

    if lecturer.owner:
        details["department_id"] = lecturer.owner
        details["department_name"] = _get_full_department_name(lecturer.owner)

    return details


def _get_timetable_events(full_modules, stumodules):
    """
    Gets a dictionary of timetabled events.
    If stumodules=True then assume full_modules = [Stumodules]
    If stumodules=False then assume full_modules [ModuleA] or [ModuleB]
    """
    if not _week_map:
        _map_weeks()

    timetable = _get_cache("timetable")
    modules = _get_cache("module")

    bookings = _get_cache("booking")

    full_timetable = {}
    for module in full_modules:
        if stumodules:
            # Get events for the lab group assigned
            # Also include general lecture events (via the or operator)
            events_data = timetable.objects.filter(
                Q(modgrpcode=module.modgrpcode) | Q(modgrpcode=''),
                moduleid=module.moduleid
            )
            module_data = modules.objects.get(moduleid=module.moduleid)
        else:
            events_data = timetable.objects.filter(
                moduleid=module.moduleid
            )
            module_data = module
        for event in events_data:
            event_bookings = bookings.objects.filter(slotid=event.slotid)
            if len(event_bookings) == 0:
                # We have to trust the data in the event because
                # no rooms are booked for some weird reason.
                for date in _get_real_dates(event):
                    event_data = {
                        "start_time": event.starttime,
                        "end_time": event.finishtime,
                        "duration": event.duration,
                        "module": {
                            "module_id": module_data.moduleid,
                            "department_id": event.owner,
                            "department_name": _get_full_department_name(
                                event.owner
                            ),
                            "name": module_data.name
                        },
                        "location": _get_location_details(
                            event.siteid,
                            event.roomid
                        ),
                        "session_title": module_data.name,
                        "session_type": event.moduletype,
                        "session_type_str": _get_session_type_str(
                            event.moduletype
                        ),
                        "contact": "Unknown"
                    }

                    # If this is student module data, add in the group code
                    # because we have that field in Stumodules
                    if stumodules:
                        event_data["session_group"] = event.modgrpcode
                        if event.modgrpcode != '':
                            event_data["session_title"] = "{} ({})".format(
                                module_data.name,
                                event.modgrpcode
                            )

                    # Check if the module timetable event's Lecturer ID
                    # exists. If not, we use the Lecturer ID associated
                    # with the module as a whole. It's an ugly hack, but
                    # it works around not all timetabled lectures having
                    # the Lecturer ID field filled as they should.
                    # We assume therefore that if the lecturer isn't
{'fraction_non_alphanumeric': 0.08454950325453922, 'fraction_numerical': 0.001986981843096951, 'mean_word_length': 1.9081490336720461, 'pattern_counts': {'":': 62, '<': 4, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '116769', 'n_tokens_mistral': 4253, 'n_tokens_neox': 4018, 'n_words': 985}