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

iplweb / bpp / 58b9a630-8512-44e6-b730-daac96d1c4d7

29 Aug 2025 07:21AM UTC coverage: 47.493% (+2.5%) from 45.008%
58b9a630-8512-44e6-b730-daac96d1c4d7

push

circleci

mpasternak
Fix tests

6 of 27 new or added lines in 2 files covered. (22.22%)

1342 existing lines in 64 files now uncovered.

19323 of 40686 relevant lines covered (47.49%)

1.51 hits per line

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

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

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

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

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

23
from django.utils import timezone
4✔
24

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

27

28
class PBN_Export_QueueManager(models.Manager):
4✔
29
    def filter_rekord_do_wysylki(self, rekord):
4✔
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):
4✔
37
        if self.filter_rekord_do_wysylki(rekord).exists():
×
38
            raise AlreadyEnqueuedError("ten rekord jest już w kolejce do wysyłki")
×
39

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

45

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

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

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

56

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

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

64

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

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

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

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

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

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

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

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

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

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

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

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

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

113
    def dopisz_komunikat(self, msg):
4✔
114
        res = str(timezone.now())
×
115
        res += "\n" + "==============================================================="
×
116
        res += "\n" + msg + "\n"
×
117
        if self.komunikat:
×
118
            self.komunikat = "\n" + res + "\n" + self.komunikat
×
119
        else:
120
            self.komunikat = res
×
121

122
    def error(self, msg):
4✔
123
        self.wysylke_zakonczono = timezone.now()
×
124
        self.zakonczono_pomyslnie = False
×
125
        self.dopisz_komunikat(msg)
×
126
        self.save()
×
127
        return SendStatus.FINISHED_ERROR
×
128

129
    def send_to_pbn(self):
4✔
130
        """
131
        :return: (int : SendStatus,)
132
        """
133

134
        if not self.check_if_record_still_exists():
×
135
            if self.wysylke_zakonczono is not None:
×
136
                raise Exception(
×
137
                    "System próbuje ponownie wysyłać rekordy, których wysyłać nie powinien"
138
                )
139

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

142
        self.wysylke_podjeto = timezone.now()
×
143
        if self.retry_after_user_authorised:
×
144
            self.retry_after_user_authorised = (
×
145
                None  # Zresetuj wartosc tego pola, rekord wysyłany n-ty raz
146
            )
147
        self.ilosc_prob += 1
×
148
        self.save()
×
149

150
        from bpp.admin.helpers.pbn_api.cli import sprobuj_wyslac_do_pbn_celery
×
151

152
        try:
×
153
            sent_data, notificator = sprobuj_wyslac_do_pbn_celery(
×
154
                user=self.zamowil.get_pbn_user(),
155
                obj=self.rekord_do_wysylki,
156
                force_upload=True,
157
            )
158
        except PraceSerwisoweException:
×
159
            self.dopisz_komunikat("Prace serwisowe w PBN, spróbuję za kilka godzin")
×
160
            self.save()
×
161
            return SendStatus.RETRY_MUCH_LATER
×
162

163
        except NeedsPBNAuthorisationException:
×
164
            self.dopisz_komunikat(
×
165
                "Użytkownik bez autoryzacji w PBN, spróbuję po zalogowaniu do PBN."
166
            )
167
            self.retry_after_user_authorised = True
×
168
            self.save()
×
169
            return SendStatus.RETRY_AFTER_USER_AUTHORISED
×
170

171
        except CharakterFormalnyNieobslugiwanyError:
×
172
            self.error(
×
173
                "Charakter formalny tego rekordu nie jest ustawiony jako wysyłany do PBN. Zmień konfigurację "
174
                "bazy BPP, Redagowanie -> Dane systemowe -> Charaktery formalne"
175
            )
176
            return SendStatus.FINISHED_ERROR
×
177

178
        except AccessDeniedException:
×
179
            return self.error(
×
180
                "Brak uprawnień, załączam traceback:\n" + traceback.format_exc()
181
            )
182
            return SendStatus.FINISHED_ERROR
183

184
        except PKZeroExportDisabled:
×
185
            self.error(
×
186
                "Eksport prac bez punktów PK wyłączony w konfiguracji, nie wysłano."
187
            )
188
            return SendStatus.FINISHED_ERROR
×
189

190
        except ResourceLockedException as e:
×
191
            self.dopisz_komunikat(f"{e}, ponowiam wysyłkę za kilka minut...")
×
192
            self.save()
×
193
            return SendStatus.RETRY_LATER
×
194

195
        except Exception as e:
×
196
            capture_exception(e)
×
197
            return self.error(
×
198
                "Wystąpił nieobsługiwany błąd, załączam traceback:\n"
199
                + traceback.format_exc()
200
            )
201

202
        if sent_data is None:
×
203
            return self.error(
×
204
                "Wystąpił błąd, dane nie zostały wysłane, wyjaśnienie poniżej.\n\n"
205
                + "\n".join(notificator)
206
            )
207

208
        msg = (
×
209
            "Wysłano poprawnie. Link do wysłanego kodu JSON <a href="
210
            + reverse("admin:pbn_api_sentdata_change", args=[sent_data.pk])
211
            + ">tutaj</a>. "
212
        )
213
        extra_info = "\n".join(notificator)
×
214
        # Jeżeli notyfikator zawiera cokolwiek, a może zawierać np ostrzeżenia czy uwagi do
215
        # wysłanego rekordu to dołącz to
216
        if extra_info:
×
217
            msg += "\n\nDodatkowe informacje:\n" + extra_info
×
218

219
        self.wysylke_zakonczono = timezone.now()
×
220
        self.dopisz_komunikat(msg)
×
221
        self.zakonczono_pomyslnie = True
×
222
        self.save()
×
223

224
        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