Skip to content

Commit

Permalink
add read-only Donor to v2 (#744)
Browse files Browse the repository at this point in the history
[#184870657]
  • Loading branch information
uraniumanchor authored Dec 17, 2024
1 parent 295ba07 commit ed9b2d9
Show file tree
Hide file tree
Showing 9 changed files with 314 additions and 83 deletions.
132 changes: 132 additions & 0 deletions tests/apiv2/test_donors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
from django.db.models import Q

from tests import randgen
from tests.util import APITestCase
from tracker.api.serializers import DonorSerializer


class TestDonor(APITestCase):
model_name = 'donor'
serializer_class = DonorSerializer

def _format_donor(self, donor, *, include_totals=False, event=None):
return {
'type': 'donor',
'id': donor.id,
**({'alias': donor.full_alias} if donor.visibility == 'ALIAS' else {}),
**(
{
'totals': [
{
'event': c.event_id,
'total': c.donation_total,
'count': c.donation_count,
'avg': c.donation_avg,
'max': c.donation_max,
}
for c in (
donor.cache.filter(Q(event__isnull=True) | Q(event=event))
if event
else donor.cache.all()
)
]
}
if include_totals
else {}
),
}

def setUp(self):
super().setUp()
randgen.generate_runs(self.rand, self.event, 1, ordered=True)
self.visible_donor = randgen.generate_donor(self.rand, visibility='ALIAS')
self.visible_donor.save()
randgen.generate_donations(
self.rand, self.event, num_donations=5, donors=[self.visible_donor]
)
self.anonymous_donor = randgen.generate_donor(self.rand, visibility='ANON')
self.anonymous_donor.save()
randgen.generate_donations(
self.rand, self.event, num_donations=3, donors=[self.anonymous_donor]
)

def test_fetch(self):
with self.saveSnapshot():
data = self.get_list(user=self.view_user)
self.assertExactV2Models(
[self.visible_donor, self.anonymous_donor], data['results']
)

data = self.get_list(user=self.view_user, data={'include_totals': ''})
self.assertExactV2Models(
[self.visible_donor, self.anonymous_donor],
data['results'],
serializer_kwargs={'include_totals': True},
)

data = self.get_list(
user=self.view_user,
kwargs={'event_pk': self.event.id},
data={'include_totals': ''},
)
self.assertExactV2Models(
[self.visible_donor, self.anonymous_donor],
data['results'],
serializer_kwargs={'include_totals': True, 'event_pk': self.event.id},
)

data = self.get_detail(self.visible_donor, user=self.view_user)
self.assertV2ModelPresent(self.visible_donor, data)

data = self.get_detail(
self.visible_donor, user=self.view_user, data={'include_totals': ''}
)
self.assertV2ModelPresent(
self.visible_donor, data, serializer_kwargs={'include_totals': True}
)

data = self.get_detail(
self.visible_donor,
user=self.view_user,
kwargs={'event_pk': self.event.id},
data={'include_totals': ''},
)
self.assertV2ModelPresent(
self.visible_donor,
data,
serializer_kwargs={'event_pk': self.event.id, 'include_totals': True},
)

data = self.get_list(
user=self.view_user, kwargs={'event_pk': self.locked_event.id}
)
self.assertEqual(len(data['results']), 0, msg='Donor list was not empty')

with self.subTest('error cases'):
with self.subTest('no donations on event'):
self.get_detail(
self.visible_donor,
user=self.view_user,
kwargs={'event_pk': self.locked_event.id},
status_code=404,
)

with self.subTest('anonymous'):
self.get_list(user=None, status_code=403)
self.get_detail(self.visible_donor, user=None, status_code=403)

def test_serializer(self):
data = DonorSerializer(self.visible_donor, include_totals=True).data
formatted = self._format_donor(self.visible_donor, include_totals=True)
# FIXME
data['totals'] = sorted(data['totals'], key=lambda t: t['event'] or 0)
formatted['totals'] = sorted(formatted['totals'], key=lambda t: t['event'] or 0)
self.assertEqual(data, formatted)
self.assertEqual(
len(data['totals']),
self.visible_donor.cache.count(),
msg='Cache count did not match',
)

data = DonorSerializer(self.anonymous_donor).data
self.assertEqual(data, self._format_donor(self.anonymous_donor))
2 changes: 1 addition & 1 deletion tests/apiv2/test_serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def test_requestedalias_different_donor_says_requestedalias(self):
# user entered, regardless of who we attribute it to internally.
self.donation.requestedalias = 'requested by donation'
self.donation.donor = generate_donor(
self.rand, alias='requested by donor', visibility='ALIAS'
self.rand, alias='requested_by_donor', visibility='ALIAS'
)

serialized = DonationSerializer(self.donation).data
Expand Down
31 changes: 19 additions & 12 deletions tests/randgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ def generate_donor(
donor.email = random_email(rand, alias)
if rand.getrandbits(1):
donor.paypalemail = random_paypal_email(rand, alias, donor.email)
donor.clean()
donor.full_clean()
return donor


Expand Down Expand Up @@ -163,7 +163,7 @@ def generate_run(
if ordered:
last = run.event.speedrun_set.last()
run.order = last.order + 1 if last else 1
run.clean()
run.full_clean()
return run


Expand All @@ -179,7 +179,7 @@ def generate_talent(
youtube=youtube or random_name(rand, 'youtube'),
donor=donor,
)
talent.clean()
talent.full_clean()
return talent


Expand Down Expand Up @@ -215,7 +215,10 @@ def generate_prize(
random_draw=True,
maxwinners=1,
state='ACCEPTED',
handler=None,
):
from django.contrib.auth.models import User

prize = Prize()
prize.name = random_prize_name(rand)
prize.description = random_prize_description(rand, prize.name)
Expand Down Expand Up @@ -250,7 +253,8 @@ def generate_prize(
prize.maxwinners = rand.randrange(maxwinners) + 1
if state:
prize.state = state
prize.clean()
prize.handler = handler or User.objects.get_or_create(username='prizehandler')[0]
prize.full_clean()
return prize


Expand All @@ -265,7 +269,7 @@ def generate_prize_key(
if not prize_winner and winner:
prize_winner = PrizeWinner.objects.create(prize=prize, winner=winner)
prize_key.prize_winner = prize_winner
prize_key.clean()
prize_key.full_clean()
return prize_key


Expand Down Expand Up @@ -356,12 +360,12 @@ def generate_bid(
bid.name = random_name(rand, 'challenge')
else:
bid.name = random_name(rand, 'choice')
bid.clean()
bid.full_clean()
return bid, children


def chain_insert_bid(bid, children):
bid.clean()
bid.full_clean()
bid.save()
for child in children:
chain_insert_bid(child[0], child[1])
Expand Down Expand Up @@ -421,7 +425,7 @@ def generate_donation(
assert Donor.objects.exists(), 'No donor provided and none exist'
donor = rand.choice(Donor.objects.all())
donation.donor = donor
donation.clean()
donation.full_clean()
return donation


Expand All @@ -447,7 +451,8 @@ def generate_event(rand: random.Random, start_time=None):
event.name = random_event_name(rand)
event.short = event.name
event.targetamount = Decimal('1000.00')
event.clean()
event.paypalemail = 'receiver@example.com'
event.full_clean()
return event


Expand Down Expand Up @@ -654,7 +659,7 @@ def generate_milestone(
description=random_name(rand, 'description'),
short_description=random_name(rand, 'short description'),
)
milestone.clean()
milestone.full_clean()
return milestone


Expand All @@ -676,11 +681,13 @@ def generate_ad(
ad = Ad(event=event, suborder=suborder, ad_type='IMAGE')
if run:
ad.anchor = run
ad.order = run.order
else:
ad.order = order
ad.filename = random_name(rand, 'filename') + '.jpg'
ad.ad_name = random_name(rand, 'ad_name')
ad.clean()
ad.sponsor_name = random_name(rand, 'sponsor')
ad.full_clean()
return ad


Expand All @@ -704,7 +711,7 @@ def generate_interview(
interview = Interview(event=event, order=run.order, suborder=suborder)
interview.interviewers = random_name(rand, 'interviewer')
interview.topic = random_name(rand, 'topic')
interview.clean()
interview.full_clean()
return interview


Expand Down
20 changes: 6 additions & 14 deletions tracker/api/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,10 @@ class TrackerFilter(filters.BaseFilterBackend):

def filter_queryset(self, request, queryset, view):
if not view.detail:
if 'id' in request.query_params:
try:
queryset = queryset.filter(
id__in=request.query_params.getlist('id')
)
except (TypeError, ValueError):
raise ParseError(
detail=messages.MALFORMED_SEARCH_PARAMETER_SPECIFIC % 'id',
code=messages.MALFORMED_SEARCH_PARAMETER_CODE,
)
filter_args = []
filter_params = {}
filter_kwargs = {}
if 'id' in request.query_params:
filter_kwargs['id__in'] = request.query_params.getlist('id')
for param, filter_param in self.filter_params.items():
if param in request.query_params:
if isinstance(filter_param, str):
Expand All @@ -43,7 +35,7 @@ def filter_queryset(self, request, queryset, view):
detail=messages.UNAUTHORIZED_FILTER_PARAM,
code=messages.UNAUTHORIZED_FILTER_PARAM_CODE,
)
filter_params[filter_param] = [
filter_kwargs[filter_param] = [
self.normalize_value(param, value) for value in values
]
else:
Expand All @@ -53,15 +45,15 @@ def filter_queryset(self, request, queryset, view):
detail=messages.UNAUTHORIZED_FILTER_PARAM,
code=messages.UNAUTHORIZED_FILTER_PARAM_CODE,
)
filter_params[filter_param] = self.normalize_value(
filter_kwargs[filter_param] = self.normalize_value(
param, value
)
elif isinstance(filter_param, Q):
filter_args.append(filter_param)
elif callable(filter_param):
filter_args.append(filter_param(request.query_params[param]))
try:
queryset = queryset.filter(*filter_args, **filter_params)
queryset = queryset.filter(*filter_args, **filter_kwargs)
except (ValueError, TypeError):
raise ParseError(
detail=messages.MALFORMED_SEARCH_PARAMETER,
Expand Down
Loading

0 comments on commit ed9b2d9

Please sign in to comment.