Testing Django Responses to Stripe Webhooks - python

I'm trying to figure out an effective way to test how my server handles webhooks from Stripe. I'm setting up a system to add multiple subscriptions to a customer's credit card, which is described on Stripe's website:
https://support.stripe.com/questions/can-customers-have-multiple-subscriptions
The issue I'm having is figuring out how to effectively test that my server is executing the scripts correctly (i.e., adding the correct subscriptions to the invoice, recording the events in my database, etc.). I'm not too concerned about automating the test right now, I'm just struggling to effectively run any good test on the script. Has anyone done this with Django previously? What resources and tools did you use to run these tests?
Thanks!

I did not use any tools to run the tests. Impact the stripe has a FULL API REFERENCE which display the information you have send to them and they also display the error. Stripe is very easy to setup, cheap, and have full details in documentation.
What I did is?
First I create a stripe account. In that account, they will give you:
TEST_SECRET_KEY: use for sending payment and information in stripe (for testing)
TEST_PUBS_KEY: identifies your website when communicating with Stripe (for testing)
LIVE_SECRET_KEY: use for sending payment and information in stripe (for live)
LIVE_PUBS_KEY: identifies your website when communicating with Stripe (for live)
API_VERSION: "2012-11-07" //this is the version for testing only
When you login you will see Documentation at the top. Click the documentation and they will give you step by step tutorial on how to create a form, how to create subscription, how to handle errors and many more.
To check if your script is executing and connecting to stripe. Click FULL API REFERENCE then choose Python. In that page you will see the information you have send and error that you have encountered.
What I really like is, if the Stripe detect an error the system will point out that and give you a solution. The solution is in the left side and checking the information send is on the right side.
Stripe is divided into two worlds: the test mode and the live. In test mode, you can perform creating new customer, add new invoices, set up your subscription, and many more. What ever you do in test mode, is the same when your Stripe is live.

I really love that stripe provides the logs for the web hooks, however, it is difficult to view the error responses from them, so I set up a script using the Requests library. First, I went to the Stripe dashboard and copied one of the requests they were sending.
Events & Webhooks --> click on one of the requests --> copy the entire request
import requests
data = """ PASTE COPIED JSON REQUEST HERE """
# insert the appropriate url/endpoint below
res = requests.post("http://localhost:8000/stripe_hook/", data=data).text
output = open("hook_result.html", "w")
output.write(res)
output.close()
Now I could open hook_result.html and see any django errors that may have come up (given DEBUG=True in django).

In django-stripe-payments I have a test suite that while far from comprehensive is meant to be a start at getting there. What I do is just copy a real webhook's data, scrub it for sensitive data and add it as a data to the test.

testing stripe webhooks is a pain. I don't use Django, so my answer will be more general.
My php webhook handler parses the webhook data and dispatches handler functions accordingly. In my handler class, I set up class properties with legitimate data for all the ids that the test webhooks mangles. Then I have a condition in each of my handler functions that tests for livemode. If false, I replace the mangled ids with legit test ids.
I also have another class property called $fakeLiveMode, which I set to true when I'm testing. This allows me to force the code to process as though in live mode.
So, for example, when testing the customer.subscription.updated event, the plan id and customer id get botched. So in that handler I would do this:
if ($event->livemode === true || $this->fakeLivemode)
{
if ($this->fakeLivemode)
{
// override botched data returned by test webhook
$event->data->object->plan->id = $this->testPlanId;
$event->data->object->customer = $this->testCustomerId;
}
// process webhook
}
Does that help?

Related

How to use multiple Stripe API keys in Djstripe webhook, is it even possible?

I'm having a hard time trying to wrap my mind around this issue - is it possible to somehow use more than just one Stripe API key in Djstripe webhook handler? If so, how?
I have two client apps, both using Stripe. Expectedly, there are two sets of Stripe API keys, each set for a client app. There are no issues with making the payment intents and charging, app is sending enough info, and the keys are explicitly defined (e.g. stripe.api_key = STRIPE_SECRET_KEY) so those part of the code can juggle between API keys succesfully.
The hard problem I have encountered is, Stripe webhook handler does not have info to do the juggling - it fails with an error saying:
stripe.error.InvalidRequestError: Request <req_id>: No such payment_intent: <payment_intent_id>
Sure enough, if I use only one set of API keys, it'll do as expected, but I'd need them both.
My idea is to use two webhook endpoints, but I'm not sure how to define additional webhook endpoint in my config/urls.py file. Currently, I'm using this:
urlpatterns = [
...
path("stripe/", include("djstripe.urls", namespace="djstripe")),
...
In the webhook.py file, I'm using #webhooks decorator:
#webhooks.handler('payment_intent.succeeded')
def payment_intent_succeeded(event, **kwargs):
# code goes here...
Since there are only two sets of API keys, I can try to use one key in try block, then use another if that one fails, but there is some magic configuration string usage there I was not able to crack, code inside that webhook never gets executed, so I can't even try that approach.
I was wondering is there any way to define what API key to use there?
Thank you for any ideas!
(I'm using dj-stripe version 2.5.1, and yes, I've inherited that code)

make a decision based on response of webhook in mautic

I was wondering if there is any way to make decisions based on webhook responses in Mautic. To elaborate, I post a request via webhook and the corresponding API responds with an error (e.g. 411). I want to create a campaign that has a block depending on the response of that webhook if it receives 200 decision 1 is made and if it receives 411, another decision is made.
how can I implement this?
I don't think such feature exists by default, but there can be alternative ways to do this.
sending an api call from the system in question(like on success make a call do set some tag or field) same goes for error. However this is practical as long as you have control over that system.
Create a custom campaign Decision node which will listen to the responses of the webhook(in this case you will need to send the webhook using campaign only), Again the block here is that you will need to know how to code a custom campaign decision or will need to look for a developer who can do it.

How to set password reset url to a mobile deeplink using Flask Security?

Gist of the problem is, I'm not developing an SPA, I'm developing a mobile app, with a backend in Flask. FlaskSecurityToo has provided me with some great features, and I'm now trying to use their password reset functionality. Here's my gripe.
I want to have the email send a deeplink, which users on the mobile app will click and get sent to the password reset form on the app. There's no UI view for this. But FlaskSecurityToo has logic that requires the server is first hit to validate the token, then redirects them to whatever has REDIRECT_HOST set. Which works great when I set the REDIRECT_BEHAVIOR as spa
Is there a way to tell Flask "Hey, don't worry about the need to validate the token from the initially provided password reset email, let the UI/Mobile app make the call to determine that whenever they want" from the provided configuration? Thus, relaxing the constraint on the host name / details of the url for a password reset, as long as a token exists? Or is this abusing some of the principles of FlaskSecurity that I don't grasp yet?
My current plan is to let it open a mobile browser, and hopefully the redirect forces the app open? I have little experience with deeplinks, so I'm testing and probing things as I learn.
You are correct about current FS behavior - here is a suggestion (not clean but it would be interesting if it was all you need) - the POST /reset/ endpoint is stand-alone - you don't have to call GET first - the POST will ALSO verify the token is valid. So the issue becomes how to generate the link for the email that has what you want. FS currently doesn't allow to configure this (that could be an enhancement) - but in 4.0.0 you can easily replace the MailUtil class and have your implementation of send_mail look for template='reset_instructions'. Now - at this point the email has already been rendered - so you would have to parse the body and rewrite the url (keeping the token intact). Ugly but doable - is this sufficient? If so I can see a few simple improvements in FS to allow more flexibility around emails.

Get and parse data from the last message of a specific sender with python and Gmail API

Everyday, a sender "sender#sender.com" send me a message with a number inside.
I need to save this number everyday.
I want to write a python script with gmail API to get data from last mail from this sender, and then parse it.
I followed the Gmail API "Quickstart Guide" : here
I also check the page about User.message : here
However, I don't understand how to synchronize all of this to get the data.
Could someone explain me the process ?
If you where you able to complete the Gmail API quickstart, then you already have a GCP project, credentials and have authorized some Gmail API scopes for you app.
The above is the first step (being able to authenticate and be allowed to make requests for the API scope you need).
Since you need to pass a message's Id as a parameter for Users.messages.get you need to first retrieve it using listing messages for example.
So the next step is to make a request to Users.messages.list to list all messages from a user.
You could use the query (q) parameter to filter the messages by user like: q="from:someuser#example.com is:unread".
This will return a list of messages from someuser#example.com that are unread.
Try things out in the API explorer sidebar from the documentation until you have defined the request as you want, and then implement it into you app.
As aerials said.
users().messages().list(userId='me',q=("<parameters>"))).execute()
The above code will fulfill the exact same function as typing in a search request on the gmail website. You dont actually have to worry about labels or anything if you are operating at a small scale. Just follow the same syntax as the search bar on gmail.
However, I am not sure about the usage quotas on the q parameter for list. It may be more expensive for a bigger scale operation to use the q parameter instead of using the other api methods.

Send data from Django to another server

I have an already existing Django app. I would like to add a system that sends data from my Django application to another Python application hosted on another server, so that the Python application receives data from the Django App in json format, possibly.
So for example, i would need to create a view that every tot seconds sends the data from a DB table to this application, or when a form is hit, the data is sent to this external application.
How can i do this? Is there an example for this particular matter? I don't know what tools i'd need to use to create this system, i only know that i would need to use Celery to perform asynchronous tasks, but nothing else; should i use Webhooks maybe? Or Django channels?
Edit: adding some more context:
I have my Django client. Then i have one or two Python applications running on another server. On my Django client i have some forms. Once the form is submitted, the data is saved on the db, but i also want this data to be sent instantly to my Python applications. The Python applications should receive the data from Django in Json format and perform some tasks according to the values submitted by users. Then the application should send a response to Django.
Come on! I'll call your Django app here "DjangoApp" and your Python apps, in Flask or another framework by "OtherApp".
First as you predicted you will need a framework that is capable of performing tasks, the new **Django 3.0 allows this, but I haven't used it yet ... I will pass on to you something that you are using and fully functional with Django 2.8 and Python 3.8**.
On your DjangoApp server you will need to structure the communication well with your Celery, let's leave the tasks to him. You can read Celery Docs and this post, its very ok to make this architecture.
Regardless of how your form or Django App looks, when you want it to activate a task in celery, it is basically the function to transmit data but in the background.
from .tasks import send_data
...
form.save()
# Create a function within the form to get the data the way you want it
# or do it the way you want.
values = form.new_function_serializedata()
send_data.delay(values) # [CALL CELERY TASKS][1]
...
Read too CALL CELERY TASKS
In all your other applications you will need to have a POST route to receive and serialize this data, do this with lightweight frameworks like Pyramid
This way, every time a form is submitted, you will have this data sent to the server within the send_data function.
In my experience, but not knowing much about your problem I would use a similar architecture but using Celery Beat.
CELERY_BEAT_SCHEDULE = {
'send_data': {
'task': 'your_app.tasks.send_data',
'schedule': crontab(), # CONFIGURE YOUR CRON
},
}
Not only is the above code added, but it is something like that.
Within your models I would create one field for sent. And every 2 seconds, 10 seconds .. as long as I wish I would filter all objects with sent = false, and pass all objects for the send_data task.
I don't know if you got confused, that's a lot to explain. But I hope I can help and answer your questions.
import requests
from django import http
def view(request):
url = 'python.app.com' # replace with other python app url or ip
request_data = {'key': 'value'} # replace with data to be sent to other app
response = requests.post(url, json=request_data)
response_data = response.json() # data returned by other app
return http.JsonResponse(response_data)
This is an example of a function based view that uses the requests library to hit an external service. The request lib takes care of encoding/decoding your data to/from json.
Yeah, webhook would be one of the options, but there are other options available too.
-> You can use Rest Apis to send data from one app to another. but In their case, you need to think about synchronization. That depends on your requirement, If you don't want data in synchronize manner then you may use RabbiMq or other async tools. Just push your rest API request in Rabbitmq and Rabbitmq will handle.

Categories

Resources