]> git.ozlabs.org Git - patchwork/blobdiff - apps/patchwork/views/xmlrpc.py
views: Move mbox handling from models to views
[patchwork] / apps / patchwork / views / xmlrpc.py
index f493cf780f4dc66382ee5bc39077d3e2d116e67a..eebc2aae48600179471782fe8ee55e52a845d83a 100644 (file)
 # Patchwork XMLRPC interface
 #
 
-from django.core.exceptions import ImproperlyConfigured
 from SimpleXMLRPCServer import SimpleXMLRPCDispatcher
 from django.http import HttpResponse, HttpResponseRedirect, \
      HttpResponseServerError
-from django.conf import settings
 from django.core import urlresolvers
-from django.shortcuts import render_to_response
 from django.contrib.auth import authenticate
-from patchwork.models import Patch, Project, Person, Bundle, State
+from patchwork.models import Patch, Project, Person, State
+from patchwork.views import patch_to_mbox
+from django.views.decorators.csrf import csrf_exempt
 
 import sys
 import base64
@@ -39,22 +38,37 @@ class PatchworkXMLRPCDispatcher(SimpleXMLRPCDispatcher):
         if sys.version_info[:3] >= (2,5,):
             SimpleXMLRPCDispatcher.__init__(self, allow_none=False,
                     encoding=None)
+            def _dumps(obj, *args, **kwargs):
+                kwargs['allow_none'] = self.allow_none
+                kwargs['encoding'] = self.encoding
+                return xmlrpclib.dumps(obj, *args, **kwargs)
         else:
+            def _dumps(obj, *args, **kwargs):
+                return xmlrpclib.dumps(obj, *args, **kwargs)
             SimpleXMLRPCDispatcher.__init__(self)
 
+        self.dumps = _dumps
+
         # map of name => (auth, func)
         self.func_map = {}
 
-
     def register_function(self, fn, auth_required):
         self.func_map[fn.__name__] = (auth_required, fn)
 
 
     def _user_for_request(self, request):
-        if not request.META.has_key('HTTP_AUTHORIZATION'):
+        auth_header = None
+
+        if 'HTTP_AUTHORIZATION' in request.META:
+            auth_header = request.META.get('HTTP_AUTHORIZATION')
+        elif 'Authorization' in request.META:
+            auth_header = request.META.get('Authorization')
+
+        if auth_header is None or auth_header == '':
             raise Exception("No authentication credentials given")
 
-        str = request.META.get('HTTP_AUTHORIZATION').strip()
+        str = auth_header.strip()
+
         if not str.startswith('Basic '):
             raise Exception("Authentication scheme not supported")
 
@@ -91,16 +105,13 @@ class PatchworkXMLRPCDispatcher(SimpleXMLRPCDispatcher):
             response = self._dispatch(request, method, params)
             # wrap response in a singleton tuple
             response = (response,)
-            response = xmlrpclib.dumps(response, methodresponse=1,
-                           allow_none=self.allow_none, encoding=self.encoding)
+            response = self.dumps(response, methodresponse=1)
         except xmlrpclib.Fault, fault:
-            response = xmlrpclib.dumps(fault, allow_none=self.allow_none,
-                                       encoding=self.encoding)
+            response = self.dumps(fault)
         except:
             # report exception back to server
-            response = xmlrpclib.dumps(
+            response = self.dumps(
                 xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value)),
-                encoding=self.encoding, allow_none=self.allow_none,
                 )
 
         return response
@@ -108,6 +119,7 @@ class PatchworkXMLRPCDispatcher(SimpleXMLRPCDispatcher):
 dispatcher = PatchworkXMLRPCDispatcher()
 
 # XMLRPC view function
+@csrf_exempt
 def xmlrpc(request):
     if request.method != 'POST':
         return HttpResponseRedirect(
@@ -118,7 +130,7 @@ def xmlrpc(request):
     try:
         ret = dispatcher._marshaled_dispatch(request)
         response.write(ret)
-    except Exception, e:
+    except Exception:
         return HttpResponseServerError()
 
     return response
@@ -156,12 +168,20 @@ def project_to_dict(obj):
 def person_to_dict(obj):
     """Return a trimmed down dictionary representation of a Person
     object which is OK to send to the client."""
+
+    # Make sure we don't return None even if the user submitted a patch
+    # with no real name.  XMLRPC can't marshall None.
+    if obj.name is not None:
+        name = obj.name
+    else:
+        name = obj.email
+
     return \
         {
          'id'           : obj.id,
          'email'        : obj.email,
-         'name'         : obj.name,
-         'user'         : str(obj.user),
+         'name'         : name,
+         'user'         : unicode(obj.user).encode("utf-8"),
         }
 
 def patch_to_dict(obj):
@@ -170,17 +190,17 @@ def patch_to_dict(obj):
     return \
         {
          'id'           : obj.id,
-         'date'         : str(obj.date),
+         'date'         : unicode(obj.date).encode("utf-8"),
          'filename'     : obj.filename(),
          'msgid'        : obj.msgid,
          'name'         : obj.name,
-         'project'      : str(obj.project),
+         'project'      : unicode(obj.project).encode("utf-8"),
          'project_id'   : obj.project_id,
-         'state'        : str(obj.state),
+         'state'        : unicode(obj.state).encode("utf-8"),
          'state_id'     : obj.state_id,
-         'submitter'    : str(obj.submitter),
+         'submitter'    : unicode(obj.submitter).encode("utf-8"),
          'submitter_id' : obj.submitter_id,
-         'delegate'     : str(obj.delegate),
+         'delegate'     : unicode(obj.delegate).encode("utf-8"),
          'delegate_id'  : max(obj.delegate_id, 0),
          'commit_ref'   : max(obj.commit_ref, ''),
         }
@@ -284,7 +304,6 @@ def patch_list(filter={}):
             "commit_ref",
             "hash",
             "msgid",
-            "name",
             "max_count",
             ]
 
@@ -318,7 +337,7 @@ def patch_list(filter={}):
         patches = Patch.objects.filter(**dfilter)
 
         if max_count > 0:
-            return map(patch_to_dict, patches)[:max_count]
+            return map(patch_to_dict, patches[:max_count])
         else:
             return map(patch_to_dict, patches)
 
@@ -334,12 +353,31 @@ def patch_get(patch_id):
     except:
         return {}
 
+@xmlrpc_method(False)
+def patch_get_by_hash(hash):
+    """Return structure for the given patch hash."""
+    try:
+        patch = Patch.objects.filter(hash = hash)[0]
+        return patch_to_dict(patch)
+    except:
+        return {}
+
+@xmlrpc_method(False)
+def patch_get_by_project_hash(project, hash):
+    """Return structure for the given patch hash."""
+    try:
+        patch = Patch.objects.filter(project__linkname = project,
+                                     hash = hash)[0]
+        return patch_to_dict(patch)
+    except:
+        return {}
+
 @xmlrpc_method(False)
 def patch_get_mbox(patch_id):
     """Return mbox string for the given patch ID."""
     try:
         patch = Patch.objects.filter(id = patch_id)[0]
-        return patch.mbox().as_string()
+        return patch_to_mbox(patch).as_string()
     except:
         return ""