Skip to content
Snippets Groups Projects
Commit 07840063 authored by Tomáš Valenta's avatar Tomáš Valenta
Browse files

add registered events view, finished lector view, optimizations

parent bcb5472d
Branches
No related tags found
No related merge requests found
Pipeline #13079 passed
# Generated by Django 4.1.4 on 2023-05-31 13:01
from django.db import migrations, models
import lectures.models
class Migration(migrations.Migration):
dependencies = [
('lectures', '0022_lecturelector_avatar_lecturelector_description_and_more'),
]
operations = [
migrations.AlterField(
model_name='lecturelector',
name='avatar',
field=models.ImageField(blank=True, help_text='Vložený soubor má prioritu nad obrázkem synchronizovaným z Chobotnice.', null=True, upload_to=lectures.models.get_file_location, verbose_name='Profilový obrázek'),
),
migrations.AlterField(
model_name='lecturelector',
name='username',
field=models.CharField(blank=True, help_text='Např. na fóru, nebo v Chobotnici. Užívá se k synchronizaci profilového obrázku, v budoucnu i dalších informací.', max_length=128, null=True, verbose_name='Uživatelské jméno'),
),
]
......@@ -176,13 +176,13 @@ class LectureLector(NameStrMixin, models.Model):
),
)
avatar = models.FileField(
avatar = models.ImageField(
blank=True,
null=True,
upload_to=get_file_location,
verbose_name="Profilový obrázek",
help_text=(
"Vložený soubor má prioritu nad obrázkem synchronizovaným " "z Chobotnice."
"Vložený soubor má prioritu nad obrázkem synchronizovaným z Chobotnice."
),
)
......
......@@ -5,19 +5,72 @@
{% block content %}
{% render_bundle "view_group_lectures" %}
{% include "shared/includes/double_heading.html" with heading=header_name subheading=header_desc icon="ico--user" %}
{% if related_lecture_id %}
<div class="flex gap-2 mb-10">
<i class="ico--chevron-left"></i>
<a
href="{% url "lectures:view_lecture" related_lecture_id %}{% if related_group_id %}?related_group_id={{ related_group_id }}{% endif %}"
>Zpět na školení</a>
</div>
{% endif %}
<div class="flex gap-4 mb-10 items-center">
<img
alt="Profilový obrázek lektora"
{% if lector.avatar %}
src="{{ lector.avatar.url }}"
{% elif lector.username %}
src="https://a.pirati.cz/piratar/300/{{ lector.username }}.jpg"
{% else %}
src="https://a.pirati.cz/piratar/300/default.jpg"
{% endif %}
class="h-20 w-20 md:h-24 md:w-24 rounded-full"
>
<div>
<h1 class="head-alt-md md:head-alt-lg">{{ header_name }}</h1>
<h2 class="head-alt-sm">{{ header_desc }}</h2>
</div>
</div>
{% if lector.description %}
<div class="mb-10 prose max-w-none">
{{ lector.description|markdownify|safe }}
</div>
{% endif %}
<div class="flex flex-col gap-2 my-4 py-4 border-y border-gray-200 mb-10">
<div class="flex justify-between gap-2 text-lg text-gray-600">
<div class="flex gap-2 items-center">
<i class="ico--globe"></i>
<span>Web</span>
</div>
<a
href="{{ lector.url }}"
class="underline"
>
{{ lector.url }}
</a>
</div>
<div class="flex justify-between gap-2 text-lg text-gray-600">
<div class="flex gap-2 items-center">
<i class="ico--book"></i>
<span>Počet školení</span>
</div>
<div>
{{ lectures|length }}
</div>
</div>
</div>
<h2 class="head-alt-md my-8">Vytvořená školení</h2>
<h2 class="head-alt-md my-8">Vyučovaná školení</h2>
<ul class="flex flex-col gap-2">
<ul class="grid grid-cols-2 gap-2">
{% if lectures %}
{% for lecture in lectures %}
{% include "lectures/includes/lecture.html" %}
{% endfor %}
{% else %}
<span class="text-gray-600">Nebyly nalezeny žádné výsledky.</span>
<span class="text-gray-600">Žádná evidovaná školení.</span>
{% endif %}
</ul>
{% endblock %}
......@@ -17,6 +17,7 @@
<div class="flex justify-between items-start gap-3 flex-col md:flex-row">
{% include "shared/includes/double_heading.html" with heading=lecture.name subheading=lecture.get_type_display icon="ico--bookmark" %}
{% if user.is_authenticated %}
<button
id="set-rsvp"
class="font-alt text-lg bg-black text-white px-5 py-2 duration-100 hover:bg-white hover:text-black"
......@@ -28,6 +29,7 @@
Zrušit registraci
{% endif %}
</button>
{% endif %}
</div>
<script>
......@@ -139,11 +141,13 @@
<ul class="grid grid-cols-1 md:grid-cols-2 gap-4">
{% for lector in lectors %}
<li class="card elevation-3">
<div
class="hover:no-underline flex items-start gap-4 {% if lector.url %}duration-150 hover:bg-gray-100{% endif %} card__body"
>
<a
href="{% url "lectures:view_lector" lector.id %}"
class="hover:no-underline flex items-center gap-4 {% if lector.url %}duration-150 hover:bg-gray-100{% endif %} card__body"
class="avatar shrink-0 object-contain badge__avatar avatar--sm"
href="{% url "lectures:view_lector" lector.id %}?related_lecture_id={{ lecture.id }}{% if related_group_id %}&related_group_id={{ related_group_id }}{% endif %}"
>
<div class="avatar badge__avatar avatar--sm">
<img
{% if lector.avatar %}
src="{{ lector.avatar.url }}"
......@@ -152,23 +156,30 @@
{% else %}
src="https://a.pirati.cz/piratar/300/default.jpg"
{% endif %}
class="w-20 h-20"
alt="Profilový obrázek {{ lector.name }}"
>
</div>
</a>
<div class="flex flex-col gap-2">
<span class="head-heavy-2xs">
<div class="content-block--nostyle">
{{ lector.name }}
</div>
<a
class="content-block--nostyle"
href="{% url "lectures:view_lector" lector.id %}?related_lecture_id={{ lecture.id }}{% if related_group_id %}&related_group_id={{ related_group_id }}{% endif %}"
>{{ lector.name }}</a>
</span>
{% if lector.description %}
<div class="prose max-w-none">
{{ lector.description|markdownify|safe }}
</div>
{% endif %}
{% if lector.url %}
<div
<a
class="block text-ellipsis overflow-hidden"
href="{{ lector.url }}"
>{{ lector.url }}</div>
>{{ lector.url }}</a>
{% endif %}
</div>
</a>
</div>
</li>
{% endfor %}
</ul>
......
{% extends "shared/includes/base.html" %}
{% load render_bundle from webpack_loader %}
{% load markdownify static %}
{% block content %}
{% include "shared/includes/double_heading.html" with heading=header_name icon="ico--pin" %}
<div class="__js-root">
<ui-year-calendar events='{{ events|safe }}'></ui-year-calendar>
</div>
{% endblock %}
......@@ -15,6 +15,12 @@ urlpatterns = [
name="download_material_file",
),
path("lectures/<int:lecture_id>/rsvp", views.rsvp_lecture, name="rsvp_lecture"),
path("lectors/<int:id>", views.view_lector, name="view_lector"),
path(
"lectures/registered",
views.view_registered,
name="view_registered",
),
path(
"search",
views.search,
......
......@@ -5,6 +5,7 @@ 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
......@@ -258,14 +259,7 @@ def view_group_lectures(request, group_id: int):
)
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()
def get_related_group_id(request):
related_group_id = request.GET.get("related_group_id")
if related_group_id not in ("", None):
......@@ -273,7 +267,7 @@ def view_lecture(request, lecture_id: int):
raise HTTPExceptions.BAD_REQUEST
if not (
get_objects_for_user(request.user, "lectures.view_lecture")
get_objects_for_user(request.user, "lectures.view_lecturegroup")
.filter(id=related_group_id)
.exists()
):
......@@ -281,6 +275,17 @@ def view_lecture(request, lecture_id: int):
# 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()
return render(
request,
"lectures/view_lecture.html",
......@@ -290,7 +295,7 @@ def view_lecture(request, lecture_id: int):
"description": f"e-Learningové školení {lecture.name}.",
"header_name": lecture.name,
"lecture": lecture,
"related_group_id": related_group_id,
"related_group_id": get_related_group_id(request),
},
)
......@@ -349,6 +354,21 @@ def view_lector(request, id):
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
return render(
request,
"lectures/view_lector.html",
......@@ -356,15 +376,54 @@ def view_lector(request, id):
**get_base_context(request),
"title": lector.name,
"description": f"Informace o lektorovi - {lector.name}.",
"header_name": "Lektor",
"header_desc": lector.name,
"header_name": lector.name,
"header_desc": "Lektor",
"related_lecture_id": related_lecture_id,
"related_group_id": get_related_group_id(request),
"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_lecture(request, models.Q(id=lecture_id))
......
......@@ -14,3 +14,4 @@ django-environ==0.9.0
django-http-exceptions==1.4.0
django-guardian==2.4.0
PyJWT==2.6.0
Pillow==9.5.0
......@@ -36,13 +36,14 @@
media="all"
>
<!-- TODO: Replace with 2.13.x once released -->
<link
href="https://styleguide.pirati.cz/2.12.x/css/styles.css"
href="http://localhost:3000/css/styles.css"
rel="stylesheet"
media="all"
>
<link
href="https://styleguide.pirati.cz/2.12.x/css/pattern-scaffolding.css"
href="http://localhost:3000/css/pattern-scaffolding.css"
rel="stylesheet"
media="all"
>
......@@ -86,6 +87,16 @@
</li>
{% endif %}
<li class="navbar-menu__item">
<a
href="{% url "lectures:view_registered" %}"
data-href="{% url "lectures:view_registered" %}"
class="navbar-menu__link flex items-center gap-2"
>
<i class="ico--pin text-sm"></i>Tvá školení
</a>
</li>
<li class="navbar-menu__item">
<a
href="{% url "lectures:search" %}"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment