mirror of
https://github.com/dkmstr/openuds.git
synced 2025-03-20 06:50:23 +03:00
Add HelpMethod and HelpMethodInfo classes for improved API documentation
This commit is contained in:
parent
b41a1afd43
commit
4c59a25092
@ -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),
|
||||
)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -28,7 +28,15 @@
|
||||
<div class="doc">
|
||||
{% for h in help %}
|
||||
<div class="doc-item">
|
||||
{{ h }}
|
||||
{% if h.methods %}
|
||||
<div class="doc-item-methods">
|
||||
{% for m in h.methods %}
|
||||
{% for mm in m.value.methods %}
|
||||
<div class="doc-item-method">{{ h.path }}/{{ mm }}</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user