* REQUIREMENTS is to have python + django (1.5.2) installed django
** should be straightforward
** see devel/django-install.txt in case of trouble
-$ apt-get install python-django
-$ apt-get install python-django-south
$ apt-get install python-pip or sudo easy_install pip==1.4.1
+$ pip install django=="1.5.2
+$ apt-get install python-django-south
$ pip install requests
$ pip install djangorestframework
$ pip install django-celery
import portal.dashboardview
import portal.homeview
import portal.newsview
+import portal.loginwidget
from portal.about import AboutView
from portal.registrationview import RegistrationView
#(r'^view/?', include('view.urls')),
#(r'^list/slices', 'view.list.slices')
#
+ # Login widget to be used in an iframe
+ (r'^loginwidget/?$', portal.loginwidget.LoginWidget.as_view()),
#
# Portal
(r'^news/?$', portal.newsview.NewsView.as_view()),
--- /dev/null
+from django.core.context_processors import csrf
+from django.shortcuts import render_to_response
+
+from django.views.generic.base import TemplateView
+from unfold.loginrequired import FreeAccessView
+
+class LoginWidget(FreeAccessView):
+
+ def get(self, request):
+ env = {}
+ env.update(csrf(request))
+ return render_to_response("loginwidget.html", env)
import datetime\r
import urllib2\r
import ast\r
+import time\r
+\r
from django.views.decorators.csrf import csrf_exempt\r
from django.http import *\r
\r
+\r
def response_mimetype(request):\r
\r
if "application/json" in request.META['HTTP_ACCEPT']:\r
def slice_to_exp(slices_users):\r
experiments = {}\r
testbeds = {}\r
+ wildcard_testbeds = {}\r
+ \r
\r
- \r
- for slice in slices_users:\r
+ for slice in slices_users: \r
nodes={}\r
leases = slice['lease']\r
- if leases is not None:\r
+ \r
+ if leases is not None and leases:\r
for lease in leases:\r
resource = lease['resource']\r
start_t = lease['start_time']\r
end_t = lease['end_time']\r
- #node = lease['resource']\r
\r
testbed_start = resource.index('IDN+')+4\r
testbed_end = resource.index('+node+')\r
\r
testbed = resource[testbed_start:testbed_end]\r
node = resource[testbed_end+6:]\r
- \r
+ if 'omf:nitos' in testbed:\r
+ testbed = 'omf:nitos'\r
if testbed in testbeds:\r
if node not in testbeds[testbed]:\r
testbeds[testbed].append(node)\r
f=1\r
if f==0:\r
nodes[node][str(start_t)]={'start_t':start_t, 'nodes':node, 'end_t':end_t}\r
+\r
+ ######### FOR PLE LIKE start ##################\r
+ for resource in slice['resource']:\r
+ testbed_start = resource.index('IDN+')+4\r
+ testbed_end = resource.index('+node+')\r
+ tb = resource[testbed_start:testbed_end]\r
+ node = resource[testbed_end+6:]\r
+ if 'ple:' in tb:\r
+ tb = 'ple'\r
+ if 'omf:nitos' in tb:\r
+ tb = 'omf:nitos'\r
+ if tb not in testbeds:\r
+ try:\r
+ if node not in wildcard_testbeds[slice['slice_hrn']][tb]:\r
+ wildcard_testbeds[slice['slice_hrn']][tb].append([node])\r
+ except:\r
+ try:\r
+ wildcard_testbeds[slice['slice_hrn']][tb] = [node]\r
+ except:\r
+ wildcard_testbeds[slice['slice_hrn']]={tb:[node]}\r
+ \r
+ \r
+ else:\r
+ s = slice['slice_last_updated']\r
+ #s_time = int(time.mktime(datetime.datetime.strptime(s, "%Y%m%dT%H:%M:%Ss").timetuple()))\r
+ s_time = time.mktime(s.timetuple()) \r
+ \r
+ if slice['resource'] is not None:\r
+ \r
+ for resource in slice['resource']:\r
+ testbed_start = resource.index('IDN+')+4\r
+ testbed_end = resource.index('+node+')\r
+ tb = resource[testbed_start:testbed_end]\r
+ if 'ple:' in tb:\r
+ tb = 'ple'\r
+ if 'omf:nitos' in tb:\r
+ tb = 'omf:nitos'\r
+ node = resource[testbed_end+6:]\r
+ \r
+ if testbed in testbeds:\r
+ if node not in testbeds[testbed]:\r
+ testbeds[testbed].append(node)\r
+ else:\r
+ testbeds[testbed] = [node] \r
+ \r
+ if not node in nodes: \r
+ #nodes[node] = {str(start_t):{'start_t':s_time, 'nodes':node, 'end_t':int(time.time())}} \r
+ nodes[node] = {str(start_t):{'start_t':s_time, 'nodes':node, 'end_t':s_time}} \r
+ ######### FOR PLE LIKE end ##################\r
+ \r
\r
#group grouped nodes in experiments\r
for n in nodes:\r
for exp in nodes[n]:\r
- key = str(exp) + str(nodes[n][exp]['end_t'])\r
+ key = str(exp) + str(nodes[n][exp]['end_t']) + slice['slice_hrn']\r
\r
if key not in experiments:\r
experiments[key]={'slice_hrn':slice['slice_hrn'], \\r
'start':nodes[n][exp]['start_t'], 'end':nodes[n][exp]['end_t'], 'nodes':[nodes[n][exp]['nodes']]} \r
+ \r
+ \r
+ ######### FOR PLE LIKE start ##################\r
+ for item in wildcard_testbeds:\r
+ if item == experiments[key]['slice_hrn']:\r
+ for testbed in wildcard_testbeds[item]:\r
+ \r
+ if testbed not in testbeds:\r
+ testbeds[testbed] = wildcard_testbeds[item][testbed] \r
+ \r
+ for n in wildcard_testbeds[item][testbed]:\r
+ if n not in experiments[key]['nodes']:\r
+ experiments[key]['nodes'].append(n) \r
+ ######### FOR PLE LIKE end ##################\r
+ \r
elif nodes[n][exp]['end_t'] == experiments[key]['end']:\r
experiments[key]['nodes'].append(nodes[n][exp]['nodes'])\r
\r
+ \r
+ ######### FOR PLE LIKE start ##################\r
+ for item in wildcard_testbeds:\r
+ if item == experiments[key]['slice_hrn']:\r
+ for testbed in wildcard_testbeds[item]:\r
+ \r
+ if testbed not in testbeds:\r
+ testbeds[testbed] = wildcard_testbeds[item][testbed] \r
+ \r
+ for n in wildcard_testbeds[item][testbed]:\r
+ if n not in experiments[key]['nodes']:\r
+ experiments[key]['nodes'].append(n) \r
+ ######### FOR PLE LIKE end ##################\r
+ \r
return (experiments,testbeds)\r
\r
class ReputationView (LoginRequiredAutoLogoutView, ThemeView):\r
env = self.default_env()\r
env['theme'] = self.theme\r
\r
- return render_to_response(self.template, env, context_instance=RequestContext(request))\r
-\r
-\r
- \r
+ return render_to_response(self.template, env, context_instance=RequestContext(request)) \r
\r
def get (self, request, state=None):\r
env = self.default_env()\r
slices_users = []\r
\r
#get slices\r
- userslice_query = Query().get('slice').select('slice_urn', 'slice_hrn', 'users', 'resource', 'lease')\r
+ userslice_query = Query().get('slice').select('slice_urn', 'slice_hrn', 'users', 'resource', 'lease', 'slice_last_updated')\r
slice_details = execute_query(self.request, userslice_query)\r
\r
#get local users\r
local_user_query = Query().get('local:user').select('email','status','config')\r
local_user_details = execute_admin_query(self.request, local_user_query)\r
- \r
+ \r
#get users - create dict[email]=hrn\r
user_query = Query().get('user').select('user_hrn','user_urn','user_email')\r
user_details = execute_admin_query(self.request, user_query)\r
\r
#get a list of all the slices for the logged in user\r
testbeds = []\r
-\r
+ #env['slices_users'] = json.dumps(slice_details, ensure_ascii=False)\r
for slice in slice_details:\r
\r
if users_hrn[cur_username] in slice['users']:\r
slices_users.append({'slice_hrn':slice['slice_hrn'], 'user':cur_username, 'user_hrn':users_hrn[cur_username] \\r
- , 'resource':slice['resource'], 'lease':slice['lease'] }) \r
+ , 'resource':slice['resource'], 'lease':slice['lease'], 'slice_last_updated':slice['slice_last_updated'] }) \r
\r
\r
- env['slices_users'] = slices_users ### For logging\r
- \r
+ #env['slices_users'] = slices_users ### For logging\r
#####create slicelist for template & JSON\r
experiments,testbeds = slice_to_exp(slices_users)\r
- \r
+ \r
all_exp = []\r
iddata = []\r
\r
\r
iddata.append(tempid)\r
all_exp.append(experiment)\r
- \r
- \r
+ env['logging_test'] = json.dumps(all_exp, ensure_ascii=False)\r
+ env['slices_users'] = json.dumps(all_exp, ensure_ascii=False)\r
###### Check which experiments have not been rated yet. Pop from all_exp any experiment that has already been rated\r
+ \r
unrated_exp = json_to_rest('http://survivor.lab.netmode.ntua.gr:4567/reputation/qid', iddata) \r
\r
for item in all_exp:\r
else:\r
all_exp.pop(all_exp.index(item))\r
\r
-\r
-\r
###### Get Reputation values from Reputation DB\r
reps = json_to_rest('http://survivor.lab.netmode.ntua.gr:4567/reputation/showrep', "a")\r
#env['logging_test'] = reps \r
testbed['services'].append('N/A')\r
\r
###### Pass variables to template\r
- env['logging_test'] = json.dumps(all_exp, ensure_ascii=False)\r
+ #env['logging_test'] = json.dumps(all_exp, ensure_ascii=False)\r
env['serv_per_tb'] = json.dumps(serv_per_tb, ensure_ascii=False)\r
env['reputation'] = reps\r
env['rep_serv'] = services\r
--- /dev/null
+@import url("../fonts/opensans_bold_macroman/stylesheet.css");
+
+html { height: 100% }
+
+body {
+ background-color:white;
+ color:black;
+ margin:0;
+ padding:0;
+ height: 100%;
+ letter-spacing:0.3px;
+}
+a, a:active, a:focus {
+ outline: 0;
+ text-decoration:none;
+ color:#760073;
+}
+a:hover {
+ color:#0D0049;
+}
+
+a.current {
+ text-decoration:underline;
+ color:#333333;
+}
+p.command {
+ padding:15px;
+ margin:15px 0;
+ color:#890000;
+ background-color:#E0E0E0;
+ font-family:Courier, monospace;
+}
+h1 {
+ border-bottom:1px solid #DDDDDD;
+ padding:0 0 0 0;
+ margin:15px 0 15px 0;
+ font-size:14pt;
+}
+h1 img {
+ vertical-align:middle;
+ margin-bottom:4px;
+ margin-right:10px;
+}
+h2 {
+ margin:0 0 15px 0;
+ font-size:14pt;
+ color:#333333;
+}
+h3 {
+ margin:0 0 5px 0;
+ font-size:13pt;
+ color:#201E62;
+}
+h4 {
+ margin:0 0 5px 0;
+ font-size:12pt;
+ color:#333333;
+}
+span.subtitle {
+ color:#454545;
+ font-size:9pt;
+ font-weight:normal;
+ text-transform:uppercase;
+}
+span.small {
+ font-size:9pt;
+}
+span.gray {
+ color:gray;
+}
+span.type {
+ color:#201E62;
+ font-weight:bold;
+ font-size:9pt;
+}
+span.htitle {
+ color:#454545;
+ font-size:9pt;
+ font-weight:normal;
+}
+span.version {
+ font-size:8pt;
+ color:#888888;
+}
+input[type=text], input[type=password], input[type=email], input[type=tel], input[type=number], select, option {
+ min-width:260px;
+ padding:6px;
+ border:1pt solid #22606D;
+ vertical-align:bottom;
+ border-radius:0;
+}
+
+textarea {
+ padding:6px;
+ border:1pt solid #22606D !important;
+ border-radius:0 !important;
+}
+
+span.label {
+ font-size:11pt;
+ color:gray;
+ font-weight:normal;
+ padding:0;
+}
+div.el {
+ padding-bottom:15px;
+}
+div.breadcrumbs {
+ margin:15px 0;
+ color:gray;
+ font-size:10pt;
+}
+div.breadcrumbs a {
+ color:gray;
+}
+div.breadcrumbs a:hover {
+ text-decoration:underline;
+}
+.tab-pane {
+ padding-top:15px;
+}
+/* buttons */
+button.btn, input.btn {
+ padding:6px 10px;
+ border-radius:5px;
+ font-size:10pt;
+ font-weight:normal;
+}
+button.btn span.glyphicon {
+ margin-right:6px;
+}
+button.btn-default {
+ border-bottom:3px solid #cccccc;
+}
+button.btn-default:hover {
+ background-color:white;
+ border:1px solid #ADADAD;
+ border-bottom:3px solid #ADADAD;
+}
+button.btn-default:active {
+ background-color:white;
+ border:1px solid #ADADAD;
+ border-bottom:1px solid #ADADAD;
+ margin-top:2px;
+ box-shadow:none;
+}
+button.btn-primary {
+ border-bottom:3px solid #3071A9;
+}
+button.btn-primary:hover {
+ box-shadow:none;
+ background-color:#428bca;
+ border:1px solid #357ebd;
+ border-bottom:3px solid #3071A9;
+}
+button.btn-primary:active {
+ box-shadow:none;
+ border-bottom:1px solid #3071A9;
+ margin-top:2px;
+}
+button.btn-danger {
+ border-bottom:3px solid #A13F3A;
+}
+button.btn-danger:hover {
+ box-shadow:none;
+ background-color:#d9534f;
+ border:1px solid #d43f3a;
+ border-bottom:3px solid #A13F3A;
+}
+button.btn-danger:active {
+ border:1px solid #d43f3a;
+ box-shadow:none;
+ margin-top:2px;
+}
+button.btn-onelab, input.btn-onelab {
+ border:0;
+ border-bottom:3px solid #760073;
+ background-color:#302562;
+ color:white;
+}
+button.btn-onelab:hover, input.btn-onelab:hover {
+ border:0;
+ border-bottom:3px solid #760073;
+ background-color:#302562;
+ color:white;
+}
+button.btn-onelab:active, input.btn-onelab:active {
+ box-shadow:none;
+ border-bottom:1px solid #760073;
+ margin-top:2px;
+}
+
+.container-resource button {
+ padding:2px 4px;
+ border-radius:3px;
+ font-size:9pt;
+ font-weight:normal;
+}
+.container-resource select,.container-resource option, .container-resource input {
+ padding:2px 4px;
+ font-size:9pt;
+}
+.badge {
+ font-size:9pt;
+ margin-left:4px;
+}
+/***** Notifications *****/
+.warning {
+ border: 1px solid red;
+ margin: 20px 60px;
+ padding: 10px 20px;
+ color: red;
+ background-color: #f2dbdb;
+ text-align: center;
+}
+
+/* HOME DASHBOARD */
+div#home-dashboard {
+ color:black;
+ margin:0 auto 25px auto;
+}
+div#home-dashboard table {
+ margin:25px;
+ width:100%;
+}
+div#home-dashboard table td {
+ text-align:center;
+ padding:15px 0;
+ width:33%;
+}
+div#home-dashboard table tr:first-child td {
+ font-size:12pt;
+ font-weight:bold;
+ color:#270A5A;
+}
+div#home-dashboard table tr:last-child td {
+ vertical-align:top;
+ padding:25px 0;
+}
+div#home-dashboard table tr:last-child td.logged-in {
+ border-right:1px solid #DDDDDD;
+ padding:25px;
+}
+div#home-dashboard table tr:last-child td.support {
+ border-left:1px solid #DDDDDD;
+ padding:25px;
+}
+div#home-dashboard table tr:last-child td:first-child {
+}
+div#home-dashboard table tr:last-child td:last-child {
+ border-right:0;
+}
+div#home-dashboard table tr:last-child td.logged-in div {
+ text-align:left;
+ padding:25px 0;
+}
+div#home-dashboard table tr:last-child td.support div {
+ text-align:left;
+ padding:25px 0;
+}
+div#home-dashboard div.login-widget {
+ padding:20px;
+}
+div#home-dashboard table td.support {
+}
+div#home-dashboard table td.support a {
+}
+div#home-dashboard table td.support a:hover {
+ text-decoration:none;
+}
+
+div#home-dashboard div#manager {
+ display:none;
+}
+
+div#home-dashboard div#home-slice-list {
+ margin:25px 0;
+ padding:0 25px;
+ text-align:left;
+}
+div#home-dashboard div#home-slice-list ul {
+ list-style: none;
+ padding:0;
+ margin:0;
+}
+div#home-dashboard div#home-slice-list li {
+
+}
+
+/**/
+
+/**/
+/* WELL */
+div.well {
+}
+/**/
+/* TABLE */
+table.table {
+ margin:0;
+}
+table.table thead {
+ padding:0;
+}
+table.table tbody {
+ padding:0;
+}
+table.table tr {
+ padding:0;
+}
+table.table td {
+ padding:0;
+}
+/* INSTITUTION */
+div#institution {
+ color:black;
+}
+.form-hint {
+ font-size:11pt;
+ font-style:italic;
+ color:gray;
+}
+
+
+.form-hint {
+ font-size:11pt;
+ font-style:italic;
+ color:gray;
+}
+
+
+
+/* TICKET REQUEST */
+div#ticket-request {
+ color:black;
+}
+.form-hint {
+ font-size:11pt;
+ font-style:italic;
+ color:gray;
+}
+div#ticket-request p {
+ margin:20px 0;
+}
+
+ul.nav-tabs {
+ margin:0 0 15px 0;
+}
+ul.nav-tabs ul {}
+ul.nav-tabs li {}
+
+ul.nav-section li a {
+ color:black;
+ border-bottom:0;
+}
+ul.nav-section li:first-child {
+ padding:0;
+}
+ul.nav-section li:first-child a {
+}
+ul.nav-section li:first-child.active a {
+}
+
+ul.nav-resources {
+ margin:15px 0;
+}
+ul.nav-resources a {
+ padding: 4px 10px 5px 10px;
+}
+
+/* SLICE VIEW */
+div.container-resource, div.container-slice {
+ padding-right:15px;
+ padding-left:15px;
+}
+.table th {
+ border-top:0 !important;
+}
+div#slice-view {
+ margin:0;
+}
+div.list-group-item {
+ border:0;
+ -moz-border-radius: 0;
+ border-radius: 0;
+ background-color:white;
+ font-weight:bold;
+ padding-left:0;
+}
+a.list-group-item {
+ -moz-border-radius: 0;
+ border-radius: 0;
+ border:0;
+ background-color:white;
+ padding:3px 2px 3px 10px;
+ border-left:2pt white solid;
+}
+a.list-group-item.active, a.list-group-item.active:hover, a.list-group-item.active:focus {
+ -moz-border-radius: 0;
+ border-radius: 0;
+ font-weight: bold;
+ color:black;
+ background-color:#F5F5F5;
+ border-left:2pt blue solid;
+}
+
+a.list-group-item:hover {
+ -moz-border-radius: 0;
+ border-radius: 0;
+ border-left:2pt blue solid;
+}
+a.list-group-item p.list-group-item-text {
+ -moz-border-radius: 0;
+ border-radius: 0;
+ font-size:9pt;
+ font-style:italic;
+ font-weight: normal;
+ color: black !important;
+}
+
+span.sl-resources {
+ font-size:9pt;
+ color:gray;
+}
+a.sl-resources, a.sl-resources:hover {
+ font-size:9pt;
+ border:0;
+ padding:2px 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ width:105px;
+ margin-left:4px;
+ margin-bottom:8px;
+ text-align: center;
+}
+a.sl-resources.active, a.sl-resources.active:hover, a.sl-resources.active:focus {
+ border:0;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+a.sl-resources:first-child {
+ margin-left:12px;
+}
+button.btn-apply {
+ font-size:13px;
+ padding:2px 8px;
+}
+div#slice-info {
+ margin-top:25px;
+}
+div#slice-info table {
+ width:100%;
+ margin:0 auto;
+}
+div#slice-info table td:first-child {
+ text-align:right;
+ font-weight:bold;
+ padding-right:15px;
+}
+div#slice-info td {
+ padding:5px;
+}
+
+/* SLICE VIEW sections */
+.slice-sections, .slice-pending {
+ margin:0;
+ padding:0;
+}
+.slice-sections ul, .slice-pending ul {
+ margin:0;
+ padding:0;
+}
+.slice-pending ul {
+ width:400px;
+ margin:0 auto 15px auto;
+}
+.slice-sections li {
+ text-align:left;
+ margin:0;
+ padding:0;
+}
+.slice-pending li {
+ padding-right:15px;
+}
+.slice-sections li a, .slice-pending li a {
+ font-size:14px;
+ color:black;
+ padding:0;
+}
+.slice-sections li.active a, .slice-pending li.active a {
+ color:#201E62;
+ background-color:#EFEFEF;
+ text-decoration:underline;
+ padding:0;
+}
+.slice-sections ul.nav-pills li a:hover, .slice-pending ul.nav-pills li a:hover {
+ text-decoration:underline;
+ background-color:#EFEFEF;
+ color:black;
+}
+.slice-sections ul.nav-pills li.active, .slice-pending ul.nav-pills li.active {
+
+}
+.slice-sections li:first-child, .slice-sections li:first-child a {
+ color:#201E62;
+ font-weight:bold;
+}
+.slice-experiment {
+ text-align:right;
+ padding:0;
+}
+.slice-experiment button {
+ margin:3px 0 0 0;
+ background-color:#CC4125;
+ color:white;
+}
+
+.slice-pending {
+}
+.slice-pending button {
+ font-size:9pt;
+ margin:-2px 0 0 0;
+ padding:3px 5px;
+}
+.slice-pending button.apply {
+ font-size:14px;
+ padding:2px 5px;
+}
+.slice-pending button.clear {
+}
+tr.active, tr.active td {
+ background-color:#FFFFCC !important;
+}
+div.dataTables_filter label{
+ float:left;
+ width:400px;
+}
+
+/* HEADER */
+
+
+.header {
+ -moz-box-shadow: 0 0 1px rgba(82,82,82,0.6);
+ -webkit-box-shadow: 0 0 1px rgba(82,82,82,0.6);
+ box-shadow: 0 0 1px rgba(82,82,82,0.6);
+ height:61px;
+ background-color:white;
+}
+
+div.navigation {
+
+}
+div.navigation ul {
+ margin:26px 0 0 0;
+ padding:0;
+ display: inline-block;
+ list-style-type: none;
+ white-space: nowrap;
+}
+
+div.navigation li {
+ color:#0C0047;
+ font-family:open_sansbold, sans-serif;
+ font-size:9pt;
+ font-weight:normal;
+ line-height:0.8em;
+ letter-spacing:0.4pt;
+ list-style:none;
+ float:left;
+ padding:0 15px;
+ margin:0;
+ text-transform:uppercase;
+}
+div.navigation li:hover {
+}
+div.navigation li a {
+ color:#0C0047;
+}
+div.navigation li a:hover, div.navigation li a.current {
+ color:#760073;
+ text-decoration:none;
+}
+
+div.navigation li:last-child {
+ margin-right:0;
+}
+
+
+div.navigation .dropdown-menu {
+ color:black;
+ -moz-box-shadow: 1px 1px 0px 0 rgba(58, 48, 100,0.8);
+ -webkit-box-shadow: 1px 1px 0px 0 rgba(58, 48, 100,0.8);
+ box-shadow: 1px 1px 0px 0 rgba(58, 48, 100,0.8);
+ border-radius:2px;
+ padding:0 5px 5px 5px;
+ margin-top:5px;
+ margin-left:20px;
+}
+div.navigation .dropdown-menu ul {
+ margin:0;
+ padding:15px 5px 5px 5px;
+ display:list-item;
+}
+div.navigation .dropdown-menu li {
+ margin:0 10px 0 0;
+ padding:0 0 8px 0;
+ display:list-item;
+ float:none;
+ text-transform: none;
+}
+
+div.navigation .dropdown-menu a {
+ font-family:Helvetica,sans-serif;
+ font-size:10pt;
+ color:black;
+}
+div.navigation .dropdown-menu li.title {
+ margin-bottom:10px;
+}
+div.navigation .dropdown-menu li.title a {
+ font-family:open_sansbold, sans-serif;
+}
+
+
+div.navigation .dropdown-menu li:first-child {
+ border-bottom:1px solid white;
+ padding-bottom:5px;
+
+}
+
+div.secondary {
+ text-align:right;
+}
+
+div.secondary ul {
+ margin:6px 0 0 0;
+ padding:0;
+}
+
+div.secondary li {
+ font-size:9pt;
+ display:inline;
+ list-style:none;
+ margin:0px;
+ padding:0;
+ margin-right:15px;
+ color:#747474;
+ letter-spacing:0.4px;
+}
+div.secondary li:last-child {
+ margin-right:0;
+}
+div.secondary li a {
+ color:#747474;
+}
+div.secondary li a:hover {
+ text-decoration:underline;
+}
+div.secondary .button {
+ width:300px;
+ margin-top:15px;
+}
+div.secondary .account {
+ margin-top:10px;
+ padding:0;
+ font-size:9pt;
+ color:gray;
+ text-align:right;
+}
+div.secondary .account span {
+ font-size:8pt;
+}
+div.secondary .account a {
+ color:black;
+}
+
+
+div.footer {
+ padding-top:15px;
+}
+div.footer div.bottom {
+ position:absolute;
+ bottom:0;
+}
+div.footer ul {
+ margin:6px 0 0 0;
+ padding:0;
+}
+
+div.footer li {
+ font-size:9pt;
+ display:inline;
+ list-style:none;
+ margin:0px;
+ padding:0;
+ margin-right:15px;
+ color:#747474;
+ letter-spacing:0.4px;
+}
+
+div.footer li a {
+ color:#747474;
+}
+div.footer li a:hover {
+ text-decoration:underline;
+}
+div.copy {
+ font-size:8pt;
+ color:gray;
+ padding-top:15px;
+ padding-bottom:15px;
+}
+
+div.home {
+ font-size:11pt;
+ line-height:1.2em;
+ letter-spacing:0.3pt;
+ min-height:500px;
+ //background-image: url('../img/bg-experiment.png');
+ background-repeat:no-repeat;
+ background-size:cover;
+ background-position:center top;
+ background-color:#4FABA3;
+ padding:100px 0;
+}
+div.home h2 {
+ color:white;
+ line-height:1.2em;
+ font-size:18pt;
+}
+div.home h3 {
+ color:white;
+ line-height:1.4em;
+}
+div.dashboard {
+ text-align:center;
+}
+div.dashboard div {
+ margin:25px 0;
+}
+div.dashboard ul {
+ text-align:left;
+ margin-left:24px;
+ list-style:none;
+}
+div.registration-form {
+ padding-top:150px;
+ text-align:center;
+}
+
+.login-form input {
+ width:320px;
+}
+.login-form input[type=submit] {
+ width:108px;
+}
+
+.login-submit {
+ vertical-align:middle;
+ padding:0;
+}
+.lost-password {
+ font-size:10pt;
+ color:black;
+ text-align:right;
+ padding:0px;
+}
+.lost-password a {
+ color:white;
+ text-shadow:0.5px 0.5px black;
+}
+.login-signup {
+ font-size:12pt;
+ color:white;
+ text-shadow:0.5px 0.5px black;
+ margin-top:45px;
+ padding:5px 0 0 4px;
+
+}
+.login-signup a {
+ color:white;
+ text-shadow:0.5px 0.5px black;
+ padding-bottom:2px;
+ border-bottom:2pt solid white;
+}
+.login-signup a:hover {
+ text-decoration:none;
+}
+.login-signup button {
+ padding:8px;
+ border:0;
+ border-bottom:2px solid #540086;
+ background-color:#302562;
+ color:white;
+ width:100px;
+ border-radius:5px;
+ font-size:12pt;
+}
+div.slogan {
+ text-align:center;
+ color:white;
+ padding-top:60px;
+ text-shadow: 1px 1px #013540;
+}
+
+th {
+ border:0 !important;
+}
+
+div.monitor {
+ padding:40px 0 25px 0;
+}
+div.monitor h1 {
+ margin-bottom:25px;
+}
+div.s-monitor {
+ padding-bottom:25px;
+}
+span#stats-period-txt {
+ text-transform:lowercase;
+}
--- /dev/null
+<form action="//portal.onelab.eu/login/" method="post" role="form">
+{% csrf_token %}
+<div class="form-group">
+ <input class="input-md" type="email" name="username" placeholder="Enter Email / Username">
+</div>
+<div class="form-group">
+ <input type="password" name="password" placeholder="Password">
+</div>
+<div class="login-submit">
+ <input type="submit" class="btn btn-onelab" value="Sign In" />
+ <span class="lost-password"> | <a href="http://portal.onelab.eu/portal/pass_reset/">Can't access your account?</a></span>
+</div>
+<div class="login-signup">
+ You don't have an account yet?
+ <br /><a href="http://portal.onelab.eu/register">Sign Up!</a>
+</div>
+</form>
\ No newline at end of file
<div class="row">
<div class="col-md-12">
- <h1><img src="{{ STATIC_URL }}icons/user-xs.png" alt="User Registration" />User sign-up</h1>
+ <h1><img src="{{ STATIC_URL }}icons/user-xs.png" alt="User Registration" />User sign-up</h1>
</div>
</div>
<div class="row">
<div class="col-md-12">
- <p><strong>Questions? <a href="/portal/contact" >Contact us.</a></strong></p>
- </div>
+ <p><strong>Questions? <a href="/contact" >Contact us.</a></strong></p>
+ </div>
</div>
{% if errors %}
<div class="row">
<div class="col-md-12">
- <ul>
+ <ul class="error">
{% for error in errors %}
- <li>{{ error }}</li>
+ <li>{{ error | safe }}</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %}
+ <form action="/register" class="cmxform form-horizontal" method="post" enctype="multipart/form-data">
<div class="row">
<div class="col-md-12">
-
<div class="form-group">
- <form class="cmxform form-horizontal" id="registrationForm" method="post" enctype="multipart/form-data" role="form">
- {% csrf_token %}
+ {% csrf_token %}
<label for="authority_hrn" class="control-label">Organization</label>
<p></p>
- <input id="authority_hrn" name="org_name" class="form-control" style="width:590px" value="{{ organization }}"
+ <div class="ui-widget">
+ <select id="org_name" name="org_name" class="form-control" style="width:590px" value="{{ organization }}"
title="Choose your organization (company/university) from the list that apears when you click in the field and start to type.
- Use the arrow keys to scroll through the list; type part of the name to narrow down the list. If it is not in the list,
- please request its addition by clicking the link below. We will send an email to the managers that we have on record for
- your organization, asking them to validate your sign-up request." required/>
+ Use the arrow keys to scroll through the list; type part of the name to narrow down the list. We will send an email to
+ the managers that we have on record for your organization, asking them to validate your sign-up request." required>
+ {% if authorities %}
+ {% for authority in authorities %}
+ {% if authority.name %}
+ <option value="{{ authority.authority_hrn }}">{{authority.name}}</option>
+ {% else %}
+ <option value="{{ authority.authority_hrn }}">{{authority.authority_hrn}}</option>
+ {% endif %}
+ {% endfor %}
+ {% else %}
+ <option value:"">No authority found !!!</option>
+ {% endif %}
+ </select>
+ </div>
<p></p>
<p>Organization not listed? <a href="/portal/join">Request its addition now.</a></p>
</div>
<div class="form-group">
<input type="email" name="email" size="25" class="form-control" style="width:350px" value="{{ email }}"
title="Your e-mail address will be your identifier for logging in. We contact you to verify your account and then, occasionally, for important issues."
- placeholder="Email" required/>
+ placeholder="Email" required />
</div>
</div>
placeholder="Confirm password" required />
</div>
<div class="form-group">
- <!--<label for="question" class="control-label">Keys</label> -->
<select name="question" class="form-control" style="width:350px" id="key-policy"
- title="Your public/private key pair allows you to access the testbeds." required>
+ title="Your public/private key pair allows you to access the testbeds." required >
<option value="generate">Generate my keys for me (recommended)</option>
<option value="upload">Upload my public key (advanced users only)</option>
</select>
</div>
<div class="form-group" style="display:none;" id="upload_key">
<label for="file" class="control-label">Upload public key</label>
- <input type="file" name="user_public_key" class="form-control" style="width:200px" id="user_public_key" required/>
+ <input type="file" name="user_public_key" class="form-control" style="width:200px" id="user_public_key" />
<br />
<div class="alert alert-danger" id="pkey_del_msg">
In order for the portal to contact testbeds on your behalf, so as to list and reserve resources, you will need to
- <a href="http://trac.myslice.info/wiki/InstallSfa" target="_blank">delegate your public key to the portal.</a>
+ <a href="/portal/manual_delegation" target="_blank">delegate your credentials to the portal.</a>
</div>
</div>
</div>
<div class="col-md-12">
<div class="form-group">
<p></p>
- <input type="checkbox" name="agreement" value="agreement" required/> I agree to the
+ <input type="checkbox" name="agreement" value="agreement" required /> I agree to the
<a href="#" data-toggle="modal" data-target="#myModal">terms and conditions.</a>
</div>
</div>
<div class="col-md-12">
<div class="form-group" id="register">
<p></p>
- <button class="submit btn btn-onelab" type="submit">Sign up</button>
+ <input class="submit btn btn-onelab" type="submit" value="Sign up" />
+ </form>
</div>
- </form>
</div>
</div>
-
-
+
<!-- Modal - columns selector -->
- <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
</div>
<div class="modal-body">
<p align="left">
- for OneLab Basic level service
- <br/>
- Version 0.6 of 20 May 2014
- <br>
- <a href="/portal/terms" target="_blank">[Printable format]</a>
+ To be added soon.
</p>
- <h1 align="left">1 Context</h1>
- <h2 align="left">1.1 OneLab</h2>
- <p align="left">
- OneLab is an experimental facility for testing new ideas and new technologies in the area of computer networking. It consists of a variety of types of
- platforms, including:</p>
- <ul type="disc">
- <li>
- <strong>internet overlay testbeds</strong>
- , testbeds that offer virtual machines distributed across locations in different countries, allowing users to deploy overlays on the internet;
- </li>
- <li>
- <strong>wireless testbeds</strong>
- , testbeds that consist of clusters of computers that are within Wi-Fi communication range of each other, either in an office environment or in an
- isolated setting;
- </li>
- <li>
- <strong>internet of things testbeds</strong>
- , testbeds that consist of embedded computing nodes with sensor capabilities, communicating wirelessly in an isolated environment;
- </li>
- <li>
- <strong>emulation testbeds,</strong>
- computing clusters that offer virtual machines on servers that are interconnected by a high speed switch, enabling large scale network emulation.
- </li>
- </ul>
- <p align="left">
- This list of types of platforms is subject to change, and the current list, along with the identities of the specific platforms of each type, can be found
- on the OneLab website (onelab.eu).</p>
- <p align="left">
- Each platform has its own owners, and OneLab is the grouping of these platforms through a consortium of institutions. The OneLab consortium is coordinated
- by UPMC Sorbonne Universités. It operates on a not-for-profit basis.</p>
- <p align="left">
- Access to OneLab may also provide access to additional platforms that are not part of OneLab, due to a federation agreement between OneLab and the owners
- of those platforms.</p>
- <h2 align="left">1.2 Fee-free Basic level service</h2>
- <p align="left">These terms and conditions define and apply to OneLab's Basic level service, which is available free of charge.</p>
- <p align="left">
- Users who would like additional services are encouraged to contact support@onelab.eu. Some additional services require a written agreement, but are
- otherwise free. Others require the payment of fees or in-kind contributions. (An example of an in-kind contribution is the hosting of a PlanetLab Europe
- server node.)</p>
- <h2 align="left">1.3 Managers and standard users</h2>
- <p align="left">
- There are two classes of OneLab user: the manager and the standard user. OneLab grants access rights to managers, who, in turn, provide access rights to
- standard users. Examples are: for a small enterprise, an executive may be the manager and the employees may be standard users; for a research team, a
- senior scientist (faculty member or research scientist) may be a manager and doctoral students and other members of the team may be standard users; for a
- university course, a professor may be a manager and the students may be standard users.</p>
- <h2 align="left">1.4 These terms and conditions</h2>
- <p align="left">
- Acceptance of these terms and conditions is a condition of obtaining OneLab Basic level user service. They are posted to the OneLab portal site
- (portal.onelab.eu). They may be changed without other notice than the posting of a new version to the portal site.</p>
- <h1 align="left">2 Services provided by OneLab</h1>
- <h2 align="left">2.1 Access to the experimental facility</h2>
- <p align="left">
- OneLab provides users with access to the platforms that make up the experimental facility. Each platform owner determines the specifics of this access (for
- example, how many nodes are available to a user, what happens in case of oversubscription, etc.), with the proviso that Basic level service requires that
- users be able to conduct meaningful experiments on every OneLab testbed.</p>
- <p align="left">
- Basic level service may also provide access to platforms that are federated with OneLab, but such access depends upon the terms of the federation
- agreements with those platforms, which may require that the user have a higher level of service in order to gain access. For example, Basic level service
- provides access to PlanetLab Europe, a OneLab platform, without providing access to PlanetLab Central, a federated platform. Users wanting full access
- across the global PlanetLab system should contact support@onelab.eu to arrange to enter into a PlanetLab Europe membership agreement.</p>
- <p align="left">OneLab's role is to facilitate access to the platforms. Specifically, it provides each user with:</p>
- <ul>
- <li align="left">
- <strong>a single account,</strong>
- the credentials for which can be used to access all of the OneLab testbeds;
- </li>
- <li align="left">
- <strong>tools through which to access the testbeds</strong>
- , including, notably, a web-based portal (portal.onelab.eu) that allows a user to see the resources available on each testbed and to reserve them,
- along with a number of experiment control tools that a user can employ to deploy an experiment on those resources;
- </li>
- <li align="left">
- <strong>support</strong>
- , with documentation on how to use the tools, pointers to documentation for individual testbeds, and a helpdesk to respond to user questions.
- </li>
- </ul>
- <p align="left">
- Additional support, such as accompaniment through the design and deployment of experiments and the interpretation of their results, is available through
- higher levels of service.
- </p>
- <h2 align="left">
- 2.2 Best effort, without guarantees
- </h2>
- <p align="left">
- OneLab and the owners of the individual OneLab testbeds do their best to provide the services outlined here, with the understanding that Basic level
- service offers no guarantees. Users should clearly understand the following limitations.
- </p>
- <ul type="disc">
- <li>
- <strong>Reliability:</strong>
- OneLab does not provide any guarantees with respect to the reliability of the portal, of other tools, or of the individual nodes on platforms. These
- may be taken down for maintenance, rebooted, or reinstalled at any time. Reinstallation implies that disks are wiped, meaning that users should not
- consider a local disk to be a persistent form of storage.
- </li>
- <li>
- <strong>Fitness:</strong>
- OneLab does not guarantee that the platforms are suitable for the experiments that users intend to conduct. There may be limitations in the
- technologies that are offered that prevent certain types of experiments from being carried out.
- </li>
- <li>
- <strong>Privacy</strong>
- : OneLab does not guarantee the privacy of traffic generated on the platforms (e.g., wireless signals, packets). Unless otherwise specified by an
- individual platform owner, users should assume that traffic is monitored and logged. Such monitoring may be done intentionally, for example, to allow
- platform administrators as well as other users to investigate abuse.
- </li>
- </ul>
- <p align="left">
- Users who seek such guarantees are invited to consider a higher level of service.
- </p>
- <h2 align="left">
- 2.3 Limitedliability
- </h2>
- <p align="left">
- In no event shall the partners of the OneLab consortium be liable to any user for any consequential, incidental, punitive, or lost profit damages, or for
- any damages arising out of loss of use or loss of data, to the extent that such damages arise out of the activities of OneLab consortium partners, or any
- breach of the present terms and conditions, even if the consortium partner has been advised of the possibility of such damages.
- </p>
- <p align="left">
- Nothing contained in these terms and conditions shall be deemed as creating any rights or liabilities in or for third parties who are not Basic level users
- of OneLab.
- </p>
- <h1 align="left">
- 3 Acceptable use policy
- </h1>
- <h2 align="left">
- 3.1 Responsibilities of managers and standard users
- </h2>
- <p align="left">
- OneLab creates and administers accounts for managers and delegates to managers the responsibility for creating and administering accounts for standard
- users. Both managers and standard users are required to follow OneLab's acceptable use policy. In addition, managers are fully responsible for the
- activities of the standard users whose accounts they create.
- </p>
- <p align="left">
- A manager is expected to grant user access only an individual with whom he or she has a working relationship. In general, this means an individual who
- works for the same institution as the manager, or, in the case of higher education and research, an individual who is a student at the university where the
- manager works. Managers may also grant access to individuals from other institutions, provided that they are collaborating on a common project on OneLab.
- If there is a doubt, a manager should refer the question to support@onelab.eu.
- </p>
- <h2 align="left">
- 3.2 Types of use
- </h2>
- <p align="left">
- OneLab may be used by enterprise, by scientific researchers, and by educators.
- </p>
- <p align="left">
- OneLab may be used for pre-commercial research and development. In keeping with OneLab's not-for-profit status, it may not be used to deploy services that
- are designed to generate a commercial profit.
- </p>
- <p align="left">
- Not-for-profit use of OneLab to deploy services that are designed to generate revenue requires prior approval through a written agreement, and thus may not
- be carried out on a Basic level account. Interested users are invited to contact support@onelab.eu.
- </p>
- <p align="left">
- OneLab may be used for scientific research.
- </p>
- <p align="left">
- OneLab may be used to host lab exercises for university courses.
- </p>
- <p align="left">
- Questions about other types of use should be addressed to support@onelab.eu.
- </p>
- <h2 align="left">
- 3.3 Applicable laws and regulations
- </h2>
- <p align="left">
- OneLab is managed, and the portal is hosted, in France. Information regarding the countries in which individual testbeds are managed and hosted is
- available from those testbeds. Users are responsible for being aware of the countries in which their experiments are deployed and for ensuring that their
- use of OneLab fully conforms to the laws and regulations of those countries, as well as the laws and regulations of the country in which they themselves
- are present when conducting their experiments.
- </p>
- <p align="left">
- Above and beyond specific national laws, the activities email spamming, phishing through web services, and all types of Internet fraud are prohibited on
- OneLab.
- </p>
- <h2>
- 3.4 Security and accounting mechanisms
- </h2>
- <p align="left">
- Users are expected to respect the security and accounting mechanisms put in place by OneLab, its platforms, and federated platforms. For example, access to
- PlanetLab Europe is designed to take place through the SSH cryptographically-secured connection protocol, which uses public/private key pair
- authentication, and so users should not attempt to bypass this mechanism. As another example, OneLab's notion of a "slice" associates a set of resources
- with the group of users who have reserved those resources, and users should not attempt to obscure the identities of participants in a slice.
- </p>
- <p align="left">
- Hacking attempts against the OneLab portal and testbeds are not permitted. This includes "red team" (hacker test) experiments.
- </p>
- <h2>
- 3.5 Sharing of resources
- </h2>
- <p align="left">
- OneLab is intended for ambitious experiments. Large numbers of resources and extended leases on resources may legitimately be granted in order to carry
- these out. At the same time, OneLab and its testbeds are shared environments, and when there is contention for resources, limits must be imposed.
- </p>
- <p align="left">
- Each OneLab platform sets its own policies for handling resource contention. As a general rule, users are encouraged to design their experiments to use
- resources efficiently. In particular, spinning/busy-waiting techniques for extended periods of time are strongly discouraged. Some resource contention
- policies (e.g., PlanetLab Europe's) terminate the jobs that are using the most resources in the case of contention.
- </p>
- <h2>
- 3.6 Internet-connected platforms
- </h2>
- <p align="left">
- Some of OneLab's platforms allow experiments to take place on resources that have access to the public internet. These experiments can potentially generate
- traffic to, and receive traffic from, any host or router in the internet.<a></a><a id="_anchor_1" href="#_msocom_1" name="_msoanchor_1">[LB1]</a>
- </p>
- <p align="left">
- Furthermore, some internet-connected platforms (e.g., PlanetLab Europe) consist of servers that are hosted by a large number of member institutions.
- </p>
- <p align="left">
- The accessibility of internet-connected platforms and the distributed hosting model of some of these platforms imply certain responsibilities on the part
- of users, as detailed below.
- </p>
- <h3>
- 3.6.1 General guidance
- </h3>
- <p align="left">
- A good litmus test when considering whether an experiment is appropriate for such internet-connected platforms is to ask what the network administrator at
- one's own organisation would say about the experiment running locally. If the experiment disrupts local activity (e.g., uses more than its share of the
- site's internet bandwidth) or triggers complaints from remote network administrators (e.g., performs systematic port scans), then it is not appropriate for
- such internet-connected platforms.
- </p>
- <p align="left">
- It is the responsibility of the user and the user's manager to ensure that an application that will run on an internet-connected platform is tested and
- debugged in a controlled environment, to better understand its behaviour prior to deployment.
- </p>
- <h3>
- 3.6.2 Standards of network etiquette
- </h3>
- <p align="left">
- Internet-connected platforms are designed to support experiments that generate unusual traffic, such as network measurements. However, it is expected that
- all users adhere to widely accepted standards of network etiquette in an effort to minimise complaints from network administrators. Activities that have
- been interpreted as worm and denial-of-service attacks in the past (and should be avoided) include sending SYN packets to port 80 on random machines,
- probing random IP addresses, repeatedly pinging routers, overloading bottleneck links with measurement traffic, and probing a single target machine from
- many nodes.
- </p>
- <p align="left">
- For internet-connected platforms that have a distributed hosting model, each host institution will have its own acceptable use policy. Users should not
- knowingly violate such local policies. Conflicts between local policies and OneLab's stated goal of supporting research into wide-area networks should be
- brought to the attention of OneLab administrators at support@onelab.eu.
- </p>
- <h3>
- 3.6.3 Specific network usage rules
- </h3>
- <p align="left">
- It is not allowed to use one or more nodes of an internet-connected platform to generate a high number of network flows or flood a site with high traffic
- to the point of interfering with its normal operation. Use of congestion-controlled flows for large transfers is highly encouraged.
- </p>
- <p align="left">
- It is not allowed to perform systematic or random port or address block scans from an internet-connected platform.
- </p>
- <p align="left">
- For internet-connected platforms that use a distributed hosting model, it is not allowed to spoof or sniff traffic on a hosted server or on the network the
- server belongs to.
- </p>
- <p align="left">
- Access to a server on a distributed hosting platform may not be used to gain access to other servers or networked equipment that are not part of the
- testbed.
- </p>
- <h2>
- 3.7 Wireless platforms
- </h2>
- <p align="left">
- Wireless-connected platforms give users access to nodes that communicate via Wi-Fi and other wireless technologies. They may be capable of detecting
- wireless activity in the neighbourhood of those nodes: traffic generated by other users of the platform or by individuals not associated with the platform.
- In general, much of the traffic will be encrypted, with certain aspects (such as SSIDs) not encrypted, but it is also possible that there will be fully
- unencrypted traffic. They may also be capable of generating wireless activity that reaches equipment outside of the testbed.
- </p>
- <p align="left">
- Furthermore, some wireless-connected platforms may have built-in limitations to prevent them from generating signals at a strength that exceeds health and
- safety regulations.
- </p>
- <p align="left">
- These characteristics of wireless-connected platforms imply certain responsibilities on the part of users, as detailed below.
- </p>
- <h3>
- 3.7.1 Specific network usage rules
- </h3>
- <p align="left">
- Experimenters may make no attempt to defeat the encryption of encrypted third-party traffic. Furthermore, experimenters must treat with utmost discretion
- any unencrypted traffic. Limited metadata can be recorded for the bona fide purposes of an experiment, but under no case should third party communications
- be recorded.
- </p>
- <p align="left">
- No attempt may be made to reverse engineer traffic in order to learn the identities of the parties who have generated the traffic.
- </p>
- <p align="left">
- Wireless-connected platforms may not be used to gain access to any network equipment that is not part of the testbed itself.
- </p>
- <p align="left">
- It is not allowed to perform systematic or random scans of wireless networks that are not part of a wireless-connected platform. Similarly, it is not
- allowed to spoof or sniff wireless traffic of the institution that hosts a wireless-connected platform or of other networks in the proximity.
- </p>
- <p align="left">
- Care must be taken so that traffic on wireless-connected platforms does not interfere with the normal functioning of network equipment that is not part of
- the testbed itself.
- </p>
- <p align="left">
- No attempt may be made to defeat the mechanisms that limit signal strength on wireless-connected platforms.
- </p>
- <h2>
- 3.8 Handling suspected violations
- </h2>
- <p align="left">
- Suspected violations of the OneLab acceptable use policy should be reported to support@onelab.eu.
- </p>
- <p align="left">
- Upon notification or detection of a possible violation, OneLab management will attempt to understand if a violation has in fact occurred. To do so,
- management will freely communicate with the users concerned, the operators of the platforms concerned, as well as any third parties that might be involved.
- An example of a third party is a network operator who detects what they believe to be unauthorized traffic emanating from a OneLab platform.
- </p>
- <p align="left">
- The priority is to resolve any real or apparent violations amicably. However, if OneLab management believes that a violation may have occurred, it can, at
- its sole discretion, and without prior notice, apply any of the following measures:
- </p>
- <ul type="disc">
- <li>
- notification of the users of the concerned slice (set of resources);
- </li>
- <li>
- disabling of the concerned slice;
- </li>
- <li>
- disabling an individual user's account;
- </li>
- <li>
- reporting of the user's activity to his/her manager;
- </li>
- <li>
- disabling of the manager's account and all user accounts for which the manager is responsible;
- </li>
- <li>
- disabling of all accounts associated with the user's institution.
- </li>
- </ul>
- <p align="left">
- In the case of suspected illegal activity, OneLab management might need, without prior notice, to notify the relevant authorities.
- </p>
</div>
<div class="modal-footer">
<script>
-jQuery(document).ready(function(){
+$(document).ready(function(){
var availableTags = [
{% if authorities %}
{% for authority in authorities %}
{% if authority.name %}
- {value:"{{ authority.name }}",label:"{{authority.name}}"},
+ {value:"{{ authority.authority_hrn }}",label:"{{authority.name}}"},
// show hrn if we don't have the name
{% else %}
{value:"{{ authority.authority_hrn }}",label:"{{authority.authority_hrn}}"},
{% endif %}
];
// sorting the list
+
availableTags.sort(function(a,b){
var nameA=a.value.toLowerCase(), nameB=b.value.toLowerCase();
if (nameA < nameB) {
return 0;
});
// auto-complete the form
- jQuery( "#authority_hrn" ).autocomplete({
- source: availableTags,
- minLength: 0,
- change: function (event, ui) {
- if(!ui.item){
- //http://api.jqueryui.com/autocomplete/#event-change -
- // The item selected from the menu, if any. Otherwise the property is null
- //so clear the item for force selection
- jQuery("#authority_hrn").val("");
- }
- }
- //select: function( event, ui ) {console.log(jQuery(this))}
- });
- // for hover texts
- jQuery('[title!=""]').qtip();
+ jQuery("#org_name").combobox();
+ $('[title!=""]').qtip();
+ $("form").validate();
+ $("form").submit(function() {
+ if ($('select option:selected').val() == 'upload') {
+ if ($('input[name=user_public_key]').val() == '') {
+ alert('Please specify the key file to upload');
+ return false;
+ }
+ }
+ });
});
</script>
{% endblock %}
</div>\r
<div id="tabs-2">\r
<h1>Experiment Evaluation</h1>\r
- <p><b>List of your unrated experiments</b></p><div id="slicelist">\r
+ <p><b>List of your unrated experiments</b></p>\r
+ <div style=" width: 70% !important" id="slicelist">\r
\r
{% for aslice in slicelist %}\r
- <h3>Slice <b>{{ aslice.slice_hrn }}</b></h3>\r
+ <h3>Slice <b>{{ aslice.slice_hrn }}</b></h3>\r
<div style="padding-bottom:0;padding-top:0;">\r
<ul><li>\r
experiment from <b>{{ aslice.start_t }}</b> to <b>{{ aslice.end_t }}</b> | <a href="#" class="rate_button" data-resid={{ aslice.id }}>Rate it</a>\r
<div id="scoreform" style="display:none">\r
<ol>\r
<li>\r
- <span>How was your overall experience with NETMODE Testbed?</span> \r
+ <span>How was your overall experience with this Testbed?</span> \r
<div id="q1">\r
</div>\r
</li>\r
</div>\r
</li>\r
<li>\r
- Would you use NETMODE testbed again?\r
+ Would you use this testbed again?\r
<div id="q4">\r
<input type="radio" name="q4" value="1" />Yes\r
<input type="radio" name="q4" value="0" />No\r
\r
var data = jQuery.parseJSON('{{ json_data|safe }}');\r
\r
-\r
-\r
-\r
var resid = -1;\r
var q1 = -1;\r
var q2 = -1;\r
\r
$("a[data-resid='"+resid+"']").css("text-decoration", "line-through").unbind("click").removeAttr("href");\r
\r
- //TODO: check input if valid before submitting\r
+ //TODO: validate input before submitting\r
\r
sum = q1 + q2 + q3 + q4 + q5 + q6 + q7 +q8;\r
\r
} \r
}\r
\r
-\r
- \r
slicedata["user_eval"] = {'overall':q1, 'problems':q2, 'support':q3, 'reuse':q4, 'pay':q5, 'availability':q6, 'link_quality':q7, 'quality':q8};\r
testbeds_str = JSON.stringify(slicedata['testbeds'])\r
delete slicedata['testbeds'];\r
--- /dev/null
+{% extends "layout.html" %}
+{% block content %}
+
+<div class="row">
+ <div class="col-md-12">
+ <div class="breadcrumbs">
+ Account > <a href="/account">{{ person.email }}</a>
+ </div>
+ </div>
+ {%if 'no_creds' in user_cred %}
+ <p class="command"><a href="#" style="color:red" data-toggle="modal" data-target="#myModal">NO CREDENTIALS</a> are delegated to the portal!</p>
+{%endif%}
+
+</div>
+{% if messages %}
+<ul class="messages">
+ {% for message in messages %}
+ <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
+ {% endfor %}
+</ul>
+{% endif %}
+<div class="row">
+ <div class="col-md-12">
+ <ul class="nav nav-tabs nav-section">
+ <li class="active"><a href="#profile">User Profile</a></li>
+ <li><a href="#account">Account</a></li>
+ <li><a href="#access">Testbed Access</a></li>
+ </ul>
+ </div>
+</div>
+<div class="tab-content">
+ <div class="tab-pane active row" id="profile">
+
+ <div class="col-md-12">
+
+ <form id="editForm" method="post" action="account_process" enctype="multipart/form-data">
+ {% csrf_token %}
+ <table class="profile">
+ <tr>
+ <td colspan="2">
+ <div><h3>Platform: Myslice</h3></div>
+ </td>
+ </tr>
+ <tr>
+ <td class="key">Email</td>
+ <td class="value">
+ <span id="emailval" class="value" >{{ person.email }}</span>
+ <button class="btn btn-default" type="button" id="edit_email" onclick="editAlert();" title="To change your affiliation please contact the administrator">
+ <span class="glyphicon glyphicon-question-sign"></span> Edit
+ </button>
+ </td>
+ </tr>
+ <tr class="odd">
+ <td class="key">Password</td>
+ <td class="value">
+ <button class="btn btn-default btn-xs" type="button" title="Password" name="edit_pass" id="edit_pass">
+ <span class="glyphicon glyphicon-edit"></span> Edit
+ </button>
+ <span id="passval"class="value">******** </span>
+ <span class="hide_this" id="span_pass">
+ <button type="button" class="btn btn-default btn-xs" title="Cancel" id="cancel_pass_change"> Cancel </button>
+ <div style='display:none;' id="pass_form">
+ <input type='hidden' value='' /></div>
+ <table id="edit_password">
+ <tr>
+ <td>Enter password: </td>
+ <td class="field"> <input type="password" name="password" id="password" /> </td>
+ </tr>
+ <tr>
+ <td>Confirm password: </td>
+ <td class="field">
+ <input type="password" name="confirmpassword" id="confirmpassword" />
+ <input type="submit" class="btn btn-default btn-xs" name="submit_pass" value="Save"/>
+ </td>
+ </tr>
+ </table>
+ </span>
+ </td>
+ </tr>
+ <tr class="even">
+ <td class="key">Full Name</td>
+ <td class="value">
+ <span id="nameval" class="value" >{{ fullname }} </span>
+ <span class="hide_this" id="span_name">
+ <button type="button" class="btn btn-default btn-xs" title="Cancel" id="cancel_name_change"> Cancel </button>
+ <div style='display:none;'><input type='hidden' name='nameform' /></div>
+ <input id="fname" type="text" name="fname" class="required" maxlength="200" value="{{firstname}}" />
+ <input id="lname" type="text" name="lname" class="required" maxlength="200" value="{{lastname}}" />
+ <input type="submit" class="btn btn-default btn-xs" name="submit_name" value="Save"/>
+ </span>
+ <button class="btn btn-default btn-xs" type="button"title="Full Name" id="edit_name">
+ <span class="glyphicon glyphicon-edit"></span> Edit
+ </button>
+ </td>
+ </tr>
+ <tr class="odd">
+ <td class="key">Authority</td>
+ <td class="value">
+ <span id="affval" class="value">{{ authority }}</span>
+ <button class="btn btn-default btn-xs" type="button" id="edit_auth" onclick="editAlert()" title="To change your authority please contact the administrator">
+ <span class="glyphicon glyphicon-question-sign"></span> Edit
+ </button>
+ </td>
+ </tr>
+ {%if 'Enabled' in user_status %}
+ <tr class="even">
+ <td class="key">Generate Keys</td>
+ <td>
+ <input type="submit" name="generate" class="btn btn-primary" value="Generate a new Key Pair" id="generate_keypair"
+ onclick="return confirm('Are you sure? If you do so, your current credentials will be overwritten.');"
+ title="It will generate a new key Pair and your current credentials will be overwritten."/>
+ </td>
+ </tr>
+ <tr class="odd">
+ <td class="key">Public Key</td>
+ <td class="value">
+ <span id="keyval" class="value">******** </span>
+ <span class="hide_this" id="span_upload">
+ <button type="button" class="btn btn-default" title="Cancel" id="cancel_upload"> Cancel </button>
+ <div style='display:none;'>
+ <input type='hidden' name='upload' /></div>
+ <input type="file" name="pubkey" class="required" id="pubkey"/>
+ <input class="btn btn-default btn-xs" name="upload_key" id="upload_key" type="submit" title="Upload your public key" value="Upload"
+ onclick="return confirm('Are you sure? It will overwrite your current credentials and you have delegate it manually.');"/>
+ </span>
+ <div style='display:none;'> <input type='hidden' name='dload' /> </div>
+ <button type="submit" name="dl_pubkey" class="btn btn-default btn-xs" title="Download your public key" id="dl_file">
+ <span class="glyphicon glyphicon-download"></span> Download
+ </button>
+ <button class="btn btn-default btn-xs" id="upload_file" type="button" title="Upload a public key">
+ <span class="glyphicon glyphicon-upload"></span> Upload
+ </button>
+ </td>
+ </tr>
+ <tr class="even" id="pkey_row">
+ {%if 'N/A' not in user_private_key%}
+ <td class="key">Private Key </td> <!-- Hide if priv_key doesn't exist in myslice platform -->
+ <td class="value">********<a href="#"></a>
+ <button type="submit" name="dl_pkey" class="btn btn-default" title="Download your privaye key" id="dl_pkey">
+ <span class="glyphicon glyphicon-download"></span> Download
+ </button>
+ <input class="btn btn-danger btn-xs" id="delete" name="delete" type="submit" value="Delete" title="Delete your private key"
+ onclick="return confirm('Are you sure? If you do so, you have to delegate your credentials manually.');"/>
+ </td>
+ {%else%}
+ <td class="key">Private Key </td> <!-- Hide if priv_key doesn't exist in myslice platform -->
+ <td class="value">********<a href="#"></a>
+ <button type="submit" name="dl_pkey" class="btn btn-default disabled" title="Download your privaye key" id="dl_pkey">
+ <span class="glyphicon glyphicon-download"></span> Download
+ </button>
+ <input class="btn btn-danger btn-xs disabled" id="delete" name="delete" type="submit" title="Delete your private key" value="Delete" />
+ </td>
+ {%endif%}
+ </tr>
+ <tr class="even">
+ <td colspan="2">
+ <p class="message" id="pkey_del_msg"><b> Tradeoff:</b> Ease-of-use vs Security.<br>
+ <b>Ease-of-use:</b> Automatic account delegation. Don't delete private key.<br>
+ <b>Security:</b> Manual account delegation. Download & Delete private key.
+ </p>
+ </td>
+ </tr>
+ {%endif%}
+ </table>
+
+ </div>
+ </div>
+
+ <div class="tab-pane row" id="account">
+ <div class="col-md-12">
+
+ <h3>Principal Account <small>Account used for delegating credentials</small></h3>
+ <table class="table">
+ <tr class="odd">
+ <th>Platform</th>
+ <th>Account Type</th>
+ <th>Account Delegation</th>
+ <th>User hrn</th>
+ <th>User Status</th>
+ <!--<th>Pub Key</th> -->
+ </tr>
+ {% for row in principal_acc %}
+ <tr class="border_bottom">
+ <td class="odd"> {{ row.platform_name }} </td>
+ <td class="odd"> {{ row.account_type }} </td>
+ <td class="odd"> {{ row.delegation_type }} </td>
+ <td class="odd"> {{ row.usr_hrn }} </td>
+ <td class="odd"> {{ row.user_status }} </td>
+ <!-- <td class="even"> {{ row.usr_pubkey }} </td> -->
+ </tr>
+ {%endfor%}
+ </table>
+
+ </div>
+
+
+ {%if 'Enabled' in user_status %}
+ <div class="col-md-12">
+ <h3>Credentials <small>Delegated to Principal Account</small></h3>
+ <table class="table">
+ <caption><b>Delegated User Credential</b></caption>
+ <tr class="odd">
+ <th>Expiration Date</th>
+ <th>Download</th>
+ </tr>
+ {% for row in my_users %}
+ <tr class="border_bottom">
+ <td class="odd"> {{ row.cred_exp }} </td>
+ <td class="odd">
+ <button class="btn btn-default btn-xs" name= "dl_user_cred" type="submit" title="Download User Credential">
+ <span class="glyphicon glyphicon-download"></span> Credential
+ </button>
+ <button class="btn btn-default btn-xs" name= "dl_user_cert" type="submit" title="Download User Certificate">
+ <span class="glyphicon glyphicon-download"></span> Certificate
+ </button>
+ <button class="btn btn-default btn-xs" name= "dl_user_p12" type="submit" title="Download User PKCS12">
+ <span class="glyphicon glyphicon-download"></span> PKCS p12
+ </button>
+ </td>
+ </tr>
+ {%endfor%}
+ </table>
+ <p></p>
+ <table class="mytable table table-bordered table-hover">
+ <caption><b>Delegated Slice Credentials</b></caption>
+ <tr class="odd">
+ <th>Slice Name</th>
+ <th>Expiration Date</th>
+ <th>Download</th>
+ </tr>
+ {% for row in my_slices %}
+ <tr class="border_bottom">
+ <td class="odd"> {{ row.slice_name }} </td>
+ <td class="odd"> {{ row.cred_exp }} </td>
+ <td class="odd">
+ <button class="btn btn-default btn-xs" name= "dl_{{row.slice_name}}" type="submit" title="Download Slice Credentials">
+ <span class="glyphicon glyphicon-download"></span> Download
+ </button>
+ </td>
+ </tr>
+ {%endfor%}
+ </table>
+ <p></p>
+ <table class="mytable table table-bordered table-hover">
+ <caption><b>Delegated Authority Credentials</b></caption>
+ <tr class="odd">
+ <th>Authority Name</th>
+ <th>Expiration Date</th>
+ <th>Download</th>
+ </tr>
+ {% for row in my_auths %}
+ <tr class="border_bottom">
+ <td class="odd"> {{ row.auth_name }} </td>
+ <td class="odd"> {{ row.cred_exp }} </td>
+ <td class="odd">
+ <button class="btn btn-default btn-xs" name= "dl_{{row.auth_name}}" type="submit" title="Download Authority Credentials">
+ <span class="glyphicon glyphicon-download"></span> Download
+ </button>
+ </td>
+ </tr>
+ {%endfor%}
+ </table>
+ <p></p>
+ {%if '' not in my_users%}
+ <p><button class="btn btn-danger btn-lg btn-block" name= "clear_cred" type="submit" title="Clear All Credentials">Clear Credentials</button></p>
+ {%else%}
+ <p><button class="btn btn-danger btn-lg btn-block disabled" name= "clear_cred" type="submit" title="Clear All Credentials">Clear Credentials</button></p>
+ {%endif%}
+ </div>
+ </div>
+<!-- Modal- No credentials -->
+<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+ <h4 class="modal-title" id="myModalLabel">No credentials are delegated to the portal</h4>
+ </div>
+ <div class="modal-body">
+ <p>You may get this message for several reasons.</p>
+ <h3>Account Delegation: Automatic</h3>
+ <ul>
+ <li>If your account is not yet validated</li>
+ <li>If you press the "Clear Credentials" button</li>
+ <li>If you "Generate a new key pair"</li>
+ <li>If a new slice is added to your account</li>
+ </ul>
+ <p>In all the above mentioned cases, it is sufficient to refresh the page or go back to home page. The portal will regenrate your credentials.
+ In some cases it may take more time than usual. If nothing works, then please logout and login again to the portal.</p>
+ <h3>Account Delegation: Manual</h3>
+ <p>First of all your account needs to be validated by the manager of your organization.</p>
+ <p>As you have uploaded your own public key, the portal can no longer generate your credentials automatically.</p>
+ <p>In order for the portal to contact testbeds on your behalf, so as to list and reserve resources, you will need to
+ <a href="/portal/manual_delegation" target="_blank">delegate your credentials to the portal.</a>
+ </p>
+ <h5>Contact support</h5>
+ <p>If you don't have the above mentioned cases and still have this message, please <a href="/contact/" target="_blank">contact us</a>.</p>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+ </div>
+ </div>
+ </div>
+</div>
+
+
+ <div class="tab-pane row" id="access">
+ <div class="col-md-12">
+
+ <h3>Testbed Access <small>Reference Accounts in the following testbeds</small></h3>
+ <table class="mytable table table-bordered table-hover">
+ <tr class="odd">
+ <th>Platform</th>
+ <th>Account Type</th>
+ <th>Reference to</th>
+ <th>Remove Account</th>
+ </tr>
+ {% for row in ref_acc %}
+ <tr class="border_bottom">
+ <td class="odd"> {{ row.platform_name }} </td>
+ <td class="odd"> {{ row.account_type }} </td>
+ <td class="odd"> {{ row.account_reference }} </td>
+ <td class="odd">
+ <button class="btn btn-danger" name="delete_{{row.platform_name}}" type="submit" title="Delete account from this platform">
+ <span class="glyphicon glyphicon-minus"></span>
+ </button>
+ </td>
+ </tr>
+ {%endfor%}
+ </table>
+
+
+ <h3>Add reference account to the following testbeds</h3>
+ <table class="mytable table table-bordered table-hover">
+ <tr class="odd">
+ <th>Platforms</th>
+ <th>Add Account</th>
+ </tr>
+ {% for platform in platform_list %}
+ <tr class="border_bottom">
+ <td class="odd"> {{ platform.platform_no_access }} </td>
+ <td class="odd">
+ <button class="btn btn-success btn-sm" name= "add_{{platform.platform_no_access}}" type="submit" title="Add account to this platform">
+ <span class="glyphicon glyphicon-plus"></span>
+ </button>
+ </td>
+ </tr>
+ {%endfor%}
+ </table>
+ </div>
+{%endif%}
+</div>
+</form>
+</div>
+
+<script>
+ $(document).ready(function() {
+ $('.nav-tabs a').click(function (e) {
+ e.preventDefault();
+ $(this).tab('show');
+ id = $(this).attr('href').substr(1);
+
+ });
+
+ $('button#createslice').click(function() {
+ window.location="/portal/slice_request/";
+ });
+ });
+</script>
+
+{% endblock %}
--- /dev/null
+<div class="footer">
+<div class="container">
+ <div class="row">
+ <div class="col-md-12">
+ <ul>
+ <li></li>
+ </ul>
+ </div>
+ </div>
+ <div class="row">
+ <div class="col-md-12 copy">
+
+ </div>
+ </div>
+</div>
+</div>
\ No newline at end of file
--- /dev/null
+{% extends "layout_base.html" %}
+{% load portal_filters %}
+
+{% block content %}
+<!-- <div class="row">
+{% widget '_widget-news.html' %}
+</div> -->
+{% if username %}
+<div class="container dashboard">
+ <div class="row">
+ {%if 'is_pi' in pi %}
+ <div class="col-md-3">
+ <h3>
+ EXPERIMENT
+ </h3>
+ <div>
+ <a href="#"><img src="{{ STATIC_URL }}img/icon_slices.png" alt="" /></a>
+ </div>
+ <div>
+ <button id="slicerequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create Slice</button>
+ </div>
+ <div>
+ <p><strong>Your slices </strong>
+ <span title="A slice is a set of testbed resources on which you can conduct an experiment.
+ Either ask your colleagues to give you access to an existing slice or request a new slice by clicking 'Request Slice'.
+ However, on the OneLab portal, you will only see slices that you have created through OneLab. If you have created slices elsewhere,
+ such as on the PlanetLab Europe portal, those slices will not appear here."
+ class="glyphicon glyphicon-info-sign">
+ </span>
+
+ </p>
+ </div>
+ <div>
+ <div id="home-slice-list"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
+ </div>
+ </div>
+ <div class="col-md-3">
+ <h3>MANAGEMENT</h3>
+ <div>
+ <a href="/portal/institution"><img src="{{ STATIC_URL }}img/icon_authority_color.png" alt="" /></a>
+ </div>
+ <div>
+ <button id="validaterequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-ok"></span> Validate Requests</button>
+ </div>
+ </div>
+ <div class="col-md-3">
+ <h3>
+ SUPPORT
+ </h3>
+ <div>
+ <a href="/portal/support"><img src="{{ STATIC_URL }}img/icon_support.png" alt="" /></a>
+ </div>
+ <div>
+ <button id="ticketbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-envelope"></span> Contact</button>
+ </div>
+ </div>
+
+ <div class="col-md-3">
+ <h3>
+ ACCOUNT
+ </h3>
+ <div>
+ <a href="/portal/account/"><img src="{{ STATIC_URL }}img/icon_user_color.png" alt="" /></a>
+ </div>
+ <div>
+ <button id="logoutbtn" type="button" class="btn btn-default" data-username="{{ username }}"><span class="glyphicon glyphicon-off"></span> Logout</button>
+ </div>
+ <div>
+ {% if person.last_name %}
+ {{person.first_name}} {{person.last_name}}<br />
+ {% endif %}
+ <span class="label">Username:</span> <a href='/portal/account/' title="Click here to see and edit your account details.">{{person.email}}</a>
+ </div>
+ </div>
+ </div>
+ {%else%}
+ <div class="row">
+ <div class="col-md-4">
+ <h3>
+ EXPERIMENT
+ </h3>
+ <div>
+ <a href="#"><img src="{{ STATIC_URL }}img/icon_slices.png" alt="" /></a>
+ </div>
+ <div>
+ <button id="slicerequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request Slice</button>
+ </div>
+ <div>
+ <p><strong>Your slices </strong>
+ <span title="A slice is a set of testbed resources on which you can conduct an experiment.
+ Either ask your colleagues to give you access to an existing slice or request a new slice by clicking 'Request Slice'.
+ However, on the OneLab portal, you will only see slices that you have created through OneLab. If you have created slices elsewhere,
+ such as on the PlanetLab Europe portal, those slices will not appear here."
+ class="glyphicon glyphicon-info-sign">
+ </span>
+ </p>
+ </div>
+ <div>
+ <div id="home-slice-list"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
+ </div>
+ </div>
+ <div class="col-md-4">
+ <h3>
+ SUPPORT
+ </h3>
+ <div>
+ <a href="/portal/support"><img src="{{ STATIC_URL }}img/icon_support.png" alt="" /></a>
+ </div>
+ <div>
+ <button id="ticketbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-envelope"></span> Contact</button>
+ </div>
+ </div>
+
+ <div class="col-md-4">
+ <h3>
+ ACCOUNT
+ </h3>
+ <div>
+ <a href="/portal/account/"><img src="{{ STATIC_URL }}img/icon_user_color.png" alt="" /></a>
+ </div>
+ <div>
+ <button id="logoutbtn" type="button" class="btn btn-default" data-username="{{ username }}"><span class="glyphicon glyphicon-off"></span> Logout</button>
+ </div>
+ <div>
+ {% if person.last_name %}
+ {{person.first_name}} {{person.last_name}}<br />
+ {% endif %}
+ <span class="label">Username:</span> <a href='/portal/account/' title="Click here to see and edit your account details.">{{person.email}}</a>
+ </div>
+ </div>
+ </div>
+ {%endif%}
+
+</div>
+{% else %}
+<div class="container-fluid home">
+ <div class="">
+ <div class="col-sm-2"></div>
+ <div class="col-sm-4 slogan">
+ <h2>
+ SmartFIRE
+ </h2>
+ <h3>
+ EU-South Korea Cooperation<br>
+ On Future Internet Infrastructure
+ </h3>
+ </div>
+ <div class="col-sm-5 col-sm-offset-1">
+ <div class="row">
+ {% widget '_widget-login-user.html' %}
+ </div>
+ </div>
+ <div class="col-sm-1"></div>
+ </div>
+</div>
+{% endif %}
+
+
+<script type="text/javascript">
+ $(document).ready(function() {
+ $('a.home-tab').click(function() {
+ $('ul.nav-tabs li').removeClass('active');
+ $(this).parent().addClass('active');
+ $('div.home-panel').hide();
+ $('div#'+$(this).data('panel')).show();
+ });
+ $('button#validaterequestbtn').click(function() {
+ window.location="/portal/institution#requests";
+ });
+ $('button#ticketbtn').click(function() {
+ window.location="/portal/contact/";
+ });
+ $('button#signupbtn').click(function() {
+ window.location="/portal/register/";
+ });
+ $('button#slicerequestbtn').click(function() {
+ window.location="/portal/slice_request/";
+ });
+/*-------
+List of slices has been moved in
+portal/templates/base.html
+This should go into session
+--------*/
+});
+</script>
+{# widget "_widget-monitor.html" #}
+{# widget "_widget-stats-top-slices.html" #}
+
+{% endblock %}
--- /dev/null
+{% extends "layout_wide.html" %}
+
+{% block head %}
+<script type="text/javascript" src="{{STATIC_URL}}/js/institution.js"></script>
+{% endblock head %}
+
+{% block content %}
+<div class="container">
+ <div class="row">
+ <div class="col-md-12">
+ <div class="breadcrumbs">
+ Management > Institution: <span id="authority_name"></span>
+ </div>
+ </div>
+ </div>
+</div>
+<div class="container">
+ <div class="row">
+ <div class="col-md-12">
+ <ul class="nav nav-tabs nav-section">
+ <li class="active"><a href="#about">About</a></li>
+ <li><a href="#users">Users</a></li>
+ <li><a href="#slices">Slices</a></li>
+ <li><a href="#requests">Requests</a></li>
+ </ul>
+ </div>
+ </div>
+</div>
+<div class="container tab-content">
+ <div class="tab-pane active row" id="about">
+ </div>
+
+ <div class="tab-pane row" id="users" data-authority="{{user_details.parent_authority}}">
+ <div class="col-md-12 el">
+ <div id="user-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
+ <div id="user-tab-loaded" style="display:none;">
+ <table id="user-tab" class="table">
+ <tr>
+ <th>+/-</th>
+ <th>Email</th>
+ <th>User hrn</th>
+ <!--
+ <th>First name</th>
+ <th>Last name</th>
+ <th>Enabled</th>
+ -->
+ </tr>
+ </table>
+
+ </div>
+ {%if 'is_pi' in pi %}
+ <div>
+ <button id="deleteusers" type="button" class="btn btn-danger"><span class="glyphicon glyphicon-remove"></span> Delete selected users</button>
+ </div>
+ {% endif %}
+ </div>
+ </div>
+
+ <div class="tab-pane row" id="slices">
+ <div class="col-md-12 el">
+ <div id="slice-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
+ <div id="slice-tab-loaded" style="display:none;">
+ <table id="slice-tab" class="table">
+ <tr>
+ <th>+/-</th>
+ <th>Slice hrn</th>
+ <th>Users</th>
+ <th>Url</th>
+ <!-- <th>nodes</th> -->
+ <th>Creation</th>
+ </tr>
+ </table>
+ </div>
+ {% if 'is_pi' in pi %}
+ <div>
+ {% if 'is_pi' in pi %}
+ <button id="createslice" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create slice</button>
+ {% else %}
+ <button id="createslice" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request slice</button>
+ {% endif %}
+ <button id="renewslices" type="button" class="btn btn-primary"><span class="glyphicon glyphicon-refresh"></span> Renew Slices</button>
+ <button id="deleteslices" type="button" class="btn btn-danger"><span class="glyphicon glyphicon-remove"></span> Delete Slices</button>
+ </div>
+ {% endif %}
+ </div>
+ </div>
+ <div class="tab-pane row" id="requests">
+ </div>
+</div>
+<script>
+$(document).ready(function() {
+ {% if person %}
+ {% if user_details.parent_authority %}
+
+ $.post("/rest/slice/",{'fields':['slice_hrn','users','url','slice_date_created'],'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
+ var list_slices = [];
+ var table_slices = [];
+ /* "slice_hrn", "slice_description", "slice_type", "parent_authority", "created", "nodes", "slice_url", "slice_last_updated", "users", "slice_urn", "slice_expires" */
+ $.each( data, function( key, val ) {
+ list_slices.push( "<li><a href=\"portal/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></li>" );
+ if(val.nodes=="undefined" || val.nodes==null){
+ nodes_length=0;
+ }else{
+ nodes_length=val.nodes.length;
+ }
+ console.log(val);
+ if(val.users=="undefined" || val.users==null){
+ users_length=0;
+ }else{
+ users_length=val.users.length;
+ }
+
+ if(val.url=="undefined" || val.url==null){
+ slice_url="";
+ }else{
+ slice_url="<a href='"+val.url+"' target='_blank'>"+val.url+"</a>";
+ }
+
+ slice_row = "<tr id='"+val.slice_hrn+"'>";
+ slice_row += "<td><input type='checkbox' class='slice' id='"+val.slice_hrn+"'></td>";
+ slice_row += "<td><a href=\"/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></td>";
+ slice_row += "<td>"+users_length+"</td>";
+ slice_row += "<td>"+slice_url+"</td>";
+ //slice_row += "<td>"+nodes_length+"</td>";
+ slice_row += "<td>"+val.slice_date_created+"</td>";
+ slice_row += "</tr>";
+ table_slices.push(slice_row);
+
+ });
+
+ /* $("div#slice-list").html($( "<ul/>", { html: list_slices.join( "" ) })); */
+ $("table#slice-tab tr:last").after(table_slices.join( "" ));
+ $("div#slice-tab-loaded").css("display","block");
+ $("div#slice-tab-loading").css("display","none");
+ });
+
+
+ $.post("/rest/user/",{'fields':['user_hrn','user_email'],'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
+ var list_users = [];
+ var table_users = [];
+ /* Available fields
+ user_gid, user_enabled, slices, pi_authorities, keys, parent_authority, user_first_name,
+ user_urn, user_last_name, user_phone, user_hrn, user_email, user_type
+ */
+ $.each( data, function( key, val ) {
+ list_users.push( "<li><a href=\"portal/user/"+val.user_email+"\">" + val.user_email + "</a></li>" );
+ user_row = "<tr id='"+val.user_hrn+"'>";
+ user_row += "<td><input type='checkbox' class='user' id='"+val.user_hrn+"'></td>";
+ user_row += "<td>"+val.user_email+"</td>";
+ user_row += "<td>"+val.user_hrn+"</td>";
+ /*
+ user_row += "<td>"+val.user_first_name+"</td>";
+ user_row += "<td>"+val.user_last_name+"</td>";
+ user_row += "<td>"+val.user_enabled+"</td>";
+ */
+ user_row += "</tr>";
+ table_users.push(user_row);
+ });
+ $("table#user-tab tr:last").after(table_users.join( "" ));
+ $("div#user-tab-loaded").css("display","block");
+ $("div#user-tab-loading").css("display","none");
+ });
+
+ {% endif %}
+ {% endif %}
+
+}); // End document.ready
+
+$(document).ready(function() {
+ $('.nav-tabs a').click(function (e) {
+ e.preventDefault();
+ $(this).tab('show');
+ var id = $(this).attr('href').substr(1);
+ if ((id == 'requests') || (id == 'about'))
+ $("#" + id).load('/management/' + id);
+ });
+ var hash = window.location.hash;
+ if (hash) {
+ $('.nav-tabs a[href='+hash+']').click();
+ } else {
+ $('.nav-tabs a[href=#about]').click();
+ }
+});
+</script>
+{% endblock %}
--- /dev/null
+<script type="text/javascript">
+ $(document).ready(function() {
+ $("li#nav-request").addClass("active");
+ });
+ function on_click_event() {
+ var ids = [];
+ $('.portal__validate__checkbox').each(function(i, el) {
+ if ($(el).prop('checked')) {
+ // portal__validate__checkbox__slice__2
+ var id_array = $(el).attr('id').split('__');
+ // push(slice__2)
+ ids.push(id_array[3] + '__' + id_array[4]);
+ }
+ });
+ if (ids.length > 0) {
+ var id_str = ids.join('/');
+ // XXX spinner
+ $.getJSON('/portal/validate_action/' + id_str,
+ function(status) {
+ $.each(status, function(request_type__id, request_status) {
+ // request_status: NAME -> dict (status, description)
+ var status_str = '';
+ $.each(request_status, function(name, result) {
+ if (status_str != '')
+ status_str += ' -- ';
+
+ if (result.status) {
+ status_str += '<font color="green">OK</font>';
+ $('#portal__validate__checkbox__' + request_type__id).hide();
+ } else {
+ status_str += '<font color="red">ERROR: ' + result.description + '</font>';
+ }
+ });
+ $('#portal__status__' + request_type__id).html(status_str);
+
+
+ });
+ }
+ );
+ }
+ }
+</script>
+
+<div class="col-md-12">
+ <h2>From your authorities</h2>
+</div>
+{% if my_authorities %}
+
+ {% for authority, requests in my_authorities.items %}
+
+ <div class="col-md-12">
+ <h2>{{authority}}</h2>
+ </div>
+
+ <table class="table">
+ <th>
+ <td>Type</td>
+ <td>Id</td>
+ <td>Details</td>
+ <td>Timestamp</td>
+ <td>Status</td>
+ </th>
+ {% for request in requests %}
+
+ <tr>
+ <td>
+ {% if request.allowed == 'allowed' %}
+ <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
+ {% else %}
+ {% if request.allowed == 'expired' %}
+ expired
+ {% else %} {# denied #}
+ denied
+ {% endif %}
+ {% endif %}
+ </td>
+ <td>{{ request.type }}</td>
+ <td>{{ request.id }}</td>
+ <td>
+ {% if request.type == 'user' %}
+ <b>{{request.first_name}} {{request.last_name}}</b> <a href="mailto:{{request.email}}">{{request.email}}</a>
+ {% else %}
+ {% if request.type == 'slice' %}
+ <b>{{request.slice_name}}</b> -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+ {% else %} {# authority #}
+ <b>{{request.site_name}}</b> ({{request.site_authority}}) -- {{request.address_city}}, {{request.address_country}}
+ {% endif %}
+ {% endif %}
+ </td>
+ <td>{{ request.timestamp }}</td>
+
+ <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
+
+ <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+ </tr>
+
+ {% endfor %}
+ </table>
+ {% endfor %}
+
+{% else %}
+ <div class="col-md-12">
+ <i>There is no pending request waiting for validation.</i>
+ </div>
+{% endif %}
+<div>nnllknjkn<br /><br /></div>
+<div class="col-md-12">
+ <h2>From your sub-authorities</h2>
+</div>
+{% if sub_authorities %}
+
+ {% for authority, requests in sub_authorities.items %}
+ <div class="col-md-12">
+ <h2>{{authority}}</h2>
+ </div>
+
+ <table class="table">
+ <th>
+ <td>Type</td>
+ <td>Id</td>
+ <td>Details</td>
+ <td>Timestamp</td>
+ <td>Status</td>
+ </th>
+ {% for request in requests %}
+ <tr>
+ <td>
+ {% if request.allowed == 'allowed' %}
+ <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
+ {% else %}
+ {% if request.allowed == 'expired' %}
+ expired
+ {% else %} {# denied #}
+ denied
+ {% endif %}
+ {% endif %}
+ </td>
+ <td>{{ request.type }}</td>
+ <td>{{ request.id }}</td>
+ <td>
+ {% if request.type == 'user' %}
+ Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
+ {% else %}
+ {% if request.type == 'slice' %}
+ Slice name: {{request.slice_name}} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+ {% else %} {# authority #}
+ Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
+ {% endif %}
+ {% endif %}
+ </td>
+ <td>{{ request.timestamp }}</td>
+
+ <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
+
+ <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+ </tr>
+ {% endfor %}
+ </table>
+ {% endfor %}
+{% else %}
+<div class="col-md-12">
+ <i>There is no pending request waiting for validation.</i>
+</div>
+{% endif %}
+
+<div class="col-md-12">
+ <h2>From your authorities with delegation</h2>
+</div>
+
+{% if delegation_authorities %}
+
+ {% for authority, requests in delegation_authorities.items %}
+ <div class="col-md-12">
+ <h3>{{authority}}</h3>
+ </div>
+ <table class="table">
+ <th>
+ <td>Type</td>
+ <td>Id</td>
+ <td>Details</td>
+ <td>Timestamp</td>
+ <td>Status</td>
+ </th>
+ {% for request in requests %}
+ <tr>
+ <td>
+ {% if request.allowed == 'allowed' %}
+ <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
+ {% else %}
+ {% if request.allowed == 'expired' %}
+ expired
+ {% else %} {# denied #}
+ denied
+ {% endif %}
+ {% endif %}
+ </td>
+ <td>{{ request.type }}</td>
+ <td>{{ request.id }}</td>
+ <td>
+ {% if request.type == 'user' %}
+ Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
+ {% else %}
+ {% if request.type == 'slice' %}
+ Slice name: {{request.slice_name}} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+ {% else %} {# authority #}
+ Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
+ {% endif %}
+ {% endif %}
+ </td>
+ <td>{{ request.timestamp }}</td>
+
+ <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
+
+ <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+ </tr>
+ {% endfor %}
+ </table>
+ {% endfor %}
+{% else %}
+<div class="col-md-12">
+ <i>There is no pending request waiting for validation.</i>
+</div>
+{% endif %}
+<div class="col-md-12">
+ <button class="btn btn-onelab" type="button" id="portal__validate" onclick="on_click_event();"><span class="glyphicon glyphicon-ok"></span> Validate</button>
+</div>
--- /dev/null
+{% extends "layout.html" %}
+{% load i18n %}
+
+{% block content %}
+ <div class="row">
+ <div class="col-md-12">
+ <div class="breadcrumbs">
+ Experiment > Request a new Slice
+ </div>
+ </div>
+ </div>
+
+ {% if errors %}
+ <div class="row">
+ <div class="col-md-12">
+ <ul class="error">
+ {% for error in errors %}
+ <li>{{ error }}</li>
+ {% endfor %}
+ </ul>
+ </div>
+ </div>
+ {% endif %}
+
+ <div class="row">
+ <div class="col-md-8 el">
+ <form role="form" method="post">
+ {% csrf_token %}
+ <div class="form-group" style="display:none">
+ <input type="email" class="form-control" id="email" style="width:300px" value="{{ email }}" readonly="readonly">
+ </div>
+ <div class="form-group">
+ <input type="text" class="form-control" name="slice_name" id="slice_name" style="width:300px" placeholder="Slice name" value="{{slice_name}}"
+ title="Please enter a name for your slice"required="required">
+ </div>
+ <div class="form-group">
+ {%if 'is_pi' in pi %}
+ <input type="text" class="form-control" id="authority_hrn" name="org_name" style="width:300px" placeholder="Organization"
+ title="An authority responsible for vetting your slice" required="required">
+ {%else%}
+ <input type="text" class="form-control" id="authority_hrn" name="org_name" placeholder="Organization" style="width:300px;"
+ title="An authority responsible for vetting your slice" required="required" readonly>
+ {%endif%}
+ </div>
+ <div class="form-group">
+ <input type="text" class="form-control" name="url" id="url" style="width:300px" placeholder="Experiment URL (if one exists)"
+ title="Please provide the url of your experiment if you have one." value="{{url}}">
+ </div>
+ <div class="form-group">
+ <textarea id="purpose" name="purpose" class="form-control" rows="6" placeholder="Experiment purpose" style="width:300px"
+ title="Purpose of your experiment (informative)" required="required">{{ purpose }}</textarea>
+ </div>
+ {%if 'is_pi' in pi %}
+ <button type="submit" id=submit_pi class="btn btn-onelab"><span class="glyphicon glyphicon-plus"></span> Create slice</button>
+ {%else%}
+ <button type="submit" class="btn btn-onelab"><span class="glyphicon glyphicon-plus"></span> Request slice</button>
+ {%endif%}
+ </form>
+
+ </div>
+ </div>
+
+<script>
+jQuery(document).ready(function(){
+
+ /*$("#authority_hrn").load("/rest/user/", {"fields" : ["parent_authority"], "filters": {"user_hrn": "{{ user_hrn }}"}}, function(data) {
+ var jsonData = JSON.parse(data);
+ $(this).attr("value", jsonData[0]['parent_authority']);
+ });*/
+ $("#authority_hrn").val("{{authority_name}}");
+ var availableTags = [
+ {% if authorities %}
+ {% for authority in authorities %}
+ {% if authority.name %}
+ {value:"{{ authority.name }}",label:"{{authority.name}}"},
+ // to show only full name
+ // {% else %}
+ // {value:"{{ authority.authority_hrn }}",label:"{{authority.authority_hrn}}"},
+ {% endif %}
+ {% endfor %}
+ {% else %}
+ {value:"",label:"No authority found !!!"}
+ {% endif %}
+ ];
+ // sorting the list
+ availableTags.sort(function(a,b){
+ var nameA=a.value.toLowerCase(), nameB=b.value.toLowerCase();
+ if (nameA < nameB) {
+ return -1;
+ }
+ if (nameA > nameB) {
+ return 1;
+ }
+ return 0;
+ });
+ $( "#authority_hrn" ).autocomplete({
+ source: availableTags,
+ minLength: 0,
+ select: function( event, ui ) {console.log(jQuery(this));}
+ });
+
+ $("#submit_pi").click(function() {
+ localStorage.clear();
+ });
+});
+</script>
+{% endblock %}
+
--- /dev/null
+<div class="login-form">
+ {% if state %}
+ <span class="help-block">{{ state }}</span>
+ {% endif %}
+ <form action="/login/" method="post" role="form">
+ {% csrf_token %}
+ {% if next %}
+ <input type="hidden" name="next" value="{{ next }}" />
+ {% endif %}
+ <div class="form-group">
+ <input type="email" name="username" placeholder="Enter Email / Username">
+ </div>
+ <div class="form-group">
+ <input type="password" name="password" placeholder="Password">
+ </div>
+ <div class="login-submit">
+ <input type="submit" class="btn btn-onelab" value="Sign In" />
+ <span class="lost-password"> | <a href="/portal/pass_reset/">Can't access your account?</a></span>
+ </div>
+ <div class="login-signup">
+ <!-- You don't have yet an account?
+
+ <a href="/register">Sign Up!</a> -->
+ </div>
+ </form>
+</div>
--- /dev/null
+{% load portal_filters %}
+<div class="header">
+<div class="container">
+ <div class="row">
+ <div class="col-sm-3 col-md-3 logo">
+ <a href="/"><img height="60" src="{{ STATIC_URL }}img/SmartFIRE_logo.png" alt="SmartFIRE | sinis.ipv6.lip6.fr Portal - SmartFIRE" /></a>
+ </div>
+ {% if username %}
+ <div class="col-sm-4 col-md-4 navigation">
+ <ul>
+ <li>
+ <a class="dropdown-toggle" data-toggle="dropdown" href="#">
+ EXPERIMENT <span class="caret"></span>
+ </a>
+
+ <div class="dropdown-menu" style="z-index:99;">
+ <ul id="dropdown-slice-list">
+ <li class="title"><a href="/portal/slice_request/">Request Slice</a></li>
+ </ul>
+ </div>
+ </li>
+ {%if 'is_pi' in pi %}
+ <li id="nav-institution" class=""><a href="/institution">MANAGEMENT</a></li>
+ {%endif%}
+ <li><a href="/support/">SUPPORT</a></li>
+ </ul>
+ </div>
+ {% else %}
+ <div class="col-sm-4 col-md-4 navigation">
+ </div>
+ {% endif %}
+ <div class="col-sm-5 col-md-5 secondary">
+ <ul>
+
+ <!--<li><a target="_blank" href="http://status.testbeds.eu">Services Status</a></li> -->
+ <li><a target="_blank" href="http://eukorea-fire.eu">Web site</a></li>
+ </ul>
+ {% if username %}
+ <div class="account">You are logged in as <a href="/account/">{{ username }}</a> | <a id="logout" style="cursor:pointer;" data-username="{{ username }}"><span class="glyphicon glyphicon-off"></span> Logout</a></div>
+ {% endif %}
+ </div>
+ </div>
+</div>
+</div>
+
+<div class="row">
+{% widget '_widget-message.html' %}
+</div>
+<script>
+ $(document).ready(function() {
+ $('li.slices').mouseenter(function() {
+ $('div#menu-slice-list').fadeIn(100);
+ });
+ $('div#menu-slice-list').mouseleave(function(e) {
+ if (!$('li.slices').is(":hover")) {
+ $(this).fadeOut(100);
+ }
+ });
+ // var slices = localStorage.getItem('slices');
+ // if (slices.length == 0) {
+ // $.post("/rest/user/",{'filters':{'user_hrn':'$user_hrn'}}, function( data ) {
+ // var items = [];
+ // localStorage.setItem('slices', data[0].slice);
+ // });
+ // }
+ // $.each(slices, function( key, val ) {
+ // items.push( "<li><a href=\"/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></li>" );
+ // });
+ // $("div#home-slice-list").html($( "<ul/>", { html: items.join( "" ) }));
+ });
+</script>