diff --git a/lectures/admin.py b/lectures/admin.py index 6e9e288eadd8dddc9842a91cf092a7f368a819b0..e99d3583833c46a391558bbd24a1a94144b24848 100644 --- a/lectures/admin.py +++ b/lectures/admin.py @@ -1,6 +1,5 @@ from django.contrib import admin - -from shared.admin import MarkdownxGuardedModelAdmin +from markdownx.admin import MarkdownxModelAdmin from .forms import LectureGroupTypeFormset from .models import ( @@ -16,12 +15,12 @@ from .models import ( # Register your models here. -class IndexHiddenModelAdmin(MarkdownxGuardedModelAdmin): +class IndexHiddenModelAdmin(MarkdownxModelAdmin): def has_module_permission(self, request): return False -class LectureGroupAdmin(MarkdownxGuardedModelAdmin): +class LectureGroupAdmin(MarkdownxModelAdmin): autocomplete_fields = ("user_groups",) search_fields = ("name",) @@ -45,7 +44,7 @@ class LectureGroupTypeInline(admin.StackedInline): extra = 1 -class LectureAdmin(MarkdownxGuardedModelAdmin): +class LectureAdmin(MarkdownxModelAdmin): inlines = ( LectureGroupTypeInline, LectureRecordingInline, @@ -77,11 +76,11 @@ class LectureAdmin(MarkdownxGuardedModelAdmin): return display_string -class LectureCategoryAdmin(MarkdownxGuardedModelAdmin): +class LectureCategoryAdmin(MarkdownxModelAdmin): search_fields = ("name",) -class LectureLectorAdmin(MarkdownxGuardedModelAdmin): +class LectureLectorAdmin(MarkdownxModelAdmin): search_fields = ("name", "username") diff --git a/lectures/templates/lectures/view_group_lectures.html b/lectures/templates/lectures/view_group_lectures.html index 45678c8ab21b572e3f5ce9174ce3ee8a47dd62bd..0bd7b8e569c16b3d53c1d24641d2133c67c5e1fb 100644 --- a/lectures/templates/lectures/view_group_lectures.html +++ b/lectures/templates/lectures/view_group_lectures.html @@ -25,6 +25,11 @@ > <div class="flex justify-center mb-10"> <div class="switch overflow-x-auto"> + <a + @click="toggleView('recordings')" + class="switch__item whitespace-nowrap" + :class="{'switch__item--active': isCurrentView('recordings')}" + >Záznamy</a> <a @click="toggleView('current_lectures')" class="switch__item whitespace-nowrap" @@ -35,14 +40,58 @@ class="switch__item whitespace-nowrap" :class="{'switch__item--active': isCurrentView('timeline')}" >Časová osa</a> - <a - @click="toggleView('recordings')" - class="switch__item whitespace-nowrap" - :class="{'switch__item--active': isCurrentView('recordings')}" - >Záznamy</a> </div> </div> <div> + <template v-if="isCurrentView('recordings')"> + {% if past_lectures %} + <div class="flex flex-col gap-3"> + {% regroup past_lectures by category as lecture_categories %} + {% for category in lecture_categories %} + <div + class=" + flex flex-col gap-3 group justify-center p-4 cursor-pointer + + hover:bg-gray-100 + + __lecture-category + " + data-is-open="false" + > + <div class="flex justify-between items-center"> + <h2 class="text-3xl font-alt">{{ category.grouper }}</h2> + + <div> + <i + class=" + __lecture-category-opener + ico--chevron-down text-2xl + " + ></i> + </div> + </div> + + <noscript> + <ul class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4"> + {% for lecture in category.list %} + {% include "lectures/includes/lecture.html" with lecture=lecture group=group %} + {% endfor %} + </ul> + </noscript> + + <ul class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4 hidden __lecture-category-content"> + {% for lecture in category.list %} + {% include "lectures/includes/lecture.html" with lecture=lecture group=group %} + {% endfor %} + </ul> + </div> + {% endfor %} + </div> + {% else %} + <span class="text-gray-600">Žádné dostupné záznamy.</span> + {% endif %} + </template> + <template v-if="isCurrentView('current_lectures')"> {% if current_lectures %} <ul class="grid grid-cols-1 md:grid-cols-2 gap-4"> @@ -54,6 +103,7 @@ <span class="text-gray-600">Žádná dostupná aktuální školení.</span> {% endif %} </template> + <template v-if="isCurrentView('timeline')"> <div> <div class="head-alt-md mb-4 flex items-center justify-between"> @@ -120,24 +170,6 @@ </script> </div> </template> - <template v-if="isCurrentView('recordings')"> - {% if past_lectures %} - <div class="flex flex-col gap-3"> - {% regroup past_lectures by category as lecture_categories %} - {% for category in lecture_categories %} - <h2 class="text-3xl font-alt">{{ category.grouper }}</h2> - - <ul class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4"> - {% for lecture in category.list %} - {% include "lectures/includes/lecture.html" with lecture=lecture group=group %} - {% endfor %} - </ul> - {% endfor %} - </div> - {% else %} - <span class="text-gray-600">Žádné dostupné záznamy.</span> - {% endif %} - </template> </div> </ui-view-provider> </div> diff --git a/lectures/views.py b/lectures/views.py index 59cd78afc95d3c023626a06a020b6b0bad2a9966..c1961a545114126363a6da69f1cc0cee3c0138da 100644 --- a/lectures/views.py +++ b/lectures/views.py @@ -14,9 +14,8 @@ from django.utils import timezone from django.views.decorators.http import require_POST from django_downloadview import ObjectDownloadView from django_http_exceptions import HTTPExceptions -from guardian.shortcuts import get_objects_for_user -from .models import Lecture, LectureGroup, LectureMaterial +from .models import Lecture, LectureGroup, LectureLector, LectureMaterial class LectureMaterialFileDownloadView(ObjectDownloadView): @@ -60,7 +59,7 @@ def generate_auth_redirect(request) -> HttpResponseRedirect: def get_lectures(request, filter=None, get_exceptions: bool = True) -> tuple: - lectures = get_objects_for_user(request.user, "lectures.view_lecture") + lectures = Lecture.objects if filter is not None: lectures = lectures.filter(filter) @@ -68,9 +67,10 @@ def get_lectures(request, filter=None, get_exceptions: bool = True) -> tuple: if get_exceptions and not lectures.exists(): raise HTTPExceptions.NOT_FOUND + lectures = lectures.all() + if not ( - get_objects_for_user(request.user, "lectures.view_lecturegroup") - .filter( + LectureGroup.objects.filter( models.Q( id__in=( LectureGroup.objects.filter( @@ -104,8 +104,7 @@ def get_lectures(request, filter=None, get_exceptions: bool = True) -> tuple: def view_groups(request): lecture_groups = ( - get_objects_for_user(request.user, "lectures.view_lecturegroup") - .filter( + LectureGroup.objects.filter( ( models.Q(user_groups__in=request.user.groups.all()) | models.Q(user_groups=None) @@ -132,9 +131,7 @@ def view_groups(request): def view_group_lectures(request, group_id: int): - group = get_objects_for_user(request.user, "lectures.view_lecturegroup").filter( - id=group_id - ) + group = LectureGroup.objects.filter(id=group_id) group_id_exists = group.exists() @@ -159,22 +156,18 @@ def view_group_lectures(request, group_id: int): timestamp_ending_separator = timezone.now() + Lecture.is_current_ending_treshold past_lectures = ( - get_objects_for_user(request.user, "lectures.view_lecture") - .filter( + Lecture.objects.filter( lecture_group_types__group=group, timestamp__lt=timestamp_starting_separator, ) + .order_by("category") .all() ) - current_lectures = ( - get_objects_for_user(request.user, "lectures.view_lecture") - .filter( - lecture_group_types__group=group, - timestamp__gte=timestamp_starting_separator, - timestamp__lte=timestamp_ending_separator, - ) - .all() - ) + current_lectures = Lecture.objects.filter( + lecture_group_types__group=group, + timestamp__gte=timestamp_starting_separator, + timestamp__lte=timestamp_ending_separator, + ).all() calendar_data = [] all_lectures = list( @@ -182,12 +175,10 @@ def view_group_lectures(request, group_id: int): past_lectures, current_lectures, ( - get_objects_for_user(request.user, "lectures.view_lecture") - .filter( + Lecture.objects.filter( lecture_group_types__group=group, timestamp__gte=timestamp_ending_separator, - ) - .all() + ).all() ), ) ) @@ -272,11 +263,7 @@ def get_related_group_id(request): if not str(related_group_id).isnumeric(): raise HTTPExceptions.BAD_REQUEST - if not ( - get_objects_for_user(request.user, "lectures.view_lecturegroup") - .filter(id=related_group_id) - .exists() - ): + if not (LectureGroup.objects.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. related_group_id = None @@ -360,9 +347,7 @@ def search(request): def view_lector(request, id): - lector = get_object_or_404( - get_objects_for_user(request.user, "lectures.view_lecturelector"), id=id - ) + lector = get_object_or_404(LectureLector, id=id) lectures = get_lectures( request, models.Q(id__in=lector.lectures.all()), get_exceptions=False @@ -374,11 +359,7 @@ def view_lector(request, id): 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() - ): + if not (Lecture.objects.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 diff --git a/package-lock.json b/package-lock.json index ce73779d1e6fe369f75e3b0dca7919f8cfd3eb30..c666f3160a86514e8d3cb01cbdea05dbb0ed5941 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1283,9 +1283,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "funding": [ { "type": "github", @@ -1447,9 +1447,9 @@ } }, "node_modules/postcss": { - "version": "8.4.27", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.27.tgz", - "integrity": "sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==", + "version": "8.4.33", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz", + "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==", "funding": [ { "type": "opencollective", @@ -1465,7 +1465,7 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, diff --git a/requirements/base.txt b/requirements/base.txt index 3366e4140d2f54d37723e52eb6f50416259ad040..9115d8a6957a9722b87f776de8bac0d47f6be0e7 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -11,7 +11,6 @@ pirates==0.6.0 django-markdownx==4.0.0b1 django-environ==0.9.0 django-http-exceptions==1.4.0 -django-guardian==2.4.0 gql[requests]==3.4.1 requests==2.31.0 PyJWT==2.6.0 diff --git a/shared/admin.py b/shared/admin.py index a8fd3e7a1c340ff489022f303c29a36826d394e6..16ab4e9eec61ed030cafa6d8caa8b085190799c8 100644 --- a/shared/admin.py +++ b/shared/admin.py @@ -1,12 +1,6 @@ import enum from django.contrib import admin -from guardian.admin import GuardedModelAdmin -from markdownx.admin import MarkdownxModelAdmin - - -class MarkdownxGuardedModelAdmin(MarkdownxModelAdmin, GuardedModelAdmin): - pass class FieldsetInlineOrder(enum.Enum): diff --git a/static_src/view_group_lectures.js b/static_src/view_group_lectures.js index e60c9eb791e9ba1f4663431fae2d68c2a1a0c198..aa05271e51d2514cfb62ba47564d29f35b212d37 100644 --- a/static_src/view_group_lectures.js +++ b/static_src/view_group_lectures.js @@ -26,5 +26,34 @@ $(window).ready( window.currentTimelineYear--; showTimelineYear(); } + + $(".__lecture-category").on( + "click", + event => { + if (event.currentTarget.dataset.isOpen === 'true') { + $(event.currentTarget). + find(".__lecture-category-opener"). + addClass("ico--chevron-down"). + removeClass("ico--chevron-up") + + event.currentTarget.dataset.isOpen = 'false' + + $(event.currentTarget). + find(".__lecture-category-content"). + addClass("hidden") + } else { + $(event.currentTarget). + find(".__lecture-category-opener"). + removeClass("ico--chevron-down"). + addClass("ico--chevron-up") + + event.currentTarget.dataset.isOpen = 'true' + + $(event.currentTarget). + find(".__lecture-category-content"). + removeClass("hidden") + } + } + ) } ) diff --git a/ucebnice/settings/base.py b/ucebnice/settings/base.py index 96f9c481d307777d4abb2b64d2e16b4046e6e507..792f93dfc6b8cc8e2d71bfd935e081dee56ecbf0 100644 --- a/ucebnice/settings/base.py +++ b/ucebnice/settings/base.py @@ -52,7 +52,6 @@ INSTALLED_APPS = [ "django.contrib.messages", "django.contrib.staticfiles", "dbsettings", - "guardian", "markdownx", "pirates", "webpack_loader", @@ -131,7 +130,6 @@ AUTH_USER_MODEL = "users.User" AUTHENTICATION_BACKENDS = ( "oidc.auth.UcebniceOIDCAuthenticationBackend", "django.contrib.auth.backends.ModelBackend", - "guardian.backends.ObjectPermissionBackend", ) LOGIN_URL = "/oidc/authenticate/" diff --git a/users/admin.py b/users/admin.py index 128fc422e4ce148aaa75e58b4f4ef3bd3e2e9688..3772e66562cdf5a84df459c2325d65e192d7687d 100644 --- a/users/admin.py +++ b/users/admin.py @@ -1,11 +1,10 @@ from django.contrib import admin - -from shared.admin import MarkdownxGuardedModelAdmin +from markdownx.admin import MarkdownxModelAdmin from .models import User -class UserAdmin(MarkdownxGuardedModelAdmin): +class UserAdmin(MarkdownxModelAdmin): search_fields = ("first_name", "last_name", "email") diff --git a/users/models.py b/users/models.py index 49a91f105b367b8138566daf371a75b48eeb5438..259a6e1a1e92c651a3c93de41ca8be5245cf6414 100644 --- a/users/models.py +++ b/users/models.py @@ -30,10 +30,6 @@ class User(pirates_models.AbstractUser): verbose_name="E-mailová adresa", ) - def set_unusable_password(self) -> None: - # Purely for compatibility with Guardian - pass - def get_username(self) -> str: first_name = self.first_name