150 lines
4.8 KiB
Python
150 lines
4.8 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
from typing import Self, Any, Sequence, Callable
|
|
from re import Match as REMatch, Pattern as REPattern, compile as re_compile
|
|
from Abstracts.RouteAbstract import RouteAbstract
|
|
from Utils.Common import Common
|
|
from Utils.Checks import Check
|
|
from Utils.Patterns import RE
|
|
from Models.RequestModel import RequestModel
|
|
|
|
class RouteModel(RouteAbstract):
|
|
|
|
def __init__(self:Self, inputs:str|dict[str, Any|None]|Sequence[Any|None]) -> None:
|
|
|
|
request:str|REPattern
|
|
self.method:str
|
|
self.request:REPattern
|
|
self.action:str|None = None
|
|
self.controller:str|None = None
|
|
self.path:str|None = None
|
|
self.callback:Callable[[RequestModel], None]|None = None
|
|
self.permissions:list[str] = []
|
|
self.variables:list[str] = []
|
|
self.error:int = 0
|
|
self.keys:list[str] = []
|
|
self.has_keys:bool = False
|
|
|
|
if Check.is_string(inputs):
|
|
|
|
matches:REMatch = RE.ROUTE.match(inputs.strip())
|
|
|
|
if matches is not None:
|
|
|
|
permissions:str|None
|
|
method:str|None
|
|
raw_keys:str|None
|
|
|
|
raw_keys, method, request, self.action, self.controller, self.path, permissions = matches.groups()
|
|
|
|
self.method = "get" if method is None else method.lower()
|
|
if permissions is not None and (permissions := permissions.strip()) != "":
|
|
self.permissions.extend(permissions.split(","))
|
|
|
|
raw_keys and self.keys.extend(raw_keys.split(","))
|
|
|
|
elif Check.is_dictionary(inputs):
|
|
|
|
preaction:str|Callable[[RequestModel], None]|None = Common.get_value("action", inputs)
|
|
|
|
self.method = Common.get_value("method", inputs, "get").lower()
|
|
request = Common.get_value("request", inputs, "/")
|
|
self.controller = Common.get_value("controller", inputs)
|
|
self.path = Common.get_value("path", inputs)
|
|
self.permissions.extend(Common.get_value("permissions", inputs, []))
|
|
self.keys.extend(Common.get_value("keys", inputs, []))
|
|
|
|
if Check.is_function(preaction):
|
|
self.callback = preaction
|
|
elif Check.is_key(preaction):
|
|
self.action = preaction
|
|
|
|
elif Check.is_array(inputs):
|
|
|
|
l:int = len(inputs)
|
|
preaction:str|Callable[[RequestModel], None]|None
|
|
i:int = 4
|
|
|
|
if l < 4:
|
|
self.error = 1 << 1
|
|
return
|
|
|
|
self.keys, self.method, request, preaction = inputs[:4]
|
|
while l > i:
|
|
if Check.is_key(inputs[i]):
|
|
self.controller = inputs[i]
|
|
elif Check.is_array(inputs[i]):
|
|
self.permissions.extend(inputs[i])
|
|
i += 1
|
|
|
|
if Check.is_function(preaction):
|
|
self.callback = preaction
|
|
elif Check.is_key(preaction):
|
|
self.action = preaction
|
|
|
|
else:
|
|
self.error = 1 << 0
|
|
|
|
if not self.error and not self.path and not self.callback and (
|
|
not self.action or not self.controller
|
|
):
|
|
self.error = 1 << 2
|
|
|
|
if not self.error:
|
|
if Check.is_string(request):
|
|
|
|
def callback(matches:REMatch) -> str:
|
|
|
|
self.variables.append(matches.group(1))
|
|
|
|
return r'([^\/]+)'
|
|
|
|
self.request = re_compile(r'^' + RE.ROUTE_KEY.sub(callback, Common.to_regular_expression(
|
|
request[:-1] if request[-1] == "/" else request
|
|
)) + (r'\/?' if self.path is None else r'(\/.*)?') + r'$')
|
|
|
|
elif Check.is_regular_expression(request):
|
|
request = request.pattern
|
|
else:
|
|
self.error = 1 << 3
|
|
|
|
self.has_keys = len(self.keys) > 0
|
|
|
|
def match(self:Self, keys:list[str], method:str, path:str, request:RequestModel) -> bool:
|
|
|
|
is_in_keys:bool = True
|
|
|
|
if self.has_keys:
|
|
|
|
key:str
|
|
|
|
is_in_keys = False
|
|
|
|
for key in keys:
|
|
if key in self.keys:
|
|
is_in_keys = True
|
|
break
|
|
|
|
if is_in_keys and self.method == method.lower():
|
|
|
|
matches:REMatch = self.request.match(path)
|
|
|
|
if matches is not None:
|
|
|
|
i:int
|
|
variable:str
|
|
|
|
for i, variable in enumerate(self.variables):
|
|
request.variables[variable] = matches.group(i + 1)
|
|
|
|
if self.error:
|
|
request.set_response({
|
|
"ok" : False,
|
|
"code" : 501,
|
|
"message" : "invalid_route_configuration",
|
|
"route_error" : self.error
|
|
})
|
|
|
|
return True
|
|
return False |