Skip to content

Commit

Permalink
Merge branch 'feature/1049-300-autorow' into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
mpasternak committed May 18, 2021
2 parents 79ce827 + 86cb7d1 commit 3cbe5e6
Show file tree
Hide file tree
Showing 22 changed files with 690 additions and 41 deletions.
4 changes: 4 additions & 0 deletions HISTORY.rst
Expand Up @@ -6,6 +6,10 @@ Historia zmian
202105.64
---------

* edycja autorów może odbywać się niezależnie od edycji "głównego" rekordu
(#1049),
* ograniczenie maksymalnej liczby autorów edytowanej razem z
formularzem rekordu do 25,
* lepszy komponent dla określania uprawnień w module administratora (#1048),
* wyszukiwanie po DOI w multiwyszukiwarce, module redagowania, globalnym
wyszukiwaniu (b/n),
Expand Down
2 changes: 1 addition & 1 deletion requirements.in
Expand Up @@ -59,7 +59,7 @@ progressbar2
dbfread
djangorestframework==3.11.0
markdown==3.2.1
django-admin-sortable2==0.7.6
django-admin-sortable2==1.0
cssmin==0.2.0
rjsmin==1.1.0
django-import-export==2.5.0
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Expand Up @@ -33,7 +33,7 @@ dbfread==2.0.7 # via -r requirements.in
defusedxml==0.6.0 # via cairosvg, odfpy
diff-match-patch==20200713 # via django-import-export
dj-pagination==2.4.0 # via -r requirements.in
django-admin-sortable2==0.7.6 # via -r requirements.in
django-admin-sortable2==1.0 # via -r requirements.in
django-admin-tools==0.9.0 # via -r requirements.in
django-appconf==1.0.3 # via django-compressor
django-autocomplete-light==3.8.1 # via -r requirements.in, django-multiseek
Expand Down
2 changes: 2 additions & 0 deletions src/bpp/admin/__init__.py
Expand Up @@ -36,10 +36,12 @@
from .uczelnia import UczelniaAdmin # NOQA
from .wydawca import WydawcaAdmin # noqa
from .wydawnictwo_ciagle import Wydawnictwo_CiagleAdmin # noqa
from .wydawnictwo_ciagle_autor import Wydawnictwo_Ciagle_Autor_Admin # noqa
from .wydawnictwo_zwarte import ( # noqa
Wydawnictwo_ZwarteAdmin,
Wydawnictwo_ZwarteAdmin_Baza,
)
from .wydawnictwo_zwarte_autor import Wydawnictwo_Zwarte_Autor_Admin # noqa
from .wydzial import WydzialAdmin # noqa

from django.contrib import admin
Expand Down
73 changes: 48 additions & 25 deletions src/bpp/admin/core.py
Expand Up @@ -4,17 +4,18 @@
from dal import autocomplete
from dal_select2.fields import Select2ListCreateChoiceField
from django import forms
from django.contrib import admin
from django.db.models.fields import BLANK_CHOICE_DASH
from django.forms.widgets import HiddenInput

from django.contrib import admin

from bpp.jezyk_polski import warianty_zapisanego_nazwiska
from bpp.models import (
Jednostka,
Autor,
Dyscyplina_Naukowa,
Jednostka,
Typ_Odpowiedzialnosci,
Uczelnia,
Dyscyplina_Naukowa,
)

# Proste tabele
Expand Down Expand Up @@ -42,28 +43,16 @@ def get_first_typ_odpowiedzialnosci():
return Typ_Odpowiedzialnosci.objects.filter(skrot="aut.").first()


def generuj_inline_dla_autorow(baseModel, include_dyscyplina=True):
class baseModel_AutorFormset(forms.BaseInlineFormSet):
def clean(self):
# get forms that actually have valid data
percent = Decimal("0.00")
for form in self.forms:
try:
if form.cleaned_data:
percent += form.cleaned_data.get(
"procent", Decimal("0.00")
) or Decimal("0.00")
except AttributeError:
# annoyingly, if a subform is invalid Django explicity raises
# an AttributeError for cleaned_data
pass
if percent > Decimal("100.00"):
raise forms.ValidationError(
"Liczba podanych procent odpowiedzialności przekracza 100.0"
)

def generuj_formularz_dla_autorow(
baseModel, include_rekord=False, include_dyscyplina=True
):
class baseModel_AutorForm(forms.ModelForm):

if include_rekord:
rekord = forms.ModelChoiceField(
widget=HiddenInput, queryset=baseModel.rekord.get_queryset()
)

autor = forms.ModelChoiceField(
queryset=Autor.objects.all(),
widget=autocomplete.ModelSelect2(url="bpp:autor-autocomplete"),
Expand Down Expand Up @@ -167,8 +156,36 @@ class Meta:
"procent",
"kolejnosc",
]
if include_rekord:
fields = [
"rekord",
] + fields

model = baseModel
widgets = {"kolejnosc": HiddenInput}
widgets = {"kolejnosc": HiddenInput, "rekord": HiddenInput}

return baseModel_AutorForm


def generuj_inline_dla_autorow(baseModel, include_dyscyplina=True):
class baseModel_AutorFormset(forms.BaseInlineFormSet):
def clean(self):
# get forms that actually have valid data
percent = Decimal("0.00")
for form in self.forms:
try:
if form.cleaned_data:
percent += form.cleaned_data.get(
"procent", Decimal("0.00")
) or Decimal("0.00")
except AttributeError:
# annoyingly, if a subform is invalid Django explicity raises
# an AttributeError for cleaned_data
pass
if percent > Decimal("100.00"):
raise forms.ValidationError(
"Liczba podanych procent odpowiedzialności przekracza 100.0"
)

baseClass = admin.StackedInline
extraRows = 0
Expand All @@ -182,7 +199,9 @@ class Meta:
class baseModel_AutorInline(baseClass):
model = baseModel
extra = extraRows
form = baseModel_AutorForm
form = generuj_formularz_dla_autorow(
baseModel, include_rekord=False, include_dyscyplina=include_dyscyplina
)
formset = baseModel_AutorFormset
sortable_field_name = "kolejnosc"
sortable_excludes = [
Expand All @@ -191,6 +210,10 @@ class baseModel_AutorInline(baseClass):
"afiliuje",
]

# Maksymalna ilosć autorów edytowanych w ramach formularza. Pozostałych
# autorów nalezy edytować przez opcję "Edycja autorów"
max_num = 25

return baseModel_AutorInline


Expand Down
11 changes: 11 additions & 0 deletions src/bpp/admin/helpers.py
@@ -1,5 +1,6 @@
# -*- encoding: utf-8 -*-

from urllib.parse import parse_qs
from urllib.parse import quote as urlquote

from django import forms
Expand Down Expand Up @@ -421,3 +422,13 @@ def sprobuj_wgrac_do_pbn(request, obj):
f"Dane w PBN dla rekordu {link_do_obiektu(obj)} zostały zaktualizowane. "
f'<a target=_blank href="{obj.link_do_pbn()}">Kliknij tutaj, aby otworzyć w PBN</a>. ',
)


def get_rekord_id_from_GET_qs(request):
flt = request.GET.get("_changelist_filters", "?")
data = parse_qs(flt) # noqa
if "rekord__id__exact" in data:
try:
return int(data.get("rekord__id__exact")[0])
except (ValueError, TypeError):
pass
135 changes: 135 additions & 0 deletions src/bpp/admin/wydawnictwo_autor_base.py
@@ -0,0 +1,135 @@
from adminsortable2.admin import SortableAdminMixin
from django.http import HttpResponseRedirect
from django.urls import reverse

from django.contrib import admin
from django.contrib.admin.templatetags.admin_urls import add_preserved_filters

from django.utils.safestring import mark_safe
from django.utils.text import Truncator

from bpp.admin.core import generuj_formularz_dla_autorow
from bpp.admin.helpers import get_rekord_id_from_GET_qs


class Wydawnictwo_Autor_Base(SortableAdminMixin, admin.ModelAdmin):

# Wartosci do ustawienia dla developera:

klasa_autora = None # Wydawnictwo_Ciagle_Autor
base_rekord_class = None # Wydawnictwo_Ciagle
change_list_template = None # "admin/bpp/wydawnictwo_ciagle_autor/change_list.html"

# Poniżej nie zmieniamy

show_full_result_count = False

ordering = ["kolejnosc"]
list_select_related = [
"rekord",
"jednostka",
"autor",
"jednostka__wydzial",
"typ_odpowiedzialnosci",
]
list_display = [
"rekord_short",
"autor",
"jednostka",
"zapisany_jako",
"typ_odpowiedzialnosci",
"afiliuje",
"zatrudniony",
"upowaznienie_pbn",
# "procent",
"kolejnosc",
]
list_filter = [
"zatrudniony",
"afiliuje",
"upowaznienie_pbn",
]
search_fields = [
"rekord__tytul_oryginalny",
"rekord__rok",
"jednostka__nazwa",
"autor__nazwisko",
"autor__imiona",
]

@property
def form(self):
return generuj_formularz_dla_autorow(
self.klasa_autora, include_dyscyplina=True, include_rekord=True
)

# @admin.display(description="Rekord", ordering="rekord__tytul_oryginalny")
def rekord_short(self, obj):
return mark_safe(Truncator(obj.rekord.tytul_oryginalny).chars(100))

rekord_short.short_description = "Rekord"
rekord_short.ordering = "rekord__tytul_oryginalny"

list_per_page = 500

def changelist_view(self, request, extra_context=None):
if extra_context is None:
extra_context = {}

# Jeżeli jest podany parametr z ID rekordu w filtrowaniu, to można
# przekazać go do templatki celem pokazania przycisku "Edycja rekordu"
v = None
if request.GET.get("rekord__id__exact"):
v = request.GET.get("rekord__id__exact")
try:
extra_context["rekord_id"] = int(v)
try:
rec = self.base_rekord_class.objects.get(pk=int(v))
extra_context["rekord"] = rec
except BaseException:
pass
except (ValueError, TypeError):
pass

return super(Wydawnictwo_Autor_Base, self).changelist_view(
request=request, extra_context=extra_context
)

@staticmethod
def get_extra_model_filters(request):
if request.POST.get("rekord_id"):
return {"rekord__id__iexact": request.POST.get("rekord_id")}
return {}

def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "rekord":
# setting the user from the request object
# kwargs["initial"] = 55 # request.user.id
# making the field readonly
kwargs["disabled"] = True
kwargs["initial"] = get_rekord_id_from_GET_qs(request)
return super().formfield_for_foreignkey(db_field, request, **kwargs)

def get_changeform_initial_data(self, request):
ret = super(Wydawnictwo_Autor_Base, self).get_changeform_initial_data(request)
rekord_id = get_rekord_id_from_GET_qs(request)
# ret["rekord_pk"] = rekord_id
ret["rekord"] = rekord_id
return ret

def _response_post_save(self, request, obj):
opts = self.model._meta
if self.has_view_or_change_permission(request):
post_url = reverse(
"admin:%s_%s_changelist" % (opts.app_label, opts.model_name),
current_app=self.admin_site.name,
)
preserved_filters = self.get_preserved_filters(request)
if "rekord__id__exact" not in preserved_filters:
preserved_filters += f"rekord__id__exact={obj.rekord.pk}"
post_url = add_preserved_filters(
{"preserved_filters": preserved_filters, "opts": opts}, post_url
)
else:
post_url = reverse("admin:index", current_app=self.admin_site.name)
return HttpResponseRedirect(post_url)
15 changes: 15 additions & 0 deletions src/bpp/admin/wydawnictwo_ciagle_autor.py
@@ -0,0 +1,15 @@
# -*- encoding: utf-8 -*-


from django.contrib import admin

from bpp.admin.wydawnictwo_autor_base import Wydawnictwo_Autor_Base
from bpp.models import Wydawnictwo_Ciagle
from bpp.models.wydawnictwo_ciagle import Wydawnictwo_Ciagle_Autor


@admin.register(Wydawnictwo_Ciagle_Autor)
class Wydawnictwo_Ciagle_Autor_Admin(Wydawnictwo_Autor_Base):
klasa_autora = Wydawnictwo_Ciagle_Autor
base_rekord_class = Wydawnictwo_Ciagle
change_list_template = "admin/bpp/wydawnictwo_ciagle_autor/change_list.html"
14 changes: 14 additions & 0 deletions src/bpp/admin/wydawnictwo_zwarte_autor.py
@@ -0,0 +1,14 @@
# -*- encoding: utf-8 -*-


from django.contrib import admin

from bpp.admin.wydawnictwo_autor_base import Wydawnictwo_Autor_Base
from bpp.models import Wydawnictwo_Zwarte, Wydawnictwo_Zwarte_Autor


@admin.register(Wydawnictwo_Zwarte_Autor)
class Wydawnictwo_Zwarte_Autor_Admin(Wydawnictwo_Autor_Base):
klasa_autora = Wydawnictwo_Zwarte_Autor
base_rekord_class = Wydawnictwo_Zwarte
change_list_template = "admin/bpp/wydawnictwo_zwarte_autor/change_list.html"
15 changes: 13 additions & 2 deletions src/bpp/models/abstract.py
Expand Up @@ -486,14 +486,14 @@ def clean(self):
# - musi istnieć takie przypisanie autora do dyscypliny dla danego roku
if self.dyscyplina_naukowa is not None:

if self.rekord is None:
if self.rekord_id is None:
raise ValidationError(
{
"dyscyplina_naukowa": "Określono dyscyplinę naukową, ale brak publikacji nadrzędnej. "
}
)

if self.rekord is not None and self.rekord.rok is None:
if self.rekord_id is not None and self.rekord.rok is None:
raise ValidationError(
{
"dyscyplina_naukowa": "Publikacja nadrzędna nie ma określonego roku."
Expand All @@ -514,6 +514,17 @@ def clean(self):
}
)

# Na tym etapie rekord musi być ustalony:
ValErrRek = ValidationError(
"Rekord nadrzędny (pole: rekord) musi być ustalone. "
)
if hasattr(self, "rekord"):
if self.rekord is None:
raise ValErrRek
else:
if self.rekord_id is None:
raise ValErrRek

# --- Walidacja procentów ---
# Znajdź inne obiekty z tego rekordu, które są już w bazie danych, ewentualnie
# utrudniając ich zapisanie w sytuacji, gdyby ilość procent przekroczyła 100:
Expand Down

0 comments on commit 3cbe5e6

Please sign in to comment.