consolidate API code for core and plus, fix access/default change in sliceplus, shore up caller arguments in update
diff --git a/planetstack/apigen/api.template.py b/planetstack/apigen/api.template.py
index 7ba0fe3..b3438c0 100644
--- a/planetstack/apigen/api.template.py
+++ b/planetstack/apigen/api.template.py
@@ -11,6 +11,7 @@
 from django.conf.urls import patterns, url
 from rest_framework.exceptions import PermissionDenied as RestFrameworkPermissionDenied
 from django.core.exceptions import PermissionDenied as DjangoPermissionDenied
+from xosapibase import XOSRetrieveUpdateDestroyAPIView, XOSListCreateAPIView
 
 if hasattr(serializers, "ReadOnlyField"):
     # rest_framework 3.x
@@ -152,117 +153,17 @@
 
 {% endfor %}
 
-serializerLookUp = { 
+serializerLookUp = {
 {% for object in generator.all %}
                  {{ object.camel }}: {{ object.camel }}Serializer,
 {% endfor %}
                  None: None,
                 }
 
-class PlanetStackRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
-
-    # To handle fine-grained field permissions, we have to check can_update
-    # the object has been updated but before it has been saved.
-
-    def update(self, request, *args, **kwargs):

-        partial = kwargs.pop('partial', False)

-        self.object = self.get_object_or_none()

-

-        serializer = self.get_serializer(self.object, data=request.DATA,

-                                         files=request.FILES, partial=partial)

-

-        if not serializer.is_valid():

-            response = {"error": "validation",

-                        "specific_error": "not serializer.is_valid()",

-                        "reasons": serializer.errors}

-            return Response(response, status=status.HTTP_400_BAD_REQUEST)

-

-        try:

-            self.pre_save(serializer.object)

-        except ValidationError as err:

-            # full_clean on model instance may be called in pre_save,

-            # so we have to handle eventual errors.

-            response = {"error": "validation",

-                         "specific_error": "ValidationError in pre_save",

-                         "reasons": err.message_dict}

-            return Response(response, status=status.HTTP_400_BAD_REQUEST)

-

-        if serializer.object is not None:

-            if not serializer.object.can_update(request.user):

-                return Response(status=status.HTTP_400_BAD_REQUEST)

-

-        if self.object is None:

-            raise Exception("Use the List API for creating objects")

-

-        self.object = serializer.save(force_update=True)

-        self.post_save(self.object, created=False)

-        return Response(serializer.data, status=status.HTTP_200_OK)
-
-    def destroy(self, request, *args, **kwargs):
-        obj = self.get_object()
-        if obj.can_update(request.user):
-            return super(PlanetStackRetrieveUpdateDestroyAPIView, self).destroy(request, *args, **kwargs)
-        else:
-            return Response(status=status.HTTP_400_BAD_REQUEST)
-
-    def handle_exception(self, exc):
-        # REST API drops the string attached to Django's PermissionDenied
-        # exception, and replaces it with a generic "Permission Denied"
-        if isinstance(exc, DjangoPermissionDenied):
-            response=Response({'detail': str(exc)}, status=status.HTTP_403_FORBIDDEN)
-            response.exception=True
-            return response
-        else:
-            return super(PlanetStackRetrieveUpdateDestroyAPIView, self).handle_exception(exc)
-
-class PlanetStackListCreateAPIView(generics.ListCreateAPIView):
-    def handle_exception(self, exc):
-        # REST API drops the string attached to Django's PermissionDenied
-        # exception, and replaces it with a generic "Permission Denied"
-        if isinstance(exc, DjangoPermissionDenied):
-            response=Response({'detail': str(exc)}, status=status.HTTP_403_FORBIDDEN)
-            response.exception=True
-            return response
-        else:
-            return super(PlanetStackListCreateAPIView, self).handle_exception(exc)
-
-    def create(self, request, *args, **kwargs):
-        serializer = self.get_serializer(data=request.DATA, files=request.FILES)
-        if not (serializer.is_valid()):
-            response = {"error": "validation",
-                        "specific_error": "not serializer.is_valid()",

-                        "reasons": serializer.errors}

-            return Response(response, status=status.HTTP_400_BAD_REQUEST)
-
-        # now do XOS can_update permission checking
-
-        obj = serializer.object
-        obj.caller = request.user
-        if not obj.can_update(request.user):
-            response = {"error": "validation",
-                        "specific_error": "failed can_update",

-                        "reasons": []}

-            return Response(response, status=status.HTTP_400_BAD_REQUEST)
-
-        # stuff below is from generics.ListCreateAPIView
-
-        if (hasattr(self, "pre_save")):
-            # rest_framework 2.x
-            self.pre_save(serializer.object)
-            self.object = serializer.save(force_insert=True)
-            self.post_save(self.object, created=True)
-        else:
-            # rest_framework 3.x
-            self.perform_create(serializer)
-
-        headers = self.get_success_headers(serializer.data)
-        return Response(serializer.data, status=status.HTTP_201_CREATED,

-                        headers=headers)
-
 # Based on core/views/*.py
 {% for object in generator.all %}
 
-class {{ object.camel }}List(PlanetStackListCreateAPIView):
+class {{ object.camel }}List(XOSListCreateAPIView):
     queryset = {{ object.camel }}.objects.select_related().all()
     serializer_class = {{ object.camel }}Serializer
     id_serializer_class = {{ object.camel }}IdSerializer
@@ -284,7 +185,7 @@
         return {{ object.camel }}.select_by_user(self.request.user)
 
 
-class {{ object.camel }}Detail(PlanetStackRetrieveUpdateDestroyAPIView):
+class {{ object.camel }}Detail(XOSRetrieveUpdateDestroyAPIView):
     queryset = {{ object.camel }}.objects.select_related().all()
     serializer_class = {{ object.camel }}Serializer
     id_serializer_class = {{ object.camel }}IdSerializer
@@ -303,8 +204,8 @@
             raise RestFrameworkPermissionDenied("You must be authenticated in order to use this API")
         return {{ object.camel }}.select_by_user(self.request.user)
 
-    # update() is handled by PlanetStackRetrieveUpdateDestroyAPIView
+    # update() is handled by XOSRetrieveUpdateDestroyAPIView
 
-    # destroy() is handled by PlanetStackRetrieveUpdateDestroyAPIView
+    # destroy() is handled by XOSRetrieveUpdateDestroyAPIView
 
 {% endfor %}
diff --git a/planetstack/core/xoslib/methods/plus.py b/planetstack/core/xoslib/methods/plus.py
index a50b064..f753620 100644
--- a/planetstack/core/xoslib/methods/plus.py
+++ b/planetstack/core/xoslib/methods/plus.py
@@ -2,6 +2,7 @@
 from rest_framework import serializers
 from rest_framework.response import Response
 from rest_framework import status
+from xosapibase import XOSRetrieveUpdateDestroyAPIView, XOSListCreateAPIView
 
 """ PlusSerializerMixin
 
@@ -25,87 +26,7 @@
     def getBackendHtml(self, obj):
         return obj.getBackendHtml()
 
-# XXX this was lifted and hacked up a bit from genapi.py
-class PlusListCreateAPIView(generics.ListCreateAPIView):
-    def create(self, request, *args, **kwargs):
-        serializer = self.get_serializer(data=request.DATA, files=request.FILES)
-        if not (serializer.is_valid()):
-            response = {"error": "validation",
-                        "specific_error": "not serializer.is_valid()",

-                        "reasons": serializer.errors}

-            return Response(response, status=status.HTTP_400_BAD_REQUEST)
 
-        # now do XOS can_update permission checking
 
-        obj = serializer.object
-        obj.caller = request.user
-        if not obj.can_update(request.user):
-            response = {"error": "validation",
-                        "specific_error": "failed can_update",

-                        "reasons": []}

-            return Response(response, status=status.HTTP_400_BAD_REQUEST)
 
-        # stuff below is from generics.ListCreateAPIView
-
-        if (hasattr(self, "pre_save")):
-            # rest_framework 2.x
-            self.pre_save(serializer.object)
-            self.object = serializer.save(force_insert=True)
-            self.post_save(self.object, created=True)
-        else:
-            # rest_framework 3.x
-            self.perform_create(serializer)
-
-        headers = self.get_success_headers(serializer.data)
-        return Response(serializer.data, status=status.HTTP_201_CREATED,

-                        headers=headers)
-
-# XXX this is taken from genapi.py
-# XXX find a better way to re-use the code
-class PlusRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
-
-    # To handle fine-grained field permissions, we have to check can_update
-    # the object has been updated but before it has been saved.
-
-    def update(self, request, *args, **kwargs):

-        partial = kwargs.pop('partial', False)

-        self.object = self.get_object_or_none()

-

-        serializer = self.get_serializer(self.object, data=request.DATA,

-                                         files=request.FILES, partial=partial)

-

-        if not serializer.is_valid():

-            response = {"error": "validation",

-                        "specific_error": "not serializer.is_valid()",

-                        "reasons": serializer.errors}

-            return Response(response, status=status.HTTP_400_BAD_REQUEST)

-

-        try:

-            self.pre_save(serializer.object)

-        except ValidationError as err:

-            # full_clean on model instance may be called in pre_save,

-            # so we have to handle eventual errors.

-            response = {"error": "validation",

-                         "specific_error": "ValidationError in pre_save",

-                         "reasons": err.message_dict}

-            return Response(response, status=status.HTTP_400_BAD_REQUEST)

-

-        if serializer.object is not None:

-            if not serializer.object.can_update(request.user):

-                return Response(status=status.HTTP_400_BAD_REQUEST)

-

-        if self.object is None:

-            raise Exception("Use the List API for creating objects")

-

-        self.object = serializer.save(force_update=True)

-        self.object.caller = request.user

-        self.post_save(self.object, created=False)

-        return Response(serializer.data, status=status.HTTP_200_OK)
-
-    def destroy(self, request, *args, **kwargs):
-        obj = self.get_object()
-        if obj.can_update(request.user):
-            return super(generics.RetrieveUpdateDestroyAPIView, self).destroy(request, *args, **kwargs)
-        else:
-            return Response(status=status.HTTP_400_BAD_REQUEST)
 
diff --git a/planetstack/core/xoslib/methods/sliceplus.py b/planetstack/core/xoslib/methods/sliceplus.py
index 2af4263..0539e62 100644
--- a/planetstack/core/xoslib/methods/sliceplus.py
+++ b/planetstack/core/xoslib/methods/sliceplus.py
@@ -6,7 +6,8 @@
 from core.models import *

 from django.forms import widgets
 from core.xoslib.objects.sliceplus import SlicePlus
-from plus import PlusSerializerMixin, PlusRetrieveUpdateDestroyAPIView, PlusListCreateAPIView
+from plus import PlusSerializerMixin
+from xosapibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView
 from rest_framework.exceptions import PermissionDenied as RestFrameworkPermissionDenied
 
 if hasattr(serializers, "ReadOnlyField"):
@@ -70,7 +71,7 @@
                       'default_image', 'default_flavor',
                       'serviceClass','creator','networks','sliceInfo','network_ports','backendIcon','backendHtml','site_allocation','site_ready','users',"user_names","current_user_can_see")
 
-class SlicePlusList(PlusListCreateAPIView):
+class SlicePlusList(XOSListCreateAPIView):
     queryset = SlicePlus.objects.select_related().all()
     serializer_class = SlicePlusIdSerializer
 
@@ -98,7 +99,7 @@
 
         return slices
 
-class SlicePlusDetail(PlusRetrieveUpdateDestroyAPIView):
+class SlicePlusDetail(XOSRetrieveUpdateDestroyAPIView):
     queryset = SlicePlus.objects.select_related().all()
     serializer_class = SlicePlusIdSerializer
 
@@ -110,16 +111,4 @@
             raise RestFrameworkPermissionDenied("You must be authenticated in order to use this API")
         return SlicePlus.select_by_user(self.request.user)
 
-    def update(self, request, *args, **kwargs):
-        obj = self.get_object()
-        if obj.can_update(request.user):
-            return super(SlicePlusDetail, self).update(request, *args, **kwargs)
-        else:
-            return Response(status=status.HTTP_400_BAD_REQUEST)
 
-    def destroy(self, request, *args, **kwargs):
-        obj = self.get_object()
-        if obj.can_update(request.user):
-            return super(SlicePlusDetail, self).destroy(request, *args, **kwargs)
-        else:
-            return Response(status=status.HTTP_400_BAD_REQUEST)
diff --git a/planetstack/core/xoslib/objects/sliceplus.py b/planetstack/core/xoslib/objects/sliceplus.py
index 6bbbfa2..47c93d7 100644
--- a/planetstack/core/xoslib/objects/sliceplus.py
+++ b/planetstack/core/xoslib/objects/sliceplus.py
@@ -135,6 +135,9 @@
         return nodeList
 
     def save(self, *args, **kwargs):
+        if (not hasattr(self,"caller")) or self.caller==None:
+            raise APIException("no self.caller in SlicePlus.save")
+
         updated_image = self.has_field_changed("default_image")
         updated_flavor = self.has_field_changed("default_flavor")
 
@@ -210,6 +213,7 @@
                             flavor = self.default_flavor,
                             creator = self.creator,
                             deployment = node.site_deployment.deployment)
+                    sliver.caller = self.caller
                     slivers.append(sliver)
                     if (not noAct):
                         print "added sliver", sliver
@@ -222,7 +226,10 @@
     def save_users(self, noAct = False):
         new_users = self._update_users
 
-        default_role = SliceRole.objects.get(role="default")
+        try:
+            default_role = SliceRole.objects.get(role="access")
+        except:
+            default_role = SliceRole.objects.get(role="default")
 
         slice_privs = self.sliceprivileges.all()
         slice_user_ids = [priv.user.id for priv in slice_privs]
@@ -230,6 +237,7 @@
         for user_id in new_users:
             if (user_id not in slice_user_ids):
                 priv = SlicePrivilege(slice=self, user=User.objects.get(id=user_id), role=default_role)
+                priv.caller = self.caller
                 if (not noAct):
                     priv.save()
 
@@ -256,6 +264,7 @@
                 continue
             if network.ports:
                 network.ports = self._network_ports
+                network.caller = self.caller
                 if (not noAct):
                     network.save()
                 return
@@ -268,6 +277,7 @@
                 continue
             if network.template.translation=="NAT":
                 network.ports = self._network_ports
+                network.caller = self.caller
                 if (not noAct):
                     network.save()
                 return
diff --git a/planetstack/xosapibase.py b/planetstack/xosapibase.py
new file mode 100644
index 0000000..3efb1de
--- /dev/null
+++ b/planetstack/xosapibase.py
@@ -0,0 +1,110 @@
+from rest_framework.response import Response
+from rest_framework import serializers
+from rest_framework import generics
+from rest_framework import status
+from rest_framework.exceptions import PermissionDenied as RestFrameworkPermissionDenied
+from django.core.exceptions import PermissionDenied as DjangoPermissionDenied
+
+class XOSRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
+
+    # To handle fine-grained field permissions, we have to check can_update
+    # the object has been updated but before it has been saved.
+
+    def update(self, request, *args, **kwargs):

+        partial = kwargs.pop('partial', False)

+        self.object = self.get_object_or_none()

+

+        if self.object is None:

+            raise Exception("Use the List API for creating objects")

+

+        serializer = self.get_serializer(self.object, data=request.DATA,

+                                         files=request.FILES, partial=partial)

+

+        assert(serializer.object is not None)

+

+        serializer.object.caller = request.user

+

+        if not serializer.is_valid():

+            response = {"error": "validation",

+                        "specific_error": "not serializer.is_valid()",

+                        "reasons": serializer.errors}

+            return Response(response, status=status.HTTP_400_BAD_REQUEST)

+

+        try:

+            self.pre_save(serializer.object)

+        except ValidationError as err:

+            # full_clean on model instance may be called in pre_save,

+            # so we have to handle eventual errors.

+            response = {"error": "validation",

+                         "specific_error": "ValidationError in pre_save",

+                         "reasons": err.message_dict}

+            return Response(response, status=status.HTTP_400_BAD_REQUEST)

+

+        if not serializer.object.can_update(request.user):

+            return Response(status=status.HTTP_400_BAD_REQUEST)

+

+        self.object = serializer.save(force_update=True)

+        self.post_save(self.object, created=False)

+        return Response(serializer.data, status=status.HTTP_200_OK)
+
+    def destroy(self, request, *args, **kwargs):
+        obj = self.get_object()
+        if obj.can_update(request.user):
+            return super(XOSRetrieveUpdateDestroyAPIView, self).destroy(request, *args, **kwargs)
+        else:
+            return Response(status=status.HTTP_400_BAD_REQUEST)
+
+    def handle_exception(self, exc):
+        # REST API drops the string attached to Django's PermissionDenied
+        # exception, and replaces it with a generic "Permission Denied"
+        if isinstance(exc, DjangoPermissionDenied):
+            response=Response({'detail': str(exc)}, status=status.HTTP_403_FORBIDDEN)
+            response.exception=True
+            return response
+        else:
+            return super(XOSRetrieveUpdateDestroyAPIView, self).handle_exception(exc)
+
+class XOSListCreateAPIView(generics.ListCreateAPIView):
+    def create(self, request, *args, **kwargs):
+        serializer = self.get_serializer(data=request.DATA, files=request.FILES)
+        if not (serializer.is_valid()):
+            response = {"error": "validation",
+                        "specific_error": "not serializer.is_valid()",

+                        "reasons": serializer.errors}

+            return Response(response, status=status.HTTP_400_BAD_REQUEST)
+
+        # now do XOS can_update permission checking
+
+        obj = serializer.object
+        obj.caller = request.user
+        if not obj.can_update(request.user):
+            response = {"error": "validation",
+                        "specific_error": "failed can_update",

+                        "reasons": []}

+            return Response(response, status=status.HTTP_400_BAD_REQUEST)
+
+        # stuff below is from generics.ListCreateAPIView
+
+        if (hasattr(self, "pre_save")):
+            # rest_framework 2.x
+            self.pre_save(serializer.object)
+            self.object = serializer.save(force_insert=True)
+            self.post_save(self.object, created=True)
+        else:
+            # rest_framework 3.x
+            self.perform_create(serializer)
+
+        headers = self.get_success_headers(serializer.data)
+        return Response(serializer.data, status=status.HTTP_201_CREATED,

+                        headers=headers)
+
+    def handle_exception(self, exc):
+        # REST API drops the string attached to Django's PermissionDenied
+        # exception, and replaces it with a generic "Permission Denied"
+        if isinstance(exc, DjangoPermissionDenied):
+            response=Response({'detail': str(exc)}, status=status.HTTP_403_FORBIDDEN)
+            response.exception=True
+            return response
+        else:
+            return super(XOSListCreateAPIView, self).handle_exception(exc)
+