Skip to content
This repository has been archived by the owner on Jun 28, 2022. It is now read-only.

User management #3

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE']
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['SECURITY_REGISTERABLE'] = True
app.config['SECURITY_USER_IDENTITY_ATTRIBUTES'] = ['username']
app.config['SECURITY_SEND_REGISTER_EMAIL'] = False
# Please use your own salt for productive use!
app.config['SECURITY_PASSWORD_SALT'] = "eph4OoGh Oochiel4"
Expand All @@ -18,11 +19,11 @@
from flask_admin import Admin
admin = Admin(app, name='s0inv', template_mode='bootstrap3', url='/'+NAMESPACE)

from app import models,views, modelviews
from app import models,views, modelviews, forms
# Setup Flask-Security
from flask_security import Security, SQLAlchemyUserDatastore, current_user
user_datastore = SQLAlchemyUserDatastore(db, models.User, models.Role)
security = Security(app, user_datastore)
security = Security(app, user_datastore, register_form=forms.ExtendedRegisterForm, login_form=forms.LoginForm)
modelviews.__init__()

def build_sample_db():
Expand Down
59 changes: 59 additions & 0 deletions app/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from flask_security.forms import RegisterForm, LoginForm, Required, Form, NextFormMixin
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from flask import request, current_app
from app import models, db
from flask_security.utils import verify_and_update_password
from flask_security.confirmable import requires_confirmation

class ExtendedRegisterForm(RegisterForm):
username = StringField('Username', [Required()])

class LoginForm(Form, NextFormMixin):

username = StringField('Username',
validators=[Required(message='EMAIL_NOT_PROVIDED')])
password = PasswordField('Password',
validators=[Required()])
remember = BooleanField("Remember me")
submit = SubmitField("Log In")

def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
if not self.next.data:
self.next.data = request.args.get('next', '')
self.remember.default = True
if current_app.extensions['security'].recoverable and \
not self.password.description:
html = Markup(u'<a href="{url}">{message}</a>'.format(
url=url_for_security("forgot_password"),
message=get_message("FORGOT_PASSWORD")[0],
))
self.password.description = html

def validate(self):
if not super(LoginForm, self).validate():
return False

# self.user = _datastore.get_user(self.username.data)
self.user = models.User.query.filter(models.User.username == self.username.data).first()

if self.user is None:
self.username.errors.append(get_message('USER_DOES_NOT_EXIST')[0])
# Reduce timing variation between existing and non-existung users
hash_password(self.password.data)
return False
if not self.user.password:
self.password.errors.append(get_message('PASSWORD_NOT_SET')[0])
# Reduce timing variation between existing and non-existung users
hash_password(self.password.data)
return False
if not verify_and_update_password(self.password.data, 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
1 change: 1 addition & 0 deletions app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class Role(db.Model, RoleMixin):
class User(db.Model, UserMixin):
__tablename__ = 'User'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(255), unique=True)
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
active = db.Column(db.Boolean())
Expand Down
14 changes: 14 additions & 0 deletions app/modelviews.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@ def is_accessible(self):
else:
return False

class UserView(ModelView):
can_create = False
can_edit = False
can_delete = False
column_exclude_list = ['password','confirmed_at','active', ]
# column_searchable_list = ['name', 'email']
def is_accessible(self):
if current_user.is_authenticated:
return True
else:
return False


def __init__():
admin.add_view(ItemView(models.Item, db.session))
admin.add_view(ProjectView(models.Project, db.session))
admin.add_view(UserView(models.User, db.session))
30 changes: 30 additions & 0 deletions app/templates/security/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{% block doc -%}
<!DOCTYPE html>
<html{% block html_attribs %}{% endblock html_attribs %}>
{%- block html %}
<head>
{%- block head %}
<title>{% block title %}{{ title|default }}{% endblock title %}</title>

{%- block metas %}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{%- endblock metas %}

{%- block styles %}
{%- endblock styles %}
{%- endblock head %}
</head>
<body{% block body_attribs %}{% endblock body_attribs %}>
{% block body -%}
{% block navbar %}
{%- endblock navbar %}
{% block content -%}
{%- endblock content %}

{% block scripts %}
{%- endblock scripts %}
{%- endblock body %}
</body>
{%- endblock html %}
</html>
{% endblock doc -%}
16 changes: 16 additions & 0 deletions app/templates/security/login_user.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{% extends "security/base.html" %}
{% from "security/_macros.html" import render_field_with_errors, render_field %}

{% block content %}
{% include "security/_messages.html" %}
<h1>{{ _('Login') }}</h1>
<form action="{{ url_for_security('login') }}" method="POST" name="login_user_form">
{{ login_user_form.hidden_tag() }}
{{ render_field_with_errors(login_user_form.username) }}
{{ render_field_with_errors(login_user_form.password) }}
{{ render_field_with_errors(login_user_form.remember) }}
{{ render_field(login_user_form.next) }}
{{ render_field(login_user_form.submit) }}
</form>
{% include "security/_menu.html" %}
{% endblock %}
18 changes: 18 additions & 0 deletions app/templates/security/register_user.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{% extends "security/base.html" %}
{% from "security/_macros.html" import render_field_with_errors, render_field %}

{% block content %}
{% include "security/_messages.html" %}
<h1>{{ _('Register') }}</h1>
<form action="{{ url_for_security('register') }}" method="POST" name="register_user_form">
{{ register_user_form.hidden_tag() }}
{{ render_field_with_errors(register_user_form.username) }}
{{ render_field_with_errors(register_user_form.email) }}
{{ render_field_with_errors(register_user_form.password) }}
{% if register_user_form.password_confirm %}
{{ render_field_with_errors(register_user_form.password_confirm) }}
{% endif %}
{{ render_field(register_user_form.submit) }}
</form>
{% include "security/_menu.html" %}
{% endblock %}