Skip to content
Snippets Groups Projects
views.py 13.69 KiB
# import calendar
# import locale
import json
from datetime import datetime
from itertools import chain

from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.db import models
from django.http import HttpResponseRedirect, JsonResponse
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.utils import timezone
from django.views.decorators.http import require_POST
from django_downloadview import ObjectDownloadView
from django_http_exceptions import HTTPExceptions
from guardian.shortcuts import get_objects_for_user

from .models import Lecture, LectureGroup, LectureMaterial


class LectureMaterialFileDownloadView(ObjectDownloadView):
    model = LectureMaterial
    file_field = "file"
    attachment = False

    def get_queryset(self, *args, **kwargs):
        queryset = super().get_queryset(*args, **kwargs)
        material = queryset.first()

        if material is None:
            raise HTTPExceptions.NOT_FOUND

        success, auth_redirect = get_lectures(
            self.request, filter=models.Q(id=material.lecture_id), get_exceptions=True
        )

        if not success:
            raise HTTPExceptions.NOT_FOUND

        return queryset

    def get(self, request, *args, **kwargs):
        self.request = request
        return super().get(request, *args, **kwargs)


def get_base_context(request) -> dict:
    return {
        "site_url": settings.SITE_URL,
    }


def generate_auth_redirect(request) -> HttpResponseRedirect:
    return HttpResponseRedirect(
        request.build_absolute_uri(reverse("oidc_authentication_init"))
        + "?next="
        + request.path
    )


def get_lectures(request, filter=None, get_exceptions: bool = True) -> tuple:
    lectures = get_objects_for_user(request.user, "lectures.view_lecture")

    if filter is not None:
        lectures = lectures.filter(filter)

    if get_exceptions and not lectures.exists():
        raise HTTPExceptions.NOT_FOUND

    if not (
        get_objects_for_user(request.user, "lectures.view_lecturegroup")
        .filter(
            models.Q(
                id__in=(
                    LectureGroup.objects.filter(
                        lecture_group_types__lecture__in=lectures
                    )
                )
            )
            & (
                (
                    models.Q(user_groups__in=request.user.groups.all())
                    | models.Q(user_groups=None)
                )
                if not request.user.is_superuser
                else models.Q(id__isnull=False)  # Always True
            )
        )
        .distinct()
        .exists()
    ):  # User does not have access to related groups
        if get_exceptions:
            if request.user.is_authenticated:  # The user can log in
                raise HTTPExceptions.NOT_FOUND
            else:  # They can log in
                return False, generate_auth_redirect(request)

    if get_exceptions:
        return True, lectures
    else:
        return lectures


def view_groups(request):
    lecture_groups = (
        get_objects_for_user(request.user, "lectures.view_lecturegroup")
        .filter(
            (
                models.Q(user_groups__in=request.user.groups.all())
                | models.Q(user_groups=None)
            )
            if not request.user.is_superuser
            else models.Q()
        )
        .distinct()
        .all()
    )

    return render(
        request,
        "lectures/view_groups.html",
        {
            **get_base_context(request),
            "title": "Výukové skupiny",
            "description": "Kurzy a školení zaměřené na politickou práci a organizaci kampaní.",
            "header_name": "Pirátský e-Learning",
            "lecture_groups": lecture_groups,
            "settings": Lecture.settings,
        },
    )


def view_group_lectures(request, group_id: int):
    group = get_objects_for_user(request.user, "lectures.view_lecturegroup").filter(
        id=group_id
    )

    group_id_exists = group.exists()

    if not request.user.is_superuser:
        group = group.filter(
            models.Q(user_groups__in=request.user.groups.all())
            | models.Q(user_groups=None)
        )

    if not group.exists():
        if not group_id_exists:  # Doesn't exist at all
            raise HTTPExceptions.NOT_FOUND
        elif group_id_exists:  # Exists without permissions checks
            if request.user.is_authenticated:  # The user is logged in
                raise HTTPExceptions.NOT_FOUND
            else:  # The user can log in
                return generate_auth_redirect(request)

    group = group.first()

    timestamp_starting_separator = timezone.now() - Lecture.is_current_starting_treshold
    timestamp_ending_separator = timezone.now() + Lecture.is_current_ending_treshold

    past_lectures = (
        get_objects_for_user(request.user, "lectures.view_lecture")
        .filter(
            lecture_group_types__group=group,
            timestamp__lt=timestamp_starting_separator,
        )
        .all()
    )
    current_lectures = (
        get_objects_for_user(request.user, "lectures.view_lecture")
        .filter(
            lecture_group_types__group=group,
            timestamp__gte=timestamp_starting_separator,
            timestamp__lte=timestamp_ending_separator,
        )
        .all()
    )

    calendar_data = []
    all_lectures = list(
        chain(
            past_lectures,
            current_lectures,
            (
                get_objects_for_user(request.user, "lectures.view_lecture")
                .filter(
                    lecture_group_types__group=group,
                    timestamp__gte=timestamp_ending_separator,
                )
                .all()
            ),
        )
    )

    per_month_lectures = {}

    MONTH_NAMES = {
        0: "",
        1: "Leden",
        2: "Únor",
        3: "Březen",
        4: "Duben",
        5: "Květen",
        6: "Červen",
        7: "Červenec",
        8: "Srpen",
        9: "Září",
        10: "Říjen",
        11: "Listopad",
        12: "Prosinec",
    }

    # locale.setlocale(
    # locale.LC_ALL,
    # "cs_CZ.UTF-8"
    # )

    current_year = datetime.today().year

    has_previous_timeline_years = False
    has_next_timeline_years = False

    for lecture in all_lectures:
        if not has_previous_timeline_years and lecture.timestamp.year < current_year:
            has_previous_timeline_years = True

        if not has_next_timeline_years and lecture.timestamp.year > current_year:
            has_next_timeline_years = True

        if lecture.timestamp.year not in per_month_lectures:
            per_month_lectures[lecture.timestamp.year] = {
                MONTH_NAMES[month]: [] for month in range(1, 12 + 1)
            }

        if current_year not in per_month_lectures:
            per_month_lectures[current_year] = {
                MONTH_NAMES[month]: [] for month in range(1, 12 + 1)
            }

        per_month_lectures[lecture.timestamp.year][
            MONTH_NAMES[lecture.timestamp.month]
        ].append(lecture)

    # locale.setlocale(
    #     locale.LC_ALL,
    #     ""
    # )

    return render(
        request,
        "lectures/view_group_lectures.html",
        {
            **get_base_context(request),
            "title": f"Výuka pro {group.name}",
            "description": f"e-Learningová výuka pro skupinu {group.name}.",
            "header_name": group.name,
            "group": group,
            "current_lectures": current_lectures,
            "past_lectures": past_lectures,
            "per_month_lectures": per_month_lectures,
            "current_year": current_year,
            "has_previous_timeline_years": has_previous_timeline_years,
            "has_next_timeline_years": has_next_timeline_years,
        },
    )


def get_related_group_id(request):
    related_group_id = request.GET.get("related_group_id")

    if related_group_id not in ("", None):
        if not str(related_group_id).isnumeric():
            raise HTTPExceptions.BAD_REQUEST

        if not (
            get_objects_for_user(request.user, "lectures.view_lecturegroup")
            .filter(id=related_group_id)
            .exists()
        ):
            # Ignore the wrong part of the URL and move on, don't raise exceptions
            # just because of the related_group_id being wrong.
            related_group_id = None

    return related_group_id


def view_lecture(request, lecture_id: int):
    is_successful, lecture = get_lectures(request, models.Q(id=lecture_id))

    if not is_successful:
        return lecture

    lecture = lecture.first()

    related_group_id = get_related_group_id(request)
    group = (
        LectureGroup.objects.get(id=related_group_id)
        if related_group_id is not None
        else None
    )

    return render(
        request,
        "lectures/view_lecture.html",
        {
            **get_base_context(request),
            "title": f"{lecture.name}",
            "description": f"e-Learningové školení {lecture.name}.",
            "header_name": lecture.name,
            "lecture": lecture,
            "related_group_id": related_group_id,
            "group": group,
        },
    )


def search(request):
    query = request.GET.get("q")

    if query:
        queryset = get_lectures(request, get_exceptions=False)

        queryset = queryset.annotate(
            name_lower=models.Func(models.F("name"), function="LOWER"),
            description_lower=models.Func(models.F("description"), function="LOWER"),
        )

        formatted_query = query.lower()

        lectures = queryset.filter(
            models.Q(name_lower__contains=formatted_query)
            | models.Q(description_lower__contains=formatted_query)
        ).all()

        return render(
            request,
            "lectures/view_search_results.html",
            {
                **get_base_context(request),
                "title": f"Vyhledávání - {query}",
                "description": "Vyhledávání školení v Pirátském e-Learningu.",
                "header_name": "Výsledky vyhledávání",
                "header_desc": f"{query}",
                "query": query,
                "lectures": lectures,
            },
        )
    else:
        return render(
            request,
            "lectures/view_search.html",
            {
                **get_base_context(request),
                "title": "Vyhledávání",
                "description": "Vyhledávání školení v Pirátském e-Learningu.",
                "header_name": "Vyhledávání",
                "header_desc": "školení",
            },
        )


def view_lector(request, id):
    lector = get_object_or_404(
        get_objects_for_user(request.user, "lectures.view_lecturelector"), id=id
    )

    lectures = get_lectures(
        request, models.Q(id__in=lector.lectures.all()), get_exceptions=False
    )

    related_lecture_id = request.GET.get("related_lecture_id")

    if related_lecture_id not in ("", None):
        if not str(related_lecture_id).isnumeric():
            raise HTTPExceptions.BAD_REQUEST

        if not (
            get_objects_for_user(request.user, "lectures.view_lecture")
            .filter(id=related_lecture_id)
            .exists()
        ):
            # Ignore the wrong part of the URL and move on, don't raise exceptions
            # just because of the related_lecture_id being wrong.
            related_lecture_id = None

    related_group_id = get_related_group_id(request)
    group = (
        LectureGroup.objects.get(id=related_group_id)
        if related_group_id is not None
        else None
    )

    return render(
        request,
        "lectures/view_lector.html",
        {
            **get_base_context(request),
            "title": lector.name,
            "description": f"Informace o lektorovi - {lector.name}.",
            "header_name": lector.name,
            "header_desc": "Lektor",
            "related_lecture_id": related_lecture_id,
            "related_group_id": related_group_id,
            "group": group,
            "lector": lector,
            "lectures": lectures,
        },
    )


@login_required
def view_registered(request):
    lectures = get_lectures(
        request, models.Q(rsvp_users=request.user), get_exceptions=False
    )

    events = []

    for lecture in lectures:
        events.append(
            {
                "title": lecture.name,
                "start": lecture.timestamp.isoformat(),
                "url": request.build_absolute_uri(
                    reverse("lectures:view_lecture", args=(lecture.id,))
                ),
                "description": (
                    lecture.description if lecture.description is not None else ""
                ),
            }
        )

    return render(
        request,
        "lectures/view_registered.html",
        {
            **get_base_context(request),
            "title": "Tvá školení",
            "description": "Zobrazení tvých zaregistrovaných školení.",
            "header_name": "Tvá školení",
            "lectures": lectures,
            "events": json.dumps(events),
        },
    )


@require_POST
@login_required
def rsvp_lecture(request, lecture_id: int):
    is_successful, lecture = get_lectures(request, models.Q(id=lecture_id))

    if not is_successful:
        return lecture

    lecture = lecture.first()

    is_registered = request.POST.get("register", "false") == "true"

    if is_registered is request.user.get_lecture_registered(
        lecture
    ):  # The RSVP state is the same
        return JsonResponse({"success": False})

    if is_registered:
        lecture.rsvp_users.add(request.user)
    else:
        lecture.rsvp_users.remove(request.user)

    request.user.save()

    return JsonResponse({"success": True})