jumpserver/apps/common/drf/metadata.py

182 lines
6.4 KiB
Python
Raw Normal View History

2019-05-16 06:41:11 +00:00
# -*- coding: utf-8 -*-
#
from __future__ import unicode_literals
import datetime
2022-11-11 07:04:31 +00:00
from collections import OrderedDict
2019-05-16 06:41:11 +00:00
from django.core.exceptions import PermissionDenied
from django.http import Http404
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
2022-11-11 07:04:31 +00:00
from rest_framework import exceptions, serializers
2020-10-19 12:13:01 +00:00
from rest_framework.fields import empty
2019-05-16 06:41:11 +00:00
from rest_framework.metadata import SimpleMetadata
from rest_framework.request import clone_request
2022-11-11 09:28:13 +00:00
from common.drf.fields import TreeChoicesMixin
2019-05-16 06:41:11 +00:00
class SimpleMetadataWithFilters(SimpleMetadata):
"""Override SimpleMetadata, adding info about filters"""
methods = {"PUT", "POST", "GET", "PATCH"}
2019-05-16 06:41:11 +00:00
attrs = [
2022-11-11 07:04:31 +00:00
"read_only",
"label",
"help_text",
"min_length",
"max_length",
"min_value",
"max_value",
"write_only",
2019-05-16 06:41:11 +00:00
]
def determine_actions(self, request, view):
"""
For generic class based views we return information about
the fields that are accepted for 'PUT' and 'POST' methods.
"""
actions = {}
2022-11-11 07:04:31 +00:00
view.raw_action = getattr(view, "action", None)
2019-05-16 06:41:11 +00:00
for method in self.methods & set(view.allowed_methods):
2022-11-11 07:04:31 +00:00
if hasattr(view, "action_map"):
2021-06-02 11:11:08 +00:00
view.action = view.action_map.get(method.lower(), view.action)
2019-05-16 06:41:11 +00:00
view.request = clone_request(request, method)
try:
# Test global permissions
2022-11-11 07:04:31 +00:00
if hasattr(view, "check_permissions"):
2019-05-16 06:41:11 +00:00
view.check_permissions(view.request)
# Test object permissions
2022-11-11 07:04:31 +00:00
if method == "PUT" and hasattr(view, "get_object"):
2019-05-16 06:41:11 +00:00
view.get_object()
except (exceptions.APIException, PermissionDenied, Http404):
pass
else:
# If user has appropriate permissions for the view, include
# appropriate metadata about the fields that should be supplied.
serializer = view.get_serializer()
actions[method] = self.get_serializer_info(serializer)
finally:
view.request = request
return actions
2022-11-11 09:28:13 +00:00
def get_field_type(self, field):
"""
Given a field, return a string representing the type of the field.
"""
tp = self.label_lookup[field]
class_name = field.__class__.__name__
if class_name == "LabeledChoiceField":
tp = "labeled_choice"
elif class_name == "ObjectRelatedField":
tp = "object_related_field"
elif class_name == "ManyRelatedField":
child_relation_class_name = field.child_relation.__class__.__name__
if child_relation_class_name == "ObjectRelatedField":
tp = "m2m_related_field"
return tp
@staticmethod
def set_choices_field(field, field_info):
field_info["choices"] = [
{
"value": choice_value,
"label": force_text(choice_label, strings_only=True),
}
for choice_value, choice_label in dict(field.choices).items()
]
@staticmethod
def set_tree_field(field, field_info):
field_info["tree"] = field.tree
field_info["type"] = "tree"
2019-05-16 06:41:11 +00:00
def get_field_info(self, field):
"""
Given an instance of a serializer field, return a dictionary
of metadata about it.
"""
field_info = OrderedDict()
2022-11-11 09:28:13 +00:00
field_info["type"] = self.get_field_type(field)
2022-11-11 07:04:31 +00:00
field_info["required"] = getattr(field, "required", False)
2019-05-16 06:41:11 +00:00
2022-11-11 07:04:31 +00:00
# Default value
default = getattr(field, "default", None)
if default is not None and default != empty:
if isinstance(default, (str, int, bool, float, datetime.datetime, list)):
2022-11-11 07:04:31 +00:00
field_info["default"] = default
2020-10-19 12:13:01 +00:00
2019-05-16 06:41:11 +00:00
for attr in self.attrs:
value = getattr(field, attr, None)
2022-11-11 07:04:31 +00:00
if value is not None and value != "":
2019-05-16 06:41:11 +00:00
field_info[attr] = force_text(value, strings_only=True)
2022-11-11 07:04:31 +00:00
if getattr(field, "child", None):
field_info["child"] = self.get_field_info(field.child)
elif getattr(field, "fields", None):
field_info["children"] = self.get_serializer_info(field)
2019-05-16 06:41:11 +00:00
2022-11-11 09:28:13 +00:00
if isinstance(field, TreeChoicesMixin):
self.set_tree_field(field, field_info)
elif isinstance(field, serializers.ChoiceField):
self.set_choices_field(field, field_info)
if field.field_name == 'id':
field_info['label'] = 'ID'
if field.field_name == 'org_id':
field_info['label'] = _('Organization ID')
2019-05-16 06:41:11 +00:00
return field_info
2022-11-11 07:04:31 +00:00
@staticmethod
def get_filters_fields(request, view):
2019-05-16 06:41:11 +00:00
fields = []
2022-11-11 07:04:31 +00:00
if hasattr(view, "get_filter_fields"):
fields = view.get_filter_fields(request)
2022-11-11 07:04:31 +00:00
elif hasattr(view, "filter_fields"):
2019-05-16 06:41:11 +00:00
fields = view.filter_fields
2022-11-11 07:04:31 +00:00
elif hasattr(view, "filterset_fields"):
fields = view.filterset_fields
2022-11-11 07:04:31 +00:00
elif hasattr(view, "get_filterset_fields"):
fields = view.get_filterset_fields(request)
2022-11-11 07:04:31 +00:00
elif hasattr(view, "filterset_class"):
fields = list(view.filterset_class.Meta.fields) + list(
view.filterset_class.declared_filters.keys()
)
2022-11-11 07:04:31 +00:00
if hasattr(view, "custom_filter_fields"):
# 不能写 fields += view.custom_filter_fields
# 会改变 view 的 filter_fields
fields = list(fields) + list(view.custom_filter_fields)
if isinstance(fields, dict):
fields = list(fields.keys())
2019-05-16 06:41:11 +00:00
return fields
2022-11-11 09:28:13 +00:00
@staticmethod
def get_ordering_fields(request, view):
2019-05-16 06:41:11 +00:00
fields = []
2022-11-11 07:04:31 +00:00
if hasattr(view, "get_ordering_fields"):
fields = view.get_ordering_fields(request)
2022-11-11 07:04:31 +00:00
elif hasattr(view, "ordering_fields"):
fields = view.ordering_fields
2019-05-16 06:41:11 +00:00
return fields
def determine_metadata(self, request, view):
2022-11-11 07:04:31 +00:00
metadata = super(SimpleMetadataWithFilters, self).determine_metadata(
request, view
)
filterset_fields = self.get_filters_fields(request, view)
2019-05-16 06:41:11 +00:00
order_fields = self.get_ordering_fields(request, view)
meta_get = metadata.get("actions", {}).get("GET", {})
for k, v in meta_get.items():
if k in filterset_fields:
2019-05-16 06:41:11 +00:00
v["filter"] = True
if k in order_fields:
v["order"] = True
return metadata