fix filtering of deployments when adding slivers
[plstackapi.git] / planetstack / core / admin.py
index 932d2ab..8bf7976 100644 (file)
@@ -43,10 +43,21 @@ class ReadOnlyAwareAdmin(admin.ModelAdmin):
         return actions
 
     def change_view(self,request,object_id, extra_context=None):
-
         if self.__user_is_readonly(request):
-            self.readonly_fields=self.user_readonly_fields
-            self.inlines = self.user_readonly_inlines
+            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)
@@ -57,12 +68,14 @@ class ReadOnlyAwareAdmin(admin.ModelAdmin):
         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 (admin.ModelAdmin):
+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
@@ -205,12 +218,12 @@ class NetworkLookerUpper:
 
 class SliverROInline(ReadOnlyTabularInline):
     model = Sliver
-    fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
+    fields = ['ip', 'instance_name', 'slice', 'numberCores', 'deploymentNetwork', 'image', 'node']
     suit_classes = 'suit-tab suit-tab-slivers'
 
 class SliverInline(PlStackTabularInline):
     model = Sliver
-    fields = ['ip', 'instance_name', 'slice', 'numberCores', 'image', 'node', 'deploymentNetwork']
+    fields = ['ip', 'instance_name', 'slice', 'numberCores', 'deploymentNetwork', 'image', 'node']
     extra = 0
     readonly_fields = ['ip', 'instance_name']
     suit_classes = 'suit-tab suit-tab-slivers'
@@ -218,6 +231,14 @@ class SliverInline(PlStackTabularInline):
     def queryset(self, request):
         return Sliver.select_by_user(request.user)
 
+    def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
+        if db_field.name == 'deploymentNetwork':
+           kwargs['queryset'] = Deployment.select_by_acl(request.user)
+
+        field = super(SliverInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+        return field
+
 # Note this is breaking in the admin.py when trying to use an inline to add a node/image 
 #    def _declared_fieldsets(self):
 #        # Return None so django will call get_fieldsets and we can insert our
@@ -298,25 +319,25 @@ class NodeROInline(ReadOnlyTabularInline):
     model = Node
     extra = 0
     suit_classes = 'suit-tab suit-tab-nodes'
-    fields = ['name','deployment']
+    fields = ['name','deployment','site']
 
 class NodeInline(PlStackTabularInline):
     model = Node
     extra = 0
     suit_classes = 'suit-tab suit-tab-nodes'
-    fields = ['name','deployment']
+    fields = ['name','deployment','site']
 
 class DeploymentPrivilegeROInline(ReadOnlyTabularInline):
     model = DeploymentPrivilege
     extra = 0
     suit_classes = 'suit-tab suit-tab-deploymentprivileges'
-    fields = ['user','role']
+    fields = ['user','role','deployment']
 
 class DeploymentPrivilegeInline(PlStackTabularInline):
     model = DeploymentPrivilege
     extra = 0
     suit_classes = 'suit-tab suit-tab-deploymentprivileges'
-    fields = ['user','role']
+    fields = ['user','role','deployment']
 
     def queryset(self, request):
         return DeploymentPrivilege.select_by_user(request.user)
@@ -349,7 +370,7 @@ class SiteDeploymentROInline(ReadOnlyTabularInline):
     model = SiteDeployments
     #model = Site.deployments.through
     extra = 0
-    suit_classes = 'suit-tab suit-tab-sitedeployments'
+    suit_classes = 'suit-tab suit-tab-deployments'
     fields = ['deployment','site']
 
 class SiteDeploymentInline(PlStackTabularInline):
@@ -409,6 +430,16 @@ class SliceNetworkInline(PlStackTabularInline):
     verbose_name = "Network Connection"
     verbose_name_plural = "Network Connections"
     suit_classes = 'suit-tab suit-tab-slicenetworks'
+    fields = ['network']
+
+class ImageDeploymentsInline(PlStackTabularInline):
+    model = ImageDeployments
+    extra = 0
+    verbose_name = "Image Deployments"
+    verbose_name_plural = "Image Deployments"
+    suit_classes = 'suit-tab suit-tab-imagedeployments'
+    fields = ['deployment', 'glance_image_id']
+    readonly_fields = ['deployment', 'glance_image_id']
 
 class PlainTextWidget(forms.HiddenInput):
     input_type = 'hidden'
@@ -455,10 +486,13 @@ class DeploymentAdminForm(forms.ModelForm):
         model = Deployment
 
     def __init__(self, *args, **kwargs):
+      request = kwargs.pop('request', None)
       super(DeploymentAdminForm, self).__init__(*args, **kwargs)
 
+      self.fields['accessControl'].initial = "allow site " + request.user.site.name
+
       if self.instance and self.instance.pk:
-        self.fields['sites'].initial = self.instance.sitedeployments_set.all()
+        self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
 
     def save(self, commit=True):
       deployment = super(DeploymentAdminForm, self).save(commit=False)
@@ -467,20 +501,42 @@ class DeploymentAdminForm(forms.ModelForm):
         deployment.save()
 
       if deployment.pk:
-        deployment.sites = self.cleaned_data['sites']
+        # save_m2m() doesn't seem to work with 'through' relations. So we
+        #    create/destroy the through models ourselves. There has to be
+        #    a better way...
+
+        sites = self.cleaned_data['sites']
+
+        existing_sites = []
+        for sdp in list(deployment.sitedeployments_set.all()):
+            if sdp.site not in sites:
+                #print "deleting site", sdp.site
+                sdp.delete()
+            else:
+                existing_sites.append(sdp.site)
+
+        for site in sites:
+            if site not in existing_sites:
+                #print "adding site", site
+                sdp = SiteDeployments(site=site, deployment=deployment)
+                sdp.save()
+
         self.save_m2m()
 
       return deployment
 
+class DeploymentAdminROForm(DeploymentAdminForm):
+    def save(self, commit=True):
+        raise PermissionDenied
+
 class SiteAssocInline(PlStackTabularInline):
     model = Site.deployments.through
     extra = 0
     suit_classes = 'suit-tab suit-tab-sites'
 
 class DeploymentAdmin(PlanetStackBaseAdmin):
-    form = DeploymentAdminForm
     model = Deployment
-    fieldList = ['name','sites']
+    fieldList = ['name','sites', 'accessControl']
     fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
     inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
 
@@ -489,6 +545,22 @@ class DeploymentAdmin(PlanetStackBaseAdmin):
 
     suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
 
+    def get_form(self, request, obj=None, **kwargs):
+        if request.user.isReadOnlyUser():
+            kwargs["form"] = DeploymentAdminROForm
+        else:
+            kwargs["form"] = DeploymentAdminForm
+        adminForm = super(DeploymentAdmin,self).get_form(request, obj, **kwargs)
+
+        # from stackexchange: pass the request object into the form
+
+        class AdminFormMetaClass(adminForm):
+           def __new__(cls, *args, **kwargs):
+               kwargs['request'] = request
+               return adminForm(*args, **kwargs)
+
+        return AdminFormMetaClass
+
 class ServiceAttrAsTabROInline(ReadOnlyTabularInline):
     model = ServiceAttribute
     fields = ['name','value']
@@ -540,7 +612,6 @@ class SiteAdmin(PlanetStackBaseAdmin):
     search_fields = ['name']
 
     def queryset(self, request):
-        #print dir(UserInline)
         return Site.select_by_user(request.user)
 
     def get_formsets(self, request, obj=None):
@@ -633,9 +704,9 @@ class SliceForm(forms.ModelForm):
 
 class SliceAdmin(PlanetStackBaseAdmin):
     form = SliceForm
-    fieldList = ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url']
+    fieldList = ['name', 'site', 'serviceClass', 'enabled','description', 'service', 'slice_url', 'max_slivers']
     fieldsets = [('Slice Details', {'fields': fieldList, 'classes':['suit-tab suit-tab-general']}),]
-    list_display = ('name', 'site','serviceClass', 'slice_url')
+    list_display = ('name', 'site','serviceClass', 'slice_url', 'max_slivers')
     inlines = [SlicePrivilegeInline,SliverInline, TagInline, ReservationInline,SliceNetworkInline]
 
     user_readonly_fields = fieldList
@@ -710,15 +781,15 @@ class SlicePrivilegeAdmin(PlanetStackBaseAdmin):
 class ImageAdmin(PlanetStackBaseAdmin):
 
     fieldsets = [('Image Details', 
-                   {'fields': ['image_id', 'name', 'disk_format', 'container_format'], 
+                   {'fields': ['name', 'disk_format', 'container_format'], 
                     'classes': ['suit-tab suit-tab-general']})
                ]
 
-    suit_form_tabs =(('general','Image Details'),('slivers','Slivers'))
+    suit_form_tabs =(('general','Image Details'),('slivers','Slivers'),('imagedeployments','Deployments'))
 
-    inlines = [SliverInline]
+    inlines = [SliverInline, ImageDeploymentsInline]
     
-    user_readonly_fields = ['image_id', 'name', 'disk_format', 'container_format']
+    user_readonly_fields = ['name', 'disk_format', 'container_format']
     user_readonly_inlines = [SliverROInline]
     
 class NodeForm(forms.ModelForm):
@@ -802,6 +873,9 @@ class SliverAdmin(PlanetStackBaseAdmin):
             # hide MyInline in the add view
             if obj is None:
                 continue
+            if isinstance(inline, SliverInline):
+                inline.model.caller = request.user
+            yield inline.get_formset(request, obj)
 
     #def save_model(self, request, obj, form, change):
     #    # update openstack connection to use this site/tenant
@@ -863,6 +937,18 @@ class UserChangeForm(forms.ModelForm):
         # field does not have access to the initial value
         return self.initial["password"]
 
+class UserDashboardViewInline(PlStackTabularInline):
+    model = UserDashboardView
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-dashboards'
+    fields = ['user', 'dashboardView', 'order']
+
+class UserDashboardViewROInline(ReadOnlyTabularInline):
+    model = UserDashboardView
+    extra = 0
+    suit_classes = 'suit-tab suit-tab-dashboards'
+    fields = ['user', 'dashboardView', 'order']
+
 class UserAdmin(UserAdmin):
     class Meta:
         app_label = "core"
@@ -877,7 +963,7 @@ class UserAdmin(UserAdmin):
     list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
     #list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
     list_filter = ('site',)
-    inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline]
+    inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
 
     fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
     fieldListContactInfo = ['firstname','lastname','phone','timezone']
@@ -885,6 +971,7 @@ class UserAdmin(UserAdmin):
     fieldsets = (
         ('Login Details', {'fields': ['email', 'site','password', 'is_readonly', 'is_admin', 'public_key'], 'classes':['suit-tab suit-tab-general']}),
         ('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
+        #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
         #('Important dates', {'fields': ('last_login',)}),
     )
     add_fieldsets = (
@@ -897,10 +984,15 @@ class UserAdmin(UserAdmin):
     ordering = ('email',)
     filter_horizontal = ()
 
-    user_readonly_fields = fieldListLoginDetails
-    user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline]
+    user_readonly_fields = fieldListLoginDetails + fieldListContactInfo
+    user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline,UserDashboardViewROInline]
 
-    suit_form_tabs =(('general','Login Details'),('contact','Contact Information'),('sliceprivileges','Slice Privileges'),('siteprivileges','Site Privileges'),('deploymentprivileges','Deployment Privileges'))
+    suit_form_tabs =(('general','Login Details'),
+                     ('contact','Contact Information'),
+                     ('sliceprivileges','Slice Privileges'),
+                     ('siteprivileges','Site Privileges'),
+                     ('deploymentprivileges','Deployment Privileges'),
+                     ('dashboards','Dashboard Views'))
 
     def formfield_for_foreignkey(self, db_field, request, **kwargs):
         if db_field.name == 'site':
@@ -926,8 +1018,18 @@ class UserAdmin(UserAdmin):
     def change_view(self,request,object_id, extra_context=None):
 
         if self.__user_is_readonly(request):
+            if not hasattr(self, "readonly_save"):
+                # save the original readonly fields\r
+                self.readonly_save = self.readonly_fields\r
+                self.inlines_save = self.inlines
             self.readonly_fields=self.user_readonly_fields
             self.inlines = self.user_readonly_inlines
+        else:
+            if hasattr(self, "readonly_save"):\r
+                # restore the original readonly fields\r
+                self.readonly_fields = self.readonly_save\r
+                self.inlines = self.inlines_save
+
         try:
             return super(UserAdmin, self).change_view(request, object_id, extra_context=extra_context)
         except PermissionDenied:
@@ -945,7 +1047,13 @@ class UserAdmin(UserAdmin):
     def queryset(self, request):
         return User.select_by_user(request.user)
 
+class DashboardViewAdmin(PlanetStackBaseAdmin):
+    fieldsets = [('Dashboard View Details',
+                   {'fields': ['name', 'url'],
+                    'classes': ['suit-tab suit-tab-general']})
+               ]
 
+    suit_form_tabs =(('general','Dashboard View Details'),)
 
 class ServiceResourceROInline(ReadOnlyTabularInline):
     model = ServiceResource
@@ -1367,4 +1475,5 @@ if True:
     #admin.site.register(SitePrivilege, SitePrivilegeAdmin)
     admin.site.register(Sliver, SliverAdmin)
     admin.site.register(Image, ImageAdmin)
+    admin.site.register(DashboardView, DashboardViewAdmin)