diff --git a/apps/orgs/api.py b/apps/orgs/api.py index 7da77cfce..a99715d47 100644 --- a/apps/orgs/api.py +++ b/apps/orgs/api.py @@ -1,14 +1,68 @@ # -*- coding: utf-8 -*- # -from rest_framework import viewsets +from rest_framework import status +from rest_framework.views import Response +from rest_framework_bulk import BulkModelViewSet from common.permissions import IsSuperUserOrAppUser from .models import Organization -from .serializers import OrgSerializer +from .serializers import OrgSerializer, OrgReadSerializer, \ + OrgMembershipUserSerializer, OrgMembershipAdminSerializer +from users.models import User, UserGroup +from assets.models import Asset, Domain, AdminUser, SystemUser, Label +from perms.models import AssetPermission +from orgs.utils import current_org +from common.utils import get_logger +from .mixins import OrgMembershipModelViewSetMixin + +logger = get_logger(__file__) -class OrgViewSet(viewsets.ModelViewSet): +class OrgViewSet(BulkModelViewSet): queryset = Organization.objects.all() serializer_class = OrgSerializer permission_classes = (IsSuperUserOrAppUser,) + org = None + + def get_serializer_class(self): + if self.action in ('list', 'retrieve'): + return OrgReadSerializer + else: + return super().get_serializer_class() + + def get_data_from_model(self, model): + if model == User: + data = model.objects.filter(orgs__id=self.org.id) + else: + data = model.objects.filter(org_id=self.org.id) + return data + + def destroy(self, request, *args, **kwargs): + self.org = self.get_object() + models = [ + User, UserGroup, + Asset, Domain, AdminUser, SystemUser, Label, + AssetPermission, + ] + for model in models: + data = self.get_data_from_model(model) + if data: + return Response(status=status.HTTP_400_BAD_REQUEST) + else: + if str(current_org) == str(self.org): + return Response(status=status.HTTP_405_METHOD_NOT_ALLOWED) + self.org.delete() + return Response({'msg': True}, status=status.HTTP_200_OK) + + +class OrgMembershipAdminsViewSet(OrgMembershipModelViewSetMixin, BulkModelViewSet): + serializer_class = OrgMembershipAdminSerializer + membership_class = Organization.admins.through + permission_classes = (IsSuperUserOrAppUser, ) + + +class OrgMembershipUsersViewSet(OrgMembershipModelViewSetMixin, BulkModelViewSet): + serializer_class = OrgMembershipUserSerializer + membership_class = Organization.users.through + permission_classes = (IsSuperUserOrAppUser, ) diff --git a/apps/orgs/mixins.py b/apps/orgs/mixins.py index 917a220bf..497377520 100644 --- a/apps/orgs/mixins.py +++ b/apps/orgs/mixins.py @@ -9,7 +9,6 @@ from django.forms import ModelForm from django.http.response import HttpResponseForbidden from django.core.exceptions import ValidationError - from common.utils import get_logger from .utils import current_org, set_current_org, set_to_root_org from .models import Organization @@ -19,7 +18,7 @@ tl = Local() __all__ = [ 'OrgManager', 'OrgViewGenericMixin', 'OrgModelMixin', 'OrgModelForm', - 'RootOrgViewMixin', + 'RootOrgViewMixin', 'OrgMembershipSerializerMixin', 'OrgMembershipModelViewSetMixin' ] @@ -176,3 +175,29 @@ class OrgModelForm(ModelForm): continue model = field.queryset.model field.queryset = model.objects.all() + + +class OrgMembershipSerializerMixin: + def run_validation(self, initial_data=None): + initial_data['organization'] = str(self.context['org'].id) + return super().run_validation(initial_data) + + +class OrgMembershipModelViewSetMixin: + org = None + membership_class = None + lookup_field = 'user' + lookup_url_kwarg = 'user_id' + http_method_names = ['get', 'post', 'delete', 'head', 'options'] + + def dispatch(self, request, *args, **kwargs): + self.org = Organization.objects.get(pk=kwargs.get('org_id')) + return super().dispatch(request, *args, **kwargs) + + def get_serializer_context(self): + context = super().get_serializer_context() + context['org'] = self.org + return context + + def get_queryset(self): + return self.membership_class.objects.filter(organization=self.org) diff --git a/apps/orgs/serializers.py b/apps/orgs/serializers.py index 8a2de4582..679125195 100644 --- a/apps/orgs/serializers.py +++ b/apps/orgs/serializers.py @@ -1,10 +1,81 @@ from rest_framework.serializers import ModelSerializer +from rest_framework import serializers +from rest_framework_bulk import BulkListSerializer + +from users.models import User, UserGroup +from assets.models import Asset, Domain, AdminUser, SystemUser, Label +from perms.models import AssetPermission +from .utils import set_current_org, get_current_org from .models import Organization +from .mixins import OrgMembershipSerializerMixin class OrgSerializer(ModelSerializer): class Meta: model = Organization + list_serializer_class = BulkListSerializer fields = '__all__' read_only_fields = ['id', 'created_by', 'date_created'] + + +class OrgReadSerializer(ModelSerializer): + admins = serializers.SlugRelatedField(slug_field='name', many=True, read_only=True) + users = serializers.SlugRelatedField(slug_field='name', many=True, read_only=True) + user_groups = serializers.SerializerMethodField() + assets = serializers.SerializerMethodField() + domains = serializers.SerializerMethodField() + admin_users = serializers.SerializerMethodField() + system_users = serializers.SerializerMethodField() + labels = serializers.SerializerMethodField() + perms = serializers.SerializerMethodField() + + class Meta: + model = Organization + fields = '__all__' + + @staticmethod + def get_data_from_model(obj, model): + current_org = get_current_org() + set_current_org(Organization.root()) + if model == Asset: + data = [o.hostname for o in model.objects.filter(org_id=obj.id)] + else: + data = [o.name for o in model.objects.filter(org_id=obj.id)] + set_current_org(current_org) + return data + + def get_user_groups(self, obj): + return self.get_data_from_model(obj, UserGroup) + + def get_assets(self, obj): + return self.get_data_from_model(obj, Asset) + + def get_domains(self, obj): + return self.get_data_from_model(obj, Domain) + + def get_admin_users(self, obj): + return self.get_data_from_model(obj, AdminUser) + + def get_system_users(self, obj): + return self.get_data_from_model(obj, SystemUser) + + def get_labels(self, obj): + return self.get_data_from_model(obj, Label) + + def get_perms(self, obj): + return self.get_data_from_model(obj, AssetPermission) + + +class OrgMembershipAdminSerializer(OrgMembershipSerializerMixin, ModelSerializer): + class Meta: + model = Organization.admins.through + list_serializer_class = BulkListSerializer + fields = '__all__' + + +class OrgMembershipUserSerializer(OrgMembershipSerializerMixin, ModelSerializer): + class Meta: + model = Organization.users.through + list_serializer_class = BulkListSerializer + fields = '__all__' diff --git a/apps/orgs/urls/api_urls.py b/apps/orgs/urls/api_urls.py index a90d911e2..deca429ed 100644 --- a/apps/orgs/urls/api_urls.py +++ b/apps/orgs/urls/api_urls.py @@ -1,12 +1,20 @@ # -*- coding: utf-8 -*- # +from django.urls import path from rest_framework.routers import DefaultRouter from .. import api app_name = 'orgs' router = DefaultRouter() + +router.register(r'org/(?P[0-9a-zA-Z\-]{36})/membership/admins', + api.OrgMembershipAdminsViewSet, 'membership-admins') + +router.register(r'org/(?P[0-9a-zA-Z\-]{36})/membership/users', + api.OrgMembershipUsersViewSet, 'membership-users'), + router.register(r'orgs', api.OrgViewSet, 'org') diff --git a/apps/static/js/jumpserver.js b/apps/static/js/jumpserver.js index 207733618..3feedbd54 100644 --- a/apps/static/js/jumpserver.js +++ b/apps/static/js/jumpserver.js @@ -146,7 +146,7 @@ function activeNav() { if (app === ''){ $('#index').addClass('active'); } - else if (app === 'xpack') { + else if (app === 'xpack' && resource === 'cloud') { var item = url_array[3]; $("#" + app).addClass('active'); $('#' + app + ' #' + resource).addClass('active'); diff --git a/requirements/rpm_requirements.txt b/requirements/rpm_requirements.txt index 2721d614d..be3ce68e3 100644 --- a/requirements/rpm_requirements.txt +++ b/requirements/rpm_requirements.txt @@ -1 +1 @@ -libtiff-devel libjpeg-devel libzip-devel freetype-devel lcms2-devel libwebp-devel tcl-devel tk-devel sshpass openldap-devel mysql-devel libffi-devel openssh-clients +libtiff-devel libjpeg-devel libzip-devel freetype-devel lcms2-devel libwebp-devel tcl-devel tk-devel sshpass openldap-devel mariadb-devel libffi-devel openssh-clients