diff --git a/apps/common/mixins/serializers.py b/apps/common/mixins/serializers.py index 5f8668b93..2dc9483ad 100644 --- a/apps/common/mixins/serializers.py +++ b/apps/common/mixins/serializers.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # +from django.core.exceptions import ObjectDoesNotExist from rest_framework.utils import html from rest_framework.settings import api_settings from rest_framework.exceptions import ValidationError @@ -74,16 +75,21 @@ class BulkListSerializerMixin(object): for item in data: try: # prepare child serializer to only handle one instance - if 'id' in item.keys(): - self.child.instance = self.instance.get(id=item['id']) if self.instance else None - if 'pk' in item.keys(): - self.child.instance = self.instance.get(id=item['pk']) if self.instance else None - + if 'id' in item: + pk = item["id"] + elif 'pk' in item: + pk = item["pk"] + else: + raise ValidationError("id or pk not in data") + child = self.instance.get(id=pk) + self.child.instance = child self.child.initial_data = item # raw validated = self.child.run_validation(item) except ValidationError as exc: errors.append(exc.detail) + except ObjectDoesNotExist as e: + errors.append(e) else: ret.append(validated) errors.append({}) diff --git a/apps/common/parsers/csv.py b/apps/common/parsers/csv.py index d96e9d2ef..7cd7e1648 100644 --- a/apps/common/parsers/csv.py +++ b/apps/common/parsers/csv.py @@ -40,7 +40,7 @@ class JMSCSVParser(BaseParser): @staticmethod def _get_fields_map(serializer): fields_map = {} - fields = serializer.get_fields() + fields = serializer.fields fields_map.update({v.label: k for k, v in fields.items()}) fields_map.update({k: k for k, _ in fields.items()}) return fields_map @@ -91,7 +91,7 @@ class JMSCSVParser(BaseParser): header = next(rows) fields_map = self._get_fields_map(serializer) - header = [fields_map.get(name, '') for name in header] + header = [fields_map.get(name.strip('*'), '') for name in header] data = [] for row in rows: diff --git a/apps/common/renders/csv.py b/apps/common/renders/csv.py index f80498f55..7eaac2b47 100644 --- a/apps/common/renders/csv.py +++ b/apps/common/renders/csv.py @@ -20,26 +20,18 @@ class JMSCSVRender(BaseRenderer): format = 'csv' @staticmethod - def _get_header(fields, template): - if template == 'import': - header = [ - k for k, v in fields.items() - if not v.read_only and k != 'org_id' - ] - elif template == 'update': - header = [k for k, v in fields.items() if not v.read_only] + def _get_show_fields(fields, template): + if template in ('import', 'update'): + return [v for k, v in fields.items() if not v.read_only and k != "org_id"] else: - # template in ['export'] - header = [k for k, v in fields.items() if not v.write_only] - return header + return [v for k, v in fields.items() if not v.write_only and k != "org_id"] @staticmethod - def _gen_table(data, header, labels=None): - labels = labels or {} - yield [labels.get(k, k) for k in header] + def _gen_table(data, fields): + yield ['*{}'.format(f.label) if f.required else f.label for f in fields] for item in data: - row = [item.get(key) for key in header] + row = [item.get(f.field_name) for f in fields] yield row def set_response_disposition(self, serializer, context): @@ -73,10 +65,9 @@ class JMSCSVRender(BaseRenderer): logger.debug(e, exc_info=True) value = 'The resource not support export!'.encode('utf-8') else: - fields = serializer.get_fields() - header = self._get_header(fields, template) - labels = {k: v.label for k, v in fields.items() if v.label} - table = self._gen_table(data, header, labels) + fields = serializer.fields + show_fields = self._get_show_fields(fields, template) + table = self._gen_table(data, show_fields) csv_buffer = BytesIO() csv_buffer.write(codecs.BOM_UTF8) diff --git a/apps/users/api/user.py b/apps/users/api/user.py index 8f3ad6150..31fccf47b 100644 --- a/apps/users/api/user.py +++ b/apps/users/api/user.py @@ -5,10 +5,10 @@ from django.core.cache import cache from django.contrib.auth import logout from django.utils.translation import ugettext as _ -from rest_framework import status from rest_framework import generics from rest_framework.response import Response from rest_framework.permissions import IsAuthenticated +from rest_framework.serializers import ValidationError from rest_framework_bulk import BulkModelViewSet from rest_framework.pagination import LimitOffsetPagination @@ -69,9 +69,7 @@ class UserViewSet(IDInCacheFilterMixin, BulkModelViewSet): check current user has permission to handle instance (update, destroy, bulk_update, bulk destroy) """ - if not self.request.user.is_superuser and instance.is_superuser: - return True - if self.request.user == instance: + if instance.is_superuser and not self.request.user.is_superuser: return True return False @@ -87,16 +85,14 @@ class UserViewSet(IDInCacheFilterMixin, BulkModelViewSet): return False return qs.count() != filtered.count() - def bulk_update(self, request, *args, **kwargs): - """ - rewrite because limit org_admin update superuser - """ - # restrict the update to the filtered queryset - queryset = self.filter_queryset(self.get_queryset()) - if self._bulk_deny_permission(queryset): - data = {'msg': _("You do not have permission.")} - return Response(data=data, status=status.HTTP_403_FORBIDDEN) - return super().bulk_update(request, *args, **kwargs) + def perform_bulk_update(self, serializer): + users_ids = [d.get("id") or d.get("pk") for d in serializer.validated_data] + users = User.objects.filter(id__in=users_ids) + deny_instances = [str(i.id) for i in users if self._deny_permission(i)] + if deny_instances: + msg = "{} can't be update".format(deny_instances) + raise ValidationError({"id": msg}) + return super().perform_bulk_update(serializer) class UserChangePasswordApi(generics.RetrieveUpdateAPIView):