Skip to content

Commit

Permalink
bids can be pinned
Browse files Browse the repository at this point in the history
[#182383661]
  • Loading branch information
uraniumanchor committed Jun 6, 2022
1 parent ada843d commit 57d6922
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 44 deletions.
1 change: 1 addition & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,7 @@ def add_event_fields(fields, event, prefix):
goal=bid.goal,
state=bid.state,
istarget=bid.istarget,
pinned=bid.pinned,
revealedtime=format_time(bid.revealedtime),
allowuseroptions=bid.allowuseroptions,
biddependency=bid.biddependency_id,
Expand Down
92 changes: 61 additions & 31 deletions tests/test_bid.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,12 @@ def setUp(self):
)
self.pending_bid.save()
self.challenge = models.Bid.objects.create(
name='Challenge', speedrun=self.run, istarget=True, state='OPENED', goal=15,
name='Challenge',
istarget=True,
state='OPENED',
pinned=True,
goal=15,
speedrun=self.run,
)
self.challenge_donation = models.DonationBid.objects.create(
donation=self.donation2, bid=self.challenge, amount=self.donation2.amount,
Expand Down Expand Up @@ -161,42 +166,67 @@ def test_pending_bid(self):
self.opened_parent_bid.total, 0, msg='parent bid total is wrong'
)

def test_autoclose(self):
self.challenge.refresh_from_db()
self.assertEqual(self.challenge.state, 'OPENED')
self.assertTrue(self.challenge.pinned)
models.DonationBid.objects.create(
donation=self.donation, bid=self.challenge, amount=self.donation.amount
)
self.challenge.refresh_from_db()
self.assertEqual(self.challenge.state, 'CLOSED')
self.assertFalse(self.challenge.pinned)

def test_state_propagation(self):
for state in ['CLOSED', 'HIDDEN', 'OPENED']:
self.opened_parent_bid.state = state
self.opened_parent_bid.save()
self.opened_bid.refresh_from_db()
self.assertEqual(
self.opened_bid.state,
state,
msg=f'Child state `{state}` did not propagate from parent during parent save',
)
for bid in [self.pending_bid, self.denied_bid]:
old_state = bid.state
bid.refresh_from_db()
with self.subTest(state=state):
self.opened_parent_bid.state = state
self.opened_parent_bid.save()
self.opened_bid.refresh_from_db()
self.assertEqual(
bid.state,
old_state,
msg=f'Child state `{old_state}` should not have changed during parent save',
self.opened_bid.state,
state,
msg=f'Child state `{state}` did not propagate from parent during parent save',
)
for bid in [self.pending_bid, self.denied_bid]:
with self.subTest(child_state=bid.state):
old_state = bid.state
bid.refresh_from_db()
self.assertEqual(
bid.state,
old_state,
msg=f'Child state `{old_state}` should not have changed during parent save',
)
for state in ['CLOSED', 'HIDDEN']:
self.opened_bid.state = state
self.opened_bid.save()
self.opened_bid.refresh_from_db()
self.assertEqual(
self.opened_bid.state,
'OPENED',
msg=f'Child state `{state}` did not propagate from parent during child save',
)
with self.subTest(child_state=state):
self.opened_bid.state = state
self.opened_bid.save()
self.opened_bid.refresh_from_db()
self.assertEqual(
self.opened_bid.state,
'OPENED',
msg=f'Child state `{state}` did not propagate from parent during child save',
)
for state in ['PENDING', 'DENIED']:
self.opened_bid.state = state
self.opened_bid.save()
self.opened_bid.refresh_from_db()
self.assertEqual(
self.opened_bid.state,
state,
msg=f'Child state `{state}` should not have propagated from parent during child save',
)
with self.subTest(child_state=state):
self.opened_bid.state = state
self.opened_bid.save()
self.opened_bid.refresh_from_db()
self.assertEqual(
self.opened_bid.state,
state,
msg=f'Child state `{state}` should not have propagated from parent during child save',
)

def test_pin_propagation(self):
self.opened_parent_bid.pinned = True
self.opened_parent_bid.save()
self.opened_bid.refresh_from_db()
self.assertTrue(self.opened_bid.pinned, msg='Child pin flag did not propagate')
self.opened_parent_bid.pinned = False
self.opened_parent_bid.save()
self.opened_bid.refresh_from_db()
self.assertFalse(self.opened_bid.pinned, msg='Child pin flag did not propagate')

def test_bid_option_max_length_require(self):
# A bid cannot set option_max_length if allowuseroptions is not set
Expand Down
49 changes: 49 additions & 0 deletions tests/test_search_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import datetime
import random

import pytz
from django.contrib.auth.models import User, Permission
from django.core.exceptions import PermissionDenied
from django.db.models import Q
Expand Down Expand Up @@ -45,6 +46,9 @@ def setUp(self):
)
self.opened_bids += denied_bids[0]
self.denied_bids = denied_bids[1]
self.pinned_bid = opened_bids[0][-1]
self.pinned_bid.pinned = True
self.pinned_bid.save()
self.accepted_prizes = randgen.generate_prizes(self.rand, self.event, 5)
self.pending_prizes = randgen.generate_prizes(
self.rand, self.event, 5, state='PENDING'
Expand Down Expand Up @@ -185,6 +189,51 @@ def test_closed_feed(self):
expected = self.query.filter(state='CLOSED')
self.assertSetEqual(set(actual), set(expected))

# TODO: these need more detailed tests
def test_current_feed(self):
actual = apply_feed_filter(
self.query,
'bid',
'current',
params=dict(time=self.event.datetime, min_runs=0, max_runs=5),
)
expected = self.query.filter(
Q(
speedrun__in=(
r.pk
for r in self.event.speedrun_set.filter(
endtime__lte=self.event.datetime.astimezone(pytz.utc)
+ datetime.timedelta(hours=6)
)[:5]
)
)
| Q(pinned=True),
state='OPENED',
)
self.assertSetEqual(set(actual), set(expected))

def test_current_plus_feed(self):
actual = apply_feed_filter(
self.query,
'bid',
'current_plus',
params=dict(time=self.event.datetime, min_runs=0, max_runs=5),
)
expected = self.query.filter(
Q(
speedrun__in=(
r.pk
for r in self.event.speedrun_set.filter(
endtime__lte=self.event.datetime.astimezone(pytz.utc)
+ datetime.timedelta(hours=6)
)[:5]
)
)
| Q(pinned=True),
state__in=['OPENED', 'CLOSED'],
)
self.assertSetEqual(set(actual), set(expected))

def test_all_feed_without_permission(self):
with self.assertRaises(PermissionDenied):
apply_feed_filter(self.query, 'bid', 'all')
Expand Down
1 change: 1 addition & 0 deletions tracker/admin/bid.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class BidAdmin(CustomModelAdmin):
'shortdescription',
'goal',
'istarget',
'pinned',
'allowuseroptions',
'option_max_length',
'revealedtime',
Expand Down
18 changes: 18 additions & 0 deletions tracker/migrations/0020_add_pinned_to_bid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.2.16 on 2021-01-04 03:11

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('tracker', '0019_add_pinned_to_donation'),
]

operations = [
migrations.AddField(
model_name='bid',
name='pinned',
field=models.BooleanField(default=False, help_text='Will always show up in the current feeds'),
),
]
14 changes: 14 additions & 0 deletions tracker/migrations/0021_merge_20210628_2126.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Generated by Django 2.2.19 on 2021-06-28 21:26

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('tracker', '0020_add_milestone'),
('tracker', '0020_add_pinned_to_bid'),
]

operations = [
]
12 changes: 11 additions & 1 deletion tracker/models/bid.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from datetime import datetime
from decimal import Decimal
from gettext import gettext as _
import logging

import mptt.models
import pytz
Expand All @@ -20,6 +21,8 @@
'BidSuggestion',
]

logger = logging.getLogger(__name__)


class BidManager(models.Manager):
def get_by_natural_key(self, event, name, speedrun=None, parent=None):
Expand Down Expand Up @@ -119,6 +122,9 @@ class Bid(mptt.models.MPTTModel):
decimal_places=2, max_digits=20, editable=False, default=Decimal('0.00')
)
count = models.IntegerField(editable=False)
pinned = models.BooleanField(
default=False, help_text='Will always show up in the current feeds'
)

class Meta:
app_label = 'tracker'
Expand Down Expand Up @@ -300,6 +306,9 @@ def check_parent(self):
if self.state not in ['PENDING', 'DENIED'] and self.state != self.parent.state:
self.state = self.parent.state
changed = True
if self.pinned != self.parent.pinned:
self.pinned = self.parent.pinned
changed = True
return changed

@property
Expand All @@ -320,14 +329,15 @@ def update_total(self):
self.count = self.bids.filter(
donation__transactionstate='COMPLETED'
).count()
# auto close this if it's a challenge with no children and the goal's been met
# auto close and unpin this if it's a challenge with no children and the goal's been met
if (
self.goal
and self.state == 'OPENED'
and self.total >= self.goal
and self.istarget
):
self.state = 'CLOSED'
self.pinned = False
analytics.track(
AnalyticsEventTypes.INCENTIVE_MET,
{
Expand Down
27 changes: 15 additions & 12 deletions tracker/search_feeds.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,8 @@ def get_future_runs(**kwargs):
return get_upcoming_runs(include_current=False, **kwargs)


# TODO: why is this so complicated
def upcoming_bid_filter(**kwargs):
runs = [
run.id
for run in get_upcoming_runs(
SpeedRun.objects.filter(Q(bids__state='OPENED')).distinct(), **kwargs
)
]
return Q(speedrun__in=runs)
return Q(speedrun__in=(run.id for run in get_upcoming_runs(**kwargs)))


def get_upcoming_bids(**kwargs):
Expand Down Expand Up @@ -195,8 +188,12 @@ def run_feed_filter(feed_name, noslice, params, query):

def feed_params(noslice, params, init=None):
call_params = init or {}
if 'max_runs' in params:
call_params['max_runs'] = int(params['max_runs'])
if 'maxRuns' in params:
call_params['max_runs'] = int(params['maxRuns'])
if 'min_runs' in params:
call_params['min_runs'] = int(params['min_runs'])
if 'minRuns' in params:
call_params['min_runs'] = int(params['minRuns'])
if noslice:
Expand All @@ -219,12 +216,18 @@ def bid_feed_filter(feed_name, noslice, params, query, user):
elif feed_name == 'closed':
query = query.filter(state='CLOSED')
elif feed_name == 'current':
query = query.filter(state='OPENED').filter(
upcoming_bid_filter(**feed_params(noslice, params))
query = query.filter(
Q(state='OPENED')
& (upcoming_bid_filter(**feed_params(noslice, params)) | Q(pinned=True))
)
elif feed_name == 'current_plus':
query = query.filter(
Q(state__in=['OPENED', 'CLOSED'])
& (upcoming_bid_filter(**feed_params(noslice, params)) | Q(pinned=True))
)
elif feed_name == 'future':
query = query.filter(state='OPENED').filter(
future_bid_filter(**feed_params(noslice, params))
query = query.filter(
Q(state='OPENED') & future_bid_filter(**feed_params(noslice, params))
)
elif feed_name == 'pending':
if not user.has_perm('tracker.view_hidden_bid'):
Expand Down
1 change: 1 addition & 0 deletions tracker/views/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
'biddependency',
'total',
'count',
'pinned',
],
'speedrun': [
'name',
Expand Down

0 comments on commit 57d6922

Please sign in to comment.