From b9651249903e3ad2b7b340e2dd4f37252e0929f0 Mon Sep 17 00:00:00 2001 From: Benjamin Cutler Date: Fri, 17 Jan 2025 17:55:00 -0700 Subject: [PATCH] remove targetamount field from Event, migrate it to Milestones [#188794734] --- bundles/tracker/events/EventActions.ts | 1 - bundles/tracker/events/EventTypes.ts | 1 - spec/fixtures/event.ts | 1 - tests/randgen.py | 3 +-- tests/test_api.py | 2 -- tests/test_bid.py | 4 +-- tests/test_consumers.py | 2 -- tests/test_delete_protection.py | 2 -- tests/test_donate.py | 4 +-- tests/test_donation.py | 7 +++-- tests/test_donor.py | 10 +++---- tests/test_event.py | 16 +++-------- tests/test_eventutil.py | 1 - tests/test_headset.py | 4 ++- tests/test_interstitial.py | 8 ++---- tests/test_milestone.py | 21 ++++++++++++++- tests/test_mod_filter.py | 4 +-- tests/test_speedrun.py | 7 ++--- tests/util.py | 6 ++--- tracker/admin/event.py | 1 - .../0053_migrate_target_to_milestone.py | 27 +++++++++++++++++++ .../0054_delete_event_targetamount.py | 17 ++++++++++++ tracker/models/event.py | 7 ----- tracker/views/public.py | 2 -- 24 files changed, 91 insertions(+), 67 deletions(-) create mode 100644 tracker/migrations/0053_migrate_target_to_milestone.py create mode 100644 tracker/migrations/0054_delete_event_targetamount.py diff --git a/bundles/tracker/events/EventActions.ts b/bundles/tracker/events/EventActions.ts index 325868c5a..6243c145b 100644 --- a/bundles/tracker/events/EventActions.ts +++ b/bundles/tracker/events/EventActions.ts @@ -24,7 +24,6 @@ function eventFromAPIEvent({ pk, fields }: { pk: number; fields: { [field: strin paypalEmail: fields.paypalemail, paypalCurrency: fields.paypalcurrency, paypalImgurl: fields.paypalimgurl, - targetAmount: CurrencyUtils.parseCurrencyForced(fields.targetamount), allowDonations: fields.allow_donations, minimumDonation: CurrencyUtils.parseCurrencyForced(fields.minimumdonation), autoApproveThreshold: CurrencyUtils.parseCurrency(fields.auto_approve_threshold), diff --git a/bundles/tracker/events/EventTypes.ts b/bundles/tracker/events/EventTypes.ts index b612159fd..2f989c9ff 100644 --- a/bundles/tracker/events/EventTypes.ts +++ b/bundles/tracker/events/EventTypes.ts @@ -16,7 +16,6 @@ export type Event = { paypalEmail: string; paypalCurrency: string; paypalImgurl: string; - targetAmount: number; allowDonations: boolean; minimumDonation: number; autoApproveThreshold?: number; diff --git a/spec/fixtures/event.ts b/spec/fixtures/event.ts index f1e9a5f99..3fb9a8475 100644 --- a/spec/fixtures/event.ts +++ b/spec/fixtures/event.ts @@ -13,7 +13,6 @@ export function getFixtureEvent(overrides?: Partial): Event { paypalEmail: 'paypal@example.com', paypalCurrency: 'USB', paypalImgurl: '', - targetAmount: 5000, allowDonations: true, minimumDonation: 5, allowedPrizeCountries: [], diff --git a/tests/randgen.py b/tests/randgen.py index 3c20967d9..3bc860268 100644 --- a/tests/randgen.py +++ b/tests/randgen.py @@ -457,7 +457,6 @@ def generate_event(rand: random.Random, start_time=None): event.datetime = start_time event.name = random_event_name(rand) event.short = event.name - event.targetamount = Decimal('1000.00') event.paypalemail = 'receiver@example.com' event.full_clean() return event @@ -655,7 +654,7 @@ def generate_milestone( if min_amount is None: min_amount = 1 if max_amount is None: - max_amount = event.targetamount + max_amount = 1000 if amount is None: amount = random_amount(rand, min_amount=min_amount, max_amount=max_amount) # TODO: this very occasionally makes a duplicate diff --git a/tests/test_api.py b/tests/test_api.py index aece95e0d..c2bf2627f 100755 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -117,7 +117,6 @@ def setUp(self): self.run1.runners.add(self.runner1) self.event2 = models.Event.objects.create( datetime=tomorrow_noon, - targetamount=5, short='event2', ) self.run5 = models.SpeedRun.objects.create( @@ -499,7 +498,6 @@ def format_event(self, event): receiver_short=event.receiver_short, receivername=event.receivername, short=event.short, - targetamount=event.targetamount, timezone=str(event.timezone), use_one_step_screening=event.use_one_step_screening, ), diff --git a/tests/test_bid.py b/tests/test_bid.py index edf623906..401af3654 100644 --- a/tests/test_bid.py +++ b/tests/test_bid.py @@ -18,12 +18,12 @@ def setUp(self): self.rand = random.Random(None) self.event = models.Event.objects.get_or_create( short='test', - defaults=dict(datetime=today_noon, targetamount=5), + defaults=dict(datetime=today_noon), )[0] self.locked_event = models.Event.objects.get_or_create( short='locked', locked=True, - defaults=dict(datetime=long_ago_noon, targetamount=5), + defaults=dict(datetime=long_ago_noon), )[0] self.run = models.SpeedRun.objects.create( event=self.event, diff --git a/tests/test_consumers.py b/tests/test_consumers.py index b2ab4f65b..736dade52 100644 --- a/tests/test_consumers.py +++ b/tests/test_consumers.py @@ -43,7 +43,6 @@ def setUp(self): self.donor = models.Donor.objects.create() self.event = models.Event.objects.create( receivername='Médecins Sans Frontières', - targetamount=1, paypalemail='msf@example.com', paypalcurrency='USD', datetime=today_noon, @@ -141,7 +140,6 @@ def setUp(self): self.donor = models.Donor.objects.create() self.event = models.Event.objects.create( receivername='Médecins Sans Frontières', - targetamount=1, paypalemail='msf@example.com', paypalcurrency='USD', datetime=today_noon, diff --git a/tests/test_delete_protection.py b/tests/test_delete_protection.py index fa3662baf..72c723d86 100644 --- a/tests/test_delete_protection.py +++ b/tests/test_delete_protection.py @@ -12,7 +12,6 @@ def setUp(self): short='scratch', name='Scratch Event', datetime=datetime.datetime(2000, 1, 1, 12, tzinfo=datetime.timezone.utc), - targetamount=1000, ) def tearDown(self): @@ -139,7 +138,6 @@ def testDeleteEvent(self): short='delete', name='Delete Event', datetime=datetime.datetime(2001, 1, 1, 12), - targetamount=1000, ) ): pass diff --git a/tests/test_donate.py b/tests/test_donate.py index 10c2fc281..a2c568968 100644 --- a/tests/test_donate.py +++ b/tests/test_donate.py @@ -26,17 +26,15 @@ def testAliasAnonToVisibilityAnon(self): class TestDonateViews(TransactionTestCase): def setUp(self): self.normal_event = models.Event.objects.create( - targetamount=5, short='normal', name='Normal', datetime=today_noon + short='normal', name='Normal', datetime=today_noon ) self.upcoming_event = models.Event.objects.create( - targetamount=5, short='upcoming', name='Upcoming', datetime=tomorrow_noon, allow_donations=False, ) self.locked_event = models.Event.objects.create( - targetamount=5, short='locked', name='Locked', datetime=long_ago_noon, diff --git a/tests/test_donation.py b/tests/test_donation.py index 47ab5ffba..7c9db0e4d 100644 --- a/tests/test_donation.py +++ b/tests/test_donation.py @@ -20,7 +20,6 @@ class TestDonation(TestCase): def setUp(self): self.event = models.Event.objects.create( receivername='Médecins Sans Frontières', - targetamount=1, datetime=datetime.datetime(2018, 1, 1), ) @@ -270,7 +269,7 @@ def setUp(self): Permission.objects.get(name='Can view donation'), ) self.event = models.Event.objects.create( - short='ev1', name='Event 1', targetamount=5, datetime=today_noon + short='ev1', name='Event 1', datetime=today_noon ) self.donor = models.Donor.objects.create(firstname='John', lastname='Doe') @@ -462,10 +461,10 @@ def setUp(self): 'admin', 'admin@example.com', 'password' ) self.event = models.Event.objects.create( - short='ev1', name='Event 1', targetamount=5, datetime=today_noon + short='ev1', name='Event 1', datetime=today_noon ) self.other_event = models.Event.objects.create( - short='ev2', name='Event 2', targetamount=5, datetime=tomorrow_noon + short='ev2', name='Event 2', datetime=tomorrow_noon ) self.regular_donor = models.Donor.objects.create( alias='JohnDoe', visibility='ALIAS' diff --git a/tests/test_donor.py b/tests/test_donor.py index 4f04a49d9..fbe22d395 100644 --- a/tests/test_donor.py +++ b/tests/test_donor.py @@ -29,10 +29,10 @@ def setUp(self): firstname='Jane', lastname='Doe', email='janedoe@example.com' ) self.ev1 = models.Event.objects.create( - short='ev1', name='Event 1', targetamount=5, datetime=today_noon + short='ev1', name='Event 1', datetime=today_noon ) self.ev2 = models.Event.objects.create( - short='ev2', name='Event 2', targetamount=5, datetime=today_noon + short='ev2', name='Event 2', datetime=today_noon ) def test_donor_cache(self): @@ -290,10 +290,10 @@ class TestDonorView(TestCase): def setUp(self): super(TestDonorView, self).setUp() self.event = models.Event.objects.create( - name='test', targetamount=10, datetime=today_noon, short='test' + name='test', datetime=today_noon, short='test' ) self.other_event = models.Event.objects.create( - name='test2', targetamount=10, datetime=tomorrow_noon, short='test2' + name='test2', datetime=tomorrow_noon, short='test2' ) def set_donor(self, firstname='John', lastname='Doe', **kwargs): @@ -428,7 +428,7 @@ def setUp(self): self.super_user = User.objects.create_superuser('admin', 'admin@example.com') self.limited_user = User.objects.create(username='staff') self.event = models.Event.objects.create( - short='ev1', name='Event 1', targetamount=5, datetime=today_noon + short='ev1', name='Event 1', datetime=today_noon ) self.donor = models.Donor.objects.create(firstname='John', lastname='Doe') diff --git a/tests/test_event.py b/tests/test_event.py index 8112ef3c4..8ac3e8161 100644 --- a/tests/test_event.py +++ b/tests/test_event.py @@ -19,9 +19,7 @@ class TestEvent(TestCase): def setUp(self): self.rand = make_rand() - self.event = models.Event.objects.create( - targetamount=1, datetime=today_noon, short='test' - ) + self.event = models.Event.objects.create(datetime=today_noon, short='test') self.run = models.SpeedRun.objects.create( event=self.event, starttime=today_noon, @@ -107,7 +105,7 @@ def test_manager_current(self): self.event.datetime = today_noon self.event.save() overlap_event = models.Event.objects.create( - targetamount=1, datetime=today_noon, short='test2' + datetime=today_noon, short='test2' ) models.SpeedRun.objects.create( event=overlap_event, @@ -136,12 +134,10 @@ def test_manager_next(self): with self.subTest('multiple events'): prev_event = models.Event.objects.create( - targetamount=1, datetime=today_noon - datetime.timedelta(hours=1), short='test2', ) next_event = models.Event.objects.create( - targetamount=1, datetime=today_noon + datetime.timedelta(hours=1), short='test4', ) @@ -191,7 +187,7 @@ def test_prev_and_next(self): class TestEventManager(TransactionTestCase): def setUp(self): self.rand = random.Random() - self.event = models.Event.objects.create(targetamount=1, datetime=today_noon) + self.event = models.Event.objects.create(datetime=today_noon) self.completed_donations = randgen.generate_donations( self.rand, self.event, @@ -225,7 +221,7 @@ def test_amount_annotation(self): class TestEventViews(TransactionTestCase): def setUp(self): self.event = models.Event.objects.create( - targetamount=1, datetime=today_noon, short='short', name='Short' + datetime=today_noon, short='short', name='Short' ) @override_settings(TRACKER_LOGO='example-logo.png') @@ -263,7 +259,6 @@ def test_json_with_no_donations(self): 'count': 0, 'max': 0.0, 'median': 0.0, - 'target': 1.0, }, }, ) @@ -289,7 +284,6 @@ def test_json_with_only_pending_donations(self): 'count': 0, 'max': 0.0, 'median': 0.0, - 'target': 1.0, }, }, ) @@ -320,7 +314,6 @@ def test_json_with_cleared_donations(self): 'count': 2, 'max': 10.0, 'median': 7.5, - 'target': 1.0, }, }, ) @@ -333,7 +326,6 @@ def setUp(self): ) timezone = zoneinfo.ZoneInfo(settings.TIME_ZONE) self.event = models.Event.objects.create( - targetamount=5, datetime=today_noon, timezone=timezone, name='test event', diff --git a/tests/test_eventutil.py b/tests/test_eventutil.py index af75af032..fa70b61be 100644 --- a/tests/test_eventutil.py +++ b/tests/test_eventutil.py @@ -16,7 +16,6 @@ def setUp(self): self.donor = Donor.objects.create() self.event = Event.objects.create( receivername='Médecins Sans Frontières', - targetamount=1, paypalemail='msf@example.com', paypalcurrency='USD', datetime=datetime.datetime(2018, 1, 1), diff --git a/tests/test_headset.py b/tests/test_headset.py index 04aead7b9..73ef24c8c 100644 --- a/tests/test_headset.py +++ b/tests/test_headset.py @@ -13,7 +13,9 @@ def setUpBeforeMigration(self, apps): SpeedRun = apps.get_model('tracker', 'SpeedRun') HostSlot = apps.get_model('tracker', 'HostSlot') self.event = Event.objects.create( - short='test', name='Test Event', datetime=today_noon, targetamount=100 + short='test', + name='Test Event', + datetime=today_noon, ) self.run1 = SpeedRun.objects.create( event=self.event, name='Test Run 1', order=1, run_time='0:05:00' diff --git a/tests/test_interstitial.py b/tests/test_interstitial.py index a965b45b4..564590ed7 100644 --- a/tests/test_interstitial.py +++ b/tests/test_interstitial.py @@ -10,12 +10,8 @@ class TestInterstitial(TestCase): def setUp(self): - self.event1 = models.Event.objects.create( - short='test1', datetime=today_noon, targetamount=5 - ) - self.event2 = models.Event.objects.create( - short='test2', datetime=today_noon, targetamount=5 - ) + self.event1 = models.Event.objects.create(short='test1', datetime=today_noon) + self.event2 = models.Event.objects.create(short='test2', datetime=today_noon) self.run1 = models.SpeedRun.objects.create( event=self.event1, name='Test Run 1', order=1 ) diff --git a/tests/test_milestone.py b/tests/test_milestone.py index 91cfc9fa9..e70f1e8d0 100644 --- a/tests/test_milestone.py +++ b/tests/test_milestone.py @@ -7,7 +7,7 @@ from tracker.models import Milestone from . import randgen -from .util import APITestCase, today_noon +from .util import APITestCase, MigrationsTestCase, today_noon, tomorrow_noon class TestMilestone(APITestCase): @@ -64,3 +64,22 @@ def test_milestone_list(self): ) self.assertContains(resp, self.visible_milestone.name) self.assertNotContains(resp, self.invisible_milestone.name) + + +class TestMilestoneTargetMigration(MigrationsTestCase): + migrate_from = (('tracker', '0052_delete_interview_text_columns'),) + migrate_to = (('tracker', '0054_delete_event_targetamount'),) + + def setUpBeforeMigration(self, apps): + Event = apps.get_model('tracker', 'Event') + Event.objects.create( + name='Test', short='test', targetamount=500, datetime=today_noon + ) + Event.objects.create( + name='Empty Test', short='empty', targetamount=0, datetime=tomorrow_noon + ) + + def test_milestone_created(self): + Milestone = self.apps.get_model('tracker', 'Milestone') + self.assertEqual(Milestone.objects.count(), 1) + self.assertEqual(Milestone.objects.first().amount, 500) diff --git a/tests/test_mod_filter.py b/tests/test_mod_filter.py index d71760a22..c39a8ece6 100644 --- a/tests/test_mod_filter.py +++ b/tests/test_mod_filter.py @@ -11,7 +11,7 @@ class TestWordFilter(TransactionTestCase): def setUp(self): self.filter = models.WordFilter.objects.create(word='hype') self.event = models.Event.objects.create( - short='ev1', name='Event 1', targetamount=5, datetime=today_noon + short='ev1', name='Event 1', datetime=today_noon ) def testRejectionOfWordMatch(self): @@ -52,7 +52,7 @@ class TestAmountFilter(TransactionTestCase): def setUp(self): self.filter = models.AmountFilter.objects.create(amount=Decimal('4.20')) self.event = models.Event.objects.create( - short='ev1', name='Event 1', targetamount=5, datetime=today_noon + short='ev1', name='Event 1', datetime=today_noon ) def testRejectionOfAmountMatch(self): diff --git a/tests/test_speedrun.py b/tests/test_speedrun.py index 5a64b6db1..a2ae01c36 100755 --- a/tests/test_speedrun.py +++ b/tests/test_speedrun.py @@ -21,9 +21,7 @@ class TestSpeedRunBase(TransactionTestCase): def setUp(self): super().setUp() if not hasattr(self, 'event'): - self.event = models.Event.objects.create( - datetime=today_noon, targetamount=5 - ) + self.event = models.Event.objects.create(datetime=today_noon) self.run1 = models.SpeedRun.objects.create( event=self.event, name='Test Run', @@ -189,7 +187,7 @@ def test_tags(self): class TestMoveSpeedRun(TransactionTestCase): def setUp(self): - self.event1 = models.Event.objects.create(datetime=today_noon, targetamount=5) + self.event1 = models.Event.objects.create(datetime=today_noon) self.run1 = models.SpeedRun.objects.create( name='Test Run 1', run_time='0:45:00', setup_time='0:05:00', order=1 ) @@ -385,7 +383,6 @@ class TestSpeedRunAdmin(TransactionTestCase): def setUp(self): self.event1 = models.Event.objects.create( datetime=today_noon, - targetamount=5, timezone=zoneinfo.ZoneInfo( getattr(settings, 'TIME_ZONE', 'America/Denver') ), diff --git a/tests/util.py b/tests/util.py index ea42f0539..25e3501a8 100644 --- a/tests/util.py +++ b/tests/util.py @@ -195,7 +195,7 @@ def setUpBeforeMigration(self, apps): Prize = apps.get_model('tracker', 'Prize') Event = apps.get_model('tracker', 'Event') self.event = Event.objects.create( - short='test', name='Test Event', datetime=today_noon, targetamount=100 + short='test', name='Test Event', datetime=today_noon ) self.prize1 = Prize.objects.create(event=self.event, name='Test Prize') @@ -977,19 +977,17 @@ def setUp(self): self.client = APIClient() self.locked_event = models.Event.objects.create( datetime=long_ago_noon, - targetamount=5, short='locked', name='Locked Event', locked=True, ) self.blank_event = models.Event.objects.create( datetime=tomorrow_noon, - targetamount=5, short='blank', name='Blank Event', ) self.event = models.Event.objects.create( - datetime=today_noon, targetamount=5, short='test', name='Test Event' + datetime=today_noon, short='test', name='Test Event' ) self.anonymous_user = AnonymousUser() self.user = User.objects.create(username='test') diff --git a/tracker/admin/event.py b/tracker/admin/event.py index 1e680d3b7..6812f1c67 100644 --- a/tracker/admin/event.py +++ b/tracker/admin/event.py @@ -71,7 +71,6 @@ class EventAdmin(RelatedUserMixin, CustomModelAdmin): 'hashtag', 'receivername', 'receiver_short', - 'targetamount', 'use_one_step_screening', 'minimumdonation', 'auto_approve_threshold', diff --git a/tracker/migrations/0053_migrate_target_to_milestone.py b/tracker/migrations/0053_migrate_target_to_milestone.py new file mode 100644 index 000000000..eaa47409c --- /dev/null +++ b/tracker/migrations/0053_migrate_target_to_milestone.py @@ -0,0 +1,27 @@ +# Generated by Django 5.1.4 on 2025-01-18 00:33 + +from django.db import migrations + + +def target_to_milestone(apps, schema_editor): + Event = apps.get_model('tracker', 'Event') + Milestone = apps.get_model('tracker', 'Milestone') + for e in Event.objects.all(): + if e.targetamount: + Milestone.objects.get_or_create(event=e, amount=e.targetamount, defaults={'name': 'Target', 'visible': True}) + + +def noop(apps, schema_editor): + # no sensible way to undo this, so just leave it alone + pass + + +class Migration(migrations.Migration): + + dependencies = [ + ('tracker', '0052_delete_interview_text_columns'), + ] + + operations = [ + migrations.RunPython(target_to_milestone, noop, elidable=True) + ] diff --git a/tracker/migrations/0054_delete_event_targetamount.py b/tracker/migrations/0054_delete_event_targetamount.py new file mode 100644 index 000000000..e00201956 --- /dev/null +++ b/tracker/migrations/0054_delete_event_targetamount.py @@ -0,0 +1,17 @@ +# Generated by Django 5.1.4 on 2025-01-18 00:39 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('tracker', '0053_migrate_target_to_milestone'), + ] + + operations = [ + migrations.RemoveField( + model_name='event', + name='targetamount', + ), + ] diff --git a/tracker/models/event.py b/tracker/models/event.py index 6a222150f..e060475f7 100644 --- a/tracker/models/event.py +++ b/tracker/models/event.py @@ -116,13 +116,6 @@ class Event(models.Model): verbose_name='Receiver Name (Short)', help_text='Useful for space constrained displays', ) - targetamount = models.DecimalField( - decimal_places=2, - max_digits=20, - validators=[positive, nonzero], - verbose_name='Target Amount', - default=0, - ) minimumdonation = models.DecimalField( decimal_places=2, max_digits=20, diff --git a/tracker/views/public.py b/tracker/views/public.py index 17e87a53b..dd8421faf 100644 --- a/tracker/views/public.py +++ b/tracker/views/public.py @@ -80,8 +80,6 @@ def index(request, event=None): avg=Cast(Coalesce(Avg('amount'), 0), output_field=FloatField()), ) agg['median'] = float(util.median(donations, 'amount')) - if event.targetamount: - agg['target'] = float(event.targetamount) count = { 'runs': filters.run_model_query('run', eventParams).count(), 'prizes': filters.run_model_query('prize', eventParams).count(),