-
Tomáš Valenta authoredTomáš Valenta authored
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})