From 9496740998d3d5aeaf3c2f76b312f309c15c4f60 Mon Sep 17 00:00:00 2001 From: Scott Baker Date: Mon, 12 Jan 2015 19:45:40 -0800 Subject: [PATCH] edit users button in tenant view --- .../core/xoslib/dashboards/xosTenant.html | 19 ++++- planetstack/core/xoslib/methods/sliceplus.py | 15 +++- planetstack/core/xoslib/methods/tenantview.py | 6 ++ planetstack/core/xoslib/objects/sliceplus.py | 14 +++- .../core/xoslib/static/js/xosTenant.js | 76 +++++++++++++++++-- .../core/xoslib/static/js/xoslib/xos-util.js | 32 ++++++++ .../core/xoslib/static/js/xoslib/xosHelper.js | 15 +++- .../core/xoslib/templates/xosAdmin.html | 4 +- 8 files changed, 161 insertions(+), 20 deletions(-) diff --git a/planetstack/core/xoslib/dashboards/xosTenant.html b/planetstack/core/xoslib/dashboards/xosTenant.html index 42a41e0..16e60f0 100644 --- a/planetstack/core/xoslib/dashboards/xosTenant.html +++ b/planetstack/core/xoslib/dashboards/xosTenant.html @@ -14,13 +14,14 @@ + @@ -33,13 +34,27 @@ + +
Are you sure about this?
-
+ + +
+
+
diff --git a/planetstack/core/xoslib/methods/sliceplus.py b/planetstack/core/xoslib/methods/sliceplus.py index 0cfc67c..c48d036 100644 --- a/planetstack/core/xoslib/methods/sliceplus.py +++ b/planetstack/core/xoslib/methods/sliceplus.py @@ -22,7 +22,14 @@ class NetworkPortsField(serializers.WritableField): # note: maybe just Field i def to_internal_value(self, data): return data -class SiteAllocationField(serializers.WritableField): # note: maybe just Field in rest_framework 3.x instead of WritableField +class DictionaryField(serializers.WritableField): # note: maybe just Field in rest_framework 3.x instead of WritableField + def to_representation(self, obj): + return json.dumps(obj) + + def to_internal_value(self, data): + return json.loads(data) + +class ListField(serializers.WritableField): # note: maybe just Field in rest_framework 3.x instead of WritableField def to_representation(self, obj): return json.dumps(obj) @@ -35,7 +42,8 @@ class SlicePlusIdSerializer(serializers.ModelSerializer, PlusSerializerMixin): sliceInfo = serializers.SerializerMethodField("getSliceInfo") humanReadableName = serializers.SerializerMethodField("getHumanReadableName") network_ports = NetworkPortsField(required=False) - site_allocation = SiteAllocationField(required=False) + site_allocation = DictionaryField(required=False) + users = ListField(required=False) def getSliceInfo(self, slice): return slice.getSliceInfo(user=self.context['request'].user) @@ -44,13 +52,12 @@ class SlicePlusIdSerializer(serializers.ModelSerializer, PlusSerializerMixin): return str(obj) networks = serializers.PrimaryKeyRelatedField(many=True, read_only=True) -# availableNetworks = serializers.PrimaryKeyRelatedField(many=True, read_only=True, view_name='network-detail') class Meta: model = SlicePlus fields = ('humanReadableName', 'id','created','updated','enacted','name','enabled','omf_friendly','description','slice_url','site','max_slivers','service','network','mount_data_sets', 'default_image', 'default_flavor', - 'serviceClass','creator','networks','sliceInfo','network_ports','backendIcon','backendHtml','site_allocation') + 'serviceClass','creator','networks','sliceInfo','network_ports','backendIcon','backendHtml','site_allocation','users') class SlicePlusList(PlusListCreateAPIView): #generics.ListCreateAPIView): queryset = SlicePlus.objects.select_related().all() diff --git a/planetstack/core/xoslib/methods/tenantview.py b/planetstack/core/xoslib/methods/tenantview.py index 596c082..b2e0e0e 100644 --- a/planetstack/core/xoslib/methods/tenantview.py +++ b/planetstack/core/xoslib/methods/tenantview.py @@ -46,6 +46,10 @@ def getTenantViewDict(user): if not volume.private: volumes.append(volume) + site_users=[] + for auser in user.site.users.all(): + site_users.append(auser) + blessed_service_classes = [ServiceClass.objects.get(name="Best Effort")] return {"id": 0, @@ -62,6 +66,8 @@ def getTenantViewDict(user): "public_volumes": [volume.id for volume in volumes], "current_user_site_id": user.site.id, "current_user_login_base": user.site.login_base, + "current_user_site_users": [auser.id for auser in site_users], + "current_user_site_user_names": [auser.email for auser in site_users], } class TenantList(APIView): diff --git a/planetstack/core/xoslib/objects/sliceplus.py b/planetstack/core/xoslib/objects/sliceplus.py index 7ec8e27..adbc77e 100644 --- a/planetstack/core/xoslib/objects/sliceplus.py +++ b/planetstack/core/xoslib/objects/sliceplus.py @@ -1,4 +1,4 @@ -from core.models.slice import Slice +from core.models.slice import Slice, SlicePrivilege from plus import PlusObjectMixin class SlicePlus(Slice, PlusObjectMixin): @@ -34,6 +34,18 @@ class SlicePlus(Slice, PlusObjectMixin): def site_allocation(self, value): print "XXX set sitesUsed to", value + @property + def users(self): + user_ids = [] + for priv in SlicePrivilege.objects.filter(slice=self): + if not (priv.user.id in user_ids): + user_ids.append(priv.user.id) + return user_ids + + @users.setter + def users(self, value): + print "XXX set users to", value + @property def network_ports(self): # XXX this assumes there is only one network that can have ports bound diff --git a/planetstack/core/xoslib/static/js/xosTenant.js b/planetstack/core/xoslib/static/js/xosTenant.js index 8bf2442..fc510f3 100644 --- a/planetstack/core/xoslib/static/js/xosTenant.js +++ b/planetstack/core/xoslib/static/js/xosTenant.js @@ -9,7 +9,7 @@ XOSTenantSiteCollection = XOSCollection.extend( { modelName: "tenantSite", collectionName: "tenantSites", - updateFromSlice: function(slice) { + getFromSlice: function(slice) { var tenantSites = []; var id = 0; for (siteName in slice.attributes.site_allocation) { @@ -26,8 +26,31 @@ XOSTenantSiteCollection = XOSCollection.extend( { } this.set(tenantSites); }, + + putToSlice: function(slice) { + slice.attributes.site_allocation = {}; + for (index in this.models) { + model = this.models[index]; + slice.attributes.site_allocation[ model.attributes.name ] = model.attributes.allocated; + } + }, }); +XOSEditUsersView = Marionette.ItemView.extend({ + template: "#tenant-edit-users", + viewInitializers: [], + + onShow: function() { + _.each(this.viewInitializers, function(initializer) { + initializer(); + }); + }, + + templateHelpers: function() { return { detailView: this, model: this.model }; }, + + }); + + XOSTenantButtonView = Marionette.ItemView.extend({ template: "#xos-tenant-buttons-template", @@ -46,9 +69,12 @@ XOSTenantButtonView = Marionette.ItemView.extend({ }, addUserClicked: function(e) { + XOSTenantApp.editUsers(this.options.linkedView.model); }, saveClicked: function(e) { + model = this.options.linkedView.model; + model.tenantSiteCollection.putToSlice(model); this.options.linkedView.submitContinueClicked.call(this.options.linkedView, e); }, }); @@ -66,6 +92,7 @@ XOSTenantApp.addRegions({ tenantSiteList: "#tenantSiteList", tenantButtons: "#tenantButtons", tenantAddSliceInterior: "#tenant-addslice-interior", + tenantEditUsersInterior: "#tenant-edit-users-interior", }); XOSTenantApp.buildViews = function() { @@ -73,7 +100,9 @@ XOSTenantApp.buildViews = function() { tenantSummaryClass = XOSDetailView.extend({template: "#xos-detail-template", app: XOSTenantApp, - detailFields: ["serviceClass", "default_image", "default_flavor", "network_ports", "mount_data_sets"]}); + detailFields: ["serviceClass", "default_image", "default_flavor", "network_ports", "mount_data_sets"], + fieldDisplayNames: {serviceClass: "Service Level", "default_flavor": "Flavor", "default_image": "Image"}, + }); XOSTenantApp.tenantSummaryView = tenantSummaryClass; @@ -138,10 +167,14 @@ XOSTenantApp.adjustCollectionField = function(collectionName, id, fieldName, amo XOSTenantApp.addSlice = function() { var app=this; - model = new xos.slicesPlus.model({site: xos.tenant().current_user_site_id}); + model = new xos.slicesPlus.model({site: xos.tenant().current_user_site_id, + name: xos.tenant().current_user_login_base + "_"}); console.log(model); - var detailView = new XOSTenantApp.tenantAddView({model: model, collection: xos.slicesPlus}); - detailView.dialog = $("tenant-addslice-dialog"); + var detailView = new XOSTenantApp.tenantAddView({model: model, + collection: xos.slicesPlus, + noSubmitButton: true, + }); + detailView.dialog = $("#tenant-addslice-dialog"); app.tenantAddSliceInterior.show(detailView); $("#tenant-addslice-dialog").dialog({ autoOpen: false, @@ -150,6 +183,7 @@ XOSTenantApp.addSlice = function() { buttons : { "Save" : function() { var addDialog = this; + console.log("SAVE!!!"); detailView.synchronous = true; detailView.afterSave = function() { $(addDialog).dialog("close"); XOSTenantApp.navToSlice(detailView.model.id); } detailView.save(); @@ -162,6 +196,31 @@ XOSTenantApp.addSlice = function() { $("#tenant-addslice-dialog").dialog("open"); }; +XOSTenantApp.editUsers = function(model) { + var app=this; + var detailView = new XOSEditUsersView({model: model, collection: xos.slicesPlus}); + detailView.dialog = $("#tenant-edit-users-dialog"); + app.tenantEditUsersInterior.show(detailView); + $("#tenant-edit-users-dialog").dialog({ + autoOpen: false, + modal: true, + width: 640, + buttons : { + "Save" : function() { + var editDialog = this; + user_ids = all_options($("#tenant-edit-users-dialog").find(".select-picker-to")); + user_ids = user_ids.map( function(x) { return parseInt(x,10); } ); + model.attributes.users = user_ids; + $(editDialog).dialog("close"); + }, + "Cancel" : function() { + $(this).dialog("close"); + } + } + }); + $("#tenant-edit-users-dialog").dialog("open"); +}; + XOSTenantApp.deleteSlice = function(model) { var app=this; app.deleteDialog(model, function() { console.log("afterDelete"); app.viewSlice(undefined); }); @@ -181,13 +240,14 @@ XOSTenantApp.viewSlice = function(model) { tenantSummary = new XOSTenantApp.tenantSummaryView({model: model, choices: {mount_data_sets: make_choices(xos.tenant().public_volume_names, null), serviceClass: make_choices(xos.tenant().blessed_service_class_names, xos.tenant().blessed_service_classes), - default_image: make_choices(xos.tenant().blessed_image_names, xos.tenant().blessed_image_ids), - default_flavor: make_choices(xos.tenant().blessed_flavor_names, xos.tenant().blessed_flavor_ids),}, + default_image: make_choices(xos.tenant().blessed_image_names, xos.tenant().blessed_images), + default_flavor: make_choices(xos.tenant().blessed_flavor_names, xos.tenant().blessed_flavors),}, }); XOSTenantApp.tenantSummary.show(tenantSummary); tenantSites = new XOSTenantSiteCollection(); - tenantSites.updateFromSlice(model); + tenantSites.getFromSlice(model); + model.tenantSiteCollection = tenantSites; XOSTenantApp.tenantSites = tenantSites; tenantSiteList = new XOSTenantApp.tenantSiteListView({collection: tenantSites }); diff --git a/planetstack/core/xoslib/static/js/xoslib/xos-util.js b/planetstack/core/xoslib/static/js/xoslib/xos-util.js index 3fd597b..1d135f4 100644 --- a/planetstack/core/xoslib/static/js/xoslib/xos-util.js +++ b/planetstack/core/xoslib/static/js/xoslib/xos-util.js @@ -79,3 +79,35 @@ function validateField(validatorName, value, obj) { return true; } + +function array_diff(a1, a2) +{ + var a=[], diff=[]; + for(var i=0;i <% args = arguments; %> <% _.each(detailFields, function(fieldName) { %> - <%= fieldNameToHumanReadable(fieldName) %>: + <%= fieldName in fieldDisplayNames ? fieldDisplayNames[fieldName] : fieldNameToHumanReadable(fieldName) %>: <% readOnly = $.inArray(fieldName, model.readOnlyFields)>=0 ? " readonly" : ""; %> <% if (fieldName in choices) { %> <%= choicesToSelect(fieldName, model.attributes[fieldName], choices[fieldName]) %> @@ -165,7 +165,7 @@ <%= idToSelect(fieldName, model.attributes[fieldName], foreignFields[fieldName], "humanReadableName", readOnly) %> <% } else if (inputType[fieldName] == "spinner") { %> - <%= xosSpinnerTemplate({id: "picker_" + fieldName, fieldName: fieldName, value: model.attributes[fieldName]}) %> + <%= xosSpinnerTemplate({id: "spinner_" + fieldName, fieldName: fieldName, value: model.attributes[fieldName]}) %> <% } else if (inputType[fieldName] == "checkbox") { %> <%= readOnly %>> <% } else if (inputType[fieldName] == "picker") { %> -- 2.43.0