Reputation: 287
I am getting the error below. I think that for some reason my UserMixin import does not include the has_role property that @role_required requires. Do I need to use RoleMixin. Can anyone help?
Traceback (most recent call last):
File "/Users/henry.arnold/anaconda/lib/python3.5/site-packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/Users/henry.arnold/anaconda/lib/python3.5/site-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Users/henry.arnold/anaconda/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise
raise value
File "/Users/henry.arnold/anaconda/lib/python3.5/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/Users/henry.arnold/anaconda/lib/python3.5/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/henry.arnold/anaconda/lib/python3.5/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Users/henry.arnold/anaconda/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise
raise value
File "/Users/henry.arnold/anaconda/lib/python3.5/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/Users/henry.arnold/anaconda/lib/python3.5/site-packages/flask_debugtoolbar/__init__.py", line 125, in dispatch_request
return view_func(**req.view_args)
File "/Users/henry.arnold/anaconda/lib/python3.5/site-packages/flask_login.py", line 792, in decorated_view
return func(*args, **kwargs)
File "/Users/henry.arnold/anaconda/lib/python3.5/site-packages/flask_user/decorators.py", line 69, in decorated_view
if not current_user.has_roles(*role_names):
File "/Users/henry.arnold/anaconda/lib/python3.5/site-packages/werkzeug/local.py", line 338, in __getattr__
return getattr(self._get_current_object(), name)
AttributeError: 'User' object has no attribute 'has_roles'
My model
import datetime as dt
from flask_login import UserMixin
from flaskapp.database import Column, Model, SurrogatePK, db
from flaskapp.teams.models import Teams
class User(UserMixin, SurrogatePK, Model):
"""A user of the app."""
__tablename__ = 'users'
user_id = Column(db.BigInteger, unique=True, nullable=False)
first_name = Column(db.String(30), nullable=True)
last_name = Column(db.String(80), nullable=True)
email = Column(db.String(80), unique=True, nullable=False)
isaf_id = Column(db.String(10), nullable=True)
primary_team_id = Column(db.Integer, db.ForeignKey(Teams.id), nullable=True)
primary_team = db.relationship('Teams', foreign_keys='User.primary_team_id')
is_admin = Column(db.Boolean(), default=False)
created_at = Column(db.DateTime, nullable=False, default=dt.datetime.utcnow)
roles = db.relationship('Role', secondary='user_roles',
backref=db.backref('users', lazy='dynamic'))
def __init__(self, user_id=user_id, first_name=first_name, last_name=last_name, email=email, is_admin=is_admin, **kwargs):
"""if int(user_id) in current_app.config['ADMINS']:
self.is_admin = True
else:
self.is_admin = False"""
db.Model.__init__(self, user_id=user_id, first_name=first_name, last_name=last_name, email=email, is_admin=is_admin, **kwargs)
"""Create instance."""
@property
def full_name(self):
"""Full user name."""
return '{0} {1}'.format(self.first_name, self.last_name)
def __repr__(self):
"""Represent instance as a unique string."""
return '{0} {1}'.format(self.first_name, self.last_name)
# Define Role model
class Role(db.Model):
role_id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(50), unique=True)
# Define UserRoles model
class UserRoles(db.Model):
id = db.Column(db.Integer(), primary_key=True)
user_id = db.Column(db.Integer(), db.ForeignKey('users.user_id', ondelete='CASCADE'))
role_id = db.Column(db.Integer(), db.ForeignKey('role.role_id', ondelete='CASCADE'))
to create the user I do the following
@blueprint.route('/callback/<provider>')
def oauth_callback(provider):
if not current_user.is_anonymous:
return redirect(url_for('public.home'))
oauth = OAuthSignIn.get_provider(provider)
user_id, first_name, last_name, email, is_admin = oauth.callback()
if user_id is None:
flash('Authentication failed.')
return redirect(url_for('public.home'))
user = User.query.filter_by(user_id=user_id).first()
if not user:
User.create(user_id=user_id, first_name=first_name, last_name=last_name, email=email, is_admin = is_admin)
user = User.query.filter_by(user_id=user_id).first()
if is_admin:
print('is admin')
admin = Role.query.filter(Role.name == 'admin').first()
user.roles.append(admin)
User.query.filter_by(user_id=user_id).update({'is_admin': True})
else:
print('is not admin')
User.query.filter_by(user_id=user_id).update({'is_admin': False})
login_user(user, True)
db.session.commit()
return redirect(url_for('public.home'))
I think check the user is an admin
from flask import Blueprint, flash, redirect, render_template, request, url_for
from flask_login import current_user, login_required
from flask_user import roles_required
from flaskapp.events.forms import CreateEventForm
from flaskapp.events.models import Events
from flaskapp.database import db
from datetime import date
from collections import OrderedDict
@blueprint.route('/add_event', methods=['POST', 'GET'])
@login_required
@roles_required('admin')
def add_event():
Upvotes: 0
Views: 3174
Reputation: 576
UserMixin
class from flask_login
does not provide has_roles
attribute (source). You can provide it by yourself in your User
class:
class User(UserMixin, SurrogatePK, Model):
# ... Everything that you've written so far
def has_roles(self, *args):
return set(args).issubset({role.name for role in self.roles})
Also, you can use UserMixin
class not from flask_login
module, but from flask_user
module (yes, there is a confusion in names). The latter class indeed does provide has_roles
method. In this case all you need to do is change this line
from flask_login import UserMixin
to this:
from flask_user import UserMixin
Upvotes: 4