Twilio not working - after connecting with Database [on pythonanywhere] - python

Hi I want to create a chatbot to gather user's information and store user inputs in MySQL database. I followed this tutorial and everything worked but after implementing database connection, I couldn't access it via Twilio SMS. I can still check the chatbot flow from dialogflow but twilio is not responding. Here is the code.. it was big so couldn't share the whole webhook function. Please tell me how to connect with database.. seems like dialogflow inbuilt chatbot is working fine but my main motive is to work from Twilio SMS. How to establish that?
P.s. before database connection, it was working fine just like in the tutorial.
import json
import apiai
import os
from flask import Flask
from twilio.rest import Client
from twilio.http.http_client import TwilioHttpClient
from flask import request, make_response, jsonify
# Twilio account info
account_sid = "_####__"
auth_token = "_###__"
account_num = "+_###__"
proxy_client = TwilioHttpClient()
proxy_client.session.proxies = {'https': os.environ['https_proxy']}
client = Client(account_sid, auth_token, http_client=proxy_client)
# api.ai account info
CLIENT_ACCESS_TOKEN = "_###__"
ai = apiai.ApiAI(CLIENT_ACCESS_TOKEN)
app = Flask(__name__)
# ---database handling starts-----
# create a MySQL client connecting to your MySQL server
import mysql.connector
mydb = mysql.connector.connect(
host="---###---",
user="---###---",
passwd="---###---",
database="---###---"
)
mycursor = mydb.cursor()
# ----webhook method calling----
#app.route('/', methods=['POST'])
def webhook():
global counting_id
req = request.get_json(silent=True, force=True)
action = req.get('queryResult').get('action')
# WEBHOOK CODE
# return make_response(jsonify({"speech": res}))
#app.route('/hello')
def hello_world():
return 'Hello api.ai (from Flask!)'
#app.route("/", methods=['GET', 'POST'])
def server():
from flask import request
# get SMS metadata
msg_from = request.values.get("From", None)
msg = request.values.get("Body", None)
# print(msg)
# print('msg_from=', msg_from)
# prepare API.ai request
req = ai.text_request()
req.lang = 'en' # optional, default value equal 'en'
req.query = msg
# req.session_id = msg_from
# print(ai)
# print(req)
# get response from API.ai
api_response = req.getresponse()
responsestr = api_response.read().decode('utf-8')
response_obj = json.loads(responsestr)
reply="Hello [reply from flask]"
if 'result' in response_obj:
response = response_obj["result"]["fulfillment"]["speech"]
# send SMS response back via twilio
reply=client.messages.create(to=msg_from, from_= account_num, body=response)
return str(reply)
if __name__ == "__main__":
app.run(debug=True)

Related

When connecting it to my react frontend. I get spotipy invalid client. However example works just fine on backend host

Using the example for testing: https://github.com/spotipy-dev/spotipy/blob/master/examples/app.py
Trying to use a React frontend that gets the html from the backend ("http://127.0.0.1:8080", which is my callback).
When I try to request the data for it, I keep getting errors and undefined states. However when I just simply go to the callback redirect url and get data, it works perfectly What could be the issue? I set the necessary env variables
Here is my python and React code
React code:
Python:
import os
from flask import Flask, session, request, redirect
from flask_cors import CORS, cross_origin
from flask_session import Session
import spotipy
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(64)
app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_FILE_DIR'] = './.flask_session/'
CORS(app)
Session(app)
client_id = os.getenv("SPOTIPY_CLIENT_ID")
client_secret = os.getenv("SPOTIPY_CLIENT_SECRET")
redirect_uri = os.getenv("SPOTIPY_REDIRECT_URI")
#app.route('/')
def index():
cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
auth_manager = spotipy.oauth2.SpotifyOAuth(scope='user-read-currently-playing playlist-modify-private',
cache_handler=cache_handler,
show_dialog=True)
if request.args.get("code"):
# Step 2. Being redirected from Spotify auth page
auth_manager.get_access_token(request.args.get("code"))
return redirect('/')
if not auth_manager.validate_token(cache_handler.get_cached_token()):
# Step 1. Display sign in link when no token
auth_url = auth_manager.get_authorize_url()
return f'<h2>Sign in</h2>'
# Step 3. Signed in, display data
spotify = spotipy.Spotify(auth_manager=auth_manager)
return f'<small><a href="/sign_out">[sign out]<a/></small></h2>' \
f'my playlists | ' \
f'currently playing | ' \
f'me' \
#app.route('/sign_out')
def sign_out():
session.pop("token_info", None)
return redirect('/')
#app.route('/playlists')
def playlists():
cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler)
if not auth_manager.validate_token(cache_handler.get_cached_token()):
return redirect('/')
spotify = spotipy.Spotify(auth_manager=auth_manager)
return spotify.current_user_playlists()
#app.route('/currently_playing')
def currently_playing():
cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler)
if not auth_manager.validate_token(cache_handler.get_cached_token()):
return redirect('/')
spotify = spotipy.Spotify(auth_manager=auth_manager)
track = spotify.current_user_playing_track()
if not track is None:
return track
return "No track currently playing."
#app.route('/current_user')
def current_user():
cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler)
if not auth_manager.validate_token(cache_handler.get_cached_token()):
return redirect('/')
spotify = spotipy.Spotify(auth_manager=auth_manager)
return spotify.current_user()
'''
Following lines allow application to be run more conveniently with
`python app.py` (Make sure you're using python3)
(Also includes directive to leverage pythons threading capacity.)
'''
if __name__ == '__main__':
app.run(threaded=True, port=int(os.environ.get("PORT",
os.environ.get("SPOTIPY_REDIRECT_URI", "8080").split(":")[-1])))

Twitter Account Activity API - 'code': 214, 'message': 'Non-200 response code during CRC GET request (i.e. 404, 500, etc).'

I was using a sample app, that manages Tweeter Account Activity API, here's the link:
https://github.com/RickRedSix/twitter-webhook-boilerplate-python/blob/master/Main.py
I built my web app in pythonanywhere.com and I keep getting this:
{error : {'code': 214, 'message': 'Non-200 response code during CRC GET request (i.e. 404, 500, etc).'}}
In my wsgi configuration the code goes as follows
# This file contains the WSGI configuration required to serve up your
# web application at http://<your-username>.pythonanywhere.com/
# It works by setting the variable 'application' to a WSGI handler of some
# description.
#
# The below has been auto-generated for your Flask project
import sys
# add your project directory to the sys.path
project_home = '/home/YouMatterBot2/mysite'
if project_home not in sys.path:
sys.path = [project_home] + sys.path
# import flask app but need to call it "application" for WSGI to work
from flask_app import app as application # noqa
Here's the code in the flask_app.py:
#!/usr/bin/env python
from flask import Flask, request, send_from_directory, make_response
from http import HTTPStatus
import Twitter, hashlib, hmac, base64, os, logging, json
from dotenv import load_dotenv
load_dotenv('.env')
CONSUMER_SECRET = os.getenv('CONSUMER_SECRET')
CURRENT_USER_ID = os.getenv('CURRENT_USER_ID')
app = Flask(__name__)
#generic index route
#app.route('/')
def default_route():
return send_from_directory('www', 'index.html')
#The GET method for webhook should be used for the CRC check
#TODO: add header validation (compare_digest https://docs.python.org/3.6/library/hmac.html)
#app.route("/webhook", methods=["GET"])
def twitterCrcValidation():
crc = request.args['crc_token']
validation = hmac.new(
key=bytes(CONSUMER_SECRET, 'utf-8'),
msg=bytes(crc, 'utf-8'),
digestmod = hashlib.sha256
)
digested = base64.b64encode(validation.digest())
response = {
'response_token': 'sha256=' + format(str(digested)[2:-1])
}
print('responding to CRC call')
return json.dumps(response)
#The POST method for webhook should be used for all other API events
#TODO: add event-specific behaviours beyond Direct Message and Like
#app.route("/webhook", methods=["POST"])
def twitterEventReceived():
requestJson = request.get_json()
#dump to console for debugging purposes
print(json.dumps(requestJson, indent=4, sort_keys=True))
if 'favorite_events' in requestJson.keys():
#Tweet Favourite Event, process that
likeObject = requestJson['favorite_events'][0]
userId = likeObject.get('user', {}).get('id')
#event is from myself so ignore (Favourite event fires when you send a DM too)
if userId == CURRENT_USER_ID:
return ('', HTTPStatus.OK)
Twitter.processLikeEvent(likeObject)
elif 'direct_message_events' in requestJson.keys():
#DM recieved, process that
eventType = requestJson['direct_message_events'][0].get("type")
messageObject = requestJson['direct_message_events'][0].get('message_create', {})
messageSenderId = messageObject.get('sender_id')
#event type isnt new message so ignore
if eventType != 'message_create':
return ('', HTTPStatus.OK)
#message is from myself so ignore (Message create fires when you send a DM too)
if messageSenderId == CURRENT_USER_ID:
return ('', HTTPStatus.OK)
Twitter.processDirectMessageEvent(messageObject)
else:
#Event type not supported
return ('', HTTPStatus.OK)
return ('', HTTPStatus.OK)
if __name__ == '__main__':
# Bind to PORT if defined, otherwise default to 65010.
port = int(os.environ.get('PORT', 65010))
gunicorn_logger = logging.getLogger('gunicorn.error')
app.logger.handlers = gunicorn_logger.handlers
app.logger.setLevel(gunicorn_logger.level)
app.run(host='0.0.0.0', port=port, debug=True)
but when I run the this code to register my webhook
from TwitterAPI import TwitterAPI
import os
from dotenv import load_dotenv
load_dotenv('.env')
CONSUMER_KEY = os.getenv('CONSUMER_KEY')
CONSUMER_SECRET = os.getenv('CONSUMER_SECRET')
ACCESS_TOKEN = os.getenv('ACCESS_TOKEN')
ACCESS_TOKEN_SECRET = os.getenv('ACCESS_TOKEN_SECRET')
#The environment name for the beta is filled below. Will need changing in future
ENVNAME = os.getenv('ENVNAME')
WEBHOOK_URL = os.getenv('WEBHOOK_URL')
twitterAPI = TwitterAPI(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
r = twitterAPI.request('account_activity/all/:%s/webhooks' % ENVNAME, {'url': WEBHOOK_URL})
print (r.status_code)
print(r.json())
print (r.text)
I get the said error.
Is this a problem because of pythonanywhere.com, if so how can I fix it?

Python how to obtain ID_Token to use with Open ID Connect from using account authentication with oauthlib

Right now I can obtain an access token using requests_oauthlib and a scope. However I'd like to be able to get the full ID_Token and was wondering if it was possible with the way I'm doing things.
import flask
import requests_oauthlib
import os
import requests
CLIENT_ID = "ClientIDKEY"
CLIENT_SECRET = "CLIENTSECRETKEY"
redirect_uri = "http://localhost:5000/callback"
AUTHORIZATION_BASE_URL = "https://accounts.google.com/o/oauth2/auth"
TOKEN_URL = "https://oauth2.googleapis.com/token"
USERINFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json"
SCOPE_URL = "https://www.googleapis.com/auth/userinfo.profile"
# This allows us to use a plain HTTP callback
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"
app = flask.Flask(__name__)
#app.route("/")
def index():
return """
Login with Google
"""
#app.route("/login")
def login():
simplelogin = requests_oauthlib.OAuth2Session(
CLIENT_ID, redirect_uri=redirect_uri, scope=SCOPE_URL
)
authorization_url, _ = simplelogin.authorization_url(AUTHORIZATION_BASE_URL)
return flask.redirect(authorization_url)
#app.route("/callback")
def callback():
simplelogin = requests_oauthlib.OAuth2Session(CLIENT_ID, redirect_uri=redirect_uri)
simplelogin.fetch_token(
TOKEN_URL, client_secret=CLIENT_SECRET, authorization_response=flask.request.url
)
URL = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=" + str(simplelogin.access_token)
req = requests.get(url = URL)
print(req.json)
return f"""
Ok
"""
if __name__ == "__main__":
app.run(host="localhost", debug=True)
I'd like to either obtain the ID token when authenticating instead of the Access Token, or simply use the Access Token from the authentication to obtain the ID_Token.
The final result here, not in the scope of this question, is to use the jwt token and validate it with cloud endpoints, so they can be used on a REST api on the backend.
So I managed to do it with python 2.7 (since for some reason they just decided to use 2.7) but the concept is the same.
In the SCOPE_URL I passed ["openid"], which made the request return and ID_Token. I then used that ID_Token and made a call such as:
AUTHORIZATION_BASE_URL = "https://accounts.google.com/o/oauth2/auth"
TOKEN_URL = "https://oauth2.googleapis.com/token"
USERINFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json"
SCOPE_URL = ["openid"]
(...)
#app.route("/callback")
def callback():
simplelogin = requests_oauthlib.OAuth2Session(CLIENT_ID, redirect_uri=redirect_uri)
simplelogin.fetch_token(
TOKEN_URL, client_secret=CLIENT_SECRET, authorization_response=flask.request.url
)
ID_Token = simplelogin.token.get('id_token')
URL = "https://oauth2.googleapis.com/tokeninfo?id_token=" + str(ID_Token)
req = requests.get(url=URL)
print(req.content)
return """
Ok
"""

Storing Spotify token in flask session using spotipy?

I may have a bad understanding of how the flask session works, but I am trying to generate a Spotify API access token using SpotiPY with the Authorization Code Flow, and store it in Flask's session storage.
The program doesn't seem to be able to store it, and therefore later runs in to an error when trying to call it. Here is a visual explanation with images and captions: https://imgur.com/a/KiYZFiQ
Here is the main server script:
from flask import Flask, render_template, redirect, request, session, make_response,session,redirect
import spotipy
import spotipy.util as util
from credentz import *
app = Flask(__name__)
app.secret_key = SSK
#app.route("/")
def verify():
session.clear()
session['toke'] = util.prompt_for_user_token("", scope='playlist-modify-private,playlist-modify-public,user-top-read', client_id=CLI_ID, client_secret=CLI_SEC, redirect_uri="http://127.0.0.1:5000/index")
return redirect("/index")
#app.route("/index")
def index():
return render_template("index.html")
#app.route("/go", methods=['POST'])
def go():
data=request.form
sp = spotipy.Spotify(auth=session['toke'])
response = sp.current_user_top_artists(limit=data['num_tracks'], time_range=data['time_range'])
return render_template("results.html",data=data)
if __name__ == "__main__":
app.run(debug=True)
and here are the two html files: Index.html, Results.html
Some things worth noting:
Credentz stores all of the private info including SSK, CLI_SEC, and CLI_ID.
The spotipy request works fine if I do it in a non-flask environment with no web-browser interaction.
I am able to store other things in the session storage, and call it back later, just not the access token for some reason.
My best guess is that the page doesn't have time to store it before the Spotify api redirects the page, not sure though.
Any help is really appreciated, Thank You!
You are right, spotify is redirecting you before the token can be added therefore ending the execution of that function. So you need to add a callback step to grab the authentication token after you've been redirected.
Spotitpy's util.prompt_for_user_token method is not designed to be used in a web server so your best best is to implement the auth flow your self and then use spotipy once you have the token. Luckily the spotify authorization flow is pretty simple and easy to implement.
Method 1: Implementing auth flow our self:
from flask import Flask, render_template, redirect, request, session, make_response,session,redirect
import spotipy
import spotipy.util as util
from credentz import *
import requests
app = Flask(__name__)
app.secret_key = SSK
API_BASE = 'https://accounts.spotify.com'
# Make sure you add this to Redirect URIs in the setting of the application dashboard
REDIRECT_URI = "http://127.0.0.1:5000/api_callback"
SCOPE = 'playlist-modify-private,playlist-modify-public,user-top-read'
# Set this to True for testing but you probably want it set to False in production.
SHOW_DIALOG = True
# authorization-code-flow Step 1. Have your application request authorization;
# the user logs in and authorizes access
#app.route("/")
def verify():
auth_url = f'{API_BASE}/authorize?client_id={CLI_ID}&response_type=code&redirect_uri={REDIRECT_URI}&scope={SCOPE}&show_dialog={SHOW_DIALOG}'
print(auth_url)
return redirect(auth_url)
#app.route("/index")
def index():
return render_template("index.html")
# authorization-code-flow Step 2.
# Have your application request refresh and access tokens;
# Spotify returns access and refresh tokens
#app.route("/api_callback")
def api_callback():
session.clear()
code = request.args.get('code')
auth_token_url = f"{API_BASE}/api/token"
res = requests.post(auth_token_url, data={
"grant_type":"authorization_code",
"code":code,
"redirect_uri":"http://127.0.0.1:5000/api_callback",
"client_id":CLI_ID,
"client_secret":CLI_SEC
})
res_body = res.json()
print(res.json())
session["toke"] = res_body.get("access_token")
return redirect("index")
# authorization-code-flow Step 3.
# Use the access token to access the Spotify Web API;
# Spotify returns requested data
#app.route("/go", methods=['POST'])
def go():
data = request.form
sp = spotipy.Spotify(auth=session['toke'])
response = sp.current_user_top_artists(limit=data['num_tracks'], time_range=data['time_range'])
return render_template("results.html", data=data)
if __name__ == "__main__":
app.run(debug=True)
On the other hand we can cheat a little bit and use the methods that spotipy itself is using in order to save us some code.
Method 2: Implementing auth flow (along with custom token management) using spotipy.oauth2.SpotifyOAuth method:
from flask import Flask, render_template, redirect, request, session, make_response,session,redirect
import spotipy
import spotipy.util as util
from credentz import *
import time
import json
app = Flask(__name__)
app.secret_key = SSK
API_BASE = 'https://accounts.spotify.com'
# Make sure you add this to Redirect URIs in the setting of the application dashboard
REDIRECT_URI = "http://127.0.0.1:5000/api_callback"
SCOPE = 'playlist-modify-private,playlist-modify-public,user-top-read'
# Set this to True for testing but you probaly want it set to False in production.
SHOW_DIALOG = True
# authorization-code-flow Step 1. Have your application request authorization;
# the user logs in and authorizes access
#app.route("/")
def verify():
# Don't reuse a SpotifyOAuth object because they store token info and you could leak user tokens if you reuse a SpotifyOAuth object
sp_oauth = spotipy.oauth2.SpotifyOAuth(client_id = CLI_ID, client_secret = CLI_SEC, redirect_uri = REDIRECT_URI, scope = SCOPE)
auth_url = sp_oauth.get_authorize_url()
print(auth_url)
return redirect(auth_url)
#app.route("/index")
def index():
return render_template("index.html")
# authorization-code-flow Step 2.
# Have your application request refresh and access tokens;
# Spotify returns access and refresh tokens
#app.route("/api_callback")
def api_callback():
# Don't reuse a SpotifyOAuth object because they store token info and you could leak user tokens if you reuse a SpotifyOAuth object
sp_oauth = spotipy.oauth2.SpotifyOAuth(client_id = CLI_ID, client_secret = CLI_SEC, redirect_uri = REDIRECT_URI, scope = SCOPE)
session.clear()
code = request.args.get('code')
token_info = sp_oauth.get_access_token(code)
# Saving the access token along with all other token related info
session["token_info"] = token_info
return redirect("index")
# authorization-code-flow Step 3.
# Use the access token to access the Spotify Web API;
# Spotify returns requested data
#app.route("/go", methods=['POST'])
def go():
session['token_info'], authorized = get_token(session)
session.modified = True
if not authorized:
return redirect('/')
data = request.form
sp = spotipy.Spotify(auth=session.get('token_info').get('access_token'))
response = sp.current_user_top_tracks(limit=data['num_tracks'], time_range=data['time_range'])
# print(json.dumps(response))
return render_template("results.html", data=data)
# Checks to see if token is valid and gets a new token if not
def get_token(session):
token_valid = False
token_info = session.get("token_info", {})
# Checking if the session already has a token stored
if not (session.get('token_info', False)):
token_valid = False
return token_info, token_valid
# Checking if token has expired
now = int(time.time())
is_token_expired = session.get('token_info').get('expires_at') - now < 60
# Refreshing token if it has expired
if (is_token_expired):
# Don't reuse a SpotifyOAuth object because they store token info and you could leak user tokens if you reuse a SpotifyOAuth object
sp_oauth = spotipy.oauth2.SpotifyOAuth(client_id = CLI_ID, client_secret = CLI_SEC, redirect_uri = REDIRECT_URI, scope = SCOPE)
token_info = sp_oauth.refresh_access_token(session.get('token_info').get('refresh_token'))
token_valid = True
return token_info, token_valid
if __name__ == "__main__":
app.run(debug=True)
Either method is equally valid in my opinion, just go with whichever method you find easier to understand.
Make sure that you update the authorized Redirect URIs in your spotify application dashboard.
See the spotify docs for more info: https://developer.spotify.com/documentation/general/guides/authorization-guide/#authorization-code-flow

OAuth Facebook Login doesn't work

I'm trying to develop a web app using Google App Engine.
The language i'm using is Python and i'm using the facebook-sdk (https://facebook-sdk.readthedocs.io/en/latest/).
I'm stuck at making the OAuth Facebook login works correctly.
Every single time I attempt to log in to my app using Facebook login i get the error
URL Blocked: This redirect failed because the redirect URI is not whitelisted in the app’s Client OAuth Settings. Make sure Client and Web OAuth Login are on and add all your app domains as Valid OAuth Redirect URIs.
You can see the screenshot of the error (in the original language) below
That are the settings of my Facebook app
That's the code of my app's RequestHandler which handle the login's requests
import facebook
import os
import webapp2
import urllib
from webapp2_extras import sessions
facebook_ID = 'xxxxxxxxxxx'
facebook_secret = 'xxxxxxxxxxxxxxxxxxxxxx'
facebook_graphUrl = 'https://graph.facebook.com/v2.8'
facebook_redirectUri = 'http://gold-circlet-160109.appspot.com/login/'
facebook_requestCode = 'https://www.facebook.com/v2.8/dialog/oauth?' +
urllib.urlencode(
{'client_id':facebook_ID,
'redirect_uri':facebook_redirectUri,
'scope':'public_profile, email, user_friends'})
def retrieve_access_token(code):
args = {'redirect_uri': facebook_redirectUri,
'client_id': facebook_ID,
'client_secret': facebook_secret,
'code': code}
access_token = urllib.urlopen(facebook_graphUrl + "/oauth/access_token?" + urllib.urlencode(args)).read()
access_token = urlparse.parse_qs(access_token)
return access_token['access_token'][0]
def get_graph_api(token):
if isinstance(token, dict):
return facebook.GraphAPI(token['access_token'])
else:
return facebook.GraphAPI(token)
class BaseHandler(webapp2.RequestHandler):
def dispatch(self):
self.session_store = sessions.get_store(request=self.request)
try:
webapp2.RequestHandler.dispatch(self)
finally:
self.session_store.save_sessions(self.response)
#webapp2.cached_property
def session(self):
return self.session_store.get_session()
class FBLogin(BaseHandler):
def get(self):
code = self.request.get('code')
if self.request.get("code"):
access_tk = retrieve_access_token(code)
facebookObject = get_graph_api(access_tk)
facebookObject = facebookObject.get_object('me')
self.session["ECommerceUser"] = dict(
idSocial = facebookObject['id'],
image='http://graph.facebook.com/'+facebookObject['id']+'/picture?type=square',
username=last_name[0] + " " + last_name[1],
loginMethod=loginMethod
)
self.redirect("/")
else:
self.redirect(facebook_requestCode)
I set the same redirect URI in the URL login request is set in the Facebook Login settings, as you can see from the code above (i followed this guide: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow)
Any suggestion?

Categories