Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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))
Ejemplo n.º 3
0
def payday():

    # Wire things up.
    # ===============

    env = wireup.env()
    db = wireup.db(env)

    wireup.billing(env)
    wireup.nanswers(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 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)
Ejemplo n.º 5
0
    def setUp(self):
        Harness.setUp(self)

        # Grab configuration from the environment, storing for later.
        env = wireup.env()
        self.environ = env.environ

        # Change env, doesn't change self.environ.
        env.canonical_scheme = 'https'
        env.canonical_host = 'gratipay.com'

        wireup.canonical(env)
Ejemplo n.º 6
0
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))
Ejemplo n.º 7
0
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.")
Ejemplo n.º 8
0
    def test_stats_description_accurate_during_payday_run(self, utcnow):
        """Test that stats page takes running payday into account.

        This test was originally written to expose the fix required for
        https://github.com/gratipay/gratipay.com/issues/92.
        """
        a_thursday = DateTime(2012, 8, 9, 11, 00, 01)
        utcnow.return_value = a_thursday

        self.client.hydrate_website()

        env = wireup.env()
        wireup.billing(env)
        payday = Payday.start()

        body = self.get_stats_page()
        assert "is changing hands <b>right now!</b>" in body, body
        payday.end()
Ejemplo n.º 9
0
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)
Ejemplo n.º 10
0
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))
Ejemplo n.º 11
0
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.")
Ejemplo n.º 12
0
#!/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:
Ejemplo n.º 13
0
def main():
    db = wireup.db(wireup.env())
    prep_db(db)
    populate_db(db)
    clean_db(db)
    check_db(db)
Ejemplo n.º 14
0
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.")
Ejemplo n.º 15
0
#!/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')
Ejemplo n.º 16
0
def _wireup():
    env = wireup.env()
    db = wireup.db(env)
    wireup.crypto(env)
    return db
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)
Ejemplo n.º 18
0
def main():
    populate_db(wireup.db(wireup.env()))
Ejemplo n.º 19
0
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))
Ejemplo n.º 20
0
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.")