From b6687f03c53ea1e3bb603bb29295c02f910b51e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Valenta?= <git@imaniti.org> Date: Tue, 9 May 2023 21:18:03 +0200 Subject: [PATCH] finish timeline, rename lectures --- .pre-commit-config.yaml | 26 +++++++++ lectures/apps.py | 2 +- ...ure_options_alter_lecture_type_and_more.py | 44 ++++++++++++++ lectures/models.py | 22 +++---- .../lectures/view_group_lectures.html | 47 +++++++++------ lectures/views.py | 49 +++++++++++++--- shared/templates/shared/includes/base.html | 2 +- static_src/view_group_lectures.js | 57 ++++++++----------- .../0008_alter_user_rsvp_lectures.py | 19 +++++++ users/models.py | 2 +- 10 files changed, 195 insertions(+), 75 deletions(-) create mode 100644 .pre-commit-config.yaml create mode 100644 lectures/migrations/0015_alter_lecture_options_alter_lecture_type_and_more.py create mode 100644 users/migrations/0008_alter_user_rsvp_lectures.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..1cdf315 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,26 @@ +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 diff --git a/lectures/apps.py b/lectures/apps.py index 5518d56..63c9edf 100644 --- a/lectures/apps.py +++ b/lectures/apps.py @@ -4,4 +4,4 @@ from django.apps import AppConfig class LecturesConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" name = "lectures" - verbose_name = "Lekce" + verbose_name = "Školení" diff --git a/lectures/migrations/0015_alter_lecture_options_alter_lecture_type_and_more.py b/lectures/migrations/0015_alter_lecture_options_alter_lecture_type_and_more.py new file mode 100644 index 0000000..fd4694f --- /dev/null +++ b/lectures/migrations/0015_alter_lecture_options_alter_lecture_type_and_more.py @@ -0,0 +1,44 @@ +# 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í'), + ), + ] diff --git a/lectures/models.py b/lectures/models.py index 2dc4dce..c03b51e 100644 --- a/lectures/models.py +++ b/lectures/models.py @@ -30,7 +30,7 @@ class LectureGroup(NameStrMixin, models.Model): Group, blank=True, 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: @@ -40,7 +40,8 @@ class LectureGroup(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( verbose_name="Datum a čas konání", @@ -49,8 +50,8 @@ class Lecture(NameStrMixin, models.Model): ) # If undefined, assume this event was in the past class TypeChoices(models.TextChoices): - RECOMMENDED = "recommended", "Doporučená lekce" - OPTIONAL = "optional", "Volitelná lekce" + RECOMMENDED = "recommended", "Doporučené školení" + OPTIONAL = "optional", "Volitelné školení" groups = models.ManyToManyField( LectureGroup, @@ -77,17 +78,12 @@ class Lecture(NameStrMixin, models.Model): 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 = app_settings.LectureSettings("Nastavení") class Meta: - verbose_name = "Lekce" + verbose_name = "Školení" verbose_name_plural = verbose_name ordering = ("-timestamp", "-name") @@ -97,7 +93,7 @@ class LectureLector(NameStrMixin, models.Model): "Lecture", on_delete=models.CASCADE, related_name="lectors", - verbose_name="Lekce", + verbose_name="Školení", ) name = models.CharField( @@ -133,7 +129,7 @@ class LectureRecording(NameStrMixin, models.Model): "Lecture", on_delete=models.CASCADE, related_name="recordings", - verbose_name="Lekce", + verbose_name="Školení", ) name = models.CharField( @@ -158,7 +154,7 @@ class LectureMaterial(NameStrMixin, models.Model): "Lecture", on_delete=models.CASCADE, related_name="materials", - verbose_name="Lekce", + verbose_name="Školení", ) name = models.CharField( diff --git a/lectures/templates/lectures/view_group_lectures.html b/lectures/templates/lectures/view_group_lectures.html index 866d0c2..ec2891b 100644 --- a/lectures/templates/lectures/view_group_lectures.html +++ b/lectures/templates/lectures/view_group_lectures.html @@ -1,8 +1,10 @@ {% extends "shared/includes/base.html" %} {% load render_bundle from webpack_loader %} -{% load markdownify %} +{% load markdownify static %} {% block content %} + {% render_bundle "view_group_lectures" %} + {% include "shared/includes/double_heading.html" with heading=group.name subheading="výuka" icon="ico--user" %} {% if group.description %} @@ -49,7 +51,7 @@ {% endfor %} </ul> {% else %} - <span class="text-gray-600">Žádné dostupné aktuální lekce.</span> + <span class="text-gray-600">Žádná dostupná aktuální školení.</span> {% endif %} </template> <template v-if="isCurrentView('timeline')"> @@ -63,36 +65,49 @@ <button class="bg-black p-3 text-2xl text-white hover:bg-grey-800 disabled:opacity-50 disabled:cursor-normal" 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> <button class="bg-black p-3 text-2xl text-white hover:bg-grey-800 disabled:opacity-50 disabled:cursor-normal" 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> </div> </div> {% 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 %} <li class="card elevation-3"> <div class="card__body p-5"> <h4 class="head-alt-sm mb-2">{{ month }}</h4> - <ul class="flex flex-col gap-1"> - {% for lecture in lectures %} - <li> - <a - class="inline-block px-2.5 py-1.5 bg-gray-200 duration-100 hover:no-underline hover:bg-gray-300" - href="{% url "lectures:view_lecture" lecture.id %}?related_group_id={{ group.id }}" - >{{ lecture.name }}</a> - </li> - {% endfor %} - </ul> + {% if lectures %} + <ul class="flex flex-col gap-1"> + {% for lecture in lectures %} + <li> + <a + 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 }}" + >{{ lecture.name }}</a> + </li> + {% endfor %} + </ul> + {% else %} + <span class="block text-gray-600 pt-2">Žádná školení.</span> + {% endif %} </div> </li> {% endfor %} </ul> {% endfor %} + + <script type="application/javascript" defer> + window.currentTimelineYear = {{ current_year }}; + </script> </div> </template> <template v-if="isCurrentView('recordings')"> @@ -109,6 +124,4 @@ </div> </ui-view-provider> </div> - - {% render_bundle "view_group_lectures" %} {% endblock %} diff --git a/lectures/views.py b/lectures/views.py index 33d05db..a7e3a51 100644 --- a/lectures/views.py +++ b/lectures/views.py @@ -53,27 +53,42 @@ def view_group_lectures(request, group_id: int): 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") .filter( groups=group, - timestamp__gte=timestamp_separator, + timestamp__lt=timestamp_starting_separator, ) .all() ) - past_lectures = ( + current_lectures = ( get_objects_for_user(request.user, "lectures.view_lecture") .filter( groups=group, - timestamp__lt=timestamp_separator, + timestamp__gte=timestamp_starting_separator, + timestamp__lte=timestamp_ending_separator ) .all() ) 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 = {} @@ -98,13 +113,29 @@ def view_group_lectures(request, group_id: int): #"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) @@ -125,7 +156,9 @@ def view_group_lectures(request, group_id: int): "current_lectures": current_lectures, "past_lectures": past_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): { **get_base_context(request), "title": f"{lecture.name}", - "description": f"e-Learningová lekce {lecture.name}.", + "description": f"e-Learningové školení {lecture.name}.", "header_name": lecture.name, "lecture": lecture, "related_group_id": related_group_id, diff --git a/shared/templates/shared/includes/base.html b/shared/templates/shared/includes/base.html index 3d50e73..087da92 100644 --- a/shared/templates/shared/includes/base.html +++ b/shared/templates/shared/includes/base.html @@ -193,7 +193,7 @@ </footer> <script - src="http://localhost:3000/js/main.bundle.js" + src="https://styleguide.pirati.cz/2.12.x/js/main.bundle.js" ></script> </body> </html> diff --git a/static_src/view_group_lectures.js b/static_src/view_group_lectures.js index fd53f48..e60c9eb 100644 --- a/static_src/view_group_lectures.js +++ b/static_src/view_group_lectures.js @@ -1,41 +1,30 @@ import $ from "jquery"; -const showTimelineYear = (year) => { - $(".__timeline-year").not(`#timeline-year-${year}`).addClass("display", "hidden"); - $(`#timeline-year-${year}`).removeClass("hidden"); - $("#timeline-current-year").html(year); +const showTimelineYear = () => { + $(".__timeline-year").not(`#timeline-year-${window.currentTimelineYear}`).addClass("hidden"); + $(`#timeline-year-${window.currentTimelineYear}`).removeClass("hidden"); + $("#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( () => { - $("#previous-timeline-item").on( - "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++; - - showTimelineYear(window.currentTimelineYear); - - const nextYear = window.currentTimelineYear + 1; - if ($(`#timeline-year-${window.currentTimelineYear}`).length === 0) { - $(event.currentTarget).attr("disabled", true); - } - } - ); + window.nextTimelineYear = () => { + window.currentTimelineYear++; + showTimelineYear(); + } + + window.previousTimelineYear = () => { + window.currentTimelineYear--; + showTimelineYear(); + } } -); +) diff --git a/users/migrations/0008_alter_user_rsvp_lectures.py b/users/migrations/0008_alter_user_rsvp_lectures.py new file mode 100644 index 0000000..f2168ae --- /dev/null +++ b/users/migrations/0008_alter_user_rsvp_lectures.py @@ -0,0 +1,19 @@ +# 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í'), + ), + ] diff --git a/users/models.py b/users/models.py index eca7b68..bb042e1 100644 --- a/users/models.py +++ b/users/models.py @@ -32,7 +32,7 @@ class User(pirates_models.AbstractUser): "lectures.Lecture", blank=True, related_name="rsvp_users", - verbose_name="Zaregistrované lekce", + verbose_name="Zaregistrovaná školení", ) def set_unusable_password(self) -> None: -- GitLab