def payday(): # Wire things up. # =============== env = wireup.env() wireup.db(env) wireup.billing(env) # Lazily import the billing module. # ================================= # This dodges a problem where db in billing is None if we import it from # gratipay before calling wireup.billing. from gratipay.billing.payday import Payday try: Payday.start().run() except KeyboardInterrupt: pass except: import aspen import traceback aspen.log(traceback.format_exc())
def set_paypal_email(username='', email='', api_key_fragment='', overwrite=False): """ Usage: [gratipay] $ env/bin/invoke set_paypal_email --username=username [email protected] [--api-key-fragment=12e4s678] [--overwrite] """ if not username or not email: print_help(set_paypal_email) sys.exit(1) if not os.environ.get('DATABASE_URL'): load_prod_envvars() if not api_key_fragment: first_eight = "unknown!" else: first_eight = api_key_fragment wireup.db(wireup.env()) participant = Participant.from_username(username) if not participant: print("No Gratipay participant found with username '" + username + "'") sys.exit(2) route = ExchangeRoute.from_network(participant, 'paypal') # PayPal caps the MassPay fee at $20 for users outside the U.S., and $1 for # users inside the U.S. Most Gratipay users using PayPal are outside the U.S. # so we set to $20 and I'll manually adjust to $1 when running MassPay and # noticing that something is off. FEE_CAP = 20 if route: print("PayPal email is already set to: " + route.address) if not overwrite: print("Not overwriting existing PayPal email.") sys.exit(3) if participant.api_key == None: assert first_eight == "None" else: assert participant.api_key[0:8] == first_eight print("Setting PayPal email for " + username + " to " + email) ExchangeRoute.insert(participant, 'paypal', email, fee_cap=FEE_CAP) print("All done.")
def main(_argv=sys.argv, _input=raw_input): """This is a script to dequeue and send emails. In production we have a thread inside the main web process that dequeues emails according to the DEQUEUE_EMAILS_EVERY envvar. This script is more for development, though when we're ready to move to a separate worker process/dyno we can start with this. """ env = wireup.env() wireup.make_sentry_teller(env) wireup.mail(env) wireup.db(env) Participant.dequeue_emails()
def payday(): # Wire things up. # =============== env = wireup.env() db = wireup.db(env) wireup.billing(env) # Lazily import the billing module. # ================================= # This dodges a problem where db in billing is None if we import it from # gratipay before calling wireup.billing. from gratipay.billing.exchanges import sync_with_balanced from gratipay.billing.payday import Payday try: sync_with_balanced(db) Payday.start().run() except KeyboardInterrupt: pass except: import aspen import traceback aspen.log(traceback.format_exc())
def compute_input_csv(): db = wireup.db(wireup.env()) participants = db.all(""" SELECT p.*, r.address AS paypal_email, r.fee_cap AS paypal_fee_cap FROM exchange_routes r JOIN participants p ON p.id = r.participant WHERE r.network = 'paypal' AND p.balance > 0 ORDER BY p.balance DESC """) writer = csv.writer(open(INPUT_CSV, 'w+')) print_rule(88) headers = "username", "email", "fee cap", "balance", "tips", "amount" print("{:<24}{:<32} {:^7} {:^7} {:^7} {:^7}".format(*headers)) print_rule(88) total_gross = 0 for participant in participants: total = participant.giving + participant.pledging amount = participant.balance - total if amount < 0.50: # Minimum payout of 50 cents. I think that otherwise PayPal upcharges to a penny. # See https://github.com/gratipay/gratipay.com/issues/1958. continue total_gross += amount print("{:<24}{:<32} {:>7} {:>7} {:>7} {:>7}".format( participant.username, participant.paypal_email, participant.paypal_fee_cap, participant.balance, total, amount)) row = (participant.username, participant.paypal_email, participant.paypal_fee_cap, amount) writer.writerow(row) print(" " * 80, "-" * 7) print("{:>88}".format(total_gross))
def main(db=None, *a, **kw): db = db or wireup.db(wireup.env()) clean_db(db) prep_db(db) populate_db(db, *a, **kw) clean_db(db) check_db(db)
def main(): """This function is installed via an entrypoint in ``setup.py`` as ``sync-npm``. Usage:: sync-npm """ env = wireup.env() db = wireup.db(env) while 1: with sentry.teller(env): last_seq = get_last_seq(db) log("Picking up with npm sync at {}.".format(last_seq)) stream = production_change_stream(last_seq) consume_change_stream(stream, db) try: last_seq = get_last_seq(db) sleep_for = 60 log('Encountered an error, will pick up with %s in %s seconds (Ctrl-C to exit) ...' % (last_seq, sleep_for)) time.sleep(sleep_for) # avoid a busy loop if thrashing except KeyboardInterrupt: return
def compute_input_csv(): from gratipay import wireup db = wireup.db(wireup.env()) participants = db.all(""" SELECT participants.*::participants FROM participants WHERE paypal_email IS NOT null AND balance > 0 ORDER BY balance DESC """) writer = csv.writer(open(INPUT_CSV, 'w+')) print_rule(88) headers = "username", "email", "fee cap", "balance", "tips", "amount" print("{:<24}{:<32} {:^7} {:^7} {:^7} {:^7}".format(*headers)) print_rule(88) total_gross = 0 for participant in participants: total = participant.giving + participant.pledging amount = participant.balance - total if amount < 0.50: # Minimum payout of 50 cents. I think that otherwise PayPal upcharges to a penny. # See https://github.com/gratipay/gratipay.com/issues/1958. continue total_gross += amount print("{:<24}{:<32} {:>7} {:>7} {:>7} {:>7}".format( participant.username, participant.paypal_email, participant.paypal_fee_cap, participant.balance, total, amount)) row = (participant.username, participant.paypal_email, participant.paypal_fee_cap, amount) writer.writerow(row) print(" " * 80, "-" * 7) print("{:>88}".format(total_gross))
def upsert(args): from gratipay import wireup db = wireup.db(wireup.env()) fp = open(args.path) with db.get_cursor() as cursor: assert cursor.connection.encoding == 'UTF8' # http://tapoueh.org/blog/2013/03/15-batch-update.html cursor.run( "CREATE TEMP TABLE updates (LIKE packages INCLUDING ALL) ON COMMIT DROP" ) cursor.copy_expert( 'COPY updates (package_manager, name, description, emails) ' "FROM STDIN WITH (FORMAT csv, NULL '%s')" % NULL, fp) cursor.run(""" WITH updated AS ( UPDATE packages p SET package_manager = u.package_manager , description = u.description , emails = u.emails FROM updates u WHERE p.name = u.name RETURNING p.name ) INSERT INTO packages(package_manager, name, description, emails) SELECT package_manager, name, description, emails FROM updates u LEFT JOIN updated USING(name) WHERE updated.name IS NULL GROUP BY u.package_manager, u.name, u.description, u.emails """)
def main(argv=sys.argv): """This function is installed via an entrypoint in ``setup.py`` as ``sync-npm``. Usage:: sync-npm {serialize,upsert,fetch-readmes,process-readmes} {<filepath>} ``<filepath>`` defaults to stdin. It's necessary for ``serialize`` and ``upsert``, and silently ignored for ``{fetch,process}-readmes``. .. note:: Sphinx is expanding ``sys.argv`` in the parameter list. Sorry. :-/ """ env = wireup.env() args = parse_args(argv[1:]) db = wireup.db(env) try: sys.stdout = sys.stderr # work around aspen.log_dammit limitation; sigh tell_sentry = wireup.make_sentry_teller(env) finally: sys.stdout = sys.__stdout__ def sentrified(func): def _(*a, **kw): try: func(*a, **kw) except: e = sys.exc_info()[0] tell_sentry(e, {}) return _ subcommands[args.command](env, args, db, sentrified)
def compute_input_csv(): db = wireup.db(wireup.env()) routes = get_ready_payout_routes_by_network(db, 'paypal') writer = csv.writer(open(INPUT_CSV, 'w+')) print_rule(88) headers = "username", "email", "fee cap", "amount" print("{:<24}{:<32} {:^7} {:^7}".format(*headers)) print_rule(88) total_gross = 0 for route in routes: amount = route.participant.balance if amount < 0.50: # Minimum payout of 50 cents. I think that otherwise PayPal upcharges to a penny. # See https://github.com/gratipay/gratipay.com/issues/1958. continue total_gross += amount print("{:<24}{:<32} {:>7} {:>7}".format( route.participant.username , route.address , route.fee_cap , amount )) row = (route.participant.username, route.address, route.fee_cap, amount) writer.writerow(row) print(" "*80, "-"*7) print("{:>88}".format(total_gross))
def compute_input_csv(): db = wireup.db(wireup.env()) routes = get_ready_payout_routes_by_network(db, 'paypal') writer = csv.writer(open(INPUT_CSV, 'w+')) print_rule(88) headers = "username", "email", "fee cap", "amount" print("{:<24}{:<32} {:^7} {:^7}".format(*headers)) print_rule(88) total_gross = 0 for route in routes: amount = route.participant.balance if amount < 0.50: # Minimum payout of 50 cents. I think that otherwise PayPal upcharges to a penny. # See https://github.com/gratipay/gratipay.com/issues/1958. continue total_gross += amount print("{:<24}{:<32} {:>7} {:>7}".format( route.participant.username , route.address , route.fee_cap , amount )) row = (route.participant.username, route.address, route.fee_cap, amount) writer.writerow(row) print(" "*64, "-"*7) print("{:>72}".format(total_gross))
def main(_argv=sys.argv, _print=print): """This is a script to list the email queue. """ env = wireup.env() db = wireup.db(env) for i, email in enumerate(db.all(QUEUE), start=1): _print("{:>4} {:>6} {:<16} {:<24} {}".format(i, *email)) # Trigger logging of sentry/mailer configuration for reference. wireup.make_sentry_teller(env) wireup.mail(env)
def compute_input_csv(): db = wireup.db(wireup.env()) participants = db.all(""" SELECT p.*, r.address AS paypal_email, r.fee_cap AS paypal_fee_cap FROM exchange_routes r JOIN participants p ON p.id = r.participant WHERE r.network = 'paypal' AND p.balance > 0 ---- Only include team owners ---- TODO: Include members on payroll once process_payroll is implemented AND ( SELECT count(*) FROM teams t WHERE t.owner = p.username AND t.is_approved IS TRUE AND t.is_closed IS NOT TRUE ) > 0 ORDER BY p.balance DESC """) writer = csv.writer(open(INPUT_CSV, 'w+')) print_rule(88) headers = "username", "email", "fee cap", "balance", "tips", "amount" print("{:<24}{:<32} {:^7} {:^7} {:^7} {:^7}".format(*headers)) print_rule(88) total_gross = 0 for participant in participants: total = participant.giving amount = participant.balance - total if amount < 0.50: # Minimum payout of 50 cents. I think that otherwise PayPal upcharges to a penny. # See https://github.com/gratipay/gratipay.com/issues/1958. continue total_gross += amount print("{:<24}{:<32} {:>7} {:>7} {:>7} {:>7}".format( participant.username , participant.paypal_email , participant.paypal_fee_cap , participant.balance , total , amount )) row = (participant.username, participant.paypal_email, participant.paypal_fee_cap, amount) writer.writerow(row) print(" "*80, "-"*7) print("{:>88}".format(total_gross))
def main(argv=sys.argv): """This function is installed via an entrypoint in ``setup.py`` as ``sync-npm``. Usage:: sync-npm {serialize,upsert} {<filepath>} ``<filepath>`` defaults to stdin. .. note:: Sphinx is expanding ``sys.argv`` in the parameter list. Sorry. :-/ """ env = wireup.env() args = parse_args(argv[1:]) db = wireup.db(env) subcommands[args.command](env, args, db)
def compute_input_csv(): from gratipay import wireup db = wireup.db(wireup.env()) participants = db.all(""" SELECT participants.*::participants FROM participants WHERE paypal_email IS NOT null AND balance > 0 ORDER BY balance DESC """) writer = csv.writer(open(INPUT_CSV, 'w+')) print_rule(88) headers = "username", "email", "fee cap", "balance", "tips", "amount" print("{:<24}{:<32} {:^7} {:^7} {:^7} {:^7}".format(*headers)) print_rule(88) total_gross = 0 for participant in participants: total = participant.giving + participant.pledging amount = participant.balance - total if amount < 0.50: # Minimum payout of 50 cents. I think that otherwise PayPal upcharges to a penny. # See https://github.com/gratipay/gratipay.com/issues/1958. continue total_gross += amount print("{:<24}{:<32} {:>7} {:>7} {:>7} {:>7}".format( participant.username , participant.paypal_email , participant.paypal_fee_cap , participant.balance , total , amount )) row = (participant.username, participant.paypal_email, participant.paypal_fee_cap, amount) writer.writerow(row) print(" "*80, "-"*7) print("{:>88}".format(total_gross))
def main(): db = wireup.db(wireup.env()) prep_db(db) populate_db(db) clean_db(db) check_db(db)
def set_paypal_email(username='', email='', api_key_fragment='', overwrite=False): """ Usage: [gratipay] $ env/bin/invoke set_paypal_email --username=username [email protected] [--api-key-fragment=12e4s678] [--overwrite] """ if not os.environ.get('DATABASE_URL'): load_prod_envvars() if not username or not email: print(set_paypal_email.__doc__) sys.exit(1) if not api_key_fragment: first_eight = "unknown!" else: first_eight = api_key_fragment db = wireup.db(wireup.env()) FIELDS = """ SELECT username, api_key, paypal_email FROM participants WHERE username = %s """ fields = db.one(FIELDS, (username,)) print(fields) if fields == None: print("No Gratipay participant found with username '" + username + "'") sys.exit(2) # PayPal caps the MassPay fee at $20 for users outside the U.S., and $1 for # users inside the U.S. Most Gratipay users using PayPal are outside the U.S. # so we set to $20 and I'll manually adjust to $1 when running MassPay and # noticing that something is off. FEE_CAP = ', paypal_fee_cap=20' if fields.paypal_email != None: print("PayPal email is already set to: " + fields.paypal_email) if not overwrite: print("Not overwriting existing PayPal email.") sys.exit(3) else: FEE_CAP = '' # Don't overwrite fee_cap when overwriting email address. if fields.api_key == None: assert first_eight == "None" else: assert fields.api_key[0:8] == first_eight print("Setting PayPal email for " + username + " to " + email) SET_EMAIL = """ UPDATE participants SET paypal_email=%s{} WHERE username=%s; """.format(FEE_CAP) print(SET_EMAIL % (email, username)) db.run(SET_EMAIL, (email, username)) print("All done.")
def bitcoin_payout(username='', amount='', api_key_fragment=''): """ Usage: [gratipay] $ env/bin/invoke bitcoin_payout --username=username --amount=amount [--api-key-fragment=12e4s678] """ if not username or not amount: print(bitcoin_payout.__doc__) sys.exit(1) amount = D(amount) assert amount >= MINIMUM_COINBASE_PAYOUT amount = subtract_fee(amount) if not api_key_fragment: first_eight = "unknown!" else: first_eight = api_key_fragment db = wireup.db(wireup.env()) FIELDS = """ SELECT username, api_key, bitcoin_address, balance FROM participants WHERE username = %s """ fields = db.one(FIELDS, (username,)) print(fields) if fields == None: print("No Gratipay participant found with username '" + username + "'") sys.exit(2) if not fields.bitcoin_address: print(username + " hasn't linked a bitcoin address to their profile!") sys.exit(3) print("Fetching bitcoin_address from database: " + fields.bitcoin_address) bitcoin_address = fields.bitcoin_address if D(fields.balance) < D(amount): print("Not enough balance. %s only has %f in their account!" % username, D(amount)) sys.exit(4) if fields.api_key == None: assert first_eight == "None" else: assert fields.api_key[0:8] == first_eight print("Sending bitcoin payout for " + username + " to " + bitcoin_address) try: data = { "transaction":{ "to": bitcoin_address, "amount_string": str(amount), "amount_currency_iso": "USD", "notes": "Gratipay Bitcoin Payout", "instant_buy": True } } result = coinbase_request('https://api.coinbase.com/v1/transactions/send_money', json.dumps(data)) except requests.HTTPError as e: print(e) return e if result.status_code != 200: print("Oops! Coinbase returned a " + str(result.status_code)) print(result.json()) sys.exit(5) elif result.json()['success'] != True: print("Coinbase transaction didn't succeed!") print(result.json()) sys.exit(6) else: print("Coinbase transaction succeeded!") print("Entering Exchange in database") # Get the fee from the response fee_dict = result.json()['transfer']['fees'] assert fee_dict['coinbase']['currency_iso'] == fee_dict['bank']['currency_iso'] == "USD" coinbase_fee = int(fee_dict['coinbase']['cents']) bank_fee = int(fee_dict['bank']['cents']) fee = (coinbase_fee + bank_fee) * D('0.01') # Get the amount from the response assert result.json()['transfer']['subtotal']['currency'] == "USD" amount = -D(result.json()['transfer']['subtotal']['amount']) # Negative amount for payouts btcamount = result.json()['transfer']['btc']['amount'] note = "Sent %s btc to %s" % (btcamount, bitcoin_address) with db.get_cursor() as cursor: exchange_id = cursor.one(""" INSERT INTO exchanges (amount, fee, participant, note, status) VALUES (%s, %s, %s, %s, %s) RETURNING id """, (amount, fee, username, note, 'succeeded')) new_balance = cursor.one(""" UPDATE participants SET balance=(balance + %s) WHERE username=%s RETURNING balance """, (amount - fee, username)) if new_balance < 0: raise NegativeBalance print("Exchange recorded: " + str(exchange_id)) print("New Balance: " + str(new_balance)) print("All done.")
#!/usr/bin/env python """verify-identity.py <participant_id>, <country_code> """ from __future__ import absolute_import, division, print_function, unicode_literals import sys from gratipay import wireup from gratipay.models.participant import Participant from gratipay.models.country import Country wireup.db(wireup.env()) participant = Participant.from_id(int(sys.argv[1])) country = Country.from_code(sys.argv[2]) participant.set_identity_verification(country.id, True)
def main(_argv=sys.argv, _input=raw_input, _print=print): """This is a script to enqueue global site notification emails. It should only be used for important transactional messages like a Terms of Service change. Process: - write your email in emails/branch.spt - test locally using your own database and AWS keys in local.env - when reviewed and merged: - deploy - `heroku run bash` - `queue-branch-email your_username` # final test from production - `queue-branch-email all 2> queued.log` # !!! - make a commit to master to empty branch.spt (leave an empty file [but with speclines] or tests will fail) - push to GitHub """ db = wireup.db(wireup.env()) def prompt(msg): answer = _input(msg + " [y/N]") if answer.lower() != 'y': raise SystemExit(1) # Fetch participants. # =================== try: username = _argv[1] except IndexError: _print("Usage: {0} [username|all]".format(_argv[0])) raise SystemExit if username == 'all': prompt("Are you ready?") prompt("Are you REALLY ready?") prompt("... ?") _print("Okay, you asked for it!") participants = get_recently_active_participants(db) else: _print("Okay, just {}.".format(username)) participants = db.all( "SELECT p.*::participants FROM participants p " "WHERE p.username=%s", (username, )) N = len(participants) _print(N) for p in random.sample(participants, 5 if N > 5 else 1) if N else []: _print("spotcheck: {} ({}={})".format(p.email_address, p.username, p.id)) # Send emails. # ============ if username == 'all': prompt("But really actually tho? I mean, ... seriously?") for i, p in enumerate(participants, start=1): _print("{:>4} queuing for {} ({}={})".format(i, p.email_address, p.username, p.id), file=sys.stderr) p.queue_email('branch', include_unsubscribe=False)
def readmes(args): from gratipay import wireup db = wireup.db(wireup.env()) _readmes.sync_all(db)
#!/usr/bin/env python """This is a one-off script to resend emails for #3355.""" import sys from gratipay import wireup env = wireup.env() db = wireup.db(env) # Temporary, will fill with actual values when running script email_txt = """ [email protected] [email protected] """ emails = [email.strip() for email in email_txt.split()] assert len(emails) == 176 participants = [] participants = db.all(""" SELECT p.*::participants FROM participants p WHERE email_address IN %s """, (tuple(emails), )) for p in participants: p.queue_email('double_emails')
from datetime import timedelta from aspen.utils import utcnow import gratipay from gratipay import wireup from gratipay.models.participant import Participant if len(sys.argv) < 2: sys.exit('Usage: %s <user>' % sys.argv[0]) db = Participant.db = wireup.db(wireup.env()) gratipay.RESTRICTED_USERNAMES = os.listdir('./www/') username = sys.argv[1] session_token = uuid.uuid4().hex session_expires = utcnow() + timedelta(hours=6) participant = Participant.from_username(username) if not participant: participant = Participant.with_random_username() participant.change_username(username) db.run(""" INSERT INTO elsewhere (platform, user_id, user_name, participant) VALUES ('twitter', %s, %s, %s) """, (participant.id, username, username))
def bitcoin_payout(username='', amount='', api_key_fragment=''): """ Usage: [gratipay] $ env/bin/invoke bitcoin_payout --username=username --amount=amount [--api-key-fragment=12e4s678] """ if not username or not amount: print_help(bitcoin_payout) sys.exit(1) if not os.environ.get('DATABASE_URL'): load_prod_envvars() amount = D(amount) assert amount >= MINIMUM_COINBASE_PAYOUT amount = subtract_fee(amount) if not api_key_fragment: first_eight = "unknown!" else: first_eight = api_key_fragment db = wireup.db(wireup.env()) participant = Participant.from_username(username) if not participant: print("No Gratipay participant found with username '" + username + "'") sys.exit(2) route = ExchangeRoute.from_network(participant, 'bitcoin') if not route: print(username + " hasn't linked a bitcoin address to their profile!") sys.exit(3) bitcoin_address = route.address print("Fetched bitcoin_address from database: " + bitcoin_address) if D(participant.balance) < D(amount): print("Not enough balance. %s only has %f in their account!" % (username, D(amount))) sys.exit(4) if participant.api_key == None: assert first_eight == "None" else: assert participant.api_key[0:8] == first_eight print("Sending bitcoin payout for " + username + " to " + bitcoin_address) try: data = { "transaction": { "to": bitcoin_address, "amount_string": str(amount), "amount_currency_iso": "USD", "notes": "Gratipay Bitcoin Payout", "instant_buy": True } } result = coinbase_request( 'https://api.coinbase.com/v1/transactions/send_money', json.dumps(data)) except requests.HTTPError as e: print(e) return e if result.status_code != 200: print("Oops! Coinbase returned a " + str(result.status_code)) print(result.json()) sys.exit(5) elif result.json()['success'] != True: print("Coinbase transaction didn't succeed!") print(result.json()) sys.exit(6) else: print("Coinbase transaction succeeded!") print("Entering Exchange in database") # Get the fee from the response fee_dict = result.json()['transfer']['fees'] assert fee_dict['coinbase']['currency_iso'] == fee_dict['bank'][ 'currency_iso'] == "USD" coinbase_fee = int(fee_dict['coinbase']['cents']) bank_fee = int(fee_dict['bank']['cents']) fee = (coinbase_fee + bank_fee) * D('0.01') # Get the amount from the response assert result.json()['transfer']['subtotal']['currency'] == "USD" amount = -D(result.json()['transfer']['subtotal'] ['amount']) # Negative amount for payouts btcamount = result.json()['transfer']['btc']['amount'] note = "Sent %s btc to %s" % (btcamount, bitcoin_address) with db.get_cursor() as cursor: exchange_id = cursor.one( """ INSERT INTO exchanges (amount, fee, participant, note, status, route) VALUES (%s, %s, %s, %s, %s, %s) RETURNING id """, (amount, fee, username, note, 'succeeded', route.id)) new_balance = cursor.one( """ UPDATE participants SET balance=(balance + %s) WHERE username=%s RETURNING balance """, (amount - fee, username)) if new_balance < 0: raise NegativeBalance print("Exchange recorded: " + str(exchange_id)) print("New Balance: " + str(new_balance)) print("All done.")
def main(_argv=sys.argv, _input=raw_input, _print=print): """This is a script to enqueue global site notification emails. It should only be used for important transactional messages like a Terms of Service change. Process: - write your email in emails/branch.spt - test locally using your own database and AWS keys in local.env - when reviewed and merged: - deploy - `heroku run bash` - `queue-branch-email your_username` # final test from production - `queue-branch-email all 2> queued.log` # !!! - make a commit to master to empty branch.spt (leave an empty file [but with speclines] or tests will fail) - push to GitHub """ db = wireup.db(wireup.env()) def prompt(msg): answer = _input(msg + " [y/N]") if answer.lower() != 'y': raise SystemExit(1) # Fetch participants. # =================== try: username = _argv[1] except IndexError: _print("Usage: {0} [username|all]".format(_argv[0])) raise SystemExit if username == 'all': prompt("Are you ready?") prompt("Are you REALLY ready?") prompt("... ?") _print("Okay, you asked for it!") participants = db.all(""" SELECT p.*::participants FROM participants p WHERE email_address is not null AND claimed_time is not null AND is_closed is not true AND is_suspicious is not true """) else: _print("Okay, just {}.".format(username)) participants = db.all("SELECT p.*::participants FROM participants p " "WHERE p.username=%s", (username,)) N = len(participants) _print(N) for p in random.sample(participants, 5 if N > 5 else 1) if N else []: _print("spotcheck: {} ({}={})".format(p.email_address, p.username, p.id)) # Send emails. # ============ if username == 'all': prompt("But really actually tho? I mean, ... seriously?") for i, p in enumerate(participants, start=1): _print( "{:>4} queuing for {} ({}={})".format(i, p.email_address, p.username, p.id) , file=sys.stderr ) p.queue_email('branch', include_unsubscribe=False)
def main(): populate_db(wireup.db(wireup.env()))
#!/usr/bin/env python2 """See gratipay.models.participant.mixins.identity.rekey for documentation. """ from __future__ import absolute_import, division, print_function, unicode_literals from gratipay import wireup from gratipay.models.participant.mixins import identity as participant_identities env = wireup.env() db = wireup.db(env) packer = wireup.crypto(env) n = participant_identities.rekey(db, packer) print("Rekeyed {} participant identity record(s).".format(n))
def _wireup(): env = wireup.env() db = wireup.db(env) wireup.crypto(env) return db
#!/usr/bin/env python -u from __future__ import absolute_import, division, print_function, unicode_literals import json, os, sys, traceback from collections import defaultdict from gratipay import wireup from decimal import Decimal as D from pprint import pprint from gratipay.models.exchange_route import ExchangeRoute db = wireup.db(wireup.env()) dirname = os.path.join(os.path.dirname(__file__), 'balanced', 'transactions') class UnknownExchange(Exception): def __str__(self): return "\n\n{}".format(self.args[0]) class UnknownCustomer(Exception): pass class UnknownRoute(Exception): pass class AmbiguousCustomer(Exception): pass class AmbiguousRoute(Exception): pass class CountsOff(Exception): def __str__(self): msg, counts = self.args out = [msg] cur = '' for name, val in sorted(counts.__dict__.items()): if name[0] != cur:
def set_paypal_email(username='', email='', api_key_fragment='', overwrite=False): """ Usage: [gratipay] $ env/bin/invoke set_paypal_email --username=username [email protected] [--api-key-fragment=12e4s678] [--overwrite] """ if not os.environ.get('DATABASE_URL'): load_prod_envvars() if not username or not email: print(set_paypal_email.__doc__) sys.exit(1) if not api_key_fragment: first_eight = "unknown!" else: first_eight = api_key_fragment db = wireup.db(wireup.env()) FIELDS = """ SELECT username, api_key, paypal_email FROM participants WHERE username = %s """ fields = db.one(FIELDS, (username, )) print(fields) if fields == None: print("No Gratipay participant found with username '" + username + "'") sys.exit(2) # PayPal caps the MassPay fee at $20 for users outside the U.S., and $1 for # users inside the U.S. Most Gratipay users using PayPal are outside the U.S. # so we set to $20 and I'll manually adjust to $1 when running MassPay and # noticing that something is off. FEE_CAP = ', paypal_fee_cap=20' if fields.paypal_email != None: print("PayPal email is already set to: " + fields.paypal_email) if not overwrite: print("Not overwriting existing PayPal email.") sys.exit(3) else: FEE_CAP = '' # Don't overwrite fee_cap when overwriting email address. if fields.api_key == None: assert first_eight == "None" else: assert fields.api_key[0:8] == first_eight print("Setting PayPal email for " + username + " to " + email) SET_EMAIL = """ UPDATE participants SET paypal_email=%s{} WHERE username=%s; """.format(FEE_CAP) print(SET_EMAIL % (email, username)) db.run(SET_EMAIL, (email, username)) print("All done.")
#!/usr/bin/env python """This is a one-off script to update user_info for #1936. This could be generalized for #900. """ from __future__ import absolute_import, division, print_function, unicode_literals import os import time import sys import requests from gratipay import wireup from requests_oauthlib import OAuth1 db = wireup.db(wireup.env()) def update_twitter(): oauth = OAuth1(os.environ['TWITTER_CONSUMER_KEY'], os.environ['TWITTER_CONSUMER_SECRET'], os.environ['TWITTER_ACCESS_TOKEN'], os.environ['TWITTER_ACCESS_TOKEN_SECRET']) elsewhere = db.all( "SELECT user_id FROM ELSEWHERE WHERE platform='twitter' ORDER BY id;") url = "https://api.twitter.com/1.1/users/lookup.json" while elsewhere: batch = elsewhere[:100] elsewhere = elsewhere[100:] user_ids = ','.join([str(user_id) for user_id in batch])
from gratipay.wireup import db, env from gratipay.models.team import AlreadyMigrated db = db(env()) teams = db.all(""" SELECT distinct ON (t.slug) t.*::teams FROM teams t JOIN tips ON t.owner = tips.tippee -- Only fetch teams whose owners had tips under Gratipay 1.0 WHERE t.is_approved IS TRUE -- Only fetch approved teams AND NOT EXISTS ( -- Make sure tips haven't been migrated for any teams with same owner SELECT 1 FROM payment_instructions pi JOIN teams t2 ON t2.slug = pi.team WHERE t2.owner = t.owner AND pi.ctime < t2.ctime ) """) for team in teams: try: ntips = team.migrate_tips() print("Migrated {} tip(s) for '{}'".format(ntips, team.slug)) except AlreadyMigrated: print("'%s' already migrated." % team.slug) print("Done.")
#!/usr/bin/env python """verify-identity.py <participant_id> <country_code> """ from __future__ import absolute_import, division, print_function, unicode_literals import sys from gratipay import wireup from gratipay.models.participant import Participant from gratipay.models.country import Country wireup.db(wireup.env()) participant = Participant.from_id(int(sys.argv[1])) country = Country.from_code(sys.argv[2]) participant.set_identity_verification(country.id, True)