premier commit
This commit is contained in:
17
Pipfile
Normal file
17
Pipfile
Normal file
@@ -0,0 +1,17 @@
|
||||
[[source]]
|
||||
url = "https://pypi.python.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
flask = "*"
|
||||
flask-api = "*"
|
||||
flask-cors = "*"
|
||||
jsonschema = "*"
|
||||
pyjwt = "*"
|
||||
flask-jwt-extended = "*"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[requires]
|
||||
python_version = "3.7"
|
||||
222
Pipfile.lock
generated
Normal file
222
Pipfile.lock
generated
Normal file
@@ -0,0 +1,222 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "aa2dcf776d27427f1752d52efb3fbb8ed86b3056f099f09c88c7ec7da77fdcae"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.7"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.python.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
"sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6",
|
||||
"sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"
|
||||
],
|
||||
"version": "==22.1.0"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e",
|
||||
"sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"
|
||||
],
|
||||
"version": "==8.1.3"
|
||||
},
|
||||
"flask": {
|
||||
"hashes": [
|
||||
"sha256:642c450d19c4ad482f96729bd2a8f6d32554aa1e231f4f6b4e7e5264b16cca2b",
|
||||
"sha256:b9c46cc36662a7949f34b52d8ec7bb59c0d74ba08ba6cb9ce9adc1d8676d9526"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.2.2"
|
||||
},
|
||||
"flask-api": {
|
||||
"hashes": [
|
||||
"sha256:331889500433b0a5e71ae7910a00ee577c8999baba03ca685b3558ee93031cce",
|
||||
"sha256:913d1ef4d303b5e4490a712175d83a91c2b9cc6052ef501cff8301d9f553b179"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.0.post1"
|
||||
},
|
||||
"flask-cors": {
|
||||
"hashes": [
|
||||
"sha256:74efc975af1194fc7891ff5cd85b0f7478be4f7f59fe158102e91abb72bb4438",
|
||||
"sha256:b60839393f3b84a0f3746f6cdca56c1ad7426aa738b70d6c61375857823181de"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.0.10"
|
||||
},
|
||||
"flask-jwt-extended": {
|
||||
"hashes": [
|
||||
"sha256:62b521d75494c290a646ae8acc77123721e4364790f1e64af0038d823961fbf0",
|
||||
"sha256:a85eebfa17c339a7260c4643475af444784ba6de5588adda67406f0a75599553"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.4.4"
|
||||
},
|
||||
"importlib-metadata": {
|
||||
"hashes": [
|
||||
"sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab",
|
||||
"sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"
|
||||
],
|
||||
"markers": "python_version < '3.8'",
|
||||
"version": "==5.0.0"
|
||||
},
|
||||
"importlib-resources": {
|
||||
"hashes": [
|
||||
"sha256:5481e97fb45af8dcf2f798952625591c58fe599d0735d86b10f54de086a61681",
|
||||
"sha256:f78a8df21a79bcc30cfd400bdc38f314333de7c0fb619763f6b9dabab8268bb7"
|
||||
],
|
||||
"markers": "python_version < '3.9'",
|
||||
"version": "==5.9.0"
|
||||
},
|
||||
"itsdangerous": {
|
||||
"hashes": [
|
||||
"sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44",
|
||||
"sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"
|
||||
],
|
||||
"version": "==2.1.2"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852",
|
||||
"sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"
|
||||
],
|
||||
"version": "==3.1.2"
|
||||
},
|
||||
"jsonschema": {
|
||||
"hashes": [
|
||||
"sha256:165059f076eff6971bae5b742fc029a7b4ef3f9bcf04c14e4776a7605de14b23",
|
||||
"sha256:9e74b8f9738d6a946d70705dc692b74b5429cd0960d58e79ffecfc43b2221eb9"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.16.0"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003",
|
||||
"sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88",
|
||||
"sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5",
|
||||
"sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7",
|
||||
"sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a",
|
||||
"sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603",
|
||||
"sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1",
|
||||
"sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135",
|
||||
"sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247",
|
||||
"sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6",
|
||||
"sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601",
|
||||
"sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77",
|
||||
"sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02",
|
||||
"sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e",
|
||||
"sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63",
|
||||
"sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f",
|
||||
"sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980",
|
||||
"sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b",
|
||||
"sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812",
|
||||
"sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff",
|
||||
"sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96",
|
||||
"sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1",
|
||||
"sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925",
|
||||
"sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a",
|
||||
"sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6",
|
||||
"sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e",
|
||||
"sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f",
|
||||
"sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4",
|
||||
"sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f",
|
||||
"sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3",
|
||||
"sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c",
|
||||
"sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a",
|
||||
"sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417",
|
||||
"sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a",
|
||||
"sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a",
|
||||
"sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37",
|
||||
"sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452",
|
||||
"sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933",
|
||||
"sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a",
|
||||
"sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"
|
||||
],
|
||||
"version": "==2.1.1"
|
||||
},
|
||||
"pkgutil-resolve-name": {
|
||||
"hashes": [
|
||||
"sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174",
|
||||
"sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"
|
||||
],
|
||||
"markers": "python_version < '3.9'",
|
||||
"version": "==1.3.10"
|
||||
},
|
||||
"pyjwt": {
|
||||
"hashes": [
|
||||
"sha256:8d82e7087868e94dd8d7d418e5088ce64f7daab4b36db654cbaedb46f9d1ca80",
|
||||
"sha256:e77ab89480905d86998442ac5788f35333fa85f65047a534adc38edf3c88fc3b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.5.0"
|
||||
},
|
||||
"pyrsistent": {
|
||||
"hashes": [
|
||||
"sha256:0e3e1fcc45199df76053026a51cc59ab2ea3fc7c094c6627e93b7b44cdae2c8c",
|
||||
"sha256:1b34eedd6812bf4d33814fca1b66005805d3640ce53140ab8bbb1e2651b0d9bc",
|
||||
"sha256:4ed6784ceac462a7d6fcb7e9b663e93b9a6fb373b7f43594f9ff68875788e01e",
|
||||
"sha256:5d45866ececf4a5fff8742c25722da6d4c9e180daa7b405dc0a2a2790d668c26",
|
||||
"sha256:636ce2dc235046ccd3d8c56a7ad54e99d5c1cd0ef07d9ae847306c91d11b5fec",
|
||||
"sha256:6455fc599df93d1f60e1c5c4fe471499f08d190d57eca040c0ea182301321286",
|
||||
"sha256:6bc66318fb7ee012071b2792024564973ecc80e9522842eb4e17743604b5e045",
|
||||
"sha256:7bfe2388663fd18bd8ce7db2c91c7400bf3e1a9e8bd7d63bf7e77d39051b85ec",
|
||||
"sha256:7ec335fc998faa4febe75cc5268a9eac0478b3f681602c1f27befaf2a1abe1d8",
|
||||
"sha256:914474c9f1d93080338ace89cb2acee74f4f666fb0424896fcfb8d86058bf17c",
|
||||
"sha256:b568f35ad53a7b07ed9b1b2bae09eb15cdd671a5ba5d2c66caee40dbf91c68ca",
|
||||
"sha256:cdfd2c361b8a8e5d9499b9082b501c452ade8bbf42aef97ea04854f4a3f43b22",
|
||||
"sha256:d1b96547410f76078eaf66d282ddca2e4baae8964364abb4f4dcdde855cd123a",
|
||||
"sha256:d4d61f8b993a7255ba714df3aca52700f8125289f84f704cf80916517c46eb96",
|
||||
"sha256:d7a096646eab884bf8bed965bad63ea327e0d0c38989fc83c5ea7b8a87037bfc",
|
||||
"sha256:df46c854f490f81210870e509818b729db4488e1f30f2a1ce1698b2295a878d1",
|
||||
"sha256:e24a828f57e0c337c8d8bb9f6b12f09dfdf0273da25fda9e314f0b684b415a07",
|
||||
"sha256:e4f3149fd5eb9b285d6bfb54d2e5173f6a116fe19172686797c056672689daf6",
|
||||
"sha256:e92a52c166426efbe0d1ec1332ee9119b6d32fc1f0bbfd55d5c1088070e7fc1b",
|
||||
"sha256:f87cc2863ef33c709e237d4b5f4502a62a00fab450c9e020892e8e2ede5847f5",
|
||||
"sha256:fd8da6d0124efa2f67d86fa70c851022f87c98e205f0594e1fae044e7119a5a6"
|
||||
],
|
||||
"version": "==0.18.1"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926",
|
||||
"sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"
|
||||
],
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"typing-extensions": {
|
||||
"hashes": [
|
||||
"sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02",
|
||||
"sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"
|
||||
],
|
||||
"markers": "python_version < '3.8'",
|
||||
"version": "==4.3.0"
|
||||
},
|
||||
"werkzeug": {
|
||||
"hashes": [
|
||||
"sha256:7ea2d48322cc7c0f8b3a215ed73eabd7b5d75d0b50e31ab006286ccff9e00b8f",
|
||||
"sha256:f979ab81f58d7318e064e99c4506445d60135ac5cd2e177a2de0089bfd4c9bd5"
|
||||
],
|
||||
"version": "==2.2.2"
|
||||
},
|
||||
"zipp": {
|
||||
"hashes": [
|
||||
"sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2",
|
||||
"sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009"
|
||||
],
|
||||
"markers": "python_version < '3.10'",
|
||||
"version": "==3.8.1"
|
||||
}
|
||||
},
|
||||
"develop": {}
|
||||
}
|
||||
6
db.json
Normal file
6
db.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"utilisateur":{
|
||||
"id" : "admin",
|
||||
"password" : "28e55d1d25cd6e50cf4933c85636299367813225cecd7fd73c88282ed9e2c0d8"
|
||||
}
|
||||
}
|
||||
10
run.py
Normal file
10
run.py
Normal file
@@ -0,0 +1,10 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
# @author : vincent.benoit@benserv.fr
|
||||
# @brief : Backend Configurateur KineInterCOM
|
||||
|
||||
from src import app
|
||||
print("Launch Flask KineInterCOM Configurateur Backend ...")
|
||||
application = app.create_app()
|
||||
if application:
|
||||
application.run(host="0.0.0.0", port=6000, use_reloader=False)
|
||||
13
run_prod.py
Normal file
13
run_prod.py
Normal file
@@ -0,0 +1,13 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
# @author : vincent.benoit@benserv.fr
|
||||
# @brief : KineIntercom Backend
|
||||
|
||||
from src import app
|
||||
from src.config import ProdConfig
|
||||
from waitress import serve
|
||||
|
||||
print("Launch Flask KineIntercom Backend ...")
|
||||
application = app.create_app(config=ProdConfig)
|
||||
if application:
|
||||
serve(application, host="127.0.0.1", port=6000)
|
||||
1
src/VERSION
Normal file
1
src/VERSION
Normal file
@@ -0,0 +1 @@
|
||||
1.0.0
|
||||
0
src/__init__.py
Normal file
0
src/__init__.py
Normal file
131
src/app.py
Normal file
131
src/app.py
Normal file
@@ -0,0 +1,131 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
# @author : vincent.benoit@benserv.fr
|
||||
# @brief : Configurateur Backend Flask API
|
||||
|
||||
#########################################################
|
||||
# Importation de modules externes #
|
||||
|
||||
import sys, re, os
|
||||
import logging as log
|
||||
from logging.config import dictConfig
|
||||
|
||||
from flask import Flask
|
||||
from flask.logging import default_handler
|
||||
from flask_cors import CORS, cross_origin
|
||||
from flask_jwt_extended import JWTManager
|
||||
|
||||
import jwt
|
||||
|
||||
from src.config import DefaultConfig
|
||||
from src.auth import auth
|
||||
from src.log import log as logs
|
||||
|
||||
#########################################################
|
||||
# Corps principal du programme #
|
||||
|
||||
def create_app(config=None, app_name=None):
|
||||
''' Create and configure the app
|
||||
|
||||
:param config:
|
||||
configuration object
|
||||
|
||||
:param app_name:
|
||||
application name
|
||||
'''
|
||||
if app_name is None:
|
||||
app_name = DefaultConfig.PROJECT
|
||||
|
||||
# create the app
|
||||
# tells the app that configuration files are relative to the instance folder.
|
||||
app = Flask(app_name,
|
||||
instance_path=os.path.join(os.getcwd(), app_name),
|
||||
instance_relative_config=True)
|
||||
|
||||
if not configure_app(app, config):
|
||||
return None
|
||||
|
||||
configure_log(app)
|
||||
configure_blueprints(app)
|
||||
|
||||
return app
|
||||
|
||||
def configure_app(app=None, config=None):
|
||||
''' configure the application with configuration file and/or object
|
||||
|
||||
:param app:
|
||||
Application object
|
||||
|
||||
:param config:
|
||||
Configuration object
|
||||
|
||||
:return bool:
|
||||
True if OK, otherwise False
|
||||
'''
|
||||
# load default config
|
||||
app.config.from_object(DefaultConfig)
|
||||
|
||||
try:
|
||||
if config:
|
||||
# load specific config
|
||||
app.config.from_object(config)
|
||||
except ModuleNotFoundError as e:
|
||||
print("Module de configuration non trouvé: {}".format(e))
|
||||
return False
|
||||
|
||||
# setup the Flask-JWT-Extended extension
|
||||
jwt = JWTManager(app)
|
||||
# setup the Flask-CORS extension for handling Cross Origin Resource Sharing
|
||||
CORS(app, resources={r"/api/*": {
|
||||
# "origins": ["http://localhost:4200","http://localhost:5000"],
|
||||
"origins": "*",
|
||||
"supports_credentials": True
|
||||
}})
|
||||
return True
|
||||
|
||||
def configure_log(app=None):
|
||||
''' Configure log handler
|
||||
|
||||
:param app:
|
||||
Application object
|
||||
|
||||
:return None:
|
||||
'''
|
||||
if not os.path.exists(app.config['LOG_FOLDER']):
|
||||
try:
|
||||
os.makedirs(app.config['LOG_FOLDER'])
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# On vire tous les handlers
|
||||
for h in app.logger.handlers:
|
||||
app.logger.removeHandler(h)
|
||||
|
||||
# Set info level on logger, which might be overwritten by handers.
|
||||
# Suppress DEBUG messages.
|
||||
app.logger.setLevel(log.DEBUG)
|
||||
|
||||
formatter = log.Formatter('%(asctime)s - %(name)s [%(module)s.%(funcName)s:%(lineno)d] - %(levelname)s - %(message)s')
|
||||
info_log = os.path.join(app.config['LOG_FOLDER'], DefaultConfig.PROJECT + '.log')
|
||||
info_file_handler = log.handlers.RotatingFileHandler(info_log, maxBytes=100000, backupCount=10)
|
||||
info_file_handler.setLevel(log.DEBUG)
|
||||
info_file_handler.setFormatter(formatter)
|
||||
app.logger.addHandler(info_file_handler)
|
||||
|
||||
fl = log.StreamHandler()
|
||||
fl.setLevel(log.DEBUG)
|
||||
fl.setFormatter(formatter)
|
||||
app.logger.addHandler(fl)
|
||||
|
||||
#logging.getLogger('apscheduler').setLevel(logging.DEBUG)
|
||||
|
||||
def configure_blueprints(app=None):
|
||||
''' configure blueprints
|
||||
|
||||
:param app:
|
||||
Application object
|
||||
|
||||
:return None:
|
||||
'''
|
||||
for bp in [auth, logs]:
|
||||
app.register_blueprint(bp)
|
||||
6
src/auth/__init__.py
Normal file
6
src/auth/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
# @author : vincent.benoit@benserv.fr
|
||||
# @brief : auth views and models
|
||||
|
||||
from .views import auth
|
||||
148
src/auth/views.py
Normal file
148
src/auth/views.py
Normal file
@@ -0,0 +1,148 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
# @author : vincent.benoit@benserv.fr
|
||||
# @brief : Auth routes
|
||||
|
||||
#########################################################
|
||||
# Importation de modules externes #
|
||||
|
||||
import sys, re, os
|
||||
import logging as log
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from flask import Flask, Blueprint, request, abort, jsonify, current_app
|
||||
from flask_api import status
|
||||
from flask_jwt_extended import create_access_token
|
||||
from flask_jwt_extended import get_jwt
|
||||
from flask_jwt_extended import set_access_cookies
|
||||
from flask_jwt_extended import unset_jwt_cookies
|
||||
from flask_jwt_extended import get_jwt_identity
|
||||
from flask_jwt_extended import jwt_required, decode_token
|
||||
|
||||
import json
|
||||
import shutil
|
||||
import hashlib
|
||||
from werkzeug.exceptions import HTTPException
|
||||
|
||||
#########################################################
|
||||
# Class et Methods #
|
||||
|
||||
auth = Blueprint('auth', __name__, url_prefix='/api/configurateur')
|
||||
|
||||
@auth.errorhandler(HTTPException)
|
||||
def handle_exception(e):
|
||||
''' return JSON instead of HTML for HTTP errors '''
|
||||
response = e.get_response()
|
||||
# replace the body with JSON
|
||||
response.data = json.dumps({
|
||||
'code': e.code,
|
||||
'name': e.name,
|
||||
'description': e.description,
|
||||
})
|
||||
response.content_type = "application/json"
|
||||
return response
|
||||
|
||||
@auth.after_request
|
||||
def refresh_expiring_tokens(response):
|
||||
''' Using an 'after_request' callback, we refresh any token that is within
|
||||
30 minutes of expiring.'''
|
||||
try:
|
||||
exp_timestamp = get_jwt()['exp']
|
||||
now = datetime.now(timezone.utc)
|
||||
target_timestamp = datetime.timestamp(now + current_app.config['DELTA'])
|
||||
if target_timestamp > exp_timestamp:
|
||||
current_app.logger.warning("On doit recréer un token JWT ....")
|
||||
access_token = create_access_token(identity=get_jwt_identity())
|
||||
# refresh token in storage place
|
||||
if os.path.exists(os.path.join("/tmp", current_app.config['PROJECT'])):
|
||||
with open(os.path.join("/tmp", current_app.config['PROJECT'], get_jwt_identity()['id']), 'w') as f:
|
||||
f.write(access_token)
|
||||
# Modifiy a Flask Response to set a cookie containing the access JWT.
|
||||
set_access_cookies(response, access_token)
|
||||
return response
|
||||
except (RuntimeError, KeyError):
|
||||
return response
|
||||
|
||||
@auth.route('/login', methods=['POST'])
|
||||
def login():
|
||||
''' Authenticate User '''
|
||||
auth = request.authorization
|
||||
current_app.logger.info("Connexion de l'utilisateur : {}".format(auth.username))
|
||||
if not auth or not auth.username or not auth.password:
|
||||
current_app.logger.error("Login and Password required !")
|
||||
abort(401, description='Login and Password required')
|
||||
|
||||
try:
|
||||
hashstr = hashlib.sha256(auth.password.encode('utf-8')).hexdigest()
|
||||
with open(current_app.config['DB_PATH'], 'r') as f:
|
||||
data = json.load(f)
|
||||
# authenticate user with his username and password hash
|
||||
if hashstr == data['utilisateur']['password']:
|
||||
# create a new access token
|
||||
current_app.logger.debug("create JWT Token with id: {}".format(auth.username))
|
||||
token = create_access_token(identity={'id': auth.username})
|
||||
if not os.path.exists(os.path.join("/tmp", current_app.config['PROJECT'])):
|
||||
os.mkdir(os.path.join("/tmp", current_app.config['PROJECT']))
|
||||
with open(os.path.join("/tmp", current_app.config['PROJECT'], auth.username), 'w') as f:
|
||||
f.write(token)
|
||||
content = jsonify({'message': 'login successful !'})
|
||||
# set token as cookie
|
||||
set_access_cookies(content, token)
|
||||
return content, status.HTTP_200_OK
|
||||
current_app.logger.error("Authorization failed !")
|
||||
except Exception as e:
|
||||
current_app.logger.error("Erreur : {}".format(e))
|
||||
abort(500, description='Authentification impossible')
|
||||
abort(401, description="Authorization failed !")
|
||||
|
||||
@auth.route('/logout', methods=['POST'])
|
||||
@jwt_required()
|
||||
def logout():
|
||||
""" Handles HTTP requests to URL: /api/configurateur/logout """
|
||||
current_app.logger.info("Deconnexion de l'utilisateur")
|
||||
current_user = get_jwt_identity()
|
||||
content = jsonify({'message': 'logout successful !'})
|
||||
unset_jwt_cookies(content)
|
||||
userpath = os.path.join("/tmp", current_app.config['PROJECT'])
|
||||
if os.path.exists(userpath):
|
||||
shutil.rmtree(userpath)
|
||||
return content, status.HTTP_200_OK
|
||||
|
||||
@auth.route('/current', methods=['GET'])
|
||||
@jwt_required()
|
||||
def current_user():
|
||||
''' retourne l'utilisateur courant connecté '''
|
||||
# Access the identity of the current user with get_jwt_identity
|
||||
current_user = get_jwt_identity()
|
||||
return jsonify(current_user)
|
||||
|
||||
@auth.route('/userConnected', methods=['GET'])
|
||||
def user_connected():
|
||||
''' retourne "oui" si un utilisateur est déjà connecté sinon "non" '''
|
||||
flag = False
|
||||
resp = 'non'
|
||||
uid = ''
|
||||
path = os.path.join("/tmp", current_app.config['PROJECT'])
|
||||
if os.path.exists(path):
|
||||
# search unique file in path
|
||||
for root, dirs, files in os.walk(path):
|
||||
for f in files:
|
||||
uid = str(f)
|
||||
# retreive token in file
|
||||
with open(os.path.join(path, f), 'r') as fp:
|
||||
token = fp.read()
|
||||
exp = decode_token(token, allow_expired = True)['exp']
|
||||
now = datetime.now(timezone.utc)
|
||||
target = datetime.timestamp(now)
|
||||
if target > exp:
|
||||
current_app.logger.warning("Le token de l'ancien utilisateur a expiré")
|
||||
# remove tmp dir
|
||||
shutil.rmtree(os.path.join("/tmp", current_app.config['PROJECT']))
|
||||
flag = True
|
||||
break
|
||||
|
||||
if not flag:
|
||||
current_app.logger.warning("Un autre utilisateur est déjà connecté")
|
||||
resp = 'oui'
|
||||
content = ({'message':resp, 'uid':uid})
|
||||
return jsonify(content), status.HTTP_200_OK
|
||||
60
src/config.py
Normal file
60
src/config.py
Normal file
@@ -0,0 +1,60 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# @author: vincent.benoit@benserv.fr
|
||||
# @brief: Flask Config classes
|
||||
|
||||
import os
|
||||
import datetime
|
||||
|
||||
class BaseConfig(object):
|
||||
PROJECT = "configurateur"
|
||||
|
||||
# Get app root path, also can use flask.root_path.
|
||||
PROJECT_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
||||
|
||||
DEBUG = False
|
||||
TESTING = False
|
||||
FLASK_ENV = 'production'
|
||||
|
||||
ADMINS = ['vincent.benoit@benserv.fr']
|
||||
|
||||
LOG_FOLDER = os.path.join(os.getcwd(), 'log')
|
||||
|
||||
SECRET_KEY = "d]omg;<*|uHfs}ogN=dk_$YW"
|
||||
|
||||
# Setup the Flask-JWT-Extended extension
|
||||
JWT_SECRET_KEY = "xbNNvwHCY*cN,)Yq;A,e(]|P"
|
||||
JWT_COOKIE_SECURE = False
|
||||
JWT_TOKEN_LOCATION = ["cookies"]
|
||||
JWT_ACCESS_TOKEN_EXPIRES = datetime.timedelta(minutes=30)
|
||||
DELTA = datetime.timedelta(minutes=20) # in minutes
|
||||
# Controls if Cross Site Request Forgery (CSRF) protection is enabled when using cookies
|
||||
# This should always be True in production
|
||||
JWT_COOKIE_CSRF_PROTECT = True
|
||||
JWT_CSRF_IN_COOKIES = True
|
||||
|
||||
STATIC_FOLDER = os.path.join(os.getcwd(), 'static')
|
||||
UPLOAD_FOLDER = STATIC_FOLDER + '/upload'
|
||||
DOWNLOAD_FOLDER = STATIC_FOLDER + '/download'
|
||||
ALLOWED_EXTENSIONS = {'json', 'tar', 'txt'}
|
||||
MAX_CONTENT_LENGTH = 200 * 1024 * 1024 # 100 megabytes
|
||||
|
||||
DB_PATH = os.path.join(os.getcwd(), 'db.json')
|
||||
|
||||
class DefaultConfig(BaseConfig):
|
||||
DEBUG = True
|
||||
TESTING = True
|
||||
FLASK_ENV = 'development'
|
||||
|
||||
SECRET_KEY = "secretkey1"
|
||||
|
||||
# Setup the Flask-JWT-Extended extension
|
||||
JWT_SECRET_KEY = "secretkeyjwt1"
|
||||
JWT_ACCESS_TOKEN_EXPIRES = datetime.timedelta(minutes=10)
|
||||
DELTA = datetime.timedelta(minutes=5) # in minutes
|
||||
|
||||
class ProdConfig(BaseConfig):
|
||||
ROOT_BASE_FOLDER = "/opt"
|
||||
# Log Folder path
|
||||
LOG_FOLDER = os.path.join("/var/log", BaseConfig.PROJECT)
|
||||
|
||||
6
src/log/__init__.py
Normal file
6
src/log/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
# @author : vincent.benoit@benserv.fr
|
||||
# @brief : log views and models
|
||||
|
||||
from .views import log
|
||||
80
src/log/views.py
Normal file
80
src/log/views.py
Normal file
@@ -0,0 +1,80 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
# @author : vincent.benoit@benserv.fr
|
||||
# @brief : log routes
|
||||
|
||||
#########################################################
|
||||
# Importation de modules externes #
|
||||
|
||||
import sys, re, os
|
||||
import logging as log
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from flask import Flask, Blueprint, request, abort, jsonify, current_app
|
||||
from flask_api import status
|
||||
from flask_jwt_extended import create_access_token
|
||||
from flask_jwt_extended import get_jwt
|
||||
from flask_jwt_extended import set_access_cookies
|
||||
from flask_jwt_extended import get_jwt_identity
|
||||
from flask_jwt_extended import jwt_required
|
||||
|
||||
import json
|
||||
|
||||
from werkzeug.exceptions import HTTPException
|
||||
|
||||
#########################################################
|
||||
# Class et Methods #
|
||||
|
||||
log = Blueprint('log', __name__, url_prefix='/api/configurateur')
|
||||
|
||||
@log.errorhandler(HTTPException)
|
||||
def handle_exception(e):
|
||||
''' return JSON instead of HTML for HTTP errors '''
|
||||
response = e.get_response()
|
||||
# replace the body with JSON
|
||||
response.data = json.dumps({
|
||||
'code': e.code,
|
||||
'name': e.name,
|
||||
'description': e.description,
|
||||
})
|
||||
response.content_type = "application/json"
|
||||
return response
|
||||
|
||||
@log.after_request
|
||||
def refresh_expiring_tokens(response):
|
||||
''' Using an 'after_request' callback, we refresh any token that is within
|
||||
30 minutes of expiring.'''
|
||||
try:
|
||||
exp_timestamp = get_jwt()['exp']
|
||||
now = datetime.now(timezone.utc)
|
||||
target_timestamp = datetime.timestamp(now + current_app.config['DELTA'])
|
||||
if target_timestamp > exp_timestamp:
|
||||
currenT_app.logger.warning("On doit recréer un token ....")
|
||||
access_token = create_access_token(identity=get_jwt_identity())
|
||||
# refresh token in storage place
|
||||
if os.path.exists(os.path.join("/tmp", current_app.config['PROJECT'])):
|
||||
with open(os.path.join("/tmp", current_app.config['PROJECT'], get_jwt_identity()['id']), 'w') as f:
|
||||
f.write(access_token)
|
||||
# Modifiy a Flask Response to set a cookie containing the access JWT.
|
||||
set_access_cookies(response, access_token)
|
||||
return response
|
||||
except (RuntimeError, KeyError):
|
||||
return response
|
||||
|
||||
@log.route('/logs', methods=['GET'])
|
||||
@jwt_required()
|
||||
def get_all_logs():
|
||||
''' Retreive app logs '''
|
||||
# Access the identity of the current user with get_jwt_identity
|
||||
current_user = get_jwt_identity()
|
||||
|
||||
lines = []
|
||||
with open(os.path.join(current_app.config['LOG_FOLDER'], current_app.config['PROJECT'] + '.log')) as f:
|
||||
for idx, line in enumerate(f.readlines()):
|
||||
try:
|
||||
date_time, head, gravity, msg = line.split(' - ', 3)
|
||||
content = {'datetime': date_time, 'header': head, 'gravity': gravity, 'msg':msg}
|
||||
lines.append(content)
|
||||
except ValueError as e:
|
||||
lines[-1]['msg'] = lines[-1]['msg'] + line
|
||||
return jsonify(lines), status.HTTP_200_OK
|
||||
Reference in New Issue
Block a user