[conf] add envfile supprt / fix the bugs related to acl_caller_middleware / fix the bugs related to responses classes

This commit is contained in:
Maxime Alves LIRMM@home 2020-07-09 08:02:44 +02:00
parent f0d5eb7d92
commit 644e5c5d3d
7 changed files with 129 additions and 28 deletions

View File

@ -1,2 +1,3 @@
export HALFORM_SECRET="halform_secret" HALFORM_SECRET="halform_secret"
export HALFORM_DSN="dbname=api user=api password= host=127.0.0.1 port=5432" HALFORM_DSN="dbname=api user=api password= host=127.0.0.1 port=5432"
DEBUG=1

View File

@ -100,16 +100,18 @@ def check_conf():
if not environ.get('HALFORM_DSN', False): if not environ.get('HALFORM_DSN', False):
print('Missing HALFORM_DSN variable from configuration') print('Missing HALFORM_DSN variable from configuration')
DEBUG = True CONFIG={
'DEBUG' : 'DEBUG' in environ.keys()
}
debug_routes = [ debug_routes = [
Route('/', lambda request: PlainTextResponse('It Works!')), Route('/', lambda request, *args, **kwargs: PlainTextResponse('It Works!')),
Route('/user', lambda request: JSONResponse({'user':request.user})), Route('/user', lambda request, *args, **kwargs: JSONResponse({'user':str(request.user)})),
Route('/payload', lambda request: JSONResponse({'payload':request.payload})) Route('/payload', lambda request, *args, **kwargs: JSONResponse({'payload':str(request.payload)}))
] if DEBUG is True else [] ] if CONFIG['DEBUG'] is True else []
app = Starlette( app = Starlette(
debug=DEBUG, debug=CONFIG['DEBUG'],
routes=debug_routes, routes=debug_routes,
middleware=[ middleware=[
Middleware(AuthenticationMiddleware, backend=JWTAuthenticationBackend(secret_key=environ.get('HALFORM_SECRET'))), Middleware(AuthenticationMiddleware, backend=JWTAuthenticationBackend(secret_key=environ.get('HALFORM_SECRET'))),

View File

@ -32,6 +32,7 @@ def cli(ctx):
if ctx.invoked_subcommand is None: if ctx.invoked_subcommand is None:
return run() return run()
@click.option('--envfile', default=None)
@click.option('--host', default='127.0.0.1') @click.option('--host', default='127.0.0.1')
@click.option('--port', default='8000') @click.option('--port', default='8000')
@click.option('--debug', default=False) @click.option('--debug', default=False)
@ -42,7 +43,17 @@ def cli(ctx):
@click.option('--dbuser', default='api') @click.option('--dbuser', default='api')
@click.option('--dbpassword', default='') @click.option('--dbpassword', default='')
@cli.command() @cli.command()
def run(host, port, debug, dev, dbname, dbhost, dbport, dbuser, dbpassword): def run(envfile, host, port, debug, dev, dbname, dbhost, dbport, dbuser, dbpassword):
if envfile:
try:
with open(envfile) as f:
print('Will use the following env parameters')
print(f.readlines())
pass
except FileNotFoundError:
print(f'No file named {envfile}')
envfile = None
if dev: if dev:
debug = True debug = True
reload = True reload = True
@ -87,6 +98,7 @@ def run(host, port, debug, dev, dbname, dbhost, dbport, dbuser, dbpassword):
sys.path.insert(0, os.getcwd()) sys.path.insert(0, os.getcwd())
click.echo(sys.path) click.echo(sys.path)
uvicorn.run('halfapi.app:app', uvicorn.run('halfapi.app:app',
env_file=envfile,
host=host, host=host,
port=int(port), port=int(port),
log_level=log_level, log_level=log_level,

View File

@ -1,4 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from os import environ
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from starlette.middleware.base import BaseHTTPMiddleware from starlette.middleware.base import BaseHTTPMiddleware
from starlette.routing import Match, Mount from starlette.routing import Match, Mount
@ -6,7 +8,11 @@ from starlette.types import ASGIApp, Receive, Scope, Send
from halfapi.models.api.view.acl import Acl as AclView from halfapi.models.api.view.acl import Acl as AclView
def match_route(scope: Scope): class DebugRouteException(Exception):
def __init__(self, *args, **kwargs):
super().__init__(self)
def match_route(app: ASGIApp, scope: Scope):
""" Checks all routes from "app" and checks if it matches with the one from """ Checks all routes from "app" and checks if it matches with the one from
scope scope
@ -30,7 +36,10 @@ def match_route(scope: Scope):
Refer to the database documentation for more details on the api.route Refer to the database documentation for more details on the api.route
table. table.
""" """
from halfapi.app import app
print('3')
from ..app import CONFIG
print(CONFIG)
result = { result = {
'domain': None, 'domain': None,
@ -39,6 +48,9 @@ def match_route(scope: Scope):
'version': None 'version': None
} }
if 'DEBUG' in CONFIG.keys() and len(scope['path'].split('/')) <= 3:
raise DebugRouteException()
try: try:
""" Identification of the parts of the path """ Identification of the parts of the path
@ -51,7 +63,6 @@ def match_route(scope: Scope):
except ValueError as e: except ValueError as e:
#404 Not found #404 Not found
raise HTTPException(404) raise HTTPException(404)
# Prefix the path with "/" # Prefix the path with "/"
path = f'/{path}' path = f'/{path}'
@ -111,13 +122,18 @@ class AclCallerMiddleware(BaseHTTPMiddleware):
await self.app(scope, receive, send) await self.app(scope, receive, send)
return return
app = self.app
while True:
if not hasattr(app, 'app'):
break
app = app.app
if scope['path'].split('/')[-1] not in ['docs','openapi.json','redoc']: if scope['path'].split('/')[-1] not in ['docs','openapi.json','redoc']:
# routes in the the database, the others being # routes in the the database, the others being
# docs/openapi.json/redoc # docs/openapi.json/redoc
d_match, path_params = match_route(scope)
try: try:
d_match, path_params = match_route(app, scope)
scope['acls'] = [] scope['acls'] = []
for acl in AclView(**d_match).select(): for acl in AclView(**d_match).select():
# retrieve related ACLs # retrieve related ACLs
@ -132,5 +148,11 @@ class AclCallerMiddleware(BaseHTTPMiddleware):
# TODO : No ACL sur une route existante, prevenir l'admin? # TODO : No ACL sur une route existante, prevenir l'admin?
print("No ACL") print("No ACL")
pass pass
except DebugRouteException:
print("Debug route")
if 'DEBUG_ACL' in environ.keys():
scope['acls'] = environ['DEBUG_ACL'].split(':')
else:
scope['acls'] = []
return await self.app(scope, receive, send) return await self.app(scope, receive, send)

View File

@ -5,12 +5,13 @@ from datetime import date
from io import TextIOBase, StringIO from io import TextIOBase, StringIO
# asgi framework # asgi framework
from starlette.responses import Response from starlette.responses import PlainTextResponse, Response
__all__ = ['CSVResponse', __all__ = ['CSVResponse',
'InternalServerErrorResponse', 'InternalServerErrorResponse',
'NotFoundResponse', 'NotFoundResponse',
'NotImplementedResponse', 'NotImplementedResponse',
'PlainTextResponse',
'UnauthorizedResponse'] 'UnauthorizedResponse']
class CSVResponse(Response): class CSVResponse(Response):
@ -32,27 +33,27 @@ class CSVResponse(Response):
class InternalServerErrorResponse(Response): class InternalServerErrorResponse(Response):
""" The 500 Internal Server Error default Response """ The 500 Internal Server Error default Response
""" """
def __init__(self): def __init__(self, *args, **kwargs):
super().__init__(status_code=500) super().__init__(status_code=500)
class NotFoundResponse(Response): class NotFoundResponse(Response):
""" The 404 Not Found default Response """ The 404 Not Found default Response
""" """
def __init__(self): def __init__(self, *args, **kwargs):
super().__init__(status_code=404) super().__init__(status_code=404)
class NotImplementedResponse(Response): class NotImplementedResponse(Response):
""" The 501 Not Implemented default Response """ The 501 Not Implemented default Response
""" """
def __init__(self): def __init__(self, *args, **kwargs):
super().__init__(status_code=501) super().__init__(status_code=501)
class UnauthorizedResponse(Response): class UnauthorizedResponse(Response):
""" The 401 Not Found default Response """ The 401 Not Found default Response
""" """
def __init__(self): def __init__(self, *args, **kwargs):
super().__init__(status_code = 401) super().__init__(status_code = 401)

79
poetry.lock generated
View File

@ -1,6 +1,7 @@
[[package]] [[package]]
category = "dev" category = "dev"
description = "Atomic file writes." description = "Atomic file writes."
marker = "sys_platform == \"win32\""
name = "atomicwrites" name = "atomicwrites"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
@ -53,6 +54,14 @@ optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "0.4.3" version = "0.4.3"
[[package]]
category = "main"
description = "Handle .env files"
name = "dotenv"
optional = false
python-versions = "*"
version = "0.0.5"
[[package]] [[package]]
category = "main" category = "main"
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
@ -95,6 +104,7 @@ psycopg2-binary = "*"
reference = "fe53195abb637d2192857e8b4878f4865b0fcce4" reference = "fe53195abb637d2192857e8b4878f4865b0fcce4"
type = "git" type = "git"
url = "git@gite.lirmm.fr:newsi/halfORM.git" url = "git@gite.lirmm.fr:newsi/halfORM.git"
[[package]] [[package]]
category = "main" category = "main"
description = "A collection of framework independent HTTP protocol utils." description = "A collection of framework independent HTTP protocol utils."
@ -159,6 +169,19 @@ uvicorn = "*"
reference = "4f9cf92253b2ee526a528724877840c8ec158d3a" reference = "4f9cf92253b2ee526a528724877840c8ec158d3a"
type = "git" type = "git"
url = "git@gite.lirmm.fr:newsi/api/organigramme.git" url = "git@gite.lirmm.fr:newsi/api/organigramme.git"
[[package]]
category = "dev"
description = "Core utilities for Python packages"
name = "packaging"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "20.4"
[package.dependencies]
pyparsing = ">=2.0.2"
six = "*"
[[package]] [[package]]
category = "dev" category = "dev"
description = "plugin and hook calling mechanisms for python" description = "plugin and hook calling mechanisms for python"
@ -217,23 +240,39 @@ crypto = ["cryptography (>=1.4)"]
flake8 = ["flake8", "flake8-import-order", "pep8-naming"] flake8 = ["flake8", "flake8-import-order", "pep8-naming"]
test = ["pytest (>=4.0.1,<5.0.0)", "pytest-cov (>=2.6.0,<3.0.0)", "pytest-runner (>=4.2,<5.0.0)"] test = ["pytest (>=4.0.1,<5.0.0)", "pytest-cov (>=2.6.0,<3.0.0)", "pytest-runner (>=4.2,<5.0.0)"]
[[package]]
category = "dev"
description = "Python parsing module"
name = "pyparsing"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
version = "2.4.7"
[[package]] [[package]]
category = "dev" category = "dev"
description = "pytest: simple powerful testing with Python" description = "pytest: simple powerful testing with Python"
name = "pytest" name = "pytest"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=3.5"
version = "3.10.1" version = "5.4.3"
[package.dependencies] [package.dependencies]
atomicwrites = ">=1.0" atomicwrites = ">=1.0"
attrs = ">=17.4.0" attrs = ">=17.4.0"
colorama = "*" colorama = "*"
more-itertools = ">=4.0.0" more-itertools = ">=4.0.0"
pluggy = ">=0.7" packaging = "*"
pluggy = ">=0.12,<1.0"
py = ">=1.5.0" py = ">=1.5.0"
setuptools = "*" wcwidth = "*"
six = ">=1.10.0"
[package.dependencies.importlib-metadata]
python = "<3.8"
version = ">=0.12"
[package.extras]
checkqa-mypy = ["mypy (v0.761)"]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
[[package]] [[package]]
category = "main" category = "main"
@ -276,6 +315,7 @@ half_orm = "*"
reference = "d0f14a9631eecd29098d13a3f34e9cd533145f24" reference = "d0f14a9631eecd29098d13a3f34e9cd533145f24"
type = "git" type = "git"
url = "git@gite.lirmm.fr:newsi/sidb_halfORM.git" url = "git@gite.lirmm.fr:newsi/sidb_halfORM.git"
[[package]] [[package]]
category = "dev" category = "dev"
description = "Python 2 and 3 compatibility utilities" description = "Python 2 and 3 compatibility utilities"
@ -335,6 +375,14 @@ optional = false
python-versions = "*" python-versions = "*"
version = "0.14.0" version = "0.14.0"
[[package]]
category = "dev"
description = "Measures the displayed width of unicode strings in a terminal"
name = "wcwidth"
optional = false
python-versions = "*"
version = "0.2.5"
[[package]] [[package]]
category = "main" category = "main"
description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
@ -360,7 +408,7 @@ testing = ["jaraco.itertools", "func-timeout"]
organigramme = ["fastapi", "organigramme"] organigramme = ["fastapi", "organigramme"]
[metadata] [metadata]
content-hash = "54154bcf65bf5540092d6493dd5810fb541bc4a75e9fc328ca66d25ef5ed0584" content-hash = "56e1f269ca07039fa6898fa427261f61cab9ef871c5a82edb592cbfb197c2d03"
python-versions = "^3.7" python-versions = "^3.7"
[metadata.files] [metadata.files]
@ -388,6 +436,9 @@ colorama = [
{file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"}, {file = "colorama-0.4.3-py2.py3-none-any.whl", hash = "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff"},
{file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"}, {file = "colorama-0.4.3.tar.gz", hash = "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1"},
] ]
dotenv = [
{file = "dotenv-0.0.5.tar.gz", hash = "sha256:b58d2ab3f83dbd4f8a362b21158a606bee87317a9444485566b3c8f0af847091"},
]
fastapi = [ fastapi = [
{file = "fastapi-0.58.1-py3-none-any.whl", hash = "sha256:d7499761d5ca901cdf5b6b73018d14729593f8ab1ea22d241f82fa574fc406ad"}, {file = "fastapi-0.58.1-py3-none-any.whl", hash = "sha256:d7499761d5ca901cdf5b6b73018d14729593f8ab1ea22d241f82fa574fc406ad"},
{file = "fastapi-0.58.1.tar.gz", hash = "sha256:92e59b77eef7d6eaa80b16d275adda06b5f33b12d777e3fc5521b2f7f4718e13"}, {file = "fastapi-0.58.1.tar.gz", hash = "sha256:92e59b77eef7d6eaa80b16d275adda06b5f33b12d777e3fc5521b2f7f4718e13"},
@ -424,6 +475,10 @@ more-itertools = [
{file = "more_itertools-8.4.0-py3-none-any.whl", hash = "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2"}, {file = "more_itertools-8.4.0-py3-none-any.whl", hash = "sha256:b78134b2063dd214000685165d81c154522c3ee0a1c0d4d113c80361c234c5a2"},
] ]
organigramme = [] organigramme = []
packaging = [
{file = "packaging-20.4-py2.py3-none-any.whl", hash = "sha256:998416ba6962ae7fbd6596850b80e17859a5753ba17c32284f67bfff33784181"},
{file = "packaging-20.4.tar.gz", hash = "sha256:4357f74f47b9c12db93624a82154e9b120fa8293699949152b22065d556079f8"},
]
pluggy = [ pluggy = [
{file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"}, {file = "pluggy-0.13.1-py2.py3-none-any.whl", hash = "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"},
{file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"},
@ -487,9 +542,13 @@ pyjwt = [
{file = "PyJWT-1.7.1-py2.py3-none-any.whl", hash = "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e"}, {file = "PyJWT-1.7.1-py2.py3-none-any.whl", hash = "sha256:5c6eca3c2940464d106b99ba83b00c6add741c9becaec087fb7ccdefea71350e"},
{file = "PyJWT-1.7.1.tar.gz", hash = "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"}, {file = "PyJWT-1.7.1.tar.gz", hash = "sha256:8d59a976fb773f3e6a39c85636357c4f0e242707394cadadd9814f5cbaa20e96"},
] ]
pyparsing = [
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
]
pytest = [ pytest = [
{file = "pytest-3.10.1-py2.py3-none-any.whl", hash = "sha256:3f193df1cfe1d1609d4c583838bea3d532b18d6160fd3f55c9447fdca30848ec"}, {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"},
{file = "pytest-3.10.1.tar.gz", hash = "sha256:e246cf173c01169b9617fc07264b7b1316e78d7a650055235d6d897bc80d9660"}, {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"},
] ]
pyyaml = [ pyyaml = [
{file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"}, {file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"},
@ -536,6 +595,10 @@ uvloop = [
{file = "uvloop-0.14.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4315d2ec3ca393dd5bc0b0089d23101276778c304d42faff5dc4579cb6caef09"}, {file = "uvloop-0.14.0-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:4315d2ec3ca393dd5bc0b0089d23101276778c304d42faff5dc4579cb6caef09"},
{file = "uvloop-0.14.0.tar.gz", hash = "sha256:123ac9c0c7dd71464f58f1b4ee0bbd81285d96cdda8bc3519281b8973e3a461e"}, {file = "uvloop-0.14.0.tar.gz", hash = "sha256:123ac9c0c7dd71464f58f1b4ee0bbd81285d96cdda8bc3519281b8973e3a461e"},
] ]
wcwidth = [
{file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
{file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
]
websockets = [ websockets = [
{file = "websockets-8.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:3762791ab8b38948f0c4d281c8b2ddfa99b7e510e46bd8dfa942a5fff621068c"}, {file = "websockets-8.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:3762791ab8b38948f0c4d281c8b2ddfa99b7e510e46bd8dfa942a5fff621068c"},
{file = "websockets-8.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:3db87421956f1b0779a7564915875ba774295cc86e81bc671631379371af1170"}, {file = "websockets-8.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:3db87421956f1b0779a7564915875ba774295cc86e81bc671631379371af1170"},

View File

@ -22,9 +22,9 @@ requests = "^2"
[tool.poetry.extras] [tool.poetry.extras]
organigramme = [ "fastapi", "organigramme" ] organigramme = [ "fastapi", "organigramme" ]
[tool.poetry.scripts]
halfapi = 'halfapi.cli:cli'
[build-system] [build-system]
requires = ["poetry>=0.12"] requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api" build-backend = "poetry.masonry.api"
[tool.poetry.scripts]
halfapi = 'halfapi.cli:cli'