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

finish timeline, rename lectures

parent 28b4db25
No related branches found
No related tags found
1 merge request!1Sync branches
Pipeline #12787 passed
This commit is part of merge request !1. Comments created here will be created in the context of that merge request.
default_language_version:
python: python3.11
exclude: snapshots/
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace
exclude: ^.*\.md$
- id: end-of-file-fixer
- id: debug-statements
- id: mixed-line-ending
args: [--fix=lf]
- id: detect-private-key
- id: check-merge-conflict
- repo: https://github.com/timothycrosley/isort
rev: 5.12.0
hooks:
- id: isort
- repo: https://github.com/psf/black
rev: 23.1.0
hooks:
- id: black
...@@ -4,4 +4,4 @@ from django.apps import AppConfig ...@@ -4,4 +4,4 @@ from django.apps import AppConfig
class LecturesConfig(AppConfig): class LecturesConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField" default_auto_field = "django.db.models.BigAutoField"
name = "lectures" name = "lectures"
verbose_name = "Lekce" verbose_name = "Školení"
# Generated by Django 4.1.4 on 2023-05-09 19:17
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
('lectures', '0014_alter_lecture_options_alter_lecturelector_username'),
]
operations = [
migrations.AlterModelOptions(
name='lecture',
options={'ordering': ('-timestamp', '-name'), 'permissions': [('can_edit_lecture_settings', 'Can edit Školení settings')], 'verbose_name': 'Školení', 'verbose_name_plural': 'Školení'},
),
migrations.AlterField(
model_name='lecture',
name='type',
field=models.CharField(choices=[('recommended', 'Doporučené školení'), ('optional', 'Volitelné školení')], max_length=11, verbose_name='Typ'),
),
migrations.AlterField(
model_name='lecturegroup',
name='user_groups',
field=models.ManyToManyField(blank=True, help_text='Pokud žádná nedefinuješ, školení ve skupině jsou dostupné všem.', to='auth.group', verbose_name='Uživatelské skupiny'),
),
migrations.AlterField(
model_name='lecturelector',
name='lecture',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='lectors', to='lectures.lecture', verbose_name='Školení'),
),
migrations.AlterField(
model_name='lecturematerial',
name='lecture',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='materials', to='lectures.lecture', verbose_name='Školení'),
),
migrations.AlterField(
model_name='lecturerecording',
name='lecture',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='recordings', to='lectures.lecture', verbose_name='Školení'),
),
]
...@@ -30,7 +30,7 @@ class LectureGroup(NameStrMixin, models.Model): ...@@ -30,7 +30,7 @@ class LectureGroup(NameStrMixin, models.Model):
Group, Group,
blank=True, blank=True,
verbose_name="Uživatelské skupiny", verbose_name="Uživatelské skupiny",
help_text="Pokud nedefinuješ žádné, lekce ve skupině jsou dostupné všem.", help_text="Pokud žádná nedefinuješ, školení ve skupině jsou dostupné všem.",
) )
class Meta: class Meta:
...@@ -40,7 +40,8 @@ class LectureGroup(NameStrMixin, models.Model): ...@@ -40,7 +40,8 @@ class LectureGroup(NameStrMixin, models.Model):
class Lecture(NameStrMixin, models.Model): class Lecture(NameStrMixin, models.Model):
is_current_treshold = timedelta(hours=8) is_current_starting_treshold = timedelta(hours=8)
is_current_ending_treshold = timedelta(days=60)
timestamp = models.DateTimeField( timestamp = models.DateTimeField(
verbose_name="Datum a čas konání", verbose_name="Datum a čas konání",
...@@ -49,8 +50,8 @@ class Lecture(NameStrMixin, models.Model): ...@@ -49,8 +50,8 @@ class Lecture(NameStrMixin, models.Model):
) # If undefined, assume this event was in the past ) # If undefined, assume this event was in the past
class TypeChoices(models.TextChoices): class TypeChoices(models.TextChoices):
RECOMMENDED = "recommended", "Doporučená lekce" RECOMMENDED = "recommended", "Doporučené školení"
OPTIONAL = "optional", "Volitelná lekce" OPTIONAL = "optional", "Volitelné školení"
groups = models.ManyToManyField( groups = models.ManyToManyField(
LectureGroup, LectureGroup,
...@@ -77,17 +78,12 @@ class Lecture(NameStrMixin, models.Model): ...@@ -77,17 +78,12 @@ class Lecture(NameStrMixin, models.Model):
help_text="Můžeš použít Markdown.", help_text="Můžeš použít Markdown.",
) )
@property
def is_current(self) -> bool:
# On or after the current time, minus 8 hours
return self.timestamp >= (timezone.now() - self.is_current_treshold)
# Settings # Settings
settings = app_settings.LectureSettings("Nastavení") settings = app_settings.LectureSettings("Nastavení")
class Meta: class Meta:
verbose_name = "Lekce" verbose_name = "Školení"
verbose_name_plural = verbose_name verbose_name_plural = verbose_name
ordering = ("-timestamp", "-name") ordering = ("-timestamp", "-name")
...@@ -97,7 +93,7 @@ class LectureLector(NameStrMixin, models.Model): ...@@ -97,7 +93,7 @@ class LectureLector(NameStrMixin, models.Model):
"Lecture", "Lecture",
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name="lectors", related_name="lectors",
verbose_name="Lekce", verbose_name="Školení",
) )
name = models.CharField( name = models.CharField(
...@@ -133,7 +129,7 @@ class LectureRecording(NameStrMixin, models.Model): ...@@ -133,7 +129,7 @@ class LectureRecording(NameStrMixin, models.Model):
"Lecture", "Lecture",
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name="recordings", related_name="recordings",
verbose_name="Lekce", verbose_name="Školení",
) )
name = models.CharField( name = models.CharField(
...@@ -158,7 +154,7 @@ class LectureMaterial(NameStrMixin, models.Model): ...@@ -158,7 +154,7 @@ class LectureMaterial(NameStrMixin, models.Model):
"Lecture", "Lecture",
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name="materials", related_name="materials",
verbose_name="Lekce", verbose_name="Školení",
) )
name = models.CharField( name = models.CharField(
......
{% extends "shared/includes/base.html" %} {% extends "shared/includes/base.html" %}
{% load render_bundle from webpack_loader %} {% load render_bundle from webpack_loader %}
{% load markdownify %} {% load markdownify static %}
{% block content %} {% block content %}
{% render_bundle "view_group_lectures" %}
{% include "shared/includes/double_heading.html" with heading=group.name subheading="výuka" icon="ico--user" %} {% include "shared/includes/double_heading.html" with heading=group.name subheading="výuka" icon="ico--user" %}
{% if group.description %} {% if group.description %}
...@@ -49,7 +51,7 @@ ...@@ -49,7 +51,7 @@
{% endfor %} {% endfor %}
</ul> </ul>
{% else %} {% else %}
<span class="text-gray-600">Žádné dostupné aktuální lekce.</span> <span class="text-gray-600">Žádná dostupná aktuální školení.</span>
{% endif %} {% endif %}
</template> </template>
<template v-if="isCurrentView('timeline')"> <template v-if="isCurrentView('timeline')">
...@@ -63,36 +65,49 @@ ...@@ -63,36 +65,49 @@
<button <button
class="bg-black p-3 text-2xl text-white hover:bg-grey-800 disabled:opacity-50 disabled:cursor-normal" class="bg-black p-3 text-2xl text-white hover:bg-grey-800 disabled:opacity-50 disabled:cursor-normal"
id="previous-timeline-item" id="previous-timeline-item"
{% if per_month_lectures|length < 2 %}disabled{% endif %} onclick="window.previousTimelineYear()"
{% if not has_previous_timeline_years %}disabled{% endif %}
><i class="ico--chevron-left"></i></button> ><i class="ico--chevron-left"></i></button>
<button <button
class="bg-black p-3 text-2xl text-white hover:bg-grey-800 disabled:opacity-50 disabled:cursor-normal" class="bg-black p-3 text-2xl text-white hover:bg-grey-800 disabled:opacity-50 disabled:cursor-normal"
id="next-timeline-item" id="next-timeline-item"
{% if per_month_lectures|length < 2 %}disabled{% endif %} onclick="window.nextTimelineYear()"
{% if not has_next_timeline_years %}disabled{% endif %}
><i class="ico--chevron-right"></i></button> ><i class="ico--chevron-right"></i></button>
</div> </div>
</div> </div>
{% for year, month_data in per_month_lectures.items %} {% for year, month_data in per_month_lectures.items %}
<ul class="__timeline-year grid grid-cols-1 md:grid-cols-3 gap-3" id="timeline-year-{{ year }}"> <ul
class="__timeline-year grid grid-cols-1 md:grid-cols-3 gap-3{% if current_year != year %} hidden{% endif %}"
id="timeline-year-{{ year }}"
>
{% for month, lectures in month_data.items %} {% for month, lectures in month_data.items %}
<li class="card elevation-3"> <li class="card elevation-3">
<div class="card__body p-5"> <div class="card__body p-5">
<h4 class="head-alt-sm mb-2">{{ month }}</h4> <h4 class="head-alt-sm mb-2">{{ month }}</h4>
{% if lectures %}
<ul class="flex flex-col gap-1"> <ul class="flex flex-col gap-1">
{% for lecture in lectures %} {% for lecture in lectures %}
<li> <li>
<a <a
class="inline-block px-2.5 py-1.5 bg-gray-200 duration-100 hover:no-underline hover:bg-gray-300" class="inline-block px-2.5 py-1.5 bg-gray-200 rounded-sm duration-100 hover:no-underline hover:bg-gray-300"
href="{% url "lectures:view_lecture" lecture.id %}?related_group_id={{ group.id }}" href="{% url "lectures:view_lecture" lecture.id %}?related_group_id={{ group.id }}"
>{{ lecture.name }}</a> >{{ lecture.name }}</a>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% else %}
<span class="block text-gray-600 pt-2">Žádná školení.</span>
{% endif %}
</div> </div>
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% endfor %} {% endfor %}
<script type="application/javascript" defer>
window.currentTimelineYear = {{ current_year }};
</script>
</div> </div>
</template> </template>
<template v-if="isCurrentView('recordings')"> <template v-if="isCurrentView('recordings')">
...@@ -109,6 +124,4 @@ ...@@ -109,6 +124,4 @@
</div> </div>
</ui-view-provider> </ui-view-provider>
</div> </div>
{% render_bundle "view_group_lectures" %}
{% endblock %} {% endblock %}
...@@ -53,27 +53,42 @@ def view_group_lectures(request, group_id: int): ...@@ -53,27 +53,42 @@ def view_group_lectures(request, group_id: int):
id=group_id, id=group_id,
) )
timestamp_separator = timezone.now() - Lecture.is_current_treshold timestamp_starting_separator = timezone.now() - Lecture.is_current_starting_treshold
timestamp_ending_separator = timezone.now() + Lecture.is_current_ending_treshold
current_lectures = ( past_lectures = (
get_objects_for_user(request.user, "lectures.view_lecture") get_objects_for_user(request.user, "lectures.view_lecture")
.filter( .filter(
groups=group, groups=group,
timestamp__gte=timestamp_separator, timestamp__lt=timestamp_starting_separator,
) )
.all() .all()
) )
past_lectures = ( current_lectures = (
get_objects_for_user(request.user, "lectures.view_lecture") get_objects_for_user(request.user, "lectures.view_lecture")
.filter( .filter(
groups=group, groups=group,
timestamp__lt=timestamp_separator, timestamp__gte=timestamp_starting_separator,
timestamp__lte=timestamp_ending_separator
) )
.all() .all()
) )
calendar_data = [] calendar_data = []
all_lectures = list(chain(current_lectures, past_lectures)) all_lectures = list(
chain(
past_lectures,
current_lectures,
(
get_objects_for_user(request.user, "lectures.view_lecture")
.filter(
groups=group,
timestamp__gte=timestamp_ending_separator
)
.all()
)
)
)
per_month_lectures = {} per_month_lectures = {}
...@@ -98,13 +113,29 @@ def view_group_lectures(request, group_id: int): ...@@ -98,13 +113,29 @@ def view_group_lectures(request, group_id: int):
#"cs_CZ.UTF-8" #"cs_CZ.UTF-8"
#) #)
current_year = datetime.today().year
has_previous_timeline_years = False
has_next_timeline_years = False
for lecture in all_lectures: 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: if lecture.timestamp.year not in per_month_lectures:
per_month_lectures[lecture.timestamp.year] = { per_month_lectures[lecture.timestamp.year] = {
MONTH_NAMES[month]: [] MONTH_NAMES[month]: []
for month in range(1, 12 + 1) 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) per_month_lectures[lecture.timestamp.year][MONTH_NAMES[lecture.timestamp.month]].append(lecture)
...@@ -125,7 +156,9 @@ def view_group_lectures(request, group_id: int): ...@@ -125,7 +156,9 @@ def view_group_lectures(request, group_id: int):
"current_lectures": current_lectures, "current_lectures": current_lectures,
"past_lectures": past_lectures, "past_lectures": past_lectures,
"per_month_lectures": per_month_lectures, "per_month_lectures": per_month_lectures,
"current_year": datetime.today().year "current_year": current_year,
"has_previous_timeline_years": has_previous_timeline_years,
"has_next_timeline_years": has_next_timeline_years,
}, },
) )
...@@ -160,7 +193,7 @@ def view_lecture(request, lecture_id: int): ...@@ -160,7 +193,7 @@ def view_lecture(request, lecture_id: int):
{ {
**get_base_context(request), **get_base_context(request),
"title": f"{lecture.name}", "title": f"{lecture.name}",
"description": f"e-Learningová lekce {lecture.name}.", "description": f"e-Learningové školení {lecture.name}.",
"header_name": lecture.name, "header_name": lecture.name,
"lecture": lecture, "lecture": lecture,
"related_group_id": related_group_id, "related_group_id": related_group_id,
......
...@@ -193,7 +193,7 @@ ...@@ -193,7 +193,7 @@
</footer> </footer>
<script <script
src="http://localhost:3000/js/main.bundle.js" src="https://styleguide.pirati.cz/2.12.x/js/main.bundle.js"
></script> ></script>
</body> </body>
</html> </html>
import $ from "jquery"; import $ from "jquery";
const showTimelineYear = (year) => { const showTimelineYear = () => {
$(".__timeline-year").not(`#timeline-year-${year}`).addClass("display", "hidden"); $(".__timeline-year").not(`#timeline-year-${window.currentTimelineYear}`).addClass("hidden");
$(`#timeline-year-${year}`).removeClass("hidden"); $(`#timeline-year-${window.currentTimelineYear}`).removeClass("hidden");
$("#timeline-current-year").html(year); $("#timeline-current-year").html(window.currentTimelineYear);
$("#next-timeline-item").attr(
"disabled",
($(`#timeline-year-${window.currentTimelineYear + 1}`).length === 0)
);
$("#previous-timeline-item").attr(
"disabled",
($(`#timeline-year-${window.currentTimelineYear - 1}`).length === 0)
);
} }
$(window).ready( $(window).ready(
() => { () => {
$("#previous-timeline-item").on( window.nextTimelineYear = () => {
"click",
event => {
window.currentTimelineYear--;
console.log(window.currentTimelineYear);
showTimelineYear(window.currentTimelineYear);
const previousYear = window.currentTimelineYear - 1;
if ($(`#timeline-year-${window.previousYear}`).length === 0) {
$(event.currentTarget).attr("disabled", true);
}
}
);
$("#next-timeline-item").on(
"click",
event => {
window.currentTimelineYear++; window.currentTimelineYear++;
showTimelineYear();
showTimelineYear(window.currentTimelineYear);
const nextYear = window.currentTimelineYear + 1;
if ($(`#timeline-year-${window.currentTimelineYear}`).length === 0) {
$(event.currentTarget).attr("disabled", true);
} }
window.previousTimelineYear = () => {
window.currentTimelineYear--;
showTimelineYear();
} }
);
} }
); )
# Generated by Django 4.1.4 on 2023-05-09 19:17
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lectures', '0015_alter_lecture_options_alter_lecture_type_and_more'),
('users', '0007_alter_user_rsvp_lectures'),
]
operations = [
migrations.AlterField(
model_name='user',
name='rsvp_lectures',
field=models.ManyToManyField(blank=True, related_name='rsvp_users', to='lectures.lecture', verbose_name='Zaregistrovaná školení'),
),
]
...@@ -32,7 +32,7 @@ class User(pirates_models.AbstractUser): ...@@ -32,7 +32,7 @@ class User(pirates_models.AbstractUser):
"lectures.Lecture", "lectures.Lecture",
blank=True, blank=True,
related_name="rsvp_users", related_name="rsvp_users",
verbose_name="Zaregistrované lekce", verbose_name="Zaregistrovaná školení",
) )
def set_unusable_password(self) -> None: def set_unusable_password(self) -> None:
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment