Using Django to create Strava Webhook subscription - python-3.x

I am trying to create a Strava webhook subscription to recieve events from users who have authorised my Strava application. I was able to successfully create a subscription using the code in this Strava tutorial. However, I don't understand Javascript, so can't adapt the code to my needs. I am therefore trying to replicate it's functionality within Python using Django.
My basic approach has been to follow the setup outlined in the Django section of this webpage, then replace the code in the file views.py with the code below. I have tried to make the code function as similarly as possible to the Javascript function within the tutorial I linked above. However, I'm very new to web applications, so have taken shortcuts / 'gone with what works without understang why' in several places.
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.clickjacking import xframe_options_exempt
import json
#csrf_exempt
#xframe_options_exempt
def example(request):
if request.method == "GET":
verify_token = "STRAVA"
str_request = str(request)
try:
mode = str_request[str_request.find("hub.mode=") + 9 : len(str_request) - 2]
token = str_request[str_request.find("hub.verify_token=") + 17 : str_request.find("&hub.challenge")]
challenge = str_request[str_request.find("hub.challenge=") + 14 : str_request.find("&hub.mode")]
except:
return HttpResponse('Could not verify. Mode, token or challenge not valid.')
if (mode == 'subscribe' and token == verify_token):
resp = json.dumps({"hub.challenge":challenge},separators=(',', ':'))
return HttpResponse(resp, content_type='application/json; charset=utf-8')
else:
return HttpResponse('Could not verify mode or token.')
The Strava documentation says that the callback url must respond to a GET request within 2 seconds with a status of 200 and an echo of the hub.challenge json string. This function seems to do that. Yet when I try to create a POST request equivalent to the one below:
$ curl -X POST https://www.strava.com/api/v3/push_subscriptions \
-F client_id=[MY-CLIENT-ID] \
-F client_secret=[MY-CLIENT-SECRET] \
-F 'callback_url=http://[MY-IP-ADDRESS]:8000/webhooks/example/' \
-F 'verify_token=STRAVA'
I get the following response:
{
"message": "Bad Request",
"errors": [
{
"resource": "PushSubscription",
"field": "callback url",
"code": "not verifiable"
}
]
}
Does anyone have any idea what might be going wrong?
P.S. Please let me know if there's anything I can do to make this example more reproducible. I don't really understand this area well enough to know whether I'm leaving out some crucial info!

Related

How to implement the Microsoft Speaker Recognition / Verification API in Python?

I would like to implement the Speaker Recognition API from Microsoft's Cognitive Services for a Speaker Verification project. I already have a Speaker Recognition API key. I got the sample Python code directly from the documentation (on the bottom of the documentation):
https://westus.dev.cognitive.microsoft.com/docs/services/563309b6778daf02acc0a508/operations/563309b7778daf06340c9652
########### Python 3.2 #############
import http.client, urllib.request, urllib.parse, urllib.error, base64
headers = {
# Request headers
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key': '{subscription key}',
}
params = urllib.parse.urlencode({
})
try:
conn = http.client.HTTPSConnection('westus.api.cognitive.microsoft.com')
conn.request("POST", "/spid/v1.0/verificationProfiles?%s" % params, "{body}", headers)
response = conn.getresponse()
data = response.read()
print(data)
conn.close()
except Exception as e:
print("[Errno {0}] {1}".format(e.errno, e.strerror))
####################################
This is the code sample for the first step, create and save a voice profile.
To conduct Speaker Verification, we need to do 3 steps:
1) Create Profile
2) Create Enrollment
3) Verification
I'm stuck already at the first step now. This is my first time working with APIs in general, so I'm not really sure what parts of the Python code I have to change. I know that I need do insert my API key in 'Ocp-Apim-Subscription-Key' but other than that, what else? For example, if I add my API key in that specific field and let the code run, I received this error message.
b'{"error":{"code":"BadRequest","message":"locale is not specified"}}'
Where do I need to insert the locale ("en-us") for example? It is not really clear to me from the documentation what I need to edit. If you can guide me what I need to insert/add in my API calls I would be very thankful.
Thanks so much in advance!
When you create a Speaker Recognition profile, it has to be linked with a locale, and you specify this locale in the request body. The body should be a JSON object like the following one:
{
"locale":"en-us",
}
For the sample to work, you need to replace "{body}" with the actual body value like this:
conn.request("POST", "/spid/v1.0/verificationProfiles?%s" % params, "{\"locale\":\"en-US\"}", headers)

Facebook messenger chatbot with Flask and pymessenger

I have created a messenger chatbot with flask, pymessenger and wit.ai.
I want to add facebook provided templates (like buttons, adding images and sound media)(https://developers.facebook.com/docs/messenger-platform/reference/template/button/)
There using some curl and json thing which I do not understand. Can some one help me, where should I put these snippet in my python code.
#app.route('/', methods=['POST'])
def webhook():
data = request.get_json()
log(data)
if data['object'] == 'page':
for entry in data['entry']:
for messaging_event in entry['messaging']:
sender_id = messaging_event['sender']['id']
recipient_id = messaging_event['recipient']['id']
if messaging_event.get('message'):
if 'text' in messaging_event['message']:
messaging_text = messaging_event['message']['text']
else:
messaging_text = 'no text'
response = None
entity, value = wit_response(messaging_text)
if entity == 'newstype':
response = "OK. I will send you {} news".format(str(value))
elif entity == 'cust_greet':
response = get_message()
elif entity == 'cust_bye':
response = "Bye! Have a Good Day!".format(str(value))
elif entity == 'cust_option':
response = "Option 1: Option 2:"
bot.send_text_message(sender_id, response)
return "ok", 200
def log(message):
print(message)
sys.stdout.flush()
HTTP requests use one of these two formats:
GET: All the request information is in the url
POST: Some information is sent via a JSON format to the url
What we see in the Facebook API is a POST request: the url is defined as
https://graph.facebook.com/v2.6/me/messages?access_token=<PAGE_ACCESS_TOKEN>
...and there is POST request information in the JSON section underneath
Curl is a program used to send HTTP requests from the terminal. If you install Curl, you can fill in the JSON/url information, run the command (which sends the POST request), and see the buttons pop up for the recipient. Just as you want your chatbot to do!
However, Curl is a tool, not a Python library!
To do this in Python, you can send the request through Python's built in libraries, or install a package which makes this easier (such as requests), look into "sending http requests via python".
Below is an example (adapted from this question):
from urllib.parse import urlencode
from urllib.request import Request, urlopen
# the url we are sending the request to
url = "https://graph.facebook.com/v2.6/me/..."
# the POST request data
request_data = {
"recipient": {
"id": "<PSID>"
},
"message": {
"attachment": {
...
}
}
}
# create the request with the url and the data
post_request = Request(url, urlencode(request_data).encode())
# send it to Facebook! Response is the API response from Facebook
response = urlopen(post_request).read().decode()

Messenger Send API

I am creating a self built Python chatbot that does not use a chatbot platform such as Dialogflow. The issue is that there is no easy integration with messaging apps such as Messenger to connect it too. I am trying to create a webhook to Messenger using the Messenger Send API. I am looking at the documentation and it shows me how to request a POST api call. However when I look at examples online they all seem to deal with json values called "entry" and "messaging" which I can't find anywhere and can't seem to see why it is necessary. I was wondering how exactly the input body of a Messenger Send API looks like so I can call it appropriately and what json objects are in its body. This is what I have so far from following online examples. I am using Flask. And am using Postman to test this
#app.route("/webhook", methods=['GET','POST'])
def listen():
if request.method == 'GET':
return verify_webhook(request)
if request.method == 'POST':
payload = request.json
event = payload['entry'][0]['messaging']
for x in event:
if is_user_message(x):
text = x['message']['text']
sender_id = x['sender']['id']
respond(sender_id, text)
return "ok"
Below is what I think the body of the request looks like:
{
"object":"page",
"entry":[
{
"id":"1234",
"time":1458692752478,
"messaging":[
{
"message":{
"text":"book me a cab"
},
"sender":{
"id":"1234"
}
}
]
}
]
}
But it is unable to read this and gives me an error of:
File"/Users/raphael******/Documents/*****_Project_Raphael/FacebookWebHookEdition.py", line 42, in listen
event = payload['entry'][0]['messaging']
TypeError: 'NoneType' object is not subscriptable
Where am I going wrong that the webhook is not registering the body correctly as json objects?
Here is how we do it:
# GET: validate facebook token
if request.method == 'GET':
valid = messenger.verify_request(request)
if not valid:
abort(400, 'Invalid Facebook Verify Token')
return valid
# POST: process message
output = request.get_json()
if 'entry' not in output:
return 'OK'
for entry in output['entry']:
if 'messaging' not in entry:
continue
for item in entry['messaging']:
# delivery notification (skip)
if 'delivery' in item:
continue
# get user
user = item['sender'] if 'sender' in item else None
if not user:
continue
else:
user_id = user['id']
# handle event
messenger.handle(user_id, item)
# message processed
return 'OK'
EDIT:
If you are using postman, please make sure to also set Content-Type header to application/json, otherwise Flask can't decode it with request.json. I guess that's where None comes from in your case.

how to post a curl command using python

I need help with this.. Basically i need to use this command. This is the example given using CURL. All i need to do is simply paste this in cmd and it does its job.
curl \
-H "Content-Type: application/json" -X POST \
-u "{username}":"{password}" \
-d "{\"dialog_node\":\"greeting\",\"conditions\":\"#hello\",\"output\":{\"text\":\"Hi! How can I help you?\"},\"title\":\"greeting\"}" "https://gateway-s.watsonplatform.net/conversation/api/v1/workspaces/bec28d8f-18c1-4e97-8d08-9c842c658b51/dialog_nodes?version=2017-05-26"
The URL documentation can be found here:
https://www.ibm.com/watson/developercloud/conversation/api/v1/?curl#create_dialognode
The problem now is that i want to run this in a python script instead of in CMD.. i have searched google and stackOverflow for a few hours now.. but i cant seem to find the right answer..
So far i seen ppl using
1.requests
2.urllib
3.urllib2
4.pycurl
5.subprocess
I want to do it the right way. What is the best way to run the above command in a python script and how do i do it?
Also i am using python 3
Likes Simon O'Doherty said, you can use the Python SDK for using Conversation service. It is really the best practice to use the service, using the SDK or http requests.
"If something's worth doing, it's worth doing right, right?". So what
you're asking is "how do I run this other program, from within my
program, just to make a measly little web request?".
You can use cURL command, yes, you can. But it hardly looks very
Pythonic. That's a lot of work just for one little request. Python's
is more than it.
Author from the phrases here.
But, your question looks like you really want to use the cURL command inside your Python code, so, here is one example. In this case, you can use subprocess.
Call the Converstation:
import subprocess
subprocess.call(['curl', '-x', 'POST', '-H', '"Accept: application/json"', '-u', '{"userNameFromServiceCredentials:PasswordFromServiceCredentials" }', '"https://gateway-s.watsonplatform.net/conversation/api/v1/workspaces/bec28d8f-18c1-4e97-8d08-9c842c658b51/dialog_nodes?version=2017-05-26"'])
Important: For send the message and getting the output, you need to use the function subprocess.check_output(); like this example. And send the message for the right router, your cURL command needs to looks like this example from #German Atannasio and #Pridkkett.
Note: This answer is just to tell what is the better way to you follow, and if you really wants to use, one "Stone path" for you follow.
API Reference for using Watson Conversation Service with Python.
Requests documentation here.
If you are using Watson Conversation, then you can just use the Python WDC SDK.
https://github.com/watson-developer-cloud/python-sdk
For your example above it would be:
from watson_developer_cloud import ConversationV1
username = 'USERNAME',
password = 'PASSWORD',
version = '2017-05-26',
workspace_id = 'bec28d8f-18c1-4e97-8d08-9c842c658b51'
url = 'https://gateway-s.watsonplatform.net/conversation/api'
conversation = ConversationV1(
username=username
password=password,
version=version,
url=url
}
dialog_nodes = []
welcome_node = {
'output': {
'text': { 'values': [ 'Welcome!' ],
'selection_policy': 'sequential'
}
},
'parent': None,
'context': None,
'metadata': None,
'next_step': None,
'conditions': 'welcome',
'dialog_node': 'Welcome',
'previous_sibling': None
}
dialog_nodes.append(welcome_node)
# this appends to the previous node above, set by previous_sibling
node = {
'dialog_node': 'greeting',
'conditions': '#hello',
'context': None,
'metadata': None,
'next_step': None,
'output':{
'text': { 'values': [ 'Hi! How can I help you?' ]},
'selection_policy': 'sequential'
}
},
'title': 'greeting ',
'previous_sibling': 'Welcome',
'parent': None
}
dialog_nodes.append(node)
## Update the workspace.
response = conversation.update_workspace(
workspace_id=workspace_id,
dialog_nodes=dialog_nodes
)
print(response)
This call is an all or nothing, so if you have existing nodes it will delete them. The reason being is the SDK doesn't have the individual node editing. But this is a faster way to do it, rather then editing a single node (if you have more then one node).
If you want to make the individual call, then you will need to use something like requests, until the SDK is updated.
Example (using same variables from above):
import requests
from requests.auth import HTTPBasicAuth
endpoint = '{}/v1/workspaces/{}/dialog_nodes?version={}'.format(url,workspace_id,version)
basic_auth = HTTPBasicAuth(username, password)
# Change the condition to always execute.
node['conditions'] = 'true'
response = requests.post(url=endpoint, auth=basic_auth, json=node)
In python3 when sending files with pycurl, I want to understand why do I have to send the binary file directly
instead of providing its path
IBM Watson
#coding:utf-8
import certifi
import pycurl
import io
response = io.BytesIO()
c = pycurl.Curl()
#"apikey" is a key word
user = "apikey"
pwd = "YouRaPiKey"
#the file you want to submit
with open("path_to_file/audio-file.flac","rb") as f:
audiofile = f.read()
c.setopt(c.URL, "https://api. .... /.... /.. /v1/recognize")
c.setopt(pycurl.USERPWD, "{}:{}".format(user, pwd))
c.setopt(c.WRITEFUNCTION, response.write)
c.setopt(c.HTTPHEADER, ['Content-Type: audio/flac','Transfer-Encoding: chunked'])
c.setopt(c.POSTFIELDS, audiofile)
c.setopt(c.CAINFO,certifi.where())
c.perform()
c.close()
body = response.getvalue()
body = body.decode('iso-8859-1')
print(body)

Connect to API and send back a message with Flask app

I have a flask app deployed to Heroku and would like to receive text from Chatfuel (bot building platform) and send back texts in return.
Now, what I did is to use my heroku app as a web-hook, so that Chatfuel can make a simple GET or POST query to my API. The problem is that I have no experience with Flask or APIs, so I am not sure about how my app can receive information (in json format) and send it back to chatfuel.
This is what I wrote so far:
import os
import sys
import json
import requests
from flask import Flask, jsonify, render_template, request
app = Flask(__name__)
#app.route('/', methods=['GET'])
def verify():
# when the endpoint is registered as a webhook, it must echo back
# the 'hub.challenge' value it receives in the query arguments
if request.args.get("hub.mode") == "subscribe" and request.args.get("hub.challenge"):
if not request.args.get("hub.verify_token") == os.environ["VERIFY_TOKEN"]:
return "Verification token mismatch", 403
return request.args["hub.challenge"], 200
return "Hello world", 200
#app.route("/json", methods=['GET','POST'])
def json():
url = "chatfuel_api"
data = json.load(urllib2.urlopen(url))
if request.json:
mydata = request.json
return "Thanks",200
else:
return "no json received"
#app.route('/hello', methods = ['GET','POST'])
def api_echo():
if request.method == 'GET':
return "ECHO: GET\n",200
if __name__ == '__main__':
app.run(debug=True)
The verify() function works, as I see an 'Hello world' message if I run the app locally. However, both json() and api_echo() don't work, and when my server receives a get or post request from chatfuel, it returns a 404 error.
As you can see, I really have a lot of confusion, and your help would be really invaluable.
Thanks
You need to make sure you have registered the proper webhook url with Chatfuel. For the code you currently have, to hit the json endpoint the url would be https://www.your_server.com/json
The verify route looks like the hub challenge FB sends, so you would have to register the root of your site (that is, with your current code) with FB to hit the verify function. That url would look like this https://www.your_site.com/

Resources