pref: 优化 permission actionss

pull/9075/head
ibuler 2022-11-11 17:28:13 +08:00
parent 1cd551e692
commit 9c5b3a03c6
4 changed files with 76 additions and 83 deletions

View File

@ -2,10 +2,10 @@
# #
import json import json
from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.utils.encoding import force_text
from django.core.validators import MinValueValidator, MaxValueValidator from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from common.utils import signer, crypto from common.utils import signer, crypto
@ -211,22 +211,28 @@ class BitChoices(models.IntegerChoices):
def branches(cls): def branches(cls):
return [i for i in cls] return [i for i in cls]
@classmethod
def is_tree(cls):
return False
@classmethod @classmethod
def tree(cls): def tree(cls):
if not cls.is_tree():
return []
root = [_("All"), cls.branches()] root = [_("All"), cls.branches()]
return cls.render_node(root) return [cls.render_node(root)]
@classmethod @classmethod
def render_node(cls, node): def render_node(cls, node):
if isinstance(node, BitChoices): if isinstance(node, BitChoices):
return { return {
"id": node.name, "value": node.name,
"label": node.label, "label": node.label,
} }
else: else:
name, children = node name, children = node
return { return {
"id": name, "value": name,
"label": name, "label": name,
"children": [cls.render_node(child) for child in children], "children": [cls.render_node(child) for child in children],
} }

View File

@ -2,11 +2,11 @@
# #
import six import six
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.db.models import IntegerChoices
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from rest_framework.fields import ChoiceField from rest_framework.fields import ChoiceField
from common.db.fields import BitChoices
from common.utils import decrypt_password from common.utils import decrypt_password
__all__ = [ __all__ = [
@ -15,6 +15,7 @@ __all__ = [
"LabeledChoiceField", "LabeledChoiceField",
"ObjectRelatedField", "ObjectRelatedField",
"BitChoicesField", "BitChoicesField",
"TreeChoicesMixin"
] ]
@ -102,14 +103,19 @@ class ObjectRelatedField(serializers.RelatedField):
self.fail("incorrect_type", data_type=type(pk).__name__) self.fail("incorrect_type", data_type=type(pk).__name__)
class BitChoicesField(serializers.MultipleChoiceField): class TreeChoicesMixin:
tree = []
class BitChoicesField(TreeChoicesMixin, serializers.MultipleChoiceField):
""" """
位字段 位字段
""" """
def __init__(self, choice_cls, **kwargs): def __init__(self, choice_cls, **kwargs):
assert issubclass(choice_cls, IntegerChoices) assert issubclass(choice_cls, BitChoices)
choices = [(c.name, c.label) for c in choice_cls] choices = [(c.name, c.label) for c in choice_cls]
self.tree = choice_cls.tree()
self._choice_cls = choice_cls self._choice_cls = choice_cls
super().__init__(choices=choices, **kwargs) super().__init__(choices=choices, **kwargs)

View File

@ -13,6 +13,8 @@ from rest_framework.fields import empty
from rest_framework.metadata import SimpleMetadata from rest_framework.metadata import SimpleMetadata
from rest_framework.request import clone_request from rest_framework.request import clone_request
from common.drf.fields import TreeChoicesMixin
class SimpleMetadataWithFilters(SimpleMetadata): class SimpleMetadataWithFilters(SimpleMetadata):
"""Override SimpleMetadata, adding info about filters""" """Override SimpleMetadata, adding info about filters"""
@ -59,13 +61,45 @@ class SimpleMetadataWithFilters(SimpleMetadata):
view.request = request view.request = request
return actions return actions
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"
def get_field_info(self, field): def get_field_info(self, field):
""" """
Given an instance of a serializer field, return a dictionary Given an instance of a serializer field, return a dictionary
of metadata about it. of metadata about it.
""" """
field_info = OrderedDict() field_info = OrderedDict()
field_info["type"] = self.label_lookup[field] field_info["type"] = self.get_field_type(field)
field_info["required"] = getattr(field, "required", False) field_info["required"] = getattr(field, "required", False)
# Default value # Default value
@ -84,25 +118,10 @@ class SimpleMetadataWithFilters(SimpleMetadata):
elif getattr(field, "fields", None): elif getattr(field, "fields", None):
field_info["children"] = self.get_serializer_info(field) field_info["children"] = self.get_serializer_info(field)
is_choice_field = isinstance(field, (serializers.ChoiceField,)) if isinstance(field, TreeChoicesMixin):
if is_choice_field and hasattr(field, "choices"): self.set_tree_field(field, field_info)
field_info["choices"] = [ elif isinstance(field, serializers.ChoiceField):
{ self.set_choices_field(field, field_info)
"value": choice_value,
"label": force_text(choice_label, strings_only=True),
}
for choice_value, choice_label in dict(field.choices).items()
]
class_name = field.__class__.__name__
if class_name == "LabeledChoiceField":
field_info["type"] = "labeled_choice"
elif class_name == "ObjectRelatedField":
field_info["type"] = "object_related_field"
elif class_name == "ManyRelatedField":
child_relation_class_name = field.child_relation.__class__.__name__
if child_relation_class_name == "ObjectRelatedField":
field_info["type"] = "m2m_related_field"
return field_info return field_info
@staticmethod @staticmethod
@ -130,7 +149,8 @@ class SimpleMetadataWithFilters(SimpleMetadata):
fields = list(fields.keys()) fields = list(fields.keys())
return fields return fields
def get_ordering_fields(self, request, view): @staticmethod
def get_ordering_fields(request, view):
fields = [] fields = []
if hasattr(view, "get_ordering_fields"): if hasattr(view, "get_ordering_fields"):
fields = view.get_ordering_fields(request) fields = view.get_ordering_fields(request)

View File

@ -3,69 +3,30 @@
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from common.utils.integer import bit
from common.db.fields import BitChoices from common.db.fields import BitChoices
from common.utils.integer import bit
__all__ = ["SpecialAccount", "ActionChoices"]
__all__ = ['SpecialAccount', 'ActionChoices']
class ActionChoices(BitChoices): class ActionChoices(BitChoices):
connect = bit(0), _('Connect') connect = bit(0), _("Connect")
upload = bit(1), _('Upload') upload = bit(1), _("Upload")
download = bit(2), _('Download') download = bit(2), _("Download")
copy = bit(3), _('Copy') copy = bit(3), _("Copy")
paste = bit(4), _('Paste') paste = bit(4), _("Paste")
@classmethod
def is_tree(cls):
return True
@classmethod @classmethod
def branches(cls): def branches(cls):
return ( return (
(_('Transfer'), [cls.upload, cls.download]), (_("Transfer"), [cls.upload, cls.download]),
(_('Clipboard'), [cls.copy, cls.paste]), (_("Clipboard"), [cls.copy, cls.paste]),
) )
# class Action(BitOperationChoice):
# CONNECT = 0b1
# UPLOAD = 0b1 << 1
# DOWNLOAD = 0b1 << 2
# COPY = 0b1 << 3
# PASTE = 0b1 << 4
# ALL = 0 << 8
# TRANSFER = UPLOAD | DOWNLOAD
# CLIPBOARD = COPY | PASTE
#
# DB_CHOICES = (
# (ALL, _('All')),
# (CONNECT, _('Connect')),
# (UPLOAD, _('Upload file')),
# (DOWNLOAD, _('Download file')),
# (TRANSFER, _("Upload download")),
# (COPY, _('Clipboard copy')),
# (PASTE, _('Clipboard paste')),
# (CLIPBOARD, _('Clipboard copy paste'))
# )
#
# NAME_MAP = {
# ALL: "all",
# CONNECT: "connect",
# UPLOAD: "upload",
# DOWNLOAD: "download",
# TRANSFER: "transfer",
# COPY: 'copy',
# PASTE: 'paste',
# CLIPBOARD: 'clipboard'
# }
#
# NAME_MAP_REVERSE = {v: k for k, v in NAME_MAP.items()}
# CHOICES = []
# for i, j in DB_CHOICES:
# CHOICES.append((NAME_MAP[i], j))
#
# @classmethod
# def choices(cls):
# pass
#
class SpecialAccount(models.TextChoices): class SpecialAccount(models.TextChoices):
ALL = '@ALL', 'All' ALL = "@ALL", "All"