I have a python Twilio code like this(Click to Call method in twilio):
from flask import Flask
from flask import jsonify
#from flask import render_template
#from flask import request
from flask import url_for
from twilio.twiml.voice_response import VoiceResponse
from twilio.rest import Client
app = Flask(__name__)
# Voice Request URL
#app.route('/call')
def call():
# Get phone number we need to call
phone_number = request.form.get('phoneNumber', None)
try:
twilio_client = Client(app.config['TWILIO_ACCOUNT_SID'],
app.config['TWILIO_AUTH_TOKEN'])
except Exception as e:
msg = 'Missing configuration variable: {0}'.format(e)
return jsonify({'error': msg})
try:
twilio_client.calls.create(from_=app.config['TWILIO_CALLER_ID'],
to=phone_number,
url=url_for('.outbound', _external=True))
except Exception as e:
app.logger.error(e)
return jsonify({'error': str(e)})
return jsonify({'message': 'Call incoming!'})
#app.route('/outbound', methods=['POST'])
def outbound():
response = VoiceResponse()
response.say("Thank you for contacting our sales department. If this "
"click to call application was in production, we would "
"dial out to your sales team with the Dial verb.",
voice='alice')
response.number("+16518675309")
return str(response)
if __name__ == '__main__':
app.run()
When i try run run this from browser by calling : http://localhost:5000/call
i am getting ERROR: Unable to create record: Url is not a valid url:
How to call the Outbound function in the url and start the conversation between two people.
Instead of url_for('.outbound', _external=True) you should use url_for('outbound'). The docs linked by stamaimer say:
In case blueprints are active you can shortcut references to the same blueprint by prefixing the local endpoint with a dot (.).
You do not need a dot at the beginning. Check how url building is handled in flask.
Related
I am running python and flask, when it starts to run I encounter this error message image of error message I have looked at other forums of people encoutering the same error to no avail
#here is the code
'''
from flask import Flask, request, url_for, session, redirect
import spotipy
from spotipy.oauth2 import SpotifyOAuth
app = Flask(__name__)
app.secret_key = ""
app.config['SESSION_COOKIE_NAME'] = 'Spotify cookie'
#app.route('/')
def login():
sp_oauth = create_spotify_oauth()
auth_url = sp_oauth.get_authorize_url()
return redirect(auth_url)
#app.route('/redirect')
def redirectPage():
return 'redirect'
#app.route('/getTracks')
def getTracks():
return 'PAIN'
def create_spotify_oauth():
return SpotifyOAuth(
client_id="",
client_secret="",
redirect_uri=url_for('redirectPage', _external=True),
scope="user-library-read")
i have added the redirect URIs to the settings in spotify for developers
image of redirect URIs added, I have pressed save
i am expecting this to pop up image of spotify Oauth pop up
Looks like you have a typo in the Redirect URI, in the one being sent to Spotify it is
http://127.0.0.1:5000/redirect
Note the spelling of redirect, from the Screenshot from the Spotify Dashboard this is "redierect" and also the lack of a forward slash on the one being passed to Spotify as this has to match exactly also so you just need to add that URI to the Spotify Dashboard as is as the URL needs to be exactly correct for it not to show that error for the Invalid Redirect URI so add this one to see if it works
http://127.0.0.1:5000/redirect
I am working on a simple service with my show_greeting endpoint handling Get request while set_greeting is my Post.
The purpose of this app is that when "header_message: {header parameter}" is sent to set_greeting, {header parameter} will be returned in the header for responses to show_greeting and to reset {header parameter}, "clear" would reset header_message and header.
I have tried using global variables but encountered an error with shadowing from outside the scope and am not sure which approach to take for this. For now, I would like to learn how to return {header parameter} from my /show_greeting endpoint.
Edit: The /show_greeting endpoint returns holiday_message from the request. The header that I would like to send in addition to holiday_message is "header_message".
My code is as follows:
from flask import Flask, request, make_response, Response
app = Flask(__name__)
#app.route('/show_greeting', methods=['GET'])
def show_greeting():
received = request.args
(I do not know how to set header here from header_message in set_greeting)
return received['holiday_message']
#app.route('/set_greeting', methods=['POST'])
def set_greeting():
posted = request.args
if 'header_message' in posted:
(I attempted save_message = posted['header_message'] here but this approach failed)
return "Header Message Set"
else:
return "Please Send A Header Message"
if __name__ == '__main__':
app.run()
My recommendation is to use the session object. It stores the data in a cookie, which is sent with every request.
If a cookie is not desired, there are other options for saving sessions. For this, however, an extension will be necessary.
Saving with global variables should also work, but is not recommended.
A file or a database can also be used if the data is to be saved across multiple requests from many users.
The data of the post body can be accessed via request.form, while the url parameters of a get request can be queried via request.args.
from flask import Flask
from flask import request, session
app = Flask(__name__)
app.secret_key = b'your secret here'
#app.route('/show_greeting', methods=['GET'])
def show_greeting():
received = request.args
# get the saved message or an empty string if no message is saved
header_message = session.get('header_message', '')
return f"{received['holiday_message']} - {header_message}"
#app.route('/set_greeting', methods=['POST'])
def set_greeting():
posted = request.form
if 'header_message' in posted:
# store the message
session['header_message'] = posted['header_message']
return "Header Message Set"
else:
# clear the message
session.pop('header_message', None)
return "Please Send A Header Message"
Much success in your further steps.
If I understood your problem, you can work with "g" the flask global object.
Check this code, I expect it will fix your issue.
from flask import g # Added
from flask import Flask, request, make_response, Response
app = Flask(__name__)
#app.route('/show_greeting', methods=['GET'])
def show_greeting():
received = request.args
return g.saved_message # Modified
#app.route('/set_greeting', methods=['POST'])
def set_greeting():
posted = request.args
if 'message' in posted:
g.saved_message = posted['request'] # Added
return "Message Set"
else:
return "Please Send A Greeting Message"
if __name__ == '__main__':
app.run()
I am trying to generate a swagger documentation for the API I am building in flask however when I execute below code I get very staring error, What I am missing here ?
This is what I have tried :
try:
from flask import Flask, g, request
from flask_restful import Resource, Api
from flask_limiter.util import get_remote_address
from flask_limiter import Limiter
from flasgger import Swagger
from flasgger.utils import swag_from
from flask_restful_swagger import swagger
from flask_httpauth import HTTPTokenAuth
import os
import json
except Exception as e:
print("some modules are missing {}".format(e))
app = Flask(__name__)
api = Api(app)
limiter = Limiter(app, key_func=get_remote_address)
limiter.init_app(app)
api = swagger.docs(Api(app), apiVersion='0.1', api_spec_url='/doc')
auth = HTTPTokenAuth(scheme='Token')
tokens = {
'awserftggyjkk34)ghtyrjrhhye34nnmw': 'cadmin',
'bwsosjhee(dhj345gtyuioplsertbsjkl': 'dadmin',
'mnchthas(sjklertyusvfgmbshdls234h': 'eadmin'
}
#auth.verify_token
def verify_token(token):
if token in tokens:
g.current_user = tokens[token]
return True
return False
class defr(Resource):
decorators = [limiter.limit("100/day")]
#swagger.model
#swagger.operation(notes='my notes ntes')
#auth.login_required
def currentuser(self):
return "Hello, %s!" % g.current_user
api.add_resource(defr, '/user')
error :
File "C:\Users\codamd\AppData\Local\Continuum\anaconda3\lib\site-packages\flask_restful_swagger\swagger.py", line 294, in extract_operations
for method in [m.lower() for m in resource.methods]:
TypeError: 'NoneType' object is not iterable
Any help would be great
The problem here is that you've used a custom named method in your defr class. The Flask-RESTful documentation specifies defining HTTP methods in your Resource class e.g.
class defr(Resource):
decorators = [limiter.limit("100/day")]
#swagger.model
#swagger.operation(notes='my notes ntes')
#auth.login_required
def get(self):
return "Hello, %s!" % g.current_user
So this is my code.
from flask import Flask, request
from flask_restful import Resource, Api
app = Flask(__name__)
app.config['DEBUG'] = True
api = Api(app)
# Make the WSGI interface available at the top level so wfastcgi can get it.
wsgi_app = app.wsgi_app
class Default(Resource):
def get(self, name):
"""Renders a sample page."""
return "Hello " + name
class LiveStats(Resource):
def get(self, url):
return "Trying to get " + url
# data = request.get(url)
# return data
api.add_resource(Default, '/default/<string:name>') # Route_1
api.add_resource(LiveStats, '/liveStats/<path:url>') # Route_2
if __name__ == '__main__':
import os
HOST = os.environ.get('SERVER_HOST', 'localhost')
try:
PORT = int(os.environ.get('SERVER_PORT', '5555'))
except ValueError:
PORT = 5555
app.run(HOST, PORT)
Now firstly this post helped a lot. how-to-pass-urls-as-parameters-in-a-get-request-within-python-flask-restplus
Changing what I originally had.
api.add_resource(LiveStats, '/liveStats/<string:url>') # Route_2
to this
api.add_resource(LiveStats, '/liveStats/<path:url>') # Route_2
got rid of 404 errors that I had but now I am noticing that it's not passing all of the url.
Example if I try this
localhost:60933/liveStats/http://address/Statistics?NoLogo=1%26KSLive=1
I get this
Trying to get http://address/Statistics
so it has taken off ?NoLogo=1%26KSLive=1
How do you prevent this?
All characters after the ? are considered parameters. From the docs:
To access parameters submitted in the URL (?key=value) you can use the args attribute:
searchword = request.args.get('key', '')
We recommend accessing URL
parameters with get or by catching the KeyError because users might
change the URL and presenting them a 400 bad request page in that case
is not user friendly.
For a full list of methods and attributes of the request object, head
over to the Request documentation.
Maybe you could encode the query string in a way that you can retrieve it as a single parameter on the back end, but not sure it would be useful.
If you don't want to access the args individually, you can access the full query string:
request.query_string
Putting this all together I think this will work for you:
class LiveStats(Resource):
def get(self, url):
return "Trying to get " + url + request.query_string
I am using Flask-dance in order to authenticate users to my app. The auth provider is Google.
From time to time the following exception is raised:
2019-08-09 08:07:26 default[20190809t105407] "GET / HTTP/1.1" 500
2019-08-09 08:07:26 default[20190809t105407] -- 0 --
2019-08-09 08:07:26 default[20190809t105407] -- 1 --
2019-08-09 08:07:27 default[20190809t105407] InvalidClientIdError was caught: (invalid_request) Missing required parameter: refresh_token
Looking around this problem I could find 2 directions to go with:
Use offline=True while creating the Google blueprint
Implementing error handler for TokenExpiredError
I did both and deployed my app to GAE but I still face the same error. From the stacktrace I understand that the error handler is being invoked but while the code tries to recover the 'refresh_token' is raised
My code: (The code is based on Google QuickStart and Flask-dance issue 143)
import oauthlib
from flask import Flask, redirect, url_for, flash, session, current_app
from flask_dance.contrib.google import make_google_blueprint, google
import os
import time
from oauthlib.oauth2.rfc6749.errors import InvalidClientIdError, TokenExpiredError
GOOGLE_CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID", None)
GOOGLE_CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET", None)
app = Flask(__name__)
app.secret_key = "TODO_TODO"
blueprint = make_google_blueprint(
client_id=GOOGLE_CLIENT_ID,
client_secret=GOOGLE_CLIENT_SECRET,
offline=True
)
app.register_blueprint(blueprint, url_prefix="/login")
#app.route('/logout', methods=['GET'])
def logout():
_revoke_token_and_empty_session()
return redirect(url_for('app.index'))
def _revoke_token_and_empty_session():
print('inside _revoke_token_and_empty_session')
if google.authorized:
try:
google.get(
'https://accounts.google.com/o/oauth2/revoke',
params={
'token':
current_app.blueprints['google'].token['access_token']},
)
except TokenExpiredError:
pass
except InvalidClientIdError:
# Our OAuth session apparently expired. We could renew the token
# and logout again but that seems a bit silly, so for now fake
# it.
pass
session.clear()
#app.errorhandler(oauthlib.oauth2.rfc6749.errors.TokenExpiredError)
def token_expired(_):
print('In TokenExpiredError')
del blueprint.token
_revoke_token_and_empty_session()
flash('Your session had expired. Please submit the request again',
'error')
return redirect(url_for('app.index'))
#app.route("/")
def index():
print('-- 0 --')
if not google.authorized:
return redirect(url_for("google.login"))
print('-- 1 --')
user_info_url = 'https://openidconnect.googleapis.com/v1/userinfo'
try:
resp = google.get(user_info_url)
except InvalidClientIdError as e:
#
# Here is the problem
#
print('InvalidClientIdError was caught: {}'.format(str(e)))
return 'Having an InvalidClientIdError issue: {}'.format(str(e)), 500
else:
print('-- 2 --')
user_info = resp.json()
return "You are {user_name} on Google. Time: {t}".format(user_name=user_info['name'], t=time.time())
if __name__ == "__main__":
app.run()
My current understanding is that the TokenExpiredError was caught and the function index was called. When the function tries to call resp = google.get(user_info_url) the InvalidClientIdError: (invalid_request) Missing required parameter: refresh_token is raised.
Any idea how to solve it?
From your code, and flask code, looks like you are trying to delete the token before revoking it, even though it's already invalid. If you want to avoid passing "offline=True" then try to simplify the code since there is no need to flash anything (the user will be redirected), and the token is already invalid, so it doesn't make much sense to revoke it either. I'm also setting only one error handler.
Here is the code that worked for me:
import oauthlib
from flask import Flask, redirect, url_for, flash, session, current_app
from flask_dance.contrib.google import make_google_blueprint, google
import os
import time
from oauthlib.oauth2.rfc6749.errors import InvalidClientIdError, TokenExpiredError
GOOGLE_CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID", None)
GOOGLE_CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET", None)
app = Flask(__name__)
app.secret_key = "TODO_TODO"
blueprint = make_google_blueprint(
client_id=GOOGLE_CLIENT_ID,
client_secret=GOOGLE_CLIENT_SECRET,
offline=True
)
app.register_blueprint(blueprint, url_prefix="/login")
#app.route('/logout', methods=['GET'])
def logout():
"""
This endpoint tries to revoke the token
and then it clears the session
"""
if google.authorized:
try:
google.get(
'https://accounts.google.com/o/oauth2/revoke',
params={
'token':
current_app.blueprints['google'].token['access_token']},
)
except TokenExpiredError:
pass
except InvalidClientIdError:
# Our OAuth session apparently expired. We could renew the token
# and logout again but that seems a bit silly, so for now fake
# it.
pass
_empty_session()
return redirect(url_for('app.index'))
def _empty_session():
"""
Deletes the google token and clears the session
"""
if 'google' in current_app.blueprints and hasattr(current_app.blueprints['google'], 'token'):
del current_app.blueprints['google'].token
session.clear()
#app.errorhandler(oauthlib.oauth2.rfc6749.errors.TokenExpiredError)
#app.errorhandler(oauthlib.oauth2.rfc6749.errors.InvalidClientIdError)
def token_expired(_):
_empty_session()
return redirect(url_for('app.index'))
#app.route("/")
def index():
print('-- 0 --')
if not google.authorized:
return redirect(url_for("google.login"))
print('-- 1 --')
user_info_url = 'https://openidconnect.googleapis.com/v1/userinfo'
resp = google.get(user_info_url)
user_info = resp.json()
return "You are {user_name} on Google. Time: {t}".format(user_name=user_info['name'], t=time.time())
if __name__ == "__main__":
app.run()