import portal.slicetabusers
import portal.slicetabmeasurements
+import portal.managementtabrequests
+
#### high level choices
# main entry point (set to the / URL)
# beware that if this view is broken you end up in an endless cycle...
(r'^testbeds/(?P<slicename>[^/]+)/?$', portal.slicetabtestbeds.SliceTabTestbeds.as_view()),
(r'^measurements/(?P<slicename>[^/]+)/?$', portal.slicetabmeasurements.SliceTabMeasurements.as_view()),
(r'^experiment/(?P<slicename>[^/]+)/?$', portal.slicetabexperiment.ExperimentView.as_view()),
+ #
+ (r'^management/requests/?$', portal.managementtabrequests.ManagementRequestsView.as_view()),
+ #
url(r'^portal/', include('portal.urls')),
# SLA
font-size:13pt;
color:#201E62;
}
-
-div.wrapper {
- width:980px;
- margin:0 auto;
- position:relative;
-}
-div.container {
- /*width:980px;
- margin:25px auto;*/
-}
-div.wide {
- margin:25px auto;
- padding:0 25px;
-}
-
span.label {
font-size:11pt;
color:gray;
font-weight:normal;
padding:0;
}
+div.el {
+ padding-bottom:15px;
+}
+/* buttons */
+button.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;
+ box-shadow:none;
+}
+button.btn-primary {
+ border-bottom:3px solid #3071A9;
+}
+button.btn-primary:hover {
+ border-bottom:3px solid #3071A9;
+}
+button.btn-primary:active {
+ box-shadow:none;
+}
+button.btn-danger {
+ border-bottom:2px solid #FF7394;
+}
+button.btn-danger:hover {
+ border-bottom:2px solid #D2322D;
+}
+button.btn-danger:active {
+ border:1px solid #D2322D;
+ box-shadow:none;
+}
+button.btn-onelab {
+ border:0;
+ border-bottom:2px solid #540086;
+ background-color:#302562;
+ color:white;
+}
+button.btn-onelab:hover {
+ border:0;
+ border-bottom:2px solid #540086;
+ background-color:#302562;
+ color:#FFFFCC;
+}
+button.btn-primary:active {
+ box-shadow:none;
+}
/***** Notifications *****/
.warning {
border: 1px solid red;
div.well {
}
/**/
-/* BUTTON */
-.btn.btn-default {
- font-weight: bold;
-}
-
-.btn.btn-default:hover {
- font-weight: bold;
-}
-/**/
/* TABLE */
table.table {
margin:0;
-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;
+ margin-bottom:15px;
background-color:white;
}
div.navigation {
<li class="active"><a href="#info"><img src="{{ STATIC_URL }}icons/authority-xs.png" alt="Institution" /> Institution {{user_details.parent_authority}}</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="info">
- <div class="col-md-12">
+ <div class="col-md-12 el">
<div id="authority-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Authority" /></div>
<div id="authority-tab-loaded" style="display:none;">
<div id="authority-data" style="float:left; width:50%;"></div>
</div>
<div class="tab-pane row" id="users" data-authority="{{user_details.parent_authority}}">
- <div class="col-md-12">
+ <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">
+ <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>
+ <th>Email</th>
+ <th>User hrn</th>
+ <th>First name</th>
+ <th>Last name</th>
+ <th>Enabled</th>
</tr>
</table>
- {%if 'is_pi' in pi %}
- <div>
- <button id="deleteusers" type="button" class="btn btn-default"><span class="glyphicon glyphicon-remove"></span> Delete Users</button>
- </div>
- {%endif%}
+
</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">
- {%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%}
+ <div class="col-md-12 el">
+ {% if 'is_pi' in pi %}
+ <button id="createslice" type="button" class="btn btn-onelab"><span class="glyphicon glyphicon-plus"></span> Create slice</button>
+ {% else %}
+ <button id="createslice" type="button" class="btn btn-onelab"><span class="glyphicon glyphicon-plus"></span> Request slice</button>
+ {% endif %}
+ <br /><br />
<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">
+ <table id="slice-tab" class="table">
<tr>
<th>+/-</th>
- <th>slice_hrn</th>
- <th>users</th>
- <th>url</th>
+ <th>Slice hrn</th>
+ <th>Users</th>
+ <th>Url</th>
<!-- <th>nodes</th> -->
- <th>expiration</th>
+ <th>Expiration</th>
</tr>
- </table>
- <br>
- {%if 'is_pi' in pi %}
- <div>
- <button id="renewslices" type="button" class="btn btn-default"><span class="glyphicon glyphicon-refresh"></span> Renew Slices</button>
- <button id="deleteslices" type="button" class="btn btn-default"><span class="glyphicon glyphicon-remove"></span> Delete Slices</button>
- </div>
- {%endif%}
+ </table>
</div>
+ {% if 'is_pi' in pi %}
+ <div>
+ <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>
{% 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).load('/management/' + id);
+ });
+});
</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>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' %}
+ 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>
+ </div>
+ {% 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>Sub-Authorities</h2>
+</div>
+{% if sub_authorities %}
+
+ {% for authority, requests in sub_authorities.items %}
+ <div class="col-md-12">
+ <h3>{{authority}}</h3>
+ <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>
+ </div>
+ {% 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>Authorities with delegation</h2>
+</div>
+
+{% if delegation_authorities %}
+
+ {% for authority, requests in delegation_authorities.items %}
+ <div class="col-md-12">
+ <h3>{{authority}}</h3>
+ <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>
+ </div>
+ {% 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();">Validate</button>
+</div>
<a href="/"><img src="{{ STATIC_URL }}img/onelab-portal.png" alt="OneLab Portal - Future Internet Testbeds" /></a>
</div>
{% if username %}
- <div class="col-sm-5 col-md-5 navigation">
+ <div class="col-sm-4 col-md-4 navigation">
<ul>
<li>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
</li>
{%if 'is_pi' in pi %}
<li id="nav-institution" class=""><a href="/portal/institution">MANAGEMENT</a></li>
- <li id="nav-request"><a href="/portal/validate">REQUESTS</a></li>
{%endif%}
<li><a href="/portal/support/">SUPPORT</a></li>
-
-
-
</ul>
</div>
{% else %}
- <div class="col-sm-5 col-md-5 navigation">
+ <div class="col-sm-4 col-md-4 navigation">
</div>
{% endif %}
- <div class="col-sm-4 col-md-4 secondary">
+ <div class="col-sm-5 col-md-5 secondary">
<ul>
-
<li><a href="/news">News</a></li>
<li><a href="/portal/about">About</a></li>
<li><a target="_blank" href="http://www.onelab.eu">Public Website</a></li>
{% block content %}
<div class="row">
- <div class="col-md-12">
- <h1><img src="{{ STATIC_URL }}icons/slices-xs.png" alt="Request a Slice" /> Request a new Slice</h1>
+ <div class="col-md-12 el">
+ <h1><img src="{{ STATIC_URL }}icons/slices-xs.png" alt="Request a Slice" /> Request a new Slice</h1>
</div>
</div>
{% if errors %}
- <ul>
- {% for error in errors %}
- <li>{{ error }}</li>
- {% endfor %}
- </ul>
- {% endif %}
<div class="row">
- <div class="col-md-12"> </div>
+ <div class="col-md-12 el">
+ <ul>
+ {% for error in errors %}
+ <li>{{ error }}</li>
+ {% endfor %}
+ </ul>
+ </div>
</div>
+ {% endif %}
+
<div class="row">
- <div class="col-md-2"></div>
- <div class="col-md-8">
+ <div class="col-md-8 col-md-offset-2 el">
<form role="form" method="post">
{% csrf_token %}
<div class="form-group">
<textarea id="purpose" name="purpose" class="form-control" rows="6" placeholder="Experiment Purpose" required="required">{{ purpose }}</textarea>
<p class="help-block">Purpose of your experiment (informative)</p>
</div>
- <button type="submit" class="btn btn-default">Request Slice</button>
+ <button type="submit" class="btn btn-default btn-onelab">Request Slice</button>
</form>
</div>
<div class="col-md-12">
<h2>Report a Bug</h2>
<p>If you have found a bug or having difficulties accesing some features or found some anomalies, please report it using our ticketing system.</p>
- <button id="ticketbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create Ticket</button>
+ <button id="ticketbtn" type="button" class="btn btn-default btn-onelab"><span class="glyphicon glyphicon-plus"></span> Create Ticket</button>
<!-- <h3>Unresolved Tickets</h3>
<table class="mytable table table-bordered table-hover">
<tr>
template_name = "validate_pending.html"
def get_context_data(self, **kwargs):
+ pi = ""
# We might have slices on different registries with different user accounts
# We note that this portal could be specific to a given registry, to which we register users, but i'm not sure that simplifies things
# Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
if not auth_hrn in dest:
dest[auth_hrn] = []
dest[auth_hrn].append(request)
-
- ## check user is pi or not
- platform_query = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled')
- account_query = Query().get('local:account').select('user_id','platform_id','auth_type','config')
- platform_details = execute_query(self.request, platform_query)
- account_details = execute_query(self.request, account_query)
- for platform_detail in platform_details:
- for account_detail in account_details:
- if platform_detail['platform_id'] == account_detail['platform_id']:
- if 'config' in account_detail and account_detail['config'] is not '':
- account_config = json.loads(account_detail['config'])
- if 'myslice' in platform_detail['platform']:
- acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
- # assigning values
- if acc_auth_cred == {}:
- pi = "is_not_pi"
- else:
- pi = "is_pi"
context = super(ValidatePendingView, self).get_context_data(**kwargs)
context['my_authorities'] = ctx_my_authorities
context['topmenu_items'] = topmenu_items_live('Validation', page)
# so we can sho who is logged
context['username'] = the_user(self.request)
- context['pi'] = pi
+ context['pi'] = "is_pi"
context['theme'] = self.theme
context['section'] = "Requests"
# XXX We need to prepare the page for queries