This commit is contained in:
2018-08-31 17:48:29 +03:00
parent be28af1ccb
commit 48ebf82a1f
44 changed files with 645 additions and 28077 deletions
+1 -4
View File
@@ -5,8 +5,5 @@
# Каталог с данными
**/data/
**/config/
/config
**/logs/
Python/graph.png
*.rrd
+31
View File
@@ -1,3 +1,34 @@
<html>
<head>
<link rel="stylesheet" href="./myapp/static/css/bootstrap.min.css" />
<link rel="stylesheet" href="./myapp/static/css/font-awesome.min.css" />
<script type="text/javascript" src="./myapp/static/js/jquery-3.3.1.slim.min.js"></script>
<script type="text/javascript" src="./myapp/static/js/popper.min.js"></script>
<script type="text/javascript" src="./myapp/static/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container-fluid">
<h3>Описание</h3>
<p>Каркас веб-приложения на Flask</p>
<p>Структура каталогов для проекта (в частности на Flask) <a href="https://habr.com/post/421887/">https://habr.com/post/421887/</a></p>
<h3>Утилиты</h3>
<p>Добавление пользователя</p>
<pre>
./utils/useradd.py --user admin --password admin
</pre>
<p>Запуск из консоли</p>
<pre>
./run.py
</pre>
</div>
</body>
</html>
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.ru'
CONFIG = 'config.demo'
+33
View File
@@ -0,0 +1,33 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.ru'
import os
import sys
# Конфигурация
DEBUG = True
SQLDEBUG = False
SESSION_COOKIE_NAME = 'myapp'
SESSION_TYPE = 'filesystem'
TITLE = 'Проект'
DIR_BASE = '/'.join(os.path.dirname(os.path.abspath(__file__)).split('/')[:-1])
DIR_DATA = DIR_BASE + '/data'
DIR_FILES = DIR_DATA + '/files'
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + DIR_DATA + '/db.sqlite3'
# Генерировать можно утилитой pwgen
# Пример:
# pwgen -sy 64
SECRET_KEY = '''0123456789'''
# Логирование
LOG_FILE = DIR_DATA + '/myapp.log'
LONG_LOG_FORMAT = '%(asctime)s - [%(name)s.%(levelname)s] [%(threadName)s, %(module)s.%(funcName)s@%(lineno)d] %(message)s'
LOG_FILE_SIZE = 128 # Размер файла лога в МБ
+10
View File
@@ -0,0 +1,10 @@
server {
listen 80;
server_name myapp www.myapp;
access_log /var/log/nginx/myapp-access.log mainproxy;
error_log /var/log/nginx/myapp-error.log info;
location / {
include uwsgi_params;
uwsgi_pass unix:///var/run/uwsgi/myapp.sock;
}
}
@@ -3,3 +3,4 @@ flask
sqlalchemy
sqlalchemy-utils
alembic
celery
+8
View File
@@ -0,0 +1,8 @@
[uwsgi]
chdir = /home/user/myapp
logto = /home/user/myapp/logs/myapp.log
wsgi-file = /home/user/myapp/wsgi.py
py-autoreload = 10
uid = user
gid = user
+4 -7
View File
@@ -27,13 +27,10 @@ formatter = logging.Formatter(app.config['LONG_LOG_FORMAT'])
handler.setFormatter(formatter)
app.logger.addHandler(handler)
# celery
from celery import Celery
# API
from . import ns_api
celery = Celery(app.name,
broker=app.config['CELERY_BROKER_URL'],
backend=app.config['CELERY_RESULT_BACKEND'],
include=['myapp.tasks'])
celery.conf.update(app.config)
# Пользователи
from . import ns_user
from . import views
+14
View File
@@ -0,0 +1,14 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.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
__all__ = []
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.ru'
__url__ = 'http://remizoffalex.ru'
from flask import session, request
from .. import app, models
def get_user():
"""Получить текущего пользователя"""
result = None
if 'user_id' in session:
result = models.db_session.query(
models.User
).filter(
models.User.id==session['user_id']
).first()
if result is None:
session.pop('logged_in', None)
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
+56
View File
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.ru'
from math import ceil
def getpage(query, page=1, page_size=10):
"""
Постраничный вывод
"""
if page_size:
query = query.limit(page_size)
if page:
query = query.offset((page-1)*page_size)
return query
class Pagination(object):
"""
Пагинация
"""
def __init__(self, page, per_page, total_count):
self.page = page
self.per_page = per_page
self.total_count = total_count
@property
def pages(self):
return int(ceil(self.total_count / float(self.per_page)))
@property
def has_prev(self):
return self.page > 1
@property
def has_next(self):
return self.page < self.pages
def iter_pages(self, left_edge=2, left_current=2,
right_current=5, right_edge=2):
last = 0
for num in range(1, self.pages + 1):
if num <= left_edge or \
(num > self.page - left_current - 1 and \
num < self.page + right_current) or \
num > self.pages - right_edge:
if last + 1 != num:
yield None
yield num
last = num
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.ru'
import random
import hashlib
from .. import app
def pwgen(length=15, hex=False):
"""
Генератор пароля
"""
keylist='0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
if hex:
keylist='0123456789ABCDEF'
password=[]
while len(password) < length:
a_char = random.choice(keylist)
password.append(a_char)
return ''.join(password)
def get_hash_password(password, salt = None):
"""
Получить хеш пароля SHA-512
"""
if salt == None:
salt = uuid.uuid4().hex
text = password.encode('utf-8') + salt.encode('utf-8')
h = hashlib.sha512()
h.update(text)
return str(h.hexdigest())
+29
View File
@@ -0,0 +1,29 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.ru'
def gettree(number, count=3):
"""
Сформировать дерево каталогов
"""
result = []
newline = str(number)
while len(newline) % count:
newline = '0' + newline
for i in range(0, len(newline)//count):
result.append(newline[i*count:i*count+count])
return result
def gethashtree(hash, count=3):
"""
Сформировать дерево каталогов
"""
result = []
for i in range(0, count):
element = hash[2*i:2*(i+1)]
result.append(element)
return '/'.join(result)
+2 -16
View File
@@ -5,6 +5,7 @@ __author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.ru'
__url__ = 'http://remizoffalex.ru'
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
@@ -26,21 +27,6 @@ Base.query = db_session.query_property()
# Пользователи
from .users import User
# IP
from .ip import IP
# ACL
from .acl import (
ObjectPermission,
RolePermission,
RoleSetPermission,
UserPermission,
UserRole,
IPPermission
)
Base.metadata.create_all(engine)
__all__ = [
'db_session'
]
__all__ = []
-180
View File
@@ -1,180 +0,0 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.ru'
__url__ = 'http://remizoffalex.ru'
import datetime
from sqlalchemy import (
Table,
Column,
Boolean,
Integer,
ForeignKey,
String,
DateTime,
Enum
)
from sqlalchemy.orm import relationship
from . import Base
class ObjectPermission(Base):
"""
Объекты доступа: процедура и содержащий процедуру модуль
"""
__tablename__ = "object_permission"
id = Column(Integer, primary_key=True)
funcname = Column(String)
modulename = Column(String)
# Связи
user_permissions = relationship(
"UserPermission",
primaryjoin="ObjectPermission.id==UserPermission.object_id"
)
ip_permissions = relationship(
"IPPermission",
primaryjoin="ObjectPermission.id==IPPermission.object_id"
)
def __init__(self, modulename, funcname):
self.funcname = funcname
self.modulename = modulename
def __repr__(self):
return "<ObjectPermission('%s': '%s')>" % (self.funcname,
self.modulename)
class RolePermission(Base):
"""Роли доступа"""
__tablename__ = "role_permission"
id = Column(Integer, primary_key=True)
name = Column(String)
description = Column(String, default='')
# Связи
set_objects = relationship(
"RoleSetPermission",
primaryjoin="RolePermission.id==RoleSetPermission.role_id"
)
users = relationship(
"UserRole",
primaryjoin="RolePermission.id==UserRole.role_id"
)
def __init__(self, name):
self.name = name
class RoleSetPermission(Base):
"""Набор прав доступа для роли"""
__tablename__ = "role_set_permission"
id = Column(Integer, primary_key=True)
role_id = Column(Integer, ForeignKey('role_permission.id'))
object_id = Column(Integer, ForeignKey('object_permission.id'))
permission = Column(Enum('allow', 'deny')) # Разрешение
# Связи
role = relationship(
"RolePermission",
primaryjoin="RoleSetPermission.role_id==RolePermission.id",
uselist=False
)
object_permission = relationship(
"ObjectPermission",
primaryjoin="RoleSetPermission.object_id==ObjectPermission.id",
uselist=False
)
def __init__(self, role_permission, object_permission, permission):
self.role_id = role_permission.id
self.object_id = object_permission.id
self.permission = permission
class UserPermission(Base):
"""Права доступа пользователя"""
__tablename__ = "user_permission"
id = Column(Integer, primary_key=True)
object_id = Column(Integer, ForeignKey('object_permission.id'))
user_id = Column(Integer, ForeignKey('user.id'))
permission = Column(Enum('allow', 'deny')) # Разрешение
# Связи
user = relationship(
"User",
primaryjoin="UserPermission.user_id==User.id",
uselist=False
)
object_permission = relationship(
"ObjectPermission",
primaryjoin="UserPermission.object_id==ObjectPermission.id",
uselist=False
)
def __init__(self, object_permission, user, permission):
assert type(object_permission).__name__=='ObjectPermission', app.logger.info('Не передан объект ObjectPermission')
assert type(user).__name__=='User', app.logger.info('Не передан объект User')
self.object_id = object_permission.id
self.user_id = user.id
self.permission = permission
class UserRole(Base):
"""Роль пользователя"""
__tablename__ = "user_role"
id = Column(Integer, primary_key=True)
role_id = Column(Integer, ForeignKey('role_permission.id'))
user_id = Column(Integer, ForeignKey('user.id'))
# Связи
user = relationship(
"User",
primaryjoin="UserRole.user_id==User.id",
uselist=False
)
role_permission = relationship(
"RolePermission",
primaryjoin="UserRole.role_id==RolePermission.id",
uselist=False
)
def __init__(self, role_permission, user):
assert type(role_permission).__name__=='RolePermission', app.logger.info('Не передан объект RolePermission')
assert type(user).__name__=='User', app.logger.info('Не передан объект User')
self.role_id = role_permission.id
self.user_id = user.id
class IPPermission(Base):
"""
Права доступа для IP
"""
__tablename__ = "ip_permission"
id = Column(Integer, primary_key=True)
object_id = Column(Integer, ForeignKey('object_permission.id'))
ip_id = Column(Integer, ForeignKey('ip.id'))
permission = Column(Enum('allow', 'deny')) # Разрешение
# Связи
ip = relationship("IP", primaryjoin="IPPermission.ip_id==IP.id", uselist=False)
object_permission = relationship("ObjectPermission", primaryjoin="IPPermission.object_id==ObjectPermission.id", uselist=False)
def __init__(self, object_permission, ip, permission):
assert type(object_permission).__name__=='ObjectPermission', app.logger.info('Не передан объект ObjectPermission')
assert type(ip).__name__=='IP', app.logger.info('Не передан объект IP')
self.object_id = object_permission.id
self.ip_id = ip.id
self.permission = permission
-30
View File
@@ -1,30 +0,0 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.ru'
__url__ = 'http://remizoffalex.ru'
import datetime
from sqlalchemy import Table, Column, Boolean, Integer, ForeignKey, String, DateTime
from sqlalchemy.orm import relationship
from . import Base
class IP(Base):
__tablename__ = "ip"
id = Column(Integer, primary_key=True)
ip = Column(String, nullable=False, unique=True)
description = Column(String)
# Связи
# tagquestion = relationship("TagQuestion", primaryjoin="TagQuestion.tag_id==Tag.id")
def __init__(self, ip):
self.ip = ip
def __repr__(self):
return "<IP('%s')>" % (self.ip)
+17 -1
View File
@@ -5,21 +5,37 @@ __author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.ru'
__url__ = 'http://remizoffalex.ru'
import datetime
from sqlalchemy import Table, Column, Boolean, Integer, ForeignKey, String, DateTime
from sqlalchemy import (
Table,
Column,
Boolean,
Integer,
ForeignKey,
String,
DateTime
)
from sqlalchemy.orm import relationship
from . import Base
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False, unique=True)
password = Column(String, nullable=False)
disabled = Column(Boolean, default=True)
created = Column(DateTime)
def __init__(self, name):
self.name = name
self.created = datetime.datetime.utcnow()
def as_dict(self):
return {c.name: getattr(self, c.name)
for c in self.__table__.columns
if c.name!='password'}
+12
View File
@@ -0,0 +1,12 @@
<a href="https://github.com/cenobites/flask-jsonrpc">https://github.com/cenobites/flask-jsonrpc</a>
<pre>
curl -i -X POST \
-H "Content-Type: application/json; indent=4" \
-d '{
"jsonrpc": "2.0",
"method": "users.getList",
"params": {},
"id": "1"
}' http://localhost:8000/api
</pre>
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.ru'
__url__ = 'http://remizoffalex.ru'
from flask_jsonrpc import JSONRPC
from .. import app
jsonrpc = JSONRPC(app, '/api')
from . import user
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.ru'
__url__ = 'http://remizoffalex.ru'
from flask import abort, escape
from . import jsonrpc
from .. import models
@jsonrpc.method('users.getList')
def users_getList():
"""
Показать список пользователей
"""
users = models.db_session.query(
models.User
).all()
result = []
for item in users:
result.append(item.as_dict())
return result
+21
View File
@@ -0,0 +1,21 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__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
+67
View File
@@ -0,0 +1,67 @@
{% extends "skeleton.html" %}
{% block body %}
<h3>Список пользователей</h3>
<hr />
<div class="btn btn-outline-primary" v-on:click="getUserList()">Получить/обновить список пользователей</div>
{% raw %}
<div class="row" v-for="(user, userIdx) in users">
<div class="col py-2">
<a :href="'/user/' + user.id">{{ user.name }}</a>
<small class="text-muted">
<br />
Создан: {{ user.created }}
</small>
</div>
</div>
{% endraw %}
<backtotop-component></backtotop-component>
{% endblock %}
{% block breadcrumb %}
<ol class="breadcrumb mt-3">
<li class="breadcrumb-item"><a href="/"><i class="fa fa-home"></i></a></li>
<li class="breadcrumb-item">Список пользователей</li>
</ol>
{% endblock %}
{% block script %}
<script type="text/javascript" src="/static/components/backtotop.js"></script>
<link rel="stylesheet" href="/static/components/backtotop.css"></link>
<script type="text/javascript">
var app = new Vue({
el: '#app',
data: {
users: []
},
methods: {
getUserList: function() {
var vm = this;
axios.post(
'/api',
{
"jsonrpc": "2.0",
"method": 'users.getList',
"params": {
},
"id": 1
}
).then(
function(response) {
if ('result' in response.data) {
vm.users = response.data['result'];
}
}
);
}
}
})
</script>
{% endblock %}
+23
View File
@@ -0,0 +1,23 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.ru'
__url__ = 'http://remizoffalex.ru'
from flask import render_template
from .. import app
@app.route('/users')
def users():
"""
Список пользователей
"""
pagedata = {}
pagedata['title'] = 'Список пользователей - ' + app.config['TITLE']
body = render_template('users.html', pagedata=pagedata)
return body
+18
View File
@@ -0,0 +1,18 @@
.scrollToTop{
text-align: center;
font-weight: bold;
text-decoration: none;
position: fixed;
bottom: 10px;
left: 10px;
opacity: 0.3;
display: inline;
}
.scrollToTop:hover{
text-decoration: none;
opacity: 1.0;
}
.scrollToTop .card{
margin-bottom: 0;
border-color: #7ca8b1;
}
+53
View File
@@ -0,0 +1,53 @@
var backtotopTemplate = `
<div>
<span class="scrollToTop" style="z-index: 10;" v-show="visible" v-on:click="backToTop">
<div class="card">
<div class="card-body py-2 px-2">
<i class="fa fa-chevron-up"></i>
</div>
</div>
</span>
</div>`;
Vue.component('backtotop-component', {
props: {
visibleoffset: {
type: [String, Number],
default: 600
},
},
template: backtotopTemplate,
data () {
return {
visible: false
}
},
mounted () {
var vm = this;
window.addEventListener('scroll', this.catchScroll);
let currentScroll = document.documentElement.scrollTop || document.body.scrollTop
vm.visible = (currentScroll > 100);
},
destroyed () {
window.removeEventListener('scroll', this.catchScroll)
},
methods: {
catchScroll () {
var vm = this;
vm.visible = (window.pageYOffset > 100);
},
backToTop () {
var vm = this;
vm.scrollAnimate();
},
scrollAnimate: function() {
var vm = this;
let currentScroll = document.documentElement.scrollTop || document.body.scrollTop
if (currentScroll > 0) {
//alert(currentScroll);
window.requestAnimationFrame(vm.scrollAnimate)
window.scrollTo(0, Math.floor(currentScroll - (currentScroll / 5)))
}
}
}
});
-8899
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-2337
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+9
View File
File diff suppressed because one or more lines are too long
-3892
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-10253
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
+5
View File
File diff suppressed because one or more lines are too long
+6
View File
File diff suppressed because one or more lines are too long
+7 -5
View File
@@ -3,10 +3,12 @@
<meta name="author" content="Ремизов Александр" />
<meta name="copyright" lang="ru" content="RemiZOffAlex" />
<link rel="shortcut icon" href="/static/favicon.ico">
<link rel="stylesheet" href="/static/css/bootstrap.css" />
<link rel="stylesheet" href="/static/css/font-awesome.css" />
<script type="text/javascript" src="/static/js/jquery-3.2.1.js"></script>
<script type="text/javascript" src="/static/js/popper.js"></script>
<script type="text/javascript" src="/static/js/bootstrap.js"></script>
<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
<link rel="stylesheet" href="/static/css/font-awesome.min.css" />
<script type="text/javascript" src="/static/js/jquery-3.3.1.slim.min.js"></script>
<script type="text/javascript" src="/static/js/popper.min.js"></script>
<script type="text/javascript" src="/static/js/bootstrap.min.js"></script>
<script type="text/javascript" src="/static/js/vue.min.js"></script>
<script type="text/javascript" src="/static/js/axios.min.js"></script>
<title>{{ pagedata['title'] }}</title>
</head>
+7
View File
@@ -0,0 +1,7 @@
<div class="container-fluid py-2">
<a class="btn btn-outline-success border-0 float-right" href="/login"><i class="fa fa-sign-in"></i></a>
<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>
<a class="btn btn-outline-secondary border-0" href="/api/browse">API JSON-RPC</a>
</div>
+6 -1
View File
@@ -2,13 +2,18 @@
<html lang="ru">
{% include 'header.html' %}
<body>
<section id="app">
{% include 'topbar.html' %}
{% include 'navbar.html' %}
<div class="container">
{% block body %}
{% endblock %}
</div>
</section>
{% block script %}
{% endblock %}
</body>
</html>
-5
View File
@@ -1,5 +0,0 @@
<div class="container-fluid py-2">
<a class="btn btn-outline-success float-right" href="/login"><i class="fa fa-sign-in"></i></a>
<a class="btn btn-outline-secondary" href="/"><i class="fa fa-home"></i></a>
<a class="btn btn-outline-secondary" href="/edit"><i class="fa fa-edit"></i></a>
</div>
+58
View File
@@ -0,0 +1,58 @@
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
__author__ = 'RemiZOffAlex'
__copyright__ = '(c) RemiZOffAlex'
__license__ = 'MIT'
__email__ = 'remizoffalex@mail.ru'
__url__ = 'http://remizoffalex.ru'
import os
import sys
import argparse
import traceback
sys.path.insert(0, '/'.join(os.path.dirname(os.path.abspath(__file__)).split('/')[:-1]))
from myapp import app, lib, models
def main():
parser = argparse.ArgumentParser(description='Скрипт добавления пользователя',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser._optionals.title = "Необязательные аргументы"
parser.add_argument("--user", dest="user", required=True, help="Новый пользователь")
parser.add_argument("--password", dest="password", help="Новый пароль")
args = parser.parse_args()
user = models.db_session.query(
models.User
).filter(
models.User.name==args.user
).first()
if user:
app.logger.warning('Пользователь %s уже существует' % args.user)
sys.exit(1)
user = models.User(args.user)
if args.password is None:
args.password = lib.pwgen()
print('Пароль пользователя: {}'.format(args.password))
user.password = lib.get_hash_password(
args.password,
app.config['SECRET_KEY']
)
user.disabled = False
models.db_session.add(user)
models.db_session.commit()
app.logger.info('Пользователь %s успешно добавлен' % args.user)
if __name__ == "__main__":
try:
main()
except Exception as err:
traceback.print_exc(file=sys.stdout)
exit(1)
exit(0)