Reset repo
This commit is contained in:
parent
cd8467bfb7
commit
b5e82d3c33
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
# ---> Python
|
# ---> Python
|
||||||
# Byte-compiled / optimized / DLL files
|
# Byte-compiled / optimized / DLL files
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
#!/bin/python
|
|
||||||
import mimetypes
|
|
||||||
|
|
||||||
from flask import Flask, request, session
|
|
||||||
from flask import url_for
|
|
||||||
from flask_admin import helpers as admin_helpers
|
|
||||||
from flask_babelex import Babel
|
|
||||||
from flask_security import Security, SQLAlchemyUserDatastore
|
|
||||||
from flask_uploads import patch_request_class
|
|
||||||
|
|
||||||
from PDMI.blueprints.admin import admin
|
|
||||||
from PDMI.blueprints.api import api, api_0_0_1
|
|
||||||
from PDMI.blueprints.front import front
|
|
||||||
from PDMI.blueprints.documentation import documentation
|
|
||||||
from PDMI.blueprints.external import external
|
|
||||||
from PDMI.models import db, Users, Roles
|
|
||||||
from PDMI.views import main_bp
|
|
||||||
|
|
||||||
# Config mimetype
|
|
||||||
mimetypes.add_type('text/css', '.css')
|
|
||||||
mimetypes.add_type('text/javascript', '.js')
|
|
||||||
|
|
||||||
server = Flask(__name__)
|
|
||||||
|
|
||||||
# Load config
|
|
||||||
server.config.from_object('PDMI.config')
|
|
||||||
|
|
||||||
# Create database
|
|
||||||
db.init_app(server)
|
|
||||||
with server.app_context():
|
|
||||||
db.create_all(app=server)
|
|
||||||
|
|
||||||
# Setup Flask-security
|
|
||||||
user_datastore = SQLAlchemyUserDatastore(db, Users, Roles)
|
|
||||||
security = Security(server, user_datastore)
|
|
||||||
|
|
||||||
patch_request_class(server, 16 * 1024 * 1024)
|
|
||||||
|
|
||||||
# Setup babel
|
|
||||||
babel = Babel(server)
|
|
||||||
|
|
||||||
|
|
||||||
@babel.localeselector
|
|
||||||
def get_locale():
|
|
||||||
if request.args.get('lang'):
|
|
||||||
session['lang'] = request.args.get('lang')
|
|
||||||
return session.get('lang', 'fr')
|
|
||||||
|
|
||||||
|
|
||||||
@security.context_processor
|
|
||||||
def security_context_processor():
|
|
||||||
return dict(
|
|
||||||
admin_base_template=admin.base_template,
|
|
||||||
admin_view=admin.index_view,
|
|
||||||
h=admin_helpers,
|
|
||||||
get_url=url_for
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@server.context_processor
|
|
||||||
def utility_functions():
|
|
||||||
def print_in_console(message):
|
|
||||||
print(str(message))
|
|
||||||
|
|
||||||
return dict(mdebug=print_in_console)
|
|
||||||
|
|
||||||
|
|
||||||
# Register admin
|
|
||||||
admin.init_app(server)
|
|
||||||
|
|
||||||
# Register api
|
|
||||||
api.init_app(server)
|
|
||||||
api_0_0_1.init_app(server)
|
|
||||||
|
|
||||||
server.register_blueprint(front)
|
|
||||||
server.register_blueprint(documentation)
|
|
||||||
server.register_blueprint(external)
|
|
||||||
|
|
||||||
# Register main blueprint
|
|
||||||
server.register_blueprint(main_bp)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
server.run()
|
|
@ -1,147 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
import wtforms as wtf
|
|
||||||
from flask import url_for, request
|
|
||||||
from flask_admin import Admin, AdminIndexView, expose
|
|
||||||
from flask_admin.contrib import sqla
|
|
||||||
from flask_admin.contrib import fileadmin
|
|
||||||
from flask_admin.menu import MenuLink
|
|
||||||
from flask_security import current_user
|
|
||||||
from werkzeug.exceptions import abort
|
|
||||||
from werkzeug.utils import redirect
|
|
||||||
|
|
||||||
from PDMI.models import db, Users, Modules, ModuleVersions, Roles
|
|
||||||
|
|
||||||
|
|
||||||
# from server.main import security
|
|
||||||
# Pour les fichiers
|
|
||||||
# def _imagename_uuid1_gen(obj, file_data):
|
|
||||||
# _, ext = os.path.splitext(file_data.filename)
|
|
||||||
# uid = uuid.uuid1()
|
|
||||||
# return secure_filename('{}{}'.format(uid, ext))
|
|
||||||
|
|
||||||
|
|
||||||
class BooleanField(wtf.BooleanField):
|
|
||||||
"""Boolean field without form-control class"""
|
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
|
||||||
# Adding `readonly` property to `input` field
|
|
||||||
kwargs.update({'class': kwargs.get('class', '').replace("form-control", "")})
|
|
||||||
return super(BooleanField, self).__call__(*args, **kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigurableView(sqla.ModelView):
|
|
||||||
roles = []
|
|
||||||
details_modal = True
|
|
||||||
edit_modal = True
|
|
||||||
create_modal = True
|
|
||||||
|
|
||||||
def is_accessible(self):
|
|
||||||
if not current_user.is_active or not current_user.is_authenticated:
|
|
||||||
return False
|
|
||||||
if current_user.has_role("superadmin"):
|
|
||||||
return True
|
|
||||||
for role in self.roles:
|
|
||||||
if current_user.has_role(role):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _handle_view(self, name, **kwargs):
|
|
||||||
"""
|
|
||||||
Override builtin _handle_view in order to redirect users when a view is not accessible.
|
|
||||||
"""
|
|
||||||
if not self.is_accessible():
|
|
||||||
if current_user.is_authenticated:
|
|
||||||
# permission denied
|
|
||||||
abort(403)
|
|
||||||
else:
|
|
||||||
# login
|
|
||||||
return redirect(url_for('security.login', next=request.url))
|
|
||||||
|
|
||||||
|
|
||||||
class SuperUserView(ConfigurableView):
|
|
||||||
roles = []
|
|
||||||
# Affichage de la table
|
|
||||||
column_editable_list = ['active', 'username', 'email', ]
|
|
||||||
column_searchable_list = ['active', 'username', 'email', ]
|
|
||||||
column_filters = ['active', 'username', 'email', 'roles', ]
|
|
||||||
column_exclude_list = ['password', ]
|
|
||||||
# Formulaire
|
|
||||||
form_excluded_columns = ['password', ]
|
|
||||||
form_columns = ['username', 'email', 'roles', 'active', ]
|
|
||||||
form_overrides = {
|
|
||||||
"active": BooleanField,
|
|
||||||
}
|
|
||||||
# Details
|
|
||||||
column_details_exclude_list = ['password', ]
|
|
||||||
|
|
||||||
class RolesView(ConfigurableView):
|
|
||||||
roles = []
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ModuleView(ConfigurableView):
|
|
||||||
inline_models = (
|
|
||||||
(
|
|
||||||
ModuleVersions,
|
|
||||||
{
|
|
||||||
'form_label': "Versions",
|
|
||||||
'form_columns': ('id', 'version',)
|
|
||||||
}
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Index view
|
|
||||||
class IndexView(AdminIndexView):
|
|
||||||
@expose('/')
|
|
||||||
def index(self):
|
|
||||||
return self.render('admin/index.html')
|
|
||||||
|
|
||||||
|
|
||||||
admin = Admin( # server,
|
|
||||||
index_view=IndexView(menu_icon_type='fa',
|
|
||||||
menu_icon_value='fa-home', ),
|
|
||||||
name='PDMI',
|
|
||||||
template_mode='bootstrap3',
|
|
||||||
category_icon_classes={
|
|
||||||
'Administration': 'fa fa-cogs',
|
|
||||||
},
|
|
||||||
endpoint='administration',
|
|
||||||
disconnect_route="security.logout",
|
|
||||||
connect_route="security.login",
|
|
||||||
favicon="favicon.ico"
|
|
||||||
)
|
|
||||||
|
|
||||||
admin.add_view(SuperUserView(
|
|
||||||
Users,
|
|
||||||
db.session,
|
|
||||||
menu_icon_type='fa',
|
|
||||||
menu_icon_value='fa-users',
|
|
||||||
name="Administrateurs",
|
|
||||||
category="Administration",
|
|
||||||
endpoint="admin.users"
|
|
||||||
))
|
|
||||||
|
|
||||||
admin.add_view(RolesView(
|
|
||||||
Roles,
|
|
||||||
db.session,
|
|
||||||
menu_icon_type='fa',
|
|
||||||
menu_icon_value='fa-users',
|
|
||||||
name="Roles",
|
|
||||||
category="Administration",
|
|
||||||
endpoint="admin.roles"
|
|
||||||
))
|
|
||||||
|
|
||||||
admin.add_view(ModuleView(
|
|
||||||
Modules,
|
|
||||||
db.session,
|
|
||||||
menu_icon_type="fa",
|
|
||||||
menu_icon_value="fa-gears",
|
|
||||||
name="Modules",
|
|
||||||
category="Modules",
|
|
||||||
endpoint="admin.modules"
|
|
||||||
))
|
|
||||||
|
|
||||||
admin.add_view(fileadmin.FileAdmin('modules',
|
|
||||||
'/files/', name='Module Files'))
|
|
@ -1,28 +0,0 @@
|
|||||||
from flask_restful import Api
|
|
||||||
|
|
||||||
from PDMI.blueprints.api.download import ApiIndex, ApiModuleList, ApiModuleVersions, ApiModuleGet
|
|
||||||
|
|
||||||
# Current version
|
|
||||||
api = Api(prefix="/api/current")
|
|
||||||
|
|
||||||
api.add_resource(ApiIndex, '/',
|
|
||||||
endpoint='api.download.index')
|
|
||||||
api.add_resource(ApiModuleList, "/modules/",
|
|
||||||
endpoint="api.download.modules.list")
|
|
||||||
api.add_resource(ApiModuleVersions, "/modules/<string:module>/",
|
|
||||||
endpoint="api.download.modules.versions")
|
|
||||||
api.add_resource(ApiModuleGet, "/modules/<string:module>/<string:version>/",
|
|
||||||
endpoint="api.download.modules.get")
|
|
||||||
|
|
||||||
# Version 0.0.1
|
|
||||||
|
|
||||||
api_0_0_1 = Api(prefix="/api/v/0.0.1")
|
|
||||||
|
|
||||||
api_0_0_1.add_resource(ApiIndex, '/',
|
|
||||||
endpoint='api.0_0_1.download.index')
|
|
||||||
api_0_0_1.add_resource(ApiModuleList, "/modules/",
|
|
||||||
endpoint="api.0_0_1.download.modules.list")
|
|
||||||
api_0_0_1.add_resource(ApiModuleVersions, "/modules/<string:module>/",
|
|
||||||
endpoint="api.0_0_1.download.modules.versions")
|
|
||||||
api_0_0_1.add_resource(ApiModuleGet, "/modules/<string:module>/<string:version>/",
|
|
||||||
endpoint="api.0_0_1.download.modules.get")
|
|
@ -1,42 +0,0 @@
|
|||||||
import os
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
from flask import send_from_directory
|
|
||||||
from flask_restful import Resource, abort
|
|
||||||
|
|
||||||
from PDMI.models import Modules
|
|
||||||
|
|
||||||
|
|
||||||
class ApiIndex(Resource):
|
|
||||||
def get(self):
|
|
||||||
return {
|
|
||||||
"api version": "0.0.1"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class ApiModuleList(Resource):
|
|
||||||
def get(self):
|
|
||||||
modules = Modules.query.filter().all()
|
|
||||||
return {module.name: [version.version for version in module.versions] for module in modules}
|
|
||||||
|
|
||||||
|
|
||||||
class ApiModuleVersions(Resource):
|
|
||||||
def get(self, module):
|
|
||||||
module = Modules.query.filter_by(name=module).first_or_404()
|
|
||||||
return {"versions": [version.version for version in module.versions]}
|
|
||||||
|
|
||||||
|
|
||||||
class ApiModuleGet(Resource):
|
|
||||||
def get(self, module, version):
|
|
||||||
module = Modules.query.filter_by(name=module).first_or_404()
|
|
||||||
versions = [version.version for version in module.versions]
|
|
||||||
if version not in versions:
|
|
||||||
abort(404)
|
|
||||||
print(os.getcwd())
|
|
||||||
if not os.path.exists(os.path.join("PDMI", "modules", module.name, version + ".zip")):
|
|
||||||
shutil.make_archive(os.path.join("PDMI", "modules", module.name, version), 'zip',
|
|
||||||
os.path.join("PDMI", "modules", module.name, version))
|
|
||||||
return send_from_directory(
|
|
||||||
os.path.join("modules", module.name, ),
|
|
||||||
version + ".zip"
|
|
||||||
)
|
|
@ -1,17 +0,0 @@
|
|||||||
from flask import Blueprint, render_template, abort
|
|
||||||
|
|
||||||
documentation = Blueprint('documentation', __name__, template_folder="templates", url_prefix="/documentation")
|
|
||||||
|
|
||||||
|
|
||||||
@documentation.route("/")
|
|
||||||
def index():
|
|
||||||
return render_template("documentation/index.html")
|
|
||||||
|
|
||||||
|
|
||||||
@documentation.route("/create_module")
|
|
||||||
def create_module():
|
|
||||||
return render_template("documentation/create_module.html")
|
|
||||||
|
|
||||||
@documentation.route("/create_repository")
|
|
||||||
def create_repository():
|
|
||||||
return render_template("documentation/create_repository.html")
|
|
13
PDMI/blueprints/external/__init__.py
vendored
13
PDMI/blueprints/external/__init__.py
vendored
@ -1,13 +0,0 @@
|
|||||||
from flask import Blueprint, render_template, abort
|
|
||||||
|
|
||||||
external = Blueprint('external', __name__, template_folder="templates")
|
|
||||||
|
|
||||||
|
|
||||||
@external.route("/external/download")
|
|
||||||
def download():
|
|
||||||
return redirect("https://moriya.zapto.org/PDBA/bot-base", code=302)
|
|
||||||
|
|
||||||
@external.route("/external/download_server")
|
|
||||||
def download_server():
|
|
||||||
return redirect("https://moriya.zapto.org/PDBA/PDMI", code=302)
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
|||||||
from flask import Blueprint, render_template, abort, send_from_directory
|
|
||||||
|
|
||||||
front = Blueprint('front', __name__, template_folder="templates")
|
|
||||||
|
|
||||||
|
|
||||||
@front.route('/favicon.ico')
|
|
||||||
def favicon():
|
|
||||||
return send_from_directory('static', 'favicon.ico', mimetype='image/vnd.microsoft.icon')
|
|
||||||
|
|
||||||
|
|
||||||
@front.route("/")
|
|
||||||
def index():
|
|
||||||
return render_template("front/index.html")
|
|
@ -1,47 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
# ======================================================================================================================
|
|
||||||
# ===================================================== general ========================================================
|
|
||||||
# ======================================================================================================================
|
|
||||||
# Secret key for decode cookies, generate new one for prod server, never share it
|
|
||||||
SECRET_KEY = "SECRET_KEY" # TODO
|
|
||||||
# Enable debug mode
|
|
||||||
DEBUG = True # TODO
|
|
||||||
# ======================================================================================================================
|
|
||||||
# =================================================== sqlalchemy =======================================================
|
|
||||||
# ======================================================================================================================
|
|
||||||
SQLALCHEMY_DATABASE_URI = "mysql+pymysql://"+os.environ["DATABASE_USER"]+":"+os.environ["DATABASE_PASSWORD"]+\
|
|
||||||
"@"+os.environ["DATABASE_HOST"]+":"+os.environ["DATABASE_PORT"]+"/"\
|
|
||||||
+os.environ["DATABASE_NAME"]
|
|
||||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
|
||||||
|
|
||||||
# ======================================================================================================================
|
|
||||||
# ================================================= flask-security =====================================================
|
|
||||||
# ======================================================================================================================
|
|
||||||
# Protected urls
|
|
||||||
SECURITY_URL_PREFIX = "/admin"
|
|
||||||
|
|
||||||
# Pasword config
|
|
||||||
SECURITY_PASSWORD_HASH = "pbkdf2_sha512"
|
|
||||||
# Secret salt for password, generate new one for prod server, never share it
|
|
||||||
SECURITY_PASSWORD_SALT = "ATGUOHAELKiubahiughaerGOJAEGj" # TODO
|
|
||||||
|
|
||||||
# Urls for login/logout/register
|
|
||||||
SECURITY_LOGIN_URL = "/login/"
|
|
||||||
SECURITY_LOGOUT_URL = "/logout/"
|
|
||||||
SECURITY_REGISTER_URL = "/register/"
|
|
||||||
|
|
||||||
# Urls for page just after login/logout/register
|
|
||||||
SECURITY_POST_LOGIN_VIEW = "/admin/"
|
|
||||||
SECURITY_POST_LOGOUT_VIEW = "/admin/"
|
|
||||||
SECURITY_POST_REGISTER_VIEW = "/admin/"
|
|
||||||
|
|
||||||
# Features
|
|
||||||
SECURITY_REGISTERABLE = True
|
|
||||||
# todo: How can I activate that properly?
|
|
||||||
SECURITY_SEND_REGISTER_EMAIL = False # TODO
|
|
||||||
|
|
||||||
# ======================================================================================================================
|
|
||||||
# =================================================== flask-babel ======================================================
|
|
||||||
# ======================================================================================================================
|
|
||||||
BABEL_DEFAULT_LOCALE = "fr_FR"
|
|
@ -1,54 +0,0 @@
|
|||||||
import datetime
|
|
||||||
|
|
||||||
from flask_security import RoleMixin, UserMixin
|
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
|
||||||
|
|
||||||
db = SQLAlchemy()
|
|
||||||
|
|
||||||
roles_users = db.Table(
|
|
||||||
'roles_users',
|
|
||||||
db.Column('user_id', db.Integer(), db.ForeignKey('users.id', ondelete='CASCADE')),
|
|
||||||
db.Column('role_id', db.Integer(), db.ForeignKey('roles.id', ondelete='CASCADE'))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Roles(db.Model, RoleMixin):
|
|
||||||
__tablename__ = "roles"
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
name = db.Column(db.String(80), unique=True)
|
|
||||||
description = db.Column(db.String(255))
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
|
|
||||||
class Modules(db.Model):
|
|
||||||
__tablename__ = "modules"
|
|
||||||
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
|
||||||
name = db.Column(db.String(100))
|
|
||||||
versions = db.relationship('ModuleVersions', backref='modules', lazy=True)
|
|
||||||
|
|
||||||
|
|
||||||
class ModuleVersions(db.Model):
|
|
||||||
__tablename__ = "moduleversions"
|
|
||||||
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
|
|
||||||
version = db.Column(db.String(10))
|
|
||||||
module_id = db.Column(db.Integer, db.ForeignKey('modules.id'), nullable=False)
|
|
||||||
|
|
||||||
|
|
||||||
class Users(db.Model, UserMixin):
|
|
||||||
__tablename__ = "users"
|
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
|
||||||
date_created = db.Column(db.DateTime, default=datetime.datetime.utcnow)
|
|
||||||
username = db.Column(db.String(100))
|
|
||||||
email = db.Column(db.String(100), unique=True)
|
|
||||||
password = db.Column(db.String(200))
|
|
||||||
active = db.Column(db.Boolean)
|
|
||||||
roles = db.relationship('Roles', secondary=roles_users,
|
|
||||||
backref=db.backref('users', lazy='dynamic'))
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return str(self.username)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return str(self.username)
|
|
@ -1,19 +0,0 @@
|
|||||||
from modules.base import BaseClass
|
|
||||||
|
|
||||||
|
|
||||||
class MainClass(BaseClass):
|
|
||||||
name = "Panic"
|
|
||||||
help_active = True
|
|
||||||
help = {
|
|
||||||
"description": "Dans quel état est Nikola Tesla",
|
|
||||||
"commands": {
|
|
||||||
"`{prefix}{command}`": "Donne l'état actuel de Nikola Tesla",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
command_text = "panic"
|
|
||||||
|
|
||||||
async def command(self, message, args, kwargs):
|
|
||||||
temperature = 0
|
|
||||||
with open("/sys/class/thermal/thermal_zone0/temp") as f:
|
|
||||||
temperature = int(f.read().rstrip("\n")) / 1000
|
|
||||||
await message.channel.send("Nikola est à {temperature}°C".format(temperature=temperature))
|
|
@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"version": "0.1.0",
|
|
||||||
"dependencies": {
|
|
||||||
"base": {
|
|
||||||
"min": "0.1.0",
|
|
||||||
"max": "0.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"bot_version": {
|
|
||||||
"min": "0.1.0",
|
|
||||||
"max": "0.1.0"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
from modules.base import BaseClass
|
|
||||||
|
|
||||||
|
|
||||||
class MainClass(BaseClass):
|
|
||||||
name = "Panic"
|
|
||||||
help_active = True
|
|
||||||
help = {
|
|
||||||
"description": "Dans quel état est Nikola TeslaTOTOTOTOTOTOTOTOTOTOTOTOTOTOTOTOTOTOOTOTOTOTOTOTOTOTOT",
|
|
||||||
"commands": {
|
|
||||||
"`{prefix}{command}`": "Donne l'état actuel de Nikola Tesla",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
command_text = "panic"
|
|
||||||
|
|
||||||
async def command(self, message, args, kwargs):
|
|
||||||
temperature = 0
|
|
||||||
with open("/sys/class/thermal/thermal_zone0/temp") as f:
|
|
||||||
temperature = int(f.read().rstrip("\n")) / 1000
|
|
||||||
await message.channel.send("Nikola est à {temperature}°C".format(temperature=temperature))
|
|
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "panic",
|
|
||||||
"version": "0.0.2",
|
|
||||||
"requirement": {
|
|
||||||
"base": {
|
|
||||||
"min": "0.0.2",
|
|
||||||
"max": "0.0.2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
Before Width: | Height: | Size: 36 KiB |
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
File diff suppressed because one or more lines are too long
@ -1,331 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
|
|
||||||
* Copyright 2011-2019 The Bootstrap Authors
|
|
||||||
* Copyright 2011-2019 Twitter, Inc.
|
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
||||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
|
||||||
*/
|
|
||||||
*,
|
|
||||||
*::before,
|
|
||||||
*::after {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-family: sans-serif;
|
|
||||||
line-height: 1.15;
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: #212529;
|
|
||||||
text-align: left;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
[tabindex="-1"]:focus {
|
|
||||||
outline: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
box-sizing: content-box;
|
|
||||||
height: 0;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
abbr[title],
|
|
||||||
abbr[data-original-title] {
|
|
||||||
text-decoration: underline;
|
|
||||||
-webkit-text-decoration: underline dotted;
|
|
||||||
text-decoration: underline dotted;
|
|
||||||
cursor: help;
|
|
||||||
border-bottom: 0;
|
|
||||||
-webkit-text-decoration-skip-ink: none;
|
|
||||||
text-decoration-skip-ink: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
address {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
font-style: normal;
|
|
||||||
line-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol,
|
|
||||||
ul,
|
|
||||||
dl {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol ol,
|
|
||||||
ul ul,
|
|
||||||
ol ul,
|
|
||||||
ul ol {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dt {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
dd {
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
margin: 0 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
b,
|
|
||||||
strong {
|
|
||||||
font-weight: bolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub,
|
|
||||||
sup {
|
|
||||||
position: relative;
|
|
||||||
font-size: 75%;
|
|
||||||
line-height: 0;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub {
|
|
||||||
bottom: -.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
sup {
|
|
||||||
top: -.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #007bff;
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #0056b3;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]) {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]):focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre,
|
|
||||||
code,
|
|
||||||
kbd,
|
|
||||||
samp {
|
|
||||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
figure {
|
|
||||||
margin: 0 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
vertical-align: middle;
|
|
||||||
border-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
overflow: hidden;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
caption {
|
|
||||||
padding-top: 0.75rem;
|
|
||||||
padding-bottom: 0.75rem;
|
|
||||||
color: #6c757d;
|
|
||||||
text-align: left;
|
|
||||||
caption-side: bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
text-align: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: inline-block;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:focus {
|
|
||||||
outline: 1px dotted;
|
|
||||||
outline: 5px auto -webkit-focus-ring-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
button,
|
|
||||||
select,
|
|
||||||
optgroup,
|
|
||||||
textarea {
|
|
||||||
margin: 0;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
line-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
input {
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
select {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
word-wrap: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
[type="button"],
|
|
||||||
[type="reset"],
|
|
||||||
[type="submit"] {
|
|
||||||
-webkit-appearance: button;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:not(:disabled),
|
|
||||||
[type="button"]:not(:disabled),
|
|
||||||
[type="reset"]:not(:disabled),
|
|
||||||
[type="submit"]:not(:disabled) {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
button::-moz-focus-inner,
|
|
||||||
[type="button"]::-moz-focus-inner,
|
|
||||||
[type="reset"]::-moz-focus-inner,
|
|
||||||
[type="submit"]::-moz-focus-inner {
|
|
||||||
padding: 0;
|
|
||||||
border-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="radio"],
|
|
||||||
input[type="checkbox"] {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="date"],
|
|
||||||
input[type="time"],
|
|
||||||
input[type="datetime-local"],
|
|
||||||
input[type="month"] {
|
|
||||||
-webkit-appearance: listbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
overflow: auto;
|
|
||||||
resize: vertical;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
min-width: 0;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
legend {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
padding: 0;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
line-height: inherit;
|
|
||||||
color: inherit;
|
|
||||||
white-space: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
progress {
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="number"]::-webkit-inner-spin-button,
|
|
||||||
[type="number"]::-webkit-outer-spin-button {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="search"] {
|
|
||||||
outline-offset: -2px;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="search"]::-webkit-search-decoration {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-file-upload-button {
|
|
||||||
font: inherit;
|
|
||||||
-webkit-appearance: button;
|
|
||||||
}
|
|
||||||
|
|
||||||
output {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
summary {
|
|
||||||
display: list-item;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
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
File diff suppressed because one or more lines are too long
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
File diff suppressed because one or more lines are too long
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
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 36 KiB |
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
File diff suppressed because one or more lines are too long
@ -1,331 +0,0 @@
|
|||||||
/*!
|
|
||||||
* Bootstrap Reboot v4.3.1 (https://getbootstrap.com/)
|
|
||||||
* Copyright 2011-2019 The Bootstrap Authors
|
|
||||||
* Copyright 2011-2019 Twitter, Inc.
|
|
||||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
|
||||||
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
|
|
||||||
*/
|
|
||||||
*,
|
|
||||||
*::before,
|
|
||||||
*::after {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
font-family: sans-serif;
|
|
||||||
line-height: 1.15;
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
|
||||||
font-size: 1rem;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: #212529;
|
|
||||||
text-align: left;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
[tabindex="-1"]:focus {
|
|
||||||
outline: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
box-sizing: content-box;
|
|
||||||
height: 0;
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
abbr[title],
|
|
||||||
abbr[data-original-title] {
|
|
||||||
text-decoration: underline;
|
|
||||||
-webkit-text-decoration: underline dotted;
|
|
||||||
text-decoration: underline dotted;
|
|
||||||
cursor: help;
|
|
||||||
border-bottom: 0;
|
|
||||||
-webkit-text-decoration-skip-ink: none;
|
|
||||||
text-decoration-skip-ink: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
address {
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
font-style: normal;
|
|
||||||
line-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol,
|
|
||||||
ul,
|
|
||||||
dl {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol ol,
|
|
||||||
ul ul,
|
|
||||||
ol ul,
|
|
||||||
ul ol {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dt {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
dd {
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
margin: 0 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
b,
|
|
||||||
strong {
|
|
||||||
font-weight: bolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
small {
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub,
|
|
||||||
sup {
|
|
||||||
position: relative;
|
|
||||||
font-size: 75%;
|
|
||||||
line-height: 0;
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub {
|
|
||||||
bottom: -.25em;
|
|
||||||
}
|
|
||||||
|
|
||||||
sup {
|
|
||||||
top: -.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #007bff;
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #0056b3;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]) {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]):hover, a:not([href]):not([tabindex]):focus {
|
|
||||||
color: inherit;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:not([href]):not([tabindex]):focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre,
|
|
||||||
code,
|
|
||||||
kbd,
|
|
||||||
samp {
|
|
||||||
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
figure {
|
|
||||||
margin: 0 0 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
vertical-align: middle;
|
|
||||||
border-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
svg {
|
|
||||||
overflow: hidden;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
|
|
||||||
caption {
|
|
||||||
padding-top: 0.75rem;
|
|
||||||
padding-bottom: 0.75rem;
|
|
||||||
color: #6c757d;
|
|
||||||
text-align: left;
|
|
||||||
caption-side: bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
th {
|
|
||||||
text-align: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
label {
|
|
||||||
display: inline-block;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:focus {
|
|
||||||
outline: 1px dotted;
|
|
||||||
outline: 5px auto -webkit-focus-ring-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
button,
|
|
||||||
select,
|
|
||||||
optgroup,
|
|
||||||
textarea {
|
|
||||||
margin: 0;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: inherit;
|
|
||||||
line-height: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
input {
|
|
||||||
overflow: visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
select {
|
|
||||||
text-transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
word-wrap: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
[type="button"],
|
|
||||||
[type="reset"],
|
|
||||||
[type="submit"] {
|
|
||||||
-webkit-appearance: button;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:not(:disabled),
|
|
||||||
[type="button"]:not(:disabled),
|
|
||||||
[type="reset"]:not(:disabled),
|
|
||||||
[type="submit"]:not(:disabled) {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
button::-moz-focus-inner,
|
|
||||||
[type="button"]::-moz-focus-inner,
|
|
||||||
[type="reset"]::-moz-focus-inner,
|
|
||||||
[type="submit"]::-moz-focus-inner {
|
|
||||||
padding: 0;
|
|
||||||
border-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="radio"],
|
|
||||||
input[type="checkbox"] {
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
input[type="date"],
|
|
||||||
input[type="time"],
|
|
||||||
input[type="datetime-local"],
|
|
||||||
input[type="month"] {
|
|
||||||
-webkit-appearance: listbox;
|
|
||||||
}
|
|
||||||
|
|
||||||
textarea {
|
|
||||||
overflow: auto;
|
|
||||||
resize: vertical;
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldset {
|
|
||||||
min-width: 0;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
legend {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
padding: 0;
|
|
||||||
margin-bottom: .5rem;
|
|
||||||
font-size: 1.5rem;
|
|
||||||
line-height: inherit;
|
|
||||||
color: inherit;
|
|
||||||
white-space: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
progress {
|
|
||||||
vertical-align: baseline;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="number"]::-webkit-inner-spin-button,
|
|
||||||
[type="number"]::-webkit-outer-spin-button {
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="search"] {
|
|
||||||
outline-offset: -2px;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
[type="search"]::-webkit-search-decoration {
|
|
||||||
-webkit-appearance: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-file-upload-button {
|
|
||||||
font: inherit;
|
|
||||||
-webkit-appearance: button;
|
|
||||||
}
|
|
||||||
|
|
||||||
output {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
summary {
|
|
||||||
display: list-item;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
template {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
[hidden] {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/*# sourceMappingURL=bootstrap-reboot.css.map */
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
10038
PDMI/static/front/vendor/bootstrap-4.3.1/css/bootstrap.css
vendored
10038
PDMI/static/front/vendor/bootstrap-4.3.1/css/bootstrap.css
vendored
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
File diff suppressed because one or more lines are too long
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
File diff suppressed because one or more lines are too long
4435
PDMI/static/front/vendor/bootstrap-4.3.1/js/bootstrap.js
vendored
4435
PDMI/static/front/vendor/bootstrap-4.3.1/js/bootstrap.js
vendored
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
File diff suppressed because one or more lines are too long
@ -1,49 +0,0 @@
|
|||||||
{% extends 'admin/master.html' %}
|
|
||||||
{% block body %}
|
|
||||||
{{ super() }}
|
|
||||||
|
|
||||||
{% if current_user.is_authenticated %}
|
|
||||||
|
|
||||||
<!-- Content Header (Page header) -->
|
|
||||||
<section class="content-header">
|
|
||||||
<h1>
|
|
||||||
Tableau de bord
|
|
||||||
<small>Panneau de contrôle</small>
|
|
||||||
</h1>
|
|
||||||
<ol class="breadcrumb">
|
|
||||||
<li><a href="#"><i class="fa fa-dashboard"></i> Tableau de bord</a></li>
|
|
||||||
<li class="active">Panneau de contrôle</li>
|
|
||||||
</ol>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="content">
|
|
||||||
{# todo: Fill index page #}
|
|
||||||
</section>
|
|
||||||
<!-- /.content -->
|
|
||||||
{% else %}
|
|
||||||
|
|
||||||
<section class="content" style="color: white;text-align: center;height:100%;width: 50%;
|
|
||||||
margin: 0 auto;">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<h1>LBI - PiPy</h1>
|
|
||||||
<p class="lead">
|
|
||||||
Connection
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Pour accéder à l'interface d'administration veuillez utiliser vos identifiants.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<a class="btn btn-primary" href="{{ url_for('security.login') }}">Connection</a>
|
|
||||||
</p>
|
|
||||||
<br>
|
|
||||||
<p>
|
|
||||||
<a class="btn btn-primary" href="/"><i class="glyphicon glyphicon-chevron-left"></i> Retour</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<br><br><br><br><br><br><br><br><br>
|
|
||||||
<br><br><br><br><br><br><br><br><br><br>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endblock body %}
|
|
@ -1 +0,0 @@
|
|||||||
{% extends admin_base_template %}
|
|
@ -1,20 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<title>{% block title %}PDMI - Documentation{% endblock %}</title>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta name="description" content="PDMI - Python Discord Module Index">
|
|
||||||
<meta name="author" content="Louis Chauvet">
|
|
||||||
<!-- Favicon.ico -->
|
|
||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
|
||||||
|
|
||||||
<link href="{{ url_for('static', filename='documentation/vendor/bootstrap-4.3.1/css/bootstrap.css') }}" rel="stylesheet">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{% include "front/base/navbar.html" %}
|
|
||||||
{% block body %}
|
|
||||||
{% endblock %}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,5 +0,0 @@
|
|||||||
{% extends 'documentation/base/base.html' %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
create_module
|
|
||||||
{% endblock %}
|
|
@ -1,5 +0,0 @@
|
|||||||
{% extends 'documentation/base/base.html' %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
create_repository
|
|
||||||
{% endblock %}
|
|
@ -1,5 +0,0 @@
|
|||||||
{% extends 'documentation/base/base.html' %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
index
|
|
||||||
{% endblock %}
|
|
@ -1,20 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<title>{% block title %}PDMI - Python Discord Module Index{% endblock %}</title>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta name="description" content="PDMI - Python Discord Module Index">
|
|
||||||
<meta name="author" content="Louis Chauvet">
|
|
||||||
<!-- Favicon.ico -->
|
|
||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
|
||||||
|
|
||||||
<link href="{{ url_for('static', filename='front/vendor/bootstrap-4.3.1/css/bootstrap.css') }}" rel="stylesheet">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
{% include "front/base/navbar.html" %}
|
|
||||||
{% block body %}
|
|
||||||
{% endblock %}
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,31 +0,0 @@
|
|||||||
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
|
|
||||||
<a class="navbar-brand" href="#">P.D.M.I</a>
|
|
||||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="collapse navbar-collapse" id="navbarsExampleDefault">
|
|
||||||
<ul class="navbar-nav mr-auto">
|
|
||||||
<li class="nav-item active">
|
|
||||||
<a class="nav-link" href="{{ url_for('front.index') }}">Home <span class="sr-only">(current)</span></a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="{{ url_for('documentation.index') }}">Documentation</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Download</a>
|
|
||||||
<div class="dropdown-menu" aria-labelledby="dropdown01">
|
|
||||||
<a class="dropdown-item" href="{{ url_for('external.download') }}">Download bot</a>
|
|
||||||
<a class="dropdown-item" href="{{ url_for('external.download_server') }}">Download server</a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item">
|
|
||||||
<a class="nav-link" href="{{ url_for('admin.index') }}">Gestion des modules</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<form class="form-inline my-2 my-lg-0">
|
|
||||||
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
|
|
||||||
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
@ -1,69 +0,0 @@
|
|||||||
{% extends 'front/base/base.html' %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
|
|
||||||
|
|
||||||
<main role="main">
|
|
||||||
|
|
||||||
<!-- Main jumbotron for a primary marketing message or call to action -->
|
|
||||||
<div class="jumbotron">
|
|
||||||
<div class="container">
|
|
||||||
<h1 class="display-3">PDMI - Python Discord Module Index</h1>
|
|
||||||
<p>
|
|
||||||
PDMI is a part of PDBA project. PDBA is a basic discord bot which integrate possibility to install
|
|
||||||
modules.
|
|
||||||
PDMI is the website where most of modules are uploaded. If you want to create your own module you can
|
|
||||||
check
|
|
||||||
<a href="{{ url_for('documentation.create_module') }}">documentation</a>. You can also create your own
|
|
||||||
<a href="{{ url_for('documentation.create_repository') }}">repository</a>.
|
|
||||||
</p>
|
|
||||||
<p><a class="btn btn-primary btn-lg" href="{{ url_for('documentation.index') }}" role="button">Learn more
|
|
||||||
»</a></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{#
|
|
||||||
<div class="container">
|
|
||||||
<!-- Example row of columns -->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<h2>Heading</h2>
|
|
||||||
<p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor
|
|
||||||
mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna
|
|
||||||
mollis euismod. Donec sed odio dui. </p>
|
|
||||||
<p><a class="btn btn-secondary" href="#" role="button">View details »</a></p>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<h2>Heading</h2>
|
|
||||||
<p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor
|
|
||||||
mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna
|
|
||||||
mollis euismod. Donec sed odio dui. </p>
|
|
||||||
<p><a class="btn btn-secondary" href="#" role="button">View details »</a></p>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<h2>Heading</h2>
|
|
||||||
<p>Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula
|
|
||||||
porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh,
|
|
||||||
ut fermentum massa justo sit amet risus.</p>
|
|
||||||
<p><a class="btn btn-secondary" href="#" role="button">View details »</a></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
</div> <!-- /container -->#}
|
|
||||||
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer class="container">
|
|
||||||
<p>© Louis Chauvet 2019</p>
|
|
||||||
</footer>
|
|
||||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
|
|
||||||
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
|
|
||||||
crossorigin="anonymous"></script>
|
|
||||||
<script>window.jQuery || document.write('<script src="/docs/4.3/assets/js/vendor/jquery-slim.min.js"><\/script>')
|
|
||||||
</script>
|
|
||||||
<script src="/docs/4.3/dist/js/bootstrap.bundle.min.js"
|
|
||||||
integrity="sha384-xrRywqdh3PHs8keKZN+8zzc5TX0GRTLCcmivcbNJWm2rs5C8PRhcEn3czEjhAO9o"
|
|
||||||
crossorigin="anonymous"></script>
|
|
||||||
{% endblock %}
|
|
@ -1,16 +0,0 @@
|
|||||||
<!doctype html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<title>PDMI - Python Discord Module Index</title>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<meta name="description" content="PDMI - Python Discord Module Index">
|
|
||||||
<meta name="author" content="Louis Chauvet">
|
|
||||||
<!-- Favicon.ico -->
|
|
||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<a href="{{ url_for("admin.index") }}">Connection à la gestion des modules</a><br/>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,27 +0,0 @@
|
|||||||
{% macro render_field_with_errors(field) %}
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
{{ field.label }} {{ field(class_='form-control', **kwargs)|safe }}
|
|
||||||
{% if field.errors %}
|
|
||||||
<ul>
|
|
||||||
{% for error in field.errors %}
|
|
||||||
<li>{{ error }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endmacro %}
|
|
||||||
|
|
||||||
{% macro render_field(field) %}
|
|
||||||
<p>{{ field(class_='form-control', **kwargs)|safe }}</p>
|
|
||||||
{% endmacro %}
|
|
||||||
|
|
||||||
{% macro render_checkbox_field(field) -%}
|
|
||||||
<div class="form-group">
|
|
||||||
<div class="checkbox">
|
|
||||||
<label>
|
|
||||||
{{ field(type='checkbox', **kwargs) }} {{ field.label }}
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{%- endmacro %}
|
|
@ -1,19 +0,0 @@
|
|||||||
{% if security.registerable or security.recoverable or security.confirmable %}
|
|
||||||
<h2>Menu</h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="
|
|
||||||
{{ url_for_security('login') }}{% if 'next' in request.args %}?next={{ request.args.next|urlencode }}{% endif %}">Login</a>
|
|
||||||
</li>
|
|
||||||
{% if security.registerable %}
|
|
||||||
<li><a href="
|
|
||||||
{{ url_for_security('register') }}{% if 'next' in request.args %}?next={{ request.args.next|urlencode }}{% endif %}">Register</a><br/>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% if security.recoverable %}
|
|
||||||
<li><a href="{{ url_for_security('forgot_password') }}">Forgot password</a><br/></li>
|
|
||||||
{% endif %}
|
|
||||||
{% if security.confirmable %}
|
|
||||||
<li><a href="{{ url_for_security('send_confirmation') }}">Confirm account</a></li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
@ -1,9 +0,0 @@
|
|||||||
{%- with messages = get_flashed_messages(with_categories=true) -%}
|
|
||||||
{% if messages %}
|
|
||||||
<ul class="flashes">
|
|
||||||
{% for category, message in messages %}
|
|
||||||
<li class="{{ category }}">{{ message }}</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endif %}
|
|
||||||
{%- endwith %}
|
|
@ -1,24 +0,0 @@
|
|||||||
{% extends 'admin/master.html' %}
|
|
||||||
{% from "security/_macros.html" import render_field, render_field_with_errors, render_checkbox_field %}
|
|
||||||
{% include "security/_messages.html" %}
|
|
||||||
{% block body %}
|
|
||||||
{{ super() }}
|
|
||||||
<br><br><br><br><br>
|
|
||||||
<section class="content">
|
|
||||||
<div class="col-sm-8 col-sm-offset-2">
|
|
||||||
<div class="well">
|
|
||||||
<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.email) }}
|
|
||||||
{{ render_field_with_errors(login_user_form.password) }}
|
|
||||||
{{ render_checkbox_field(login_user_form.remember) }}
|
|
||||||
{{ render_field(login_user_form.next) }}
|
|
||||||
{{ render_field(login_user_form.submit, class="btn btn-primary") }}
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<br><br><br><br><br><br><br><br><br><br><br>
|
|
||||||
<br><br><br><br><br><br><br><br><br>
|
|
||||||
{% endblock body %}
|
|
@ -1,28 +0,0 @@
|
|||||||
{% extends 'admin/master.html' %}
|
|
||||||
{% from "security/_macros.html" import render_field_with_errors, render_field %}
|
|
||||||
{% include "security/_messages.html" %}
|
|
||||||
{% block body %}
|
|
||||||
{{ super() }}
|
|
||||||
<br><br><br><br>
|
|
||||||
|
|
||||||
<div class="row-fluid">
|
|
||||||
<div class="col-sm-8 col-sm-offset-2">
|
|
||||||
<br>
|
|
||||||
<div class="well">
|
|
||||||
<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.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, class="btn btn-primary") }}
|
|
||||||
</form>
|
|
||||||
<p>Already signed up? Please <a href="{{ url_for('security.login') }}">log in</a>.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
|
|
||||||
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
|
|
||||||
{% endblock body %}
|
|
@ -1,10 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
from flask import render_template, Blueprint, send_from_directory
|
|
||||||
|
|
||||||
main_bp = Blueprint('', __name__)
|
|
||||||
|
|
||||||
|
|
||||||
@main_bp.route('/favicon.ico')
|
|
||||||
def favicon():
|
|
||||||
return send_from_directory('static', 'favicon.ico', mimetype='image/vnd.microsoft.icon')
|
|
32
Pipfile
32
Pipfile
@ -1,32 +0,0 @@
|
|||||||
[[source]]
|
|
||||||
|
|
||||||
url = "https://pypi.org/simple"
|
|
||||||
verify_ssl = true
|
|
||||||
name = "pypi"
|
|
||||||
|
|
||||||
|
|
||||||
[packages]
|
|
||||||
|
|
||||||
flask-admin = {git = "https://github.com/Fomys/flask-admin"}
|
|
||||||
flask = "*"
|
|
||||||
flask-babelex = "*"
|
|
||||||
flask-security = "*"
|
|
||||||
flask-migrate = "*"
|
|
||||||
flask-script = "*"
|
|
||||||
flask-uploads = "*"
|
|
||||||
sqlalchemy = "*"
|
|
||||||
flask-sqlalchemy = "*"
|
|
||||||
flask-restful = "*"
|
|
||||||
gunicorn = "*"
|
|
||||||
aiohttp = "*"
|
|
||||||
pymysql = "*"
|
|
||||||
mysqlclient = "*"
|
|
||||||
|
|
||||||
|
|
||||||
[dev-packages]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[requires]
|
|
||||||
|
|
||||||
python_version = "3.7"
|
|
417
conf.sh
417
conf.sh
@ -1,417 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
SCRIPT_NAME=$0
|
|
||||||
|
|
||||||
#################
|
|
||||||
# Configuration #
|
|
||||||
#################
|
|
||||||
|
|
||||||
# List of all env variable
|
|
||||||
declare -A DATABASE_VAR_DESCRIPTION
|
|
||||||
DATABASE_VAR_DESCRIPTION["DATABASE_HOST"]="Set database host"
|
|
||||||
DATABASE_VAR_DESCRIPTION["DATABASE_PORT"]="Set database port"
|
|
||||||
DATABASE_VAR_DESCRIPTION["DATABASE_USER"]="Set database user"
|
|
||||||
DATABASE_VAR_DESCRIPTION["DATABASE_PASSWORD"]="Set database password, never share your .env file, your password is stored in clear"
|
|
||||||
DATABASE_VAR_DESCRIPTION["DATABASE_NAME"]="Set database name"
|
|
||||||
DATABASE_VARS="${!DATABASE_VAR_DESCRIPTION[@]}"
|
|
||||||
|
|
||||||
declare -A CONFIG_CATEGORIES_DESCRIPTION
|
|
||||||
CONFIG_CATEGORIES_DESCRIPTION["DATABASE"]="Set database related config vars"
|
|
||||||
CONFIG_CATEGORIES=(DATABASE)
|
|
||||||
|
|
||||||
CONFIG_VARS="$DATABASE_VARS"
|
|
||||||
|
|
||||||
################
|
|
||||||
# USEFULL VARS #
|
|
||||||
################
|
|
||||||
|
|
||||||
# Usefull vars for using dialog, kdialog and xdialog
|
|
||||||
: ${DIALOG_OK=0}
|
|
||||||
: ${DIALOG_CANCEL=1}
|
|
||||||
: ${DIALOG_HELP=2}
|
|
||||||
: ${DIALOG_EXTRA=3}
|
|
||||||
: ${DIALOG_ITEM_HELP=4}
|
|
||||||
: ${DIALOG_ESC=255}
|
|
||||||
# Colors
|
|
||||||
: ${BLACK='\033[0:30m'}
|
|
||||||
: ${RED='\033[0;31m'}
|
|
||||||
: ${GREEN='\033[0;32m'}
|
|
||||||
: ${ORANGE='\033[0;33m'}
|
|
||||||
: ${BLUE='\033[0;34m'}
|
|
||||||
: ${PURPLE='\033[0;35m'}
|
|
||||||
: ${CYAN='\033[0;36m'}
|
|
||||||
: ${LIGHT_GRAY='\033[0;37m'}
|
|
||||||
: ${DARK_GRAY='\033[1;30m'}
|
|
||||||
: ${LIGHT_RED='\033[1;31m'}
|
|
||||||
: ${LIGHT_GREEN='\033[1;32m'}
|
|
||||||
: ${YELLOW='\033[1;33m'}
|
|
||||||
: ${LIGHT_BLUE='\033[1;34m'}
|
|
||||||
: ${LIGHT_PURPLE='\033[1;35m'}
|
|
||||||
: ${LIGHT_CYAN='\033[1;36m'}
|
|
||||||
: ${WHITE='\033[1;37m'}
|
|
||||||
: ${NC='\033[0m'}
|
|
||||||
|
|
||||||
##########################
|
|
||||||
# Rewrite beautiful echo #
|
|
||||||
##########################
|
|
||||||
|
|
||||||
einfo () {
|
|
||||||
# einfo "comment"
|
|
||||||
echo -e " ${GREEN}*${NC} ${@:1}${NC}"
|
|
||||||
}
|
|
||||||
ewarn () {
|
|
||||||
# ewarn "comment"
|
|
||||||
echo -e " ${YELLOW}*${NC} ${@:1}${NC}"
|
|
||||||
}
|
|
||||||
eerror () {
|
|
||||||
# eerror "comment"
|
|
||||||
echo -e " ${RED}*${LIGHT_RED} ${@:1}${NC}"
|
|
||||||
}
|
|
||||||
die () {
|
|
||||||
# die exit_code "comment"
|
|
||||||
echo
|
|
||||||
eerror $2
|
|
||||||
exit $1
|
|
||||||
}
|
|
||||||
eend () {
|
|
||||||
# eend exit_status "comment"
|
|
||||||
einfo $2
|
|
||||||
exit $1
|
|
||||||
}
|
|
||||||
show_help () {
|
|
||||||
# show_help
|
|
||||||
echo "Usage : PDMI-configure [OPTIONS...]"
|
|
||||||
echo
|
|
||||||
echo " -h, --help Print this help menu"
|
|
||||||
echo " --xdialog Use xdialog instead of dialog"
|
|
||||||
}
|
|
||||||
|
|
||||||
####################
|
|
||||||
# Useful functions #
|
|
||||||
####################
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###################
|
|
||||||
# Parse arguments #
|
|
||||||
###################
|
|
||||||
|
|
||||||
SHORT=h:
|
|
||||||
LONG=xdialog,help,easter-egg:
|
|
||||||
|
|
||||||
OPTS=$(getopt --options ${SHORT} --long ${LONG} --name "$0" -- "$@")
|
|
||||||
|
|
||||||
# Problem when parsing args
|
|
||||||
if [[ $? != 0 ]] ; then echo "Failed to parse options...exiting." >&2 ; exit 1 ; fi
|
|
||||||
|
|
||||||
eval set -- "${OPTS}"
|
|
||||||
|
|
||||||
DIALOG=dialog
|
|
||||||
|
|
||||||
while true ; do
|
|
||||||
case "$1" in
|
|
||||||
--xdialog )
|
|
||||||
which Xdialog && : || die 1 "Xdialog not found"
|
|
||||||
DIALOG=Xdialog
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
--easter-egg)
|
|
||||||
die 0 "Suwako, je t'ai vu décortiquer le fichier"
|
|
||||||
;;
|
|
||||||
-h | --help )
|
|
||||||
show_help
|
|
||||||
end
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
-- )
|
|
||||||
shift
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Internal error!"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
set_env_var () {
|
|
||||||
load_config
|
|
||||||
exec 3>&1
|
|
||||||
local value=$(${DIALOG} \
|
|
||||||
--backtitle "Configuration" \
|
|
||||||
--title $1 \
|
|
||||||
--inputbox "Veuillez insérez la nouvelle valeur de la variable ${1}:" \
|
|
||||||
0 0 \
|
|
||||||
${!1} \
|
|
||||||
2>&1 1>&3)
|
|
||||||
local exit_status=$?
|
|
||||||
exec 3>&-
|
|
||||||
export ${1}=$value
|
|
||||||
save_config
|
|
||||||
}
|
|
||||||
|
|
||||||
set_env_vars_cat () {
|
|
||||||
clear
|
|
||||||
CATEGORY=$1
|
|
||||||
CATEGORY_VARS_NAME=${1}_VARS
|
|
||||||
CAT=${!CATEGORY_VARS_NAME}
|
|
||||||
CATEGORY_LIST=($CAT)
|
|
||||||
local OPTIONS=""
|
|
||||||
local COUNT=${#CATEGORY_LIST[@]}
|
|
||||||
for I in `seq 1 ${COUNT}`;
|
|
||||||
do
|
|
||||||
OPTIONS="$OPTIONS "${I}" "${CATEGORY_LIST[$(($I-1))]}""
|
|
||||||
done
|
|
||||||
echo $OPTIONS
|
|
||||||
exec 3>&1
|
|
||||||
selection=$(${DIALOG} \
|
|
||||||
--backtitle "PDMI - Configuration" \
|
|
||||||
--title "Set $CATEGORY vars" \
|
|
||||||
--help-button \
|
|
||||||
--menu "Choose an option" \
|
|
||||||
-1 -1 0 \
|
|
||||||
${OPTIONS} \
|
|
||||||
2>&1 1>&3)
|
|
||||||
exit_status=$?
|
|
||||||
exec 3>&-
|
|
||||||
case ${exit_status} in
|
|
||||||
${DIALOG_CANCEL})
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
${DIALOG_HELP})
|
|
||||||
;;
|
|
||||||
${DIALOG_ESC})
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
set_env_var ${CATEGORY_LIST[$(($selection-1))]}
|
|
||||||
}
|
|
||||||
|
|
||||||
set_env_vars () {
|
|
||||||
local OPTIONS=""
|
|
||||||
local COUNT=`echo "$CONFIG_CATEGORIES" | wc -w`
|
|
||||||
for I in `seq 1 ${COUNT}`;
|
|
||||||
do
|
|
||||||
OPTIONS="$OPTIONS "${I}" "${CONFIG_CATEGORIES[$(($I-1))]}""
|
|
||||||
done
|
|
||||||
exec 3>&1
|
|
||||||
selection=$(${DIALOG} \
|
|
||||||
--backtitle "PDMI - Configuration" \
|
|
||||||
--title "Set configuration vars" \
|
|
||||||
--help-button \
|
|
||||||
--menu "Choose an option" \
|
|
||||||
-1 -1 0 \
|
|
||||||
${OPTIONS} \
|
|
||||||
2>&1 1>&3)
|
|
||||||
exit_status=$?
|
|
||||||
exec 3>&-
|
|
||||||
case ${exit_status} in
|
|
||||||
${DIALOG_CANCEL})
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
${DIALOG_HELP})
|
|
||||||
local HELP=""
|
|
||||||
for NAME in ${!CONFIG_CATEGORIES_DESCRIPTION[@]}; do
|
|
||||||
HELP="$HELP\n${NAME} - ${CONFIG_CATEGORIES_DESCRIPTION[${NAME}]}"
|
|
||||||
done
|
|
||||||
echo ${HELP}
|
|
||||||
${DIALOG} \
|
|
||||||
--backtitle "PDMI - Set configuration vars" \
|
|
||||||
--title "Set configuration vars - Help" \
|
|
||||||
--msgbox "$HELP" \
|
|
||||||
-1 -1
|
|
||||||
;;
|
|
||||||
${DIALOG_ESC})
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
set_env_vars_cat $CONFIG_CATEGORIES
|
|
||||||
}
|
|
||||||
|
|
||||||
load_config () {
|
|
||||||
export $(cat .env | xargs)
|
|
||||||
}
|
|
||||||
|
|
||||||
save_config () {
|
|
||||||
rm .env
|
|
||||||
for VAR in ${CONFIG_VARS}
|
|
||||||
do
|
|
||||||
if [[ -z ${!VAR} ]]; then
|
|
||||||
export ${VAR}=${VAR}
|
|
||||||
fi
|
|
||||||
echo ${VAR}=${!VAR} >> .env
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
bdd_config () {
|
|
||||||
exec 3>&1
|
|
||||||
local selection=$(${DIALOG} \
|
|
||||||
--backtitle "Base de donnée" \
|
|
||||||
--menu "Que souhaitez vous faire?" \
|
|
||||||
0 0 0 \
|
|
||||||
"1" "manage db init" \
|
|
||||||
"2" "manage db migrate" \
|
|
||||||
"3" "manage db upgrade" \
|
|
||||||
2>&1 1>&3)
|
|
||||||
local exit_status=$?
|
|
||||||
exec 3>&-
|
|
||||||
source .env
|
|
||||||
case ${selection} in
|
|
||||||
1)
|
|
||||||
pipenv run python manage.py db init;;
|
|
||||||
2)
|
|
||||||
pipenv run python manage.py db migrate;;
|
|
||||||
3)
|
|
||||||
pipenv run python manage.py db upgrade;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
add_super_admin () {
|
|
||||||
exec 3>&1
|
|
||||||
local utilisateur=$(${DIALOG} \
|
|
||||||
--backtitle "Utilitaires" \
|
|
||||||
--title "Administrateurs" \
|
|
||||||
--inputbox "Entrez le mail de l'utilisateur que vous voulez passer en superadministrateur" \
|
|
||||||
0 0 \
|
|
||||||
"" \
|
|
||||||
2>&1 1>&3)
|
|
||||||
local exit_status=$?
|
|
||||||
exec 3>&-
|
|
||||||
source .env
|
|
||||||
pipenv run python manage.py set_superadmin -m "${utilisateur}"
|
|
||||||
exit
|
|
||||||
}
|
|
||||||
|
|
||||||
utilitaires () {
|
|
||||||
exec 3>&1
|
|
||||||
selection=$(${DIALOG} \
|
|
||||||
--backtitle "Utilitaires" \
|
|
||||||
--menu "Que voulez vous faire?" \
|
|
||||||
0 0 0 \
|
|
||||||
"1" "Ajouter un superadministrateur" \
|
|
||||||
"2" "Installation de pipenv" \
|
|
||||||
2>&1 1>&3)
|
|
||||||
exit_status=$?
|
|
||||||
exec 3>&-
|
|
||||||
case ${selection} in
|
|
||||||
1)
|
|
||||||
add_super_admin;;
|
|
||||||
2)
|
|
||||||
pipenv install;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
check_config_file () {
|
|
||||||
clear
|
|
||||||
export $(cat .env | xargs)
|
|
||||||
rm .env
|
|
||||||
echo ${CONFIG_VARS}
|
|
||||||
for VAR in ${CONFIG_VARS}
|
|
||||||
do
|
|
||||||
echo ${VAR}=${!VAR}
|
|
||||||
if [[ -z ${!VAR} ]]; then
|
|
||||||
export ${VAR}=${VAR}
|
|
||||||
fi
|
|
||||||
echo ${VAR}=${!VAR} >> .env
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
initialisation () {
|
|
||||||
:
|
|
||||||
}
|
|
||||||
|
|
||||||
start () {
|
|
||||||
pipenv run gunicorn wsgy -b 0.0.0.0:8000
|
|
||||||
}
|
|
||||||
|
|
||||||
configuration () {
|
|
||||||
exec 3>&1
|
|
||||||
selection=$(${DIALOG} \
|
|
||||||
--backtitle "PDMI - Configuration" \
|
|
||||||
--title "Configuration" \
|
|
||||||
--help-button \
|
|
||||||
--menu "Choose an option" \
|
|
||||||
-1 -1 0 \
|
|
||||||
"1" "Check config file" \
|
|
||||||
"2" "Set configuration" \
|
|
||||||
"-" "" \
|
|
||||||
"3" "Exit" \
|
|
||||||
2>&1 1>&3)
|
|
||||||
exit_status=$?
|
|
||||||
exec 3>&-
|
|
||||||
case ${exit_status} in
|
|
||||||
${DIALOG_OK})
|
|
||||||
;;
|
|
||||||
${DIALOG_CANCEL})
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
${DIALOG_HELP})
|
|
||||||
${DIALOG} \
|
|
||||||
--backtitle "PDMI - Configuration" \
|
|
||||||
--title "Configuration - Help" \
|
|
||||||
--msgbox "Check config file - Check config file integrity
|
|
||||||
Set configuration - Set configuration" \
|
|
||||||
-1 -1
|
|
||||||
;;
|
|
||||||
${DIALOG_ESC})
|
|
||||||
return
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
case ${selection} in
|
|
||||||
1)
|
|
||||||
check_config_file
|
|
||||||
;;
|
|
||||||
2)
|
|
||||||
set_env_vars
|
|
||||||
;;
|
|
||||||
3)
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
}
|
|
||||||
|
|
||||||
# Main loop
|
|
||||||
while true; do
|
|
||||||
exec 3>&1
|
|
||||||
selection=$(${DIALOG} \
|
|
||||||
--backtitle "PDMI - Configuration" \
|
|
||||||
--title "Configuration" \
|
|
||||||
--help-button \
|
|
||||||
--menu "Choose an option" \
|
|
||||||
-1 -1 0 \
|
|
||||||
"1" "Initialisation" \
|
|
||||||
"2" "Configuration" \
|
|
||||||
"3" "Start" \
|
|
||||||
"-" "-" \
|
|
||||||
"4" "Quit" \
|
|
||||||
2>&1 1>&3)
|
|
||||||
exit_status=$?
|
|
||||||
exec 3>&-
|
|
||||||
case ${exit_status} in
|
|
||||||
${DIALOG_OK})
|
|
||||||
;;
|
|
||||||
${DIALOG_CANCEL})
|
|
||||||
eend 0 "End."
|
|
||||||
;;
|
|
||||||
${DIALOG_HELP})
|
|
||||||
${DIALOG} \
|
|
||||||
--backtitle "PDMI - Configuration" \
|
|
||||||
--title "Configuration - Help" \
|
|
||||||
--msgbox "Initialisation - \n\nConfiguration - Configure usefull parameters, such as port, database uri, ..." \
|
|
||||||
-1 -1
|
|
||||||
;;
|
|
||||||
${DIALOG_ESC})
|
|
||||||
eend 0 "End."
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
case ${selection} in
|
|
||||||
1)
|
|
||||||
initialisation;;
|
|
||||||
2)
|
|
||||||
configuration;;
|
|
||||||
3)
|
|
||||||
start;;
|
|
||||||
4)
|
|
||||||
exit;;
|
|
||||||
esac
|
|
||||||
done
|
|
51
manage.py
51
manage.py
@ -1,51 +0,0 @@
|
|||||||
from flask import url_for
|
|
||||||
from flask_migrate import Migrate, MigrateCommand
|
|
||||||
from flask_script import Manager
|
|
||||||
|
|
||||||
from PDMI import server, db, Roles, Users
|
|
||||||
|
|
||||||
server.config.from_object('PDMI.config')
|
|
||||||
|
|
||||||
migrate = Migrate(server, db)
|
|
||||||
manager = Manager(server)
|
|
||||||
|
|
||||||
manager.add_command('db', MigrateCommand)
|
|
||||||
|
|
||||||
@manager.option('-m', '--mail', help="Mail de l'utilisateur à mettre en admin")
|
|
||||||
def set_superadmin(mail):
|
|
||||||
roles = Roles.query.filter(Roles.name == "superadmin").all()
|
|
||||||
if len(roles) == 0:
|
|
||||||
superAdminRole = Roles(name="superadmin", description="Role pour les super administrateurs")
|
|
||||||
db.session.add(superAdminRole)
|
|
||||||
db.session.commit()
|
|
||||||
role = Roles.query.filter(Roles.name == "superadmin").first()
|
|
||||||
users = Users.query.filter(Users.email == mail).all()
|
|
||||||
if len(users) == 0:
|
|
||||||
print("Aucun compte avec le mail {mail} existe, annulation".format(mail=mail))
|
|
||||||
return
|
|
||||||
user = Users.query.filter(Users.email == mail).first()
|
|
||||||
user.roles.append(role)
|
|
||||||
db.session.commit()
|
|
||||||
print("Role ajouté")
|
|
||||||
|
|
||||||
@manager.command
|
|
||||||
def list_routes():
|
|
||||||
import urllib.parse
|
|
||||||
output = []
|
|
||||||
for rule in server.url_map.iter_rules():
|
|
||||||
options = {}
|
|
||||||
for arg in rule.arguments:
|
|
||||||
if arg == "id":
|
|
||||||
options[arg] = "0"
|
|
||||||
else:
|
|
||||||
options[arg] = f"[{arg}]"
|
|
||||||
methods = ",".join(rule.methods)
|
|
||||||
url = url_for(rule.endpoint, **options)
|
|
||||||
line = urllib.parse.unquote("{:50s} {:20s} {}".format(rule.endpoint, methods, url))
|
|
||||||
output.append(line)
|
|
||||||
for line in sorted(output):
|
|
||||||
print(line)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
manager.run()
|
|
Loading…
Reference in New Issue
Block a user