+class ReadOnlyAwareAdmin(admin.ModelAdmin):
+
+ def has_add_permission(self, request, obj=None):
+ return (not self.__user_is_readonly(request))
+
+ def has_delete_permission(self, request, obj=None):
+ return (not self.__user_is_readonly(request))
+
+ def save_model(self, request, obj, form, change):
+ if self.__user_is_readonly(request):
+ raise PermissionDenied
+ #pass
+ else:
+ return super(ReadOnlyAwareAdmin, self).save_model(request, obj, form, change)
+
+ def get_actions(self,request):
+ actions = super(ReadOnlyAwareAdmin,self).get_actions(request)
+
+ if self.__user_is_readonly(request):
+ if 'delete_selected' in actions:
+ del actions['delete_selected']
+
+ return actions
+
+ def change_view(self,request,object_id, extra_context=None):
+ if self.__user_is_readonly(request):
+ if not hasattr(self, "readonly_save"):\r
+ # save the original readonly fields\r
+ self.readonly_save = self.readonly_fields\r
+ self.inlines_save = self.inlines\r
+ if hasattr(self, "user_readonly_fields"):\r
+ self.readonly_fields=self.user_readonly_fields\r
+ if hasattr(self, "user_readonly_inlines"):\r
+ self.inlines = self.user_readonly_inlines\r
+ else:\r
+ if hasattr(self, "readonly_save"):\r
+ # restore the original readonly fields\r
+ self.readonly_fields = self.readonly_save\r
+ if hasattr(self, "inlines_save"):\r
+ self.inlines = self.inlines_save
+
+ try:
+ return super(ReadOnlyAwareAdmin, self).change_view(request, object_id, extra_context=extra_context)
+ except PermissionDenied:
+ pass
+ if request.method == 'POST':
+ raise PermissionDenied
+ request.readonly = True
+ return super(ReadOnlyAwareAdmin, self).change_view(request, object_id, extra_context=extra_context)
+
+ def __user_is_readonly(self, request):
+ return request.user.isReadOnlyUser()
+
+class SingletonAdmin (ReadOnlyAwareAdmin):
+ def has_add_permission(self, request):
+ if not super(SingletonAdmin, self).has_add_permission(request):
+ return False
+
+ num_objects = self.model.objects.count()
+ if num_objects >= 1:
+ return False
+ else:
+ return True
+
+
+class PlStackTabularInline(admin.TabularInline):
+ def __init__(self, *args, **kwargs):
+ super(PlStackTabularInline, self).__init__(*args, **kwargs)
+
+ # InlineModelAdmin as no get_fields() method, so in order to add
+ # the selflink field, we override __init__ to modify self.fields and
+ # self.readonly_fields.
+
+ self.setup_selflink()
+
+ def get_change_url(self, model, id):
+ """ Get the URL to a change form in the admin for this model """
+ reverse_path = "admin:%s_change" % (model._meta.db_table)
+ try:
+ url = reverse(reverse_path, args=(id,))
+ except NoReverseMatch:
+ return None
+
+ return url
+
+ def setup_selflink(self):
+ if hasattr(self, "selflink_fieldname"):
+ """ self.selflink_model can be defined to punch through a relation
+ to its target object. For example, in SliceNetworkInline, set
+ selflink_model = "network", and the URL will lead to the Network
+ object instead of trying to bring up a change view of the
+ SliceNetwork object.
+ """
+ self.selflink_model = getattr(self.model,self.selflink_fieldname).field.rel.to
+ else:
+ self.selflink_model = self.model
+
+ url = self.get_change_url(self.selflink_model, 0)
+
+ # We don't have an admin for this object, so don't create the
+ # selflink.
+ if (url == None):
+ return
+
+ # Since we need to add "selflink" to the field list, we need to create
+ # self.fields if it is None.
+ if (self.fields is None):
+ self.fields = []
+ for f in self.model._meta.fields:
+ if f.editable and f.name != "id":
+ self.fields.append(f.name)
+
+ self.fields = tuple(self.fields) + ("selflink", )
+
+ if self.readonly_fields is None:
+ self.readonly_fields = ()
+
+ self.readonly_fields = tuple(self.readonly_fields) + ("selflink", )
+
+ def selflink(self, obj):
+ if hasattr(self, "selflink_fieldname"):
+ obj = getattr(obj, self.selflink_fieldname)