diff --git a/server/src/uds/REST/documentation.py b/server/src/uds/REST/documentation.py index 079d19bb4..5bdc06db0 100644 --- a/server/src/uds/REST/documentation.py +++ b/server/src/uds/REST/documentation.py @@ -30,6 +30,7 @@ Author: Adolfo Gómez, dkmaster at dkmon dot com """ import dataclasses +import enum import logging import typing @@ -49,6 +50,49 @@ if typing.TYPE_CHECKING: logger = logging.getLogger(__name__) +@dataclasses.dataclass +class HelpMethodInfo: + method: str + params: list[str] + text: str + + @property + def methods(self) -> typing.Generator[str, None, None]: + for param in self.params: + if param == '': + yield self.method + else: + if (self.method + ' ')[0] == '-': + yield f'<{param}>/{self.method[1:]}' + elif self.method: + yield f'{self.method}/<{param}>' + else: + yield f'<{param}>' + + def __str__(self) -> str: + return ', '.join(self.methods) + + def __repr__(self) -> str: + return self.__str__() + + +class HelpMethod(enum.Enum): + ITEM = HelpMethodInfo('', ['uuid'], 'Retrieves an item by its UUID') + LOG = HelpMethodInfo('-' + consts.rest.LOG, ['uuid'], 'Retrieves the log of an item') + OVERVIEW = HelpMethodInfo(consts.rest.OVERVIEW, [''], 'General Overview of all items (a list') + TABLEINFO = HelpMethodInfo(consts.rest.TABLEINFO, [''], 'Table visualization information (types, etc..)') + TYPES = HelpMethodInfo(consts.rest.TYPES, ['', 'type'], 'Types information') + GUI = HelpMethodInfo(consts.rest.GUI, ['', 'type'], 'GUI information') + + +@dataclasses.dataclass +class HelpInfo: + level: int + path: str + text: str + methods: list[HelpMethod] + + class Documentation(View): def dispatch( @@ -61,21 +105,29 @@ class Documentation(View): if not request.user.get_role().can_access(consts.UserRole.STAFF): return auth.weblogout(request) - @dataclasses.dataclass - class HelpInfo: - level: int - path: str - text: str - help_data: list[HelpInfo] = [] def _process_node(node: 'types.rest.HelpNode', path: str, level: int) -> None: - help_data.append(HelpInfo(level, path, node.help.text)) + if node.kind == types.rest.HelpNode.HelpNodeType.MODEL: + methods = [ + HelpMethod.OVERVIEW, + HelpMethod.GUI, + HelpMethod.TABLEINFO, + HelpMethod.TYPES, + HelpMethod.ITEM, + HelpMethod.LOG, + ] + elif node.kind == types.rest.HelpNode.HelpNodeType.DETAIL: + methods = [] + else: + methods = [] + + help_data.append(HelpInfo(level, path, node.help.text, methods)) for child in node.children: _process_node( child, - path + '/' + child.help.path, + child.help.path, level + (0 if node.kind == types.rest.HelpNode.HelpNodeType.PATH else 1), ) diff --git a/server/src/uds/REST/model/model.py b/server/src/uds/REST/model/model.py index acb6aeb6f..911380136 100644 --- a/server/src/uds/REST/model/model.py +++ b/server/src/uds/REST/model/model.py @@ -232,13 +232,13 @@ class ModelHandler(BaseModelHandler): self, *args: typing.Any, **kwargs: typing.Any ) -> typing.Generator[types.rest.ItemDictType, None, None]: if 'overview' in kwargs: - overview = kwargs['overview'] + overview: bool = kwargs['overview'] del kwargs['overview'] else: overview = True if 'prefetch' in kwargs: - prefetch = kwargs['prefetch'] + prefetch: list[str] = kwargs['prefetch'] logger.debug('Prefetching %s', prefetch) del kwargs['prefetch'] else: @@ -327,61 +327,53 @@ class ModelHandler(BaseModelHandler): return operation() - if number_of_args == 1: - if self._args[0] == consts.rest.OVERVIEW: - return list(self.get_items()) - if self._args[0] == consts.rest.TYPES: - return list(self.get_types()) - if self._args[0] == consts.rest.TABLEINFO: + match self._args[0]: + case consts.rest.OVERVIEW: + if number_of_args == 1: + return list(self.get_items()) + raise self.invalid_request_response() + case consts.rest.TABLEINFO: + if number_of_args != 1: + raise self.invalid_request_response() return self.process_table_fields( self.table_title, self.table_fields, self.table_row_style, self.table_subtitle, ) - if self._args[0] == consts.rest.GUI: - return self.get_gui('') + case consts.rest.TYPES: + if number_of_args == 1: + return list(self.get_types()) + if number_of_args != 2: + raise self.invalid_request_response() + return self.get_type(self._args[1]) + case consts.rest.GUI: + if number_of_args == 1: + return self.get_gui('') + if number_of_args != 2: + raise self.invalid_request_response() + return sorted(self.get_gui(self._args[1]), key=lambda f: f['gui']['order']) + case _: # Maybe an item or a detail + if number_of_args == 1: + try: + item = self.model.objects.get(uuid__iexact=self._args[0].lower()) + self.ensure_has_access(item, types.permissions.PermissionType.READ) + res = self.item_as_dict(item) + self.fill_instance_fields(item, res) + return res + except Exception as e: + logger.exception('Got Exception looking for item') + raise self.invalid_item_response() from e + elif number_of_args == 2: + if self._args[1] == consts.rest.LOG: + try: + item = self.model.objects.get(uuid__iexact=self._args[0].lower()) + return self.get_logs(item) + except Exception as e: + raise self.invalid_item_response() from e - # get item ID - try: - item = self.model.objects.get(uuid__iexact=self._args[0].lower()) - - self.ensure_has_access(item, types.permissions.PermissionType.READ) - - res = self.item_as_dict(item) - self.fill_instance_fields(item, res) - return res - except Exception as e: - logger.exception('Got Exception looking for item') - raise self.invalid_item_response() from e - - # nArgs > 1 - # Request type info or gui, or detail - if self._args[0] == consts.rest.OVERVIEW: - if number_of_args != 2: - raise self.invalid_request_response() - elif self._args[0] == consts.rest.TYPES: - if number_of_args != 2: - raise self.invalid_request_response() - return self.get_type(self._args[1]) - elif self._args[0] == consts.rest.GUI: - if number_of_args != 2: - raise self.invalid_request_response() - gui = self.get_gui(self._args[1]) - return sorted(gui, key=lambda f: f['gui']['order']) - elif self._args[1] == consts.rest.LOG: - if number_of_args != 2: - raise self.invalid_request_response() - try: - # DB maybe case sensitive??, anyway, uuids are stored in lowercase - item = self.model.objects.get(uuid__iexact=self._args[0].lower()) - return self.get_logs(item) - except Exception as e: - raise self.invalid_item_response() from e - - # If has detail and is requesting detail - if self.detail is not None: - return self.process_detail() + if self.detail is not None: + return self.process_detail() raise self.invalid_request_response() # Will not return diff --git a/server/src/uds/templates/uds/modern/documentation.html b/server/src/uds/templates/uds/modern/documentation.html index 8fb8ad3ad..3dabb25ad 100644 --- a/server/src/uds/templates/uds/modern/documentation.html +++ b/server/src/uds/templates/uds/modern/documentation.html @@ -28,7 +28,15 @@