Commits

Matthew Schinckel committed 070954f

Added in logging (and logging middleware).
Will log when masquerades happen (as warning).
Will log all requests (and all data if set to less than logging.DEBUG).
Will log all API change requests (add/change/delete).
Handles embedded objects a bit better in serialisation

Comments (0)

Files changed (3)

rest_api/middleware.py

-         
+import logging
 from auth import _authenticate
 from django.contrib.auth.models import AnonymousUser, User
+import datetime
 
 class HttpAuthMiddleware(object):
     """
 
     def process_request(self, request):
         if isinstance(request.user, AnonymousUser):
+            # We may return an HttpResponse, if we are not authenticated
             return _authenticate(request)
 
 
     def process_request(self, request):
         if request.user.is_superuser:
             if request.META.get('HTTP_X_MASQUERADE_AS', False):
+                if request.user.username == request.META.get('HTTP_X_MASQUERADE_AS'):
+                    return
                 request.real_user = request.user
-                request.user = User.objects.get(username=request.META.get('HTTP_X_MASQUERADE_AS'))
+                request.user = User.objects.get(username=request.META.get('HTTP_X_MASQUERADE_AS'))
+                logging.warning("User %s masquerades as %s from %s" % (
+                    request.real_user, request.user, request.META['REMOTE_ADDR']
+                ))
+
+class HttpContentLoggingMiddleware(object):
+    """
+    Log all request and response data.
+    """
+    
+    def process_request(self, request):
+        self._start_time = datetime.datetime.now()
+        if request.raw_post_data:
+            logging.log(logging.DEBUG - 1, request.raw_post_data)
+    
+    def process_response(self, request, response):
+        time_spent = datetime.datetime.now() - self._start_time
+        
+        logging.log(
+            logging.INFO,
+            "%s %s %s [%s] \"%s %s %s\" %s %s %s" % (
+            request.META.get('REMOTE_ADDR'),
+            '-',
+            '-',
+            (datetime.datetime.now() + datetime.timedelta(hours=9.5)).strftime("%d/%b/%Y %H:%M:%S"),
+            request.method,
+            request.path,
+            "HTTP/1.1",
+            response.status_code,
+            len(response.content) or '-',
+            time_spent.microseconds / 1000000.0,
+        ))
+        logging.log(logging.DEBUG - 1, "\n%s" % response.content)
+        return response
+    
+    def process_exception(self, request, exception):
+        import traceback
+        output = "%s %s" % (request.method, request.path)
+        output += "\nUser: %s" % request.user
+        output += "\nPOST DATA:\n%s\n" % request.raw_post_data
+        output += traceback.format_exc()
+        logging.critical("%s" % output)
+        

rest_api/options.py

 import http
 
 import datetime
+import logging
 
 from models import LogEntry, ADDITION, CHANGE, DELETION
 
             object_repr     = force_unicode(object),
             action_flag     = ADDITION
         )
+        logging.info("%s added by %s" % (
+            force_unicode(object), _get_user(request))
+        )
     
     def log_change(self, request, object, message):
         """
             action_flag     = CHANGE,
             change_message  = message
         )
+        logging.info("%s updated by %s [%s]" % (
+            force_unicode(object), _get_user(request), message)
+        )
     
     def log_deletion(self, request, object, object_repr):
         """
             object_repr     = object_repr,
             action_flag     = DELETION
         )
+        logging.info("%s deleted by %s" % (object_repr, _get_user(request)))
             
     def index(self, request):
         return self.queryset(request)
 class InlineApi(BaseModelApi):
     """
     A model that is a related model of another.
+    
+    It is not accessible as /root/model/, but rather only as
+    /root/parent/:id/models/.
     """
     pass
 

rest_api/serializers.py

 from django.core.serializers.json import simplejson, DjangoJSONEncoder
 from django.core.exceptions import FieldError, ObjectDoesNotExist
 from django.db.models import FieldDoesNotExist
+from django.db import models
 from datetime import date, time, datetime, timedelta
 from decimal import Decimal
 
         exclude = []
     
     if hasattr(queryset, 'model'):
-        api_model = sites.site.get_registered(queryset.model)
+        model = queryset.model
+    elif isinstance(queryset, models.Model):
+        model = queryset.__class__
+    else:
+        model = None
+        
+    if model:
+        api_model = sites.site.get_registered(model)
         if fields is None:
             # First, see if this model is already registered, and use the
             # fields it is registered with.
             if api_model:
                 fields = list(api_model.fields)
             else:
-                fields = [x.name for x in queryset.model._meta.fields]
+                fields = [x.name for x in model._meta.fields]
         else:
             fields = list(fields)
         if api_model:
            fields = []
     
         data = []
+        if not hasattr(queryset, '__iter__'):
+            queryset = [queryset]
+            single = True
+        else:
+            single = False
+        
         for obj in queryset:
             this = {
                 # 'type':obj.__class__.__name__
                     temp = None
                 if api_model and field in api_model.embed_objects:
                     # Need to serialize one object
+                    new_kwargs = kwargs.copy()
+                    new_kwargs['python'] = True
                     if hasattr(temp, 'all'):
-                        temp = serialize(temp.all(), python=True, **kwargs)
+                        temp = serialize(temp.all(), **new_kwargs)
                     else:
-                        temp = serialize(temp, python=True, **kwargs)
+                        temp = serialize(temp, **new_kwargs)
                 elif hasattr(temp, 'pk'):
                     temp = temp.pk
                 elif hasattr(temp, 'all'):
                             temp = temp()
                 # Not sure if this test should be here. Do we want to
                 # exclude extra fields if they are null?
-                if temp is not None and api_model and field not in api_model.extra_fields:
-                    this[field] = temp
+                #if temp is not None and api_model and field not in api_model.extra_fields:
+                this[field] = temp
             data.append(this)
+        if single:
+            data = data[0]
     else:
-        # This is a python structure, not a queryset.
+        # This is a python structure, not a queryset/object.
         data = queryset
     
     if kwargs.get('python'):