def post(self, request, *args, **kwargs): """ Return a mapping of participant IDs to membership statuses. """ postdata = json.loads(self.request.body) par_pks = postdata.get('participant_ids') if not isinstance(par_pks, list): return JsonResponse({'message': 'Bad request'}, status=400) # Span databases to map from participants -> users -> email addresses participants = models.Participant.objects.filter(pk__in=par_pks) user_to_par = dict(participants.values_list('user_id', 'pk')) email_addresses = EmailAddress.objects.filter( user_id__in=user_to_par, verified=True ) email_to_user = dict(email_addresses.values_list('email', 'user_id')) # Gives email -> membership info for all matches matches = geardb_utils.matching_memberships(email_to_user) # Default to blank memberships in case not found participant_memberships = { pk: geardb_utils.repr_blank_membership() for pk in par_pks } # Update participants where matching membership information was found for email, membership in matches.items(): par_pk = user_to_par[email_to_user[email]] # We might overwrite a previous membership record, but that will # only happen if the user has memberships under 2+ emails # (Older memberships come first, so this will safely yield the newest) participant_memberships[par_pk] = membership return JsonResponse({'memberships': participant_memberships})
def test_just_one_record(self): """ When requesting records under many emails, just one is returned. (Provided that the primary email is included in the lookup list) """ person_id = self.create_tim() alternate_emails = [f'tim@{i}.example.com' for i in range(3)] for email in alternate_emails: self.record_alternate_email(person_id, email) # When we request just the alternate emails, it returns one for each self.assertEqual(len(geardb.matching_memberships(alternate_emails)), 3) # However, so long as the primary is included, we'll just have one all_emails = ['*****@*****.**'] + alternate_emails self.expect_under_email('*****@*****.**', lookup=all_emails)
def test_alternate_email(self): """ We can look up participants by other emails. """ person_id = self.create_tim() # First, there is no known membership for the other email self.assertEqual(geardb.matching_memberships(['*****@*****.**']), OrderedDict()) # Then, after tying the alternate email to the main account, results! self.record_alternate_email(person_id, '*****@*****.**') self.expect_under_email('*****@*****.**') # Importantly, we can still look up by the main email address! self.expect_under_email('*****@*****.**') # If looking up by both emails, the primary email is reported # (Importantly, only one membership is returned) self.expect_under_email('*****@*****.**', lookup=['*****@*****.**', '*****@*****.**'])
def test_empty_emails(self): """ Passing an empty list of emails will return zero matches. There's no need to hit the database. """ self.assertEqual(OrderedDict(), geardb_utils.matching_memberships([]))
def expect_under_email(self, email, lookup=None): expected = self.just_tim expected['membership']['email'] = email lookup_emails = lookup or [email] results = geardb.matching_memberships(lookup_emails) # (OrderedDict) self.assertEqual({email: expected}, dict(results))
def test_no_people_record(self): """ Without a match, nothing is returned. """ matches = geardb.matching_memberships(['*****@*****.**']) self.assertEqual(matches, OrderedDict())
def one_match(self, email): matches = geardb.matching_memberships([email]) self.assertEqual(len(matches), 1) return matches[email]