0

I had a small flask application where I would like to add only paid users in a database. The app has a registration form where the user clicks in "Go to Payment", after filling the form, and is direct to a session in stripe. If payment is successful, the app directs the user to a template succes.html.

I can get the session information using webhook:

@app.route('/event', methods=['POST'])
def new_event():
    event = None
    payload = request.data
    signature = request.headers['STRIPE_SIGNATURE']

    try:
        event = stripe.Webhook.construct_event(
            payload, signature, os.environ['STRIPE_WEBHOOK_SECRET'])
    except Exception as e:
        # the payload could not be verified
        abort(400)

    if event['type'] == 'checkout.session.completed':
      session = stripe.checkout.Session.retrieve(
          event['data']['object'].id, expand=['line_items'])
      user = User(username=form.username.data, email=form.email.data)
      user.set_password(form.password.data)
      db.session.add(user)
      db.session.commit()

    return {'success': True}

The problem, of course, is that the variable form is not defined inside the function new_event. Instead, I define it as a global variable in the route where I had access to the form data:

@app.route("/order/<product_id>", methods=["POST"])
def order(product_id):
    if product_id not in products:
        abort(404)

    global form
    form = RegistrationForm()

    checkout_session = stripe.checkout.Session.create(
        line_items=[
            {
                'price_data': {
                    'product_data': {
                        'name': products[product_id]['name'],
                    },
                    'unit_amount': products[product_id]['price'],
                    'currency': 'usd',
                    'recurring': {
                        'interval':'month'
                    }
                },
                'quantity': 1,
            },
        ],
        payment_method_types=['card'],
        mode='subscription',
        success_url=request.host_url + 'order/success',
        cancel_url=request.host_url + 'order/cancel',
    )
    return redirect(checkout_session.url)

Well, this is working, but this particular solution looks very problematic to me. The above solution relies on a variable defined and used in different routes. I wonder if near simultaneous access by several users can lead my application to use different user's data in each route since the route event always uses the last defined form data.

P.S: All codes in this question are modified versions from Miguel's blog flask tutorials. See, in particular, The Flask Mega-Tutorial Part V: User Logins, and Accept Credit Card Payments in Flask with Stripe Checkout.

Lucas
  • 799
  • 2
  • 9
  • 24
  • 1
    Global variables aren't safe here. I would write the customer to the database prior to creating the checkout session. Then, in the webhook handling code, update a field on the customer in the database, indicating that they have successfully paid. – codename_duchess Jan 26 '22 at 21:05

0 Answers0