Skip to content
This repository has been archived by the owner on Feb 8, 2018. It is now read-only.

Commit

Permalink
implement has_verified_identity
Browse files Browse the repository at this point in the history
  • Loading branch information
chadwhitacre committed May 9, 2016
1 parent 44472ca commit cfe2d0b
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 0 deletions.
32 changes: 32 additions & 0 deletions sql/branch.sql
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,35 @@ CREATE TRIGGER enforce_email_for_participant_identity
BEFORE INSERT ON participant_identities
FOR EACH ROW
EXECUTE PROCEDURE fail_if_no_email();


-- participants.has_verified_identity

ALTER TABLE participants ADD COLUMN has_verified_identity bool NOT NULL DEFAULT false;

CREATE FUNCTION update_has_verified_identity() RETURNS trigger AS $$
BEGIN
UPDATE participants p
SET has_verified_identity=COALESCE((
SELECT is_verified
FROM participant_identities
WHERE participant_id = OLD.participant_id
AND is_verified
LIMIT 1
), false)
WHERE p.id = OLD.participant_id;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER propagate_is_verified_changes
AFTER UPDATE OF is_verified ON participant_identities
FOR EACH ROW
EXECUTE PROCEDURE update_has_verified_identity();

CREATE TRIGGER propagate_is_verified_removal
AFTER DELETE ON participant_identities
FOR EACH ROW
EXECUTE PROCEDURE update_has_verified_identity();

-- We don't need an INSERT trigger, because of the way the defaults play out.
83 changes: 83 additions & 0 deletions tests/py/test_participant_identities.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

from cryptography.fernet import InvalidToken
from gratipay.testing import Harness
from gratipay.models.participant import Participant
from gratipay.models.participant.mixins import identity, Identity
from gratipay.models.participant.mixins.identity import _validate_info, rekey
from gratipay.models.participant.mixins.identity import ParticipantIdentityInfoInvalid
from gratipay.models.participant.mixins.identity import ParticipantIdentitySchemaUnknown
from gratipay.security.crypto import EncryptingPacker, Fernet
from postgres.orm import ReadOnly
from psycopg2 import IntegrityError
from pytest import raises

Expand Down Expand Up @@ -250,6 +252,87 @@ def test_ci_still_logs_an_event_when_noop(self):
self.assert_events(self.crusher.id, [None], [self.TTO], ['clear identity'])


# hvi - has_verified_identity

def test_hvi_defaults_to_false(self):
assert self.crusher.has_verified_identity is False

def test_hvi_is_read_only(self):
with raises(ReadOnly):
self.crusher.has_verified_identity = True

def test_hvi_becomes_true_when_an_identity_is_verified(self):
self.crusher.store_identity_info(self.TTO, 'nothing-enforced', {})
self.crusher.set_identity_verification(self.TTO, True)
assert Participant.from_username('crusher').has_verified_identity

def test_hvi_becomes_false_when_the_identity_is_unverified(self):
self.crusher.store_identity_info(self.TTO, 'nothing-enforced', {})
self.crusher.set_identity_verification(self.TTO, True)
self.crusher.set_identity_verification(self.TTO, False)
assert not Participant.from_username('crusher').has_verified_identity

def test_hvi_stays_true_when_a_secondary_identity_is_verified(self):
self.crusher.store_identity_info(self.USA, 'nothing-enforced', {})
self.crusher.set_identity_verification(self.USA, True)
self.crusher.store_identity_info(self.TTO, 'nothing-enforced', {})
self.crusher.set_identity_verification(self.TTO, True)
assert Participant.from_username('crusher').has_verified_identity

def test_hvi_stays_true_when_the_secondary_identity_is_unverified(self):
self.crusher.store_identity_info(self.USA, 'nothing-enforced', {})
self.crusher.set_identity_verification(self.USA, True)
self.crusher.store_identity_info(self.TTO, 'nothing-enforced', {})
self.crusher.set_identity_verification(self.TTO, True)
self.crusher.set_identity_verification(self.TTO, False)
assert Participant.from_username('crusher').has_verified_identity

def test_hvi_goes_back_to_false_when_both_are_unverified(self):
self.crusher.store_identity_info(self.USA, 'nothing-enforced', {})
self.crusher.store_identity_info(self.TTO, 'nothing-enforced', {})
self.crusher.set_identity_verification(self.TTO, True)
self.crusher.set_identity_verification(self.USA, True)
self.crusher.set_identity_verification(self.TTO, False)
self.crusher.set_identity_verification(self.USA, False)
assert not Participant.from_username('crusher').has_verified_identity

def test_hvi_changes_are_scoped_to_a_participant(self):
self.crusher.store_identity_info(self.USA, 'nothing-enforced', {})

bruiser = self.make_participant('bruiser', email_address='[email protected]')
bruiser.store_identity_info(self.USA, 'nothing-enforced', {})

self.crusher.set_identity_verification(self.USA, True)

assert Participant.from_username('crusher').has_verified_identity
assert not Participant.from_username('bruiser').has_verified_identity

def test_hvi_resets_when_identity_is_cleared(self):
self.crusher.store_identity_info(self.TTO, 'nothing-enforced', {})
self.crusher.set_identity_verification(self.TTO, True)
self.crusher.clear_identity(self.TTO)
assert not Participant.from_username('crusher').has_verified_identity

def test_hvi_doesnt_reset_when_penultimate_identity_is_cleared(self):
self.crusher.store_identity_info(self.USA, 'nothing-enforced', {})
self.crusher.set_identity_verification(self.USA, True)
self.crusher.store_identity_info(self.TTO, 'nothing-enforced', {})
self.crusher.set_identity_verification(self.TTO, True)
self.crusher.set_identity_verification(self.TTO, False)
self.crusher.clear_identity(self.TTO)
assert Participant.from_username('crusher').has_verified_identity

def test_hvi_does_reset_when_both_identities_are_cleared(self):
self.crusher.store_identity_info(self.USA, 'nothing-enforced', {})
self.crusher.store_identity_info(self.TTO, 'nothing-enforced', {})
self.crusher.set_identity_verification(self.USA, True)
self.crusher.set_identity_verification(self.TTO, True)
self.crusher.set_identity_verification(self.TTO, False)
self.crusher.set_identity_verification(self.USA, False)
self.crusher.clear_identity(self.TTO)
assert not Participant.from_username('crusher').has_verified_identity


# fine - fail_if_no_email

def test_fine_fails_if_no_email(self):
Expand Down

0 comments on commit cfe2d0b

Please sign in to comment.