import logging from django.db.models import Count, Q from django.http import Http404 from rest_framework.decorators import action from rest_framework.mixins import ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from core.mixins import ApiPermissionCheckMixin from ncircc.models.comments import Comment from ncircc.models.notification import Notification from ncircc.serializers.comments import CommentCreateSerializer, CommentRetrieveSerializer from ncircc.serializers.notification import NotificationSerializer from ncircc.services.comments import CommentSenderService from ncircc.services.notification import NotificationSenderCreateService, NotificationUpdateSenderService, \ NotificationUploadFileService, NOCRCCCreateException from perms.models import Perm _log = logging.getLogger(__name__) class NotificationApiViewSet(ApiPermissionCheckMixin, ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, GenericViewSet): """View Set for getting list for creating/updating notification ncircc events.""" serializer_class = NotificationSerializer queryset = Notification.objects.order_by('updated') console_permissions = { 'list': [Perm.can_view_message_list], 'retrieve': [Perm.can_view_message_card], 'update': [Perm.can_edit_message_card], 'create': [Perm.can_edit_message_card], 'comments': [Perm.can_view_message_card], 'comments_create': ['can_view_message_card'], } def create(self, request, *args, **kwargs) -> Response: serializer = self.get_serializer(data=request.data) if not serializer.is_valid(): errors = serializer.errors _log.error(f'Error: {errors}') return Response(errors, status=400) instance = serializer.save() try: sender = NotificationSenderCreateService(instance.pk) except NOCRCCCreateException as err: instance.delete() return Response({'error': str(err)}, status=400) msg, status = sender.send() if status == 400: instance.delete() _log.error(f'Error: {msg}') return Response({'error': msg}, status=400) return Response(serializer.data, status=201) def update(self, request, *args, **kwargs) -> Response: partial = kwargs.pop('partial', False) instance = self.get_object() serializer = self.get_serializer(instance, data=request.data, partial=partial) if not serializer.is_valid(): errors = serializer.errors _log.error(f'Error: {errors}') return Response(errors, status=400) serializer.save() if getattr(instance, '_prefetched_objects_cache', None): # If 'prefetch_related' has been applied to a queryset, we need to # forcibly invalidate the prefetch cache on the instance. instance._prefetched_objects_cache = {} sender = NotificationUpdateSenderService(instance.pk) msg, status = sender.send() if status == 400: _log.error(f'Error:{msg}') return Response({'error': msg}, status=status) return Response(serializer.data, status=200) @action(detail=True, methods=['Get'], name='Comment list') def comments(self, request, pk=None) -> Response: """Return comment list.""" if not Notification.objects.filter(pk=pk).exists(): raise Http404 comments = Comment.objects.filter(notification=pk) data = CommentRetrieveSerializer(comments, many=True).data comments.update(is_read=True) return Response(data) @comments.mapping.post def comments_create(self, request, pk=None) -> Response: """Create comments to ncitcc.""" if not Notification.objects.filter(pk=pk).exists(): raise Http404 serializer = CommentCreateSerializer(data=request.data) if not serializer.is_valid(): errors = serializer.errors _log.error(f'Error: {errors}') return Response(errors, status=400) text = serializer.data.get('text', '') sender = CommentSenderService(text, int(pk), request.user) msg, status = sender.send() if status == 400: _log.error(f'Error: {msg}') return Response({'error': msg}, status=400) return Response(msg, status=201) @action(detail=True, methods=['POST'], name='Upload File') def upload(self, request, pk=None) -> Response: """Upload file data.""" file = request.FILES file_name = file['files'].name file_data = file['files'].file uploader = NotificationUploadFileService(pk, file_data, file_name) msg, status = uploader.send() if status == 200: return Response({}, status=200) else: return Response({'error': msg}, status=status) def get_queryset(self): qs = super().get_queryset() qs = qs.annotate(new_comment_count=Count('comment', filter=Q(comment__is_read=False))) return qs class Meta: model = Notification