From 637fbc07cc9a8731da6b519d1b216d525c967079 Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Sat, 30 Apr 2016 19:52:19 -0400 Subject: [PATCH 1/2] clean up fake_data.py a little Still not showing up in Sphinx, though, hmm ... --- gratipay/utils/fake_data.py | 153 ++++++++++++++++++++---------------- 1 file changed, 84 insertions(+), 69 deletions(-) diff --git a/gratipay/utils/fake_data.py b/gratipay/utils/fake_data.py index f789ff49a6..c21cb94d9a 100644 --- a/gratipay/utils/fake_data.py +++ b/gratipay/utils/fake_data.py @@ -1,3 +1,5 @@ +"""This module contains utilities for populating a non-production environment with fake data. +""" import datetime from decimal import Decimal as D import random @@ -16,7 +18,15 @@ faker = Factory.create() -def _fake_thing(db, tablename, **kw): + +def insert_fake_data(db, tablename, **kw): + """Insert fake data into the database. + + :param Postgres db: a ``Postgres`` or ``Cursor`` object + :param unicode tablename: the name of the table to insert into + :param dict **kw: a mapping of column names to values + + """ column_names = [] column_value_placeholders = [] column_values = [] @@ -53,20 +63,20 @@ def fake_participant(db, is_admin=False): """ username = faker.first_name() + fake_text_id(3) try: - _fake_thing( db - , "participants" - , username=username - , username_lower=username.lower() - , ctime=faker.date_time_this_year() - , is_admin=is_admin - , balance=0 - , anonymous_giving=(random.randrange(5) == 0) - , balanced_customer_href=faker.uri() - , is_suspicious=False - , claimed_time=faker.date_time_this_year() - ) + insert_fake_data( db + , "participants" + , username=username + , username_lower=username.lower() + , ctime=faker.date_time_this_year() + , is_admin=is_admin + , balance=0 + , anonymous_giving=(random.randrange(5) == 0) + , balanced_customer_href=faker.uri() + , is_suspicious=False + , claimed_time=faker.date_time_this_year() + ) except IntegrityError: - return fake_participant(db, is_admin) + return fake_participant(db, is_admin) #Call participant constructor to perform other DB initialization return Participant.from_username(username) @@ -84,36 +94,38 @@ def fake_team(db, teamowner): try: teamslug = slugize(teamslugname) homepage = 'http://www.example.org/' + fake_text_id(3) - _fake_thing( db - , "teams" - , slug=teamslug - , slug_lower=teamslug.lower() - , name=teamname - , homepage=homepage - , product_or_service=random.sample(productorservice,1)[0] - , todo_url=homepage + '/tickets' - , onboarding_url=homepage + '/contributing' - , owner=teamowner.username - , is_approved=random.sample(isapproved,1)[0] - , receiving=0.1 - , nreceiving_from=3 - ) + insert_fake_data( db + , "teams" + , slug=teamslug + , slug_lower=teamslug.lower() + , name=teamname + , homepage=homepage + , product_or_service=random.sample(productorservice,1)[0] + , todo_url=homepage + '/tickets' + , onboarding_url=homepage + '/contributing' + , owner=teamowner.username + , is_approved=random.sample(isapproved,1)[0] + , receiving=0.1 + , nreceiving_from=3 + ) except IntegrityError: return fake_team(db, teamowner) return Team.from_slug(teamslug) + def fake_payment_instruction(db, participant, team): """Create a fake payment_instruction """ - return _fake_thing( db - , "payment_instructions" - , ctime=faker.date_time_this_year() - , mtime=faker.date_time_this_month() - , participant=participant.username - , team=team.slug - , amount=fake_tip_amount() - ) + return insert_fake_data( db + , "payment_instructions" + , ctime=faker.date_time_this_year() + , mtime=faker.date_time_this_month() + , participant=participant.username + , team=team.slug + , amount=fake_tip_amount() + ) + def fake_community(db, creator): """Create a fake community @@ -143,48 +155,50 @@ def fake_tip_amount(): def fake_tip(db, tipper, tippee): """Create a fake tip. """ - return _fake_thing( db - , "tips" - , ctime=faker.date_time_this_year() - , mtime=faker.date_time_this_month() - , tipper=tipper.username - , tippee=tippee.username - , amount=fake_tip_amount() - ) + return insert_fake_data( db + , "tips" + , ctime=faker.date_time_this_year() + , mtime=faker.date_time_this_month() + , tipper=tipper.username + , tippee=tippee.username + , amount=fake_tip_amount() + ) def fake_elsewhere(db, participant, platform): """Create a fake elsewhere. """ - _fake_thing( db - , "elsewhere" - , platform=platform - , user_id=fake_text_id() - , user_name=participant.username - , participant=participant.username - , extra_info=None - ) + insert_fake_data( db + , "elsewhere" + , platform=platform + , user_id=fake_text_id() + , user_name=participant.username + , participant=participant.username + , extra_info=None + ) def fake_transfer(db, tipper, tippee): - return _fake_thing( db - , "transfers" - , timestamp=faker.date_time_this_year() - , tipper=tipper.username - , tippee=tippee.username - , amount=fake_tip_amount() - , context='tip' - ) + return insert_fake_data( db + , "transfers" + , timestamp=faker.date_time_this_year() + , tipper=tipper.username + , tippee=tippee.username + , amount=fake_tip_amount() + , context='tip' + ) + def fake_exchange(db, participant, amount, fee, timestamp): - return _fake_thing( db - , "exchanges" - , timestamp=timestamp - , participant=participant.username - , amount=amount - , fee=fee - , status='succeeded' - ) + return insert_fake_data( db + , "exchanges" + , timestamp=timestamp + , participant=participant.username + , amount=amount + , fee=fee + , status='succeeded' + ) + def prep_db(db): db.run(""" @@ -225,6 +239,7 @@ def prep_db(db): FOR EACH ROW EXECUTE PROCEDURE process_exchange(); """) + def clean_db(db): db.run(""" DROP FUNCTION IF EXISTS process_transfer() CASCADE; @@ -337,7 +352,7 @@ def populate_db(db, num_participants=100, ntips=200, num_teams=5, num_transfers= 'nusers': len(actives), 'volume': sum(x['amount'] for x in week_transfers) } - _fake_thing(db, "paydays", **payday) + insert_fake_data(db, "paydays", **payday) date = end_date print("") From 5cc53f4740316b0b619d517a00633c2bd8300c2f Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Sat, 30 Apr 2016 20:24:33 -0400 Subject: [PATCH 2/2] add fake participant identities w/ dashboard --- gratipay/utils/fake_data.py | 69 ++++++++++++++++++++++++++++++++++--- tests/py/test_fake_data.py | 6 ++++ www/dashboard/countries.spt | 62 +++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 www/dashboard/countries.spt diff --git a/gratipay/utils/fake_data.py b/gratipay/utils/fake_data.py index c21cb94d9a..c5ab145367 100644 --- a/gratipay/utils/fake_data.py +++ b/gratipay/utils/fake_data.py @@ -58,8 +58,13 @@ def fake_sentence(start=1, stop=100): return faker.sentence(random.randrange(start,stop)) -def fake_participant(db, is_admin=False): +def fake_participant(db, is_admin=False, random_identities=True): """Create a fake User. + + :param Postgres db: a ``Postgres`` or ``Cursor`` object + :param bool is_admin: whether to make the participant an admin + :param bool random_identities: whether to give the participant random identities + """ username = faker.first_name() + fake_text_id(3) try: @@ -74,12 +79,40 @@ def fake_participant(db, is_admin=False): , balanced_customer_href=faker.uri() , is_suspicious=False , claimed_time=faker.date_time_this_year() + , email_address='{}@example.com'.format(username) ) + participant = Participant.from_username(username) + + if random_identities: + if random.randrange(100) < 66: + fake_participant_identity(participant) + if random.randrange(100) < 33: + fake_participant_identity(participant) + if random.randrange(100) < 50: + fake_participant_identity(participant) + except IntegrityError: return fake_participant(db, is_admin) - #Call participant constructor to perform other DB initialization - return Participant.from_username(username) + return participant + + +def fake_participant_identity(participant, verification=None): + """Pick a country and make an identity for the participant there. + + :param Participant participant: a participant object + :param bool verification: the value to set verification to; None will result in a 50% chance + either way + :returns: a country id + + """ + country_id = random_country_id(participant.db) + participant.store_identity_info(country_id, 'nothing-enforced', {}) + if verification: + participant.set_identity_verification(country_id, verification) + elif (random.randrange(2) == 0): # 50% + participant.set_identity_verification(country_id, True) + return country_id def fake_team(db, teamowner): @@ -200,6 +233,10 @@ def fake_exchange(db, participant, amount, fee, timestamp): ) +def random_country_id(db): + return db.one("SELECT id FROM countries ORDER BY random() LIMIT 1") + + def prep_db(db): db.run(""" CREATE OR REPLACE FUNCTION process_transfer() RETURNS trigger AS $$ @@ -251,10 +288,25 @@ def populate_db(db, num_participants=100, ntips=200, num_teams=5, num_transfers= """Populate DB with fake data. """ print("Making Participants") + make_flag_tester = num_participants > 1 + participants = [] - for i in xrange(num_participants): + for i in xrange(num_participants - 1 if make_flag_tester else num_participants): participants.append(fake_participant(db)) + if make_flag_tester: + # make a participant for testing weird flags + flag_tester = fake_participant(db, random_identities=False) + participants.append(flag_tester) + + nepal = db.one("SELECT id FROM countries WHERE code='NP'") + flag_tester.store_identity_info(nepal, 'nothing-enforced', {}) + flag_tester.set_identity_verification(nepal, True) + + vatican = db.one("SELECT id FROM countries WHERE code='VA'") + flag_tester.store_identity_info(vatican, 'nothing-enforced', {}) + flag_tester.set_identity_verification(vatican, True) + print("Making Teams") teams = [] teamowners = random.sample(participants, num_teams) @@ -357,8 +409,15 @@ def populate_db(db, num_participants=100, ntips=200, num_teams=5, num_transfers= print("") +def _wireup(): + env = wireup.env() + db = wireup.db(env) + wireup.crypto(env) + return db + + def main(db=None, *a, **kw): - db = db or wireup.db(wireup.env()) + db = db or _wireup() clean_db(db) prep_db(db) populate_db(db, *a, **kw) diff --git a/tests/py/test_fake_data.py b/tests/py/test_fake_data.py index c6caa36aca..df49351381 100644 --- a/tests/py/test_fake_data.py +++ b/tests/py/test_fake_data.py @@ -28,3 +28,9 @@ def test_fake_data(self): assert len(payment_instructions) == num_tips else: assert len(payment_instructions) == (num_participants - num_teams) + + + def test_fake_participant_identity(self): + crusher = self.make_participant('crusher', email_address='crusher@example.com') + country_id = fake_data.fake_participant_identity(crusher) + assert [x.country.id for x in crusher.list_identity_metadata()] == [country_id] diff --git a/www/dashboard/countries.spt b/www/dashboard/countries.spt new file mode 100644 index 0000000000..26f790a903 --- /dev/null +++ b/www/dashboard/countries.spt @@ -0,0 +1,62 @@ +from aspen import Response + +[---] +if not user.ADMIN: + raise Response(403) + +countries = website.db.all(""" + + SELECT name + , array_agg(username) as usernames + , array_agg(is_verified) as verifications + FROM participant_identities pi + JOIN participants p + ON p.id = participant_id + JOIN countries c + ON c.id = country_id + GROUP BY c.name + +""") + +multiple = website.db.all(""" + + WITH counts AS ( + SELECT participant_id, count(*) count + FROM participant_identities + GROUP BY participant_id + ) + SELECT p.*::participants + FROM participants p + JOIN counts c + ON p.id = c.participant_id + WHERE c.count > 1 + +""") + +zip = zip +[---] text/html +

Multiple

+{% for participant in multiple %} +{{ participant.username }} +{% for identity in participant.list_identity_metadata() %} +| {% if identity.is_verified %} +{{ identity.country.name }} +{% else %} +{{ identity.country.name }} +{% endif %} +{% endfor %} +
+{% endfor %} + +

By Country

+{% for country in countries %} +{{ country.name }} +{% for username, is_verified in zip(country.usernames, country.verifications) %} +| {% if is_verified %} +{{ username }} +{% else %} +{{ username }} +{% endif %} +{% endfor %} +
+{% endfor %}