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>

+