I have the below code for app.py:
from flask import Flask
from flask_jwt import JWT, jwt_required, current_identity
from werkzeug.security import safe_str_cmp
class User(object):
def __init__(self, id, username, password):
self.id = id
self.username = username
self.password = password
def __str__(self):
return "User(id='%s')" % self.id
users = [
User(1, 'user1', 'abcxyz'),
User(2, 'user2', 'abcxyz'),
]
username_table = {u.username: u for u in users}
userid_table = {u.id: u for u in users}
def authenticate(username, password):
user = username_table.get(username, None)
if user and safe_str_cmp(user.password.encode('utf-8'), password.encode('utf-8')):
return user
def identity(payload):
user_id = payload['identity']
return userid_table.get(user_id, None)
app = Flask(__name__)
app.debug = True
app.config['SECRET_KEY'] = 'super-secret'
jwt = JWT(app, authenticate, identity)
#app.route('/protected')
#jwt_required()
def protected():
return '%s' % current_identity
if __name__ == '__main__':
app.run()
When i try to make a post request to get the authentication token from Postman :
http://127.0.0.1:5000/auth
{
"username": "joe",
"password": "pass"
}
I get a peculiar error which i am not able to solve :
(flask-restful) C:\Users\bhatsubh\Projects\flask-restful>python Test.py
* Restarting with stat
* Debugger is active!
* Debugger PIN: 973-755-004
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [06/Sep/2017 13:38:08] "POST /auth HTTP/1.1" 500 -
Traceback (most recent call last):
File "C:\Users\bhatsubh\Envs\flask-restful\lib\site-packages\flask\app.py", li
ne 1997, in __call__
return self.wsgi_app(environ, start_response)
File "C:\Users\bhatsubh\Envs\flask-restful\lib\site-packages\flask\app.py", li
ne 1985, in wsgi_app
response = self.handle_exception(e)
File "C:\Users\bhatsubh\Envs\flask-restful\lib\site-packages\flask\app.py", li
ne 1540, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\bhatsubh\Envs\flask-restful\lib\site-packages\flask\_compat.py"
, line 33, in reraise
raise value
File "C:\Users\bhatsubh\Envs\flask-restful\lib\site-packages\flask\app.py", li
ne 1982, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\bhatsubh\Envs\flask-restful\lib\site-packages\flask\app.py", li
ne 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\bhatsubh\Envs\flask-restful\lib\site-packages\flask\app.py", li
ne 1517, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\bhatsubh\Envs\flask-restful\lib\site-packages\flask\_compat.py"
, line 33, in reraise
raise value
File "C:\Users\bhatsubh\Envs\flask-restful\lib\site-packages\flask\app.py", li
ne 1612, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\bhatsubh\Envs\flask-restful\lib\site-packages\flask\app.py", li
ne 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\bhatsubh\Envs\flask-restful\lib\site-packages\flask_jwt\__init_
_.py", line 115, in _default_auth_request_handler
username = data.get(current_app.config.get('JWT_AUTH_USERNAME_KEY'), None)
AttributeError: 'NoneType' object has no attribute 'get'
I have absolutely no idea what is going wrong. Can someone please help me with this?
make sure have set correct header
Content-Type:application/json
try curl for cross check
$ curl -H "Content-Type: application/json" -X POST -d '{ "username": "joe", "password": "pass" }' http://localhost:5000/auth
I suspect you’re being thrown off by this because there’s a bug in flask-jwt which is throwing up errors rather than providing proper feedback. So it’s hard to know what’s up.
If there are any header errors, it triggers errors rather than a proper response.
Dave B’s suggestion worked for me, setting the header with: Content-Type:application/json
I raised this with the developers, so hopefully, they can patch it up.
Look at https://github.com/vimalloc/flask-jwt-extended or https://github.com/vimalloc/flask-jwt-simple as alternatives to Flask-JWT. They are better designed, up to date, and still maintained (I am the author, so I am of course biased).
try this:
localhost:5000/auth
{ "username": "user1", "password": "abcxyz" }
Related
I have a python (flask) application that when I curl it using following command:
Request:
curl -X POST "localhost:8090/endp/" -H "Content-Type: application/json" -d #jsonExample
JsonEquals file includes:
{"idSeq":"0123","timeStamp":"15032019","source":"US","destination":"GB","content":"parcel"}
Response: Note: It will return two NEW fields which is as expected!
{
"idSeq": "0123",
"routeInfo": "Good",
"content": "parcel",
"Notes": "Send fine "
}
But when I run my python unittest using command: python myTest.py
import os, sys
import json
import main
import unittest
class PublicTestCase(unittest.TestCase):
def setUp(self):
self.app = main.app.test_client()
def my_first_test(self):
headers = {
'Content-Type': 'application/json'
}
data = {
"idSeq": "0123",
"timeStamp": "15032019",
"source": "US",
"destination": "GB",
"content": "parcel"
}
response = self.app.post('/endp',
headers=headers,
data=json.dumps(data),
follow_redirects=True)
print("+++++++++++++++++++++++++++++++++++")
print(data)
print("+++++++++++++++++++++++++++++++++++")
print(response)
assert response.status_code == 200
if __name__ == '__main__':
unittest.main()
I then get the following error:
[2020-03-05 14:00:08,093] ERROR in app: Exception on /endp/ [POST]
Traceback (most recent call last):
File "/home/ubuntu/venvs/inference/lib/python3.6/site-packages/flask/app.py", line 2446, in wsgi_app
response = self.full_dispatch_request()
File "/home/ubuntu/venvs/inference/lib/python3.6/site-packages/flask/app.py", line 1951, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/ubuntu/venvs/inference/lib/python3.6/site-packages/flask/app.py", line 1820, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/ubuntu/venvs/inference/lib/python3.6/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/home/ubuntu/venvs/inference/lib/python3.6/site-packages/flask/app.py", line 1949, in full_dispatch_request
rv = self.dispatch_request()
File "/home/ubuntu/venvs/inference/lib/python3.6/site-packages/flask/app.py", line 1935, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "../src/main.py", line 72, in mypostmethod
content = req_data['content']
TypeError: 'NoneType' object is not subscriptable
+++++++++++++++++++++++++++++++++++
{'idSeq': '0123', 'timeStamp': '15032019', 'source': 'US', 'destination': 'GB', 'content': 'parcel'}
+++++++++++++++++++++++++++++++++++
<Response streamed [500 INTERNAL SERVER ERROR]>
F
======================================================================
FAIL: my_first_test (__main__.PublicTestCase)
Any idea what I am doing wrong? Apologies if something similar was asked before but I checked and could not find a relevant answer to what I am doing with python FLASK!
main.py
#app.route("/endp/", methods=['POST'])
def mypostmethod():
req_data = request.get_json()
content = req_data['content']
timeStamp = req_data['timeStamp']
idSeq = req_data['idSeq']
...
...
I am developing a Web Service using python that would operate as the backend logic for a custom Alexa Skill. I am using the flask, flask-ask(Alexa Skill Kit), and MySQL extensions to develop this Web Service.
This Alexa Skill would allow users to reserve parking spots, check if lots are full, and find parking spots.
I also have a local database where all parking related information is stored.
I'm having an issue where I am only able to return the first result of a query.
Here is the code for one of my intents:
'''This is a Web Service for the *** Parking skill'''
author__ = '*****'
import logging
from flaskext.mysql import MySQL
from flask import Flask, render_template
from flask_ask import Ask, statement, question
mysql = MySQL()
app = Flask(__name__)
app.config.from_object(__name__)
app.config['MYSQL_DATABASE_USER'] = '*****'
app.config['MYSQL_DATABASE_PASSWORD'] = '*****'
app.config['MYSQL_DATABASE_DB'] = '*****'
app.config['MYSQL_DATABASE_HOST'] = '*****'
mysql.init_app(app)
ask = Ask(app, "/")
logging.getLogger("flask_ask").setLevel(logging.DEBUG)
#ask.intent('AvailableParking')
def available(occupancy):
#converts the inputted occupancy variable into all caps, to match the DB schema
occupancy = occupancy.upper()
#creates cursor variable that connects to DB
cursor = mysql.connect().cursor()
#connects to db and executes SQL query that displays all garages where the OCCUPANCY field matches the users slot input (OPEN OR CLOSED)
cursor.execute("SELECT GARAGE_NAME FROM GARAGES WHERE OCCUPANCY = %s", (occupancy,))
#returns the first row of the query results
data = cursor.fetchone()
data = data[0]
return statement(data)
This works as intended. Alexa says "Lot A" when triggering the intent, even thought there are 3 parking lots in total.
I thought to use the MySQL method cursor.fetchall() in place of cursor.fetchone, like so:
data = cursor.fetchall()
return statement(data)
But I receive the error:
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 2309, in __call__
return self.wsgi_app(environ, start_response)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 2295, in wsgi_app
response = self.handle_exception(e)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1741, in handle_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/usr/local/lib/python2.7/dist-packages/flask_ask/core.py", line 767, in _flask_view_func
result = self._map_intent_to_view_func(self.request.intent)()
File "/home/ngrok/ngrok/FETCHALLRETURN", line 46, in available
return statement(data)
File "/usr/local/lib/python2.7/dist-packages/flask_ask/models.py", line 188, in __init__
super(statement, self).__init__(speech)
File "/usr/local/lib/python2.7/dist-packages/flask_ask/models.py", line 51, in __init__
'outputSpeech': _output_speech(speech)
File "/usr/local/lib/python2.7/dist-packages/flask_ask/models.py", line 402, in _output_speech
xmldoc = ElementTree.fromstring(speech)
File "/usr/lib/python2.7/xml/etree/ElementTree.py", line 1311, in XML
parser.feed(text)
File "/usr/lib/python2.7/xml/etree/ElementTree.py", line 1651, in feed
self._parser.Parse(data, 0)
TypeError: Parse() argument 1 must be string or read-only buffer, not tuple
{"context": {"System": {"apiAccessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.eyJhdWQiOiJodHRwczovL2FwaS5hbWF6b25hbGV4YS5jb20iLCJpc3MiOiJBbGV4YVNraWxsS2l0Iiwic3ViIjoiYW16bjEuYXNrLnNraWxsLmY2NDViYTgxLTZmM2QtNDZlNi04MDM1LTI1MTBlYTg5ODNkYiIsImV4cCI6MTUzMTE1MzIxMiwiaWF0IjoxNTMxMTQ5NjEyLCJuYmYiOjE1MzExNDk2MTIsInByaXZhdGVDbGFpbXMiOnsiY29uc2VudFRva2VuIjpudWxsLCJkZXZpY2VJZCI6ImFtem4xLmFzay5kZXZpY2UuQUhFRzdPQ0RLN01TNkdFWkhYTUlTUlFXRkNNTktKVUxHTk1GTkdSVFlWSFk0WFZMSkVWUzRZTFFGSjVFSDVRR0YyREVYQTVVVjI0UzJHNFJNU0tYWFpHVjZFRDY0RktJWkpHVVQyWURVRlZZTzVLVUZLSENDUzVPWUdPTDI3NUU1QjRGRU1XTk5VRVAzUkxPSENFNzRUVTdLSDZBIiwidXNlcklkIjoiYW16bjEuYXNrLmFjY291bnQuQUg0T1FZSVBSQ1NRVEZaR1pIWkVRSFpCU1RISDI1VUE2MjYyNFY1WTdDWTdCSzZDWU9RWjdJN1BMV0s0Tzc0RFpVSzRBMkw0MlpQUjRQV1lFRlJIVzY2MlRPVlVEM1BCT1c0UkxRSjNFSFpVWllTTzM2VkM0NkMzRVdHT1ZPRFlVSVNWNzNPRVRHUkJEUkFTRjc0NEg3VFcyR0pYM01FN0kyWVNGQkFTNjNOUUFGNzNCVUJHUlRSSU5ZQ0tIM0dPWjZZVjNVS0tRM0xZMlFJIn19.WPKBopJc_WAxHJdHsYg6bgqYhEahsIzwCsBm3EUPWdKmqzSmjPTudJH-58a0VndsGc32CxARDhmShy1RxsSGUwacXr-Hb1sMlkHcrKV-I6dUFA9JXgGOHP92WyDBe4NcmZd2evEHGSAlWr7mW3cPpjUKax7INsSWqbziNGneP5DWV7T6FA6S3G-h5BBiX5rVx2SBcfYZ-1ixCom5GvQa8Xe77CGg2zwugd9oIvib6Q9JLfYQrmWcg9qBYfnKfaQsQNYg6I_OJ5fL5YcCmfq5FtfPpPL-k3UWvSiZwFqwch-AUNzu35csmLw9BF3JbVXPxPr-o70OlVWxmOeVEnYAzA", "apiEndpoint": "https://api.amazonalexa.com", "application": {"applicationId": "amzn1.ask.skill.f645ba81-6f3d-46e6-8035-2510ea8983db"}, "device": {"deviceId": "amzn1.ask.device.AHEG7OCDK7MS6GEZHXMISRQWFCMNKJULGNMFNGRTYVHY4XVLJEVS4YLQFJ5EH5QGF2DEXA5UV24S2G4RMSKXXZGV6ED64FKIZJGUT2YDUFVYO5KUFKHCCS5OYGOL275E5B4FEMWNNUEP3RLOHCE74TU7KH6A", "supportedInterfaces": {}}, "user": {"userId": "amzn1.ask.account.AH4OQYIPRCSQTFZGZHZEQHZBSTHH25UA62624V5Y7CY7BK6CYOQZ7I7PLWK4O74DZUK4A2L42ZPR4PWYEFRHW662TOVUD3PBOW4RLQJ3EHZUZYSO36VC46C3EWGOVODYUISV73OETGRBDRASF744H7TW2GJX3ME7I2YSFBAS63NQAF73BUBGRTRINYCKH3GOZ6YV3UKKQ3LY2QI"}}}, "request": {"error": {"message": "An exception occurred while dispatching the request to the skill.", "type": "INVALID_RESPONSE"}, "locale": "en-US", "reason": "ERROR", "requestId": "amzn1.echo-api.request.a7699e3a-71b3-4cf5-8d23-63e45c86a957", "timestamp": "2018-07-09T15:20:12Z", "type": "SessionEndedRequest"}, "session": {"application": {"applicationId": "amzn1.ask.skill.f645ba81-6f3d-46e6-8035-2510ea8983db"}, "new": false, "sessionId": "amzn1.echo-api.session.7c96f3f4-c78f-4c10-9535-9e1e9fe8a21e", "user": {"userId": "amzn1.ask.account.AH4OQYIPRCSQTFZGZHZEQHZBSTHH25UA62624V5Y7CY7BK6CYOQZ7I7PLWK4O74DZUK4A2L42ZPR4PWYEFRHW662TOVUD3PBOW4RLQJ3EHZUZYSO36VC46C3EWGOVODYUISV73OETGRBDRASF744H7TW2GJX3ME7I2YSFBAS63NQAF73BUBGRTRINYCKH3GOZ6YV3UKKQ3LY2QI"}}, "version": "1.0"}
{}
127.0.0.1 - - [09/Jul/2018 15:20:12] "POST / HTTP/1.1" 200 -
Query results are returned in a tuple which apparently is not able to be returned straight to Alexa without some formatting.
Does anyone know how I can return ALL results of a query to Alexa ?
I'm writing an app with same extensions as you except for sqlalchemy and using sqlite. My queries come back as objects so I either :
Have a method that loops through the query object to construct a statement for alexa (great for complex msg)
Pass the object to the flask-ask templates.yaml and use a jinja for loop (good for a simple query)
I am writing a script that uses Google's authenticated login. I am currently getting an access token and the user's email address and passing it to my function that connects to gmail using imap and then does some stuff with the emails. I'm generating the auth string like i've seen others do online however I am receiving this error:
Traceback (most recent call last):
File "/Library/Python/2.7/site-packages/flask/app.py", line 2000, in __call__
return self.wsgi_app(environ, start_response)
File "/Library/Python/2.7/site-packages/flask/app.py", line 1991, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/Library/Python/2.7/site-packages/flask/app.py", line 1567, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Library/Python/2.7/site-packages/flask/app.py", line 1988, in wsgi_app
response = self.full_dispatch_request()
File "/Library/Python/2.7/site-packages/flask/app.py", line 1641, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Library/Python/2.7/site-packages/flask/app.py", line 1544, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Library/Python/2.7/site-packages/flask/app.py", line 1639, in full_dispatch_request
rv = self.dispatch_request()
File "/Library/Python/2.7/site-packages/flask/app.py", line 1625, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/Harrison/Desktop/Uber/UberStats.py", line 60, in index
return Uber_Cost(email_address, access_token)
File "/Users/Harrison/Desktop/Uber/UberStats.py", line 103, in Uber_Cost
mail.authenticate('XOAUTH2', lambda x: auth_string)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/imaplib.py", line 364, in authenticate
raise self.error(dat[-1])
error: [AUTHENTICATIONFAILED] Invalid credentials (Failure)
I am printing out the access code as well as the email address that i'm logging in with, so I know those values aren't null. Am I generating the auth string wrong? Am I not authenticating with imap properly?
Here's my code:
from flask import Flask, request, url_for, session, redirect, jsonify
from flask_oauth import OAuth
import json
import imaplib
import email
from bs4 import BeautifulSoup
import base64
GOOGLE_CLIENT_ID = '****'
GOOGLE_CLIENT_SECRET = '***'
REDIRECT_URI = '/authorized' # one of the Redirect URIs from Google APIs console
SECRET_KEY = 'Uber'
DEBUG = True
app = Flask(__name__)
app.secret_key = 'Uber'
oauth = OAuth()
google = oauth.remote_app('google',
base_url='https://www.google.com/accounts/',
authorize_url='https://accounts.google.com/o/oauth2/auth',
request_token_url=None,
request_token_params={'scope': 'https://www.googleapis.com/auth/userinfo.email',
'response_type': 'code'},
access_token_url='https://accounts.google.com/o/oauth2/token',
access_token_method='POST',
access_token_params={'grant_type': 'authorization_code'},
consumer_key=GOOGLE_CLIENT_ID,
consumer_secret=GOOGLE_CLIENT_SECRET)
#app.route('/')
def index():
access_token = session.get('access_token')
if access_token is None:
return redirect(url_for('login'))
access_token = access_token[0]
from urllib2 import Request, urlopen, URLError
headers = {'Authorization': 'OAuth '+access_token}
req = Request('https://www.googleapis.com/oauth2/v1/userinfo',
None, headers)
try:
res = urlopen(req)
except URLError, e:
if e.code == 401:
# Unauthorized - bad token
session.pop('access_token', None)
return redirect(url_for('login'))
return res.read()
j = json.loads(res.read())
email_address = j['email']
print email_address, access_token
return Uber_Cost(email_address, access_token)
#app.route('/login')
def login():
callback=url_for('authorized', _external=True)
return google.authorize(callback=callback)
#app.route(REDIRECT_URI)
#google.authorized_handler
def authorized(resp):
access_token = resp['access_token']
session['access_token'] = access_token, ''
return redirect(url_for('index'))
#google.tokengetter
def get_access_token():
return session.get('access_token')
def GenerateOAuth2String(username, access_token, base64_encode=True):
auth_string = 'user=%s\1auth=Bearer %s\1\1' % (username, access_token)
if base64_encode:
auth_string = base64.b64encode(auth_string)
return auth_string
def Uber_Cost(email_address, access_token):
auth_string = GenerateOAuth2String(email_address, access_token, base64_encode=False)
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.debug = 4
mail.authenticate('XOAUTH2', lambda x: auth_string)
mail.select('INBOX')
It looks like you've got the authenticate() method down based on your latest code.
You also need the https://mail.google.com/ OAuth scope to authenticate with the IMAP and SMTP servers.
That is add it to your scope request, and make sure your app is configured for this scope on the Google App Console:
request_token_params={'scope': 'https://www.googleapis.com/auth/userinfo.email https://mail.google.com/',
'response_type': 'code'},
The Google OAUTH2 protocol and scopes are documented at their developer page.
This is my code for my main.py file which is designed to be a simple contact form built in flask.
from flask import Flask, render_template, request
from flask_mail import Mail, Message
from forms import ContactForm
app = Flask(__name__)
app.secret_key = 'YourSuperSecreteKey'
# add mail server config
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USE_SSL'] = True
app.config['MAIL_USERNAME'] = 'YourUser#NameHere'
app.config['MAIL_PASSWORD'] = 'yourMailPassword'
mail = Mail(app)
#app.route('/')
def hello():
"""Return a friendly HTTP greeting."""
return 'Hello World!'
#app.errorhandler(404)
def page_not_found(e):
"""Return a custom 404 error."""
return 'Sorry, Nothing at this URL.', 404
#app.errorhandler(500)
def application_error(e):
"""Return a custom 500 error."""
return 'Sorry, unexpected error: {}'.format(e), 500
#app.route('/contact', methods=('GET', 'POST'))
def contact():
form = ContactForm()
if request.method == 'POST':
if form.validate() == False:
return 'Please fill in all fields <p>Try Again!!!</p>'
else:
msg = Message("Message from your visitor" + form.name.data,
sender='YourUser#NameHere',
recipients=['yourRecieve#mail.com', 'someOther#mail.com'])
msg.body = """
From: %s <%s>,
%s
""" % (form.name.data, form.email.data, form.message.data)
mail.send(msg)
return "Successfully sent message!"
elif request.method == 'GET':
return render_template('contact.html', form=form)
if __name__ == '__main__':
app.run()
I get the error: Sorry, unexpected error: 'module' object has no attribute 'SMTP_SSL'
I've called my file "main.py". Everything works fine until I try and send the actual email. Is this just because I haven't populated the settings or is something else a miss?
Sorry just figured out how to see traceback on GAE:
Exception on /contact [POST]
Traceback (most recent call last):
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/main.py", line 50, in contact
mail.send(msg)
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask_mail.py", line 491, in send
with self.connect() as connection:
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask_mail.py", line 144, in __enter__
self.host = self.configure_host()
File "/base/data/home/apps/s~smart-cove-95709/1.384663697853252774/lib/flask_mail.py", line 156, in configure_host
host = smtplib.SMTP_SSL(self.mail.server, self.mail.port)
AttributeError: 'module' object has no attribute 'SMTP_SSL'
You have set the MAIL_USE_SSL option to True:
app.config['MAIL_USE_SSL'] = True
which means that the Flask-Mail extension will want to use the smtplib.SMTP_SSL class, but that class isn't usually available on Google App Engine.
That class is only available if the Python ssl module is available, which is only the case if your Python was built with SSL support available. This isn't normally the case in the GAE environment.
The module is not available on Google App Engine unless you specifically enable it. Enable it in your app.yaml:
libraries:
- name: ssl
version: latest
Do note that the socket support on GAE is experimental.
For sending email on GAE you are better off using the mail.send_mail() function however, so you can make use of the GAE infrastructure instead.
I'm using flask-security to handle user registration, login, etc. I'm facing a problem when registering a new user using the default flask-security views.
EDIT
I managed to advance a little on solving the problem. The initial problem was that I wasn't providing a load_user callback. Now I'm doing it:
#login_manager.user_loader
def load_user(user_id):
return User.objects.get(id=user_id)
Problem is that the confirmation url/view seems to use an AnonymousUser and so, the query filter does not match the correct user. Any clues guys?
Original
I'm able to provide user mail and password in the registration view, I successfully receive a confirmation e-mail (the default template provided by flask-security) but when I try to confirm the account clicking on the mail confirmation link I get the following attribute error:
AttributeError: 'AnonymousUserMixin' object has no attribute 'roles'
Here is the full traceback:
Traceback (most recent call last):
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site- packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask_security/views.py", line 226, in confirm_email
logout_user()
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask_security/utils.py", line 92, in logout_user
identity=AnonymousIdentity())
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/blinker/base.py", line 267, in send
for receiver in self.receivers_for(sender)]
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask_principal.py", line 469, in _on_identity_changed
self.set_identity(identity)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask_principal.py", line 418, in set_identity
self._set_thread_identity(identity)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask_principal.py", line 463, in _set_thread_identity
identity=identity)
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/blinker/base.py", line 267, in send
for receiver in self.receivers_for(sender)]
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/flask_security/core.py", line 217, in _on_identity_loaded
for role in current_user.roles:
File "/home/infante/PycharmProjects/venvs/wp/lib/python2.7/site-packages/werkzeug/local.py", line 338, in __getattr__
return getattr(self._get_current_object(), name)
AttributeError: 'AnonymousUserMixin' object has no attribute 'roles'
Here is my app configuration:
from flask import Flask
from flask.ext.security import MongoEngineUserDatastore, Security
from flask_login import LoginManager
from flask_mail import Mail
from wpapp.models import db, User, Role
from wpapp.views import frontend
from wpapp.configs import CONFS
login_manager = LoginManager()
app = Flask(__name__)
app.config["MONGODB_SETTINGS"] = CONFS['MONGODB_SETTINGS']
app.config["SECRET_KEY"] = CONFS['SECRET_KEY']
app.config['SECURITY_PASSWORD_HASH'] = CONFS['SECURITY_PASSWORD_HASH']
app.config['SECURITY_PASSWORD_SALT'] = CONFS['SECURITY_PASSWORD_SALT']
app.config['SECURITY_REGISTERABLE'] = CONFS['SECURITY_REGISTERABLE']
app.config['SECURITY_CONFIRMABLE'] = CONFS['SECURITY_CONFIRMABLE']
app.config['SECURITY_RECOVERABLE'] = CONFS['SECURITY_RECOVERABLE']
app.config['SECURITY_REGISTER_URL'] = CONFS['SECURITY_REGISTER_URL']
app.config['MAIL_SERVER'] = CONFS['MAIL_SERVER']
app.config['MAIL_PORT'] = CONFS['MAIL_PORT']
app.config['MAIL_USE_SSL'] = CONFS['MAIL_USE_SSL']
app.config['MAIL_USERNAME'] = CONFS['MAIL_USERNAME']
app.config['MAIL_PASSWORD'] = CONFS['MAIL_PASSWORD']
mail = Mail(app)
app.register_blueprint(frontend)
db.init_app(app)
user_datastore = MongoEngineUserDatastore(db, User, Role)
security = Security(app, user_datastore)
login_manager.init_app(app)
if __name__ == '__main__':
app.run()
And here are my models definitions (I'm using mongodb):
from flask.ext.mongoengine import MongoEngine
from flask.ext.security import UserMixin, RoleMixin
db = MongoEngine()
class Role(db.Document, RoleMixin):
name = db.StringField(verbose_name=u"Nome",
help_text=u"Inserir um nome para identificação do Papel.",
max_length=50,
required=True,
unique=True)
description = db.StringField(verbose_name=u"Descrição",
help_text=u"Inserir descrição sucinta sobre o Papel.",
max_length=255)
class User(db.Document, UserMixin):
email = db.StringField(verbose_name=u"E-mail",
help_text=u"Cadastrar um e-mail válido.",
max_length=255,
required=True,
unique=True)
password = db.StringField(verbose_name=u"Senha",
help_text=u"Cadastrar sua senha para acesso.",
required=True,
max_length=255)
active = db.BooleanField(verbose_name=u"Ativo",
help_text=u"Indica se o usuário está ativo no sistema.",
default=True)
confirmed_at = db.DateTimeField(verbose_name=u"Confirmação",
help_text=u"Horário de confirmação do usuário")
roles = db.ListField(db.ReferenceField(Role),
verbose_name=u"Papéis",
help_text=u"Atribuir papéis ao usuário.",
default=[])
Does anyone have a clue on what may the problem be?
Thanks in advance!
Thanks deadbeef404, pretty much nailed it. I would have commented on your answer, but I don't have any rep.
Actually flask login uses it's own AnonymousUserMixin class. The following snippet shows how to override it with flask security's AnonymousUser class.
login_manager = LoginManager()
from flask.ext.security import AnonymousUser
login_manager.anonymous_user = AnonymousUser
I'm not sure what your exact problem is but it seems that flask principal is trying to use the AnonymousUser (the identity in memory when no one is logged in) like an authenticated user. An AnonymousUser doesn't have a roles attribute so when it tries to access it, it throws an Exception.