[wip][routing] updated lib.domain function names
This commit is contained in:
parent
38798549f6
commit
5f7d66d4d6
|
@ -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))
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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])
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in New Issue