diff --git a/galerie/urls.py b/galerie/urls.py index 4d1e8f24..4af34ca1 100644 --- a/galerie/urls.py +++ b/galerie/urls.py @@ -1,12 +1,13 @@ # coding: utf-8 from django.urls import path +from seminar.utils import org_required from . import views urlpatterns = [ path('/', views.nahled), path('//', views.detail), - path('/new/', views.new_galerie), + path('/new/', org_required(views.new_galerie)), path('/plus//', views.plus_galerie), path('/minus//', views.minus_galerie), ] diff --git a/korektury/urls.py b/korektury/urls.py index 77bc686d..2de95918 100644 --- a/korektury/urls.py +++ b/korektury/urls.py @@ -1,12 +1,10 @@ from django.urls import path -from django.contrib.auth.decorators import user_passes_test +from seminar.utils import org_required from . import views -staff_member_required = user_passes_test(lambda u: u.is_staff) - urlpatterns = [ - path('korektury/', staff_member_required(views.KorekturyAktualniListView.as_view()), name='korektury-list'), - path('korektury/zastarale/', staff_member_required(views.KorekturyZastaraleListView.as_view()), name='korektury-list'), - path('korektury//', staff_member_required(views.KorekturyView.as_view()), name='korektury'), - path('korektury/help/', staff_member_required(views.KorekturyHelpView.as_view()), name='korektury-help'), + path('korektury/', org_required(views.KorekturyAktualniListView.as_view()), name='korektury-list'), + path('korektury/zastarale/', org_required(views.KorekturyZastaraleListView.as_view()), name='korektury-list'), + path('korektury//', org_required(views.KorekturyView.as_view()), name='korektury'), + path('korektury/help/', org_required(views.KorekturyHelpView.as_view()), name='korektury-help'), ] diff --git a/prednasky/urls.py b/prednasky/urls.py index e7890745..b55de7c3 100644 --- a/prednasky/urls.py +++ b/prednasky/urls.py @@ -1,14 +1,25 @@ from django.urls import path -from django.contrib.auth.decorators import user_passes_test +from seminar.utils import org_required, resitel_required from . import views -staff_member_required = user_passes_test(lambda u: u.is_staff) - urlpatterns = [ - path('prednasky/', views.newPrednaska), + path( + 'prednasky/', + resitel_required(views.newPrednaska) + ), path('prednasky/hotovo', views.Prednaska_hotovo), - path('prednasky/metaseznam_prednasek', staff_member_required(views.MetaSeznamListView.as_view()), name='metaseznam-list'), - path('prednasky/seznam_prednasek//export', staff_member_required(views.SeznamExportView), name='seznam-export'), - path('prednasky/seznam_prednasek//', staff_member_required(views.SeznamListView.as_view()), name='seznam-list'), -# path('korektury/help/', staff_member_required(views.KorekturyHelpView.as_view()), name='korektury-help'), + path( + 'prednasky/metaseznam_prednasek', + org_required(views.MetaSeznamListView.as_view()), + name='metaseznam-list'), + path( + 'prednasky/seznam_prednasek//export', + org_required(views.SeznamExportView), + name='seznam-export' + ), + path( + 'prednasky/seznam_prednasek//', + org_required(views.SeznamListView.as_view()), + name='seznam-list' + ), ] diff --git a/seminar/migrations/0088_perm_org_a_ucastnik.py b/seminar/migrations/0088_perm_org_a_ucastnik.py new file mode 100644 index 00000000..ca6190dd --- /dev/null +++ b/seminar/migrations/0088_perm_org_a_ucastnik.py @@ -0,0 +1,35 @@ +# Generated by Django 2.2.15 on 2020-09-05 10:10 +from django.db import migrations + + +def add_perms(apps, schema_editor): + ContentType = apps.get_model('contenttypes', 'ContentType') + User = apps.get_model('auth', 'User') + Permission = apps.get_model('auth', 'Permission') + Resitel = apps.get_model('seminar', 'Resitel') + + c = ContentType.objects.get_for_model(User) + org_perm = Permission.objects.filter(codename__exact='org').first() + if not org_perm: + org_perm = Permission.objects.create(codename='org', name='org', content_type=c) + resitel_perm = Permission.objects.filter(codename__exact='resitel').first() + if not resitel_perm: + resitel_perm = Permission.objects.create(codename='resitel', name='resitel', content_type=c) + for r in Resitel.objects.all(): + u = r.osoba.user + if u: + u.user_permissions.add(resitel_perm) + for org in User.objects.all(): + if org and org.is_staff: + org.user_permissions.add(org_perm) + + +class Migration(migrations.Migration): + + dependencies = [ + ('seminar', '0087_fix_polymorphism'), + ] + + operations = [ + migrations.RunPython(add_perms, migrations.RunPython.noop), + ] diff --git a/seminar/urls.py b/seminar/urls.py index e5fed60e..c2d6328d 100644 --- a/seminar/urls.py +++ b/seminar/urls.py @@ -1,11 +1,8 @@ from django.urls import path, include -from django.contrib.auth.decorators import user_passes_test +from django.contrib.auth.decorators import login_required from . import views, export -from .utils import staff_member_required +from .utils import org_required, resitel_required from django.views.generic.base import RedirectView -from django.contrib.auth import views as auth_views - -staff_member_required = user_passes_test(lambda u: u.is_staff) urlpatterns = [ # path('aktualni/temata/', views.TemataRozcestnikView), @@ -33,17 +30,17 @@ urlpatterns = [ ), path( 'soustredeni//seznam_ucastniku', - staff_member_required(views.SoustredeniUcastniciView.as_view()), + org_required(views.SoustredeniUcastniciView.as_view()), name='soustredeni_ucastnici' ), path( 'soustredeni//maily_ucastniku', - staff_member_required(views.SoustredeniMailyUcastnikuView.as_view()), + org_required(views.SoustredeniMailyUcastnikuView.as_view()), name='maily_ucastniku' ), path( 'soustredeni//export_ucastniku', - staff_member_required(views.soustredeniUcastniciExportView), + org_required(views.soustredeniUcastniciExportView), name='soustredeni_ucastnici_export' ), path( @@ -62,64 +59,101 @@ urlpatterns = [ #path('clanky/org/', views.ClankyOrganizatorView.as_view(), name='clanky_organizator'), # Aesop - path('aesop-export/mam-rocnik-.csv', export.ExportRocnikView.as_view(), name='seminar_export_rocnik'), - path('aesop-export/mam-sous-.csv', export.ExportSousView.as_view(), name='seminar_export_sous'), - path('aesop-export/index.csv', export.ExportIndexView.as_view(), name='seminar_export_index'), + path( + 'aesop-export/mam-rocnik-.csv', + org_required(export.ExportRocnikView.as_view()), + name='seminar_export_rocnik' + ), + path( + 'aesop-export/mam-sous-.csv', + org_required(export.ExportSousView.as_view()), + name='seminar_export_sous' + ), + path( + 'aesop-export/index.csv', + org_required(export.ExportIndexView.as_view()), + name='seminar_export_index' + ), # Stranky viditelne pouze pro orgy: path( - 'rocnik//vysledkovka.tex', - staff_member_required(views.RocnikVysledkovkaView.as_view()), - name='seminar_rocnik_vysledkovka' + 'rocnik//vysledkovka.tex', + org_required(views.RocnikVysledkovkaView.as_view()), + name='seminar_rocnik_vysledkovka' ), - path('cislo/./vysledkovka.tex', - staff_member_required(views.CisloVysledkovkaView.as_view()), - name='seminar_cislo_vysledkovka' + path( + 'cislo/./vysledkovka.tex', + org_required(views.CisloVysledkovkaView.as_view()), + name='seminar_cislo_vysledkovka' + ), + path( + 'cislo/./obalky.pdf', + org_required(views.cisloObalkyView), + name='seminar_cislo_obalky' + ), + path( + 'cislo/./tituly.tex', + org_required(views.TitulyView), + name='seminar_cislo_titul' + ), + path( + 'stav', + org_required(views.StavDatabazeView), + name='stav_databaze' + ), + path( + 'cislo/./obalkovani', + org_required(views.ObalkovaniView.as_view()), + name='seminar_cislo_resitel_obalkovani' + ), + path( + 'soustredeni//obalky.pdf', + org_required(views.soustredeniObalkyView), + name='seminar_soustredeni_obalky' + ), + path( + 'org/vloz_body//', + org_required(views.VlozBodyView.as_view()), + name='seminar_org_vlozbody' ), - path('cislo/./obalky.pdf', - staff_member_required(views.cisloObalkyView), name='seminar_cislo_obalky'), - - path('cislo/./tituly.tex', - staff_member_required(views.TitulyView), name='seminar_cislo_titul'), - path('stav', - staff_member_required(views.StavDatabazeView), name='stav_databaze'), - path('cislo/./obalkovani', - staff_member_required(views.ObalkovaniView.as_view()), name='seminar_cislo_resitel_obalkovani'), - path('soustredeni//obalky.pdf', - staff_member_required(views.soustredeniObalkyView), name='seminar_soustredeni_obalky'), - - path('org/vloz_body//', - staff_member_required(views.VlozBodyView.as_view()),name='seminar_org_vlozbody'), # příprava na nestatický orgorozcestník - path('org/rozcestnik/', - staff_member_required(views.OrgoRozcestnikView.as_view()),name='seminar_org_rozcestnik'), + path( + 'org/rozcestnik/', + org_required(views.OrgoRozcestnikView.as_view()), + name='seminar_org_rozcestnik' + ), + path('prihlaska/',views.prihlaskaView, name='seminar_prihlaska'), path('login/', views.LoginView.as_view(), name='login'), path('logout/', views.LogoutView.as_view(), name='logout'), - path('resitel/', views.ResitelView.as_view(), name='seminar_resitel'), + path('resitel/', resitel_required(views.ResitelView.as_view()), name='seminar_resitel'), path('reset_password/', views.PasswordResetView.as_view(), name='reset_password'), path('change_password/', views.PasswordChangeView.as_view(), name='change_password'), path('reset_password_done/', views.PasswordResetDoneView.as_view(), name='reset_password_done'), path('reset_password_confirm///', views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'), path('reset_password_complete/', views.PasswordResetCompleteView.as_view(), name='reset_password_complete'), - path('resitel_edit', views.resitelEditView, name='seminar_resitel_edit'), + path( + 'resitel_edit', + login_required(views.resitelEditView, login_url='/login/'), + name='seminar_resitel_edit' + ), # Obecný view na profil -- orgům dá rozcestník, řešitelům jejich stránku path('profil/', views.profilView, name='profil'), # Autocomplete path('autocomplete/skola/',views.SkolaAutocomplete.as_view(), name='autocomplete_skola'), - path('autocomplete/resitel/',views.ResitelAutocomplete.as_view(), name='autocomplete_resitel'), + path('autocomplete/resitel/', org_required(views.ResitelAutocomplete.as_view()), name='autocomplete_resitel'), path('autocomplete/problem/odevzdatelny',views.OdevzdatelnyProblemAutocomplete.as_view(), name='autocomplete_problem_odevzdatelny'), - path('temp/add_solution', views.AddSolutionView.as_view(),name='seminar_vloz_reseni'), - path('temp/nahraj_reseni', views.NahrajReseniView.as_view(),name='seminar_nahraj_reseni'), + path('temp/add_solution', org_required(views.AddSolutionView.as_view()), name='seminar_vloz_reseni'), + path('temp/nahraj_reseni', resitel_required(views.NahrajReseniView.as_view()), name='seminar_nahraj_reseni'), path('', views.TitulniStranaView.as_view(), name='titulni_strana'), # Ceka na autocomplete v3 # path('autocomplete/organizatori/', - # staff_member_required(views.OrganizatorAutocomplete.as_view()), + # org_member_required(views.OrganizatorAutocomplete.as_view()), # name='seminar_autocomplete_organizator') diff --git a/seminar/utils.py b/seminar/utils.py index 9a442127..f4e38779 100644 --- a/seminar/utils.py +++ b/seminar/utils.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import datetime -from django.contrib.auth.decorators import user_passes_test +from django.contrib.auth.decorators import permission_required from html.parser import HTMLParser from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist @@ -9,7 +9,8 @@ from django.core.exceptions import ObjectDoesNotExist import seminar.models as m import seminar.treelib as t -staff_member_required = user_passes_test(lambda u: u.is_staff) +org_required = permission_required('auth.org', raise_exception=True) +resitel_required = permission_required('auth.resitel', raise_exception=True) class FirstTagParser(HTMLParser): diff --git a/seminar/views/utils.py b/seminar/views/utils.py index 3869ffd4..1fa28827 100644 --- a/seminar/views/utils.py +++ b/seminar/views/utils.py @@ -6,8 +6,6 @@ from html.parser import HTMLParser import seminar.models as m -staff_member_required = user_passes_test(lambda u: u.is_staff) - class FirstTagParser(HTMLParser): def __init__(self, *args, **kwargs): self.firstTag = None diff --git a/seminar/views/views_all.py b/seminar/views/views_all.py index cae17b77..9e77341d 100644 --- a/seminar/views/views_all.py +++ b/seminar/views/views_all.py @@ -1,6 +1,6 @@ # coding:utf-8 -from django.shortcuts import get_object_or_404, render +from django.shortcuts import get_object_or_404, render, redirect from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse from django.urls import reverse,reverse_lazy from django.core.exceptions import PermissionDenied, ObjectDoesNotExist @@ -13,7 +13,7 @@ from django.views.generic.edit import FormView, CreateView from django.views.generic.base import TemplateView from django.contrib.auth import authenticate, login, get_user_model, logout from django.contrib.auth import views as auth_views -from django.contrib.auth.models import User +from django.contrib.auth.models import User, Permission from django.contrib.auth.mixins import LoginRequiredMixin from django.db import transaction @@ -1212,6 +1212,8 @@ def prihlaskaView(request): password=fcd['password'], email = fcd['email']) u.save() + resitel_perm = Permission.objects.filter(codename__exact='resitel').first() + u.user_permissions.add(resitel_perm) o = Osoba( jmeno = fcd['jmeno'], @@ -1311,10 +1313,9 @@ class PasswordChangeView(auth_views.PasswordChangeView): # Jen hloupé rozhazovátko def profilView(request): user = request.user - # FIXME: správná oprávnění - if user.has_perm('org'): + if user.has_perm('auth.org'): return OrgoRozcestnikView.as_view()(request) - if user.has_perm('ucastnik'): + if user.has_perm('auth.resitel'): return ResitelView.as_view()(request) else: return LoginView.as_view()(request)