pull/4049/head
Bai 2020-05-28 17:47:27 +08:00
commit 196f1654ab
19 changed files with 291 additions and 45 deletions

View File

@ -0,0 +1,7 @@
GET = 'GET'
POST = 'POST'
PUT = 'PUT'
PATCH = 'PATCH'
DELETE = 'DELETE'
OPTIONS = 'OPTIONS'

View File

@ -3,7 +3,9 @@
import time
from hashlib import md5
from threading import Thread
from collections import defaultdict
from django.db.models.signals import m2m_changed
from django.core.cache import cache
from django.http import JsonResponse
from rest_framework.response import Response
@ -14,7 +16,7 @@ from ..utils import lazyproperty
__all__ = [
"JSONResponseMixin", "CommonApiMixin",
'AsyncApiMixin',
'AsyncApiMixin', 'RelationMixin'
]
@ -187,3 +189,47 @@ class AsyncApiMixin(InterceptMixin):
data["error"] = str(e)
data["status"] = "error"
cache.set(key, data, 600)
class RelationMixin:
m2m_field = None
from_field = None
to_field = None
to_model = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
assert self.m2m_field is not None, '''
`m2m_field` should not be `None`
'''
self.from_field = self.m2m_field.m2m_field_name()
self.to_field = self.m2m_field.m2m_reverse_field_name()
self.to_model = self.m2m_field.related_model
self.through = getattr(self.m2m_field.model, self.m2m_field.attname).through
def get_queryset(self):
queryset = self.through.objects.all()
return queryset
def send_post_add_signal(self, instances):
if not isinstance(instances, list):
instances = [instances]
from_to_mapper = defaultdict(list)
for i in instances:
to_id = getattr(i, self.to_field).id
from_obj = getattr(i, self.from_field)
from_to_mapper[from_obj].append(to_id)
for from_obj, to_ids in from_to_mapper.items():
m2m_changed.send(
sender=self.through, instance=from_obj, action='post_add',
reverse=False, model=self.to_model, pk_set=to_ids
)
def perform_create(self, serializer):
instance = serializer.save()
self.send_post_add_signal(instance)

View File

@ -3,7 +3,8 @@
from django.shortcuts import get_object_or_404
from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework_bulk import BulkModelViewSet
from common.mixins import CommonApiMixin
from common.mixins import CommonApiMixin, RelationMixin
from orgs.utils import current_org
from ..utils import set_to_root_org, filter_org_queryset
from ..models import Organization
@ -80,3 +81,12 @@ class OrgMembershipModelViewSetMixin:
def get_queryset(self):
queryset = self.membership_class.objects.filter(organization=self.org)
return queryset
class OrgRelationMixin(RelationMixin):
def get_queryset(self):
queryset = super().get_queryset()
org_id = current_org.org_id()
if org_id is not None:
queryset = queryset.filter(**{f'{self.from_field}__org_id': org_id})
return queryset

View File

@ -6,6 +6,7 @@ from .user_permission import *
from .asset_permission_relation import *
from .user_group_permission import *
from .remote_app_permission import *
from .remote_app_permission_relation import *
from .user_remote_app_permission import *
from .database_app_permission import *
from .database_app_permission_relation import *

15
apps/perms/api/base.py Normal file
View File

@ -0,0 +1,15 @@
from django.db.models import F
from orgs.mixins.api import OrgBulkModelViewSet
from orgs.mixins.api import OrgRelationMixin
__all__ = [
'RelationViewSet'
]
class RelationViewSet(OrgRelationMixin, OrgBulkModelViewSet):
def get_queryset(self):
queryset = super().get_queryset()
queryset = queryset.annotate(**{f'{self.from_field}_display': F(f'{self.from_field}__name')})
return queryset

View File

@ -1,14 +1,12 @@
# coding: utf-8
#
from rest_framework import generics
from django.db.models import F, Value
from django.db.models.functions import Concat
from django.shortcuts import get_object_or_404
from orgs.mixins.api import OrgBulkModelViewSet
from orgs.utils import current_org
from common.permissions import IsOrgAdmin
from .base import RelationViewSet
from .. import models, serializers
__all__ = [
@ -21,19 +19,9 @@ __all__ = [
]
class RelationMixin(OrgBulkModelViewSet):
def get_queryset(self):
queryset = self.model.objects.all()
org_id = current_org.org_id()
if org_id is not None:
queryset = queryset.filter(databaseapppermission__org_id=org_id)
queryset = queryset.annotate(databaseapppermission_display=F('databaseapppermission__name'))
return queryset
class DatabaseAppPermissionUserRelationViewSet(RelationMixin):
class DatabaseAppPermissionUserRelationViewSet(RelationViewSet):
serializer_class = serializers.DatabaseAppPermissionUserRelationSerializer
model = models.DatabaseAppPermission.users.through
m2m_field = models.DatabaseAppPermission.users.field
permission_classes = (IsOrgAdmin,)
filterset_fields = [
'id', 'user', 'databaseapppermission'
@ -46,9 +34,9 @@ class DatabaseAppPermissionUserRelationViewSet(RelationMixin):
return queryset
class DatabaseAppPermissionUserGroupRelationViewSet(RelationMixin):
class DatabaseAppPermissionUserGroupRelationViewSet(RelationViewSet):
serializer_class = serializers.DatabaseAppPermissionUserGroupRelationSerializer
model = models.DatabaseAppPermission.user_groups.through
m2m_field = models.DatabaseAppPermission.user_groups.field
permission_classes = (IsOrgAdmin,)
filterset_fields = [
'id', "usergroup", "databaseapppermission"
@ -77,9 +65,9 @@ class DatabaseAppPermissionAllUserListApi(generics.ListAPIView):
return users
class DatabaseAppPermissionDatabaseAppRelationViewSet(RelationMixin):
class DatabaseAppPermissionDatabaseAppRelationViewSet(RelationViewSet):
serializer_class = serializers.DatabaseAppPermissionDatabaseAppRelationSerializer
model = models.DatabaseAppPermission.database_apps.through
m2m_field = models.DatabaseAppPermission.database_apps.field
permission_classes = (IsOrgAdmin,)
filterset_fields = [
'id', 'databaseapp', 'databaseapppermission',
@ -110,9 +98,9 @@ class DatabaseAppPermissionAllDatabaseAppListApi(generics.ListAPIView):
return database_apps
class DatabaseAppPermissionSystemUserRelationViewSet(RelationMixin):
class DatabaseAppPermissionSystemUserRelationViewSet(RelationViewSet):
serializer_class = serializers.DatabaseAppPermissionSystemUserRelationSerializer
model = models.DatabaseAppPermission.system_users.through
m2m_field = models.DatabaseAppPermission.system_users.field
permission_classes = (IsOrgAdmin,)
filterset_fields = [
'id', 'systemuser', 'databaseapppermission'

View File

@ -13,7 +13,6 @@ from ..serializers import (
RemoteAppPermissionUpdateRemoteAppSerializer,
)
__all__ = [
'RemoteAppPermissionViewSet',
'RemoteAppPermissionAddUserApi', 'RemoteAppPermissionAddRemoteAppApi',

View File

@ -0,0 +1,79 @@
# coding: utf-8
#
from perms.api.base import RelationViewSet
from rest_framework import generics
from django.db.models import F
from django.shortcuts import get_object_or_404
from common.permissions import IsOrgAdmin
from .. import models, serializers
__all__ = [
'RemoteAppPermissionUserRelationViewSet',
'RemoteAppPermissionRemoteAppRelationViewSet',
'RemoteAppPermissionAllRemoteAppListApi',
'RemoteAppPermissionAllUserListApi',
]
class RemoteAppPermissionAllUserListApi(generics.ListAPIView):
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.PermissionAllUserSerializer
filter_fields = ("username", "name")
search_fields = filter_fields
def get_queryset(self):
pk = self.kwargs.get("pk")
perm = get_object_or_404(models.RemoteAppPermission, pk=pk)
users = perm.all_users.only(
*self.serializer_class.Meta.only_fields
)
return users
class RemoteAppPermissionUserRelationViewSet(RelationViewSet):
serializer_class = serializers.RemoteAppPermissionUserRelationSerializer
m2m_field = models.RemoteAppPermission.users.field
permission_classes = (IsOrgAdmin,)
filterset_fields = [
'id', 'user', 'remoteapppermission'
]
search_fields = ('user__name', 'user__username', 'remoteapppermission__name')
def get_queryset(self):
queryset = super().get_queryset()
queryset = queryset.annotate(user_display=F('user__name'))
return queryset
class RemoteAppPermissionRemoteAppRelationViewSet(RelationViewSet):
serializer_class = serializers.RemoteAppPermissionRemoteAppRelationSerializer
m2m_field = models.RemoteAppPermission.remote_apps.field
permission_classes = (IsOrgAdmin,)
filterset_fields = [
'id', 'remoteapp', 'remoteapppermission',
]
search_fields = [
"id", "remoteapp__name", "remoteapppermission__name"
]
def get_queryset(self):
queryset = super().get_queryset()
queryset = queryset \
.annotate(remoteapp_display=F('remoteapp__name'))
return queryset
class RemoteAppPermissionAllRemoteAppListApi(generics.ListAPIView):
permission_classes = (IsOrgAdmin,)
serializer_class = serializers.RemoteAppPermissionAllRemoteAppSerializer
filter_fields = ("name",)
search_fields = filter_fields
def get_queryset(self):
pk = self.kwargs.get("pk")
perm = get_object_or_404(models.RemoteAppPermission, pk=pk)
remote_apps = perm.all_remote_apps.only(
*self.serializer_class.Meta.only_fields
)
return remote_apps

View File

@ -79,6 +79,23 @@ class BasePermission(OrgModelMixin):
return True
return False
@property
def all_users(self):
from users.models import User
users_query = self._meta.get_field('users').related_query_name()
user_groups_query = self._meta.get_field('user_groups').related_query_name()
users_q = Q(**{
f'{users_query}': self
})
user_groups_q = Q(**{
f'groups__{user_groups_query}': self
})
return User.objects.filter(users_q | user_groups_q).distinct()
def get_all_users(self):
from users.models import User
users_id = self.users.all().values_list('id', flat=True)

View File

@ -4,6 +4,7 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _
from common.utils import lazyproperty
from .base import BasePermission
__all__ = [
@ -28,3 +29,11 @@ class DatabaseAppPermission(BasePermission):
def get_all_database_apps(self):
return self.database_apps.all()
@lazyproperty
def database_apps_amount(self):
return self.database_apps.count()
@lazyproperty
def system_users_amount(self):
return self.system_users.count()

View File

@ -23,6 +23,10 @@ class RemoteAppPermission(BasePermission):
def get_all_remote_apps(self):
return set(self.remote_apps.all())
@property
def all_remote_apps(self):
return self.remote_apps.all()
@lazyproperty
def remote_apps_amount(self):
return self.remote_apps.count()

View File

@ -4,6 +4,8 @@
from .asset_permission import *
from .user_permission import *
from .remote_app_permission import *
from .remote_app_permission_relation import *
from .asset_permission_relation import *
from .database_app_permission import *
from .database_app_permission_relation import *
from .base import *

View File

@ -0,0 +1,13 @@
from rest_framework import serializers
class PermissionAllUserSerializer(serializers.Serializer):
user = serializers.UUIDField(read_only=True, source='id')
user_display = serializers.SerializerMethodField()
class Meta:
only_fields = ['id', 'username', 'name']
@staticmethod
def get_user_display(obj):
return str(obj)

View File

@ -1,6 +1,6 @@
# coding: utf-8
#
from django.db.models import Count
from rest_framework import serializers
from common.fields import StringManyToManyField
@ -27,13 +27,22 @@ class DatabaseAppPermissionSerializer(BulkOrgResourceModelSerializer):
class DatabaseAppPermissionListSerializer(BulkOrgResourceModelSerializer):
users = StringManyToManyField(many=True, read_only=True)
user_groups = StringManyToManyField(many=True, read_only=True)
database_apps = StringManyToManyField(many=True, read_only=True)
system_users = StringManyToManyField(many=True, read_only=True)
is_valid = serializers.BooleanField()
is_expired = serializers.BooleanField()
class Meta:
model = models.DatabaseAppPermission
fields = '__all__'
fields = [
'id', 'name', 'comment', 'is_active', 'users_amount', 'user_groups_amount',
'date_start', 'date_expired', 'is_valid', 'database_apps_amount', 'system_users_amount',
'created_by', 'date_created', 'is_expired'
]
@classmethod
def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.annotate(
users_amount=Count('users', distinct=True), user_groups_amount=Count('user_groups', distinct=True),
database_apps_amount=Count('database_apps', distinct=True),
system_users_amount=Count('system_users', distinct=True)
)
return queryset

View File

@ -1,8 +1,8 @@
# coding: utf-8
#
from perms.serializers.base import PermissionAllUserSerializer
from rest_framework import serializers
from applications.models import DatabaseApp
from common.mixins import BulkSerializerMixin
from common.serializers import AdaptedBulkListSerializer
@ -50,16 +50,9 @@ class DatabaseAppPermissionUserGroupRelationSerializer(RelationMixin, serializer
]
class DatabaseAppPermissionAllUserSerializer(serializers.Serializer):
user = serializers.UUIDField(read_only=True, source='id')
user_display = serializers.SerializerMethodField()
class Meta:
only_fields = ['id', 'username', 'name']
@staticmethod
def get_user_display(obj):
return str(obj)
class DatabaseAppPermissionAllUserSerializer(PermissionAllUserSerializer):
class Meta(PermissionAllUserSerializer.Meta):
pass
class DatabaseAppPermissionDatabaseAppRelationSerializer(RelationMixin, serializers.ModelSerializer):

View File

@ -36,8 +36,8 @@ class RemoteAppPermissionSerializer(BulkOrgResourceModelSerializer):
def setup_eager_loading(cls, queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.annotate(
users_amount=Count('users'), user_groups_amount=Count('user_groups'),
remote_apps_amount=Count('remote_apps'), system_users_amount=Count('system_users')
users_amount=Count('users', distinct=True), user_groups_amount=Count('user_groups', distinct=True),
remote_apps_amount=Count('remote_apps', distinct=True), system_users_amount=Count('system_users', distinct=True)
)
return queryset

View File

@ -0,0 +1,49 @@
# coding: utf-8
#
from rest_framework import serializers
from common.serializers import AdaptedBulkListSerializer
from ..models import RemoteAppPermission
__all__ = [
'RemoteAppPermissionRemoteAppRelationSerializer',
'RemoteAppPermissionAllRemoteAppSerializer',
'RemoteAppPermissionUserRelationSerializer',
]
class RemoteAppPermissionRemoteAppRelationSerializer(serializers.ModelSerializer):
remoteapp_display = serializers.ReadOnlyField()
remoteapppermission_display = serializers.ReadOnlyField()
class Meta:
model = RemoteAppPermission.remote_apps.through
list_serializer_class = AdaptedBulkListSerializer
fields = [
'id', 'remoteapp', 'remoteapp_display', 'remoteapppermission', 'remoteapppermission_display'
]
class RemoteAppPermissionAllRemoteAppSerializer(serializers.Serializer):
remoteapp = serializers.UUIDField(read_only=True, source='id')
remoteapp_display = serializers.SerializerMethodField()
class Meta:
only_fields = ['id', 'name']
@staticmethod
def get_remoteapp_display(obj):
return str(obj)
class RemoteAppPermissionUserRelationSerializer(serializers.ModelSerializer):
user_display = serializers.ReadOnlyField()
remoteapppermission_display = serializers.ReadOnlyField()
class Meta:
model = RemoteAppPermission.users.through
list_serializer_class = AdaptedBulkListSerializer
fields = [
'id', 'user', 'user_display', 'remoteapppermission', 'remoteapppermission_display'
]

View File

@ -7,6 +7,9 @@ from .. import api
router = BulkRouter()
router.register('remote-app-permissions', api.RemoteAppPermissionViewSet, 'remote-app-permission')
router.register('remote-app-permissions-users-relations', api.RemoteAppPermissionUserRelationViewSet, 'remote-app-permissions-users-relation')
router.register('remote-app-permissions-remote-apps-relations', api.RemoteAppPermissionRemoteAppRelationViewSet, 'remote-app-permissions-remote-apps-relation')
remote_app_permission_urlpatterns = [
# 查询用户授权的RemoteApp
@ -32,7 +35,9 @@ remote_app_permission_urlpatterns = [
path('remote-app-permissions/<uuid:pk>/users/remove/', api.RemoteAppPermissionRemoveUserApi.as_view(), name='remote-app-permission-remove-user'),
path('remote-app-permissions/<uuid:pk>/remote-apps/remove/', api.RemoteAppPermissionRemoveRemoteAppApi.as_view(), name='remote-app-permission-remove-remote-app'),
path('remote-app-permissions/<uuid:pk>/remote-apps/add/', api.RemoteAppPermissionAddRemoteAppApi.as_view(), name='remote-app-permission-add-remote-app'),
path('remote-app-permissions/<uuid:pk>/remote-apps/all/', api.RemoteAppPermissionAllRemoteAppListApi.as_view(), name='remote-app-permission-all-remote-apps'),
path('remote-app-permissions/<uuid:pk>/users/all/', api.RemoteAppPermissionAllUserListApi.as_view(), name='remote-app-permission-all-users'),
]
remote_app_permission_urlpatterns += router.urls