diff --git a/.gitignore b/.gitignore
index e06f8dbd963dde805c2ee4be219a32cd4d0deacd..8220b2e02a0e7b76565b2e92d9ef300a126089f5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,5 +3,7 @@ __pycache__/
 webpack-stats.json
 staticfiles
 node_modules
-shared/static/shared/*.{js,css,txt}
+shared/static/shared/*.js
+shared/static/shared/*.css
+shared/static/shared/*.txt
 media/*
diff --git a/gunicorn.conf.py b/gunicorn.conf.py
new file mode 100644
index 0000000000000000000000000000000000000000..16484fd52069292cf24727fbf8e393ac8583608e
--- /dev/null
+++ b/gunicorn.conf.py
@@ -0,0 +1,7 @@
+bind = "0.0.0.0:8000"
+accesslog = "-"
+workers = 1
+max_requests = 1000
+max_requests_jitter = 10
+timeout = 60
+graceful_timeout = 60
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
index fd4694f6e5dc809620c87710b1ab1815def7b236..5825868d479d33285ac75971ddc4c1351be9ae3a 100644
--- 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
@@ -1,44 +1,77 @@
 # Generated by Django 4.1.4 on 2023-05-09 19:17
 
-from django.db import migrations, models
 import django.db.models.deletion
+from django.db import migrations, models
 
 
 class Migration(migrations.Migration):
-
     dependencies = [
-        ('auth', '0012_alter_user_first_name_max_length'),
-        ('lectures', '0014_alter_lecture_options_alter_lecturelector_username'),
+        ("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í'},
+            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'),
+            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'),
+            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í'),
+            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í'),
+            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í'),
+            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/migrations/0016_alter_lecture_groups.py b/lectures/migrations/0016_alter_lecture_groups.py
new file mode 100644
index 0000000000000000000000000000000000000000..8d24a0317e452eb478347e68b7aaa68c15683017
--- /dev/null
+++ b/lectures/migrations/0016_alter_lecture_groups.py
@@ -0,0 +1,23 @@
+# Generated by Django 4.1.4 on 2023-05-25 16:21
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("lectures", "0015_alter_lecture_options_alter_lecture_type_and_more"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="lecture",
+            name="groups",
+            field=models.ManyToManyField(
+                blank=True,
+                help_text="Pokud nevybereš žádné skupiny, školení je dostupné všem.",
+                related_name="lectures",
+                to="lectures.lecturegroup",
+                verbose_name="Výukové skupiny",
+            ),
+        ),
+    ]
diff --git a/lectures/models.py b/lectures/models.py
index fc7e1d655dd31c2a77fcb4e65fb82ff3cbf6f048..08254a47d7869ecad2707b2acd052f9ed24615a7 100644
--- a/lectures/models.py
+++ b/lectures/models.py
@@ -58,6 +58,7 @@ class Lecture(NameStrMixin, models.Model):
         blank=True,
         related_name="lectures",
         verbose_name="Výukové skupiny",
+        help_text="Pokud nevybereš žádné skupiny, školení je dostupné všem.",
     )
 
     type = models.CharField(
@@ -178,15 +179,26 @@ class LectureMaterial(NameStrMixin, models.Model):
     )
 
     def clean(self) -> None:
-        BOTH_FILE_AND_LINK_DEFINED_ERROR = (
+        BOTH_FILE_AND_LINK_DEFINED = (
             "Definuj prosím pouze odkaz, nebo soubor. Nemůžeš mít oboje najednou."
         )
+        NEITHER_FILE_NOR_LINK_DEFINED = (
+            "Definuj prosím odkaz, nebo soubor. Aspoň jedna hodnota musí být vyplněna."
+        )
+
+        if not self.file and not self.link:
+            raise ValidationError(
+                {
+                    "link": NEITHER_FILE_NOR_LINK_DEFINED,
+                    "file": NEITHER_FILE_NOR_LINK_DEFINED,
+                }
+            )
 
         if self.file and self.link:
             raise ValidationError(
                 {
-                    "link": BOTH_FILE_AND_LINK_DEFINED_ERROR,
-                    "file": BOTH_FILE_AND_LINK_DEFINED_ERROR,
+                    "link": BOTH_FILE_AND_LINK_DEFINED,
+                    "file": BOTH_FILE_AND_LINK_DEFINED,
                 }
             )
 
diff --git a/lectures/templates/lectures/view_group_lectures.html b/lectures/templates/lectures/view_group_lectures.html
index ec2891bfccc5a0591ca01c51c41ff5631df9cff8..2d835f32c283d7d5150ddf0ff713c00b16aae25f 100644
--- a/lectures/templates/lectures/view_group_lectures.html
+++ b/lectures/templates/lectures/view_group_lectures.html
@@ -27,17 +27,17 @@
                 <div class="switch overflow-x-auto">
                     <a
                         @click="toggleView('current_lectures')"
-                        class="switch__item"
+                        class="switch__item whitespace-nowrap"
                         :class="{'switch__item--active': isCurrentView('current_lectures')}"
                     >Aktuálně</a>
                     <a
                         @click="toggleView('timeline')"
-                        class="switch__item"
+                        class="switch__item whitespace-nowrap"
                         :class="{'switch__item--active': isCurrentView('timeline')}"
                     >Časová osa</a>
                     <a
                         @click="toggleView('recordings')"
-                        class="switch__item"
+                        class="switch__item whitespace-nowrap"
                         :class="{'switch__item--active': isCurrentView('recordings')}"
                     >Záznamy</a>
                 </div>
diff --git a/lectures/views.py b/lectures/views.py
index a7e3a51abdf11391fc6ec9b8c6e6d2ee126684c5..673ccba0a0513dc4a6ef40e275150b7cac4dadca 100644
--- a/lectures/views.py
+++ b/lectures/views.py
@@ -1,7 +1,5 @@
-#import calendar
+# import calendar
 import json
-#import locale
-
 from datetime import datetime
 from itertools import chain
 
@@ -15,6 +13,8 @@ from guardian.shortcuts import get_objects_for_user
 
 from .models import Lecture, LectureGroup
 
+# import locale
+
 
 def get_base_context(request) -> dict:
     return {
@@ -69,7 +69,7 @@ def view_group_lectures(request, group_id: int):
         .filter(
             groups=group,
             timestamp__gte=timestamp_starting_separator,
-            timestamp__lte=timestamp_ending_separator
+            timestamp__lte=timestamp_ending_separator,
         )
         .all()
     )
@@ -81,12 +81,9 @@ def view_group_lectures(request, group_id: int):
             current_lectures,
             (
                 get_objects_for_user(request.user, "lectures.view_lecture")
-                .filter(
-                    groups=group,
-                    timestamp__gte=timestamp_ending_separator
-                )
+                .filter(groups=group, timestamp__gte=timestamp_ending_separator)
                 .all()
-            )
+            ),
         )
     )
 
@@ -108,10 +105,10 @@ def view_group_lectures(request, group_id: int):
         12: "Prosinec",
     }
 
-    #locale.setlocale(
-        #locale.LC_ALL,
-        #"cs_CZ.UTF-8"
-    #)
+    # locale.setlocale(
+    # locale.LC_ALL,
+    # "cs_CZ.UTF-8"
+    # )
 
     current_year = datetime.today().year
 
@@ -127,22 +124,22 @@ def view_group_lectures(request, group_id: int):
 
         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)
+                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)
+                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)
 
-    #locale.setlocale(
-        #locale.LC_ALL,
-        #""
-    #)
+    # locale.setlocale(
+    # locale.LC_ALL,
+    # ""
+    # )
 
     return render(
         request,
@@ -175,13 +172,10 @@ def view_lecture(request, lecture_id: int):
 
     related_group_id = request.GET.get("related_group_id")
 
-    if (
-        related_group_id is not None
-        and not (
-            get_objects_for_user(request.user, "lectures.view_lecture")
-            .filter(id=related_group_id)
-            .exists()
-        )
+    if related_group_id is not None and not (
+        get_objects_for_user(request.user, "lectures.view_lecture")
+        .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.
diff --git a/run.sh b/run.sh
old mode 100644
new mode 100755
diff --git a/users/migrations/0008_alter_user_rsvp_lectures.py b/users/migrations/0008_alter_user_rsvp_lectures.py
index f2168aef2409ccbd663c80c1652982709a59bdb9..2998ee970ebf92455f33fb86574419170e977654 100644
--- a/users/migrations/0008_alter_user_rsvp_lectures.py
+++ b/users/migrations/0008_alter_user_rsvp_lectures.py
@@ -4,16 +4,20 @@ 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'),
+        ("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í'),
+            model_name="user",
+            name="rsvp_lectures",
+            field=models.ManyToManyField(
+                blank=True,
+                related_name="rsvp_users",
+                to="lectures.lecture",
+                verbose_name="Zaregistrovaná školení",
+            ),
         ),
     ]