Scott Baker | fb9544a | 2016-03-25 10:55:03 -0700 | [diff] [blame] | 1 | from rest_framework.decorators import api_view |
| 2 | from rest_framework.response import Response |
| 3 | from rest_framework.reverse import reverse |
| 4 | from rest_framework import serializers |
| 5 | from rest_framework import generics |
| 6 | from rest_framework import viewsets |
| 7 | from rest_framework.decorators import detail_route, list_route |
| 8 | from rest_framework.views import APIView |
| 9 | from core.models import * |
| 10 | from django.forms import widgets |
| 11 | from django.conf.urls import patterns, url |
| 12 | from services.cord.models import VOLTTenant, VBNGTenant, CordSubscriberRoot |
| 13 | from core.xoslib.objects.cordsubscriber import CordSubscriber |
Scott Baker | d9d55f2 | 2016-03-25 13:33:11 -0700 | [diff] [blame] | 14 | from api.xosapi_helpers import PlusSerializerMixin, XOSViewSet |
Scott Baker | fb9544a | 2016-03-25 10:55:03 -0700 | [diff] [blame] | 15 | from django.shortcuts import get_object_or_404 |
| 16 | from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied |
| 17 | from xos.exceptions import * |
| 18 | import json |
| 19 | import subprocess |
| 20 | |
| 21 | if hasattr(serializers, "ReadOnlyField"): |
| 22 | # rest_framework 3.x |
| 23 | ReadOnlyField = serializers.ReadOnlyField |
| 24 | else: |
| 25 | # rest_framework 2.x |
| 26 | ReadOnlyField = serializers.Field |
| 27 | |
| 28 | class CordSubscriberIdSerializer(serializers.ModelSerializer, PlusSerializerMixin): |
| 29 | id = ReadOnlyField() |
| 30 | service_specific_id = ReadOnlyField() |
| 31 | vlan_id = ReadOnlyField() # XXX remove this |
| 32 | c_tag = ReadOnlyField() |
| 33 | s_tag = ReadOnlyField() |
| 34 | vcpe_id = ReadOnlyField() |
| 35 | instance = ReadOnlyField() |
| 36 | image = ReadOnlyField() |
| 37 | vbng_id = ReadOnlyField() |
| 38 | firewall_enable = serializers.BooleanField() |
| 39 | firewall_rules = serializers.CharField() |
| 40 | url_filter_enable = serializers.BooleanField() |
| 41 | url_filter_rules = serializers.CharField() |
| 42 | url_filter_level = serializers.CharField(required=False) |
| 43 | cdn_enable = serializers.BooleanField() |
| 44 | instance_name = ReadOnlyField() |
| 45 | image_name = ReadOnlyField() |
| 46 | routeable_subnet = serializers.CharField(required=False) |
| 47 | ssh_command = ReadOnlyField() |
| 48 | bbs_account = ReadOnlyField() |
| 49 | |
| 50 | wan_container_ip = ReadOnlyField() |
| 51 | uplink_speed = serializers.CharField(required=False) |
| 52 | downlink_speed = serializers.CharField(required=False) |
| 53 | status = serializers.CharField() |
| 54 | enable_uverse = serializers.BooleanField() |
| 55 | |
| 56 | lan_ip = ReadOnlyField() |
| 57 | wan_ip = ReadOnlyField() |
| 58 | nat_ip = ReadOnlyField() |
| 59 | private_ip = ReadOnlyField() |
| 60 | |
| 61 | wan_mac = ReadOnlyField() |
| 62 | |
| 63 | vcpe_synced = serializers.BooleanField() |
| 64 | |
| 65 | humanReadableName = serializers.SerializerMethodField("getHumanReadableName") |
| 66 | |
| 67 | class Meta: |
| 68 | model = CordSubscriber |
| 69 | fields = ('humanReadableName', 'id', |
| 70 | 'service_specific_id', 'vlan_id', 's_tag', 'c_tag', |
| 71 | 'vcpe_id', 'instance', 'instance_name', 'image', 'image_name', |
| 72 | 'firewall_enable', 'firewall_rules', |
| 73 | 'url_filter_enable', 'url_filter_rules', 'url_filter_level', |
| 74 | 'bbs_account', |
| 75 | 'ssh_command', |
| 76 | 'vcpe_synced', |
| 77 | 'cdn_enable', 'vbng_id', 'routeable_subnet', 'nat_ip', 'lan_ip', 'wan_ip', 'private_ip', 'wan_mac', |
| 78 | 'wan_container_ip', |
| 79 | 'uplink_speed', 'downlink_speed', 'status', 'enable_uverse') |
| 80 | |
| 81 | |
| 82 | def getHumanReadableName(self, obj): |
| 83 | return obj.__unicode__() |
| 84 | |
| 85 | #------------------------------------------------------------------------------ |
| 86 | # The "old" API |
| 87 | # This is used by the xoslib-based GUI |
| 88 | #------------------------------------------------------------------------------ |
| 89 | |
| 90 | class CordSubscriberList(XOSListCreateAPIView): |
| 91 | queryset = CordSubscriber.get_tenant_objects().select_related().all() |
| 92 | serializer_class = CordSubscriberIdSerializer |
| 93 | |
| 94 | method_kind = "list" |
| 95 | method_name = "cordsubscriber" |
| 96 | |
| 97 | class CordSubscriberDetail(XOSRetrieveUpdateDestroyAPIView): |
| 98 | queryset = CordSubscriber.get_tenant_objects().select_related().all() |
| 99 | serializer_class = CordSubscriberIdSerializer |
| 100 | |
| 101 | method_kind = "detail" |
| 102 | method_name = "cordsubscriber" |
| 103 | |
Scott Baker | fb9544a | 2016-03-25 10:55:03 -0700 | [diff] [blame] | 104 | |
| 105 | #------------------------------------------------------------------------------ |
| 106 | # The "new" API with many more REST endpoints. |
| 107 | # This is for integration with with the subscriber GUI |
| 108 | #------------------------------------------------------------------------------ |
| 109 | |
| 110 | class CordSubscriberViewSet(XOSViewSet): |
| 111 | base_name = "subscriber" |
Scott Baker | d9d55f2 | 2016-03-25 13:33:11 -0700 | [diff] [blame] | 112 | method_name = "subscriber" |
Scott Baker | fb9544a | 2016-03-25 10:55:03 -0700 | [diff] [blame] | 113 | method_kind = "viewset" |
| 114 | queryset = CordSubscriber.get_tenant_objects().select_related().all() |
| 115 | serializer_class = CordSubscriberIdSerializer |
| 116 | |
| 117 | def get_vcpe(self): |
| 118 | subscriber = self.get_object() |
| 119 | if not subscriber.vcpe: |
| 120 | raise XOSMissingField("vCPE object is not present for subscriber") |
| 121 | return subscriber.vcpe |
| 122 | |
| 123 | @classmethod |
Scott Baker | bca3a1b | 2016-03-28 13:22:10 -0700 | [diff] [blame^] | 124 | def get_urlpatterns(self, api_path="^"): |
Scott Baker | d9d55f2 | 2016-03-25 13:33:11 -0700 | [diff] [blame] | 125 | patterns = super(CordSubscriberViewSet, self).get_urlpatterns(api_path=api_path) |
Scott Baker | fb9544a | 2016-03-25 10:55:03 -0700 | [diff] [blame] | 126 | patterns.append( self.detail_url("vcpe_synced/$", {"get": "get_vcpe_synced"}, "vcpe_synced") ) |
| 127 | patterns.append( self.detail_url("url_filter/$", {"get": "get_url_filter"}, "url_filter") ) |
| 128 | patterns.append( self.detail_url("url_filter/(?P<level>[a-zA-Z0-9\-_]+)/$", {"put": "set_url_filter"}, "url_filter") ) |
| 129 | patterns.append( self.detail_url("services/$", {"get": "get_services"}, "services") ) |
| 130 | patterns.append( self.detail_url("services/(?P<service>[a-zA-Z0-9\-_]+)/$", {"get": "get_service"}, "get_service") ) |
| 131 | patterns.append( self.detail_url("services/(?P<service>[a-zA-Z0-9\-_]+)/true/$", {"put": "enable_service"}, "enable_service") ) |
| 132 | patterns.append( self.detail_url("services/(?P<service>[a-zA-Z0-9\-_]+)/false/$", {"put": "disable_service"}, "disable_service") ) |
| 133 | |
| 134 | patterns.append( self.detail_url("users/$", {"get": "get_users", "post": "create_user"}, "users") ) |
| 135 | patterns.append( self.detail_url("users/clearusers/$", {"get": "clear_users", "put": "clear_users", "post": "clear_users"}, "clearusers") ) |
| 136 | patterns.append( self.detail_url("users/newuser/$", {"put": "create_user", "post": "create_user"}, "newuser") ) |
| 137 | patterns.append( self.detail_url("users/(?P<uid>[0-9\-]+)/$", {"delete": "delete_user"}, "user") ) |
| 138 | patterns.append( self.detail_url("users/(?P<uid>[0-9\-]+)/url_filter/$", {"get": "get_user_level"}, "user_level") ) |
| 139 | patterns.append( self.detail_url("users/(?P<uid>[0-9\-]+)/url_filter/(?P<level>[a-zA-Z0-9\-_]+)/$", {"put": "set_user_level"}, "set_user_level") ) |
| 140 | |
| 141 | patterns.append( self.detail_url("bbsdump/$", {"get": "get_bbsdump"}, "bbsdump") ) |
| 142 | |
Scott Baker | d9d55f2 | 2016-03-25 13:33:11 -0700 | [diff] [blame] | 143 | patterns.append( url(self.api_path + "subidlookup/(?P<ssid>[0-9\-]+)/$", self.as_view({"get": "ssiddetail"}), name="ssiddetail") ) |
| 144 | patterns.append( url(self.api_path + "subidlookup/$", self.as_view({"get": "ssidlist"}), name="ssidlist") ) |
Scott Baker | fb9544a | 2016-03-25 10:55:03 -0700 | [diff] [blame] | 145 | |
| 146 | return patterns |
| 147 | |
| 148 | def list(self, request): |
| 149 | object_list = self.filter_queryset(self.get_queryset()) |
| 150 | |
| 151 | serializer = self.get_serializer(object_list, many=True) |
| 152 | |
| 153 | return Response({"subscribers": serializer.data}) |
| 154 | |
| 155 | def get_vcpe_synced(self, request, pk=None): |
| 156 | subscriber = self.get_object() |
| 157 | return Response({"vcpe_synced": subscriber.vcpe_synced}) |
| 158 | |
| 159 | def get_url_filter(self, request, pk=None): |
| 160 | subscriber = self.get_object() |
| 161 | return Response({"level": subscriber.url_filter_level}) |
| 162 | |
| 163 | def set_url_filter(self, request, pk=None, level=None): |
| 164 | subscriber = self.get_object() |
| 165 | subscriber.url_filter_level = level |
| 166 | subscriber.save() |
| 167 | return Response({"level": subscriber.url_filter_level}) |
| 168 | |
| 169 | def get_users(self, request, pk=None): |
| 170 | subscriber = self.get_object() |
| 171 | return Response(subscriber.users) |
| 172 | |
| 173 | def get_user_level(self, request, pk=None, uid=None): |
| 174 | subscriber = self.get_object() |
| 175 | user = subscriber.find_user(uid) |
| 176 | if user and user.get("level", None): |
| 177 | level = user["level"] |
| 178 | else: |
| 179 | level = self.get_object().url_filter_level |
| 180 | |
| 181 | return Response( {"id": uid, "level": level} ) |
| 182 | |
| 183 | def set_user_level(self, request, pk=None, uid=None, level=None): |
| 184 | subscriber = self.get_object() |
| 185 | subscriber.update_user(uid, level=level) |
| 186 | subscriber.save() |
| 187 | return self.get_user_level(request, pk, uid) |
| 188 | |
| 189 | def create_user(self, request, pk=None): |
| 190 | data = request.DATA |
| 191 | name = data.get("name",None) |
| 192 | mac = data.get("mac",None) |
| 193 | if (not name): |
| 194 | raise XOSMissingField("name must be specified when creating user") |
| 195 | if (not mac): |
| 196 | raise XOSMissingField("mac must be specified when creating user") |
| 197 | |
| 198 | subscriber = self.get_object() |
| 199 | newuser = subscriber.create_user(name=name, mac=mac) |
| 200 | subscriber.save() |
| 201 | |
| 202 | return Response(newuser) |
| 203 | |
| 204 | def delete_user(self, request, pk=None, uid=None): |
| 205 | subscriber = self.get_object() |
| 206 | subscriber.delete_user(uid) |
| 207 | subscriber.save() |
| 208 | |
| 209 | return Response( {"id": uid, "deleted": True} ) |
| 210 | |
| 211 | def clear_users(self, request, pk=None): |
| 212 | subscriber = self.get_object() |
| 213 | subscriber.users = [] |
| 214 | subscriber.save() |
| 215 | |
| 216 | return Response( "Okay" ) |
| 217 | |
| 218 | def get_services(self, request, pk=None): |
| 219 | subscriber = self.get_object() |
| 220 | return Response(subscriber.services) |
| 221 | |
| 222 | def get_service(self, request, pk=None, service=None): |
| 223 | service_attr = service+"_enable" |
| 224 | subscriber = self.get_object() |
| 225 | return Response({service: getattr(subscriber, service_attr)}) |
| 226 | |
| 227 | def enable_service(self, request, pk=None, service=None): |
| 228 | service_attr = service+"_enable" |
| 229 | subscriber = self.get_object() |
| 230 | setattr(subscriber, service_attr, True) |
| 231 | subscriber.save() |
| 232 | return Response({service: getattr(subscriber, service_attr)}) |
| 233 | |
| 234 | def disable_service(self, request, pk=None, service=None): |
| 235 | service_attr = service+"_enable" |
| 236 | subscriber = self.get_object() |
| 237 | setattr(subscriber, service_attr, False) |
| 238 | subscriber.save() |
| 239 | return Response({service: getattr(subscriber, service_attr)}) |
| 240 | |
| 241 | def get_bbsdump(self, request, pk=None): |
| 242 | subscriber = self.get_object() |
| 243 | if not subsciber.volt or not subscriber.volt.vcpe: |
| 244 | raise XOSMissingField("subscriber has no vCPE") |
| 245 | if not subscriber.volt.vcpe.bbs_account: |
| 246 | raise XOSMissingField("subscriber has no bbs_account") |
| 247 | |
| 248 | result=subprocess.check_output(["python", "/opt/xos/observers/vcpe/broadbandshield.py", "dump", subscriber.volt.vcpe.bbs_account, "123"]) |
| 249 | if request.GET.get("theformat",None)=="text": |
| 250 | from django.http import HttpResponse |
| 251 | return HttpResponse(result, content_type="text/plain") |
| 252 | else: |
| 253 | return Response( {"bbs_dump": result } ) |
| 254 | |
| 255 | def setup_demo_subscriber(self, subscriber): |
| 256 | # nuke the users and start over |
| 257 | subscriber.users = [] |
| 258 | subscriber.create_user(name="Mom's PC", mac="010203040506", level="PG_13") |
| 259 | subscriber.create_user(name="Dad's PC", mac="90E2Ba82F975", level="PG_13") |
| 260 | subscriber.create_user(name="Jack's Laptop", mac="685B359D91D5", level="PG_13") |
| 261 | subscriber.create_user(name="Jill's Laptop", mac="34363BC9B6A6", level="PG_13") |
| 262 | subscriber.save() |
| 263 | |
| 264 | def initdemo(self, request): |
| 265 | object_list = CordSubscriber.get_tenant_objects().all() |
| 266 | |
| 267 | # reset the parental controls in any existing demo vCPEs |
| 268 | for o in object_list: |
| 269 | if str(o.service_specific_id) in ["0", "1"]: |
| 270 | self.setup_demo_subscriber(o) |
| 271 | |
| 272 | demo_subscribers = [o for o in object_list if o.is_demo_user] |
| 273 | |
| 274 | if demo_subscribers: |
| 275 | return Response({"id": demo_subscribers[0].id}) |
| 276 | |
| 277 | subscriber = CordSubscriberRoot(service_specific_id=1234, |
| 278 | name="demo-subscriber",) |
| 279 | subscriber.is_demo_user = True |
| 280 | subscriber.save() |
| 281 | |
| 282 | self.setup_demo_subscriber(subscriber) |
| 283 | |
| 284 | return Response({"id": subscriber.id}) |
| 285 | |
| 286 | def ssidlist(self, request): |
| 287 | object_list = CordSubscriber.get_tenant_objects().all() |
| 288 | |
| 289 | ssidmap = [ {"service_specific_id": x.service_specific_id, "subscriber_id": x.id} for x in object_list ] |
| 290 | |
| 291 | return Response({"ssidmap": ssidmap}) |
| 292 | |
| 293 | def ssiddetail(self, pk=None, ssid=None): |
| 294 | object_list = CordSubscriber.get_tenant_objects().all() |
| 295 | |
| 296 | ssidmap = [ {"service_specific_id": x.service_specific_id, "subscriber_id": x.id} for x in object_list if str(x.service_specific_id)==str(ssid) ] |
| 297 | |
| 298 | if len(ssidmap)==0: |
| 299 | raise XOSNotFound("didn't find ssid %s" % str(ssid)) |
| 300 | |
| 301 | return Response( ssidmap[0] ) |
| 302 | |