cord subscriber view, wip
diff --git a/xos/core/xoslib/dashboards/cord.html b/xos/core/xoslib/dashboards/cord.html
new file mode 100644
index 0000000..368f264
--- /dev/null
+++ b/xos/core/xoslib/dashboards/cord.html
@@ -0,0 +1,70 @@
+<script src="{{ STATIC_URL }}/js/vendor/underscore-min.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.syphon.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.wreqr.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.babysitter.js"></script>
+<script src="{{ STATIC_URL }}/js/vendor/backbone.marionette.js"></script>
+
+<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
+<link rel="stylesheet" type="text/css" href="{% static 'css/xosAdminDashboard.css' %}" media="all" >
+<link rel="stylesheet" type="text/css" href="{% static 'css/xosAdminSite.css' %}" media="all" >
+
+<script src="{{ STATIC_URL }}/js/xoslib/xos-util.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-defaults.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-validators.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xos-backbone.js"></script>
+<script src="{{ STATIC_URL }}/js/xoslib/xosHelper.js"></script>
+<script src="{{ STATIC_URL }}/js/picker.js"></script>
+<script src="{{ STATIC_URL }}/js/xosCord.js"></script>
+
+<script type="text/template" id="xos-log-template">
+ <tr id="<%= logMessageId %>" class="xos-log xos-<%= statusclass %>">
+ <td><%= what %><br>
+ <%= status %> <%= statusText %>
+ </td>
+ </tr>
+</script>
+
+<div id="xos-confirm-dialog" title="Confirmation Required">
+ Are you sure about this?
+</div>
+
+<div id="xos-error-dialog" title="Error Message">
+</div>
+
+<div id="xos-addchild-dialog" title="Add Child">
+<div id="xos-addchild-detail"></div>
+</div>
+
+<div id="contentPanel">
+<div id="contentTitle">
+</div>
+<div id="contentButtonPanel">
+<!-- This is really a convoluted way of handling the buttons. The onClick
+ handler for this Save button tells the save button inside the detail
+ form to click itself.
+-->
+
+<div id="rightButtonPanel"></div>
+
+<div class="box" id="logPanel">
+<table id="logTable">
+<tbody>
+</tbody>
+</table> <!-- end logTable -->
+</div> <!-- end logPanel -->
+</div> <!-- end contentButtonPanel -->
+<div id="contentInner">
+<div id="tabs">
+</div>
+<div id="detail"></div>
+<div id="linkedObjs1"></div>
+<div id="linkedObjs2"></div>
+<div id="linkedObjs3"></div>
+<div id="linkedObjs4"></div>
+</div> <!-- end contentInner -->
+</div> <!-- end contentPanel -->
+
+{% include 'xosAdmin.html' %}
+{% include 'xosCordSubscriber.html' %}
+
diff --git a/xos/core/xoslib/methods/cordsubscriber.py b/xos/core/xoslib/methods/cordsubscriber.py
new file mode 100644
index 0000000..f724c1e
--- /dev/null
+++ b/xos/core/xoslib/methods/cordsubscriber.py
@@ -0,0 +1,52 @@
+from rest_framework.decorators import api_view
+from rest_framework.response import Response
+from rest_framework.reverse import reverse
+from rest_framework import serializers
+from rest_framework import generics
+from core.models import *
+from django.forms import widgets
+from cord.models import VOLTTenant
+from core.xoslib.objects.cordsubscriber import CordSubscriber
+from plus import PlusSerializerMixin
+from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+
+if hasattr(serializers, "ReadOnlyField"):
+ # rest_framework 3.x
+ IdField = serializers.ReadOnlyField
+else:
+ # rest_framework 2.x
+ IdField = serializers.Field
+
+class CordSubscriberIdSerializer(serializers.ModelSerializer, PlusSerializerMixin):
+ id = IdField()
+ vcpe_id = IdField()
+ sliver_id = IdField()
+ firewall_enable = serializers.BooleanField()
+
+ humanReadableName = serializers.SerializerMethodField("getHumanReadableName")
+
+ class Meta:
+ model = CordSubscriber
+ fields = ('humanReadableName', 'id',
+ 'service_specific_id',
+ 'vcpe_id', 'sliver_id', 'firewall_enable')
+
+
+ def getHumanReadableName(self, obj):
+ return str(obj)
+
+class CordSubscriberList(XOSListCreateAPIView):
+ queryset = CordSubscriber.get_tenant_objects().select_related().all()
+ serializer_class = CordSubscriberIdSerializer
+
+ method_kind = "list"
+ method_name = "cordsubscriber"
+
+class CordSubscriberDetail(XOSRetrieveUpdateDestroyAPIView):
+ queryset = CordSubscriber.get_tenant_objects().select_related().all()
+ serializer_class = CordSubscriberIdSerializer
+
+ method_kind = "detail"
+ method_name = "cordsubscriber"
+
+
diff --git a/xos/core/xoslib/objects/cordsubscriber.py b/xos/core/xoslib/objects/cordsubscriber.py
new file mode 100644
index 0000000..d483cac
--- /dev/null
+++ b/xos/core/xoslib/objects/cordsubscriber.py
@@ -0,0 +1,52 @@
+from core.models import Slice, SlicePrivilege, SliceRole, Sliver, Site, Node, User
+from cord.models import VOLTTenant
+from plus import PlusObjectMixin
+from operator import itemgetter, attrgetter
+from rest_framework.exceptions import APIException
+
+class CordSubscriber(VOLTTenant, PlusObjectMixin):
+ class Meta:
+ proxy = True
+
+ def __init__(self, *args, **kwargs):
+ super(VOLTTenant, self).__init__(*args, **kwargs)
+
+ @property
+ def vcpe_id(self):
+ if self.vcpe:
+ return self.vcpe.id
+ else:
+ return None
+
+ @vcpe_id.setter
+ def vcpe_id(self, value):
+ pass
+
+ @property
+ def sliver_id(self):
+ if self.vcpe and self.vcpe.sliver:
+ return self.vcpe.sliver.id
+ else:
+ return None
+
+ @sliver_id.setter
+ def sliver_id(self, value):
+ pass
+
+ @property
+ def firewall_enable(self):
+ if self.vcpe:
+ return self.vcpe.firewall_enable
+ else:
+ return None
+
+ @firewall_enable.setter
+ def firewall_enable(self, value):
+ if self.vcpe:
+ self.vcpe.firewall_enable = value
+ # TODO: save it
+
+
+
+
+
diff --git a/xos/core/xoslib/static/js/xosCord.js b/xos/core/xoslib/static/js/xosCord.js
new file mode 100644
index 0000000..96d95f1
--- /dev/null
+++ b/xos/core/xoslib/static/js/xosCord.js
@@ -0,0 +1,195 @@
+OBJS = ['cordSubscriber', ]
+
+CordAdminApp = new XOSApplication({
+ logTableId: "#logTable",
+ statusMsgId: "#statusMsg",
+ hideTabsByDefault: true
+});
+
+CordAdminApp.addRegions({
+ navigation: "#navigationPanel",
+
+ detail: "#detail",
+ linkedObjs1: "#linkedObjs1",
+ linkedObjs2: "#linkedObjs2",
+ linkedObjs3: "#linkedObjs3",
+ linkedObjs4: "#linkedObjs4",
+
+ addChildDetail: "#xos-addchild-detail",
+
+ rightButtonPanel: "#rightButtonPanel"
+});
+
+CordAdminApp.navigate = function(what, modelName, modelId) {
+ collection_name = modelName + "s";
+ if (what=="list") {
+ CordAdminApp.Router.navigate(collection_name, {trigger: true})
+ } else if (what=="detail") {
+ CordAdminApp.Router.navigate(collection_name + "/" + modelId, {trigger: true})
+ } else if (what=="add") {
+ CordAdminApp.Router.navigate("add" + firstCharUpper(modelName), {trigger: true, force: true})
+ }
+}
+
+CordAdminApp.buildViews = function() {
+ genericAddChildClass = XOSDetailView.extend({template: "#xos-add-template",
+ app: CordAdminApp});
+ CordAdminApp["genericAddChildView"] = genericAddChildClass;
+
+ genericDetailClass = XOSDetailView.extend({template: "#xos-detail-template",
+ app: CordAdminApp});
+ CordAdminApp["genericDetailView"] = genericDetailClass;
+
+ genericItemViewClass = XOSItemView.extend({template: "#xos-listitem-template",
+ app: CordAdminApp});
+ CordAdminApp["genericItemView"] = genericItemViewClass;
+
+ //genericListViewClass = XOSListView.extend({template: "#xos-list-template",
+ // app: CordAdminApp});
+
+ genericListViewClass = XOSDataTableView.extend({template: "#xos-list-template", app: CordAdminApp});
+ CordAdminApp["genericListView"] = genericListViewClass;
+
+ for (var index in OBJS) {
+ name = OBJS[index];
+ tr_template = '#xosAdmin-' + name + '-listitem-template';
+ table_template = '#xosAdmin-' + name + '-list-template';
+ detail_template = '#xosAdmin-' + name + '-detail-template';
+ add_child_template = '#xosAdmin-' + name + '-add-child-template';
+ collection_name = name + "s";
+ region_name = name + "List";
+
+ if (window["XOSDetailView_" + name]) {
+ detailClass = window["XOSDetailView_" + name].extend({template: "#xos-detail-template",
+ app: CordAdminApp});
+ } else {
+ detailClass = genericDetailClass;
+ }
+ if ($(detail_template).length) {
+ detailClass = detailClass.extend({
+ template: detail_template,
+ });
+ }
+ CordAdminApp[collection_name + "DetailView"] = detailClass;
+
+ if (window["XOSDetailView_" + name]) {
+ addClass = window["XOSDetailView_" + name].extend({template: "#xos-add-template",
+ app: CordAdminApp});
+ } else {
+ addClass = genericAddChildClass;
+ }
+ if ($(add_child_template).length) {
+ addClass = detailClass.extend({
+ template: add_child_template,
+ });
+ }
+ CordAdminApp[collection_name + "AddChildView"] = addClass;
+
+ if ($(tr_template).length) {
+ itemViewClass = XOSItemView.extend({
+ template: tr_template,
+ app: CordAdminApp,
+ });
+ } else {
+ itemViewClass = genericItemViewClass;
+ }
+
+ if ($(table_template).length) {
+ listViewClass = XOSListView.extend({
+ childView: itemViewClass,
+ template: table_template,
+ collection: xos[collection_name],
+ title: name + "s",
+ app: CordAdminApp,
+ });
+ } else {
+ listViewClass = genericListViewClass.extend( { childView: itemViewClass,
+ collection: xos[collection_name],
+ title: name + "s",
+ } );
+ }
+
+ CordAdminApp[collection_name + "ListView"] = listViewClass;
+
+ xos[collection_name].fetch(); //startPolling();
+ }
+};
+
+CordAdminApp.initRouter = function() {
+ router = XOSRouter;
+ var api = {};
+ var routes = {};
+
+ for (var index in OBJS) {
+ name = OBJS[index];
+ collection_name = name + "s";
+ nav_url = collection_name;
+ api_command = "list" + firstCharUpper(collection_name);
+ listViewName = collection_name + "ListView";
+ detailViewName = collection_name + "DetailView";
+ addChildViewName = collection_name + "AddChildView";
+
+ api[api_command] = CordAdminApp.createListHandler(listViewName, collection_name, "detail", collection_name);
+ routes[nav_url] = api_command;
+
+ nav_url = collection_name + "/:id";
+ api_command = "detail" + firstCharUpper(collection_name);
+
+ api[api_command] = CordAdminApp.createDetailHandler(detailViewName, collection_name, "detail", name);
+ routes[nav_url] = api_command;
+
+ nav_url = "add" + firstCharUpper(name);
+ api_command = "add" + firstCharUpper(name);
+ api[api_command] = CordAdminApp.createAddHandler(detailViewName, collection_name, "detail", name);
+ routes[nav_url] = api_command;
+
+ nav_url = "addChild" + firstCharUpper(name) + "/:parentModel/:parentField/:parentId";
+ api_command = "addChild" + firstCharUpper(name);
+ api[api_command] = CordAdminApp.createAddChildHandler(addChildViewName, collection_name);
+ routes[nav_url] = api_command;
+
+ nav_url = "delete" + firstCharUpper(name) + "/:id";
+ api_command = "delete" + firstCharUpper(name);
+ api[api_command] = CordAdminApp.createDeleteHandler(collection_name, name);
+ routes[nav_url] = api_command;
+ };
+
+ routes["*part"] = "listCordSubscribers";
+
+ CordAdminApp.Router = new router({ appRoutes: routes, controller: api });
+};
+
+CordAdminApp.startNavigation = function() {
+ Backbone.history.start();
+ CordAdminApp.navigationStarted = true;
+}
+
+CordAdminApp.collectionLoadChange = function() {
+ stats = xos.getCollectionStatus();
+
+ if (!CordAdminApp.navigationStarted) {
+ if (stats["isLoaded"] + stats["failedLoad"] >= stats["startedLoad"]) {
+ CordAdminApp.startNavigation();
+ } else {
+ $("#detail").html("<h3>Loading...</h3><div id='xos-startup-progress'></div>");
+ $("#xos-startup-progress").progressbar({value: stats["completedLoad"], max: stats["startedLoad"]});
+ }
+ }
+};
+
+CordAdminApp.on("start", function() {
+ CordAdminApp.buildViews();
+
+ CordAdminApp.initRouter();
+
+ // fire it once to initially show the progress bar
+ CordAdminApp.collectionLoadChange();
+
+ // fire it each time the collection load status is updated
+ Backbone.on("xoslib:collectionLoadChange", CordAdminApp.collectionLoadChange);
+});
+
+$(document).ready(function(){
+ CordAdminApp.start();
+});
+
diff --git a/xos/core/xoslib/static/js/xoslib/xos-backbone.js b/xos/core/xoslib/static/js/xoslib/xos-backbone.js
index a459458..2e9daf1 100644
--- a/xos/core/xoslib/static/js/xoslib/xos-backbone.js
+++ b/xos/core/xoslib/static/js/xoslib/xos-backbone.js
@@ -34,7 +34,9 @@
SLICEPLUS_API = XOSLIB_BASE + "/slicesplus/";
TENANTVIEW_API = XOSLIB_BASE + "/tenantview/";
- HPCVIEW_API = XOSLIB_BASE + "/hpcview";
+ HPCVIEW_API = XOSLIB_BASE + "/hpcview/";
+
+ CORDSUBSCRIBER_API = XOSLIB_BASE + "/cordsubscriber/";
XOSModel = Backbone.Model.extend({
relatedCollections: [],
@@ -725,6 +727,13 @@
detailFields: [],
});
+ define_model(this, {urlRoot: CORDSUBSCRIBER_API,
+ modelName: "cordSubscriber",
+ listFields: ["id"],
+ detailFields: ["id", "service_specific_id", "vcpe_id", "firewall_enable"],
+ inputType: {"firewall_enable": "checkbox"},
+ });
+
/* by default, have slicePlus only fetch the slices the user can see */
this.slicesPlus.currentUserCanSee = true;
diff --git a/xos/core/xoslib/templates/xosCordSubscriber.html b/xos/core/xoslib/templates/xosCordSubscriber.html
new file mode 100644
index 0000000..7d86cf7
--- /dev/null
+++ b/xos/core/xoslib/templates/xosCordSubscriber.html
@@ -0,0 +1,16 @@
+<script type="text/template" id="xos-cord-subscriber-template">
+ <h3 class="xos-detail-title">CORD Subscriber</h3>
+ <form>
+ <table class="xos-detail-table">
+ <tr><td class="xos-label-cell">vOLT</td></tr>
+ <tr><td class="xos-label-cell">ID:</td><td><%= vOLT_id %></td></tr>
+ <tr><td class="xos-label-cell">internal ID:</td><td><%= vOLT_service_specific_id %></td></tr>
+ <tr><td class="xos-label-cell">vCPE</td></tr>
+ <tr><td class="xos-label-cell">ID:</td><td><%= vCPE_id %></td></tr>
+ <tr><td class="xos-label-cell">vBNG</td></tr>
+ <tr><td class="xos-label-cell">ID:</td><td></td></tr>
+ <tr><td class="xos-label-cell">Routeable Subnet:</td><td></td></tr>
+ </table>
+ </form>
+</script>
+