# field does not have access to the initial value
return self.initial["password"]
+class UserDashboardViewInline(PlStackTabularInline):
+ model = UserDashboardView
+ extra = 0
+ suit_classes = 'suit-tab suit-tab-dashboards'
+ fields = ['user', 'dashboardView', 'order']
+
class UserAdmin(UserAdmin):
class Meta:
app_label = "core"
list_display = ('email', 'firstname', 'lastname', 'site', 'last_login')
#list_display = ('email', 'username','firstname', 'lastname', 'is_admin', 'last_login')
list_filter = ('site',)
- inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline]
+ inlines = [SlicePrivilegeInline,SitePrivilegeInline,DeploymentPrivilegeInline,UserDashboardViewInline]
fieldListLoginDetails = ['email','site','password','is_readonly','is_amin','public_key']
fieldListContactInfo = ['firstname','lastname','phone','timezone']
fieldsets = (
('Login Details', {'fields': ['email', 'site','password', 'is_readonly', 'is_admin', 'public_key'], 'classes':['suit-tab suit-tab-general']}),
('Contact Information', {'fields': ('firstname','lastname','phone', 'timezone'), 'classes':['suit-tab suit-tab-contact']}),
+ #('Dashboard Views', {'fields': ('dashboards',), 'classes':['suit-tab suit-tab-dashboards']}),
#('Important dates', {'fields': ('last_login',)}),
)
add_fieldsets = (
user_readonly_fields = fieldListLoginDetails
user_readonly_inlines = [SlicePrivilegeROInline,SitePrivilegeROInline,DeploymentPrivilegeROInline]
- suit_form_tabs =(('general','Login Details'),('contact','Contact Information'),('sliceprivileges','Slice Privileges'),('siteprivileges','Site Privileges'),('deploymentprivileges','Deployment Privileges'))
+ suit_form_tabs =(('general','Login Details'),
+ ('contact','Contact Information'),
+ ('sliceprivileges','Slice Privileges'),
+ ('siteprivileges','Site Privileges'),
+ ('deploymentprivileges','Deployment Privileges'),
+ ('dashboards','Dashboard Views'))
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == 'site':
def queryset(self, request):
return User.select_by_user(request.user)
+class DashboardViewAdmin(PlanetStackBaseAdmin):
+ fieldsets = [('Dashboard View Details',
+ {'fields': ['name', 'url'],
+ 'classes': ['suit-tab suit-tab-general']})
+ ]
+ suit_form_tabs =(('general','Dashboard View Details'),)
class ServiceResourceROInline(ReadOnlyTabularInline):
model = ServiceResource
#admin.site.register(SitePrivilege, SitePrivilegeAdmin)
admin.site.register(Sliver, SliverAdmin)
admin.site.register(Image, ImageAdmin)
+ admin.site.register(DashboardView, DashboardViewAdmin)
from .role import Role
#from .deployment import Deployment
from .site import Site,Deployment, DeploymentRole, DeploymentPrivilege, SiteDeployments
-from .user import User, UserDeployments
+from .dashboard import DashboardView
+from .user import User, UserDeployments, UserDashboardView
from .serviceclass import ServiceClass
from .slice import Slice, SliceDeployments
from .site import SitePrivilege, SiteDeployments
from .reservation import Reservation
from .network import Network, NetworkParameterType, NetworkParameter, NetworkSliver, NetworkTemplate, Router, NetworkSlice, NetworkDeployments
from .billing import Account, Invoice, Charge, UsableObject, Payment
+
--- /dev/null
+import os
+from django.db import models
+from core.models import PlCoreBase
+from django.contrib.contenttypes import generic
+
+class DashboardView(PlCoreBase):
+ name = models.CharField(max_length=200, unique=True, help_text="Name of the View")
+ url = models.CharField(max_length=1024, help_text="URL of Dashboard")
+
+ def __unicode__(self): return u'%s' % (self.name)
+
from collections import defaultdict
from django.db import models
from django.db.models import F, Q
-from core.models import PlCoreBase,Site
+from core.models import PlCoreBase,Site, DashboardView
from core.models.deployment import Deployment
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
from timezones.fields import TimeZoneField
+from operator import itemgetter, attrgetter
# Create your models here.
class UserManager(BaseUserManager):
timezone = TimeZoneField()
+ dashboards = models.ManyToManyField('DashboardView', through='UserDashboardView', blank=True)
+
objects = UserManager()
USERNAME_FIELD = 'email'
def is_superuser(self):
return False
+ def get_dashboards(self):
+ DEFAULT_DASHBOARDS=["Tenant"]
+
+ dashboards = sorted(list(self.dashboardViews.all()), key=attrgetter('order'))
+ dashboards = [x.dashboardView for x in dashboards]
+
+ if not dashboards:
+ for dashboardName in DEFAULT_DASHBOARDS:
+ dbv = DashboardView.objects.filter(name=dashboardName)
+ if dbv:
+ dashboards.append(dbv[0])
+
+ return dashboards
+
# def get_roles(self):
# from core.models.site import SitePrivilege
# from core.models.slice import SliceMembership
else:
users = Users.select_by_user(user)
qs = Usereployments.objects.filter(user__in=slices)
- return qs
+ return qs
+
+class UserDashboardView(PlCoreBase):
+ user = models.ForeignKey(User, related_name="dashboardViews")
+ dashboardView = models.ForeignKey(DashboardView, related_name="dashboardViews")
+ order = models.IntegerField(default=0)
def get_urls(self):
"""Add our dashboard view to the admin urlconf. Deleted the default index."""
from django.conf.urls import patterns, url
- from views import DashboardView, DashboardWelcomeView, DashboardAjaxView, SimulatorView, DashboardSummaryAjaxView, DashboardAddOrRemoveSliverView, DashboardUserSiteView, DashboardAnalyticsAjaxView, TenantViewData,TenantCreateSlice, TenantAddOrRemoveSliverView, TenantPickSitesView, TenantDeleteSliceView,TenantUpdateSlice
+ from views import DashboardCustomize, DashboardDynamicView, DashboardWelcomeView, DashboardAjaxView, SimulatorView, DashboardSummaryAjaxView, DashboardAddOrRemoveSliverView, DashboardUserSiteView, DashboardAnalyticsAjaxView, TenantViewData,TenantCreateSlice, TenantAddOrRemoveSliverView, TenantPickSitesView, TenantDeleteSliceView,TenantUpdateSlice
urls = super(AdminMixin, self).get_urls()
del urls[0]
custom_url = patterns('',
- url(r'^$', self.admin_view(DashboardWelcomeView.as_view()),
+ url(r'^$', self.admin_view(DashboardDynamicView.as_view()),
name="index"),
url(r'^test/', self.admin_view(DashboardUserSiteView.as_view()),
name="test"),
- url(r'^dashboard/(?P<name>\w+)/$', self.admin_view(DashboardView.as_view()),
+ url(r'^dashboard/(?P<name>\w+)/$', self.admin_view(DashboardDynamicView.as_view()),
name="dashboard"),
+ url(r'^customize/$', self.admin_view(DashboardCustomize.as_view()),
+ name="customize"),
url(r'^hpcdashuserslices/', self.admin_view(DashboardUserSiteView.as_view()),
name="hpcdashuserslices"),
url(r'^hpcdashboard/', self.admin_view(DashboardAjaxView.as_view()), # DEPRECATED
from django.core import urlresolvers
from django.contrib.gis.geoip import GeoIP
from ipware.ip import get_ip
+from operator import itemgetter, attrgetter
import traceback
import socket
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
- userDetails = getUserSliceInfo(request.user)
- #context['site'] = userDetails['site']
-
- context['userSliceInfo'] = userDetails['userSliceInfo']
- context['cdnData'] = userDetails['cdnData']
- context['cdnContentProviders'] = userDetails['cdnContentProviders']
+ context = getDashboardContext(request.user, context)
return self.render_to_response(context=context)
-class DashboardView(TemplateView):
+class DashboardDynamicView(TemplateView):
head_template = r"""{% extends "admin/dashboard/dashboard_base.html" %}
{% load admin_static %}
{% block content %}
tail_template = r"{% endblock %}"
- def get(self, request, name="hpc_historical", *args, **kwargs):
+ def get(self, request, name="root", *args, **kwargs):
context = self.get_context_data(**kwargs)
+ context = getDashboardContext(request.user, context)
+
+ if name=="root":
+ return self.multiDashboardView(request, context)
+ else:
+ return self.singleDashboardView(request, name, context)
+ def readDashboard(self, fn):
+ try:
+ template= open("/opt/planetstack/templates/admin/dashboard/%s.html" % fn, "r").read()
+ if (fn=="tenant"):
+ template = '<div id="tabs-5"></div>' + template
+ return template
+ except:
+ return "failed to open %s" % fn
+
+ def multiDashboardView(self, request, context):
head_template = self.head_template
tail_template = self.tail_template
- if (name=="tenant"):
- # quick fix for tenant view
- head_template = head_template + '<div id="tabs-5"></div>'
+ body = """
+ <div id="hometabs" >
+ <ul id="suit_form_tabs" class="nav nav-tabs nav-tabs-suit" data-tab-prefix="suit-tab">
+ """
+
+ dashboards = request.user.get_dashboards()
+
+ # customize is a special dashboard they always get
+ customize = DashboardView.objects.filter(name="Customize")
+ if customize:
+ dashboards.append(customize[0])
+
+ for i,view in enumerate(dashboards):
+ body = body + '<li><a href="#dashtab-%d">%s</a></li>\n' % (i, view.name)
+ body = body + "</ul>\n"
- t = template.Template(head_template + open("/opt/planetstack/templates/admin/dashboard/%s.html" % name, "r").read() + self.tail_template)
+ for i,view in enumerate(dashboards):
+ url = view.url
+ body = body + '<div id="dashtab-%d">\n' % i
+ if url.startswith("template:"):
+ fn = url[9:]
+ body = body + self.readDashboard(fn)
+ body = body + '</div>\n'
+
+ body=body+"</div>\n"
+
+ t = template.Template(head_template + body + self.tail_template)
+
+ response_kwargs = {}
+ response_kwargs.setdefault('content_type', self.content_type)
+ return self.response_class(\r
+ request = request,\r
+ template = t,\r
+ context = context,\r
+ **response_kwargs)
- userDetails = getUserSliceInfo(request.user)
- #context['site'] = userDetails['site']
+ def singleDashboardView(self, request, name, context):
+ head_template = self.head_template
+ tail_template = self.tail_template
- context['userSliceInfo'] = userDetails['userSliceInfo']
- context['cdnData'] = userDetails['cdnData']
- context['cdnContentProviders'] = userDetails['cdnContentProviders']
+ t = template.Template(head_template + self.readDashboard(fn) + self.tail_template)
response_kwargs = {}
response_kwargs.setdefault('content_type', self.content_type)
context = context,\r
**response_kwargs)
-def getUserSliceInfo(user, tableFormat = False):
- userDetails = {}
+def getDashboardContext(user, context={}, tableFormat = False):
+ context = {}
userSliceData = getSliceInfo(user)
if (tableFormat):
-# pprint("******* GET USER SLICE INFO")
- userDetails['userSliceInfo'] = userSliceTableFormatter(userSliceData)
+ context['userSliceInfo'] = userSliceTableFormatter(userSliceData)
else:
- userDetails['userSliceInfo'] = userSliceData
- userDetails['cdnData'] = getCDNOperatorData(wait=False)
- userDetails['cdnContentProviders'] = getCDNContentProviderData()
- return userDetails
+ context['userSliceInfo'] = userSliceData
+ context['cdnData'] = getCDNOperatorData(wait=False)
+ context['cdnContentProviders'] = getCDNContentProviderData()
+
+ (dashboards, unusedDashboards)= getDashboards(user)
+ unusedDashboards=[x for x in unusedDashboards if x!="Customize"]
+ context['dashboards'] = dashboards
+ context['unusedDashboards'] = unusedDashboards
+
+ return context
+
+def getDashboards(user):
+ #dashboards = sorted(list(user.dashboardViews.all()), key=attrgetter('order'))
+ dashboards = user.get_dashboards()
+
+ dashboard_names = [d.name for d in dashboards]
+
+ unused_dashboard_names = []
+ for dashboardView in DashboardView.objects.all():
+ if not dashboardView.name in dashboard_names:
+ unused_dashboard_names.append(dashboardView.name)
+
+ return (dashboard_names, unused_dashboard_names)
class TenantCreateSlice(View):
def post(self, request, *args, **kwargs):
class DashboardUserSiteView(View):
def get(self, request, **kwargs):
- return HttpResponse(json.dumps(getUserSliceInfo(request.user, True)), mimetype='application/javascript')
+ return HttpResponse(json.dumps(getDashboardContext(request.user, tableFormat=True)), mimetype='application/javascript')
class TenantViewData(View):
def get(self, request, **kwargs):
if (name == "hpcSummary"):
return HttpResponse(json.dumps(hpc_wizard.get_hpc_wizard().get_summary_for_view()), mimetype='application/javascript')
elif (name == "hpcUserSite"):
- return HttpResponse(json.dumps(getUserSliceInfo(request.user, True)), mimetype='application/javascript')
+ return HttpResponse(json.dumps(getDashboardContext(request.user, tableFormat=True)), mimetype='application/javascript')
elif (name == "hpcMap"):
return HttpResponse(json.dumps(getCDNOperatorData(True)), mimetype='application/javascript')
elif (name == "bigquery"):
else:
return HttpResponse(json.dumps("Unknown"), mimetype='application/javascript')
+class DashboardCustomize(View):
+ def post(self, request, *args, **kwargs):\r
+ dashboards = request.POST.get("dashboards", None)\r
+ if not dashboards:\r
+ return HttpResponse("no data")\r
+\r
+ dashboards = [x.strip() for x in dashboards.split(",")]\r
+\r
+ dashboards = [DashboardView.objects.get(name=x) for x in dashboards]\r
+\r
+ request.user.dashboardViews.all().delete()\r
+\r
+ for i,dashboard in enumerate(dashboards):\r
+ udbv = UserDashboardView(user=request.user, dashboardView=dashboard, order=i)\r
+ udbv.save()\r
+\r
+ return HttpResponse("updated")\r
+
#private-vol{
margin-right: 15% !important;
-}
\ No newline at end of file
+}\r
+\r
+.customize_row {\r
+ display: table;\r
+}\r
+.customize_column {\r
+ display: table-cell;\r
+ padding: 10px;\r
+}\r
--- /dev/null
+<form>
+ <div class="customize_row">\r
+ <div class="customize_column">\r
+ <div>Available Dashboard Views</div>\r
+ <select name="selectfrom" id="select-from" multiple size="5">\r
+ {% for cp in unusedDashboards %}\r
+ <option value="{{ cp }}">{{ cp }}</option>
+ {% endfor %}\r
+ </select>\r
+ </div>\r
+ <div class="customize_column">\r
+ <br>\r
+ <div class="btn btn-success" id="btn-add">Add »</div><br><br>\r
+ <div class="btn btn-success" id="btn-remove">« Remove</div>\r
+ </div>\r
+ <div class="customize_column">\r
+ <div>Selected Dashboard Views</div>\r
+ <select name="selectto" id="select-to" multiple size="5">\r
+ {% for cp in dashboards %}\r
+ <option value="{{ cp }}">{{ cp }}</option>
+ {% endfor %}\r
+ </select>\r
+ <br>\r
+ <div class="btn btn-high btn-info" id="btn-save">Save</div>\r
+ </div>\r
+ <div class="customize_column">\r
+ <br>\r
+ <div class="btn btn-success" id="btn-up">Up</div><br><br>\r
+ <div class="btn btn-success" id="btn-down">Down</div>\r
+ </div>\r
+ </div>\r
+</form>\r
+
+<script>
+$(document).ready(function() {
+ $('#btn-add').click(function(){\r
+ $('#select-from option:selected').each( function() {\r
+ $('#select-to').append("<option value='"+$(this).val()+"'>"+$(this).text()+"</option>");\r
+ $(this).remove();\r
+ });\r
+ });\r
+ $('#btn-remove').click(function(){\r
+ $('#select-to option:selected').each( function() {\r
+ $('#select-from').append("<option value='"+$(this).val()+"'>"+$(this).text()+"</option>");\r
+ $(this).remove();\r
+ });\r
+ });\r
+ $('#btn-up').bind('click', function() {\r
+ $('#select-to option:selected').each( function() {\r
+ var newPos = $('#select-to option').index(this) - 1;\r
+ if (newPos > -1) {\r
+ $('#select-to option').eq(newPos).before("<option value='"+$(this).val()+"' selected='selected'>"+$(this).text()+"</option>");\r
+ $(this).remove();\r
+ }\r
+ });\r
+ });\r
+ $('#btn-down').bind('click', function() {\r
+ var countOptions = $('#select-to option').size();\r
+ $('#select-to option:selected').each( function() {\r
+ var newPos = $('#select-to option').index(this) + 1;\r
+ if (newPos < countOptions) {\r
+ $('#select-to option').eq(newPos).after("<option value='"+$(this).val()+"' selected='selected'>"+$(this).text()+"</option>");\r
+ $(this).remove();\r
+ }\r
+ });\r
+ });\r
+ $('#btn-save').bind('click', function() {\r
+ var items=[];\r
+ $("#select-to option").each(function() { items.push($(this).val()); });\r
+ $.ajax({\r
+ url: '/customize/',
+ dataType: 'json',
+ data: {
+ dashboards: items.join(","),
+ csrfmiddlewaretoken: "{{ csrf_token }}" // < here
+ },
+ type: 'POST',
+ complete: function () {
+ location.reload();
+ }
+ });\r
+ });
+});
+</script>
+