Minor bug fixes
[plstackapi.git] / planetstack / core / admin.py
index 6fe9095..8e81b4b 100644 (file)
@@ -232,10 +232,10 @@ class SliverInline(PlStackTabularInline):
         return Sliver.select_by_user(request.user)
 
     def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
-        field = super(SliverInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
-
         if db_field.name == 'deploymentNetwork':
-           kwargs['queryset'] = Deployment.select_by_user(request.user)
+           kwargs['queryset'] = Deployment.select_by_acl(request.user)
+
+        field = super(SliverInline, self).formfield_for_foreignkey(db_field, request, **kwargs)
 
         return field
 
@@ -432,14 +432,22 @@ class SliceNetworkInline(PlStackTabularInline):
     suit_classes = 'suit-tab suit-tab-slicenetworks'
     fields = ['network']
 
+class ImageDeploymentsROInline(ReadOnlyTabularInline):
+    model = ImageDeployments
+    extra = 0
+    verbose_name = "Image Deployments"
+    verbose_name_plural = "Image Deployments"
+    suit_classes = 'suit-tab suit-tab-imagedeployments'
+    fields = ['image', 'deployment', 'glance_image_id']
+
 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']
+    fields = ['image', 'deployment', 'glance_image_id']
+    readonly_fields = ['glance_image_id']
 
 class PlainTextWidget(forms.HiddenInput):
     input_type = 'hidden'
@@ -478,10 +486,19 @@ class DeploymentAdminForm(forms.ModelForm):
     sites = forms.ModelMultipleChoiceField(
         queryset=Site.objects.all(),
         required=False,
+        help_text="Select which sites are allowed to host nodes in this deployment",
         widget=FilteredSelectMultiple(
             verbose_name=('Sites'), is_stacked=False
         )
     )
+    images = forms.ModelMultipleChoiceField(
+        queryset=Image.objects.all(),
+        required=False,
+        help_text="Select which images should be deployed on this deployment",
+        widget=FilteredSelectMultiple(
+            verbose_name=('Images'), is_stacked=False
+        )
+    )
     class Meta:
         model = Deployment
 
@@ -493,6 +510,42 @@ class DeploymentAdminForm(forms.ModelForm):
 
       if self.instance and self.instance.pk:
         self.fields['sites'].initial = [x.site for x in self.instance.sitedeployments_set.all()]
+        self.fields['images'].initial = [x.image for x in self.instance.imagedeployments_set.all()]
+
+    def manipulate_m2m_objs(self, this_obj, selected_objs, all_relations, relation_class, local_attrname, foreign_attrname):
+        """ helper function for handling m2m relations from the MultipleChoiceField
+
+            this_obj: the source object we want to link from
+
+            selected_objs: a list of destination objects we want to link to
+
+            all_relations: the full set of relations involving this_obj, including ones we don't want
+
+            relation_class: the class that implements the relation from source to dest
+
+            local_attrname: field name representing this_obj in relation_class
+
+            foreign_attrname: field name representing selected_objs in relation_class
+
+            This function will remove all newobjclass relations from this_obj
+            that are not contained in selected_objs, and add any relations that
+            are in selected_objs but don't exist in the data model yet.
+        """
+
+        existing_dest_objs = []
+        for relation in list(all_relations):
+            if getattr(relation, foreign_attrname) not in selected_objs:
+                #print "deleting site", sdp.site
+                relation.delete()
+            else:
+                existing_dest_objs.append(getattr(relation, foreign_attrname))
+
+        for dest_obj in selected_objs:
+            if dest_obj not in existing_dest_objs:
+                #print "adding site", site
+                kwargs = {foreign_attrname: dest_obj, local_attrname: this_obj}
+                relation = relation_class(**kwargs)
+                relation.save()
 
     def save(self, commit=True):
       deployment = super(DeploymentAdminForm, self).save(commit=False)
@@ -505,21 +558,8 @@ class DeploymentAdminForm(forms.ModelForm):
         #    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.manipulate_m2m_objs(deployment, self.cleaned_data['sites'], deployment.sitedeployments_set.all(), SiteDeployments, "deployment", "site")
+        self.manipulate_m2m_objs(deployment, self.cleaned_data['images'], deployment.imagedeployments_set.all(), ImageDeployments, "deployment", "image")
 
         self.save_m2m()
 
@@ -536,14 +576,14 @@ class SiteAssocInline(PlStackTabularInline):
 
 class DeploymentAdmin(PlanetStackBaseAdmin):
     model = Deployment
-    fieldList = ['name','sites', 'accessControl']
+    fieldList = ['name','sites', 'images', 'accessControl']
     fieldsets = [(None, {'fields': fieldList, 'classes':['suit-tab suit-tab-sites']})]
-    inlines = [DeploymentPrivilegeInline,NodeInline,TagInline]
+    inlines = [DeploymentPrivilegeInline,NodeInline,TagInline] # ,ImageDeploymentsInline]
 
-    user_readonly_inlines = [DeploymentPrivilegeROInline,NodeROInline,TagROInline]
+    user_readonly_inlines = [DeploymentPrivilegeROInline,NodeROInline,TagROInline] # ,ImageDeploymentsROInline]
     user_readonly_fields = ['name']
 
-    suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags'))
+    suit_form_tabs =(('sites','Deployment Details'),('nodes','Nodes'),('deploymentprivileges','Privileges'),('tags','Tags')) # ,('imagedeployments','Images'))
 
     def get_form(self, request, obj=None, **kwargs):
         if request.user.isReadOnlyUser():
@@ -788,9 +828,9 @@ class ImageAdmin(PlanetStackBaseAdmin):
     suit_form_tabs =(('general','Image Details'),('slivers','Slivers'),('imagedeployments','Deployments'))
 
     inlines = [SliverInline, ImageDeploymentsInline]
-    
+
     user_readonly_fields = ['name', 'disk_format', 'container_format']
-    user_readonly_inlines = [SliverROInline]
+    user_readonly_inlines = [SliverROInline, ImageDeploymentsROInline]
     
 class NodeForm(forms.ModelForm):
     class Meta: