コード例 #1
0
def submit_renew_member():
    """Processing the member renewal form.
    """
    user_email = flask_login.current_user.id

    renew_member = gapps.member_dict_from_request(flask.request, user_email,
                                                  'renew')

    gapps.renew_member_from_dict(renew_member)

    # Enqueue the renewal email
    gapps.enqueue_task('/tasks/renew-member-mail', renew_member)

    return 'success'
コード例 #2
0
def submit_new_member():
    """Create the new member.
    '409 Conflict' is thrown if the email address is already associated
    with an existing member.
    """
    user_email = flask_login.current_user.id

    new_member = gapps.member_dict_from_request(flask.request, user_email,
                                                'join')
    join_or_renew = gapps.join_or_renew_member_from_dict(new_member)

    if join_or_renew == 'join':
        # Enqueue the welcome email
        gapps.enqueue_task('/tasks/new-member-mail', new_member)
    # else the member already existed and we're going to email. This is especially
    # important because App Engine 500s even after a successful member creation. We don't
    # want a retry to spam the member.

    return f'success: {join_or_renew}'
コード例 #3
0
def submit_volunteer():
    """Handle submission of the embedded volunteer self-registration form.
    """
    logging.info('self_serve.submit_volunteer')
    logging.info('headers: %s', list(flask.request.headers.items()))
    logging.info('values: %s', list(flask.request.values.items()))

    referrer = flask.request.values.get(
        _EMBEDDER_VALUE_KEY) or flask.request.referrer or flask.request.origin

    # Create a dict of the volunteer info.
    new_volunteer = gapps.volunteer_dict_from_request(flask.request, referrer)

    gapps.join_volunteer_from_dict(new_volunteer)

    # Enqueue the welcome email
    gapps.enqueue_task('/tasks/new-volunteer-mail', new_volunteer)

    return 'success'
コード例 #4
0
def paypal_ipn():
    """This is the Paypal IPN address. Paypal will make calls to it for various
    events, including and especially a successful payment.
    https://developer.paypal.com/webapps/developer/docs/classic/ipn/gs_IPN/
    """

    logging.info('self_serve_tasks.paypal_ipn')
    logging.info('self_serve_tasks.paypal_ipn: headers: %s',
                 list(flask.request.headers.items()))

    # get_data MUST be called before accessing the form fields, or else the data won't
    # be available. https://flask.palletsprojects.com/en/1.1.x/api/#flask.Request.get_data
    req_data = flask.request.get_data(as_text=True)
    logging.info('self_serve_tasks.paypal_ipn: values: %s',
                 list(flask.request.values.items()))

    # First check with Paypal to see if this notification is legit
    validation_url = config.PAYPAL_IPN_VALIDATION_URL % req_data
    validation_response = requests.post(validation_url)
    if validation_response.status_code != 200 or validation_response.text != 'VERIFIED':
        # NOT LEGIT
        logging.warning(
            'self_serve_tasks.paypal_ipn: invalid IPN request; %d; %s',
            validation_response.status_code, validation_response.text)
        flask.abort(403)

    # Check if this actually represents a payment
    if flask.request.values.get('payment_status') != 'Completed':
        # Not a completed payment, but some intermediate event. We don't
        # do anything with these.
        logging.info(
            'self_serve_tasks.paypal_ipn: rejecting IPN with status: %s',
            flask.request.values.get('payment_status'))
        return flask.make_response('', 200)

    # Check if this is a membership payment. We want to ignore any other kind of payment.
    if flask.request.values.get('item_name') != config.PAYPAL_TXN_item_name:
        logging.info(
            'self_serve_tasks.paypal_ipn: rejecting IPN with item_name: "%s"; %s',
            flask.request.values.get('item_name'),
            list(flask.request.values.items()))
        return flask.make_response('', 200)

    # Check if the payment values are valid
    if flask.request.values.get(
            'receiver_email') != config.PAYPAL_TXN_receiver_email:
        # Alert our admins about this
        subject = 'ALERT: bad values in PayPal transaction'
        body = f'''
We received a valid PayPal IPN transaction that contained incorrect or
unexpected values. Specifically, the PayPal recipient email address doesn't
match ours; should be '{config.PAYPAL_TXN_receiver_email}', got '{flask.request.values.get('receiver_email')}'.

Here are the transaction values:
{pprint.pformat(list(flask.request.values.items()))}

Current URL:
{flask.request.full_path}

[This email was sent automatically.]
'''
        emailer.send_to_admins(subject, body)

        logging.info('self_serve_tasks.paypal_ipn: IPN had bad values')
        return flask.make_response('', 200)

    logging.info(
        'self_serve_tasks.paypal_ipn: IPN validated, enqueuing process-member-worker'
    )

    # Launch a task to actually create or renew the member.
    # We'll pass the Paypal params straight through.
    gapps.enqueue_task('/self-serve/process-member-worker',
                       dict(flask.request.values))

    return flask.make_response('', 200)
コード例 #5
0
def process_member_worker():
    """Creates or renews a member when payment has been received.
    """
    logging.debug('self_serve.process_member_worker hit')

    params = gapps.validate_queue_task(flask.request)
    logging.debug('self_serve.process_member_worker params: %s', params)

    payer_email = params.get('payer_email', '')
    payer_id = params.get('payer_id', '')
    paid_amount = params.get('mc_gross', '')
    payer_name = ''
    if params.get('first_name') and params.get('last_name'):
        payer_name = f"{params.get('first_name')} {params.get('last_name')}"

    # member_keystring should be considered untrusted. The user could have
    # removed or altered it before Paypal sent it to us. The rest of the
    # values came directly from Paypal (fwiw).
    # This value might also be empty because of an automatic renewal.
    member_keystring = params.get('invoice', '')

    # There are two scenarios here:
    #  1. This is a brand new member. We have their info in NDB and should
    #     now fully create them in the spreadsheet.
    #  2. This is an automatic renewal payment for an existing member. We
    #     should renew them in the spreadsheet.

    member_dict = {}
    candidate_found = False
    try:
        member_candidate = MemberCandidate.pop(member_keystring)

        # Get the member data we stored
        member_dict = flask.json.loads(member_candidate.member_json)
        candidate_found = True
        logging.info('found member candidate')
    except:
        logging.info('did not find member candidate')

    # Add the Paypal info, regardless
    member_dict[config.SHEETS.member.fields.paypal_name.name] = payer_name
    member_dict[config.SHEETS.member.fields.paypal_email.name] = payer_email
    member_dict[config.SHEETS.member.fields.paypal_payer_id.name] = payer_id
    member_dict[config.SHEETS.member.fields.paid_amount.name] = paid_amount

    join_or_renew = 'renew'

    if candidate_found:
        join_or_renew = gapps.join_or_renew_member_from_dict(member_dict)
    else:
        #
        # Renew an existing member.
        # We will try to find an existing user by looking up the payer_email
        # value in either the "Paypal Email" field or the "Email" field.
        #

        if not payer_email and not payer_id:
            logging.warning(
                'self_serve.process_member_worker: payer_email and payer_id empty'
            )
            renew_success = False
        else:
            renew_success = gapps.renew_member_by_email_or_paypal_id(
                payer_email, payer_id, member_dict)

        if not renew_success:
            # We failed to renew this paying member.
            # Alert our admins about this.
            subject = 'ALERT: failed to renew valid payer'
            body = f'''
We received a valid PayPal transaction but were unable to match the \
transaction to a member. In other words, we got someone's money, and it looks \
legit, but we can't figure out who they are in order to actually join or renew \
them.

Maybe they're in the spreadsheet under another email address?

Here are the transaction values:
{pprint.pformat(list(params))}

Current URL:
{flask.request.path}

[This email was sent automatically.]
'''

            emailer.send_to_admins(subject, body)

            logging.critical('failed to renew payer')
            return flask.make_response('', 200)

    # Enqueue the welcome email
    if join_or_renew == 'renew':
        gapps.enqueue_task('/tasks/renew-member-mail', member_dict)
        logging.info('renewed member')
        logging.info(member_dict)
    else:
        gapps.enqueue_task('/tasks/new-member-mail', member_dict)
        logging.info('joined member')
        logging.info(member_dict)

    return flask.make_response('', 200)
コード例 #6
0
def submit_join():
    """Handle submission of the embedded member self-registration form.
    """
    logging.info('self_serve.submit_join')
    logging.info('headers: %s', list(flask.request.headers.items()))
    logging.info('values: %s', list(flask.request.values.items()))

    referrer = flask.request.values.get(
        _EMBEDDER_VALUE_KEY) or flask.request.referrer or flask.request.origin

    # Create a dict of the member info.
    new_member = gapps.member_dict_from_request(flask.request, referrer,
                                                'join')

    # "Paid" field shouldn't be set by form in self-serve.
    new_member[config.SHEETS.member.fields.paid.name] = 'N'
    if flask.request.values.get(_PAYMENT_METHOD_VALUE_KEY) == 'paypal':
        new_member[config.SHEETS.member.fields.paid.name] = 'paypal'

    # Write the member info to the member candidate store.
    # This will be retrieved for processing by process_member_worker()
    member_candidate = MemberCandidate(
        member_json=flask.json.dumps(new_member),
        created=datetime.datetime.now(),
        expire=datetime.datetime.now() + datetime.timedelta(days=1))
    member_candidate_key = member_candidate.store()

    invoice_id = member_candidate_key.urlsafe().decode('ascii')

    # If the payment method is "cheque" create the new member directly,
    # otherwise start the PayPal process.
    if flask.request.values.get(_PAYMENT_METHOD_VALUE_KEY) == 'cheque':
        params = {'invoice': invoice_id}
        gapps.enqueue_task('/self-serve/process-member-worker', params)
        return 'success'

    logging.debug('self_serve.submit_join: awaiting PayPal IPN')

    # We put the key value into the URL so we can retrieve this member
    # after payment.
    paypal_url = config.PAYPAL_PAYMENT_URL % (invoice_id, )

    # If this is the demo server, then we skip PayPal and just create the user.
    if config.DEMO:
        params = {
            'payer_email':
            new_member.get(config.SHEETS.member.fields.email.name),
            'payer_id':
            'FAKE-ID',
            'first_name':
            new_member.get(config.SHEETS.member.fields.first_name.name),
            'last_name':
            new_member.get(config.SHEETS.member.fields.last_name.name),
            'invoice':
            invoice_id,
        }
        gapps.enqueue_task('/self-serve/process-member-worker', params)
        return 'demo'

    # Write the URL in the response so it can be shown to the user for follow-up
    return paypal_url