Update login
Add profile
This commit is contained in:
@@ -26,9 +26,31 @@ formatter = logging.Formatter(app.config['LONG_LOG_FORMAT'])
|
||||
handler.setFormatter(formatter)
|
||||
app.logger.addHandler(handler)
|
||||
|
||||
from . import lib, models
|
||||
|
||||
@app.context_processor
|
||||
def inject_data():
|
||||
result = {}
|
||||
|
||||
result['user'] = None
|
||||
if lib.get_user():
|
||||
result['user'] = lib.get_user()
|
||||
|
||||
return result
|
||||
|
||||
@app.teardown_appcontext
|
||||
def shutdown_session(exception=None):
|
||||
models.db_session.close_all()
|
||||
|
||||
# API
|
||||
from . import ns_api
|
||||
|
||||
# Авторизация
|
||||
from . import ns_login
|
||||
|
||||
# Профиль
|
||||
from . import ns_profile
|
||||
|
||||
# Пользователи
|
||||
from . import ns_user
|
||||
|
||||
|
||||
36
myapp/decorators.py
Normal file
36
myapp/decorators.py
Normal file
@@ -0,0 +1,36 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
__author__ = 'RemiZOffAlex'
|
||||
__copyright__ = '(c) RemiZOffAlex'
|
||||
__license__ = 'MIT'
|
||||
__email__ = 'remizoffalex@mail.ru'
|
||||
__url__ = 'http://remizoffalex.ru'
|
||||
|
||||
import datetime
|
||||
|
||||
from functools import wraps
|
||||
from flask import session, redirect
|
||||
|
||||
from . import models
|
||||
|
||||
|
||||
def login_required(func):
|
||||
@wraps(func)
|
||||
def decorated_function(*args, **kwargs):
|
||||
if 'logged_in' in session and 'user_id' in session:
|
||||
user = models.db_session.query(
|
||||
models.User
|
||||
).filter(
|
||||
models.User.id==session['user_id']
|
||||
).first()
|
||||
if user:
|
||||
user.last_activity = datetime.datetime.now()
|
||||
models.db_session.commit()
|
||||
return func(*args, **kwargs)
|
||||
else:
|
||||
session.pop('logged_in', None)
|
||||
session.pop('user_id', None)
|
||||
return redirect('/login')
|
||||
else:
|
||||
return redirect('/login')
|
||||
return decorated_function
|
||||
@@ -7,6 +7,6 @@ __url__ = 'https://remizoffalex.ru'
|
||||
from .pagination import Pagination, getpage
|
||||
from .passwd import pwgen, get_hash_password
|
||||
from .storage import gettree, gethashtree
|
||||
from .info import get_user, get_ip
|
||||
from .info import get_user
|
||||
|
||||
__all__ = []
|
||||
|
||||
@@ -23,14 +23,3 @@ def get_user():
|
||||
session.pop('user_id', None)
|
||||
return None
|
||||
return result
|
||||
|
||||
def get_ip():
|
||||
"""
|
||||
Получить IP
|
||||
"""
|
||||
result = ''
|
||||
if request.headers.getlist("X-Forwarded-For"):
|
||||
result = request.headers.get("X-Forwarded-For").split(",")[0]
|
||||
else:
|
||||
result = request.remote_addr
|
||||
return result
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: UTF-8 -*-
|
||||
|
||||
__author__ = 'RemiZOffAlex'
|
||||
__copyright__ = '(c) RemiZOffAlex'
|
||||
__license__ = 'MIT'
|
||||
__email__ = 'remizoffalex@mail.ru'
|
||||
__url__ = 'https://remizoffalex.ru'
|
||||
|
||||
import uuid
|
||||
import random
|
||||
import hashlib
|
||||
|
||||
from .. import app
|
||||
|
||||
def pwgen(length=15, hex=False):
|
||||
"""
|
||||
Генератор пароля
|
||||
@@ -29,7 +26,7 @@ def get_hash_password(password, salt = None):
|
||||
"""
|
||||
Получить хеш пароля SHA-512
|
||||
"""
|
||||
if salt == None:
|
||||
if salt is None:
|
||||
salt = uuid.uuid4().hex
|
||||
text = password.encode('utf-8') + salt.encode('utf-8')
|
||||
h = hashlib.sha512()
|
||||
|
||||
18
myapp/ns_login/__init__.py
Normal file
18
myapp/ns_login/__init__.py
Normal file
@@ -0,0 +1,18 @@
|
||||
__author__ = 'RemiZOffAlex'
|
||||
__copyright__ = '(c) RemiZOffAlex'
|
||||
__license__ = 'MIT'
|
||||
__email__ = 'remizoffalex@mail.ru'
|
||||
__url__ = 'https://remizoffalex.ru'
|
||||
|
||||
import os
|
||||
import jinja2
|
||||
|
||||
from . import views
|
||||
from .. import app
|
||||
|
||||
|
||||
my_loader = jinja2.ChoiceLoader([
|
||||
app.jinja_loader,
|
||||
jinja2.FileSystemLoader(os.path.dirname(os.path.abspath(__file__)) + "/templates"),
|
||||
])
|
||||
app.jinja_loader = my_loader
|
||||
17
myapp/ns_login/forms.py
Normal file
17
myapp/ns_login/forms.py
Normal file
@@ -0,0 +1,17 @@
|
||||
__author__ = 'RemiZOffAlex'
|
||||
__copyright__ = '(c) RemiZOffAlex'
|
||||
__license__ = 'MIT'
|
||||
__email__ = 'remizoffalex@mail.ru'
|
||||
__url__ = 'http://remizoffalex.ru'
|
||||
|
||||
from wtforms import (
|
||||
validators,
|
||||
Form,
|
||||
StringField,
|
||||
PasswordField
|
||||
)
|
||||
|
||||
|
||||
class LoginForm(Form):
|
||||
username = StringField('Логин', [validators.Length(min=4, max=25)])
|
||||
password = PasswordField('Пароль', [validators.DataRequired()])
|
||||
@@ -2,10 +2,9 @@
|
||||
{% block body %}
|
||||
|
||||
<div class="col-md-6 ml-auto mr-auto">
|
||||
<div class="card">
|
||||
<div class="card-header">Логин</div>
|
||||
<h3>Логин</h3>
|
||||
<hr />
|
||||
|
||||
<div class="card-body">
|
||||
<form class="form-horizontal" action="/login" method="post" autocomplete="on">
|
||||
|
||||
<div style="margin-bottom: 25px" class="input-group">
|
||||
@@ -25,7 +24,5 @@
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
45
myapp/ns_login/views.py
Normal file
45
myapp/ns_login/views.py
Normal file
@@ -0,0 +1,45 @@
|
||||
__author__ = 'RemiZOffAlex'
|
||||
__copyright__ = '(c) RemiZOffAlex'
|
||||
__license__ = 'MIT'
|
||||
__email__ = 'remizoffalex@mail.ru'
|
||||
__url__ = 'https://remizoffalex.ru'
|
||||
|
||||
from flask import render_template, escape, request, session, redirect
|
||||
|
||||
from .. import app, lib, models
|
||||
from . import forms
|
||||
|
||||
@app.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
"""
|
||||
Логин
|
||||
"""
|
||||
pagedata = {}
|
||||
pagedata['form'] = forms.LoginForm(request.form)
|
||||
|
||||
if request.method == 'POST':
|
||||
if pagedata['form'].validate():
|
||||
user = models.db_session.query(
|
||||
models.User
|
||||
).filter(
|
||||
models.User.name == escape(pagedata['form'].username.data),
|
||||
models.User.password == lib.get_hash_password(
|
||||
escape(pagedata['form'].password.data),
|
||||
app.config['SECRET_KEY']
|
||||
),
|
||||
models.User.disabled == False
|
||||
).first()
|
||||
if user:
|
||||
session['logged_in'] = True
|
||||
session['user_id'] = user.id
|
||||
return redirect('/', code=302)
|
||||
|
||||
body = render_template('login.html', pagedata=pagedata)
|
||||
return body
|
||||
|
||||
|
||||
@app.route('/logout')
|
||||
def logout():
|
||||
session.pop('logged_in', None)
|
||||
session.pop('user_id', None)
|
||||
return redirect("/", code=302)
|
||||
18
myapp/ns_profile/__init__.py
Normal file
18
myapp/ns_profile/__init__.py
Normal file
@@ -0,0 +1,18 @@
|
||||
__author__ = 'RemiZOffAlex'
|
||||
__copyright__ = '(c) RemiZOffAlex'
|
||||
__license__ = 'MIT'
|
||||
__email__ = 'remizoffalex@mail.ru'
|
||||
__url__ = 'http://remizoffalex.ru'
|
||||
|
||||
import os
|
||||
import jinja2
|
||||
|
||||
from . import views
|
||||
from .. import app
|
||||
|
||||
|
||||
my_loader = jinja2.ChoiceLoader([
|
||||
app.jinja_loader,
|
||||
jinja2.FileSystemLoader(os.path.dirname(os.path.abspath(__file__)) + "/templates"),
|
||||
])
|
||||
app.jinja_loader = my_loader
|
||||
9
myapp/ns_profile/templates/profile.html
Normal file
9
myapp/ns_profile/templates/profile.html
Normal file
@@ -0,0 +1,9 @@
|
||||
{% extends "skeleton.html" %}
|
||||
{% block body %}
|
||||
|
||||
<h3>Профиль</h3>
|
||||
<hr />
|
||||
|
||||
<p>Зарегистрирован: {{ user.created.strftime('%Y-%m-%d') }}</p>
|
||||
|
||||
{% endblock body %}
|
||||
22
myapp/ns_profile/views.py
Normal file
22
myapp/ns_profile/views.py
Normal file
@@ -0,0 +1,22 @@
|
||||
__author__ = 'RemiZOffAlex'
|
||||
__copyright__ = '(c) RemiZOffAlex'
|
||||
__license__ = 'MIT'
|
||||
__email__ = 'remizoffalex@mail.ru'
|
||||
__url__ = 'http://remizoffalex.ru'
|
||||
|
||||
from flask import render_template
|
||||
|
||||
from .. import app
|
||||
from ..decorators import login_required
|
||||
|
||||
|
||||
@app.route('/profile')
|
||||
@login_required
|
||||
def profile():
|
||||
"""
|
||||
Личный профиль пользователя
|
||||
"""
|
||||
pagedata = {}
|
||||
pagedata['title'] = 'Мой профиль - {}'.format(app.config['TITLE'])
|
||||
body = render_template('profile.html', pagedata=pagedata)
|
||||
return body
|
||||
@@ -13,14 +13,28 @@
|
||||
<div class="form-group">
|
||||
{{ pagedata['form'].text.label }}
|
||||
{{ pagedata['form'].text(class="form-control") }}
|
||||
<script>
|
||||
CKEDITOR.replace( 'text', {
|
||||
customConfig: '/static/js/ckeditor-conf.js'
|
||||
} );
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-outline-success float-right"><i class="fa fa-save-o"></i> Сохранить</button>
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script type="text/javascript" src="/static/ckeditor/ckeditor.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var app = new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
mounted: function () {
|
||||
CKEDITOR.replace( 'text', {
|
||||
customConfig: '/static/js/ckeditor-conf.js'
|
||||
} );
|
||||
}
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
<div class="container-fluid py-2">
|
||||
|
||||
{% if session.logged_in %}
|
||||
<div class="btn-group float-right">
|
||||
<a class="btn btn-outline-secondary border-0" href="/profile"><i class="fa fa-user"></i></a>
|
||||
<a class="btn btn-outline-danger border-0" href="/logout"><i class="fa fa-sign-out"></i></a>
|
||||
</div>
|
||||
{% else %}
|
||||
<a class="btn btn-outline-success border-0 float-right" href="/login"><i class="fa fa-sign-in"></i></a>
|
||||
{% endif %}
|
||||
|
||||
<a class="btn btn-outline-secondary border-0" href="/"><i class="fa fa-home"></i></a>
|
||||
<a class="btn btn-outline-secondary border-0" href="/edit"><i class="fa fa-edit"></i> Редактор</a>
|
||||
<a class="btn btn-outline-secondary border-0" href="/users">Vue & axios</a>
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
|
||||
{{ pagedata['text']|safe }}
|
||||
|
||||
{% endblock %}
|
||||
{% endblock body %}
|
||||
|
||||
@@ -8,12 +8,21 @@
|
||||
|
||||
<div class="container">
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
{% endblock body %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% block script %}
|
||||
{% endblock %}
|
||||
<script type="text/javascript">
|
||||
var app = new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
},
|
||||
methods: {
|
||||
}
|
||||
})
|
||||
</script>
|
||||
{% endblock script %}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -39,14 +39,3 @@ def edit():
|
||||
return body
|
||||
body = render_template('edit.html', pagedata=pagedata)
|
||||
return body
|
||||
|
||||
|
||||
@app.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
"""
|
||||
Логин
|
||||
"""
|
||||
pagedata = {}
|
||||
pagedata['form'] = forms.LoginForm(request.form)
|
||||
body = render_template('login.html', pagedata=pagedata)
|
||||
return body
|
||||
|
||||
Reference in New Issue
Block a user