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

iplweb / bpp / 18634744198

19 Oct 2025 07:00PM UTC coverage: 31.618% (-29.9%) from 61.514%
18634744198

push

github

mpasternak
Merge branch 'release/v202510.1270'

657 of 9430 branches covered (6.97%)

Branch coverage included in aggregate %.

229 of 523 new or added lines in 42 files covered. (43.79%)

11303 existing lines in 316 files now uncovered.

14765 of 39346 relevant lines covered (37.53%)

0.38 hits per line

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

28.41
src/pbn_export_queue/models.py
1
import sys
1✔
2
import traceback
1✔
3
from enum import Enum
1✔
4

5
import rollbar
1✔
6
from django.contrib.contenttypes.fields import GenericForeignKey
1✔
7
from django.contrib.contenttypes.models import ContentType
1✔
8
from django.core.exceptions import ObjectDoesNotExist
1✔
9
from django.db import models
1✔
10
from django.db.models import PositiveIntegerField
1✔
11
from django.urls import reverse
1✔
12
from django.utils import timezone
1✔
13

14
from django_bpp.settings.base import AUTH_USER_MODEL
1✔
15
from pbn_api.exceptions import (
1✔
16
    AccessDeniedException,
17
    AlreadyEnqueuedError,
18
    CharakterFormalnyNieobslugiwanyError,
19
    NeedsPBNAuthorisationException,
20
    PKZeroExportDisabled,
21
    PraceSerwisoweException,
22
    ResourceLockedException,
23
)
24

25

26
class PBN_Export_QueueManager(models.Manager):
1✔
27
    def filter_rekord_do_wysylki(self, rekord):
1✔
UNCOV
28
        return self.filter(
×
29
            content_type=ContentType.objects.get_for_model(rekord),
30
            object_id=rekord.pk,
31
            wysylke_zakonczono=None,
32
        )
33

34
    def sprobuj_utowrzyc_wpis(self, user, rekord):
1✔
UNCOV
35
        if self.filter_rekord_do_wysylki(rekord).exists():
×
UNCOV
36
            raise AlreadyEnqueuedError("ten rekord jest już w kolejce do wysyłki")
×
37

UNCOV
38
        return self.create(
×
39
            rekord_do_wysylki=rekord,
40
            zamowil=user,
41
        )
42

43

44
class SendStatus(Enum):
1✔
45
    RETRY_SOON = 0  # few seconds, 423 Locked
1✔
46
    RETRY_LATER = 1  # few minutes
1✔
47
    RETRY_MUCH_LATER = 2  # few hours, PraceSerwisoweExecption
1✔
48

49
    RETRY_AFTER_USER_AUTHORISED = 3  # when user logs in + authorizes
1✔
50

51
    FINISHED_OKAY = 5
1✔
52
    FINISHED_ERROR = 6
1✔
53

54

55
def model_table_exists(model):
1✔
56
    """Check if a model's table exists"""
UNCOV
57
    from django.db import connection
×
58

UNCOV
59
    table_name = model._meta.db_table
×
UNCOV
60
    return table_name in connection.introspection.table_names()
×
61

62

63
class PBN_Export_Queue(models.Model):
1✔
64
    objects = PBN_Export_QueueManager()
1✔
65

66
    object_id = PositiveIntegerField()
1✔
67
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
1✔
68
    rekord_do_wysylki = GenericForeignKey()
1✔
69

70
    zamowil = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE)
1✔
71

72
    zamowiono = models.DateTimeField(auto_now_add=True, db_index=True)
1✔
73

74
    wysylke_podjeto = models.DateTimeField(null=True, blank=True)
1✔
75
    wysylke_zakonczono = models.DateTimeField(null=True, blank=True, db_index=True)
1✔
76

77
    ilosc_prob = models.PositiveSmallIntegerField(default=0)
1✔
78
    zakonczono_pomyslnie = models.BooleanField(null=True, default=None, db_index=True)
1✔
79
    komunikat = models.TextField(null=True, blank=True)
1✔
80

81
    retry_after_user_authorised = models.BooleanField(
1✔
82
        null=True, default=None, db_index=True
83
    )
84

85
    class Meta:
1✔
86
        verbose_name = "Kolejka eksportu do PBN"
1✔
87
        verbose_name_plural = "Kolejka eksportu do PBN"
1✔
88
        ordering = ("-zamowiono", "zamowil")
1✔
89

90
    def __str__(self):
1✔
UNCOV
91
        return f"Zlecenie wysyłki do PBN dla {self.rekord_do_wysylki}"
×
92

93
    @property
1✔
94
    def ostatnia_aktualizacja(self):
1✔
95
        """Returns the most recent update timestamp"""
UNCOV
96
        if self.wysylke_zakonczono:
×
UNCOV
97
            return self.wysylke_zakonczono
×
UNCOV
98
        elif self.wysylke_podjeto:
×
UNCOV
99
            return self.wysylke_podjeto
×
100
        else:
UNCOV
101
            return self.zamowiono
×
102

103
    def check_if_record_still_exists(self):
1✔
UNCOV
104
        if not self.content_type_id:
×
UNCOV
105
            return False
×
106

UNCOV
107
        try:
×
108
            # Check iftable exists for that model...
UNCOV
109
            if not model_table_exists(self.content_type.model_class()):
×
UNCOV
110
                return False
×
111

UNCOV
112
            try:
×
UNCOV
113
                if self.content_type.get_object_for_this_type(pk=self.object_id):
×
UNCOV
114
                    return True
×
115

UNCOV
116
            except ObjectDoesNotExist:
×
UNCOV
117
                return False
×
118
        except self.content_type.model_class().DoesNotExist:
×
119
            return False
×
120

121
    def prepare_for_resend(self, user=None, message_suffix=""):
1✔
122
        """Przygotowuje obiekt do ponownej wysyłki."""
UNCOV
123
        self.refresh_from_db()
×
UNCOV
124
        self.wysylke_zakonczono = None
×
UNCOV
125
        self.zakonczono_pomyslnie = None
×
UNCOV
126
        self.retry_after_user_authorised = None
×
127

UNCOV
128
        msg = "Ponownie wysłano"
×
UNCOV
129
        if user is not None:
×
UNCOV
130
            self.zamowil = user
×
UNCOV
131
            msg += f" przez użytkownika: {user}"
×
UNCOV
132
        if message_suffix is not None:
×
UNCOV
133
            msg += f"{message_suffix}"
×
UNCOV
134
        msg += ". "
×
UNCOV
135
        self.dopisz_komunikat(msg)
×
136

UNCOV
137
        self.save()
×
138

139
    def sprobuj_wyslac_do_pbn(self):
1✔
UNCOV
140
        from pbn_export_queue.tasks import task_sprobuj_wyslac_do_pbn
×
141

UNCOV
142
        task_sprobuj_wyslac_do_pbn.delay(self.pk)
×
143

144
    def dopisz_komunikat(self, msg):
1✔
UNCOV
145
        res = str(timezone.now())
×
UNCOV
146
        res += "\n" + "==============================================================="
×
UNCOV
147
        res += "\n" + msg + "\n"
×
UNCOV
148
        if self.komunikat:
×
UNCOV
149
            self.komunikat = "\n" + res + "\n" + self.komunikat
×
150
        else:
UNCOV
151
            self.komunikat = res
×
152

153
    def error(self, msg):
1✔
UNCOV
154
        self.wysylke_zakonczono = timezone.now()
×
UNCOV
155
        self.zakonczono_pomyslnie = False
×
UNCOV
156
        self.dopisz_komunikat(msg)
×
UNCOV
157
        self.save()
×
UNCOV
158
        return SendStatus.FINISHED_ERROR
×
159

160
    def send_to_pbn(self):
1✔
161
        """
162
        :return: (int : SendStatus,)
163
        """
164

UNCOV
165
        if not self.check_if_record_still_exists():
×
UNCOV
166
            if self.wysylke_zakonczono is not None:
×
UNCOV
167
                raise Exception(
×
168
                    "System próbuje ponownie wysyłać rekordy, których wysyłać nie powinien"
169
                )
170

UNCOV
171
            return self.error("Rekord został usunięty nim wysyłka była możliwa.")
×
172

UNCOV
173
        self.wysylke_podjeto = timezone.now()
×
UNCOV
174
        if self.retry_after_user_authorised:
×
UNCOV
175
            self.retry_after_user_authorised = (
×
176
                None  # Zresetuj wartosc tego pola, rekord wysyłany n-ty raz
177
            )
UNCOV
178
        self.ilosc_prob += 1
×
UNCOV
179
        self.save()
×
180

UNCOV
181
        from bpp.admin.helpers.pbn_api.cli import sprobuj_wyslac_do_pbn_celery
×
182

UNCOV
183
        try:
×
UNCOV
184
            sent_data, notificator = sprobuj_wyslac_do_pbn_celery(
×
185
                user=self.zamowil.get_pbn_user(),
186
                obj=self.rekord_do_wysylki,
187
                force_upload=True,
188
            )
UNCOV
189
        except PraceSerwisoweException:
×
UNCOV
190
            self.dopisz_komunikat("Prace serwisowe w PBN, spróbuję za kilka godzin")
×
UNCOV
191
            self.save()
×
UNCOV
192
            return SendStatus.RETRY_MUCH_LATER
×
193

UNCOV
194
        except NeedsPBNAuthorisationException:
×
195
            self.dopisz_komunikat(
×
196
                "Użytkownik bez autoryzacji w PBN, spróbuję po zalogowaniu do PBN."
197
            )
198
            self.retry_after_user_authorised = True
×
199
            self.save()
×
200
            return SendStatus.RETRY_AFTER_USER_AUTHORISED
×
201

UNCOV
202
        except CharakterFormalnyNieobslugiwanyError:
×
UNCOV
203
            self.error(
×
204
                "Charakter formalny tego rekordu nie jest ustawiony jako wysyłany do PBN. Zmień konfigurację "
205
                "bazy BPP, Redagowanie -> Dane systemowe -> Charaktery formalne"
206
            )
UNCOV
207
            return SendStatus.FINISHED_ERROR
×
208

UNCOV
209
        except AccessDeniedException:
×
210
            return self.error(
×
211
                "Brak uprawnień, załączam traceback:\n" + traceback.format_exc()
212
            )
213
            return SendStatus.FINISHED_ERROR
214

UNCOV
215
        except PKZeroExportDisabled:
×
UNCOV
216
            self.error(
×
217
                "Eksport prac bez punktów PK wyłączony w konfiguracji, nie wysłano."
218
            )
UNCOV
219
            return SendStatus.FINISHED_ERROR
×
220

UNCOV
221
        except ResourceLockedException as e:
×
222
            self.dopisz_komunikat(f"{e}, ponowiam wysyłkę za kilka minut...")
×
223
            self.save()
×
224
            return SendStatus.RETRY_LATER
×
225

UNCOV
226
        except Exception:
×
UNCOV
227
            rollbar.report_exc_info(sys.exc_info())
×
UNCOV
228
            return self.error(
×
229
                "Wystąpił nieobsługiwany błąd, załączam traceback:\n"
230
                + traceback.format_exc()
231
            )
232

UNCOV
233
        if sent_data is None:
×
UNCOV
234
            return self.error(
×
235
                "Wystąpił błąd, dane nie zostały wysłane, wyjaśnienie poniżej.\n\n"
236
                + "\n".join(notificator)
237
            )
238

UNCOV
239
        msg = (
×
240
            "Wysłano poprawnie. Link do wysłanego kodu JSON <a href="
241
            + reverse("admin:pbn_api_sentdata_change", args=[sent_data.pk])
242
            + ">tutaj</a>. "
243
        )
UNCOV
244
        extra_info = "\n".join(notificator)
×
245
        # Jeżeli notyfikator zawiera cokolwiek, a może zawierać np ostrzeżenia czy uwagi do
246
        # wysłanego rekordu to dołącz to
UNCOV
247
        if extra_info:
×
UNCOV
248
            msg += "\n\nDodatkowe informacje:\n" + extra_info
×
249

UNCOV
250
        self.wysylke_zakonczono = timezone.now()
×
UNCOV
251
        self.dopisz_komunikat(msg)
×
UNCOV
252
        self.zakonczono_pomyslnie = True
×
UNCOV
253
        self.save()
×
254

UNCOV
255
        return SendStatus.FINISHED_OKAY
×
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