mirror of
https://github.com/bugsink/bugsink.git
synced 2026-02-14 10:33:50 -06:00
Rename ingest_order to digest_order and clarify event_count
* issue.event_count to digested_event_count * event.ingest_order to event.digest_order * issue.ingest_order to digest_order This is generally more correct/explicit, and is also in preparation of doing work on-digest (which may or may not happen)
This commit is contained in:
@@ -22,8 +22,8 @@ def create_event(project=None, issue=None, timestamp=None, event_data=None):
|
||||
event_data = create_event_data()
|
||||
|
||||
max_current = Event.objects.filter(project=project).aggregate(
|
||||
Max("ingest_order"))["ingest_order__max"]
|
||||
issue_ingest_order = max_current + 1 if max_current is not None else 1
|
||||
Max("digest_order"))["digest_order__max"]
|
||||
issue_digest_order = max_current + 1 if max_current is not None else 1
|
||||
|
||||
return Event.objects.create(
|
||||
project=project,
|
||||
@@ -34,7 +34,7 @@ def create_event(project=None, issue=None, timestamp=None, event_data=None):
|
||||
has_exception=True,
|
||||
has_logentry=True,
|
||||
data=json.dumps(event_data),
|
||||
ingest_order=issue_ingest_order,
|
||||
digest_order=issue_digest_order,
|
||||
irrelevance_for_retention=0,
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Generated by Django 4.2.13 on 2024-07-16 13:23
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('issues', '0004_rename_event_count_issue_digested_event_count'),
|
||||
('projects', '0004_project_quota_exceeded_until'),
|
||||
('events', '0009_event_events_even_issue_i_90497b_idx'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='event',
|
||||
old_name='ingest_order',
|
||||
new_name='digest_order',
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='event',
|
||||
unique_together={('project', 'event_id'), ('issue', 'digest_order')},
|
||||
),
|
||||
]
|
||||
@@ -147,7 +147,7 @@ class Event(models.Model):
|
||||
|
||||
# 1-based, because this is for human consumption only, and using 0-based internally when we don't actually do
|
||||
# anything with this value other than showing it to humans is super-confusing. Sorry Dijkstra!
|
||||
ingest_order = models.PositiveIntegerField(blank=False, null=False)
|
||||
digest_order = models.PositiveIntegerField(blank=False, null=False)
|
||||
|
||||
# irrelevance_for_retention is set on-ingest based on the number of available events for an issue; it is combined
|
||||
# with age-based-irrelevance to determine which events will be evicted when retention quota are met.
|
||||
@@ -157,7 +157,7 @@ class Event(models.Model):
|
||||
class Meta:
|
||||
unique_together = [
|
||||
("project", "event_id"),
|
||||
("issue", "ingest_order"),
|
||||
("issue", "digest_order"),
|
||||
]
|
||||
indexes = [
|
||||
models.Index(fields=["project", "never_evict", "server_side_timestamp", "irrelevance_for_retention"]),
|
||||
@@ -179,7 +179,7 @@ class Event(models.Model):
|
||||
return get_title_for_exception_type_and_value(self.calculated_type, self.calculated_value)
|
||||
|
||||
@classmethod
|
||||
def from_ingested(cls, event_metadata, ingest_order, stored_event_count, issue, parsed_data, denormalized_fields):
|
||||
def from_ingested(cls, event_metadata, digest_order, stored_event_count, issue, parsed_data, denormalized_fields):
|
||||
# 'from_ingested' may be a bit of a misnomer... the full 'from_ingested' is done in 'digest_event' in the views.
|
||||
# below at least puts the parsed_data in the right place, and does some of the basic object set up (FKs to other
|
||||
# objects etc).
|
||||
@@ -215,7 +215,7 @@ class Event(models.Model):
|
||||
|
||||
debug_info=event_metadata["debug_info"],
|
||||
|
||||
ingest_order=ingest_order,
|
||||
digest_order=digest_order,
|
||||
irrelevance_for_retention=irrelevance_for_retention,
|
||||
|
||||
**denormalized_fields,
|
||||
|
||||
@@ -57,7 +57,7 @@ def nonzero_leading_bits(n):
|
||||
return len(s.rstrip('0'))
|
||||
|
||||
|
||||
def get_random_irrelevance(event_count):
|
||||
def get_random_irrelevance(stored_event_count):
|
||||
"""
|
||||
gets a fixed-at-creation irrelevance-score for an Event; the basic idea is: the more events you have for a certain
|
||||
issue, the less relevant any new event will be _on average_; but when you have many events you will on average still
|
||||
@@ -67,7 +67,7 @@ def get_random_irrelevance(event_count):
|
||||
if `cnt` "hovers" around a certain value (which is likely to happen when there's repeated eviction/fill-up). ×2 is
|
||||
simply to correct for random() (which returns .5 on average).
|
||||
"""
|
||||
return nonzero_leading_bits(round(random() * event_count * 2))
|
||||
return nonzero_leading_bits(round(random() * stored_event_count * 2))
|
||||
|
||||
|
||||
def should_evict(project, timestamp, stored_event_count):
|
||||
|
||||
@@ -150,15 +150,15 @@ class BaseIngestAPIView(View):
|
||||
if not Grouping.objects.filter(project_id=event_metadata["project_id"], grouping_key=grouping_key).exists():
|
||||
# we don't have Project.issue_count here ('premature optimization') so we just do an aggregate instead.
|
||||
max_current = Issue.objects.filter(project_id=event_metadata["project_id"]).aggregate(
|
||||
Max("ingest_order"))["ingest_order__max"]
|
||||
issue_ingest_order = max_current + 1 if max_current is not None else 1
|
||||
Max("digest_order"))["digest_order__max"]
|
||||
issue_digest_order = max_current + 1 if max_current is not None else 1
|
||||
|
||||
issue = Issue.objects.create(
|
||||
ingest_order=issue_ingest_order,
|
||||
digest_order=issue_digest_order,
|
||||
project_id=event_metadata["project_id"],
|
||||
first_seen=timestamp,
|
||||
last_seen=timestamp,
|
||||
event_count=1,
|
||||
digested_event_count=1,
|
||||
**denormalized_fields,
|
||||
)
|
||||
# even though in our data-model a given grouping does not imply a single Issue (in fact, that's the whole
|
||||
@@ -179,7 +179,7 @@ class BaseIngestAPIView(View):
|
||||
|
||||
# update the denormalized fields
|
||||
issue.last_seen = timestamp
|
||||
issue.event_count += 1
|
||||
issue.digested_event_count += 1
|
||||
|
||||
# NOTE: possibly expensive. "in theory" we can just do some bookkeeping for a denormalized value, but that may
|
||||
# be hard to keep in-sync in practice. Let's check the actual cost first.
|
||||
@@ -200,7 +200,7 @@ class BaseIngestAPIView(View):
|
||||
# information available here, we could add it to the Event model.
|
||||
event, event_created = Event.from_ingested(
|
||||
event_metadata,
|
||||
issue.event_count,
|
||||
issue.digested_event_count,
|
||||
issue_stored_event_count,
|
||||
issue,
|
||||
event_data,
|
||||
|
||||
@@ -47,7 +47,7 @@ class IssueAdmin(admin.ModelAdmin):
|
||||
'is_muted',
|
||||
'unmute_on_volume_based_conditions',
|
||||
'unmute_after',
|
||||
'event_count',
|
||||
'digested_event_count',
|
||||
]
|
||||
|
||||
inlines = [
|
||||
@@ -58,7 +58,7 @@ class IssueAdmin(admin.ModelAdmin):
|
||||
list_display = [
|
||||
"title",
|
||||
"project",
|
||||
"event_count",
|
||||
"digested_event_count",
|
||||
]
|
||||
list_filter = [
|
||||
"project",
|
||||
@@ -71,5 +71,5 @@ class IssueAdmin(admin.ModelAdmin):
|
||||
'friendly_id',
|
||||
'calculated_type',
|
||||
'calculated_value',
|
||||
'event_count',
|
||||
'digested_event_count',
|
||||
]
|
||||
|
||||
@@ -53,5 +53,5 @@ def denormalized_issue_fields():
|
||||
return {
|
||||
"first_seen": timezone.now(),
|
||||
"last_seen": timezone.now(),
|
||||
"event_count": 1,
|
||||
"digested_event_count": 1,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.13 on 2024-07-16 13:18
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('issues', '0003_alter_turningpoint_triggering_event'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='issue',
|
||||
old_name='event_count',
|
||||
new_name='digested_event_count',
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 4.2.13 on 2024-07-16 13:23
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('projects', '0004_project_quota_exceeded_until'),
|
||||
('issues', '0004_rename_event_count_issue_digested_event_count'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameField(
|
||||
model_name='issue',
|
||||
old_name='ingest_order',
|
||||
new_name='digest_order',
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='issue',
|
||||
unique_together={('project', 'digest_order')},
|
||||
),
|
||||
]
|
||||
@@ -31,13 +31,13 @@ class Issue(models.Model):
|
||||
project = models.ForeignKey(
|
||||
"projects.Project", blank=False, null=True, on_delete=models.SET_NULL) # SET_NULL: cleanup 'later'
|
||||
|
||||
# 1-based for the same reasons as Event.ingest_order
|
||||
ingest_order = models.PositiveIntegerField(blank=False, null=False)
|
||||
# 1-based for the same reasons as Event.digest_order
|
||||
digest_order = models.PositiveIntegerField(blank=False, null=False)
|
||||
|
||||
# denormalized/cached fields:
|
||||
last_seen = models.DateTimeField(blank=False, null=False) # based on event.server_side_timestamp
|
||||
first_seen = models.DateTimeField(blank=False, null=False) # based on event.server_side_timestamp
|
||||
event_count = models.IntegerField(blank=False, null=False)
|
||||
digested_event_count = models.IntegerField(blank=False, null=False)
|
||||
calculated_type = models.CharField(max_length=255, blank=True, null=False, default="")
|
||||
calculated_value = models.CharField(max_length=255, blank=True, null=False, default="")
|
||||
transaction = models.CharField(max_length=200, blank=True, null=False, default="")
|
||||
@@ -60,15 +60,15 @@ class Issue(models.Model):
|
||||
unmute_after = models.DateTimeField(blank=True, null=True)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if self.ingest_order is None:
|
||||
if self.digest_order is None:
|
||||
# testing-only; in production this should never happen and instead have been done in the ingest view.
|
||||
max_current = self.ingest_order = Issue.objects.filter(project=self.project).aggregate(
|
||||
models.Max("ingest_order"))["ingest_order__max"]
|
||||
self.ingest_order = max_current + 1 if max_current is not None else 1
|
||||
max_current = self.digest_order = Issue.objects.filter(project=self.project).aggregate(
|
||||
models.Max("digest_order"))["digest_order__max"]
|
||||
self.digest_order = max_current + 1 if max_current is not None else 1
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def friendly_id(self):
|
||||
return f"{ self.project.slug.upper() }-{ self.ingest_order }"
|
||||
return f"{ self.project.slug.upper() }-{ self.digest_order }"
|
||||
|
||||
def get_absolute_url(self):
|
||||
return f"/issues/issue/{ self.id }/event/last/"
|
||||
@@ -104,7 +104,7 @@ class Issue(models.Model):
|
||||
|
||||
class Meta:
|
||||
unique_together = [
|
||||
("project", "ingest_order"),
|
||||
("project", "digest_order"),
|
||||
]
|
||||
indexes = [
|
||||
models.Index(fields=["first_seen"]),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{% if event.ingest_order > 1 %}
|
||||
<a href="{% url this_view issue_pk=issue.pk ingest_order=event.ingest_order|add:"-1" %}" class="font-bold text-slate-500 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md hover:bg-slate-200 active:ring inline-flex items-center justify-center">
|
||||
{% if event.digest_order > 1 %}
|
||||
<a href="{% url this_view issue_pk=issue.pk digest_order=event.digest_order|add:"-1" %}" class="font-bold text-slate-500 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md hover:bg-slate-200 active:ring inline-flex items-center justify-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M9.78 4.22a.75.75 0 0 1 0 1.06L7.06 8l2.72 2.72a.75.75 0 1 1-1.06 1.06L5.47 8.53a.75.75 0 0 1 0-1.06l3.25-3.25a.75.75 0 0 1 1.06 0Z" clip-rule="evenodd" /></svg>
|
||||
</a>
|
||||
{% else %}
|
||||
@@ -8,8 +8,8 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if event.ingest_order < issue.event_count %}
|
||||
<a href="{% url this_view issue_pk=issue.pk ingest_order=event.ingest_order|add:"1" %}"" class="font-bold text-slate-500 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md hover:bg-slate-200 active:ring inline-flex items-center justify-center">
|
||||
{% if event.digest_order < issue.digested_event_count %}
|
||||
<a href="{% url this_view issue_pk=issue.pk digest_order=event.digest_order|add:"1" %}"" class="font-bold text-slate-500 border-slate-300 pl-4 pr-4 pb-1 pt-1 mr-2 border-2 rounded-md hover:bg-slate-200 active:ring inline-flex items-center justify-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="w-6 h-6"><path fill-rule="evenodd" d="M6.22 4.22a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06l-3.25 3.25a.75.75 0 0 1-1.06-1.06L8.94 8 6.22 5.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" /></svg>
|
||||
</a>
|
||||
{% else %}
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex p-4 bg-slate-200 border-b-2"><!-- bottom nav bar -->
|
||||
{% if is_event_page %}<div>Event {{ event.ingest_order }} of {{ issue.event_count}} which occured at <span class="font-bold">{{ event.server_side_timestamp|date:"j M G:i T" }}</span></div>{% endif %}
|
||||
{% if is_event_page %}<div>Event {{ event.digest_order }} of {{ issue.digested_event_count}} which occured at <span class="font-bold">{{ event.server_side_timestamp|date:"j M G:i T" }}</span></div>{% endif %}
|
||||
<div class="ml-auto pr-4 font-bold text-slate-500">
|
||||
<a href="/admin/issues/issue/{{ issue.id }}/change/">Issue Admin</a>
|
||||
{% if is_event_page %}
|
||||
@@ -170,10 +170,10 @@
|
||||
|
||||
<div class="mb-4">
|
||||
<div class="text-sm font-bold text-slate-500">Nr. of events:</div>
|
||||
<div>{{ issue.event_count }}</div>
|
||||
<div>{{ issue.digested_event_count }}</div>
|
||||
</div>
|
||||
|
||||
{% if issue.event_count > 1 %}
|
||||
{% if issue.digested_event_count > 1 %}
|
||||
<div class="mb-4">
|
||||
<div class="text-sm font-bold text-slate-500">First seen:</div>
|
||||
<div>{{ issue.first_seen|date:"j M G:i T" }}</div>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<div class="flex">
|
||||
<div class="overflow-hidden">
|
||||
<div class="italic">{{ event.server_side_timestamp|date:"j M G:i T" }} (Event {{ event.ingest_order }} of {{ issue.event_count }})</div>
|
||||
<div class="italic">{{ event.server_side_timestamp|date:"j M G:i T" }} (Event {{ event.digest_order }} of {{ issue.digested_event_count }})</div>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto flex-none">
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{# this is here to fool tailwind (because we're foolish enough to put html in python) <span class="text-xs"></span> #}
|
||||
<div class="flex">
|
||||
<div class="overflow-hidden">
|
||||
<div class="italic">{{ event.server_side_timestamp|date:"j M G:i T" }} (Event {{ event.ingest_order }} of {{ issue.event_count }})</div>
|
||||
<div class="italic">{{ event.server_side_timestamp|date:"j M G:i T" }} (Event {{ event.digest_order }} of {{ issue.digested_event_count }})</div>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto flex-none">
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M17.25 9.75 19.5 12m0 0 2.25 2.25M19.5 12l2.25-2.25M19.5 12l-2.25 2.25m-10.5-6 4.72-4.72a.75.75 0 0 1 1.28.53v15.88a.75.75 0 0 1-1.28.53l-4.72-4.72H4.51c-.88 0-1.704-.507-1.938-1.354A9.009 9.009 0 0 1 2.25 12c0-.83.112-1.633.322-2.396C2.806 8.756 3.63 8.25 4.51 8.25H6.75Z" />
|
||||
</svg> {% endif %}{{ issue.title|truncatechars:100 }}</a>
|
||||
</div>
|
||||
<div class="text-sm">from <b>{{ issue.first_seen|date:"j M G:i T" }}</b> | last <b>{{ issue.last_seen|date:"j M G:i T" }}</b> | with <b>{{ issue.event_count }}</b> events
|
||||
<div class="text-sm">from <b>{{ issue.first_seen|date:"j M G:i T" }}</b> | last <b>{{ issue.last_seen|date:"j M G:i T" }}</b> | with <b>{{ issue.digested_event_count }}</b> events
|
||||
{% if issue.transaction %}| <span class="font-bold">{{ issue.transaction }} </span>{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
{# event-nav only #}
|
||||
<div class="flex">
|
||||
<div class="overflow-hidden">
|
||||
<div class="italic">{{ event.server_side_timestamp|date:"j M G:i T" }} (Event {{ event.ingest_order }} of {{ issue.event_count }})</div>
|
||||
<div class="italic">{{ event.server_side_timestamp|date:"j M G:i T" }} (Event {{ event.digest_order }} of {{ issue.digested_event_count }})</div>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto flex-none">
|
||||
@@ -30,7 +30,7 @@
|
||||
<div class="flex">
|
||||
<div class="overflow-hidden">
|
||||
{% if forloop.counter0 == 0 %}
|
||||
<div class="italic">{{ event.server_side_timestamp|date:"j M G:i T" }} (Event {{ event.ingest_order }} of {{ issue.event_count }})</div>
|
||||
<div class="italic">{{ event.server_side_timestamp|date:"j M G:i T" }} (Event {{ event.digest_order }} of {{ issue.digested_event_count }})</div>
|
||||
{% endif %}
|
||||
<h1 class="text-2xl font-bold {% if forloop.counter0 > 0 %}mt-4{% endif %} text-ellipsis whitespace-nowrap overflow-hidden">{{ exception.type }}</h1>
|
||||
<div class="text-lg mb-4 text-ellipsis whitespace-nowrap overflow-hidden">{{ exception.value }}</div>
|
||||
|
||||
@@ -17,9 +17,9 @@ urlpatterns = [
|
||||
path('issue/<uuid:issue_pk>/event/<uuid:event_pk>/details/', issue_event_details, name="event_details"),
|
||||
path('issue/<uuid:issue_pk>/event/<uuid:event_pk>/breadcrumbs/', issue_event_breadcrumbs, name="event_breadcrumbs"),
|
||||
|
||||
path('issue/<uuid:issue_pk>/event/<int:ingest_order>/', issue_event_stacktrace, name="event_stacktrace"),
|
||||
path('issue/<uuid:issue_pk>/event/<int:ingest_order>/details/', issue_event_details, name="event_details"),
|
||||
path('issue/<uuid:issue_pk>/event/<int:ingest_order>/breadcrumbs/', issue_event_breadcrumbs,
|
||||
path('issue/<uuid:issue_pk>/event/<int:digest_order>/', issue_event_stacktrace, name="event_stacktrace"),
|
||||
path('issue/<uuid:issue_pk>/event/<int:digest_order>/details/', issue_event_details, name="event_details"),
|
||||
path('issue/<uuid:issue_pk>/event/<int:digest_order>/breadcrumbs/', issue_event_breadcrumbs,
|
||||
name="event_breadcrumbs"),
|
||||
|
||||
path('issue/<uuid:issue_pk>/history/', issue_history),
|
||||
|
||||
@@ -257,7 +257,7 @@ def _handle_post(request, issue):
|
||||
return HttpResponseRedirect(request.path_info)
|
||||
|
||||
|
||||
def _get_event(issue, event_pk, ingest_order):
|
||||
def _get_event(issue, event_pk, digest_order):
|
||||
if event_pk is not None:
|
||||
# we match on both internal and external id, trying internal first
|
||||
try:
|
||||
@@ -265,19 +265,19 @@ def _get_event(issue, event_pk, ingest_order):
|
||||
except Event.DoesNotExist:
|
||||
return get_object_or_404(Event, issue=issue, event_id=event_pk)
|
||||
|
||||
elif ingest_order is not None:
|
||||
return get_object_or_404(Event, issue=issue, ingest_order=ingest_order)
|
||||
elif digest_order is not None:
|
||||
return get_object_or_404(Event, issue=issue, digest_order=digest_order)
|
||||
else:
|
||||
raise ValueError("either event_pk or ingest_order must be provided")
|
||||
raise ValueError("either event_pk or digest_order must be provided")
|
||||
|
||||
|
||||
@atomic_for_request_method
|
||||
@issue_membership_required
|
||||
def issue_event_stacktrace(request, issue, event_pk=None, ingest_order=None):
|
||||
def issue_event_stacktrace(request, issue, event_pk=None, digest_order=None):
|
||||
if request.method == "POST":
|
||||
return _handle_post(request, issue)
|
||||
|
||||
event = _get_event(issue, event_pk, ingest_order)
|
||||
event = _get_event(issue, event_pk, digest_order)
|
||||
|
||||
parsed_data = json.loads(event.data)
|
||||
|
||||
@@ -320,11 +320,11 @@ def issue_event_stacktrace(request, issue, event_pk=None, ingest_order=None):
|
||||
|
||||
@atomic_for_request_method
|
||||
@issue_membership_required
|
||||
def issue_event_breadcrumbs(request, issue, event_pk=None, ingest_order=None):
|
||||
def issue_event_breadcrumbs(request, issue, event_pk=None, digest_order=None):
|
||||
if request.method == "POST":
|
||||
return _handle_post(request, issue)
|
||||
|
||||
event = _get_event(issue, event_pk, ingest_order)
|
||||
event = _get_event(issue, event_pk, digest_order)
|
||||
|
||||
parsed_data = json.loads(event.data)
|
||||
|
||||
@@ -348,11 +348,11 @@ def _date_with_milis_html(timestamp):
|
||||
|
||||
@atomic_for_request_method
|
||||
@issue_membership_required
|
||||
def issue_event_details(request, issue, event_pk=None, ingest_order=None):
|
||||
def issue_event_details(request, issue, event_pk=None, digest_order=None):
|
||||
if request.method == "POST":
|
||||
return _handle_post(request, issue)
|
||||
|
||||
event = _get_event(issue, event_pk, ingest_order)
|
||||
event = _get_event(issue, event_pk, digest_order)
|
||||
parsed_data = json.loads(event.data)
|
||||
|
||||
key_info = [
|
||||
|
||||
Reference in New Issue
Block a user