From 371c5c350266e61c372d05e29378081cddee0577 Mon Sep 17 00:00:00 2001 From: Mattijs Vanhaverbeke Date: Fri, 22 May 2020 12:07:46 +0200 Subject: [PATCH] added download button, fixed perms --- README.md | 9 +++++ netbox_topology_views/api/views.py | 37 +++++++++---------- .../static/netbox_topology_views/js/app.js | 2 +- netbox_topology_views/static_dev/js/home.js | 21 ++++++++--- .../netbox_topology_views/index.html | 5 +++ 5 files changed, 48 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 4d099cb..a646cfa 100644 --- a/README.md +++ b/README.md @@ -63,3 +63,12 @@ Run `pip install netbox-topology-views --upgrade` in your venv. Run `python3 manage.py collectstatic --no-input` Clear you browser cache. + + +### Permissions + +To view `/plugins/topology-views/` you need the following permissions: + + dcim | device | can view device + + dcim | site | can view site + + extras | tag | can view tag + + dcim | device role | can view device role \ No newline at end of file diff --git a/netbox_topology_views/api/views.py b/netbox_topology_views/api/views.py index 76295f7..1a20324 100644 --- a/netbox_topology_views/api/views.py +++ b/netbox_topology_views/api/views.py @@ -30,7 +30,7 @@ class PreSelectTagsViewSet(ReadOnlyModelViewSet): queryset = Tag.objects.filter(name__in=preselected_tags) serializer_class = PreTagSerializer -class SaveCoordsViewSet(GenericViewSet): +class SaveCoordsViewSet(ReadOnlyModelViewSet): queryset = Device.objects.all() serializer_class = TopologyDummySerializer @@ -76,7 +76,7 @@ class SaveCoordsViewSet(GenericViewSet): results["status"] = "not allowed to save coords" return Response(results, status=500) -class SearchViewSet(GenericViewSet): +class SearchViewSet(ReadOnlyModelViewSet): #_ignore_model_permissions = True #permission_classes = [IsAuthenticatedOrLoginNotRequired] @@ -96,24 +96,23 @@ class SearchViewSet(GenericViewSet): return filter_devices - @action(detail=False, methods=['post']) + @action(detail=False, methods=['get']) def search(self, request): - name = None - sites = None - devicerole = None - tags = None - if "devicerole" in request.data: - if request.data["devicerole"]: - devicerole = request.data["devicerole"] - if "sites" in request.data: - if request.data["sites"]: - sites = request.data["sites"] - if "name" in request.data: - if request.data["name"]: - name = request.data["name"] - if "tags" in request.data: - if request.data["tags"]: - tags = request.data["tags"] + name = request.query_params.get('name', None) + if name == "": + name = None + + sites = request.query_params.getlist('sites[]', None) + if sites == []: + sites = None + + devicerole = request.query_params.getlist('devicerole[]', None) + if devicerole == []: + devicerole = None + + tags = request.query_params.getlist('tags[]', None) + if tags == []: + tags = None devices = self._filter(sites, devicerole, name, tags) diff --git a/netbox_topology_views/static/netbox_topology_views/js/app.js b/netbox_topology_views/static/netbox_topology_views/js/app.js index 55289fc..b899446 100644 --- a/netbox_topology_views/static/netbox_topology_views/js/app.js +++ b/netbox_topology_views/static/netbox_topology_views/js/app.js @@ -1 +1 @@ -var graph=null,container=null,csrftoken=null,nodes=new vis.DataSet,edges=new vis.DataSet,options={interaction:{hover:!0,hoverConnectedEdges:!0,multiselect:!1},nodes:{shape:"image",brokenImage:"../../static/netbox_topology_views/img/role-unknown.png",size:35,font:{multi:"md",face:"helvetica"}},edges:{length:100,width:2,font:{face:"helvetica"}},physics:{solver:"forceAtlas2Based"}};function iniPlotboxIndex(){document.addEventListener("DOMContentLoaded",function(){container=document.getElementById("visgraph"),csrftoken=jQuery("[name=csrfmiddlewaretoken]").val(),startLoadSearchBar(),handleButtonPress()},!1)}function startLoadSearchBar(){$("#device-roles").select2({allowClear:!0,placeholder:"---------",theme:"bootstrap",multiple:!0,ajax:{url:"../../api/dcim/device-roles/?brief=true",dataType:"json",type:"GET",data:function(e){return{q:e.term}},processResults:function(e){return{results:$.map(e.results,function(e){return{text:e.name,id:e.id}})}}}}),$("#sites").select2({allowClear:!0,placeholder:"---------",theme:"bootstrap",multiple:!0,ajax:{url:"../../api/dcim/sites/?brief=true",dataType:"json",type:"GET",data:function(e){return{q:e.term}},processResults:function(e){return{results:$.map(e.results,function(e){return{text:e.name,id:e.id}})}}}}),$("#tags").select2({allowClear:!0,placeholder:"---------",theme:"bootstrap",multiple:!0,ajax:{url:"../../api/extras/tags/?brief=true",dataType:"json",type:"GET",data:function(e){return{q:e.term}},processResults:function(e){return{results:$.map(e.results,function(e){return{text:e.name,id:e.id}})}}}});var s=$("#device-roles");$.ajax({type:"GET",url:"../../api/plugins/topology-views/preselectdeviceroles/"}).then(function(e){$.each(e.results,function(e,t){var a=new Option(t.name,t.id,!0,!0);s.append(a).trigger("change"),s.trigger({type:"select2:select",params:{data:t}})})});var n=$("#tags");$.ajax({type:"GET",url:"../../api/plugins/topology-views/preselecttags/"}).then(function(e){$.each(e.results,function(e,t){var a=new Option(t.name,t.id,!0,!0);n.append(a).trigger("change"),n.trigger({type:"select2:select",params:{data:t}})})})}function handleButtonPress(){$("#search-form").submit(function(e){$("#status").html('Loading data'),e.preventDefault();var t=$("#name").val(),a=$("#device-roles").val(),s=$("#sites").val(),n=$("#tags").val();$.ajax({type:"POST",url:"../../api/plugins/topology-views/search/search/",data:JSON.stringify({name:t,devicerole:a,sites:s,tags:n}),headers:{"X-CSRFToken":csrftoken},contentType:"application/json; charset=utf-8",dataType:"json",success:function(e){$("#status").html('Drawing network'),graph=null,nodes=new vis.DataSet,edges=new vis.DataSet,graph=new vis.Network(container,{nodes:nodes,edges:edges},options),$.each(e.nodes,function(e,t){nodes.add(t)}),$.each(e.edges,function(e,t){edges.add(t)}),graph.fit(),graph.on("afterDrawing",function(){$("#status").html('Ready')}),graph.on("dragEnd",function(e){dragged=this.getPositions(e.nodes),$.each(dragged,function(e,t){$("#coordstatus").html(""),$("#checkSaveCoordinates").is(":checked")&&$.ajax({url:"../../api/plugins/topology-views/save-coords/save_coords/",type:"POST",dataType:"json",headers:{"X-CSRFToken":csrftoken},contentType:"application/json; charset=utf-8",data:JSON.stringify({node_id:e,x:t.x,y:t.y}),error:function(e){$("#coordstatus").html('Failed to update coordinates')},success:function(e){$("#coordstatus").html('Updated coordinates')}})})})},error:function(e){$("#status").html('Something went wrong')}})})} \ No newline at end of file +var graph=null,container=null,downloadButton=null,MIME_TYPE="image/png",canvas=null,csrftoken=null,nodes=new vis.DataSet,edges=new vis.DataSet,options={interaction:{hover:!0,hoverConnectedEdges:!0,multiselect:!1},nodes:{shape:"image",brokenImage:"../../static/netbox_topology_views/img/role-unknown.png",size:35,font:{multi:"md",face:"helvetica"}},edges:{length:100,width:2,font:{face:"helvetica"}},physics:{solver:"forceAtlas2Based"}};function iniPlotboxIndex(){document.addEventListener("DOMContentLoaded",function(){container=document.getElementById("visgraph"),csrftoken=jQuery("[name=csrfmiddlewaretoken]").val(),startLoadSearchBar(),handleButtonPress(),downloadButton=document.getElementById("btnDownloadImage")},!1)}function startLoadSearchBar(){$("#device-roles").select2({allowClear:!0,placeholder:"---------",theme:"bootstrap",multiple:!0,ajax:{url:"../../api/dcim/device-roles/?brief=true",dataType:"json",type:"GET",data:function(e){return{q:e.term}},processResults:function(e){return{results:$.map(e.results,function(e){return{text:e.name,id:e.id}})}}}}),$("#sites").select2({allowClear:!0,placeholder:"---------",theme:"bootstrap",multiple:!0,ajax:{url:"../../api/dcim/sites/?brief=true",dataType:"json",type:"GET",data:function(e){return{q:e.term}},processResults:function(e){return{results:$.map(e.results,function(e){return{text:e.name,id:e.id}})}}}}),$("#tags").select2({allowClear:!0,placeholder:"---------",theme:"bootstrap",multiple:!0,ajax:{url:"../../api/extras/tags/?brief=true",dataType:"json",type:"GET",data:function(e){return{q:e.term}},processResults:function(e){return{results:$.map(e.results,function(e){return{text:e.name,id:e.id}})}}}});var n=$("#device-roles");$.ajax({type:"GET",url:"../../api/plugins/topology-views/preselectdeviceroles/"}).then(function(e){$.each(e.results,function(e,t){var a=new Option(t.name,t.id,!0,!0);n.append(a).trigger("change"),n.trigger({type:"select2:select",params:{data:t}})})});var s=$("#tags");$.ajax({type:"GET",url:"../../api/plugins/topology-views/preselecttags/"}).then(function(e){$.each(e.results,function(e,t){var a=new Option(t.name,t.id,!0,!0);s.append(a).trigger("change"),s.trigger({type:"select2:select",params:{data:t}})})})}function handleButtonPress(){$("#search-form").submit(function(e){$("#status").html('Loading data'),e.preventDefault();var t=$("#name").val(),a=$("#device-roles").val(),n=$("#sites").val(),s=$("#tags").val();$.ajax({type:"GET",url:"../../api/plugins/topology-views/search/search/",data:{name:t,"devicerole[]":a,"sites[]":n,"tags[]":s},headers:{"X-CSRFToken":csrftoken},contentType:"application/json; charset=utf-8",dataType:"json",success:function(e){$("#status").html('Drawing network'),graph=null,nodes=new vis.DataSet,edges=new vis.DataSet,graph=new vis.Network(container,{nodes:nodes,edges:edges},options),$.each(e.nodes,function(e,t){nodes.add(t)}),$.each(e.edges,function(e,t){edges.add(t)}),graph.fit(),canvas=document.getElementById("visgraph").getElementsByTagName("canvas")[0],graph.on("afterDrawing",function(){$("#status").html('Ready');var e=canvas.toDataURL(MIME_TYPE);downloadButton.href=e,downloadButton.download="topology"}),graph.on("dragEnd",function(e){dragged=this.getPositions(e.nodes),$.each(dragged,function(e,t){$("#coordstatus").html(""),$("#checkSaveCoordinates").is(":checked")&&$.ajax({url:"../../api/plugins/topology-views/save-coords/save_coords/",type:"POST",dataType:"json",headers:{"X-CSRFToken":csrftoken},contentType:"application/json; charset=utf-8",data:JSON.stringify({node_id:e,x:t.x,y:t.y}),error:function(e){$("#coordstatus").html('Failed to update coordinates')},success:function(e){$("#coordstatus").html('Updated coordinates')}})})})},error:function(e){$("#status").html('Something went wrong')}})})} \ No newline at end of file diff --git a/netbox_topology_views/static_dev/js/home.js b/netbox_topology_views/static_dev/js/home.js index b7acb95..ab923c7 100644 --- a/netbox_topology_views/static_dev/js/home.js +++ b/netbox_topology_views/static_dev/js/home.js @@ -1,5 +1,8 @@ var graph = null; var container = null; +var downloadButton = null; +var MIME_TYPE = "image/png"; +var canvas = null; var csrftoken = null; var nodes = new vis.DataSet(); var edges = new vis.DataSet(); @@ -36,6 +39,7 @@ function iniPlotboxIndex() { csrftoken = jQuery("[name=csrfmiddlewaretoken]").val(); startLoadSearchBar(); handleButtonPress(); + downloadButton = document.getElementById('btnDownloadImage'); }, false); } @@ -167,14 +171,14 @@ function handleButtonPress() { var value3 = $("#sites").val(); var value4 = $("#tags").val(); $.ajax({ - type: "POST", + type: "GET", url: "../../api/plugins/topology-views/search/search/", - data: JSON.stringify({ + data: { 'name': value, - 'devicerole': value2, - 'sites': value3, - 'tags': value4 - }), + 'devicerole[]': value2, + 'sites[]': value3, + 'tags[]': value4 + }, headers: { "X-CSRFToken": csrftoken }, contentType: "application/json; charset=utf-8", dataType: "json", @@ -191,9 +195,13 @@ function handleButtonPress() { edges.add(edge); }); graph.fit(); + canvas = document.getElementById('visgraph').getElementsByTagName('canvas')[0]; graph.on('afterDrawing', function () { $("#status").html('Ready'); + var image = canvas.toDataURL(MIME_TYPE); + downloadButton.href = image; + downloadButton.download = "topology"; }); graph.on("dragEnd", function (params) { @@ -223,6 +231,7 @@ function handleButtonPress() { } }); }); + }, error: function (error_result) { $("#status").html('Something went wrong'); diff --git a/netbox_topology_views/templates/netbox_topology_views/index.html b/netbox_topology_views/templates/netbox_topology_views/index.html index 87cd4d0..743285d 100644 --- a/netbox_topology_views/templates/netbox_topology_views/index.html +++ b/netbox_topology_views/templates/netbox_topology_views/index.html @@ -12,6 +12,11 @@
Network +
+ + + +