[TASK] Initial commit.
This commit is contained in:
commit
0da26c151a
|
@ -0,0 +1,9 @@
|
||||||
|
settings.py
|
||||||
|
|
||||||
|
*.pyc
|
||||||
|
*~
|
||||||
|
*.sqlite
|
||||||
|
.project
|
||||||
|
.settings
|
||||||
|
.buildpath
|
||||||
|
.pydevproject
|
|
@ -0,0 +1,97 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from flask import Flask, render_template_string, request
|
||||||
|
from flask.ext.babel import Babel
|
||||||
|
from flask.ext.mail import Mail
|
||||||
|
from flask.ext.sqlalchemy import SQLAlchemy
|
||||||
|
from flask.ext.user import current_user, login_required, SQLAlchemyAdapter, UserManager, UserMixin
|
||||||
|
from flask.ext.user import roles_required
|
||||||
|
|
||||||
|
# Import config file containing secret information and more things.
|
||||||
|
from settings import ConfigClass, username_validator
|
||||||
|
from flask.templating import render_template
|
||||||
|
|
||||||
|
def create_app(test_config=None): # For automated tests
|
||||||
|
# Setup Flask and read config from ConfigClass defined above
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config.from_object(__name__ + '.ConfigClass')
|
||||||
|
|
||||||
|
# Load local_settings.py if file exists # For automated tests
|
||||||
|
try: app.config.from_object('local_settings')
|
||||||
|
except: pass
|
||||||
|
|
||||||
|
# Load optional test_config # For automated tests
|
||||||
|
if test_config:
|
||||||
|
app.config.update(test_config)
|
||||||
|
|
||||||
|
# Initialize Flask extensions
|
||||||
|
babel = Babel(app) # Initialize Flask-Babel
|
||||||
|
mail = Mail(app) # Initialize Flask-Mail
|
||||||
|
db = SQLAlchemy(app) # Initialize Flask-SQLAlchemy
|
||||||
|
|
||||||
|
@babel.localeselector
|
||||||
|
def get_locale():
|
||||||
|
translations = [str(translation) for translation in babel.list_translations()]
|
||||||
|
return request.accept_languages.best_match(translations)
|
||||||
|
|
||||||
|
# Define the User-Roles pivot table
|
||||||
|
user_roles = db.Table('user_roles',
|
||||||
|
db.Column('id', db.Integer(), primary_key=True),
|
||||||
|
db.Column('user_id', db.Integer(), db.ForeignKey('user.id', ondelete='CASCADE')),
|
||||||
|
db.Column('role_id', db.Integer(), db.ForeignKey('role.id', ondelete='CASCADE')))
|
||||||
|
|
||||||
|
# Define Role model
|
||||||
|
class Role(db.Model):
|
||||||
|
id = db.Column(db.Integer(), primary_key=True)
|
||||||
|
name = db.Column(db.String(50), unique=True)
|
||||||
|
|
||||||
|
# Define User model. Make sure to add flask.ext.user UserMixin!!
|
||||||
|
class User(db.Model, UserMixin):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
active = db.Column(db.Boolean(), nullable=False, default=False)
|
||||||
|
username = db.Column(db.String(50), nullable=False, unique=True)
|
||||||
|
email = db.Column(db.String(255), nullable=False, unique=True)
|
||||||
|
confirmed_at = db.Column(db.DateTime())
|
||||||
|
password = db.Column(db.String(255), nullable=False, default='')
|
||||||
|
reset_password_token = db.Column(db.String(100), nullable=False, default='')
|
||||||
|
# Relationships
|
||||||
|
roles = db.relationship('Role', secondary=user_roles, backref=db.backref('users', lazy='dynamic'))
|
||||||
|
|
||||||
|
# Reset all the database tables
|
||||||
|
db.create_all()
|
||||||
|
|
||||||
|
# Setup Flask-User
|
||||||
|
db_adapter = SQLAlchemyAdapter(db, User)
|
||||||
|
user_manager = UserManager(db_adapter, username_validator=username_validator)
|
||||||
|
user_manager.init_app(app)
|
||||||
|
|
||||||
|
# Create the default admin user if not exists.
|
||||||
|
if not User.query.filter(User.username == ConfigClass.DDNS_ADMIN_USERNAME).first():
|
||||||
|
adminuser = User(username=ConfigClass.DDNS_ADMIN_USERNAME, email=ConfigClass.DDNS_ADMIN_EMAIL, active=True,
|
||||||
|
password=user_manager.hash_password(ConfigClass.DDNS_ADMIN_PASSWORD))
|
||||||
|
adminuser.roles.append(Role(name='admin'))
|
||||||
|
db.session.add(adminuser)
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def home_page():
|
||||||
|
if current_user.is_authenticated():
|
||||||
|
return profile_page()
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
@app.route('/profile')
|
||||||
|
@login_required
|
||||||
|
def profile_page():
|
||||||
|
return render_template('profile.html')
|
||||||
|
|
||||||
|
@app.route('/special')
|
||||||
|
@roles_required('admin')
|
||||||
|
def special_page():
|
||||||
|
return render_template('admin.html')
|
||||||
|
|
||||||
|
return app
|
||||||
|
|
||||||
|
""" Start development web server """
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app = create_app()
|
||||||
|
app.run(host='0.0.0.0', port=5000, debug=True)
|
|
@ -0,0 +1 @@
|
||||||
|
flask-user
|
|
@ -0,0 +1,38 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from wtforms.validators import ValidationError
|
||||||
|
|
||||||
|
class ConfigClass(object):
|
||||||
|
""" Configuration class """
|
||||||
|
SECRET_KEY = 'THIS IS AN INSECURE SECRET' # Change this for production!
|
||||||
|
SQLALCHEMY_DATABASE_URI = 'sqlite:///minimal_app.sqlite' # Use Sqlite file db
|
||||||
|
CSRF_ENABLED = True
|
||||||
|
USER_ENABLE_EMAIL = True
|
||||||
|
USER_ENABLE_CHANGE_USERNAME = True
|
||||||
|
USER_ENABLE_CHANGE_PASSWORD = True
|
||||||
|
USER_ENABLE_FORGOT_PASSWORD = True
|
||||||
|
|
||||||
|
USER_ENABLE_REGISTRATION = True # Turn to False to disable registration.
|
||||||
|
|
||||||
|
""" Configure Flask-Mail """
|
||||||
|
MAIL_SERVER = 'your.mailserver.here'
|
||||||
|
MAIL_PORT = 587
|
||||||
|
MAIL_USE_SSL = True
|
||||||
|
MAIL_USE_TLS = True # Use this for STARTTLS!
|
||||||
|
MAIL_USERNAME = ''
|
||||||
|
MAIL_PASSWORD = ''
|
||||||
|
MAIL_DEFAULT_SENDER = '"Example Sender" <cool@service.example>'
|
||||||
|
|
||||||
|
""" Default Admin User """
|
||||||
|
DDNS_ADMIN_USERNAME = 'admin'
|
||||||
|
DDNS_ADMIN_PASSWORD = 'SuperSecretAdminPassword'
|
||||||
|
DDNS_ADMIN_EMAIL = 'admin@service.example'
|
||||||
|
|
||||||
|
|
||||||
|
def username_validator(form, field):
|
||||||
|
""" Since usernames will be used for subdomains, take your time here. """
|
||||||
|
username = field.data
|
||||||
|
if len(username) < 4:
|
||||||
|
raise ValidationError(_('Username must be at least 4 characters long'))
|
||||||
|
if not username.isalnum():
|
||||||
|
raise ValidationError(_('Username may only contain letters and numbers'))
|
|
@ -0,0 +1,4 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<h1>Admin area!</h1>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,58 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Simple Dynamic DNS Service</title>
|
||||||
|
|
||||||
|
<!-- Bootstrap -->
|
||||||
|
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
.col-centered { float: none; margin: 0 auto; }
|
||||||
|
hr { border-color: #cccccc; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||||
|
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7/html5shiv.js"></script>
|
||||||
|
<script src="//cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-8 col-md-7 col-lg-6 col-centered">
|
||||||
|
<h1><a href="/">{% block title %}Simple Dynamic DNS Service{% endblock %}</a></h1>
|
||||||
|
<hr>
|
||||||
|
{% block flash_messages %}
|
||||||
|
{%- with messages = get_flashed_messages(with_categories=true) -%}
|
||||||
|
{% if messages %}
|
||||||
|
{% for category, message in messages %}
|
||||||
|
{% if category=='error' %}
|
||||||
|
{% set category='danger' %}
|
||||||
|
{% endif %}
|
||||||
|
<div class="alert alert-{{category}}">{{ message|safe }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{%- endwith %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
<hr>
|
||||||
|
Have fun!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
||||||
|
<script src="https://code.jquery.com/jquery-1.11.0.min.js"></script>
|
||||||
|
<!-- Include all compiled plugins (below), or include individual files as needed -->
|
||||||
|
<script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,39 @@
|
||||||
|
{% macro render_field(field, label=None, label_visible=true, right_url=None, right_label=None) -%}
|
||||||
|
<div class="form-group {% if field.errors %}has-error{% endif %} {{ kwargs.pop('class_', '') }}">
|
||||||
|
{% if field.type != 'HiddenField' and label_visible %}
|
||||||
|
{% if not label %}{% set label=field.label.text %}{% endif %}
|
||||||
|
<label for="{{ field.id }}" class="control-label">{{ label|safe }}</label>
|
||||||
|
{% endif %}
|
||||||
|
{{ field(class_='form-control', **kwargs) }}
|
||||||
|
{% if field.errors %}
|
||||||
|
{% for e in field.errors %}
|
||||||
|
<p class="help-block">{{ e }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro render_checkbox_field(field, label=None) -%}
|
||||||
|
{% if not label %}{% set label=field.label.text %}{% endif %}
|
||||||
|
<div class="checkbox">
|
||||||
|
<label>
|
||||||
|
{{ field(type='checkbox', **kwargs) }} {{ field.label }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro render_radio_field(field) -%}
|
||||||
|
{% for value, label, _ in field.iter_choices() %}
|
||||||
|
<div class="radio">
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="{{ field.id }}" id="{{ field.id }}" value="{{ value }}">{{ label }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{% macro render_submit_field(field, label=None, tabindex=None) -%}
|
||||||
|
{% if not label %}{% set label=field.label.text %}{% endif %}
|
||||||
|
{#<button type="submit" class="form-control btn btn-default btn-primary">{{label}}</button>#}
|
||||||
|
<input type="submit" value="{{label}}" {% if tabindex %}tabindex="{{ tabindex }}"{% endif %}>
|
||||||
|
{%- endmacro %}
|
|
@ -0,0 +1,17 @@
|
||||||
|
{% extends 'flask_user/member_base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
|
||||||
|
<h1>{%trans%}Change Password{%endtrans%}</h1>
|
||||||
|
|
||||||
|
<form action="" method="POST" class="form" role="form">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
{{ render_field(form.old_password, tabindex=10) }}
|
||||||
|
{{ render_field(form.new_password, tabindex=20) }}
|
||||||
|
{% if user_manager.enable_retype_password %}
|
||||||
|
{{ render_field(form.retype_password, tabindex=30) }}
|
||||||
|
{% endif %}
|
||||||
|
{{ render_submit_field(form.submit, tabindex=90) }}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,14 @@
|
||||||
|
{% extends 'flask_user/member_base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
|
||||||
|
<h1>{%trans%}Change Username{%endtrans%}</h1>
|
||||||
|
|
||||||
|
<form action="" method="POST" class="form" role="form">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
{{ render_field(form.new_username, tabindex=10) }}
|
||||||
|
{{ render_field(form.old_password, tabindex=20) }}
|
||||||
|
{{ render_submit_field(form.submit, tabindex=90) }}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<p>Dear User,</p>
|
||||||
|
|
||||||
|
{% block message %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
<p>Sincerely,<br/>
|
||||||
|
The Flask-User Team</p>
|
|
@ -0,0 +1,7 @@
|
||||||
|
Dear User,
|
||||||
|
|
||||||
|
{% block message %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
Sincerely,
|
||||||
|
The Flask-User Team
|
|
@ -0,0 +1 @@
|
||||||
|
Flask-User: {% block subject %}{% endblock %}
|
|
@ -0,0 +1,15 @@
|
||||||
|
{% extends 'flask_user/emails/base_message.html' %}
|
||||||
|
|
||||||
|
{% block message %}
|
||||||
|
|
||||||
|
<p>Thank you for registering with Flask-User.</p>
|
||||||
|
|
||||||
|
{% if user_manager.enable_confirm_email %}
|
||||||
|
<p>Visit the link below to complete your registration:</p>
|
||||||
|
|
||||||
|
<p><a href="{{ confirm_email_link }}?next=/">Confirm your email address</a>.</p>
|
||||||
|
|
||||||
|
<p>If you did not initiate this registration, you may safely ignore this email.</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{% extends 'flask_user/emails/base_message.txt' %}
|
||||||
|
|
||||||
|
{% block message %}
|
||||||
|
Thank you for registering with Flask-User.
|
||||||
|
|
||||||
|
{% if user_manager.enable_confirm_email -%}
|
||||||
|
Visit the link below to complete your registration:
|
||||||
|
{{ confirm_email_link }}
|
||||||
|
|
||||||
|
If you did not initiate this registration, you may safely ignore this email.
|
||||||
|
|
||||||
|
{%- endif %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{% extends 'flask_user/emails/base_subject.txt' %}
|
||||||
|
|
||||||
|
{% block subject %}Registration Confirmation{% endblock %}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{% extends 'flask_user/emails/base_message.html' %}
|
||||||
|
|
||||||
|
{% block message %}
|
||||||
|
|
||||||
|
<p>We have received your password reset request.</p>
|
||||||
|
|
||||||
|
<p>Visit the link below to provide a new password:</p>
|
||||||
|
|
||||||
|
<p><a href="{{ reset_password_link }}">Reset your password</a>.</p>
|
||||||
|
|
||||||
|
<p>If you did not initiate this password reset request, you may safely ignore this email.</p>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,11 @@
|
||||||
|
{% extends 'flask_user/emails/base_message.txt' %}
|
||||||
|
|
||||||
|
{% block message %}
|
||||||
|
We have received your password reset request.
|
||||||
|
|
||||||
|
Visit the link below to provide a new password:
|
||||||
|
{{ reset_password_link }}
|
||||||
|
|
||||||
|
If you did not initiate this password reset request, you may safely ignore this email.
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{% extends 'flask_user/emails/base_subject.txt' %}
|
||||||
|
|
||||||
|
{% block subject %}Reset password{% endblock %}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{% extends 'flask_user/emails/base_message.html' %}
|
||||||
|
|
||||||
|
{% block message %}
|
||||||
|
<p>Your password has been changed.</p>
|
||||||
|
{% if user_manager.enable_forgot_password %}
|
||||||
|
<p>If you did not change your password, <a href="{{ url_for('user.forgot_password', _external=True) }}">click here to reset it</a>.</p>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{% extends 'flask_user/emails/base_message.txt' %}
|
||||||
|
|
||||||
|
{% block message %}
|
||||||
|
Your password has been changed.
|
||||||
|
|
||||||
|
{% if user_manager.enable_forgot_password -%}
|
||||||
|
If you did not change your password, click the link below to reset it.
|
||||||
|
{{ url_for('user.forgot_password', _external=True) }}
|
||||||
|
{% endif -%}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
{% extends 'flask_user/emails/base_subject.txt' %}
|
||||||
|
|
||||||
|
{% block subject %}Your password has been changed{% endblock %}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{% extends 'flask_user/emails/base_message.html' %}
|
||||||
|
|
||||||
|
{% block message %}
|
||||||
|
|
||||||
|
<p>Thank you for registering with Flask-User.</p>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{% extends 'flask_user/emails/base_message.txt' %}
|
||||||
|
|
||||||
|
{% block message %}
|
||||||
|
Thank you for registering with Flask-User.
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{% extends 'flask_user/emails/base_subject.txt' %}
|
||||||
|
|
||||||
|
{% block subject %}Registration Confirmation{% endblock %}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{% extends 'flask_user/emails/base_message.html' %}
|
||||||
|
|
||||||
|
{% block message %}
|
||||||
|
<p>Your username has been changed.</p>
|
||||||
|
<p>If you did not change your username, please <a href="{{ url_for('user.login', _external=True) }}">sign in</a> (using your email address) and change your password.</p>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{% extends 'flask_user/emails/base_message.txt' %}
|
||||||
|
|
||||||
|
{% block message %}
|
||||||
|
Your username has been changed.
|
||||||
|
|
||||||
|
If you did not change your username, please sign in (using your email address) and change your password.
|
||||||
|
{{ url_for('user.login', _external=True) }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
{% extends 'flask_user/emails/base_subject.txt' %}
|
||||||
|
|
||||||
|
{% block subject %}Your username has been changed{% endblock %}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{% extends 'flask_user/public_base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
|
||||||
|
<h1>{%trans%}Forgot Password{%endtrans%}</h1>
|
||||||
|
|
||||||
|
<form action="" method="POST" class="form" role="form">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
{{ render_field(form.email, tabindex=10) }}
|
||||||
|
{{ render_submit_field(form.submit, tabindex=90) }}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,60 @@
|
||||||
|
{% extends 'flask_user/public_base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
|
||||||
|
<h1>{%trans%}Sign in{%endtrans%}</h1>
|
||||||
|
|
||||||
|
<form action="" method="POST" class="form" role="form">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
|
||||||
|
{# Username or Email #}
|
||||||
|
{% set field = form.username if user_manager.enable_username else form.email %}
|
||||||
|
<div class="form-group {% if field.errors %}has-error{% endif %}">
|
||||||
|
{# Label on left, "New here? Register." on right #}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label for="{{ field.id }}" class="control-label">{{ field.label.text }}</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6 text-right">
|
||||||
|
{% if user_manager.enable_register and not user_manager.require_invitation %}
|
||||||
|
<a href="{{ url_for('user.register') }}" tabindex='190'>
|
||||||
|
{%trans%}New here? Register.{%endtrans%}</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ field(class_='form-control', tabindex=110) }}
|
||||||
|
{% if field.errors %}
|
||||||
|
{% for e in field.errors %}
|
||||||
|
<p class="help-block">{{ e }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{# Password #}
|
||||||
|
{% set field = form.password %}
|
||||||
|
<div class="form-group {% if field.errors %}has-error{% endif %}">
|
||||||
|
{# Label on left, "Forgot your Password?" on right #}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label for="{{ field.id }}" class="control-label">{{ field.label.text }}</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6 text-right">
|
||||||
|
{% if user_manager.enable_forgot_password %}
|
||||||
|
<a href="{{ url_for('user.forgot_password') }}" tabindex='195'>
|
||||||
|
{%trans%}Forgot your Password?{%endtrans%}</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ field(class_='form-control', tabindex=120) }}
|
||||||
|
{% if field.errors %}
|
||||||
|
{% for e in field.errors %}
|
||||||
|
<p class="help-block">{{ e }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{# Submit button #}
|
||||||
|
{{ render_submit_field(form.submit, tabindex=180) }}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,61 @@
|
||||||
|
{% extends 'flask_user/public_base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-6">
|
||||||
|
|
||||||
|
<h1>{%trans%}Sign in{%endtrans%}</h1>
|
||||||
|
|
||||||
|
{# ** Login form ** #}
|
||||||
|
<form action="{{ url_for('user.login') }}" method="POST" class="form" role="form">
|
||||||
|
{{ login_form.hidden_tag() }}
|
||||||
|
|
||||||
|
{# Username or Email #}
|
||||||
|
{% set field = login_form.username if user_manager.enable_username else login_form.email %}
|
||||||
|
{{ render_field(field, tabindex=110) }}
|
||||||
|
|
||||||
|
{# Password #}
|
||||||
|
{{ render_field(login_form.password, tabindex=120) }}
|
||||||
|
|
||||||
|
{# Submit button #}
|
||||||
|
{{ render_submit_field(login_form.submit, tabindex=180) }}
|
||||||
|
</form>
|
||||||
|
{% if user_manager.enable_forgot_password %}
|
||||||
|
<p>
|
||||||
|
<br/>
|
||||||
|
<a href="{{ url_for('user.forgot_password') }}" tabindex='190'>
|
||||||
|
{%trans%}Forgot your Password?{%endtrans%}</a>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
|
||||||
|
<h1>{%trans%}Register{%endtrans%}</h1>
|
||||||
|
|
||||||
|
{# ** Register form ** #}
|
||||||
|
<form action="{{ url_for('user.register') }}" method="POST" novalidate formnovalidate class="form" role="form">
|
||||||
|
{{ register_form.hidden_tag() }}
|
||||||
|
|
||||||
|
{# Username or Email #}
|
||||||
|
{% set field = register_form.username if user_manager.enable_username else register_form.email %}
|
||||||
|
{{ render_field(field, tabindex=210) }}
|
||||||
|
|
||||||
|
{% if user_manager.enable_email and user_manager.enable_username %}
|
||||||
|
{{ render_field(register_form.email, tabindex=220) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ render_field(register_form.password, tabindex=230) }}
|
||||||
|
|
||||||
|
{% if user_manager.enable_retype_password %}
|
||||||
|
{{ render_field(register_form.retype_password, tabindex=240) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ render_submit_field(register_form.submit, tabindex=280) }}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,39 @@
|
||||||
|
{% extends 'flask_user/member_base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
|
||||||
|
<h1>{%trans%}Manage Emails{%endtrans%}</h1>
|
||||||
|
|
||||||
|
<table class="table">
|
||||||
|
<tr><th>Email</th><th>Status</th><th>Actions</th></tr>
|
||||||
|
{% for user_email in user_emails %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ user_email.email }}</td>
|
||||||
|
<td>
|
||||||
|
{% if user_email.confirmed_at %}
|
||||||
|
Confirmed
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ url_for('user.email_action', id=user_email.id, action='confirm') }}">Confirm Email</a>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% if user_email.is_primary %}
|
||||||
|
<b>Primary email</b>
|
||||||
|
{% else %}
|
||||||
|
{% if user_email.confirmed_at %}
|
||||||
|
<a href="{{ url_for('user.email_action', id=user_email.id, action='make-primary') }}">Make primary</a> |
|
||||||
|
{% endif %}
|
||||||
|
<a href="{{ url_for('user.email_action', id=user_email.id, action='delete') }}">Delete</a>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<form action="" method="POST" class="form" role="form">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
{{ render_field(form.email) }}
|
||||||
|
{{ render_submit_field(form.submit) }}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,2 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
{% extends 'flask_user/public_base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
|
||||||
|
<h1>{%trans%}Register{%endtrans%}</h1>
|
||||||
|
|
||||||
|
<form action="" method="POST" novalidate formnovalidate class="form" role="form">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
|
||||||
|
{# Username or Email #}
|
||||||
|
{% set field = form.username if user_manager.enable_username else form.email %}
|
||||||
|
<div class="form-group {% if field.errors %}has-error{% endif %}">
|
||||||
|
{# Label on left, "Already registered? Sign in." on right #}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<label for="{{ field.id }}" class="control-label">{{ field.label.text }}</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6 text-right">
|
||||||
|
{% if user_manager.enable_register %}
|
||||||
|
<a href="{{ url_for('user.login') }}" tabindex='290'>
|
||||||
|
{%trans%}Already registered? Sign in.{%endtrans%}</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{ field(class_='form-control', tabindex=210) }}
|
||||||
|
{% if field.errors %}
|
||||||
|
{% for e in field.errors %}
|
||||||
|
<p class="help-block">{{ e }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if user_manager.enable_email and user_manager.enable_username %}
|
||||||
|
{{ render_field(form.email, tabindex=220) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ render_field(form.password, tabindex=230) }}
|
||||||
|
|
||||||
|
{% if user_manager.enable_retype_password %}
|
||||||
|
{{ render_field(form.retype_password, tabindex=240) }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ render_submit_field(form.submit, tabindex=280) }}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{% extends 'flask_user/public_base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
|
||||||
|
<h1>{%trans%}Resend Confirmation Email{%endtrans%}</h1>
|
||||||
|
|
||||||
|
<form action="" method="POST" class="form" role="form">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
{{ render_field(form.email, tabindex=10) }}
|
||||||
|
{{ render_submit_field(form.submit, tabindex=90) }}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{% extends 'flask_user/public_base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% from "flask_user/_macros.html" import render_field, render_submit_field %}
|
||||||
|
<h1>{%trans%}Reset Password{%endtrans%}</h1>
|
||||||
|
|
||||||
|
<form action="" method="POST" class="form" role="form">
|
||||||
|
{{ form.hidden_tag() }}
|
||||||
|
{{ render_field(form.new_password, tabindex=10) }}
|
||||||
|
{% if user_manager.enable_retype_password %}
|
||||||
|
{{ render_field(form.retype_password, tabindex=20) }}
|
||||||
|
{% endif %}
|
||||||
|
{{ render_submit_field(form.submit, tabindex=90) }}
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<h1>{%trans%}Welcome!{%endtrans%}</h1>
|
||||||
|
<p>
|
||||||
|
<a href="{{ url_for('user.login') }}">{%trans%}Sign in{%endtrans%}</a> or
|
||||||
|
<a href="{{ url_for('user.register') }}">{%trans%}Register{%endtrans%}</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<h2>{%trans%}Profile Page{%endtrans%}</h2>
|
||||||
|
<p>
|
||||||
|
{%trans%}Hello{%endtrans%} {{ current_user.username or current_user.email }}!
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li><a href="{{ url_for('user.change_username') }}">{%trans%}Change username{%endtrans%}</a></li>
|
||||||
|
<li><a href="{{ url_for('user.change_password') }}">{%trans%}Change password{%endtrans%}</a></li>
|
||||||
|
<li><a href="{{ url_for('user.logout') }}?next={{ url_for('user.login') }}">{%trans%}Sign out{%endtrans%}</a></li>
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue