[wip][routing] updated lib.domain function names

This commit is contained in:
Maxime Alves LIRMM 2020-09-22 14:26:46 +02:00
parent 38798549f6
commit 5f7d66d4d6
4 changed files with 43 additions and 84 deletions

View File

@ -16,11 +16,10 @@ from halfapi.conf import HOST, PORT, DB_NAME, SECRET, PRODUCTION, DOMAINS
from halfapi.lib.jwt_middleware import JWTAuthenticationBackend from halfapi.lib.jwt_middleware import JWTAuthenticationBackend
from halfapi.lib.responses import * from halfapi.lib.responses import *
from halfapi.lib.routes import get_starlette_routes from halfapi.lib.routes import gen_starlette_routes
from halfapi.lib.domain import domain_scanner
debug_routes = [ routes = [
Route('/', lambda request, *args, **kwargs: PlainTextResponse('It Works!')), Route('/', lambda request, *args, **kwargs: PlainTextResponse('It Works!')),
Route('/user', lambda request, *args, **kwargs: Route('/user', lambda request, *args, **kwargs:
JSONResponse({'user':request.user.json}) JSONResponse({'user':request.user.json})
@ -30,10 +29,12 @@ debug_routes = [
JSONResponse({'payload':str(request.payload)})) JSONResponse({'payload':str(request.payload)}))
] if not PRODUCTION else [] ] if not PRODUCTION else []
for route in gen_starlette_routes():
routes.append(route)
application = Starlette( application = Starlette(
debug=not PRODUCTION, debug=not PRODUCTION,
routes=debug_routes + [ route for route in routes=routes,
gen_starlette_routes(domain_scanner()) ],
middleware=[ middleware=[
Middleware(AuthenticationMiddleware, Middleware(AuthenticationMiddleware,
backend=JWTAuthenticationBackend(secret_key=SECRET)) backend=JWTAuthenticationBackend(secret_key=SECRET))

View File

@ -103,57 +103,6 @@ def update_db(domain):
acl.insert() acl.insert()
def get_fct_name(http_verb, path):
"""
Returns the predictable name of the function for a route
Parameters:
- http_verb (str): The Route's HTTP method (GET, POST, ...)
- path (str): A path beginning by '/' for the route
Returns:
str: The *unique* function name for a route and it's verb
Examples:
>>> get_fct_name('foo', 'bar')
Traceback (most recent call last):
...
Exception: Malformed path
>>> get_fct_name('get', '/')
'get_'
>>> get_fct_name('GET', '/')
'get_'
>>> get_fct_name('POST', '/foo')
'post_foo'
>>> get_fct_name('POST', '/foo/bar')
'post_foo_bar'
>>> get_fct_name('DEL', '/foo/{boo}/{far}/bar')
'del_foo_BOO_FAR_bar'
>>> get_fct_name('DEL', '/foo/{boo:zoo}')
'del_foo_BOO'
"""
if path[0] != '/':
raise Exception('Malformed path')
elts = path[1:].split('/')
fct_name = [http_verb.lower()]
for elt in elts:
if elt and elt[0] == '{':
fct_name.append(elt[1:-1].split(':')[0].upper())
else:
fct_name.append(elt)
return '_'.join(fct_name)
def add_route(http_verb, path, router, acls): def add_route(http_verb, path, router, acls):
@ -216,8 +165,11 @@ def update_db(domain):
for router_name in dom_mod.ROUTERS: for router_name in dom_mod.ROUTERS:
try: try:
router_mod = getattr(dom_mod.routers, router_name) router_mod = None
except AttributError: for router_subname in router_name.split('.'):
router_mod = getattr(router_mod or dom_mod.routers, router_subname)
except AttributeError:
# Missing router, continue # Missing router, continue
click.echo(f'The domain {domain} has no *{router_name}* router', err=True) click.echo(f'The domain {domain} has no *{router_name}* router', err=True)
continue continue
@ -232,7 +184,23 @@ def update_db(domain):
continue continue
for route_path, route_params in router_mod.ROUTES.items(): d_routes = {}
if hasattr(router_mod, 'ROUTES'):
d_routes.update(router_mod.ROUTES)
else:
logger.warning(f'{router_name} is missing a ROUTES variable')
if hasattr(router_mod, 'ROUTERS'):
for router_router in router_mod.ROUTERS:
if hasattr(router_router, 'ROUTES'):
d_routes.update(router_routes.ROUTES)
else:
logger.warning(f'{router_name}.{router_router.__name__} is missing a ROUTES variable')
else:
logger.warning(f'{router_mod} is missing a ROUTERS variable')
for route_path, route_params in d_routes.items():
for http_verb, acls in route_params.items(): for http_verb, acls in route_params.items():
try: try:
# Insert a route and it's ACLS # Insert a route and it's ACLS
@ -274,6 +242,7 @@ def domain(domains, delete, update, create, read): #, domains, read, create, up
update (boolean): If set, update the database for the selected domains update (boolean): If set, update the database for the selected domains
""" """
raise NotImplementedError
if not domains: if not domains:
if create: if create:

View File

@ -50,7 +50,7 @@ def get_fct_name(http_verb, path: t.List):
return '_'.join(fct_name) return '_'.join(fct_name)
def route_generator(route_params, path, m_router): def gen_routes(route_params, path, m_router):
for verb in VERBS: for verb in VERBS:
params = route_params.get(verb) params = route_params.get(verb)
if params is None: if params is None:
@ -67,12 +67,12 @@ def route_generator(route_params, path, m_router):
yield { yield {
'verb':verb, 'verb':verb,
'path':'/'.join([ elt for elt in path if elt ]), 'path':f"/{'/'.join([ elt for elt in path if elt ])}",
'params':params, 'params':params,
'fct': fct } 'fct': fct }
def router_scanner(m_router, path=[]): def gen_router_routes(m_router, path=[]):
""" """
[ [
('path', [acl], fct) ('path', [acl], fct)
@ -80,7 +80,7 @@ def router_scanner(m_router, path=[]):
""" """
if not hasattr(m_router, 'ROUTES'): if not hasattr(m_router, 'ROUTES'):
print(f'Missing *ROUTES* constant in *{domain}.routers*') print(f'Missing *ROUTES* constant in *{m_router.__name__}*')
routes = m_router.ROUTES routes = m_router.ROUTES
@ -88,14 +88,14 @@ def router_scanner(m_router, path=[]):
for subpath, route_params in routes.items(): for subpath, route_params in routes.items():
path.append(subpath) path.append(subpath)
for route in route_generator(route_params, path, m_router): for route in gen_routes(route_params, path, m_router):
yield route yield route
subroutes = route_params.get('SUBROUTES', []) subroutes = route_params.get('SUBROUTES', [])
for subroute in subroutes: for subroute in subroutes:
path.append(subroute) path.append(subroute)
submod = importlib.import_module(f'.{subroute}', m_router.__name__) submod = importlib.import_module(f'.{subroute}', m_router.__name__)
for route_scan in router_scanner(submod, path): for route_scan in gen_router_routes(submod, path):
yield route_scan yield route_scan
path.pop() path.pop()
@ -106,7 +106,7 @@ def router_scanner(m_router, path=[]):
def domain_scanner(domain): def gen_domain_routes(domain):
m_domain = importlib.import_module(domain) m_domain = importlib.import_module(domain)
if not hasattr(m_domain, 'routers'): if not hasattr(m_domain, 'routers'):
@ -114,4 +114,4 @@ def domain_scanner(domain):
m_router = importlib.import_module('.routers', domain) m_router = importlib.import_module('.routers', domain)
return router_scanner(m_router) return gen_router_routes(m_router, [domain])

View File

@ -14,7 +14,7 @@ from halfapi.db import (
AclFunction, AclFunction,
Acl) Acl)
from halfapi.lib.responses import * from halfapi.lib.responses import *
from halfapi.lib.domain import domain_scanner from halfapi.lib.domain import gen_domain_routes
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from starlette.routing import Mount, Route from starlette.routing import Mount, Route
from starlette.requests import Request from starlette.requests import Request
@ -26,8 +26,7 @@ def route_decorator(fct: Callable, acls_mod, params: List[Dict]):
@wraps(fct) @wraps(fct)
async def caller(req: Request, *args, **kwargs): async def caller(req: Request, *args, **kwargs):
for param in params: for param in params:
acl_fct = getattr(acls_mod, param['acl']) if param['acl'](req, *args, **kwargs):
if acl_fct(req, *args, **kwargs):
""" """
We the 'acl' and 'keys' kwargs values to let the We the 'acl' and 'keys' kwargs values to let the
decorated function know which ACL function answered decorated function know which ACL function answered
@ -37,7 +36,7 @@ def route_decorator(fct: Callable, acls_mod, params: List[Dict]):
req, *args, req, *args,
**{ **{
**kwargs, **kwargs,
**params **param
}) })
raise HTTPException(401) raise HTTPException(401)
@ -49,17 +48,7 @@ def gen_starlette_routes():
domain_acl_mod = importlib.import_module( domain_acl_mod = importlib.import_module(
f'{domain}.acl') f'{domain}.acl')
( Route(route['path'], for route in gen_domain_routes(domain):
route_decorator(
route['fct'],
domain_acl_mod,
route['params'],
), methods=[route['verb']])
for route in domain_scanner(domain)
)
for route in gen_routes(domain):
yield ( yield (
Route(route['path'], Route(route['path'],
route_decorator( route_decorator(