def test_get_assertion_html_redirects_to_frontend(self): badgr_app = BadgrApp(cors='frontend.ui', public_pages_redirect='http://frontend.ui/public') badgr_app.save() redirect_accepts = [ {'HTTP_ACCEPT': 'application/xml,application/xhtml+xml,text/html;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5'}, # safari/chrome {'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'}, # firefox {'HTTP_ACCEPT': 'text/html, application/xhtml+xml, image/jxr, */*'}, # edge ] json_accepts = [ {'HTTP_ACCEPT': '*/*'}, # curl {}, # no accept header ] with self.settings(BADGR_APP_ID=badgr_app.id): test_user = self.setup_user(authenticate=False) test_issuer = self.setup_issuer(owner=test_user) test_issuer.cached_badgrapp # publish badgrapp to cache test_badgeclass = self.setup_badgeclass(issuer=test_issuer) assertion = test_badgeclass.issue(recipient_id='*****@*****.**') for headers in redirect_accepts: with self.assertNumQueries(0): response = self.client.get('/public/assertions/{}'.format(assertion.entity_id), **headers) self.assertEqual(response.status_code, 302) self.assertEqual(response.get('Location'), 'http://frontend.ui/public/assertions/{}'.format(assertion.entity_id)) for headers in json_accepts: with self.assertNumQueries(0): response = self.client.get('/public/assertions/{}'.format(assertion.entity_id), **headers) self.assertEqual(response.status_code, 200) self.assertEqual(response.get('Content-Type'), "application/ld+json")
def test_get_assertion_html_redirects_to_frontend(self): badgr_app = BadgrApp(cors='frontend.ui', public_pages_redirect='http://frontend.ui/public') badgr_app.save() testcase_headers = [ # browsers will send Accept: */* by default { 'HTTP_ACCEPT': '*/*' }, ] with self.settings(BADGR_APP_ID=badgr_app.id): test_user = self.setup_user(authenticate=False) test_issuer = self.setup_issuer(owner=test_user) test_issuer.cached_badgrapp # publish badgrapp to cache test_badgeclass = self.setup_badgeclass(issuer=test_issuer) assertion = test_badgeclass.issue( recipient_id='*****@*****.**') for headers in testcase_headers: with self.assertNumQueries(0): response = self.client.get( '/public/assertions/{}'.format(assertion.entity_id), **headers) self.assertEqual(response.status_code, 302) self.assertEqual( response.get('Location'), 'http://frontend.ui/public/assertions/{}'.format( assertion.entity_id))
class UserBadgeTests(BadgrTestCase): def setUp(self): super(UserBadgeTests, self).setUp() self.badgr_app = BadgrApp(cors='testserver', email_confirmation_redirect='http://testserver/login/', forgot_password_redirect='http://testserver/reset-password/') self.badgr_app.save() def create_badgeclass(self): with open(os.path.join(TOP_DIR, 'apps', 'issuer', 'testfiles', 'guinea_pig_testing_badge.png'), 'r') as fh: issuer = Issuer.objects.create(name='Issuer of Testing') badgeclass = BadgeClass.objects.create( issuer=issuer, name="Badge of Testing", image=SimpleUploadedFile(name='test_image.png', content=fh.read(), content_type='image/png') ) return badgeclass #@unittest.skip('For debug speedup') def test_badge_awards_transferred_on_email_verification(self): first_user_email = '*****@*****.**' first_user = self.setup_user(email=first_user_email, authenticate=True) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) starting_count = len(response.data) badgeclass = self.create_badgeclass() badgeclass.issue(recipient_id='*****@*****.**', allow_uppercase=True) badgeclass.issue(recipient_id='*****@*****.**', allow_uppercase=True) outbox_count = len(mail.outbox) response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 201) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) self.assertEqual(starting_count+1, len(response.data)) with self.settings(BADGR_APP_ID=self.badgr_app.id): # Mark email as verified email = CachedEmailAddress.cached.get(email='*****@*****.**') self.assertEqual(len(mail.outbox), outbox_count+1) verify_url = re.search("(?P<url>/v1/[^\s]+)", mail.outbox[-1].body).group("url") response = self.client.get(verify_url) self.assertEqual(response.status_code, 302) email = CachedEmailAddress.cached.get(email='*****@*****.**') self.assertTrue(email.verified) self.assertTrue('*****@*****.**' in [e.email for e in email.cached_variants()]) self.assertTrue('*****@*****.**' in [e.email for e in email.cached_variants()])
class UserBadgeTests(BadgrTestCase): def setUp(self): super(UserBadgeTests, self).setUp() self.badgr_app = BadgrApp(cors='testserver', email_confirmation_redirect='http://testserver/login/', forgot_password_redirect='http://testserver/reset-password/') self.badgr_app.save() def create_badgeclass(self): with open(os.path.join(TOP_DIR, 'apps', 'issuer', 'testfiles', 'guinea_pig_testing_badge.png'), 'r') as fh: issuer = Issuer.objects.create(name='Issuer of Testing') badgeclass = BadgeClass.objects.create( issuer=issuer, name="Badge of Testing", image=SimpleUploadedFile(name='test_image.png', content=fh.read(), content_type='image/png') ) return badgeclass def test_badge_awards_transferred_on_email_verification(self): first_user_email = '*****@*****.**' first_user = self.setup_user(email=first_user_email, authenticate=True) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) starting_count = len(response.data) badgeclass = self.create_badgeclass() badgeclass.issue(recipient_id='*****@*****.**', allow_uppercase=True) badgeclass.issue(recipient_id='*****@*****.**', allow_uppercase=True) outbox_count = len(mail.outbox) response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 201) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) self.assertEqual(starting_count+1, len(response.data)) with self.settings(BADGR_APP_ID=self.badgr_app.id): # Mark email as verified email = CachedEmailAddress.cached.get(email='*****@*****.**') self.assertEqual(len(mail.outbox), outbox_count+1) verify_url = re.search("(?P<url>/v1/[^\s]+)", mail.outbox[-1].body).group("url") response = self.client.get(verify_url) self.assertEqual(response.status_code, 302) email = CachedEmailAddress.cached.get(email='*****@*****.**') self.assertTrue(email.verified) self.assertTrue('*****@*****.**' in [e.email for e in email.cached_variants()]) self.assertTrue('*****@*****.**' in [e.email for e in email.cached_variants()])
def test_user_signup_email_confirmation_redirect(self): from django.conf import settings http_origin = getattr(settings, 'HTTP_ORIGIN') badgr_app = BadgrApp( cors='frontend.ui', email_confirmation_redirect='http://frontend.ui/login/', forgot_password_redirect='http://frontend.ui/forgot-password/', is_default=True) badgr_app.save() post_data = { 'first_name': 'Tester', 'last_name': 'McSteve', 'email': '*****@*****.**', 'password': '******' } response = self.client.post('/v1/user/profile', post_data) self.assertEqual(response.status_code, 201) user = BadgeUser.objects.get(entity_id=response.data.get('slug')) self.assertEqual(len(mail.outbox), 1) url_match = re.search( r'{}(/v1/user/confirmemail.*)'.format(http_origin), mail.outbox[0].body) self.assertIsNotNone(url_match) confirm_url = url_match.group(1) expected_redirect_url = '{badgrapp_redirect}{first_name}?authToken={auth}&email={email}'.format( badgrapp_redirect=badgr_app.email_confirmation_redirect, first_name=post_data['first_name'], email=urllib.quote(post_data['email']), auth=user.auth_token) response = self.client.get(confirm_url, follow=False) self.assertEqual(response.status_code, 302) actual = urlparse.urlparse(response.get('location')) expected = urlparse.urlparse(expected_redirect_url) self.assertEqual(actual.netloc, expected.netloc) self.assertEqual(actual.scheme, expected.scheme) actual_query = urlparse.parse_qs(actual.query) expected_query = urlparse.parse_qs(expected.query) self.assertEqual(actual_query.get('email'), expected_query.get('email')) self.assertIsNotNone(actual_query.get('authToken'))
def test_user_signup_email_confirmation_redirect(self): from django.conf import settings http_origin = getattr(settings, 'HTTP_ORIGIN') badgr_app = BadgrApp(cors='frontend.ui', email_confirmation_redirect='http://frontend.ui/login/', forgot_password_redirect='http://frontend.ui/forgot-password/') badgr_app.save() with self.settings(BADGR_APP_ID=badgr_app.id): post_data = { 'first_name': 'Tester', 'last_name': 'McSteve', 'email': '*****@*****.**', 'password': '******' } response = self.client.post('/v1/user/profile', post_data) self.assertEqual(response.status_code, 201) user = BadgeUser.objects.get(entity_id=response.data.get('slug')) self.assertEqual(len(mail.outbox), 1) url_match = re.search(r'{}(/v1/user/confirmemail.*)'.format(http_origin), mail.outbox[0].body) self.assertIsNotNone(url_match) confirm_url = url_match.group(1) expected_redirect_url = '{badgrapp_redirect}{first_name}?authToken={auth}&email={email}'.format( badgrapp_redirect=badgr_app.email_confirmation_redirect, first_name=post_data['first_name'], email=urllib.quote(post_data['email']), auth=user.auth_token ) response = self.client.get(confirm_url, follow=False) self.assertEqual(response.status_code, 302) actual = urlparse.urlparse(response.get('location')) expected = urlparse.urlparse(expected_redirect_url) self.assertEqual(actual.netloc, expected.netloc) self.assertEqual(actual.scheme, expected.scheme) actual_query = urlparse.parse_qs(actual.query) expected_query = urlparse.parse_qs(expected.query) self.assertEqual(actual_query.get('email'), expected_query.get('email')) self.assertIsNotNone(actual_query.get('authToken'))
class UserEmailTests(BadgrTestCase): def setUp(self): super(UserEmailTests, self).setUp() self.badgr_app = BadgrApp( cors='testserver', email_confirmation_redirect='http://testserver/login/', forgot_password_redirect='http://testserver/reset-password/') self.badgr_app.save() self.first_user_email = '*****@*****.**' self.first_user_email_secondary = '*****@*****.**' self.first_user = self.setup_user(email=self.first_user_email, authenticate=True) CachedEmailAddress.objects.create( user=self.first_user, email=self.first_user_email_secondary, verified=True) response = self.client.get('/v1/user/auth-token') self.assertEqual(response.status_code, 200) def test_user_register_new_email(self): response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) starting_count = len(response.data) response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 201) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) self.assertEqual(starting_count + 1, len(response.data)) # Mark email as verified email = CachedEmailAddress.cached.get(email='*****@*****.**') email.verified = True email.save() # Can not add the same email twice response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 400) self.assertTrue("Could not register email address." in response.data) def test_user_can_verify_new_email(self): response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) starting_count = len(response.data) response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 201) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) self.assertEqual(starting_count + 1, len(response.data)) with self.settings(BADGR_APP_ID=self.badgr_app.id): # Mark email as verified email = CachedEmailAddress.cached.get( email='*****@*****.**') self.assertEqual(len(mail.outbox), 1) verify_url = re.search("(?P<url>/v1/[^\s]+)", mail.outbox[0].body).group("url") response = self.client.get(verify_url) self.assertEqual(response.status_code, 302) email = CachedEmailAddress.cached.get(email='*****@*****.**') self.assertTrue(email.verified) def test_user_cant_register_new_email_verified_by_other(self): second_user = self.setup_user(authenticate=False) existing_mail = CachedEmailAddress.objects.create( user=self.first_user, email='*****@*****.**', verified=True) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) starting_count = len(response.data) # Another user tries to add this email self.client.force_authenticate(user=second_user) response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 400) self.client.force_authenticate(user=self.first_user) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) self.assertEqual(starting_count, len(response.data)) def test_user_can_remove_email(self): response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) not_primary = random.choice( filter(lambda e: e['verified'] and not e['primary'], response.data)) primary = random.choice(filter(lambda e: e['primary'], response.data)) # cant remove primary email response = self.client.delete('/v1/user/emails/{}'.format( primary.get('id'))) self.assertEqual(response.status_code, 400) response = self.client.get('/v1/user/emails/{}'.format( primary.get('id'))) self.assertEqual(response.status_code, 200) # can remove a non-primary email response = self.client.delete('/v1/user/emails/{}'.format( not_primary.get('id'))) self.assertEqual(response.status_code, 200) response = self.client.get('/v1/user/emails/{}'.format( not_primary.get('id'))) self.assertEqual(response.status_code, 404) def test_user_can_make_email_primary(self): response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) self.assertGreater(len(response.data), 0) not_primary = random.choice( filter(lambda e: e['verified'] and not e['primary'], response.data)) # set a non primary email to primary response = self.client.put( '/v1/user/emails/{}'.format(not_primary.get('id')), {'primary': True}) self.assertEqual(response.status_code, 200) # confirm that the new email is primary and the others aren't response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) for email in response.data: if email['id'] == not_primary['id']: self.assertEqual(email['primary'], True) else: self.assertEqual(email['primary'], False) def test_user_can_resend_verification_email(self): # register a new un-verified email response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 201) self.assertEqual(len(mail.outbox), 1) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) not_verified = random.choice( filter(lambda e: not e['verified'], response.data)) verified = random.choice(filter(lambda e: e['verified'], response.data)) # dont resend verification email if already verified response = self.client.put( '/v1/user/emails/{}'.format(verified.get('id')), {'resend': True}) self.assertEqual(response.status_code, 200) self.assertEqual(len(mail.outbox), 1) # gets an email for an unverified email response = self.client.put( '/v1/user/emails/{}'.format(not_verified.get('id')), {'resend': True}) self.assertEqual(response.status_code, 200) self.assertEqual(len(mail.outbox), 2) def test_user_can_request_forgot_password(self): self.client.logout() # dont send recovery to unknown emails response = self.client.post('/v1/user/forgot-password', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 200, "Does not leak information about account emails") self.assertEqual(len(mail.outbox), 0) with self.settings(BADGR_APP_ID=self.badgr_app.id): # successfully send recovery email response = self.client.post('/v1/user/forgot-password', {'email': self.first_user_email}) self.assertEqual(response.status_code, 200) # received email with recovery url self.assertEqual(len(mail.outbox), 1) matches = re.search( r'/v1/user/forgot-password\?token=([-0-9a-zA-Z]*)', mail.outbox[0].body) self.assertIsNotNone(matches) token = matches.group(1) new_password = '******' # able to use token received in email to reset password response = self.client.put('/v1/user/forgot-password', { 'token': token, 'password': new_password }) self.assertEqual(response.status_code, 200) response = self.client.post('/api-auth/token', { 'username': self.first_user.username, 'password': new_password, }) self.assertEqual(response.status_code, 200) def test_lower_variant_autocreated_on_new_email(self): first_email = CachedEmailAddress(email="*****@*****.**", user=BadgeUser.objects.first(), verified=True) first_email.save() self.assertIsNotNone(first_email.pk) variants = EmailAddressVariant.objects.filter( canonical_email=first_email) self.assertEqual(len(variants), 1) self.assertEqual(variants[0].email, '*****@*****.**') def test_can_create_new_variant_api(self): user = BadgeUser.objects.first() first_email = CachedEmailAddress(email="*****@*****.**", user=user, verified=True) first_email.save() self.assertIsNotNone(first_email.pk) self.client.force_authenticate(user=user) response = self.client.post('/v1/user/emails', {'email': '*****@*****.**'}) self.assertEqual(response.status_code, 400) self.assertTrue( 'Matching address already exists. New case variant registered.' in response.data) variants = first_email.cached_variants() self.assertEqual(len(variants), 1) self.assertEqual(variants[0].email, '*****@*****.**') def test_can_create_variants(self): user = self.setup_user(authenticate=False) first_email = CachedEmailAddress.objects.create( email="*****@*****.**", verified=True, user=user) self.assertIsNotNone(first_email.pk) first_variant_email = "*****@*****.**" second_variant_email = "*****@*****.**" first_variant = EmailAddressVariant(email=first_variant_email, canonical_email=first_email) first_variant.save() self.assertEqual(first_variant.canonical_email, first_email) second_variant = first_email.add_variant(second_variant_email) self.assertEqual(second_variant.canonical_email, first_email) self.assertEqual(len(first_email.emailaddressvariant_set.all()), 2) self.assertEqual(len(first_email.cached_variants()), 2) def test_user_can_create_variant_method(self): user = BadgeUser.objects.first() first_email = CachedEmailAddress(email="*****@*****.**", user=user, verified=True) first_email.save() first_email.add_variant("*****@*****.**") self.assertTrue(user.can_add_variant("*****@*****.**")) self.assertFalse( user.can_add_variant("*****@*****.**")) # already exists self.assertFalse( user.can_add_variant("*****@*****.**")) # is the original self.assertFalse(user.can_add_variant( "*****@*****.**")) # not a match of original def test_can_create_variant_for_unconfirmed_email(self): user = BadgeUser.objects.first() new_email_address = "*****@*****.**" new_email = CachedEmailAddress.objects.create(email=new_email_address, user=user) new_variant = EmailAddressVariant(email=new_email_address.upper(), canonical_email=new_email) new_variant.save() self.assertFalse(new_variant.verified) verified_emails = [e.email for e in user.emailaddress_set.filter(verified=True)] \ + [e.email for e in user.cached_email_variants() if e.verified] self.assertTrue(new_variant not in verified_emails) def cannot_link_variant_of_case_insensitive_nonmatch(self): first_email = CachedEmailAddress.objects.get(email="*****@*****.**") self.assertIsNotNone(first_email.pk) variant_email = "*****@*****.**" variant = EmailAddressVariant(email=variant_email, canonical_email=first_email) try: variant.save() except ValidationError as e: self.assertEqual( e.message, "New EmailAddressVariant does not match stored email address.") else: raise self.fail("ValidationError expected on nonmatch.")
class UserRecipientIdentifierTests(SetupIssuerHelper, BadgrTestCase): def setUp(self): super(UserRecipientIdentifierTests, self).setUp() self.badgr_app = BadgrApp( cors='testserver', email_confirmation_redirect='http://testserver/login/', forgot_password_redirect='http://testserver/reset-password/') self.badgr_app.save() self.first_user_email = '*****@*****.**' self.first_user_email_secondary = '*****@*****.**' self.first_user = self.setup_user(email=self.first_user_email, authenticate=True) CachedEmailAddress.objects.create( user=self.first_user, email=self.first_user_email_secondary, verified=True) response = self.client.get('/v1/user/auth-token') self.assertEqual(response.status_code, 200) self.issuer = self.setup_issuer(owner=self.first_user) self.badgeclass = self.setup_badgeclass(self.issuer) def test_two_users_can_have_same_identifier(self): url = 'http://example.com' self.first_user.userrecipientidentifier_set.create(identifier=url) second_user_email = '*****@*****.**' second_user = self.setup_user(email=second_user_email, authenticate=True) second_user.userrecipientidentifier_set.create(identifier=url) self.assertGreater( UserRecipientIdentifier.objects.filter(identifier=url).count(), 1) def test_only_one_user_can_have_verified_identifier(self): url = 'http://example.com' self.first_user.userrecipientidentifier_set.create(identifier=url, verified=True) second_user_email = '*****@*****.**' second_user = self.setup_user(email=second_user_email, authenticate=True) second_identifier = second_user.userrecipientidentifier_set.create( identifier=url) with self.assertRaisesRegex(ValidationError, re.compile('identifier', re.I)): second_identifier.verified = True second_identifier.save() def test_url_format_validation(self): self.first_user.userrecipientidentifier_set.create( identifier='http://example.com') self.first_user.userrecipientidentifier_set.create( identifier='ftp://example.com') self.first_user.userrecipientidentifier_set.create( identifier='https://withpath.com/12345678') self.first_user.userrecipientidentifier_set.create( identifier='https://withhash.com/12345678/bar.html#fooey') with self.assertRaisesRegex(ValidationError, 'valid'): self.first_user.userrecipientidentifier_set.create( identifier='http') with self.assertRaisesRegex(ValidationError, 'valid'): self.first_user.userrecipientidentifier_set.create( identifier='(541) 342-8456') with self.assertRaisesRegex(ValidationError, 'valid'): self.first_user.userrecipientidentifier_set.create(identifier='') with self.assertRaisesRegex(ValidationError, 'valid'): self.first_user.userrecipientidentifier_set.create( identifier='12345678') with self.assertRaisesRegex(ValidationError, 'valid'): self.first_user.userrecipientidentifier_set.create( identifier='*****@*****.**') with self.assertRaisesRegex(ValidationError, 'valid'): self.first_user.userrecipientidentifier_set.create( identifier='customprotocol://example.com') with self.assertRaisesRegex(ValidationError, 'valid'): self.first_user.userrecipientidentifier_set.create( identifier='http://singlepart') with self.assertRaisesRegex(ValidationError, 'valid'): self.first_user.userrecipientidentifier_set.create( identifier='/relative/url') def test_phone_format_validation(self): self.first_user.userrecipientidentifier_set.create( type=UserRecipientIdentifier.IDENTIFIER_TYPE_TELEPHONE, identifier='3428456') self.first_user.userrecipientidentifier_set.create( type=UserRecipientIdentifier.IDENTIFIER_TYPE_TELEPHONE, identifier='5413428456') self.first_user.userrecipientidentifier_set.create( type=UserRecipientIdentifier.IDENTIFIER_TYPE_TELEPHONE, identifier='15413428456') self.first_user.userrecipientidentifier_set.create( type=UserRecipientIdentifier.IDENTIFIER_TYPE_TELEPHONE, identifier='+15413428456') with self.assertRaisesRegex(ValidationError, 'valid'): self.first_user.userrecipientidentifier_set.create( type=UserRecipientIdentifier.IDENTIFIER_TYPE_TELEPHONE, identifier='+1541342845612345') with self.assertRaisesRegex(ValidationError, 'valid'): self.first_user.userrecipientidentifier_set.create( type=UserRecipientIdentifier.IDENTIFIER_TYPE_TELEPHONE, identifier='(541) 342-8456') def test_verified_phone_included_in_all_recipient_identifiers(self): identifier = '3428456' self.first_user.userrecipientidentifier_set.create( type=UserRecipientIdentifier.IDENTIFIER_TYPE_TELEPHONE, identifier=identifier, verified=True) self.assertIn(identifier, self.first_user.all_recipient_identifiers) def test_verified_url_included_in_all_recipient_identifiers(self): identifier = 'http://example.com' self.first_user.userrecipientidentifier_set.create( type=UserRecipientIdentifier.IDENTIFIER_TYPE_URL, identifier=identifier, verified=True) self.assertIn(identifier, self.first_user.all_recipient_identifiers) def test_identifiers_serialized_to_correct_fields(self): url = 'http://example.com' phone = '+15413428456' self.first_user.userrecipientidentifier_set.create( type=UserRecipientIdentifier.IDENTIFIER_TYPE_URL, identifier=url, verified=True) self.first_user.userrecipientidentifier_set.create( type=UserRecipientIdentifier.IDENTIFIER_TYPE_TELEPHONE, identifier=phone, verified=True) v1serialized = BadgeUserProfileSerializerV1(self.first_user).data v2serialized = BadgeUserSerializerV2(self.first_user).data['result'][0] self.assertIn(url, v1serialized['url']) self.assertIn(url, v2serialized['url']) self.assertIn(phone, v1serialized['telephone']) self.assertIn(phone, v2serialized['telephone']) self.assertNotIn(phone, v1serialized['url']) self.assertNotIn(phone, v2serialized['url']) self.assertNotIn(url, v1serialized['telephone']) self.assertNotIn(url, v2serialized['telephone']) def test_recipient_identity_serialized_to_correct_fields(self): user = self.setup_user(create_email_address=False) v2serialized = BadgeUserSerializerV2(user).data['result'][0] self.assertEqual(None, v2serialized['recipient']) url = 'http://example.com' phone = '+15413428456' user.userrecipientidentifier_set.create( type=UserRecipientIdentifier.IDENTIFIER_TYPE_URL, identifier=url, verified=True) user.userrecipientidentifier_set.create( type=UserRecipientIdentifier.IDENTIFIER_TYPE_TELEPHONE, identifier=phone, verified=True) v2serialized = BadgeUserSerializerV2(user).data['result'][0] self.assertIn(url, v2serialized['recipient']['identity']) self.assertIn('url', v2serialized['recipient']['type']) primary_email = '*****@*****.**' CachedEmailAddress.objects.create(user=user, email=primary_email, primary=True, verified=True) v2serialized = BadgeUserSerializerV2(user).data['result'][0] self.assertIn(primary_email, v2serialized['recipient']['identity']) self.assertIn('email', v2serialized['recipient']['type']) def test_verified_recipient_receives_assertion(self): url = 'http://example.com' self.first_user.userrecipientidentifier_set.create( identifier=url, verified=True, type=UserRecipientIdentifier.IDENTIFIER_TYPE_URL) self.badgeclass.issue( recipient_id=url, recipient_type=UserRecipientIdentifier.IDENTIFIER_TYPE_URL) self.assertEqual(len(self.first_user.cached_badgeinstances()), 1) def test_unverified_recipient_receives_no_assertion(self): url = 'http://example.com' self.first_user.userrecipientidentifier_set.create(identifier=url) self.badgeclass.issue( recipient_id=url, recipient_type=UserRecipientIdentifier.IDENTIFIER_TYPE_URL) self.assertEqual(len(self.first_user.cached_badgeinstances()), 0) def test_verified_recipient_v1_badges_endpoint(self): url = 'http://example.com' self.first_user.userrecipientidentifier_set.create( identifier=url, verified=True, type=UserRecipientIdentifier.IDENTIFIER_TYPE_URL) self.badgeclass.issue( recipient_id=url, recipient_type=UserRecipientIdentifier.IDENTIFIER_TYPE_URL) response = self.client.get('/v1/earner/badges') self.assertEqual(len(response.data), 1) def test_verified_recipient_v2_assertions_endpoint(self): url = 'http://example.com' self.first_user.userrecipientidentifier_set.create(identifier=url, verified=True) self.badgeclass.issue( recipient_id=url, recipient_type=UserRecipientIdentifier.IDENTIFIER_TYPE_URL) response = self.client.get('/v2/backpack/assertions') self.assertEqual(len(response.data['result']), 1) def test_unverified_recipient_v1_badges_endpoint(self): url = 'http://example.com' self.first_user.userrecipientidentifier_set.create(identifier=url) self.badgeclass.issue( recipient_id=url, recipient_type=UserRecipientIdentifier.IDENTIFIER_TYPE_URL) response = self.client.get('/v1/earner/badges') self.assertEqual(len(response.data), 0) def test_unverified_recipient_v2_assertions_endpoint(self): url = 'http://example.com' self.first_user.userrecipientidentifier_set.create(identifier=url) self.badgeclass.issue( recipient_id=url, recipient_type=UserRecipientIdentifier.IDENTIFIER_TYPE_URL) response = self.client.get('/v2/backpack/assertions') self.assertEqual(len(response.data['result']), 0)
class UserEmailTests(BadgrTestCase): def setUp(self): super(UserEmailTests, self).setUp() self.badgr_app = BadgrApp(cors='testserver', email_confirmation_redirect='http://testserver/login/', forgot_password_redirect='http://testserver/reset-password/') self.badgr_app.save() self.first_user_email = '*****@*****.**' self.first_user_email_secondary = '*****@*****.**' self.first_user = self.setup_user(email=self.first_user_email, authenticate=True) CachedEmailAddress.objects.create(user=self.first_user, email=self.first_user_email_secondary, verified=True) response = self.client.get('/v1/user/auth-token') self.assertEqual(response.status_code, 200) def test_user_register_new_email(self): response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) starting_count = len(response.data) response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 201) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) self.assertEqual(starting_count+1, len(response.data)) # Mark email as verified email = CachedEmailAddress.cached.get(email='*****@*****.**') email.verified = True email.save() # Can not add the same email twice response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 400) self.assertTrue("Could not register email address." in response.data) def test_user_can_verify_new_email(self): response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) starting_count = len(response.data) response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 201) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) self.assertEqual(starting_count+1, len(response.data)) with self.settings(BADGR_APP_ID=self.badgr_app.id): # Mark email as verified email = CachedEmailAddress.cached.get(email='*****@*****.**') self.assertEqual(len(mail.outbox), 1) verify_url = re.search("(?P<url>/v1/[^\s]+)", mail.outbox[0].body).group("url") response = self.client.get(verify_url) self.assertEqual(response.status_code, 302) email = CachedEmailAddress.cached.get(email='*****@*****.**') self.assertTrue(email.verified) def test_user_cant_register_new_email_verified_by_other(self): second_user = self.setup_user(authenticate=False) existing_mail = CachedEmailAddress.objects.create( user=self.first_user, email='*****@*****.**', verified=True) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) starting_count = len(response.data) # Another user tries to add this email self.client.force_authenticate(user=second_user) response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 400) self.client.force_authenticate(user=self.first_user) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) self.assertEqual(starting_count, len(response.data)) def test_user_can_remove_email(self): response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) not_primary = random.choice(filter(lambda e: e['verified'] and not e['primary'], response.data)) primary = random.choice(filter(lambda e: e['primary'], response.data)) # cant remove primary email response = self.client.delete('/v1/user/emails/{}'.format(primary.get('id'))) self.assertEqual(response.status_code, 400) response = self.client.get('/v1/user/emails/{}'.format(primary.get('id'))) self.assertEqual(response.status_code, 200) # can remove a non-primary email response = self.client.delete('/v1/user/emails/{}'.format(not_primary.get('id'))) self.assertEqual(response.status_code, 200) response = self.client.get('/v1/user/emails/{}'.format(not_primary.get('id'))) self.assertEqual(response.status_code, 404) def test_user_can_make_email_primary(self): response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) self.assertGreater(len(response.data), 0) not_primary = random.choice(filter(lambda e: e['verified'] and not e['primary'], response.data)) # set a non primary email to primary response = self.client.put('/v1/user/emails/{}'.format(not_primary.get('id')), { 'primary': True }) self.assertEqual(response.status_code, 200) # confirm that the new email is primary and the others aren't response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) for email in response.data: if email['id'] == not_primary['id']: self.assertEqual(email['primary'], True) else: self.assertEqual(email['primary'], False) def test_user_can_resend_verification_email(self): # register a new un-verified email response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 201) self.assertEqual(len(mail.outbox), 1) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) not_verified = random.choice(filter(lambda e: not e['verified'], response.data)) verified = random.choice(filter(lambda e: e['verified'], response.data)) # dont resend verification email if already verified response = self.client.put('/v1/user/emails/{}'.format(verified.get('id')), { 'resend': True }) self.assertEqual(response.status_code, 200) self.assertEqual(len(mail.outbox), 1) # gets an email for an unverified email response = self.client.put('/v1/user/emails/{}'.format(not_verified.get('id')), { 'resend': True }) self.assertEqual(response.status_code, 200) self.assertEqual(len(mail.outbox), 2) def test_user_can_request_forgot_password(self): self.client.logout() cache.clear() # dont send recovery to unknown emails response = self.client.post('/v1/user/forgot-password', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 200, "Does not leak information about account emails") self.assertEqual(len(mail.outbox), 0) with self.settings(BADGR_APP_ID=self.badgr_app.id): # successfully send recovery email response = self.client.post('/v1/user/forgot-password', { 'email': self.first_user_email }) backoff_key = backoff_cache_key(self.first_user_email, None) backoff_data = {'count': 6, 'until': timezone.now() + timezone.timedelta(seconds=60)} cache.set(backoff_key, backoff_data) self.assertEqual(cache.get(backoff_key), backoff_data) self.assertEqual(response.status_code, 200) # received email with recovery url self.assertEqual(len(mail.outbox), 1) matches = re.search(r'/v1/user/forgot-password\?token=([-0-9a-zA-Z]*)', mail.outbox[0].body) self.assertIsNotNone(matches) token = matches.group(1) new_password = '******' # able to use token received in email to reset password response = self.client.put('/v1/user/forgot-password', { 'token': token, 'password': new_password }) self.assertEqual(response.status_code, 200) backoff_data = cache.get(backoff_key) self.assertIsNone(backoff_data) response = self.client.post('/api-auth/token', { 'username': self.first_user.username, 'password': new_password, }) self.assertEqual(response.status_code, 200) def test_lower_variant_autocreated_on_new_email(self): first_email = CachedEmailAddress( email="*****@*****.**", user=BadgeUser.objects.first(), verified=True ) first_email.save() self.assertIsNotNone(first_email.pk) variants = EmailAddressVariant.objects.filter(canonical_email=first_email) self.assertEqual(len(variants), 1) self.assertEqual(variants[0].email, '*****@*****.**') def test_can_create_new_variant_api(self): user = BadgeUser.objects.first() first_email = CachedEmailAddress( email="*****@*****.**", user=user, verified=True ) first_email.save() self.assertIsNotNone(first_email.pk) self.client.force_authenticate(user=user) response = self.client.post('/v1/user/emails', {'email': '*****@*****.**'}) self.assertEqual(response.status_code, 400) self.assertTrue('Matching address already exists. New case variant registered.' in response.data) variants = first_email.cached_variants() self.assertEqual(len(variants), 1) self.assertEqual(variants[0].email, '*****@*****.**') def test_can_create_variants(self): user = self.setup_user(authenticate=False) first_email = CachedEmailAddress.objects.create(email="*****@*****.**", verified=True, user=user) self.assertIsNotNone(first_email.pk) first_variant_email = "*****@*****.**" second_variant_email = "*****@*****.**" first_variant = EmailAddressVariant(email=first_variant_email, canonical_email=first_email) first_variant.save() self.assertEqual(first_variant.canonical_email, first_email) second_variant = first_email.add_variant(second_variant_email) self.assertEqual(second_variant.canonical_email, first_email) self.assertEqual(len(first_email.emailaddressvariant_set.all()), 2) self.assertEqual(len(first_email.cached_variants()), 2) def test_user_can_create_variant_method(self): user = BadgeUser.objects.first() first_email = CachedEmailAddress( email="*****@*****.**", user=user, verified=True ) first_email.save() first_email.add_variant("*****@*****.**") self.assertTrue(user.can_add_variant("*****@*****.**")) self.assertFalse(user.can_add_variant("*****@*****.**")) # already exists self.assertFalse(user.can_add_variant("*****@*****.**")) # is the original self.assertFalse(user.can_add_variant("*****@*****.**")) # not a match of original def test_can_create_variant_for_unconfirmed_email(self): user = BadgeUser.objects.first() new_email_address = "*****@*****.**" new_email = CachedEmailAddress.objects.create(email=new_email_address, user=user) new_variant = EmailAddressVariant(email=new_email_address.upper(), canonical_email=new_email) new_variant.save() self.assertFalse(new_variant.verified) verified_emails = [e.email for e in user.emailaddress_set.filter(verified=True)] \ + [e.email for e in user.cached_email_variants() if e.verified] self.assertTrue(new_variant not in verified_emails) def cannot_link_variant_of_case_insensitive_nonmatch(self): first_email = CachedEmailAddress.objects.get(email="*****@*****.**") self.assertIsNotNone(first_email.pk) variant_email = "*****@*****.**" variant = EmailAddressVariant(email=variant_email, canonical_email=first_email) try: variant.save() except ValidationError as e: self.assertEqual(e.message, "New EmailAddressVariant does not match stored email address.") else: raise self.fail("ValidationError expected on nonmatch.")
class UserEmailTests(BadgrTestCase): def setUp(self): super(UserEmailTests, self).setUp() self.badgr_app = BadgrApp(cors='testserver', email_confirmation_redirect='http://testserver/login/', forgot_password_redirect='http://testserver/reset-password/') self.badgr_app.save() self.first_user_email = '*****@*****.**' self.first_user_email_secondary = '*****@*****.**' self.first_user = self.setup_user(email=self.first_user_email, authenticate=True) CachedEmailAddress.objects.create(user=self.first_user, email=self.first_user_email_secondary, verified=True) response = self.client.get('/v1/user/auth-token') self.assertEqual(response.status_code, 200) def test_user_register_new_email(self): response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) starting_count = len(response.data) response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 201) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) self.assertEqual(starting_count+1, len(response.data)) # Mark email as verified email = CachedEmailAddress.cached.get(email='*****@*****.**') email.verified = True email.save() # Can not add the same email twice response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 400) self.assertTrue("Could not register email address." in response.data) def test_user_can_verify_new_email(self): response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) starting_count = len(response.data) response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 201) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) self.assertEqual(starting_count+1, len(response.data)) # Mark email as verified email = CachedEmailAddress.cached.get(email='*****@*****.**') self.assertEqual(len(mail.outbox), 1) verify_url = re.search("(?P<url>/v1/[^\s]+)", mail.outbox[0].body).group("url") response = self.client.get(verify_url) self.assertEqual(response.status_code, 302) email = CachedEmailAddress.cached.get(email='*****@*****.**') self.assertTrue(email.verified) def test_user_cant_register_new_email_verified_by_other(self): second_user = self.setup_user(authenticate=False) existing_mail = CachedEmailAddress.objects.create( user=self.first_user, email='*****@*****.**', verified=True) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) starting_count = len(response.data) # Another user tries to add this email self.client.force_authenticate(user=second_user) response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 400) self.client.force_authenticate(user=self.first_user) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) self.assertEqual(starting_count, len(response.data)) def test_user_can_remove_email(self): response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) not_primary = random.choice([e for e in response.data if e['verified'] and not e['primary']]) primary = random.choice([e for e in response.data if e['primary']]) # cant remove primary email response = self.client.delete('/v1/user/emails/{}'.format(primary.get('id'))) self.assertEqual(response.status_code, 400) response = self.client.get('/v1/user/emails/{}'.format(primary.get('id'))) self.assertEqual(response.status_code, 200) # can remove a non-primary email response = self.client.delete('/v1/user/emails/{}'.format(not_primary.get('id'))) self.assertEqual(response.status_code, 200) response = self.client.get('/v1/user/emails/{}'.format(not_primary.get('id'))) self.assertEqual(response.status_code, 404) def test_user_can_make_email_primary(self): response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) self.assertGreater(len(response.data), 0) not_primary = random.choice([e for e in response.data if e['verified'] and not e['primary']]) # set a non primary email to primary response = self.client.put('/v1/user/emails/{}'.format(not_primary.get('id')), { 'primary': True }) self.assertEqual(response.status_code, 200) # confirm that the new email is primary and the others aren't response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) for email in response.data: if email['id'] == not_primary['id']: self.assertEqual(email['primary'], True) else: self.assertEqual(email['primary'], False) def test_user_can_resend_verification_email(self): # register a new un-verified email response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 201) self.assertEqual(len(mail.outbox), 1) response = self.client.get('/v1/user/emails') self.assertEqual(response.status_code, 200) not_verified = random.choice([e for e in response.data if not e['verified']]) verified = random.choice([e for e in response.data if e['verified']]) # dont resend verification email if already verified response = self.client.put('/v1/user/emails/{}'.format(verified.get('id')), { 'resend': True }) self.assertEqual(response.status_code, 200) self.assertEqual(len(mail.outbox), 1) # gets an email for an unverified email response = self.client.put('/v1/user/emails/{}'.format(not_verified.get('id')), { 'resend': True }) self.assertEqual(response.status_code, 200) self.assertEqual(len(mail.outbox), 2) def test_no_login_on_confirmation_of_verified_email(self): # register a new un-verified email response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 201) # receive verification email self.assertEqual(len(mail.outbox), 1) verify_url = re.search("(?P<url>/v1/[^\s]+)", mail.outbox[0].body).group("url") # verify the email address email_address = CachedEmailAddress.objects.filter(verified=False).get() email_address.verified = True email_address.save() # verification attempt fails response = self.client.get(verify_url) self.assertEqual(response.status_code, 302) self.assertIn('authError', response['location']) self.assertNotIn('authToken', response['location']) def test_verification_cannot_be_reused(self): # register a new un-verified email response = self.client.post('/v1/user/emails', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 201) # receive verification email self.assertEqual(len(mail.outbox), 1) verify_url = re.search("(?P<url>/v1/[^\s]+)", mail.outbox[0].body).group("url") # verify the email address successfully response = self.client.get(verify_url) self.assertEqual(response.status_code, 302) self.assertIn('authToken', response['location']) self.assertNotIn('authError', response['location']) # second verification attempt fails response = self.client.get(verify_url) self.assertEqual(response.status_code, 302) self.assertIn('authError', response['location']) self.assertNotIn('authToken', response['location']) def test_user_can_request_forgot_password(self): self.client.logout() cache.clear() # dont send recovery to unknown emails response = self.client.post('/v1/user/forgot-password', { 'email': '*****@*****.**', }) self.assertEqual(response.status_code, 200, "Does not leak information about account emails") self.assertEqual(len(mail.outbox), 0) # successfully send recovery email response = self.client.post('/v1/user/forgot-password', { 'email': self.first_user_email }) backoff_key = backoff_cache_key(self.first_user_email) backoff_data = {'127.0.0.1': {'count': 6, 'until': timezone.now() + timezone.timedelta(seconds=60)}} cache.set(backoff_key, backoff_data) self.assertEqual(cache.get(backoff_key), backoff_data) self.assertEqual(response.status_code, 200) # received email with recovery url self.assertEqual(len(mail.outbox), 1) matches = re.search(r'/v1/user/forgot-password\?token=([-0-9a-zA-Z]*)', mail.outbox[0].body) self.assertIsNotNone(matches) token = matches.group(1) new_password = '******' # able to use token received in email to reset password response = self.client.put('/v1/user/forgot-password', { 'token': token, 'password': new_password }) self.assertEqual(response.status_code, 200) backoff_data = cache.get(backoff_key) self.assertIsNone(backoff_data) application = Application.objects.create( client_id='public', client_secret='', user=None, authorization_grant_type=Application.GRANT_PASSWORD, name='public' ) ApplicationInfo.objects.create( application=application, allowed_scopes='rw:issuer rw:backpack rw:profile' ) response = self.client.post('/o/token', { 'username': self.first_user.email, 'password': new_password, }) self.assertEqual(response.status_code, 200) @patch('mainsite.serializers.badgrlogger.event') def test_log_when_api_auth_token_endpoint_is_used(self, mocked_logger): response = self.client.post('/api-auth/token', { 'username': self.first_user.username, 'password': '******', }) self.assertEqual(response.status_code, 200) self.assertIn('deprecated', response.data['warning'], 'There is a warning returned to the requester') mocked_logger.assert_called_once() self.assertTrue(mocked_logger.call_args[0][0].is_new_token) @patch('mainsite.authentication.badgrlogger.event') def test_log_when_legacy_auth_token_is_used(self, mocked_logger): # logout previous user self.client.logout() user_email = '*****@*****.**' user = self.setup_user(email=user_email, authenticate=False) token, created = Token.objects.get_or_create(user=user) response = self.client.get('/v2/users/self', HTTP_AUTHORIZATION='Token {}'.format(token.key)) mocked_logger.assert_called_once() self.assertIsNotNone(mocked_logger.call_args[0][0].request.META.get("REMOTE_ADDR", None)) self.assertEquals(mocked_logger.call_args[0][0].username, user.username) self.assertFalse(mocked_logger.call_args[0][0].is_new_token) def test_lower_variant_autocreated_on_new_email(self): first_email = CachedEmailAddress( email="*****@*****.**", user=BadgeUser.objects.first(), verified=True ) first_email.save() self.assertIsNotNone(first_email.pk) variants = EmailAddressVariant.objects.filter(canonical_email=first_email) self.assertEqual(len(variants), 1) self.assertEqual(variants[0].email, '*****@*****.**') def test_can_create_new_variant_api(self): user = BadgeUser.objects.first() first_email = CachedEmailAddress( email="*****@*****.**", user=user, verified=True ) first_email.save() self.assertIsNotNone(first_email.pk) self.client.force_authenticate(user=user) response = self.client.post('/v1/user/emails', {'email': '*****@*****.**'}) self.assertEqual(response.status_code, 400) self.assertTrue('Matching address already exists. New case variant registered.' in response.data) variants = first_email.cached_variants() self.assertEqual(len(variants), 1) self.assertEqual(variants[0].email, '*****@*****.**') def test_can_create_variants(self): user = self.setup_user(authenticate=False) first_email = CachedEmailAddress.objects.create(email="*****@*****.**", verified=True, user=user) self.assertIsNotNone(first_email.pk) first_variant_email = "*****@*****.**" second_variant_email = "*****@*****.**" first_variant = EmailAddressVariant(email=first_variant_email, canonical_email=first_email) first_variant.save() self.assertEqual(first_variant.canonical_email, first_email) second_variant = first_email.add_variant(second_variant_email) self.assertEqual(second_variant.canonical_email, first_email) self.assertEqual(len(first_email.emailaddressvariant_set.all()), 2) self.assertEqual(len(first_email.cached_variants()), 2) def test_user_can_create_variant_method(self): user = BadgeUser.objects.first() first_email = CachedEmailAddress( email="*****@*****.**", user=user, verified=True ) first_email.save() first_email.add_variant("*****@*****.**") self.assertTrue(user.can_add_variant("*****@*****.**")) self.assertFalse(user.can_add_variant("*****@*****.**")) # already exists self.assertFalse(user.can_add_variant("*****@*****.**")) # is the original self.assertFalse(user.can_add_variant("*****@*****.**")) # not a match of original def test_can_create_variant_for_unconfirmed_email(self): user = BadgeUser.objects.first() new_email_address = "*****@*****.**" new_email = CachedEmailAddress.objects.create(email=new_email_address, user=user) new_variant = EmailAddressVariant(email=new_email_address.upper(), canonical_email=new_email) new_variant.save() self.assertFalse(new_variant.verified) verified_emails = [e.email for e in user.emailaddress_set.filter(verified=True)] \ + [e.email for e in user.cached_email_variants() if e.verified] self.assertTrue(new_variant not in verified_emails) def cannot_link_variant_of_case_insensitive_nonmatch(self): first_email = CachedEmailAddress.objects.get(email="*****@*****.**") self.assertIsNotNone(first_email.pk) variant_email = "*****@*****.**" variant = EmailAddressVariant(email=variant_email, canonical_email=first_email) try: variant.save() except ValidationError as e: self.assertEqual(e.message, "New EmailAddressVariant does not match stored email address.") else: raise self.fail("ValidationError expected on nonmatch.")