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