different roles
This commit is contained in:
parent
d8ff1466c3
commit
89c7f2f955
|
@ -1,7 +1,6 @@
|
|||
import views
|
||||
|
||||
from .decorators import public_endpoint
|
||||
from .blueprint import auth
|
||||
from .security import user_datastore
|
||||
|
||||
|
||||
__all__ = ['auth', 'public_endpoint', 'views']
|
||||
__all__ = ['auth', 'public_endpoint', 'user_datastore']
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
from flask import Blueprint
|
||||
from flask.ext.security import Security
|
||||
|
||||
from .manager import login_manager, check_valid_login
|
||||
from .security import user_datastore
|
||||
from .forms import LoginForm
|
||||
|
||||
auth = Blueprint('auth', __name__, template_folder='../')
|
||||
|
||||
|
||||
@auth.record_once
|
||||
def on_registered(state):
|
||||
state.app.config['SECURITY_LOGIN_USER_TEMPLATE'] = 'auth/login.html'
|
||||
Security(
|
||||
state.app,
|
||||
user_datastore,
|
||||
login_form=LoginForm,
|
||||
)
|
||||
|
||||
login_manager.init_app(state.app)
|
||||
state.app.before_request(check_valid_login)
|
||||
|
|
|
@ -1,9 +1,47 @@
|
|||
from flask.ext.wtf import Form
|
||||
|
||||
from wtforms import TextField, PasswordField
|
||||
from wtforms import TextField, PasswordField, BooleanField
|
||||
from wtforms.validators import Required
|
||||
from flask.ext.security.forms import NextFormMixin
|
||||
from flask.ext.security.utils import verify_and_update_password, get_message
|
||||
from flask.ext.security.confirmable import requires_confirmation
|
||||
|
||||
from .security import user_datastore
|
||||
|
||||
|
||||
class LoginForm(Form):
|
||||
class LoginForm(Form, NextFormMixin):
|
||||
username = TextField('Username', [Required()])
|
||||
password = PasswordField('Password', [Required()])
|
||||
remember = BooleanField('Remember me')
|
||||
|
||||
def validate(self):
|
||||
if not super(LoginForm, self).validate():
|
||||
return False
|
||||
|
||||
username = self.username.data.strip()
|
||||
password = self.password.data.strip()
|
||||
if username == '':
|
||||
self.username.errors.append(get_message('EMAIL_NOT_PROVIDED')[0])
|
||||
return False
|
||||
|
||||
if password == '':
|
||||
self.password.errors.append(get_message('PASSWORD_NOT_PROVIDED')[0])
|
||||
return False
|
||||
|
||||
self.user = user_datastore.find_user(username=username)
|
||||
|
||||
if self.user is None:
|
||||
self.username.errors.append(get_message('USER_DOES_NOT_EXIST')[0])
|
||||
return False
|
||||
|
||||
if not verify_and_update_password(password, self.user):
|
||||
self.password.errors.append(get_message('INVALID_PASSWORD')[0])
|
||||
return False
|
||||
|
||||
if requires_confirmation(self.user):
|
||||
self.username.errors.append(get_message('CONFIRMATION_REQUIRED')[0])
|
||||
return False
|
||||
if not self.user.is_active():
|
||||
self.username.errors.append(get_message('DISABLED_ACCOUNT')[0])
|
||||
return False
|
||||
return True
|
||||
|
|
|
@ -2,15 +2,21 @@ from flask import request, current_app
|
|||
|
||||
from flask.ext.login import LoginManager, current_user
|
||||
|
||||
from .models import User
|
||||
from .security import user_datastore
|
||||
|
||||
|
||||
login_manager = LoginManager()
|
||||
login_manager.login_view = 'auth.login'
|
||||
login_manager.login_view = 'security.login'
|
||||
|
||||
|
||||
PUBLIC_ENDPOINTS = [
|
||||
'static',
|
||||
'security.login',
|
||||
]
|
||||
|
||||
|
||||
def check_valid_login():
|
||||
if 'static' == request.endpoint:
|
||||
if request.endpoint in PUBLIC_ENDPOINTS:
|
||||
return
|
||||
|
||||
if getattr(current_app.view_functions.get(request.endpoint), 'is_public', False):
|
||||
|
@ -22,4 +28,4 @@ def check_valid_login():
|
|||
|
||||
@login_manager.user_loader
|
||||
def load_user(userid):
|
||||
return User.query.get(userid)
|
||||
return user_datastore.find_user(id=userid)
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
from flask import current_app
|
||||
|
||||
from flask.ext.security import UserMixin
|
||||
from flask.ext.security import UserMixin, RoleMixin
|
||||
|
||||
|
||||
db = current_app.extensions['sqlalchemy'].db
|
||||
|
||||
ROLE_USER = 0
|
||||
ROLE_ADMIN = 1
|
||||
|
||||
class Role(db.Model, RoleMixin):
|
||||
id = db.Column(db.Integer(), primary_key=True)
|
||||
name = db.Column(db.String(80), unique=True)
|
||||
description = db.Column(db.String(255))
|
||||
|
||||
|
||||
class User(db.Model, UserMixin):
|
||||
|
@ -14,9 +17,14 @@ class User(db.Model, UserMixin):
|
|||
username = db.Column(db.String(64), unique=True)
|
||||
email = db.Column(db.String(120), unique=True)
|
||||
password = db.Column(db.String(20))
|
||||
role = db.Column(db.SmallInteger, default=ROLE_USER)
|
||||
active = db.Column(db.Boolean, default=False)
|
||||
|
||||
roles = db.relationship(
|
||||
Role,
|
||||
secondary=lambda: roles_users,
|
||||
backref=db.backref('users', lazy='dynamic'),
|
||||
)
|
||||
|
||||
def get_id(self):
|
||||
return unicode(self.id)
|
||||
|
||||
|
@ -25,3 +33,10 @@ class User(db.Model, UserMixin):
|
|||
|
||||
def is_anonymous(self):
|
||||
return False
|
||||
|
||||
|
||||
roles_users = db.Table(
|
||||
'roles_users',
|
||||
db.Column('user_id', db.Integer(), db.ForeignKey(User.id)),
|
||||
db.Column('role_id', db.Integer(), db.ForeignKey(Role.id)),
|
||||
)
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
from flask.ext.security import SQLAlchemyUserDatastore
|
||||
from .models import db, User, Role
|
||||
|
||||
user_datastore = SQLAlchemyUserDatastore(db, User, Role)
|
|
@ -1,25 +0,0 @@
|
|||
from flask import request, url_for, redirect, render_template
|
||||
from flask.ext.login import login_user
|
||||
|
||||
from .blueprint import auth
|
||||
from .decorators import public_endpoint
|
||||
from .forms import LoginForm
|
||||
from .models import User
|
||||
|
||||
|
||||
@auth.route('/login/', methods=['GET', 'POST'])
|
||||
@public_endpoint
|
||||
def login():
|
||||
form = LoginForm()
|
||||
|
||||
if form.validate_on_submit():
|
||||
user = (
|
||||
User.query
|
||||
.filter(User.username == form.username.data)
|
||||
.first()
|
||||
)
|
||||
#TODO: if user is not found
|
||||
login_user(user)
|
||||
return redirect(request.args.get('next') or url_for('index'))
|
||||
|
||||
return render_template('auth/login.html', form=form,)
|
|
@ -1,6 +1,37 @@
|
|||
from flask.ext.admin import Admin
|
||||
from flask import current_app
|
||||
from flask.ext.admin.contrib.sqlamodel import ModelView
|
||||
from pytest_bdd_example.book import db, Book
|
||||
|
||||
admin = Admin()
|
||||
admin.add_view(ModelView(Book, db.session, 'books', endpoint='books'))
|
||||
from flask.ext.principal import Permission, RoleNeed
|
||||
|
||||
from pytest_bdd_example.book import db, Book, Author
|
||||
|
||||
|
||||
admin = current_app.extensions['admin'][0]
|
||||
|
||||
|
||||
class AuthorView(ModelView):
|
||||
|
||||
def is_visible(self):
|
||||
return Permission(RoleNeed('admin')).can()
|
||||
|
||||
|
||||
admin.add_view(
|
||||
AuthorView(
|
||||
Author,
|
||||
db.session,
|
||||
'authors',
|
||||
endpoint='authors',
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
admin.add_view(
|
||||
ModelView(
|
||||
Book,
|
||||
db.session,
|
||||
'books',
|
||||
endpoint='books',
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
from flask import Blueprint
|
||||
|
||||
from .admin import admin
|
||||
|
||||
book = Blueprint('book', __name__)
|
||||
|
||||
|
||||
@book.record_once
|
||||
def on_registered(state):
|
||||
admin.init_app(state.app)
|
||||
__all__ = ['book', 'admin']
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
from flask.ext.admin import Admin
|
||||
from flask.ext.admin.base import MenuLink
|
||||
|
||||
admin = Admin(
|
||||
name='Dashboard',
|
||||
url='/',
|
||||
)
|
||||
|
||||
admin.add_link(
|
||||
MenuLink(
|
||||
name='Logout',
|
||||
endpoint='security.logout',
|
||||
)
|
||||
)
|
|
@ -3,6 +3,7 @@ from flask import Flask
|
|||
from flask.ext.sqlalchemy import SQLAlchemy
|
||||
from pytest_bdd_example.dashboard import settings
|
||||
|
||||
from .admin import admin
|
||||
|
||||
app = Flask(
|
||||
__name__,
|
||||
|
@ -13,6 +14,7 @@ app = Flask(
|
|||
app.config.from_object('pytest_bdd_example.dashboard.settings')
|
||||
app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
|
||||
|
||||
admin.init_app(app)
|
||||
|
||||
db = SQLAlchemy(app)
|
||||
|
||||
|
@ -23,6 +25,5 @@ with app.app_context():
|
|||
app.register_blueprint(auth, url_prefix='/auth')
|
||||
app.register_blueprint(book)
|
||||
|
||||
|
||||
# Register the views
|
||||
from .views import *
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
from flask import redirect, url_for
|
||||
|
||||
from .app import app
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return redirect(url_for('admin.index'))
|
|
@ -34,21 +34,23 @@
|
|||
{% block menu %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form class="form-signin" method='POST'>
|
||||
{{ form.csrf_token }}
|
||||
{{ login_user_form.csrf_token }}
|
||||
<h2 class="form-signin-heading">Please sign in</h2>
|
||||
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
{{ form.username(placeholder=form.username.label.text, class="input-block-level") }}
|
||||
<ul class="errors">{% for error in form.username.errors %}<li>{{ error|e }}</li>{% endfor %}</ul>
|
||||
{{ login_user_form.username(placeholder=login_user_form.username.label.text, class="input-block-level") }}
|
||||
|
||||
{% for error in login_user_form.username.errors %}<div class="alert alert-error">{{ error|e }}</div>{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
{{ form.password(placeholder=form.password.label.text, class="input-block-level") }}
|
||||
<ul class="errors">{% for error in form.password.errors %}<li>{{ error|e }}</li>{% endfor %}</ul>
|
||||
{{ login_user_form.password(placeholder=login_user_form.password.label.text, class="input-block-level") }}
|
||||
{% for error in login_user_form.password.errors %}<div class="alert alert-error">{{ error|e }}</div>{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,20 +1,38 @@
|
|||
from flask import current_app
|
||||
|
||||
from pytest_bdd_example.auth.models import User
|
||||
from pytest_bdd_example.auth import user_datastore
|
||||
|
||||
|
||||
def create_initial_data():
|
||||
print 'Populating the initial data...'
|
||||
db = current_app.extensions['sqlalchemy'].db
|
||||
|
||||
print 'Dashboard user: admin/asdasd'
|
||||
admin = User(
|
||||
print 'Creating roles...'
|
||||
admin_role = user_datastore.create_role(
|
||||
name='admin',
|
||||
description='Administrators',
|
||||
)
|
||||
|
||||
author_role = user_datastore.create_role(
|
||||
name='author',
|
||||
description='Book authors',
|
||||
)
|
||||
|
||||
print 'Admin user: admin/asdasd'
|
||||
admin = user_datastore.create_user(
|
||||
username='admin',
|
||||
password='asdasd',
|
||||
active=True,
|
||||
)
|
||||
db.session.add(admin)
|
||||
user_datastore.add_role_to_user(admin, admin_role)
|
||||
|
||||
print 'Author user: author/asdasd'
|
||||
author = user_datastore.create_user(
|
||||
username='author',
|
||||
password='asdasd',
|
||||
active=True,
|
||||
)
|
||||
user_datastore.add_role_to_user(author, author_role)
|
||||
|
||||
#TODO: add other data here...
|
||||
|
||||
db.session.commit()
|
||||
|
|
Loading…
Reference in New Issue