# 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})