import logging from django.db import models from django.http import HttpResponseRedirect from django_json_widget.widgets import JSONEditorWidget from rest_framework import mixins, status from rest_framework.decorators import action from rest_framework.response import Response from rest_framework.reverse import reverse from console import conslog from perms.models import Perm from storage.tasks import export_task _log = logging.getLogger(__name__) class ExportMixin: """ Mixin for exporting data in different formats We get the initial queryset and query-parameters and perform filtering inside the task using django_filters """ def export(self, request, export_type, *args, **kwargs): # Getting data for export queryset = self.get_queryset() query_parameters = request.query_params model_name = queryset.model._meta.model_name result = export_task.apply_async(args=(export_type, request.user.pk, model_name, query_parameters)) data_storage_id = result.get() download_url = reverse('store-download', kwargs={"pk": data_storage_id}) return HttpResponseRedirect(download_url) class ExportToCsvMixin(ExportMixin): """ Mixin for exporting data as CSV format """ @action(detail=False, name='csv-export', methods=['GET']) def csv_export(self, request, *args, **kwargs): return self.export(request, export_type='csv') class ExportToJSONMixin(ExportMixin): """ Mixin for exporting data as JSON format """ @action(detail=False, name='json-export', methods=['GET']) def json_export(self, request, *args, **kwargs): return self.export(request, export_type='json') class DestroyModelResponseStatus200Mixin(mixins.DestroyModelMixin): """ This mixin allow ViewSet to log destroy object process """ def destroy(self, request, *args, **kwargs): user, url = request.user, request.get_full_path() message = f"User [{user}] accessed <{url}> page" _log.info(message) instance = self.get_object() self.perform_destroy(instance) message = f'User [{user}] perform destroy of object [{instance}] of type [{self.Meta.model.__name__}]' _log.info(message) return Response(status=status.HTTP_200_OK) class ApiPermissionCheckMixin: """ API for checking the permissions if currently authenticated user has access to API Usage: from perms.models import Perm class TestViewSet(ApiPermissionCheckMixin, ...): console_permissions = [Perm.can_view_network, ...] ...code... User can set permissions for any action, or set default permissions. class TestViewSet(ApiPermissionCheckMixin, ...): console_permissions = { "create": [Perm.can_create_asset], "delete": [Perm.can_delete_asset], "default": [Perm.can_view_asset] } If for current action, no permissions is set, class will check 'default' list. """ console_permissions = [] def check_permissions(self, request): """ Actual permission check """ if isinstance(self.console_permissions, (list, tuple)): perms = [Perm.perm_req(item) for item in self.console_permissions] else: if self.action in self.console_permissions: perms = [Perm.perm_req(item) for item in self.console_permissions[self.action]] elif 'default' in self.console_permissions: perms = [Perm.perm_req(item) for item in self.console_permissions['default']] else: perms = [] if not request.user.has_perms(perms): self.permission_denied(request) return super().check_permissions(request) class JsonWidgetMixin: """ Mixin to override default json field with new widget """ formfield_overrides = { models.JSONField: {'widget': JSONEditorWidget}, } class LogURLMixin: """Log every user action""" def dispatch(self, request, *args, **kwargs): conslog.add_info_log(conslog.url_access_log(request), _log) return super().dispatch(request, *args, **kwargs)