src/notes/api/views/sync.py
author ymh <ymh.work@gmail.com>
Fri, 28 Jul 2017 19:40:35 +0200
changeset 129 d48946d164c6
parent 128 34a75bd8d0b9
child 132 906a6c7c7943
permissions -rw-r--r--
Add a first version of synchronisation Remove redux-offline dependency make the redux state fully immutable TODO: better error management TODO: make syncronization work automatically

import datetime
import logging

from auditlog.models import LogEntry
from django.utils import timezone
from notes.models import Note, Session
from rest_framework import permissions
from rest_framework.response import Response
from rest_framework.views import APIView

logger = logging.getLogger(__name__)

class ListLogsView(APIView):
    """
    View to list tle log of changes on Note and Sessions.

    * Only registered users are able to access this view.
    * the results are filtered by connected user
    """
    permission_classes = (permissions.IsAuthenticated,)

    def __filter_object(self, model, user, modified_since, client_id):
        """
        Log entries are filtered by model, actor and timestamp.
        If a client id is given, log entries from this client are ignored.
        """
        log_entries = LogEntry.objects.get_for_model(model).filter(actor=user)
        if modified_since:
            log_entries = log_entries.filter(timestamp__gte=modified_since)
        if client_id:
            log_entries = log_entries.exclude(client=client_id)
        return log_entries.order_by('timestamp')

    def __process_log_entries(self, model, user, modified_since, client_id):
        '''
        Process log entries
        '''
        log_entries = self.__filter_object(model, user, modified_since, client_id)
        logger.debug("LOG ENTRies %r", list(log_entries))

        res = {}
        for log_entry in log_entries:
            ext_id = log_entry.additional_data.get('ext_id')
            if not ext_id:
                continue
            sync_entry = res.get(ext_id, {})
            new_action = {
                (None                  , LogEntry.Action.CREATE): LogEntry.Action.CREATE,
                (LogEntry.Action.CREATE, LogEntry.Action.CREATE): LogEntry.Action.CREATE,
                (LogEntry.Action.UPDATE, LogEntry.Action.CREATE): LogEntry.Action.UPDATE,
                (LogEntry.Action.DELETE, LogEntry.Action.CREATE): LogEntry.Action.UPDATE,

                (None                  , LogEntry.Action.UPDATE): LogEntry.Action.UPDATE,
                (LogEntry.Action.CREATE, LogEntry.Action.UPDATE): LogEntry.Action.CREATE,
                (LogEntry.Action.UPDATE, LogEntry.Action.UPDATE): LogEntry.Action.UPDATE,
                (LogEntry.Action.DELETE, LogEntry.Action.UPDATE): LogEntry.Action.DELETE,

                (None                  , LogEntry.Action.DELETE): LogEntry.Action.DELETE,
                (LogEntry.Action.CREATE, LogEntry.Action.DELETE): None,
                (LogEntry.Action.UPDATE, LogEntry.Action.DELETE): LogEntry.Action.DELETE,
                (LogEntry.Action.DELETE, LogEntry.Action.DELETE): LogEntry.Action.DELETE,

            } [(sync_entry.get('action'), log_entry.action)]
            if new_action is None:
                del res[ext_id]
            else:
                res[ext_id] = {
                    'type': log_entry.content_type.model,
                    'ext_id': ext_id,
                    'action': new_action,
                    'timestamp': log_entry.timestamp
                }
        return res

    def get(self, request, format=None):
        """
        Return an aggregations of all changes.
        """
        modified_since_str = request.query_params.get('modified_since', None)
        modified_since = None
        if modified_since_str is not None:
            modified_since = datetime.datetime.fromtimestamp(
                float(modified_since_str),
                timezone.utc
            )

        user = request.user
        client_id = request.META.get('HTTP_AUDITLOG_CLIENT', None)
        res_sessions = self.__process_log_entries(Session, user, modified_since, client_id)
        res_notes = self.__process_log_entries(Note, user, modified_since, client_id)

        return Response({
            'sessions': res_sessions.values(),
            'notes': res_notes.values()
        })