Marta Miranda

Modificaciones en auditoria

@@ -4,6 +4,20 @@ from rest_framework.decorators import api_view @@ -4,6 +4,20 @@ from rest_framework.decorators import api_view
4 4
5 from django.conf import settings 5 from django.conf import settings
6 6
  7 +import datetime
  8 +
  9 +from actstream.models import Action
  10 +from django.http import Http404
  11 +from django_filters.rest_framework import DjangoFilterBackend
  12 +from rest_framework import filters
  13 +from rest_framework.generics import get_object_or_404
  14 +from rest_framework.permissions import IsAuthenticated
  15 +from rest_framework_json_api.views import ReadOnlyModelViewSet
  16 +
  17 +from core.permissions import CustomModelPermissions
  18 +from core.serializers import ActionSerializer
  19 +from usuario.models import Usuario
  20 +
7 21
8 @api_view(['POST']) 22 @api_view(['POST'])
9 def recaptcha(request): 23 def recaptcha(request):
@@ -16,3 +30,39 @@ def recaptcha(request): @@ -16,3 +30,39 @@ def recaptcha(request):
16 ) 30 )
17 31
18 return Response({'captcha': r.json()}) 32 return Response({'captcha': r.json()})
  33 +
  34 +
  35 +class AuditoriaViewSet(ReadOnlyModelViewSet):
  36 + queryset = Action.objects.all()
  37 + permission_classes = (IsAuthenticated, CustomModelPermissions)
  38 + serializer_class = ActionSerializer
  39 + filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
  40 + ordering = '-timestamp'
  41 + #
  42 + # def get_queryset(self):
  43 + # queryset = super().get_queryset()
  44 + #
  45 + # if not self.action == 'list':
  46 + # return queryset
  47 + #
  48 + # # en el caso de que la accion sea listar, controlar que se filtre por fecha obligatoriamente
  49 + # usuario_id = self.request.GET.get('u_id', None)
  50 + # fecha_desde = self.request.GET.get('fecha_desde', None)
  51 + # fecha_hasta = self.request.GET.get('fecha_hasta', None)
  52 + #
  53 + # if not fecha_desde:
  54 + # return queryset.none()
  55 + #
  56 + # if not fecha_hasta or fecha_hasta < fecha_desde:
  57 + # fecha_hasta = datetime.datetime.now()
  58 + #
  59 + # if usuario_id:
  60 + # try:
  61 + # usuario = get_object_or_404(Usuario, id=usuario_id)
  62 + # queryset = usuario.actor_actions.public(timestamp__date__range=(fecha_desde, fecha_hasta))
  63 + # except Http404:
  64 + # return queryset.none()
  65 + # else:
  66 + # queryset = Action.objects.public(timestamp__date__range=(fecha_desde, fecha_hasta))
  67 + #
  68 + # return queryset
  1 +# IMAGEN_AVATAR_DEFECTO = 'img/perfil-avatar.jpg'
  2 +TASK_TIME_LIMIT = 60 * 60
  3 +TASK_RETRY_DELAY = 60
  4 +
  5 +# Verbos para auditoria
  6 +iniciado = 'iniciado'
  7 +
  1 +from typing import Optional
  2 +from actstream import action
  3 +from actstream.models import Action
  4 +from django.contrib.contenttypes.models import ContentType
  5 +from rest_framework.response import Response
  6 +from rest_framework import status
  7 +
  8 +from core.constants import iniciado
  9 +from core.serializers import ActionSerializer
  10 +
  11 +
  12 +# class FiltroObligatorioMixin(object):
  13 +# nombre_filtro_obligatorio: Optional[str] = None
  14 +#
  15 +# def get_queryset(self):
  16 +# queryset = super().get_queryset()
  17 +#
  18 +# if not self.action == 'list':
  19 +# return queryset
  20 +#
  21 +# # en el caso de que la accion sea listar, controlar que vengan los datos del filtro indicado
  22 +# filtro = self.request.GET.get(self.get_nombre_filtro_obligatorio(), None)
  23 +# if filtro:
  24 +# return queryset
  25 +#
  26 +# return queryset.none()
  27 +#
  28 +# def get_nombre_filtro_obligatorio(self):
  29 +# assert self.nombre_filtro_obligatorio is not None, (
  30 +# "Debe definir el atributo nombre_filtro_obligatorio a la clase '%s'"
  31 +# % self.__class__.__name__
  32 +# )
  33 +#
  34 +# return self.nombre_filtro_obligatorio
  35 +
  36 +
  37 +class AuditoriaMixin:
  38 +
  39 + def create(self, request, *args, **kwargs):
  40 + serializer = self.get_serializer(data=request.data)
  41 + serializer.is_valid(raise_exception=True)
  42 + self.perform_create(serializer)
  43 + action_object = serializer.instance
  44 +
  45 + self.registrar_accion(usuario=self.request.user, verb=iniciado, instance=serializer.instance,
  46 + data=serializer.data)
  47 + headers = self.get_success_headers(serializer.data)
  48 + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
  49 +
  50 + def perform_update(self, serializer):
  51 + serializer_modificado = self.get_serializer(data=self.request.data)
  52 + serializer_modificado.is_valid()
  53 + serializer_accion = self.get_serializer(instance=serializer.instance)
  54 +
  55 + data = {'data_inicial': serializer_accion.data, 'data_modificada': serializer_modificado.data}
  56 +
  57 + self.registrar_accion(usuario=self.request.user, verb=serializer_modificado.data["estado"], instance=serializer.instance,
  58 + data=data)
  59 + serializer.save()
  60 +
  61 + @staticmethod
  62 + def registrar_accion(usuario, verb, instance, data=None, target=None):
  63 + action.send(usuario, verb=verb, action_object=instance, target=target, data=data)
  64 +
  65 + @staticmethod
  66 + def obtener_historial_acciones(content_type, action_objects_id, request):
  67 + content_type = ContentType.objects.get(model=content_type)
  68 + historial_actividades = Action.objects.filter(
  69 + action_object_object_id__in=action_objects_id,
  70 + action_object_content_type_id=content_type.id
  71 + )
  72 + serializer = ActionSerializer(historial_actividades, many=True, context={'request': request})
  73 + return serializer
  1 +from actstream.models import Action
  2 +from rest_framework import serializers
  3 +
  4 +from usuario.serializers import UsuarioSerializer
  5 +# from persona.serializers import (
  6 +# DomicilioSerializer,
  7 +# FotoComplementariaPersonaSerializer,
  8 +# IdentificacionCromaticaSerializer,
  9 +# PersonaSerializer,
  10 +# VinculoFamiliarSerializer,
  11 +# HuellaDactilarSerializer,
  12 +# VinculoFamiliarSinIdentificarSerializer,
  13 +# IdentificacionDecadactilarSerializer, AutorizacionMenorSerializer,
  14 +# )
  15 +from usuario.models import Usuario
  16 +
  17 +
  18 +class ActivityGenericRelatedField(serializers.Field):
  19 + """
  20 + DRF Serializer field that serializers GenericForeignKey fields on the :class:`~activity.models.Action`
  21 + of known model types to their respective ActionSerializer implementation.
  22 + """
  23 +
  24 + def to_representation(self, value):
  25 + from edicto.serializers import EdictoSerializer, PrecioSerializer
  26 +
  27 + MAPEO_SERIALIZADORES_POR_MODELO = {
  28 + "Usuario": UsuarioSerializer,
  29 + "Edicto": EdictoSerializer,
  30 + "Precio": PrecioSerializer
  31 + }
  32 +
  33 + nombre_modelo = type(value).__name__
  34 + serializer_cls = MAPEO_SERIALIZADORES_POR_MODELO.get(nombre_modelo, None)
  35 +
  36 + if serializer_cls:
  37 + # se genera un nuevo diccionario donde se le suma otro diccionario conteniendo el elemento "type"
  38 + data = {**{'type': nombre_modelo}, **{'id': value.id}, **serializer_cls(value, context=self.context).data}
  39 + else:
  40 + data = str(value)
  41 +
  42 + return data
  43 +
  44 +
  45 +class ActorSerializer(serializers.ModelSerializer):
  46 + class Meta:
  47 + model = Usuario
  48 + fields = (
  49 + 'username',
  50 + 'first_name',
  51 + 'last_name',
  52 + 'cuil'
  53 + )
  54 +
  55 +
  56 +class ActionSerializer(serializers.Serializer):
  57 + """
  58 + DRF serializer for :class:`~activity.models.Action`.
  59 + """
  60 + actor = ActorSerializer(read_only=True)
  61 + verb = serializers.CharField(read_only=True)
  62 + action_object = ActivityGenericRelatedField(read_only=True)
  63 + target = ActivityGenericRelatedField(read_only=True)
  64 + timestamp = serializers.DateTimeField(read_only=True)
  65 + data = serializers.DictField(read_only=True)
  66 +
  67 + class Meta:
  68 + model = Action
  69 + fields = ('id', 'actor', 'verb', 'action_object', 'target', 'timestamp', 'data')
@@ -2,13 +2,15 @@ from django_filters.rest_framework import DjangoFilterBackend @@ -2,13 +2,15 @@ from django_filters.rest_framework import DjangoFilterBackend
2 from rest_framework import viewsets, filters, mixins 2 from rest_framework import viewsets, filters, mixins
3 from rest_framework.permissions import IsAuthenticated 3 from rest_framework.permissions import IsAuthenticated
4 4
  5 +from core.mixins import AuditoriaMixin
  6 +
5 from .filters import EdictoFilter, PrecioFilter 7 from .filters import EdictoFilter, PrecioFilter
6 from .models import Edicto, Precio 8 from .models import Edicto, Precio
7 from .permissions import IsAdminOrAuthorized 9 from .permissions import IsAdminOrAuthorized
8 -from .serializer import EdictoSerializer, PrecioSerializer 10 +from .serializers import EdictoSerializer, PrecioSerializer
9 11
10 12
11 -class EdictoViewSet(mixins.CreateModelMixin, 13 +class EdictoViewSet(AuditoriaMixin, mixins.CreateModelMixin,
12 mixins.RetrieveModelMixin, 14 mixins.RetrieveModelMixin,
13 mixins.UpdateModelMixin, 15 mixins.UpdateModelMixin,
14 mixins.ListModelMixin, 16 mixins.ListModelMixin,
@@ -24,7 +26,7 @@ class EdictoViewSet(mixins.CreateModelMixin, @@ -24,7 +26,7 @@ class EdictoViewSet(mixins.CreateModelMixin,
24 lookup_field = 'uuid' 26 lookup_field = 'uuid'
25 27
26 28
27 -class PrecioViewSet(viewsets.ReadOnlyModelViewSet): 29 +class PrecioViewSet(AuditoriaMixin, viewsets.ReadOnlyModelViewSet):
28 serializer_class = PrecioSerializer 30 serializer_class = PrecioSerializer
29 permission_classes = [IsAuthenticated, IsAdminOrAuthorized] 31 permission_classes = [IsAuthenticated, IsAdminOrAuthorized]
30 filter_backends = (DjangoFilterBackend, filters.OrderingFilter) 32 filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
@@ -4,3 +4,13 @@ from django.apps import AppConfig @@ -4,3 +4,13 @@ from django.apps import AppConfig
4 class EdictoConfig(AppConfig): 4 class EdictoConfig(AppConfig):
5 default_auto_field = 'django.db.models.BigAutoField' 5 default_auto_field = 'django.db.models.BigAutoField'
6 name = 'edicto' 6 name = 'edicto'
  7 +
  8 + def ready(self):
  9 + from actstream import registry
  10 + registry.register(
  11 + self.get_model('Edicto'),
  12 + self.get_model('Precio'),
  13 + )
  14 +
  15 +
  16 +default_app_config = 'edicto.apps.EdictoConfig'
@@ -4,6 +4,8 @@ from organismo import api as organismo_api @@ -4,6 +4,8 @@ from organismo import api as organismo_api
4 from usuario import api as usuario_api 4 from usuario import api as usuario_api
5 from edicto.api import EdictoViewSet 5 from edicto.api import EdictoViewSet
6 from edicto import api as edicto_api 6 from edicto import api as edicto_api
  7 +from core import api as core_api
  8 +
7 # Define routes 9 # Define routes
8 router = routers.DefaultRouter() 10 router = routers.DefaultRouter()
9 11
@@ -11,5 +13,4 @@ router.register(prefix='usuario', viewset=usuario_api.UsuarioViewSet) @@ -11,5 +13,4 @@ router.register(prefix='usuario', viewset=usuario_api.UsuarioViewSet)
11 router.register(prefix='organismo', viewset=organismo_api.OrganismoViewSet) 13 router.register(prefix='organismo', viewset=organismo_api.OrganismoViewSet)
12 router.register(r'edicto', EdictoViewSet, basename='edicto') 14 router.register(r'edicto', EdictoViewSet, basename='edicto')
13 router.register(prefix='precio', viewset=edicto_api.PrecioViewSet) 15 router.register(prefix='precio', viewset=edicto_api.PrecioViewSet)
14 -  
15 - 16 +router.register(prefix='auditoria', viewset=core_api.AuditoriaViewSet)
@@ -52,6 +52,7 @@ THIRD_PARTY_APPS = ( @@ -52,6 +52,7 @@ THIRD_PARTY_APPS = (
52 'django_filters', 52 'django_filters',
53 'corsheaders', 53 'corsheaders',
54 'oauth2_provider', 54 'oauth2_provider',
  55 + 'actstream',
55 ) 56 )
56 57
57 PROJECT_APPS = ( 58 PROJECT_APPS = (
@@ -61,6 +62,8 @@ PROJECT_APPS = ( @@ -61,6 +62,8 @@ PROJECT_APPS = (
61 'edicto', 62 'edicto',
62 ) 63 )
63 64
  65 +SITE_ID = 1
  66 +
64 INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + PROJECT_APPS 67 INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + PROJECT_APPS
65 68
66 MIDDLEWARE = ( 69 MIDDLEWARE = (
@@ -192,3 +195,7 @@ AUTHENTICATION_BACKENDS = ( @@ -192,3 +195,7 @@ AUTHENTICATION_BACKENDS = (
192 195
193 # Secret Key para Captcha. 196 # Secret Key para Captcha.
194 SECRET_KEY_CAPTCHA = env.str('SECRET_KEY_CAPTCHA', default="") 197 SECRET_KEY_CAPTCHA = env.str('SECRET_KEY_CAPTCHA', default="")
  198 +
  199 +ACTSTREAM_SETTINGS = {
  200 + 'USE_JSONFIELD': True,
  201 +}
@@ -19,3 +19,6 @@ pyOpenSSL==22.0.0 @@ -19,3 +19,6 @@ pyOpenSSL==22.0.0
19 # database 19 # database
20 psycopg2==2.9.1 20 psycopg2==2.9.1
21 psycopg2-binary==2.9.1 21 psycopg2-binary==2.9.1
  22 +
  23 +# Django Activity
  24 +django-activity-stream==1.4.2