mirror of https://github.com/jumpserver/jumpserver
pref: 优化 permission actionss
parent
1cd551e692
commit
9c5b3a03c6
|
@ -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],
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue