REST API for managing CORD users
diff --git a/xos/cord/models.py b/xos/cord/models.py
index b3f7aa3..3fc970c 100644
--- a/xos/cord/models.py
+++ b/xos/cord/models.py
@@ -209,7 +209,8 @@
                           "url_filter_rules": "allow all",
                           "url_filter_level": "PG",
                           "cdn_enable": False,
-                          "sliver_id": None}
+                          "sliver_id": None,
+                          "users": []}
 
     def __init__(self, *args, **kwargs):
         super(VCPETenant, self).__init__(*args, **kwargs)
@@ -346,14 +347,57 @@
 
     @property
     def users(self):
-        return [ {"name": "mom", "id": 1, "role": "admin"},
-                 {"name": "dad", "id": 2, "role": "admin"},
-                 {"name": "kid1", "id": 3, "role": "user"},
-                 {"name": "kid2", "id": 4, "role": "user"} ]
+        return self.get_attribute("users", self.default_attributes["users"])
 
     @users.setter
     def users(self, value):
-        pass
+        self.set_attribute("users", value)
+
+    def find_user(self, uid):
+        uid = int(uid)
+        for user in self.users:
+            if user["id"] == uid:
+                return user
+        return None
+
+    def update_user(self, uid, **kwargs):
+        # kwargs may be "level" or "mac"
+        #    Setting one of these to None will cause None to be stored in the db
+        uid = int(uid)
+        users = self.users
+        for user in users:
+            if user["id"] == uid:
+                for arg in kwargs.keys():
+                    user[arg] = kwargs[arg]
+                    self.users = users
+                return
+        raise ValueError("User %d not found" % uid)
+
+    def create_user(self, **kwargs):
+        uids = [x["id"] for x in self.users]
+        if uids:
+            uid = max(uids)+1
+        else:
+            uid = 0
+        newuser = kwargs.copy()
+        newuser["id"] = uid
+
+        users = self.users
+        users.append(newuser)
+        self.users = users
+
+        return newuser
+
+    def delete_user(self, uid):
+        uid = int(uid)
+        users = self.users
+        for user in users:
+            if user["id"]==uid:
+                users.remove(user)
+                self.users = users
+                return
+
+        raise ValueError("Users %d not found" % uid)
 
     @property
     def services(self):
diff --git a/xos/core/xoslib/methods/cordsubscriber.py b/xos/core/xoslib/methods/cordsubscriber.py
index f351552..55af19a 100644
--- a/xos/core/xoslib/methods/cordsubscriber.py
+++ b/xos/core/xoslib/methods/cordsubscriber.py
@@ -13,6 +13,7 @@
 from plus import PlusSerializerMixin
 from django.shortcuts import get_object_or_404
 from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
+from xos.exceptions import *
 import json
 
 if hasattr(serializers, "ReadOnlyField"):
@@ -98,16 +99,28 @@
     queryset = CordSubscriber.get_tenant_objects().select_related().all()
     serializer_class = CordSubscriberIdSerializer
 
+    def get_vcpe(self):
+        subscriber = self.get_object()
+        if not subscriber.vcpe:
+            raise XOSMissingField("vCPE object is not present for subscriber")
+        return subscriber.vcpe
+
     @classmethod
     def get_urlpatterns(self):
         patterns = super(CordSubscriberViewSet, self).get_urlpatterns()
         patterns.append( self.detail_url("url_filtering/$", {"get": "get_url_filtering"}, "url_filtering") )
-        patterns.append( self.detail_url("url_filtering/(?P<level>[a-zA-Z0-9\-]+)/$", {"get": "set_url_filtering"}, "url_filtering") )
-        patterns.append( self.detail_url("users/$", {"get": "get_users"}, "users") )
+        patterns.append( self.detail_url("url_filtering/(?P<level>[a-zA-Z0-9\-]+)/$", {"put": "set_url_filtering"}, "url_filtering") )
         patterns.append( self.detail_url("services/$", {"get": "get_services"}, "services") )
         patterns.append( self.detail_url("services/(?P<service>[a-zA-Z0-9\-]+)/$", {"get": "get_service"}, "get_service") )
-        patterns.append( self.detail_url("services/(?P<service>[a-zA-Z0-9\-]+)/true/$", {"get": "enable_service"}, "enable_service") )
-        patterns.append( self.detail_url("services/(?P<service>[a-zA-Z0-9\-]+)/false/$", {"get": "disable_service"}, "disable_service") )
+        patterns.append( self.detail_url("services/(?P<service>[a-zA-Z0-9\-]+)/true/$", {"put": "enable_service"}, "enable_service") )
+        patterns.append( self.detail_url("services/(?P<service>[a-zA-Z0-9\-]+)/false/$", {"put": "disable_service"}, "disable_service") )
+
+        patterns.append( self.detail_url("users/$", {"get": "get_users", "post": "create_user"}, "users") )
+        patterns.append( self.detail_url("users/clearusers/$", {"get": "clear_users", "put": "clear_users", "post": "clear_users"}, "clearusers") )
+        patterns.append( self.detail_url("users/newuser/$", {"put": "create_user", "post": "create_user"}, "newuser") )
+        patterns.append( self.detail_url("users/(?P<uid>[0-9\-]+)/$", {"delete": "delete_user"}, "user") )
+        patterns.append( self.detail_url("users/(?P<uid>[0-9\-]+)/url_filtering/$", {"get": "get_user_level"}, "user_level") )
+        patterns.append( self.detail_url("users/(?P<uid>[0-9\-]+)/url_filtering/(?P<level>[a-zA-Z0-9\-]+)/$", {"put": "set_user_level"}, "set_user_level") )
 
         return patterns
 
@@ -132,6 +145,53 @@
         subscriber = self.get_object()
         return Response({"users": subscriber.users})
 
+    def get_user_level(self, request, pk=None, uid=None):
+        vcpe = self.get_vcpe()
+        user = vcpe.find_user(uid)
+        if user and user.get("level", None):
+            level = user["level"]
+        else:
+            level = self.get_object().url_filter_level
+
+        return Response( {"id": uid, "level": level} )
+
+    def set_user_level(self, request, pk=None, uid=None, level=None):
+        vcpe = self.get_vcpe()
+        vcpe.update_user(uid, level=level)
+        vcpe.save()
+        return self.get_user_level(request, pk, uid)
+
+    def create_user(self, request, pk=None):
+        vcpe = self.get_vcpe()
+
+        data = request.DATA
+        name = data.get("name",None)
+        mac = data.get("mac",None)
+        if (not name):
+             raise XOSMissingField("name must be specified when creating user")
+        if (not mac):
+             raise XOSMissingField("mac must be specified when creating user")
+
+        newuser = vcpe.create_user(name=name, mac=mac)
+        vcpe.save()
+
+        return Response(newuser)
+
+    def delete_user(self, request, pk=None, uid=None):
+        vcpe = self.get_vcpe()
+
+        vcpe.delete_user(uid)
+        vcpe.save()
+
+        return Response( {"id": uid, "deleted": True} )
+
+    def clear_users(self, request, pk=None):
+        vcpe = self.get_vcpe()
+        vcpe.users = []
+        vcpe.save()
+
+        return Response( "Okay" )
+
     def get_services(self, request, pk=None):
         subscriber = self.get_object()
         return Response(subscriber.services)