• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

iplweb / bpp / 69252c38-21b1-49f8-98a5-a21d59416a66

17 Feb 2025 01:27AM UTC coverage: 47.492% (+0.7%) from 46.838%
69252c38-21b1-49f8-98a5-a21d59416a66

push

circleci

mpasternak
Merge branch 'release/v202502.1156'

2 of 8 new or added lines in 3 files covered. (25.0%)

2233 existing lines in 114 files now uncovered.

16671 of 35103 relevant lines covered (47.49%)

1.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

50.43
src/bpp/admin/helpers.py
1
from urllib.parse import parse_qs
3✔
2
from urllib.parse import quote as urlquote
3✔
3

4
from django import forms
3✔
5
from django.db import models
3✔
6
from django.db.models import Q
3✔
7
from django.forms import BaseInlineFormSet
3✔
8
from django.forms.widgets import Textarea
3✔
9
from django.urls import reverse
3✔
10
from sentry_sdk import capture_exception
3✔
11

12
from import_common.normalization import normalize_isbn
3✔
13
from pbn_api.exceptions import (
3✔
14
    AccessDeniedException,
15
    NeedsPBNAuthorisationException,
16
    PKZeroExportDisabled,
17
    PraceSerwisoweException,
18
    SameDataUploadedRecently,
19
)
20
from pbn_api.models import SentData
3✔
21

22
from django.contrib import messages
3✔
23
from django.contrib.admin.utils import quote
3✔
24
from django.contrib.contenttypes.models import ContentType
3✔
25

26
from django.utils.html import format_html
3✔
27
from django.utils.safestring import mark_safe
3✔
28

29
from bpp import const
3✔
30
from bpp.const import PBN_MAX_ROK, PBN_MIN_ROK
3✔
31
from bpp.models import Status_Korekty
3✔
32
from bpp.models.sloty.core import ISlot
3✔
33
from bpp.models.sloty.exceptions import CannotAdapt
3✔
34

35
CHARMAP_SINGLE_LINE = forms.TextInput(
3✔
36
    attrs={"class": "charmap", "style": "width: 500px"}
37
)
38

39

40
# Pomocnik dla klasy ModelZMetryczka
41

42

43
class ZapiszZAdnotacjaMixin:
3✔
44
    readonly_fields = ("ostatnio_zmieniony",)
3✔
45

46

47
class AdnotacjeZDatamiMixin:
3✔
48
    readonly_fields = ("utworzono", "ostatnio_zmieniony", "id")
3✔
49

50

51
class AdnotacjeZDatamiOrazPBNMixin:
3✔
52
    readonly_fields = (
3✔
53
        "utworzono",
54
        "ostatnio_zmieniony",
55
        "id",
56
        "pbn_id",
57
    )
58

59

60
ADNOTACJE_FIELDSET = (
3✔
61
    "Adnotacje",
62
    {
63
        "classes": ("grp-collapse grp-closed",),
64
        "fields": (ZapiszZAdnotacjaMixin.readonly_fields + ("adnotacje",)),
65
    },
66
)
67

68
ADNOTACJE_Z_DATAMI_FIELDSET = (
3✔
69
    "Adnotacje",
70
    {
71
        "classes": ("grp-collapse grp-closed",),
72
        "fields": AdnotacjeZDatamiMixin.readonly_fields + ("adnotacje",),
73
    },
74
)
75

76
ADNOTACJE_Z_DATAMI_ORAZ_PBN_FIELDSET = (
3✔
77
    "Adnotacje",
78
    {
79
        "classes": ("grp-collapse grp-closed",),
80
        "fields": AdnotacjeZDatamiOrazPBNMixin.readonly_fields + ("adnotacje",),
81
    },
82
)
83

84
OPENACCESS_FIELDSET = (
3✔
85
    "OpenAccess",
86
    {
87
        "classes": ("grp-collapse grp-closed",),
88
        "fields": (
89
            "openaccess_tryb_dostepu",
90
            "openaccess_licencja",
91
            "openaccess_wersja_tekstu",
92
            "openaccess_czas_publikacji",
93
            "openaccess_ilosc_miesiecy",
94
        ),
95
    },
96
)
97

98
DWA_TYTULY = (
3✔
99
    "tytul_oryginalny",
100
    "tytul",
101
)
102

103
MODEL_ZE_SZCZEGOLAMI = (
3✔
104
    "informacje",
105
    "szczegoly",
106
    "uwagi",
107
    "slowa_kluczowe",
108
    "slowa_kluczowe_eng",
109
    "strony",
110
    "tom",
111
)
112

113
MODEL_Z_ISSN = (
3✔
114
    "issn",
115
    "e_issn",
116
)
117

118
MODEL_Z_PBN_UID = ("pbn_uid",)
3✔
119

120
MODEL_Z_OPLATA_ZA_PUBLIKACJE = (
3✔
121
    "opl_pub_cost_free",
122
    "opl_pub_research_potential",
123
    "opl_pub_research_or_development_projects",
124
    "opl_pub_other",
125
    "opl_pub_amount",
126
)
127

128
MODEL_Z_OPLATA_ZA_PUBLIKACJE_FIELDSET = (
3✔
129
    "Opłata za publikację",
130
    {"classes": ("grp-collapse grp-closed",), "fields": MODEL_Z_OPLATA_ZA_PUBLIKACJE},
131
)
132

133

134
MODEL_Z_ISBN = (
3✔
135
    "isbn",
136
    "e_isbn",
137
)
138

139
MODEL_Z_WWW = (
3✔
140
    "www",
141
    "dostep_dnia",
142
    "public_www",
143
    "public_dostep_dnia",
144
)
145

146
MODEL_Z_PUBMEDID = ("pubmed_id", "pmc_id")
3✔
147

148
MODEL_Z_DOI = ("doi",)
3✔
149

150
MODEL_Z_LICZBA_CYTOWAN = ("liczba_cytowan",)
3✔
151

152
MODEL_Z_MIEJSCEM_PRZECHOWYWANIA = ("numer_odbitki",)
3✔
153

154
MODEL_Z_ROKIEM = ("rok",)
3✔
155

156
MODEL_TYPOWANY = (
3✔
157
    "jezyk",
158
    "jezyk_alt",
159
    "jezyk_orig",
160
    "typ_kbn",
161
)
162

163
MODEL_PUNKTOWANY_BAZA = (
3✔
164
    "punkty_kbn",
165
    "impact_factor",
166
    "index_copernicus",
167
    "punktacja_snip",
168
    "punktacja_wewnetrzna",
169
)
170

171
MODEL_PUNKTOWANY = MODEL_PUNKTOWANY_BAZA + ("weryfikacja_punktacji",)
3✔
172

173
MODEL_PUNKTOWANY_Z_KWARTYLAMI_BAZA = MODEL_PUNKTOWANY_BAZA + (
3✔
174
    "kwartyl_w_scopus",
175
    "kwartyl_w_wos",
176
)
177

178
MODEL_PUNKTOWANY_Z_KWARTYLAMI = MODEL_PUNKTOWANY_Z_KWARTYLAMI_BAZA + (
3✔
179
    "weryfikacja_punktacji",
180
)
181

182
MODEL_Z_INFORMACJA_Z = ("informacja_z",)
3✔
183

184
MODEL_Z_LICZBA_ZNAKOW_WYDAWNICZYCH = ("liczba_znakow_wydawniczych",)
3✔
185

186
MODEL_ZE_STATUSEM = ("status_korekty",)
3✔
187

188
MODEL_RECENZOWANY = ("recenzowana",)
3✔
189

190
MODEL_TYPOWANY_BEZ_CHARAKTERU_FIELDSET = (
3✔
191
    "Typ",
192
    {"classes": ("",), "fields": MODEL_TYPOWANY},
193
)
194

195
MODEL_TYPOWANY_FIELDSET = (
3✔
196
    "Typ",
197
    {"classes": ("",), "fields": ("charakter_formalny",) + MODEL_TYPOWANY},
198
)
199

200
MODEL_PUNKTOWANY_FIELDSET = (
3✔
201
    "Punktacja",
202
    {"classes": ("",), "fields": MODEL_PUNKTOWANY},
203
)
204

205
MODEL_PUNKTOWANY_WYDAWNICTWO_CIAGLE_FIELDSET = (
3✔
206
    "Punktacja",
207
    {
208
        "classes": ("",),
209
        "fields": MODEL_PUNKTOWANY_Z_KWARTYLAMI + ("uzupelnij_punktacje",),
210
    },
211
)
212

213

214
MODEL_OPCJONALNIE_NIE_EKSPORTOWANY_DO_API_FIELDSET = (
3✔
215
    "Eksport do API",
216
    {"classes": ("grp-collapse grp-closed",), "fields": ("nie_eksportuj_przez_api",)},
217
)
218

219
POZOSTALE_MODELE_FIELDSET = (
3✔
220
    "Pozostałe informacje",
221
    {
222
        "classes": ("",),
223
        "fields": MODEL_Z_INFORMACJA_Z + MODEL_ZE_STATUSEM + MODEL_RECENZOWANY,
224
    },
225
)
226

227
POZOSTALE_MODELE_WYDAWNICTWO_CIAGLE_FIELDSET = (
3✔
228
    "Pozostałe informacje",
229
    {
230
        "classes": ("",),
231
        "fields": MODEL_Z_LICZBA_ZNAKOW_WYDAWNICZYCH
232
        + MODEL_Z_INFORMACJA_Z
233
        + MODEL_ZE_STATUSEM
234
        + MODEL_RECENZOWANY,
235
    },
236
)
237

238
POZOSTALE_MODELE_WYDAWNICTWO_ZWARTE_FIELDSET = (
3✔
239
    "Pozostałe informacje",
240
    {
241
        "classes": ("",),
242
        "fields": MODEL_Z_LICZBA_ZNAKOW_WYDAWNICZYCH
243
        + MODEL_Z_INFORMACJA_Z
244
        + MODEL_ZE_STATUSEM
245
        + MODEL_RECENZOWANY,
246
    },
247
)
248

249
SERIA_WYDAWNICZA_FIELDSET = (
3✔
250
    "Seria wydawnicza",
251
    {
252
        "classes": ("grp-collapse grp-closed",),
253
        "fields": ("seria_wydawnicza", "numer_w_serii"),
254
    },
255
)
256

257
PRACA_WYBITNA_FIELDSET = (
3✔
258
    "Praca wybitna",
259
    {
260
        "classes": ("grp-collapse grp-closed",),
261
        "fields": ("praca_wybitna", "uzasadnienie_wybitnosci"),
262
    },
263
)
264

265
PRZED_PO_LISCIE_AUTOROW_FIELDSET = (
3✔
266
    "Dowolny tekst przed lub po liście autorów",
267
    {
268
        "classes": ("grp-collapse grp-closed",),
269
        "fields": ("tekst_przed_pierwszym_autorem", "tekst_po_ostatnim_autorze"),
270
    },
271
)
272

273
EKSTRA_INFORMACJE_WYDAWNICTWO_CIAGLE_FIELDSET = (
3✔
274
    "Ekstra informacje",
275
    {
276
        "classes": ("grp-collapse grp-closed",),
277
        "fields": MODEL_Z_PBN_UID
278
        + MODEL_Z_ISSN
279
        + MODEL_Z_WWW
280
        + MODEL_Z_PUBMEDID
281
        + MODEL_Z_DOI
282
        + MODEL_Z_LICZBA_CYTOWAN
283
        + MODEL_Z_MIEJSCEM_PRZECHOWYWANIA,
284
    },
285
)
286

287
EKSTRA_INFORMACJE_WYDAWNICTWO_ZWARTE_FIELDSET = (
3✔
288
    "Ekstra informacje",
289
    {
290
        "classes": ("grp-collapse grp-closed",),
291
        "fields": MODEL_Z_PBN_UID
292
        + MODEL_Z_ISSN
293
        + MODEL_Z_WWW
294
        + MODEL_Z_PUBMEDID
295
        + MODEL_Z_DOI
296
        + MODEL_Z_LICZBA_CYTOWAN
297
        + MODEL_Z_MIEJSCEM_PRZECHOWYWANIA,
298
    },
299
)
300

301
EKSTRA_INFORMACJE_DOKTORSKA_HABILITACYJNA_FIELDSET = (
3✔
302
    "Ekstra informacje",
303
    {
304
        "classes": ("grp-collapse grp-closed",),
305
        "fields": MODEL_Z_WWW
306
        + MODEL_Z_PUBMEDID
307
        + MODEL_Z_DOI
308
        + MODEL_Z_LICZBA_CYTOWAN
309
        + MODEL_Z_MIEJSCEM_PRZECHOWYWANIA,
310
    },
311
)
312

313

314
def js_openwin(url, handle, options):
3✔
315
    options = ",".join([f"{a}={b}" for a, b in list(options.items())])
×
316
    d = dict(url=url, handle=handle, options=options)
×
317
    return "window.open('%(url)s','\\%(handle)s','%(options)s')" % d
×
318

319

320
NIZSZE_TEXTFIELD_Z_MAPA_ZNAKOW = {
3✔
321
    models.TextField: {
322
        "widget": Textarea(attrs={"rows": 2, "cols": 90, "class": "charmap"})
323
    },
324
}
325

326

327
class DomyslnyStatusKorektyMixin:
3✔
328
    status_korekty = forms.ModelChoiceField(
3✔
329
        required=True,
330
        queryset=Status_Korekty.objects.all(),
331
        initial=lambda: Status_Korekty.objects.first(),
332
    )
333

334

335
class Wycinaj_W_z_InformacjiMixin:
3✔
336
    def clean_informacje(self):
3✔
UNCOV
337
        i = self.cleaned_data.get("informacje")
1✔
UNCOV
338
        if i:
1✔
339
            x = i.lower()
×
340
            n = 0
×
341
            if x.startswith("w:"):
×
342
                n = 2
×
343
            if x.startswith("w :"):
×
344
                n = 3
×
345
            if n:
×
346
                return i[n:].strip()
×
UNCOV
347
        return i
1✔
348

349

350
class LimitingFormset(BaseInlineFormSet):
3✔
351
    def get_queryset(self):
3✔
352
        if not hasattr(self, "_queryset_limited"):
×
353
            qs = super().get_queryset()
×
354
            self._queryset_limited = qs[:100]
×
355
        return self._queryset_limited
×
356

357

358
def link_do_obiektu(obj, friendly_name=None):
3✔
UNCOV
359
    opts = obj._meta
1✔
UNCOV
360
    obj_url = reverse(
1✔
361
        f"admin:{opts.app_label}_{opts.model_name}_change",
362
        args=(quote(obj.pk),),
363
        # current_app=self.admin_site.name,
364
    )
365
    # Add a link to the object's change form if the user can edit the obj.
UNCOV
366
    if friendly_name is None:
1✔
UNCOV
367
        friendly_name = mark_safe(obj)
1✔
UNCOV
368
    return format_html('<a href="{}">{}</a>', urlquote(obj_url), friendly_name)
1✔
369

370

371
def sprobuj_policzyc_sloty(request, obj):
3✔
UNCOV
372
    if obj.rok >= PBN_MIN_ROK and obj.rok <= PBN_MAX_ROK:
1✔
UNCOV
373
        try:
1✔
UNCOV
374
            ISlot(obj)
1✔
375
            messages.success(
×
376
                request,
377
                'Punkty dla dyscyplin dla "%s" będą mogły być obliczone.'
378
                % link_do_obiektu(obj),
379
            )
UNCOV
380
        except CannotAdapt as e:
1✔
UNCOV
381
            messages.error(
1✔
382
                request,
383
                'Nie można obliczyć punktów dla dyscyplin dla "%s": %s'
384
                % (link_do_obiektu(obj), e),
385
            )
386
    else:
387
        messages.warning(
1✔
388
            request,
389
            'Punkty dla dyscyplin dla "%s" nie będą liczone - rok poza zakresem (%i)'
390
            % (link_do_obiektu(obj), obj.rok),
391
        )
392

393

394
def sprobuj_wgrac_do_pbn(request, obj, force_upload=False, pbn_client=None):
3✔
395
    from bpp.models.uczelnia import Uczelnia
×
396

397
    if obj.charakter_formalny.rodzaj_pbn is None:
×
398
        messages.info(
×
399
            request,
400
            'Rekord "%s" nie będzie eksportowany do PBN zgodnie z ustawieniem dla charakteru formalnego.'
401
            % link_do_obiektu(obj),
402
        )
403
        return
×
404

405
    uczelnia = Uczelnia.objects.get_for_request(request)
×
406
    if uczelnia is None:
×
407
        messages.info(
×
408
            request,
409
            'Rekord "%s" nie zostanie wyeksportowany do PBN, ponieważ w systemie brakuje obiektu "Uczelnia", a'
410
            " co za tym idzie, jakchkolwiek ustawień" % link_do_obiektu(obj),
411
        )
412
        return
×
413

414
    if not uczelnia.pbn_integracja or not uczelnia.pbn_aktualizuj_na_biezaco:
×
415
        return
×
416

417
    if pbn_client is None:
×
418
        pbn_client = uczelnia.pbn_client(request.user.pbn_token)
×
419

420
    # Sprawdź, czy wydawnictwo nadrzędne ma odpowoednik PBN:
421
    if (
×
422
        hasattr(obj, "wydawnictwo_nadrzedne_id")
423
        and obj.wydawnictwo_nadrzedne_id is not None
424
    ):
425
        wn = obj.wydawnictwo_nadrzedne
×
426
        if wn.pbn_uid_id is None:
×
427
            messages.info(
×
428
                request,
429
                "Wygląda na to, że wydawnictwo nadrzędne tego rekordu nie posiada odpowiednika "
430
                "w PBN, spróbuję go pobrać.",
431
            )
432
            udalo = False
×
433
            if wn.isbn:
×
434
                ni = normalize_isbn(wn.isbn)
×
435
                if ni:
×
436
                    from pbn_api.integrator import _pobierz_prace_po_elemencie
×
437

438
                    res = None
×
439
                    try:
×
440
                        res = _pobierz_prace_po_elemencie(pbn_client, "isbn", ni)
×
441
                    except PraceSerwisoweException:
×
442
                        messages.warning(
×
443
                            request,
444
                            "Pobieranie z PBN odpowiednika wydawnictwa nadrzędnego pracy po ISBN nie powiodło się "
445
                            "-- trwają prace serwisowe po stronie PBN. ",
446
                        )
447
                    except NeedsPBNAuthorisationException:
×
448
                        messages.warning(
×
449
                            request,
450
                            "Wyszukanie PBN UID wydawnictwa nadrzędnego po ISBN nieudane - "
451
                            "autoryzuj się najpierw w PBN. ",
452
                        )
453

454
                    if res:
×
455
                        messages.info(
×
456
                            request,
457
                            f"Udało się dopasować PBN UID wydawnictwa nadrzędnego po ISBN "
458
                            f"({', '.join([x.tytul_oryginalny for x in res])}). ",
459
                        )
460
                        udalo = True
×
461

462
            elif wn.doi:
×
463
                nd = normalize_isbn(wn.doi)
×
464
                if nd:
×
465
                    from pbn_api.integrator import _pobierz_prace_po_elemencie
×
466

467
                    res = None
×
468
                    try:
×
469
                        res = _pobierz_prace_po_elemencie(pbn_client, "doi", nd)
×
470
                    except PraceSerwisoweException:
×
471
                        messages.warning(
×
472
                            request,
473
                            "Pobieranie z PBN odpowiednika wydawnictwa nadrzędnego pracy po DOI nie powiodło się "
474
                            "-- trwają prace serwisowe po stronie PBN. ",
475
                        )
476
                    except NeedsPBNAuthorisationException:
×
477
                        messages.warning(
×
478
                            request,
479
                            "Wyszukanie PBN UID wydawnictwa nadrzędnego po DOI nieudane - "
480
                            "autoryzuj się najpierw w PBN. ",
481
                        )
482

483
                    if res:
×
484
                        messages.info(
×
485
                            request,
486
                            f"Udało się dopasować PBN UID wydawnictwa nadrzędnego po DOI. "
487
                            f"({', '.join([x.tytul_oryginalny for x in res])}). ",
488
                        )
489
                        udalo = True
×
490

491
            if not udalo:
×
492
                messages.warning(
×
493
                    request,
494
                    "Wygląda na to, że nie udało się dopasować rekordu nadrzędnego po ISBN/DOI do rekordu "
495
                    "po stronie PBN. Jeżeli jednak dokonano autoryzacji w PBN, to pewne rekordy z PBN "
496
                    "zostały teraz pobrane i możesz spróbować ustawić odpowiednik "
497
                    "PBN dla wydawnictwa nadrzędnego ręcznie. ",
498
                )
499

500
    try:
×
501
        uczelnia = Uczelnia.objects.get_for_request(request)
×
502

503
        pbn_client.sync_publication(
×
504
            obj,
505
            force_upload=force_upload,
506
            delete_statements_before_upload=uczelnia.pbn_api_kasuj_przed_wysylka,
507
            export_pk_zero=not uczelnia.pbn_api_nie_wysylaj_prac_bez_pk,
508
            always_affiliate_to_uid=(
509
                uczelnia.pbn_uid_id
510
                if uczelnia.pbn_api_afiliacja_zawsze_na_uczelnie
511
                else None
512
            ),
513
        )
514

515
    except SameDataUploadedRecently as e:
×
516
        link_do_wyslanych = reverse(
×
517
            "admin:pbn_api_sentdata_change",
518
            args=(SentData.objects.get_for_rec(obj).pk,),
519
        )
520

521
        messages.info(
×
522
            request,
523
            f'Identyczne dane rekordu "{link_do_obiektu(obj)}" zostały wgrane do PBN w dniu {e}. '
524
            f"Nie aktualizuję w PBN API. Jeżeli chcesz wysłać ten rekord do PBN, musisz dokonać jakiejś zmiany "
525
            f"danych rekodu lub "
526
            f'usunąć informacje o <a target=_blank href="{link_do_wyslanych}">wcześniej wysłanych danych do PBN</a> '
527
            f"(Redagowanie -> PBN API -> Wysłane informacje). "
528
            f'<a target=_blank href="{obj.link_do_pbn()}">Kliknij tutaj, aby otworzyć w PBN</a>. ',
529
        )
530
        return
×
531

532
    except AccessDeniedException as e:
×
533
        messages.warning(
×
534
            request,
535
            f'Nie można zsynchronizować obiektu "{link_do_obiektu(obj)}" z PBN pod adresem '
536
            f"API {e.url}. Brak dostępu -- najprawdopodobniej użytkownik nie posiada odpowiednich uprawnień "
537
            f"po stronie PBN/POLON. ",
538
        )
539
        return
×
540

541
    except PKZeroExportDisabled:
×
542
        messages.warning(
×
543
            request,
544
            f"Eksport prac z PK=0 jest wyłączony w konfiguracji. Próba wysyłki do PBN rekordu "
545
            f'"{link_do_obiektu(obj)}" nie została podjęta z uwagi na konfigurację systemu. ',
546
        )
547
        return
×
548

549
    except NeedsPBNAuthorisationException as e:
×
550
        messages.warning(
×
551
            request,
552
            f'Nie można zsynchronizować obiektu "{link_do_obiektu(obj)}" z PBN pod adresem '
553
            f"API {e.url}. Brak dostępu z powodu nieprawidłowego tokena -- wymagana autoryzacja w PBN. "
554
            f'<a target=_blank href="{reverse("pbn_api:authorize")}">Kliknij tutaj, aby autoryzować sesję</a>.',
555
        )
556
        return
×
557

558
    except Exception as e:
×
559
        try:
×
560
            link_do_wyslanych = reverse(
×
561
                "admin:pbn_api_sentdata_change",
562
                args=(SentData.objects.get_for_rec(obj).pk,),
563
            )
564
        except SentData.DoesNotExist:
×
565
            link_do_wyslanych = None
×
566

567
        extra = ""
×
568
        if link_do_wyslanych:
×
569
            extra = (
×
570
                '<a target=_blank href="%s">Kliknij, aby otworzyć widok wysłanych danych</a>.'
571
                % link_do_wyslanych
572
            )
573

574
        messages.warning(
×
575
            request,
576
            'Nie można zsynchronizować obiektu "%s" z PBN. Kod błędu: %r. %s'
577
            % (link_do_obiektu(obj), e, extra),
578
        )
579

580
        # Zaloguj problem do Sentry, bo w sumie nie wiadomo, co to za problem na tym etapie...
581
        capture_exception(e)
×
582

583
        return
×
584

585
    sent_data = SentData.objects.get(
×
586
        content_type=ContentType.objects.get_for_model(obj), object_id=obj.pk
587
    )
588
    sent_data_link = link_do_obiektu(
×
589
        sent_data, "Kliknij tutaj, aby otworzyć widok wysłanych danych. "
590
    )
591

592
    publication_link = link_do_obiektu(
×
593
        sent_data.pbn_uid,
594
        "Kliknij tutaj, aby otworzyć zwrotnie otrzymane z PBN dane o rekordzie. ",
595
    )
596
    messages.success(
×
597
        request,
598
        f"Dane w PBN dla rekordu {link_do_obiektu(obj)} zostały zaktualizowane. "
599
        f'<a target=_blank href="{obj.link_do_pbn()}">Kliknij tutaj, aby otworzyć w PBN</a>. '
600
        f"{sent_data_link}{publication_link}",
601
    )
602

603

604
def get_rekord_id_from_GET_qs(request):
3✔
UNCOV
605
    flt = request.GET.get("_changelist_filters", "?")
1✔
UNCOV
606
    data = parse_qs(flt)  # noqa
1✔
UNCOV
607
    if "rekord__id__exact" in data:
1✔
UNCOV
608
        try:
1✔
UNCOV
609
            return int(data.get("rekord__id__exact")[0])
1✔
610
        except (ValueError, TypeError):
×
611
            pass
×
612

613

614
class OptionalPBNSaveMixin:
3✔
615
    def render_change_form(
3✔
616
        self, request, context, add=False, change=False, form_url="", obj=None
617
    ):
UNCOV
618
        from bpp.models import Uczelnia
1✔
619

UNCOV
620
        uczelnia = Uczelnia.objects.get_default()
1✔
UNCOV
621
        if uczelnia is not None:
1✔
UNCOV
622
            if uczelnia.pbn_integracja and uczelnia.pbn_aktualizuj_na_biezaco:
1✔
623
                context.update({"show_save_and_pbn": True})
×
624

UNCOV
625
        return super().render_change_form(request, context, add, change, form_url, obj)
1✔
626

627
    def response_post_save_change(self, request, obj):
3✔
628
        if "_continue_and_pbn" in request.POST:
×
629
            sprobuj_wgrac_do_pbn(request, obj)
×
630

631
            opts = self.model._meta
×
632
            route = f"admin:{opts.app_label}_{opts.model_name}_change"
×
633

634
            post_url = reverse(route, args=(obj.pk,))
×
635

636
            from django.http import HttpResponseRedirect
×
637

638
            return HttpResponseRedirect(post_url)
×
639
        else:
640
            # Otherwise, use default behavior
641
            return super().response_post_save_change(request, obj)
×
642

643

644
def sprawdz_duplikaty_www_doi(request, obj):
3✔
UNCOV
645
    from bpp.models.cache import Rekord
1✔
646

UNCOV
647
    IEXACT = "__iexact"
1✔
UNCOV
648
    for field, operator, label in [
1✔
649
        ("www", IEXACT, const.WWW_FIELD_LABEL),
650
        ("public_www", IEXACT, const.PUBLIC_WWW_FIELD_LABEL),
651
        ("doi", IEXACT, const.DOI_FIELD_LABEL),
652
        ("pbn_uid_id", "", const.PBN_UID_FIELD_LABEL),
653
    ]:
UNCOV
654
        if not hasattr(obj, field):
1✔
655
            continue
×
656

UNCOV
657
        v = getattr(obj, field)
1✔
UNCOV
658
        if v in [None, ""]:
1✔
UNCOV
659
            continue
1✔
660

661
        rekord_pk = (ContentType.objects.get_for_model(obj).pk, obj.pk)
×
662

663
        query = Q(**{field + operator: v})
×
664

665
        if field == "www":
×
666
            query |= Q(public_www__iexact=v)
×
667
        elif field == "public_www":
×
668
            query |= Q(www__iexact=v)
×
669

670
        if Rekord.objects.filter(query).exclude(pk=rekord_pk).exists():
×
671
            messages.warning(
×
672
                request, const.ZDUBLOWANE_POLE_KOMUNIKAT.format(label=label)
673
            )
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc