AnP/Python/Models/RouteModel.py

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