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

iplweb / bpp / 3c407b5b-8434-4f25-9e12-005b14d23a79

07 Sep 2025 02:53PM UTC coverage: 33.615% (-8.7%) from 42.328%
3c407b5b-8434-4f25-9e12-005b14d23a79

push

circleci

mpasternak
Merge branch 'release/v202509.1221'

1 of 45 new or added lines in 2 files covered. (2.22%)

3993 existing lines in 129 files now uncovered.

16522 of 49150 relevant lines covered (33.62%)

0.34 hits per line

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

33.57
src/pbn_api/models/queue.py
1
import traceback
1✔
2
from enum import Enum
1✔
3

4
from django.core.exceptions import ObjectDoesNotExist
1✔
5
from django.db import models
1✔
6
from django.db.models import PositiveIntegerField
1✔
7
from django.urls import reverse
1✔
8
from sentry_sdk import capture_exception
1✔
9

10
from pbn_api.exceptions import (
1✔
11
    AccessDeniedException,
12
    AlreadyEnqueuedError,
13
    CharakterFormalnyNieobslugiwanyError,
14
    NeedsPBNAuthorisationException,
15
    PKZeroExportDisabled,
16
    PraceSerwisoweException,
17
    ResourceLockedException,
18
)
19

20
from django.contrib.contenttypes.fields import GenericForeignKey
1✔
21
from django.contrib.contenttypes.models import ContentType
1✔
22

23
from django.utils import timezone
1✔
24

25
from django_bpp.settings.base import AUTH_USER_MODEL
1✔
26

27

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

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

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

45

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

51
    RETRY_AFTER_USER_AUTHORISED = 3  # when user logs in + authorizes
1✔
52

53
    FINISHED_OKAY = 5
1✔
54
    FINISHED_ERROR = 6
1✔
55

56

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

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

64

65
class PBN_Export_Queue(models.Model):
1✔
66
    objects = PBN_Export_QueueManager()
1✔
67

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

72
    zamowil = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE)
1✔
73

74
    zamowiono = models.DateTimeField(auto_now_add=True, db_index=True)
1✔
75

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

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

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

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

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

95
    def check_if_record_still_exists(self):
1✔
96
        if not self.content_type_id:
×
UNCOV
97
            return False
×
98

UNCOV
99
        try:
×
100
            # Check iftable exists for that model...
101
            if not model_table_exists(self.content_type.model_class()):
×
102
                return False
×
103

104
            try:
×
105
                if self.content_type.get_object_for_this_type(pk=self.object_id):
×
UNCOV
106
                    return True
×
107

UNCOV
108
            except ObjectDoesNotExist:
×
UNCOV
109
                return False
×
UNCOV
110
        except self.content_type.model_class().DoesNotExist:
×
UNCOV
111
            return False
×
112

113
    def prepare_for_resend(self, user=None, message_suffix=""):
1✔
114
        """Przygotowuje obiekt do ponownej wysyłki."""
UNCOV
115
        self.refresh_from_db()
×
UNCOV
116
        self.wysylke_zakonczono = None
×
UNCOV
117
        self.zakonczono_pomyslnie = None
×
118
        self.retry_after_user_authorised = None
×
119

120
        msg = "Ponownie wysłano"
×
121
        if user is not None:
×
122
            self.zamowil = user
×
UNCOV
123
            msg += f" przez użytkownika: {user}"
×
UNCOV
124
        if message_suffix is not None:
×
125
            msg += f"{message_suffix}"
×
126
        msg += ". "
×
UNCOV
127
        self.dopisz_komunikat(msg)
×
128

UNCOV
129
        self.save()
×
130

131
    def sprobuj_wyslac_do_pbn(self):
1✔
UNCOV
132
        from pbn_api.tasks import task_sprobuj_wyslac_do_pbn
×
133

UNCOV
134
        task_sprobuj_wyslac_do_pbn.delay(self.pk)
×
135

136
    def dopisz_komunikat(self, msg):
1✔
137
        res = str(timezone.now())
×
138
        res += "\n" + "==============================================================="
×
139
        res += "\n" + msg + "\n"
×
UNCOV
140
        if self.komunikat:
×
141
            self.komunikat = "\n" + res + "\n" + self.komunikat
×
142
        else:
UNCOV
143
            self.komunikat = res
×
144

145
    def error(self, msg):
1✔
146
        self.wysylke_zakonczono = timezone.now()
×
147
        self.zakonczono_pomyslnie = False
×
UNCOV
148
        self.dopisz_komunikat(msg)
×
149
        self.save()
×
150
        return SendStatus.FINISHED_ERROR
×
151

152
    def send_to_pbn(self):
1✔
153
        """
154
        :return: (int : SendStatus,)
155
        """
156

157
        if not self.check_if_record_still_exists():
×
UNCOV
158
            if self.wysylke_zakonczono is not None:
×
UNCOV
159
                raise Exception(
×
160
                    "System próbuje ponownie wysyłać rekordy, których wysyłać nie powinien"
161
                )
162

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

UNCOV
165
        self.wysylke_podjeto = timezone.now()
×
166
        if self.retry_after_user_authorised:
×
UNCOV
167
            self.retry_after_user_authorised = (
×
168
                None  # Zresetuj wartosc tego pola, rekord wysyłany n-ty raz
169
            )
170
        self.ilosc_prob += 1
×
171
        self.save()
×
172

173
        from bpp.admin.helpers.pbn_api.cli import sprobuj_wyslac_do_pbn_celery
×
174

175
        try:
×
UNCOV
176
            sent_data, notificator = sprobuj_wyslac_do_pbn_celery(
×
177
                user=self.zamowil.get_pbn_user(),
178
                obj=self.rekord_do_wysylki,
179
                force_upload=True,
180
            )
181
        except PraceSerwisoweException:
×
UNCOV
182
            self.dopisz_komunikat("Prace serwisowe w PBN, spróbuję za kilka godzin")
×
UNCOV
183
            self.save()
×
UNCOV
184
            return SendStatus.RETRY_MUCH_LATER
×
185

186
        except NeedsPBNAuthorisationException:
×
UNCOV
187
            self.dopisz_komunikat(
×
188
                "Użytkownik bez autoryzacji w PBN, spróbuję po zalogowaniu do PBN."
189
            )
UNCOV
190
            self.retry_after_user_authorised = True
×
191
            self.save()
×
UNCOV
192
            return SendStatus.RETRY_AFTER_USER_AUTHORISED
×
193

194
        except CharakterFormalnyNieobslugiwanyError:
×
195
            self.error(
×
196
                "Charakter formalny tego rekordu nie jest ustawiony jako wysyłany do PBN. Zmień konfigurację "
197
                "bazy BPP, Redagowanie -> Dane systemowe -> Charaktery formalne"
198
            )
199
            return SendStatus.FINISHED_ERROR
×
200

UNCOV
201
        except AccessDeniedException:
×
202
            return self.error(
×
203
                "Brak uprawnień, załączam traceback:\n" + traceback.format_exc()
204
            )
205
            return SendStatus.FINISHED_ERROR
206

UNCOV
207
        except PKZeroExportDisabled:
×
UNCOV
208
            self.error(
×
209
                "Eksport prac bez punktów PK wyłączony w konfiguracji, nie wysłano."
210
            )
UNCOV
211
            return SendStatus.FINISHED_ERROR
×
212

UNCOV
213
        except ResourceLockedException as e:
×
UNCOV
214
            self.dopisz_komunikat(f"{e}, ponowiam wysyłkę za kilka minut...")
×
UNCOV
215
            self.save()
×
UNCOV
216
            return SendStatus.RETRY_LATER
×
217

UNCOV
218
        except Exception as e:
×
UNCOV
219
            capture_exception(e)
×
UNCOV
220
            return self.error(
×
221
                "Wystąpił nieobsługiwany błąd, załączam traceback:\n"
222
                + traceback.format_exc()
223
            )
224

UNCOV
225
        if sent_data is None:
×
UNCOV
226
            return self.error(
×
227
                "Wystąpił błąd, dane nie zostały wysłane, wyjaśnienie poniżej.\n\n"
228
                + "\n".join(notificator)
229
            )
230

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

UNCOV
242
        self.wysylke_zakonczono = timezone.now()
×
UNCOV
243
        self.dopisz_komunikat(msg)
×
UNCOV
244
        self.zakonczono_pomyslnie = True
×
UNCOV
245
        self.save()
×
246

UNCOV
247
        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

© 2025 Coveralls, Inc