Skip to content

Commit

Permalink
add optional Run field to Milestones (#761)
Browse files Browse the repository at this point in the history
[#188762424]
  • Loading branch information
uraniumanchor authored Jan 10, 2025
1 parent b416071 commit 927261d
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 12 deletions.
21 changes: 19 additions & 2 deletions tests/apiv2/test_milestones.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from tests import randgen
from tests.util import APITestCase
from tracker import models
from tracker.api import messages
Expand All @@ -18,13 +19,19 @@ def _format_milestone(self, milestone, with_event=True):
'short_description': milestone.short_description,
'start': milestone.start,
'name': milestone.name,
'run': milestone.run_id,
'visible': milestone.visible,
}

def setUp(self):
super().setUp()
self.run = randgen.generate_runs(self.rand, self.event, 1, ordered=True)[0]
self.public_milestone = models.Milestone.objects.create(
event=self.event, name='Public Milestone', amount=500.0, visible=True
event=self.event,
name='Public Milestone',
amount=500.0,
visible=True,
run=self.run,
)
self.hidden_milestone = models.Milestone.objects.create(
event=self.event, name='Hidden Milestone', amount=1500.0, visible=False
Expand All @@ -43,7 +50,7 @@ def test_serializer(self):
)

def test_fetch(self):
with self.subTest('happy path'), self.saveSnapshot():
with self.saveSnapshot():
with self.subTest('public'):
serialized = MilestoneSerializer(self.public_milestone)
data = self.get_detail(self.public_milestone)
Expand Down Expand Up @@ -83,6 +90,7 @@ def test_create(self):
data={
'name': 'New Milestone 2',
'amount': 1250,
'run': self.run.pk,
},
user=self.add_user,
kwargs={'event_pk': self.event.pk},
Expand Down Expand Up @@ -134,6 +142,15 @@ def test_create(self):
},
status_code=403,
)
self.post_new(
data={
'name': 'Mismatched Event Milestone',
'amount': 100,
'event': self.blank_event.pk,
'run': self.run.pk,
},
status_code=400,
)
self.post_new(user=None, status_code=403)

with self.subTest('user with locked permission'):
Expand Down
1 change: 1 addition & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,7 @@ def format_milestone(cls, milestone, request):
description=milestone.description,
short_description=milestone.short_description,
public=str(milestone),
run=milestone.run_id,
visible=milestone.visible,
),
model='tracker.milestone',
Expand Down
19 changes: 10 additions & 9 deletions tests/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,19 +549,19 @@ def _compare_value(self, key, expected, found):
def _compare_model(
self, expected_model, found_model, partial, prefix='', *, missing_ok=None
):
missing_ok = missing_ok or []
missing_ok = set(missing_ok or [])
self.assertIsInstance(found_model, dict, 'found_model was not a dict')
self.assertIsInstance(expected_model, dict, 'expected_model was not a dict')
found_keys = set(found_model.keys())
expected_keys = set(expected_model.keys())
if partial:
extra_keys = []
else:
extra_keys = set(found_model.keys()) - set(expected_model.keys())
missing_keys = (
set(expected_model.keys()) - set(found_model.keys()) - set(missing_ok)
)
extra_keys = found_keys - expected_keys
missing_keys = expected_keys - found_keys - missing_ok
unequal_keys = [
k
for k in expected_model.keys()
for k in expected_keys
if k in found_model
and not isinstance(found_model[k], (list, dict))
and not self._compare_value(k, expected_model[k], found_model[k])
Expand All @@ -574,18 +574,19 @@ def _compare_model(
found_model[k],
partial,
prefix=k,
missing_ok=missing_ok,
missing_ok=missing_ok
| {'event'}, # always ok to be missing 'event' on nested objects
),
)
for k in expected_model.keys()
for k in expected_keys
if k in found_model and isinstance(found_model[k], dict)
]
nested_objects = [n for n in nested_objects if n[1]]
nested_list_keys = {
f'{prefix}.' if prefix else '' + f'{k}': self._compare_lists(
expected_model[k], found_model[k], partial, prefix=k
)
for k in expected_model.keys()
for k in expected_keys
if k in found_model and isinstance(found_model[k], list)
}
for k, v in nested_list_keys.items():
Expand Down
2 changes: 1 addition & 1 deletion tracker/admin/donation.py
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ def merge_donors(self, request, queryset):

@register(models.Milestone)
class MilestoneAdmin(EventLockedMixin, EventReadOnlyMixin, CustomModelAdmin):
autocomplete_fields = ('event',)
autocomplete_fields = ('event', 'run')
search_fields = ('name', 'description', 'short_description')
list_filter = ('event',)
list_display = ('name', 'event', 'start', 'amount', 'visible')
3 changes: 3 additions & 0 deletions tracker/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from rest_framework.exceptions import ErrorDetail, ValidationError
from rest_framework.relations import PrimaryKeyRelatedField
from rest_framework.serializers import ListSerializer, as_serializer_error
from rest_framework.utils import model_meta
from rest_framework.validators import UniqueTogetherValidator
Expand Down Expand Up @@ -946,6 +947,7 @@ class MilestoneSerializer(
):
type = ClassNameField()
event = EventSerializer()
run = PrimaryKeyRelatedField(queryset=SpeedRun.objects.all(), required=False)

class Meta:
model = Milestone
Expand All @@ -956,6 +958,7 @@ class Meta:
'start',
'amount',
'name',
'run',
'visible',
'description',
'short_description',
Expand Down
19 changes: 19 additions & 0 deletions tracker/migrations/0049_add_milestone_run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 5.1.4 on 2025-01-09 14:38

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('tracker', '0048_remove_old_ad_permission'),
]

operations = [
migrations.AddField(
model_name='milestone',
name='run',
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to='tracker.speedrun'),
),
]
9 changes: 9 additions & 0 deletions tracker/models/donation.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,13 @@ class Milestone(models.Model):
validators=[positive, nonzero],
)
name = models.CharField(max_length=64)
run = models.ForeignKey(
'tracker.SpeedRun',
blank=True,
null=True,
default=None,
on_delete=models.SET_NULL,
)
visible = models.BooleanField(default=False)
description = models.TextField(max_length=1024, blank=True)
short_description = models.TextField(
Expand All @@ -675,6 +682,8 @@ class Milestone(models.Model):
def clean(self):
if self.start >= self.amount:
raise ValidationError({'start': 'start must be less than amount'})
if self.run_id and self.run.event_id != self.event_id:
raise ValidationError({'run': 'Run does not belong to that event'})

def __str__(self):
return f'{self.event.name} -- {self.name} -- {self.amount}'
Expand Down

0 comments on commit 927261d

Please sign in to comment.