if (this[i] instanceof Array && array[i] instanceof Array) {
// recurse into the nested arrays
if (!this[i].equals(array[i]))
- return false;
- }
- else if (this[i] != array[i]) {
+ return false;
+ }
+ else if (this[i] != array[i]) {
// Warning - two different object instances will never be equal: {x:20} != {x:20}
- return false;
- }
- }
+ return false;
+ }
+ }
return true;
}
default_set = (default_set === undefined) ? STATE_SET_OUT : default_set;
var self = this;
- var query_ext = this.find_analyzed_query_ext(query_uuid);
- var record_key = manifold.metadata.get_key(query_ext.query.object);
+ var key, object, query_ext, record_key;
+
+ query_ext = this.find_analyzed_query_ext(query_uuid);
+ object = query_ext.query.object;
+ if (object.indexOf(':') != -1) {
+ object = object.split(':')[1];
+ }
+ record_key = manifold.metadata.get_key(object);
+ // ["start_time", "resource", "end_time"]
+ // ["urn"]
+
$.each(records, function(i, record) {
//var key = manifold.metadata.get_key(query_ext.query.object);
- // ["start_time", "resource", "end_time"]
- // ["urn"]
+
var record_key_value = manifold.record_get_value(record, record_key);
+
query_ext.records.put(record_key_value, record);
if (!(query_ext.state.get(record_key_value)))
this.iter_records(query_uuid, function(record_key, record) {
var is_reserved, is_pending, in_set, is_unconfigured;
+
+ /* By default, a record is visible unless a filter says the opposite */
var visible = true;
var record_state = manifold.query_store.get_record_state(query_uuid, record_key, STATE_SET);
if (op == '=' || op == '==') {
if ( col_value != value || col_value==null || col_value=="" || col_value=="n/a")
visible = false;
+
}else if (op == 'included') {
+ /* By default, the filter returns false unless the record
+ * field match at least one value of the included statement
+ */
+ visible = false;
$.each(value, function(i,x) {
if(x == col_value){
visible = true;
return false; // ~ break
- }else{
- visible = false;
}
});
}else if (op == '!=') {
});
var end = new Date().getTime();
- console.log("APPLY FILTERS took", end - start, "ms");
+ console.log("APPLY FILTERS [", filters, "] took", end - start, "ms");
}
make_record: function(object, record)
{
// To make an object a record, we just add the hash function
- var key = manifold.metadata.get_key(object);
+ var key, new_object;
+
+ if (object.indexOf(':') != -1) {
+ new_object = object.split(':')[1];
+ } else {
+ new_object = object;
+ }
+
+ key = manifold.metadata.get_key(new_object);
record.hashCode = manifold.record_hashcode(key.sort());
record.equals = manifold.record_equals(key);
import portal.homeview
import portal.newsview
+import plugins.cafe.edelberto
+
+ from portal.about import AboutView
from portal.registrationview import RegistrationView
+ from portal.accountview import AccountView, account_process
+ from portal.institution import InstitutionView
+
+ from portal.supportview import SupportView
+ from portal.contactview import ContactView
+
from portal.termsview import TermsView
home_view=portal.homeview.HomeView.as_view()
(r'^credentials/(?P<action>[^/]+)/?$', 'rest.credentials.dispatch'),
#
# REST monitoring
- #(r'^monitor/sfa/getversion/?$', 'rest.monitor.sfaGetVersion'),
+ (r'^monitor/services/?$', 'rest.monitor.servicesStatus'),
#
#(r'^view/?', include('view.urls')),
#(r'^list/slices', 'view.list.slices')
(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()),
- #
+
+ url(r'^about/?$', AboutView.as_view(), name='about'),
+
+ url(r'^institution/?$', InstitutionView.as_view(), name='institution'),
(r'^management/requests/?$', portal.managementtabrequests.ManagementRequestsView.as_view()),
(r'^management/about/?$', portal.managementtababout.ManagementAboutView.as_view()),
#
- url(r'^register/?$', RegistrationView.as_view(), name='registration'),
+ url(r'^register/?$', RegistrationView.as_view(), name='registration'),
+ url(r'^account/?$', AccountView.as_view(), name='account'),
+ url(r'^account/account_process/?$', account_process),
+ url(r'^contact/?$', ContactView.as_view(), name='contact'),
url(r'^terms/?$', TermsView.as_view(), name='terms'),
+ url(r'^support/?$', SupportView.as_view(), name='support'),
#
url(r'^portal/', include('portal.urls')),
urls.append ( url ( r'^%s/'%aux, include ('%s.urls'%aux )))
urlpatterns = patterns(*urls)
+
+# Shibboleth - Edelberto
+urlpatterns += patterns('',
+ url(r'^cafe/', plugins.cafe.edelberto.EdelbertoView.as_view()),
+ #url(r'^cafe/', 'plugins.cafe.edelberto.index'),
+)
+
</div>\r
<div id="plugin-{{ domid }}" class="">\r
<div class="row m-b">\r
- <div class="col-md-2">\r
- <label for="inputEmail3" class="col-sm-2 control-label">Day:</label>\r
- </div>\r
- <div class="col-md-10">\r
- <label for="inputEmail3" class="col-sm-2 control-label">Time of day:</label>\r
- </div>\r
- </div>\r
- <div class="row m-b">\r
- <div class="col-md-2">\r
- <input id="DateToRes" type="text" placeholder="Reservation Date">\r
- <!-- <input id="DateToRes" type="text" class="form-control" placeholder="Reservation Date"> -->\r
- <span class="glyphicon glyphicon-calendar"></span>\r
+ <div class="col-md-4">\r
+ <div class="row">\r
+ <div class="col-md-1">\r
+ <label for="inputEmail3" class="control-label">Date:</label>\r
+ </div>\r
+ <div class="col-md-11">\r
+ <input id="DateToRes" type="text" placeholder="Reservation Date">\r
+ <span class="glyphicon glyphicon-calendar" style="position:absolute;margin-left:-20px;margin-top:4px;"></span>\r
+ <!-- <input id="DateToRes" type="text" class="form-control" placeholder="Reservation Date"> -->\r
+ </div>\r
+ </div>\r
</div>\r
- <div class="col-md-10">\r
- <div class="sliderContainer">\r
- <div id="tblSlider"></div>\r
+ <div class="col-md-8">\r
+ <div class="row">\r
+ <div class="col-md-2">\r
+ <label for="inputEmail3" class="control-label">Time of day:</label>\r
+ </div>\r
+ <div class="col-md-10">\r
+ <div class="sliderContainer">\r
+ <div id="tblSlider"></div>\r
+ </div>\r
+ </div>\r
</div>\r
</div>\r
</div>\r
//alert("1");\r
</script>\r
</div>\r
+</div>\r
from portal.models import PendingUser, PendingSlice, PendingAuthority
import json
- from django.contrib.auth.models import User
+ from django.contrib.auth.models import User
+ from django.contrib.sites.models import Site
+ from django.contrib.auth import get_user_model
from django.template.loader import render_to_string
from django.core.mail import EmailMultiAlternatives, send_mail
from myslice.theme import ThemeView
+# LS Client - By Bruno Soares (UFG)
+from lsapiclient import LaboraSchedulerClient
+
theme = ThemeView()
+ import activity.slice
+
# Thierry: moving this right into the code so
# most people can use myslice without having to install sfa
# XXX tmp sfa dependency, should be moved to SFA gateway
#default_email = default_email.replace('\n', '')
#return default_email
# the above doesn't work
- return ['support@myslice.info']
+ return ['support@onelab.eu']
else:
pi_user_hrns = [ hrn for x in pi_users for hrn in x['pi_users'] ]
query = Query.get('user').filter_by('user_hrn', 'included', pi_user_hrns).select('user_email')
try:
user_query = Query().get('local:user').filter_by('email', '==', user_email).select('user_id','email','password','config')
user_details = execute_admin_query(request, user_query)
-
+
# getting the user_id from the session
for user_detail in user_details:
user_id = user_detail['user_id']
if platform_detail['platform_id'] == account_detail['platform_id']:
if 'myslice' in platform_detail['platform']:
account_config = json.loads(account_detail['config'])
- user_cred = account_config.get('delegated_user_credential','N/A')
+ #user_cred = account_config.get('delegated_user_credential','N/A')
+ user_cred = account_config.get('user_credential','N/A')
if 'N/A' not in user_cred:
user_hrn = account_config.get('user_hrn','N/A')
user_pub_key = json.dumps(account_config.get('user_public_key','N/A'))
?
"""
+
+ authority_hrn = request['authority_hrn']
+ request['authority_hrn'] = authority_hrn.split(".")[0]
+
USER_CONFIG = '{"firstname": "%(first_name)s", "lastname": "%(last_name)s", "authority": "%(authority_hrn)s"}'
user_params = {
- 'email' : request['email'],
+ 'email' : request['username'],
'password' : request['password'],
'config' : USER_CONFIG % request,
- 'status' : 1,
+ 'status' : 1
}
+ request['authority_hrn'] = authority_hrn
+
query = Query.create('local:user').set(user_params).select('email')
results = execute_admin_query(request, query)
if not results:
results = execute_admin_query(request,query)
return results
+ def manifold_delete_user(request, user_id, user_params):
+ query = Query.delete('local:user').filter_by('user_id', '==', user_id).set(user_params).select('user_id')
+ results = execute_admin_query(request,query)
+ return results
+
#not tested
def manifold_add_platform(request, platform_params):
request['user_hrn'] = user.user_hrn
request['public_key'] = user.public_key
request['private_key'] = user.private_key
+ request['username'] = user.login
+ request['reasons'] = user.reasons
return request
def make_request_slice(slice):
return status
-
def validate_action(request, **kwargs):
ids = filter(None, kwargs['id'].split('/'))
status = portal_validate_request(request, ids)
json_answer = json.dumps(status)
return HttpResponse (json_answer, mimetype="application/json")
+
+ def reject_action(request, **kwargs):
+ ids = filter(None, kwargs['id'].split('/'))
+ status = portal_reject_request(request, ids)
+ json_answer = json.dumps(status)
+ return HttpResponse (json_answer, mimetype="application/json")
+
+
+ def portal_reject_request(wsgi_request, request_ids):
+ status = {}
+ # get the domain url
+ current_site = Site.objects.get_current()
+ current_site = current_site.domain
+
+
+ if not isinstance(request_ids, list):
+ request_ids = [request_ids]
+
+ requests = get_request_by_id(request_ids)
+ for request in requests:
+ # type, id, timestamp, details, allowed -- MISSING: authority_hrn
+ # CAREFUL about details
+ # user : first name, last name, email, password, keypair
+ # slice : number of nodes, type of nodes, purpose
+
+ request_status = {}
+
+ if request['type'] == 'user':
+ try:
+ request_status['SFA user'] = {'status': True }
+ # getting user email based on id
+ ## RAW SQL queries on Django DB- https://docs.djangoproject.com/en/dev/topics/db/sql/
+ for user in PendingUser.objects.raw('SELECT * FROM portal_pendinguser WHERE id = %s', [request['id']]):
+ user_email= user.email
+ first_name = user.first_name
+ last_name = user.last_name
+
+ ctx = {
+ 'first_name' : first_name,
+ 'last_name' : last_name,
+ 'portal_url' : current_site,
+ }
+ try:
+ theme.template_name = 'user_request_denied.txt'
+ text_content = render_to_string(theme.template, ctx)
+ theme.template_name = 'user_request_denied.html'
+ html_content = render_to_string(theme.template, ctx)
+ theme.template_name = 'email_default_sender.txt'
+ sender = render_to_string(theme.template, ctx)
+ sender = sender.replace('\n', '')
+
+ subject = 'User request denied.'
+
+ msg = EmailMultiAlternatives(subject, text_content, sender, [user_email])
+ msg.attach_alternative(html_content, "text/html")
+ msg.send()
+ except Exception, e:
+ print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
+
+ # removing from Django auth_user
+ UserModel = get_user_model()
+ UserModel._default_manager.filter(email__iexact = user_email).delete()
+ # removing from Django portal_pendinguser
+ PendingUser.objects.get(id=request['id']).delete()
+ # removing from manifold
+ # removing manifold account
+ user_query = Query().get('local:user') \
+ .filter_by('email', '==', user_email) \
+ .select('user_id')
+ user = execute_admin_query(wsgi_request, user_query)
+ user_id = user[0]['user_id']
+
+ platform_query = Query().get('local:platform') \
+ .filter_by('platform', '==', 'myslice') \
+ .select('platform_id')
+ platform = execute_admin_query(wsgi_request, platform_query)
+ platform_id = platform[0]['platform_id']
+ account_params = {'user_id':user_id}
+ manifold_delete_account(request, platform_id, user_id, account_params)
+
+ # removing manifold user
+ user_params = {'user_id':user_id}
+ manifold_delete_user(request, user_id, user_params)
+ except Exception, e:
+ request_status['SFA authority'] = {'status': False, 'description': str(e)}
+
+ elif request['type'] == 'slice':
+ request_status['SFA slice'] = {'status': True }
+
+ # getting user email based on id
+ ## RAW SQL queries on Django DB- https://docs.djangoproject.com/en/dev/topics/db/sql/
+ for user in PendingSlice.objects.raw('SELECT * FROM portal_pendingslice WHERE id = %s', [request['id']]):
+ user_email= user.type_of_nodes # XXX type_of_nodes field contains the email [shd be renamed in DB]
+ slice_name = user.slice_name
+ purpose = user.purpose
+ url = user.number_of_nodes
+
+ ctx = {
+ 'slice_name': slice_name,
+ 'purpose': purpose,
+ 'url': url,
+ 'portal_url': current_site,
+ }
+ try:
+ theme.template_name = 'slice_request_denied.txt'
+ text_content = render_to_string(theme.template, ctx)
+ theme.template_name = 'slice_request_denied.html'
+ html_content = render_to_string(theme.template, ctx)
+ theme.template_name = 'email_default_sender.txt'
+ sender = render_to_string(theme.template, ctx)
+ sender = sender.replace('\n', '')
+
+ subject = 'Slice request denied.'
+
+ msg = EmailMultiAlternatives(subject, text_content, sender, [user_email])
+ msg.attach_alternative(html_content, "text/html")
+ msg.send()
+ except Exception, e:
+ print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
+
+ PendingSlice.objects.get(id=request['id']).delete()
+
+ elif request['type'] == 'authority':
+ request_status['SFA authority'] = {'status': True }
+
+ # getting user email based on id
+ ## RAW SQL queries on Django DB- https://docs.djangoproject.com/en/dev/topics/db/sql/
+ for user in PendingAuthority.objects.raw('SELECT * FROM portal_pendingauthority WHERE id = %s', [request['id']]):
+ user_email= user.address_line1 # XXX address_line1 field contains the email [shd be renamed in DB]
+ site_name = user.site_name
+ city = user.address_city
+ country = user.address_country
+ short_name = user.site_abbreviated_name
+ url = user.site_url
+
+ ctx = {
+ 'site_name': site_name,
+ 'short_name': short_name,
+ 'url': url,
+ 'city': city,
+ 'country': country,
+ 'portal_url' : current_site,
+ }
+
+ try:
+ theme.template_name = 'authority_request_denied.txt'
+ text_content = render_to_string(theme.template, ctx)
+ theme.template_name = 'authority_request_denied.html'
+ html_content = render_to_string(theme.template, ctx)
+ theme.template_name = 'email_default_sender.txt'
+ sender = render_to_string(theme.template, ctx)
+ sender = sender.replace('\n', '')
+ subject = 'Authority request denied.'
+ msg = EmailMultiAlternatives(subject, text_content, sender, [user_email])
+ msg.attach_alternative(html_content, "text/html")
+ msg.send()
+ except Exception, e:
+ print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
+
+ PendingAuthority.objects.get(id=request['id']).delete()
+
+ status['%s__%s' % (request['type'], request['id'])] = request_status
+
+ return status
+
# Django and ajax
# http://djangosnippets.org/snippets/942/
user_hrn = request.get('user_hrn', None)
user_hrns = list([user_hrn]) if user_hrn else list()
- user_email = request.get
+ user_query = Query().get('user').select('user_hrn','user_email').filter_by('user_hrn','==',user_hrn)
+ user_details_sfa = execute_admin_query(wsgi_request, user_query)
+ if not user_details_sfa:
+ raise Exception, "User %s doesn't exist, validate user before validating slice" % user_hrn
+ for user in user_details_sfa:
+ user_email = user['user_email']
+
+ # XXX LOIC Quick fix because this is totally inconsistent
+ if not 'number_of_nodes' in request:
+ request['number_of_nodes']=""
# XXX We should create a slice with Manifold terminology
slice_params = {
'slice_hrn' : hrn,
'slice_urn' : urn,
'slice_type' : request['type'],
+ 'url' : request['number_of_nodes'],
'users' : user_hrns,
'slice_enabled' : True
}
results = execute_query(wsgi_request, query)
if not results:
raise Exception, "Could not create %s. Already exists ?" % slice_params['hrn']
- ## We do not store the email in pendingslice table. As a result receiver's email is unknown ##
- ## Need modification in pendingslice table ###
- #else:
- # subject = 'Slice created'
- # msg = 'A manager of your institution has validated your slice request. You can now add resources to the slice and start experimenting.'
- # send_mail(subject, msg, 'support@onelab.eu',['yasin.upmc@gmail.com'], fail_silently=False)
+ else:
+ clear_user_creds(wsgi_request,user_email)
+ # log user activity
+ activity.slice.validate(self.request, "Slice validation", { "slice" : hrn })
+ try:
+ theme.template_name = 'slice_request_validated.txt'
+ text_content = render_to_string(theme.template, request)
+ theme.template_name = 'slice_request_validated.html'
+ html_content = render_to_string(theme.template, request)
+
+ theme.template_name = 'email_default_sender.txt'
+ sender = render_to_string(theme.template, request)
+ sender = sender.replace('\n', '')
+
+ subject = 'Slice request validated'
+
+ msg = EmailMultiAlternatives(subject, text_content, sender, [user_email])
+ msg.attach_alternative(html_content, "text/html")
+ msg.send()
+ except Exception, e:
+ print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
return results
slice_name = request['slice_name'],
user_hrn = request['user_hrn'],
authority_hrn = request['authority_hrn'],
- number_of_nodes = request['exp_url'],
+ number_of_nodes = request['url'], # field needs to be renamed
purpose = request['purpose'],
+ type_of_nodes = request['email'] # field needs to be renamed
)
s.save()
subject = render_to_string(theme.template, request)
subject = subject.replace('\n', '')
- sender = email
+ theme.template_name = 'email_default_sender.txt'
+ sender = render_to_string(theme.template, request)
+ sender = sender.replace('\n', '')
+
+ #sender = email
msg = EmailMultiAlternatives(subject, text_content, sender, recipients)
msg.attach_alternative(html_content, "text/html")
msg.send()
# Retrieve user information
user_query = Query().get('local:user') \
.select('user_id', 'config', 'email', 'status') \
- .filter_by('email', '==', request['email'])
+ .filter_by('email', '==', request['username'])
user_details = execute_admin_query(wsgi_request, user_query)
# USER MAIN ACCOUNT != reference
}
manifold_add_account(wsgi_request, manifold_account_params)
- def sfa_create_user(wsgi_request, request):
+ def sfa_create_user(wsgi_request, request, namespace = None, as_admin = False):
"""
Arguments:
wsgi_request (~ WSGIRequest) :
'user_enabled' : True
}
- query = Query.create('user').set(sfa_user_params).select('user_hrn')
- results = execute_query(wsgi_request, query)
++ ## Conflict
++ #query = Query.create('user').set(sfa_user_params).select('user_hrn')
++ #results = execute_query(wsgi_request, query)
++
+ if namespace is not None:
+ query = Query.create('%s:user' % namespace).set(sfa_user_params).select('user_hrn')
+ else:
+ query = Query.create('user').set(sfa_user_params).select('user_hrn')
+
+ if as_admin:
+ results = execute_admin_query(wsgi_request, query)
+ else:
+ results = execute_query(wsgi_request, query)
if not results:
raise Exception, "Could not create %s. Already exists ?" % sfa_user_params['user_hrn']
else:
- try:
- theme.template_name = 'user_request_validated.txt'
- text_content = render_to_string(theme.template, request)
- theme.template_name = 'user_request_validated.html'
- html_content = render_to_string(theme.template, request)
-
- theme.template_name = 'email_default_sender.txt'
- sender = render_to_string(theme.template, request)
- sender = sender.replace('\n', '')
+ subject = 'User validated'
+ msg = 'A manager of your institution has validated your account. You have now full user access to the portal.'
+ send_mail(subject, msg, 'support@fibre.org.br',[request['email']], fail_silently=False)
+ return results
+def ls_create_user(wsgi_request, request, user_detail):
+ organization = request['username'].split('@')[1]
+ lsClient = LaboraSchedulerClient( organization )
- subject = 'User validated'
+ orgGIDNumber = lsClient.get_testbed_info()['gidnumber']
+ userHomeDirectory = "/home/" + organization + "/" + request['username'].split('@')[0]
+ userHomeDirectory = userHomeDirectory.encode('utf-8')
+
+ userData = {
+ 'username' : request['username'],
+ 'email' : request['email'].encode('utf-8'),
+ 'password' : request['password'].encode('utf-8'),
+ 'name' : str( request['first_name'].encode('latin1') ) + ' ' + str( request['last_name'].encode('latin1') ),
+ 'gidnumber' : orgGIDNumber,
+ 'homedirectory' : userHomeDirectory,
+ 'created_by' : "myslice"
+ }
+
+ # Add user in the island.
+ addUser = lsClient.add_user( userData )
+
+ # User successfully created, upload user public key.
+ if addUser:
+ ls_update_public_key( wsgi_request, request, lsClient, addUser )
+
+ return addUser
- msg = EmailMultiAlternatives(subject, text_content, sender, [request['email']])
- msg.attach_alternative(html_content, "text/html")
- msg.send()
- except Exception, e:
- print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
+def ls_validate_user(wsgi_request, request):
+ organization = request['username'].split('@')[1]
+ lsClient = LaboraSchedulerClient( organization )
+
+ userId = lsClient.get_user_id_by_username( { 'username': str( request['username'] ) } )
+
+ validate = False
+ if userId:
+ userData = {
+ 'user_id' : userId,
+ 'new_user_data' : { 'enable': 'TRUE' }
+ }
+
+ validate = lsClient.update_user( userData )
+
+ return validate and addUserPublicKey
- return results
+def ls_update_public_key( wsgi_request, request, lsClient, userId ):
+ userPbKey = {
+ 'user_id' : userId,
+ 'public_key' : request['public_key']
+ }
+
+ addUserPublicKey = lsClient.add_user_public_key( userPbKey )
+
+ return addUserPublicKey
- def create_user(wsgi_request, request):
+ def iotlab_create_user (wsgi_request, request, namespace = None, as_admin=False):
+
+ import requests
+ import time
+ from requests.auth import HTTPBasicAuth
+ URL_REST = 'https://devgrenoble.senslab.info/rest/admin/users'
+ LOGIN_ADMIN = "auge"
+ PASSWORD_ADMIN = "k,mfg1+Q"
+
+ auth = HTTPBasicAuth(LOGIN_ADMIN,PASSWORD_ADMIN)
+ headers = {'content-type': 'application/json'}
+
+ for user in PendingUser.objects.raw('SELECT * FROM portal_pendinguser WHERE email = %s', [request['email']]):
+ password= user.password
+
+
+ iotlab_user_params = {
+ "type" : "SA",
+ "login" : request['email'],
+ "password" : password,
+ "firstName" : request['first_name'],
+ "lastName" : request['last_name'],
+ "email" : request['email'],
+ "structure" : request['authority_hrn'],
+ "city" : "N/A",
+ "country" : "N/A",
+ "sshPublicKey" : [request['public_key']],
+ "motivations" : "SFA federation",
+ }
+
+ iotlab_user_params1 = json.dumps(iotlab_user_params)
+ r=requests.post(url=URL_REST, data=iotlab_user_params1, headers=headers, auth=auth)
+ print 'Create iotlab user : ', r.status_code, r.text
+ return r.text
+
+ def create_user(wsgi_request, request, namespace = None, as_admin = False):
# XXX This has to be stored centrally
USER_STATUS_ENABLED = 2
# NOTE : if we were to create a user directly (just like we create slices,
# we would have to perform the steps in create_pending_user too
+
+ # Edelberto - I put this more below
+ # Add the user to the SFA registry
+ #sfa_create_user(wsgi_request, request)
+ # Update Manifold user status
+ manifold_update_user(wsgi_request, request['username'], {'status': USER_STATUS_ENABLED})
+
+ # Add reference accounts for platforms
+ manifold_add_reference_user_accounts(wsgi_request, request)
+
++ # Conflict
++ # sfa_create_user(wsgi_request, request)
# Add the user to the SFA registry
- sfa_create_user(wsgi_request, request)
+ sfa_create_user(wsgi_request, request, namespace, as_admin)
+
+ # Validate the user using the LS API ( By Bruno - UFG ):
+ try:
+ ls_validate_user( wsgi_request, request )
+ except Exception, e:
+ "Error to validate the user in Labora Scheduler."
+
+def create_user_in_ldap(wsgi_request, request, user_detail):
+ """
+ """
+
+ # saves the user to django auth_user table [needed for password reset]
+ user = User.objects.create_user(request['username'], request['email'], request['password'])
+
+ # Creating a manifold user
+ user_id = manifold_add_user(wsgi_request, request)
+
+ # Creating a Manifold account on the MySlice platform
+ # Note the JSON representation of public and private keys already includes quotes
+ account_config = {
+ 'user_hrn' : request['user_hrn'],
+ 'user_public_key' : request['public_key'],
+ }
+ if request['private_key']:
+ account_config['user_private_key'] = request['private_key']
+
+ user_id = user_detail['user_id'] + 1 # the user_id for the newly created user in local:user
+
+ # XXX TODO: Require a myslice platform
+ # ALERT: this will disapear with ROUTERV2 of Manifold
+ # We have to consider the case where several registries can be used
+ # Removed hardcoded platform = 5
+ # This platform == 'myslice' is a TMP FIX !!
+ try:
+ reg_platform_query = Query().get('local:platform') \
+ .filter_by('platform', '==', 'myslice') \
+ .select('platform_id')
+ reg_platform = execute_admin_query(wsgi_request, reg_platform_query)
+ reg_platform_id = reg_platform[0]['platform_id']
+ account_params = {
+ 'platform_id' : reg_platform_id, # XXX ALERT !!
+ 'user_id' : user_id,
+ 'auth_type' : request['auth_type'],
+ 'config' : json.dumps(account_config),
+ }
+ manifold_add_account(wsgi_request, account_params)
+ except Exception, e:
+ print "Failed creating manifold account on platform %s for user: %s" % ('myslice', request['email'])
+
+ # XXX This has to be stored centrally
+ USER_STATUS_ENABLED = 2
# Update Manifold user status
- manifold_update_user(wsgi_request, request['email'], {'status': USER_STATUS_ENABLED})
+ manifold_update_user(wsgi_request, request['username'], {'status': USER_STATUS_ENABLED})
# Add reference accounts for platforms
manifold_add_reference_user_accounts(wsgi_request, request)
+
+ organization = request['username'].split('@')[1]
+ lsClient = LaboraSchedulerClient( organization )
+
+ userId = lsClient.get_user_id_by_username( { 'username': str( request['username'] ) } )
+
+ ls_up_pkey = ls_update_public_key( wsgi_request, request, lsClient, userId )
+
+ if ls_up_pkey:
+ print "OK PKEY"
+
+ from sfa.util.xrn import Xrn
+
+ auth_pi = request.get('pi', None)
+ auth_pi = list([auth_pi]) if auth_pi else list()
+
+ # We create a user request with Manifold terminology
+ sfa_user_params = {
+ 'user_hrn' : request['user_hrn'],
+ 'user_email' : request['email'],
+ 'user_urn' : Xrn(request['user_hrn'], request['type']).get_urn(),
+ 'user_type' : request['type'],
+ 'keys' : request['public_key'],
+ 'user_first_name' : request['first_name'],
+ 'user_last_name' : request['last_name'],
+ 'pi_authorities' : auth_pi,
+ 'user_enabled' : True
+ }
+
+ print request['user_hrn']
+ print request['email']
+ print request['first_name']
+ print request['last_name']
+ print request['type']
+ print request['public_key']
+
+ query = Query.create('user').set(sfa_user_params).select('user_hrn')
+
+ print query
+
+ results = execute_admin_query(wsgi_request, query)
+
+ print results
+
+ if not results:
+ raise Exception, "Could not create %s. Already exists ?" % sfa_user_params['user_hrn']
+ else:
+ subject = 'User validated'
+ msg = 'A manager of your institution has validated your account. You have now full user access to the portal.'
+ send_mail(subject, msg, 'support@fibre.org.br',[request['email']], fail_silently=False)
+ return results
+ # Add the user to iotlab portal if theme is set to onelab
+ if theme.theme == 'onelab':
+ iotlab_create_user (wsgi_request, request)
+
def create_pending_user(wsgi_request, request, user_detail):
"""
"""
last_name = request['last_name'],
authority_hrn = request['authority_hrn'],
email = request['email'],
+ login = request['username'],
password = request['password'],
public_key = request['public_key'],
private_key = request['private_key'],
user_hrn = request['user_hrn'],
pi = request['pi'],
email_hash = request['email_hash'],
+ reasons = request['reasons'],
status = 'False',
)
b.save()
+
# sends email to user to activate the email
theme.template_name = 'activate_user.html'
html_content = render_to_string(theme.template, request)
theme.template_name = 'activate_user_email_subject.txt'
subject = render_to_string(theme.template, request)
subject = subject.replace('\n', '')
- #sender = 'support@myslice.info'
theme.template_name = 'email_default_sender.txt'
sender = render_to_string(theme.template, request)
sender = sender.replace('\n', '')
msg.send()
# saves the user to django auth_user table [needed for password reset]
- user = User.objects.create_user(request['email'], request['email'], request['password'])
+ user = User.objects.create_user(request['username'], request['email'], request['password'])
# Creating a manifold user
user_id = manifold_add_user(wsgi_request, request)
.filter_by('platform', '==', 'myslice') \
.select('platform_id')
reg_platform = execute_admin_query(wsgi_request, reg_platform_query)
-
reg_platform_id = reg_platform[0]['platform_id']
account_params = {
'platform_id' : reg_platform_id, # XXX ALERT !!
}
manifold_add_account(wsgi_request, account_params)
except Exception, e:
- print "Failed creating manifold account on platform %s for user: %s" % ('myslice', request['email'])
+ print "Failed creating manifold account on platform %s for user: %s" % ('myslice', request['email'])
+
+ # Add user to island using LS API ( By Bruno - UFG )
+ ls_user_create = ls_create_user( wsgi_request, request, user_detail )
try:
# Send an email: the recipients are the PI of the authority
# If No PI is defined for this Authority, send to a default email (different for each theme)
- recipients = authority_get_pi_emails(wsgi_request, request['authority_hrn'])
-
+
+ split_authority_hrn = request['authority_hrn'].split(".")[0]
+
+ recipients = authority_get_pi_emails(wsgi_request, split_authority_hrn)
+
+ pis = authority_get_pis(request, split_authority_hrn)
+ pi_emails = []
+ for x in pis:
+ for e in x['pi_users']:
+ try:
+ u = e.split(".")[1]
+ y = User.objects.get(username = u)
+ if y.username.count("@") != 0:
+ if y.username.split("@")[1] == request['username'].split("@")[1]:
+ pi_emails += [y.email]
+ except:
+ print "fail"
+
theme.template_name = 'user_request_email.html'
html_content = render_to_string(theme.template, request)
sender = render_to_string(theme.template, request)
sender = sender.replace('\n', '')
- msg = EmailMultiAlternatives(subject, text_content, sender, recipients)
+ msg = EmailMultiAlternatives(subject, text_content, sender, pi_emails)
+
msg.attach_alternative(html_content, "text/html")
msg.send()
+ print pi_emails
except Exception, e:
print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
import traceback
import json
from myslice.theme import ThemeView
+
+ import activity.user
+
theme = ThemeView()
# splitting the 2 functions done here
subject = form.cleaned_data['subject']
description = form.cleaned_data['description']
email = form.cleaned_data['email'] # email of the sender
- cc_myself = form.cleaned_data['cc_myself']
+ #cc_myself = form.cleaned_data['cc_myself']
#try:
# Send an email: the support recipients
- #theme.template_name = 'email_support.txt'
- #recipients = render_to_string(theme.template, form.cleaned_data)
- #recipients = subject.replace('\n', '')
- recipients = ['support@myslice.info']
- if cc_myself:
- recipients.append(email)
- #recipients = ['support@myslice.info']
+ theme.template_name = 'email_default_recipients.txt'
+ recipients = render_to_string(theme.template, form.cleaned_data)
+ recipients = recipients.replace('\n', '')
+ #recipients = ['support@onelab.eu']
+ ## removed it cz recipients is not a list so append doesn't work ###
+ ## we don't need it cz the new ticketing systems sends a confirmation email ###
+ #if cc_myself:
+ # recipients.append(email)
theme.template_name = 'contact_support_email.html'
html_content = render_to_string(theme.template, form.cleaned_data)
# else:
sender = email
- msg = EmailMultiAlternatives(subject, text_content, sender, recipients)
+ msg = EmailMultiAlternatives(subject, text_content, sender, [recipients])
msg.attach_alternative(html_content, "text/html")
msg.send()
#except Exception, e:
username = request.user.email
else :
username = None
+ # log user activity
+ activity.user.contact(self.request)
return render(request,'contact_sent.html', { 'theme' : self.theme, 'username': username}) # Redirect after POST
else:
return self._display (request, form)
'theme' : self.theme,
'username': username,
'pi': pi,
- 'section': "Contact"
+ 'section': "Contact",
+ 'email': request.user.username
})
#
from manifold.core.query import Query
from manifoldapi.manifoldapi import execute_query, execute_admin_query
- from portal.actions import manifold_update_user, manifold_update_account, manifold_add_account, manifold_delete_account, sfa_update_user, authority_get_pi_emails, authority_get_pis
-from portal.actions import manifold_update_user, manifold_update_account, manifold_add_account, manifold_delete_account, sfa_update_user, authority_get_pi_emails, make_request_user, create_user
++from portal.actions import manifold_update_user, manifold_update_account, manifold_add_account, manifold_delete_account, sfa_update_user, authority_get_pi_emails, make_request_user, create_user, authority_get_pis
#
from unfold.page import Page
from ui.topmenu import topmenu_items_live, the_user
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from myslice.theme import ThemeView
- from portal.models import PendingUser
+ from portal.models import PendingUser, PendingAuthority
from django.core.mail import EmailMultiAlternatives, send_mail
from django.contrib.sites.models import Site
-
+from django.contrib.auth.models import User
#
import json, os, re, itertools
+ def ValuesQuerySetToDict(vqs):
+ return [item for item in vqs]
+
# requires login
class ActivateEmailView(FreeAccessView, ThemeView):
template_name = "email_activation.html"
+ def is_ple_enabled(self, pending_user):
+ pending_authorities = PendingAuthority.objects.filter(site_authority__iexact = pending_user.authority_hrn)
+ if pending_authorities:
+ return False
+ pending_user_email = pending_user.email
+ query = Query.get('myplcuser').filter_by('email', '==', pending_user_email).select('enabled')
+ results = execute_admin_query(self.request, query)
+ for result in results:
+ # User is enabled in PLE
+ if 'enabled' in result and result['enabled']==True:
+ return True
+ return False
+
def dispatch(self, *args, **kwargs):
return super(ActivateEmailView, self).dispatch(*args, **kwargs)
-
def get_context_data(self, **kwargs):
page = Page(self.request)
#print "%s = %s" % (key, value)
if key == "hash_code":
hash_code=value
-
- if PendingUser.objects.filter(email_hash__iexact = hash_code):
- #get_user = PendingUser.objects.filter(email_hash__iexact = hash_code)
- #get_user.status= 'True'
- #get_user.save()
- #for user in PendingUser.objects.all():
- # first_name = user.first_name
- # last_name = user.last_name
- # authority_hrn = user.authority_hrn
- # public_key = user.public_key
- # email = user.email
- # user_hrn = user.user_hrn
- PendingUser.objects.filter(email_hash__iexact = hash_code).update(status='True')
+ if PendingUser.objects.filter(email_hash__iexact = hash_code).filter(status__iexact = 'False'):
activation = 'success'
- split_authority_hrn = request[0].authority_hrn.split('.')[0]
- pis = authority_get_pis(request, split_authority_hrn)
- pi_emails = []
- for x in pis:
- for e in x['pi_users']:
- u = e.split('.')[1]
- y = User.Objects.get(username = u)
- if y.username.count("@") != 0:
- if y.username.split("@")[1] == request[0].user_hrn.split("@")[1]:
- pi_emails += [y.email]
- subject = 'User email activated'
- msg = 'The user %s has validated his/her email. Now you can validate his/her account' % (request[0].login)
- send_mail(subject, msg, 'support@fibre.org.br', pi_emails, fail_silently = False)
- except:
- print "error sending the email!"
- #try:
- # Send an email: the recipients are the PI of the authority
- # If No PI is defined for this Authority, send to a default email (different for each theme)
- # recipients = authority_get_pi_emails(wsgi_request, authority_hrn)
- # theme.template_name = 'user_request_email.html'
- # html_content = render_to_string(theme.template, request)
- # theme.template_name = 'user_request_email.txt'
- # text_content = render_to_string(theme.template, request)
- # theme.template_name = 'user_request_email_subject.txt'
- # subject = render_to_string(theme.template, request)
- # subject = subject.replace('\n', '')
- # theme.template_name = 'email_default_sender.txt'
- # sender = render_to_string(theme.template, request)
- # sender = sender.replace('\n', '')
- # msg = EmailMultiAlternatives(subject, text_content, sender, recipients)
- # msg.attach_alternative(html_content, "text/html")
- # msg.send()
- # except Exception, e:
- # print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
- # import traceback
- # traceback.print_exc()
+ # sending email after activation success
+ try:
+ request = PendingUser.objects.filter(email_hash= hash_code)
++ split_authority_hrn = request[0].authority_hrn.split('.')[0]
++ pis = authority_get_pis(request, split_authority_hrn)
++ pi_emails = []
++ for x in pis:
++ for e in x['pi_users']:
++ u = e.split('.')[1]
++ y = User.Objects.get(username = u)
++ if y.username.count("@") != 0:
++ if y.username.split("@")[1] == request[0].user_hrn.split("@")[1]:
++ pi_emails += [y.email]
++ subject = 'User email activated'
++ msg = 'The user %s has validated his/her email. Now you can validate his/her account' % (request[0].login)
++ send_mail(subject, msg, 'support@fibre.org.br', pi_emails, fail_silently = False)
++ except:
++ print "error sending the email!"
++ #try:
++ # Send an email: the recipients are the PI of the authority
++ # If No PI is defined for this Authority, send to a default email (different for each theme)
++ # recipients = authority_get_pi_emails(wsgi_request, authority_hrn)
++ # theme.template_name = 'user_request_email.html'
++ # html_content = render_to_string(theme.template, request)
++ # theme.template_name = 'user_request_email.txt'
++ # text_content = render_to_string(theme.template, request)
++ # theme.template_name = 'user_request_email_subject.txt'
++ # subject = render_to_string(theme.template, request)
++ # subject = subject.replace('\n', '')
++ # theme.template_name = 'email_default_sender.txt'
++ # sender = render_to_string(theme.template, request)
++ # sender = sender.replace('\n', '')
++ # msg = EmailMultiAlternatives(subject, text_content, sender, recipients)
++ # msg.attach_alternative(html_content, "text/html")
++ # msg.send()
++ # except Exception, e:
++ # print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
++ # import traceback
++ # traceback.print_exc()
+
+ # AUTO VALIDATION of PLE enabled users (only for OneLab Portal)
+ if self.theme == "onelab":
+ # Auto-Validation of pending user, which is enabled in a trusted SFA Registry (example: PLE)
+ # We could check in the Registry based on email, but it takes too long
+ # as we currently need to do a Resolve on each user_hrn of the Registry in order to get its email
+ # TODO in SFA XXX We need a Resolve based on email
+ # TODO maybe we can use MyPLC API for PLE
+ pending_users = PendingUser.objects.filter(email_hash__iexact = hash_code)
+ # by default user is not in PLE
+ ple_user_enabled = False
+
+ if pending_users:
+ pending_user = pending_users[0]
+
+ # Auto Validation
+ if self.is_ple_enabled(pending_user):
+ pending_user_request = make_request_user(pending_user)
+ # Create user in SFA and Update in Manifold
+ create_user(self.request, pending_user_request, namespace = 'myslice', as_admin = True)
+ # Delete pending user
+ PendingUser.objects.filter(email_hash__iexact = hash_code).delete()
+
+ # template user auto validated
+ activation = 'validated'
+
+ # sending email after activation success
+ #try:
+ # # Send an email: the recipient is the user
+ # recipients = pending_user_eamil
+ # theme.template_name = 'user_request_email.html'
+ # html_content = render_to_string(theme.template, request)
+ # theme.template_name = 'user_request_email.txt'
+ # text_content = render_to_string(theme.template, request)
+ # theme.template_name = 'user_request_email_subject.txt'
+ # subject = render_to_string(theme.template, request)
+ # subject = subject.replace('\n', '')
+ # theme.template_name = 'email_default_sender.txt'
+ # sender = render_to_string(theme.template, request)
+ # sender = sender.replace('\n', '')
+ # msg = EmailMultiAlternatives(subject, text_content, sender, recipients)
+ # msg.attach_alternative(html_content, "text/html")
+ # msg.send()
+ #except Exception, e:
+ # print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
+ # import traceback
+ # traceback.print_exc()
+
+ PendingUser.objects.filter(email_hash__iexact = hash_code).update(status='True')
else:
activation = 'failed'
# this somehow is not used anymore - should it not be ?
from django.core.context_processors import csrf
from django.http import HttpResponseRedirect
-from django.contrib.auth import authenticate, login, logout
+from django.contrib.auth import authenticate, login, logout, get_user_model
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.shortcuts import render
+
import json
from unfold.loginrequired import FreeAccessView
from manifold.core.query import Query
-from manifoldapi.manifoldapi import execute_query
+#from manifoldapi.manifoldapi import execute_query
+# LDAP query admin // If transfer this code to actions.py maybe don't need more execute_admin_query
+from manifoldapi.manifoldapi import execute_query, execute_admin_query
+# Edelberto - LDAP XXX
+from portal.models import PendingUser
+from django.contrib.auth.models import User #Pedro
+from portal.actions import create_pending_user, create_user, create_user_in_ldap, clear_user_creds
+from registrationview import RegistrationView
+from random import randint
+from hashlib import md5
+from django.contrib.sites.models import Site
+import os.path, re
+##################
+
from manifoldapi.manifoldresult import ManifoldResult
from ui.topmenu import topmenu_items, the_user
from myslice.theme import ThemeView
-import activity.user
+# Edelberto LDAP authentication XXX
+import ldap
+
++#import activity.user
+
class HomeView (FreeAccessView, ThemeView):
template_name = 'home-view.html'
env['theme'] = self.theme
env['section'] = "Dashboard"
- username = request.POST.get('username')
+ username = request.POST.get('username').lower()
password = request.POST.get('password')
-
- # pass request within the token, so manifold session key can be attached to the request session.
- token = {'username': username, 'password': password, 'request': request}
-
- # our authenticate function returns either
- # . a ManifoldResult - when something has gone wrong, like e.g. backend is unreachable
- # . a django User in case of success
- # . or None if the backend could be reached but the authentication failed
- auth_result = authenticate(token=token)
- # use one or two columns for the layout - not logged in users will see the login prompt
- # high-level errors, like connection refused or the like
- if isinstance (auth_result, ManifoldResult):
- manifoldresult = auth_result
- # let's use ManifoldResult.__repr__
- env['state']="%s"%manifoldresult
-
- return render_to_response(self.template,env, context_instance=RequestContext(request))
- # user was authenticated at the backend
- elif auth_result is not None:
- user=auth_result
- if user.is_active:
- print "LOGGING IN"
- login(request, user)
-
- if request.user.is_authenticated():
- env['person'] = self.request.user
- env['username'] = self.request.user
-
- # log user activity
- activity.user.login(self.request)
-
- ## check user is pi or not
- platform_details = {}
- account_details = {}
- acc_auth_cred = {}
- acc_user_cred = {}
- 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')
- acc_user_cred = account_config.get('delegated_user_credential','N/A')
- # assigning values
- if acc_auth_cred=={} or acc_auth_cred=='N/A':
- pi = "is_not_pi"
- else:
- pi = "is_pi"
-
- # check if the user has creds or not
- if acc_user_cred == {} or acc_user_cred == 'N/A':
- user_cred = 'no_creds'
- else:
- user_cred = 'has_creds'
-
-
- env['pi'] = pi
- env['user_cred'] = user_cred
- else:
- env['person'] = None
- return render_to_response(self.template,env, context_instance=RequestContext(request))
- else:
- # log user activity
- activity.user.login(self.request, "notactive")
- env['state'] = "Your account is not active, please contact the site admin."
- env['layout_1_or_2']="layout-unfold2.html"
-
- return render_to_response(self.template,env, context_instance=RequestContext(request))
- # otherwise
+
+ # LDAP form - If FIBRE, then get the possibilite to authenticate using usernameldap
+ #if self.theme == 'fibre':
+ #usernameldap = request.POST.get('usernameldap')
+ #token = {'usernameldap': usernameldap, 'username': username ,'password': password, 'request': request}
+
+ ##################################################
+ ########## XXX Edelberto 010914 XXX
+ #################################################
+ ## first you must open a connection to the server
+ try:
+ # Connect to NOC
+ l = ldap.initialize("ldap://10.128.0.50:389")
+ # Bind/authenticate with a root user to search all objects
+ l.simple_bind_s("cn=Manager,dc=br,dc=fibre","fibre2013")
+
+ l.protocol_version = ldap.VERSION3
+ except ldap.LDAPError, e:
+ print e
+
+ ## Base directory
+ baseDN = "dc=fibre"
+ searchScope = ldap.SCOPE_SUBTREE
+ ## retrieve all attributes
+ retrieveAttributes = None
+ #retrieveAttributes = ['userEnable']
+ searchFilter = "uid=" + username
+ print searchFilter
+
+ in_ldap = 0
+
+ try:
+ if username != "admin":
+ ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes)
+ result_set = []
+ result_type, result_data = l.result(ldap_result_id, 0)
+ if (result_data == []):
+ print "User doesnt exist in LDAP"
+ in_ldap = 0
+ else:
+ if result_type == ldap.RES_SEARCH_ENTRY:
+ result_set.append(result_data)
+ else:
+ result_set.append(result_data)
+ # TRUE or FALSE for userEnable attribute
+ userEnable = result_set[0][0][1]['userEnable'][0]
+ if userEnable == 'TRUE':
+ in_ldap = 1
+ enabled = 1
+ print "In LDAP and Enabled"
+
+ dn = result_set[0][0][0]
+ try:
+ l.simple_bind_s(dn,password)
+ pwd = 1
+ print "User password OK"
+
+ except:
+ pwd = 0
+ print "User password WRONG"
+
+ if in_ldap and enabled and pwd:
+ ldap_mail = result_set[0][0][1]['mail'][0]
+
+ user_exists = Query().get('local:user') \
+ .select('status') \
+ .filter_by('email', '==', username)
+ results = execute_admin_query(request, user_exists)
+ print "DEBUG: %s" % user_exists
+ if results:
+ print "DEBUG: user exists on MySlice DBs"
+ else:
+ print "DEBUG: user NOT exists on MySlice DBs"
+
+ cn = result_set[0][0][1]['cn'][0]
+ sn = result_set[0][0][1]['sn'][0]
+
+ fname=None
+ lname=None
+
+ try:
+ fname = sn.split(' ')[0]
+ lname = sn.split(' ')[1]
+ except:
+ fname = sn
+ lname = ""
+
+ #authority_hrn = 'fibre' + '.' + username.split('@')[1]
+ authority_hrn = 'fibre'
+ print authority_hrn
+ email = ldap_mail
+ print ldap_mail
+ username = username
+ print username
+ password = password
+ print password
+ # user_hrn = 'fibre' + '.' + username.split('@')[1] + '.' + username
+ user_hrn = 'fibre' + '.' + username
+ print user_hrn
+
+ # Based on registrationview
+
+
+ # get the domain url
+ current_site = Site.objects.get_current()
+ current_site = current_site.domain
+ print current_site
+
+ post_email = ldap_mail
+ salt = randint(1,100000)
+ email_hash = md5(str(salt)+post_email).hexdigest()
+ print email_hash
+
+ user_request = {
+ 'first_name' : fname,
+ 'last_name' : lname,
+ 'organization' : authority_hrn,
+ 'authority_hrn' : authority_hrn,
+ 'email' : ldap_mail,
+ 'username' : username,
+ 'password' : password,
+ 'current_site' : current_site,
+ 'email_hash' : email_hash,
+ 'pi' : '',
+ 'user_hrn' : user_hrn,
+ 'reasons' : 'already exists in the LDAP',
+ 'type' : 'user',
+ 'validation_link': 'https://' + current_site + '/portal/email_activation/'+ email_hash
+ }
+
+ # Validate input
+ errors = []
+ UserModel = get_user_model()
+ if (re.search(r'^[\w+\s.@+-]+$', user_request['first_name']) == None):
+ errors.append('First name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
+ if (re.search(r'^[\w+\s.@+-]+$', user_request['last_name']) == None):
+ errors.append('Last name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
+ if (re.search(r'^[\w,]+$' , username) == None):
+ errors.append('Username may contain only letters,numbers and -/_ characters.')
+ # checking in django_db !!
+ if PendingUser.objects.filter(email__iexact = user_request['email']):
+ errors.append('Email is pending for validation. Please provide a new email address.')
+ if User.objects.filter(username__iexact = user_request['username']):
+ errors.append('This username is already in use, try another one')
+ # Does the user exist in Manifold?
+ user_query = Query().get('local:user').select('user_id','email')
+ user_details = execute_admin_query(request, user_query)
+ for user_detail in user_details:
+ if user_detail['email'] == user_request['email']:
+ errors.append('Email already registered in Manifold. Please provide a new email address.')
+ # Does the user exist in sfa? [query is very slow!!]
+ #user_query = Query().get('user').select('user_hrn','user_email')
+ # XXX Test based on the user_hrn is quick
+ #user_query = Query().get('user').select('user_hrn','user_email').filter_by('user_hrn','==',user_request['user_hrn'])
+ user_query = Query().get('user').select('user_hrn','user_email').filter_by('user_hrn','==',user_hrn)
+ user_details_sfa = execute_admin_query(request, user_query)
+
+ #if 'generate' in wsgi_request.POST['question']:
+ user_request['auth_type'] = 'managed'
+
+ # XXX Common code, dependency ?
+ from Crypto.PublicKey import RSA
+ private = RSA.generate(1024)
+
+ # Example: private_key = '-----BEGIN RSA PRIVATE KEY-----\nMIIC...'
+ # Example: public_key = 'ssh-rsa AAAAB3...'
+ user_request['private_key'] = private.exportKey()
+ user_request['public_key'] = private.publickey().exportKey(format='OpenSSH')
+
+ # XXX Verify if errors exist - After!
+ #if not errors:
+ create_user_in_ldap(request, user_request, user_detail)
+ #create_pending_user(request, user_request, user_detail)
+
+ #create_user(request, user_request)
+
+ env['state'] = "LDAP associated. Please, login again."
+ return render_to_response(self.template, env, context_instance=RequestContext(request))
+
+
+ else:
+ env['state'] = "Access denied. Verify LDAP userEnable and password."
+ return render_to_response(self.template, env, context_instance=RequestContext(request))
+
+ else:
+ in_ldap = 1
+ enabled = 0
+ print "In LDAP but Disabled"
+ env['state'] = "Access denied. Verify LDAP userEnable."
+ return render_to_response(self.template, env, context_instance=RequestContext(request))
+
+ #print result_set
+ except ldap.LDAPError, e:
+ print e
+
+ #else:
+ if in_ldap and enabled and pwd or username=="admin":
+
+################################################################################
+### XXX Edelberto LDAP auth end XXX
+###############################################################################
+ # Follow original code
+ ## pass request within the token, so manifold session key can be attached to the request session.
+ token = {'username': username, 'password': password, 'request': request}
+
+ # our authenticate function returns either
+ # . a ManifoldResult - when something has gone wrong, like e.g. backend is unreachable
+ # . a django User in case of success
+ # . or None if the backend could be reached but the authentication failed
+ auth_result = authenticate(token=token)
+ # use one or two columns for the layout - not logged in users will see the login prompt
+ # high-level errors, like connection refused or the like
+ if isinstance (auth_result, ManifoldResult):
+ manifoldresult = auth_result
+ # let's use ManifoldResult.__repr__
+ env['state']="%s"%manifoldresult
+
+ return render_to_response(self.template,env, context_instance=RequestContext(request))
+ # user was authenticated at the backend
+ elif auth_result is not None:
+ user=auth_result
+ if user.is_active:
+ print "LOGGING IN"
+ login(request, user)
+
+ if request.user.is_authenticated():
+ env['person'] = self.request.user
+ env['username'] = self.request.user
+
+ ## 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')
+
+ # Edleberto
+ #cc_auth_cred = {}
+
+ 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=={} or acc_auth_cred=='N/A':
+ pi = "is_not_pi"
+ else:
+ pi = "is_pi"
+ env['pi'] = pi
+ else:
+ env['person'] = None
+ return render_to_response(self.template,env, context_instance=RequestContext(request))
+ else:
+ env['state'] = "Your account is not active, please contact the site admin."
+ env['layout_1_or_2']="layout-unfold2.html"
+
+ return render_to_response(self.template,env, context_instance=RequestContext(request))
+ # otherwise
else:
- activity.user.login(self.request, "error")
+ # log user activity
++ #activity.user.login(self.request, "error")
env['state'] = "Your username and/or password were incorrect."
return render_to_response(self.template, env, context_instance=RequestContext(request))
env = self.default_env()
acc_auth_cred={}
if request.user.is_authenticated():
+
## check user is pi or not
+ platform_details = {}
+ account_details = {}
+ acc_auth_cred = {}
+ acc_user_cred = {}
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')
# XXX Something like an invalid session seems to make the execute fail sometimes, and thus gives an error on the main page
account_config = json.loads(account_detail['config'])
if 'myslice' in platform_detail['platform']:
acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
+ acc_user_cred = account_config.get('delegated_user_credential','N/A')
# assigning values
if acc_auth_cred=={} or acc_auth_cred=='N/A':
pi = "is_not_pi"
else:
pi = "is_pi"
- env['pi'] = pi
+ # check if the user has creds or not
+ if acc_user_cred == {} or acc_user_cred == 'N/A':
+ user_cred = 'no_creds'
+ else:
+ user_cred = 'has_creds'
+
+
+ env['pi'] = pi
+ env['user_cred'] = user_cred
env['person'] = self.request.user
else:
env['person'] = None
from myslice.theme import ThemeView
import json
+import ast
class ManagementRequestsView (LoginRequiredView, ThemeView):
template_name = "management-tab-requests.html"
ctx_delegation_authorities = {}
ctx_sub_authorities = {}
dest = {}
-
+ user_username = ''
+ user_authority = ''
# The user need to be logged in
if (self.request.user):
- user_query = Query().get('local:user').filter_by('email', '==', self.request.user.email).select('user_id')
+ user_query = Query().get('local:user').filter_by('email', '==', self.request.user.username).select('user_id')
user, = execute_query(self.request, user_query)
user_id = user['user_id']
-
+ user_query = Query().get('local:user').filter_by('email', '==', self.request.user.username).select('config')
+ user, = execute_query(self.request, user_query)
+ user_config = user['config']
+ user_config = ast.literal_eval(user_config)
+ user_authority = user_config['authority']
+ user_username = self.request.user.username
# Query manifold to learn about available SFA platforms for more information
# In general we will at least have the portal
# For now we are considering all registries
# iterate on the requests and check if the authority matches a prefix
# startswith an authority on which the user is PI
requests = get_requests()
- for r in requests:
- auth_hrn = r['authority_hrn']
+ auth_hrn = ''
+ for r in requests:
+ auth_hrn = r['authority_hrn']
for my_auth in pi_my_authorities:
if auth_hrn.startswith(my_auth):
dest = ctx_my_authorities
# env['pi'] = "is_pi"
# env['theme'] = self.theme
# env['section'] = "Requests"
-
+# auth_hrn = user_authority + '.' + user_username.split("@")[1]
+ ctx_list = [ctx_my_authorities, ctx_sub_authorities, ctx_delegation_authorities]
+ for ctx in ctx_list:
+ if ctx:
+ for authorities in ctx:
+ for requests in ctx[authorities]:
+ try:
+ requests['object_auth'] = requests['user_hrn'].split('.')[0] + '.' + requests['user_hrn'].split('@')[1]
+ except:
+ print "This object has no user_hrn"
+
+ pi_authority = user_authority + '.' + user_username.split("@")[1]
context = super(ManagementRequestsView, self).get_context_data(**kwargs)
- print "testing"
- print ctx_my_authorities
- print auth_hrn
- print user_username
- print pi_authority
-
-
++ #print "testing"
++ #print ctx_my_authorities
++ #print auth_hrn
++ #print user_username
++ #print pi_authority
context['my_authorities'] = ctx_my_authorities
context['sub_authorities'] = ctx_sub_authorities
context['delegation_authorities'] = ctx_delegation_authorities
context['pi'] = "is_pi"
context['theme'] = self.theme
context['section'] = "Requests"
+ context['pi_authority'] = pi_authority
# XXX We need to prepare the page for queries
#context.update(page.prelude_env())
from django.views.generic import View
from django.template.loader import render_to_string
+
from django.shortcuts import render
from django.contrib.auth import get_user_model
from django.contrib.sites.models import Site
from manifold.core.query import Query
from portal.models import PendingUser
+from django.contrib.auth.models import User #Pedro
+
from portal.actions import create_pending_user
from myslice.theme import ThemeView
+ import activity.user
+
# since we inherit from FreeAccessView we cannot redefine 'dispatch'
# so let's override 'get' and 'post' instead
#
"""
errors = []
authority_hrn = None
- authorities_query = Query.get('authority').select('name', 'authority_hrn')
+ authorities_query = Query.get('authority').select('name','authority_hrn')
authorities = execute_admin_query(wsgi_request, authorities_query)
if authorities is not None:
authorities = sorted(authorities)
+ print "############ BREAKPOINT 1 #################"
# Page rendering
page = Page(wsgi_request)
page.add_js_files ( [ "js/jquery.validate.js", "js/my_account.register.js", "js/jquery.qtip.min.js","js/jquery-ui.js" ] )
page.add_css_files ( [ "css/onelab.css", "css/registration.css", "css/jquery.qtip.min.css" ] )
page.add_css_files ( [ "https://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" ] )
-
+ print "############ BREAKPOINT 2 #################"
if method == 'POST':
reg_form = {}
# The form has been submitted
# get the domain url
current_site = Site.objects.get_current()
current_site = current_site.domain
-
+
- #authorities_query = Query.get('authority').select('name', 'authority_hrn')
- #authorities = execute_admin_query(wsgi_request, authorities_query)
-
+ print "############ BREAKPOINT 3 #################"
-
++
for authority in authorities:
if authority['name'] == wsgi_request.POST.get('org_name', ''):
authority_hrn = authority['authority_hrn']
# Handle the case when the template uses only hrn and not name
if authority_hrn is None:
authority_hrn = wsgi_request.POST.get('org_name', '')
-
+
+ print "############ BREAKPOINT 4 #################"
+
post_email = wsgi_request.POST.get('email','').lower()
salt = randint(1,100000)
email_hash = md5(str(salt)+post_email).hexdigest()
'organization' : wsgi_request.POST.get('org_name', ''),
'authority_hrn' : authority_hrn,
'email' : post_email,
+ 'username' : wsgi_request.POST.get('username','').lower(),
'password' : wsgi_request.POST.get('password', ''),
+ 'reasons' : wsgi_request.POST.get('reasons', ''),
'current_site' : current_site,
'email_hash' : email_hash,
'pi' : '',
- 'validation_link': 'http://' + current_site + '/portal/email_activation/'+ email_hash
+ 'validation_link': 'https://' + current_site + '/portal/email_activation/'+ email_hash
}
-
+
+ print "############ BREAKPOINT 5 #################"
+
# Construct user_hrn from email (XXX Should use common code)
- split_email = user_request['email'].split("@")[0]
- split_email = split_email.replace(".", "_")
- # Replace + by _ => more convenient for testing and validate with a real email
- split_email = split_email.replace("+", "_")
- user_request['user_hrn'] = user_request['authority_hrn'] \
- + '.' + split_email
+ # split_email = user_request['email'].split("@")[0]
+ # split_email = split_email.replace(".", "_")
+ # user_request['user_hrn'] = user_request['authority_hrn'] \
+ # + '.' + split_email
+ username = user_request['username']
+
+ if user_request['authority_hrn'] == "fibre" :
+ user_request['username'] = user_request['username'] + "@" + "rnp" # catch-all island
+ split_authority = user_request['authority_hrn']
+ else :
+ split_authority = user_request['authority_hrn'].split(".")[1]
+ user_request['username'] = user_request['username'] + '@' + split_authority
+ split_authority = user_request['authority_hrn'].split(".")[0]
+
+ user_request['user_hrn'] = split_authority + '.' + user_request['username']
+
# Validate input
UserModel = get_user_model()
if (re.search(r'^[\w+\s.@+-]+$', user_request['first_name']) == None):
errors.append('First name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
if (re.search(r'^[\w+\s.@+-]+$', user_request['last_name']) == None):
errors.append('Last name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
+ if (re.search(r'^[\w,]+$' , username) == None):
+ errors.append('Username may contain only letters,numbers and -/_ characters.')
+ # checking in django_db !!
+ if PendingUser.objects.filter(email__iexact = user_request['email']):
+ errors.append('Email is pending for validation. Please provide a new email address.')
+ # if UserModel._default_manager.filter(email__iexact = user_request['email']):
+ # errors.append('This email is not usable. Please contact the administrator or try with another email.')
+ if User.objects.filter(username__iexact = user_request['username']):
+ errors.append('This username is already in use, try another one')
# Does the user exist in Manifold?
user_query = Query().get('local:user').select('user_id','email')
user_details = execute_admin_query(wsgi_request, user_query)
for user_detail in user_details:
if user_detail['email'] == user_request['email']:
- errors.append('Email already registered in Manifold. Please provide a new email address.')
+ errors.append('Email already registered. <a href="/">Login</a> with your existing account. <a href="/portal/pass_reset/">Forgot your password?</a>')
+
# Does the user exist in sfa? [query is very slow!!]
#user_query = Query().get('user').select('user_hrn','user_email')
# XXX Test based on the user_hrn is quick
user_query = Query().get('user').select('user_hrn','user_email').filter_by('user_hrn','==',user_request['user_hrn'])
user_details_sfa = execute_admin_query(wsgi_request, user_query)
- for user in user_details_sfa:
- if user['user_email'] == user_request['email']:
- errors.append('Email already registered in OneLab registry. <a href="/contact">Contact OneLab support</a> or use another email.')
- if user['user_hrn'] == user_request['user_hrn']:
- # add random number if user_hrn already exists in the registry
- user_request['user_hrn'] = user_request['authority_hrn'] \
- + '.' + split_email + str(randint(1,1000000))
-
+ # for user in user_details_sfa:
+ # if user['user_email'] == user_request['email']:
+ # errors.append('Email already registered in SFA registry. Please use another email.')
+ # if user['user_hrn'] == user_request['user_hrn']:
+ # # add random number if user_hrn already exists in the registry
+ # user_request['user_hrn'] = user_request['authority_hrn'] \
+ # + '.' + split_email + str(randint(1,1000000))
+
+ # checking in django unfold db portal application pending users
+ # sqlite3 /var/unfold/unfold.sqlite3
+ # select email from portal_pendinguser;
+ if PendingUser.objects.filter(email__iexact = user_request['email']):
+ errors.append('Account pending for validation. Please wait till your account is validated or contact OneLab support.')
+
+ # checking in django_db !!
+ # sqlite3 /var/unfold/unfold.sqlite3
+ # select email from auth_user;
+ if UserModel._default_manager.filter(email__iexact = user_request['email']):
- errors.append('<a href="/contact">Contact OneLab support</a> or try with another email.')
++ errors.append('Please try with another email.')
+
# XXX TODO: Factorize with portal/accountview.py
# XXX TODO: Factorize with portal/registrationview.py
# XXX TODO: Factorize with portal/joinview.py
if not errors:
create_pending_user(wsgi_request, user_request, user_detail)
self.template_name = 'user_register_complete.html'
-
+ # log user activity
- activity.user.registered(self.request)
- return render(wsgi_request, self.template, {'theme': self.theme})
++ #activity.user.registered(self.request)
++
+ return render(wsgi_request, self.template, {'theme': self.theme, 'REQINST':wsgi_request.POST.get('org_name', '').split(".")[1].upper()})
else:
+ print "############ BREAKPOINT A #################"
user_request = {}
## this is coming from onelab website onelab.eu
reg_form = {
'last_name': wsgi_request.GET.get('last_name', ''),
'email': wsgi_request.GET.get('email', ''),
}
+ # log user activity
+ activity.user.signup(self.request)
+ print "############ BREAKPOINT B #################"
template_env = {
'topmenu_items': topmenu_items_live('Register', page),
'errors': errors,
'authorities': authorities,
- 'theme': self.theme
+ 'theme': self.theme,
+ 'section':'Registration'
}
template_env.update(user_request)
template_env.update(reg_form)
template_env.update(page.prelude_env ())
+ print "############ BREAKPOINT C #################"
return render(wsgi_request, self.template,template_env)
import json, time, re
+ import activity.user
+
class SliceRequestView (LoginRequiredAutoLogoutView, ThemeView):
template_name = 'slicerequest_view.html'
errors = []
slice_name =''
purpose=''
- exp_url=''
+ url=''
authority_hrn = None
authority_name = None
# Retrieve the list of authorities
'authority_hrn' : authority_hrn,
'organization' : wsgi_request.POST.get('org_name', ''),
'slice_name' : wsgi_request.POST.get('slice_name', ''),
- 'exp_url' : wsgi_request.POST.get('exp_url', ''),
+ 'url' : wsgi_request.POST.get('url', ''),
'purpose' : wsgi_request.POST.get('purpose', ''),
'current_site' : current_site
}
if (purpose is None or purpose == ''):
errors.append('Experiment purpose is mandatory')
- exp_url = slice_request['exp_url']
+ url = slice_request['url']
if not errors:
if is_pi(wsgi_request, user_hrn, authority_hrn):
create_pending_slice(wsgi_request, slice_request, user_email)
self.template_name = 'slice-request-ack-view.html'
+ # log user activity
+ activity.user.slice(wsgi_request)
+
return render(wsgi_request, self.template, {'theme': self.theme}) # Redirect after POST
else:
slice_request = {}
'purpose': purpose,
'email': user_email,
'user_hrn': user_hrn,
- 'exp_url': exp_url,
+ 'url': url,
'pi': pi,
'authority_name': authority_name,
- 'authority_hrn': user_authority,
+ 'authority_hrn': user_authority,
'cc_myself': True,
'authorities': authorities,
'theme': self.theme,
from django.template import RequestContext
from django.shortcuts import render_to_response
- from manifold.core.query import Query, AnalyzedQuery
- from manifoldapi.manifoldapi import execute_query
+ from manifold.core.query import Query, AnalyzedQuery
+ from manifoldapi.manifoldapi import execute_query
import json
from django.views.generic.base import TemplateView
from plugins.scheduler2 import Scheduler2
# Bristol plugin
- from plugins.univbrisfoam import UnivbrisFoam
- from plugins.univbrisfv import UnivbrisFv
- from plugins.univbrisfvf import UnivbrisFvf
+ from plugins.univbris import Univbris
+ from plugins.univbrisfoam import UnivbrisFoam
+ from plugins.univbrisfv import UnivbrisFv
+ from plugins.univbrisfvf import UnivbrisFvf
+ from plugins.univbrisfvfo import UnivbrisFvfo
+ from plugins.univbristopo import UnivbrisTopo
-
from plugins.columns_editor import ColumnsEditor
from plugins.sladialog import SlaDialog
from plugins.lists.simplelist import SimpleList
metadata = page.get_metadata()
page.expose_js_metadata()
+ # Bristol
+ univbrisfoam_query=Query().get('ofelia-bristol-of:resource').select('urn')
+ page.enqueue_query(univbrisfoam_query)
+
+
resource_md = metadata.details_by_object('resource')
resource_fields = [column['name'] for column in resource_md['column']]
# Example: select slice_hrn, resource.urn, lease.resource, lease.start_time, lease.end_time from slice where slice_hrn == "ple.upmc.myslicedemo"
main_query = Query.get('slice').filter_by('slice_hrn', '=', slicename)
main_query.select(
- 'slice_urn', # XXX We need the key otherwise the storage of records bugs !
+ # SLICE
'slice_hrn',
+ # - The record key is needed otherwise the storage of records
+ # bugs !
+ 'slice_urn',
+ # RESOURCES
'resource.urn',
'resource.hostname', 'resource.type',
- 'resource.network_hrn',
+ # - The facility_name and testbed_name are required for the
+ # testbeds plugin to properly work.
+ 'resource.facility_name',
+ 'resource.testbed_name',
+ # LEASES
'lease.resource',
'lease.start_time',
'lease.end_time',
- 'lease.lease_id', # Important for NITOS identify already existing leases
+ # - The lease_id is important for NITOS identify already existing
+ # leases
+ 'lease.lease_id',
+
#'user.user_hrn',
#'application.measurement_point.counter'
)
sq_lease = aq.subquery('lease')
query_resource_all = Query.get('resource').select(resource_fields)
- #page.enqueue_query(query_resource_all)
+ page.enqueue_query(query_resource_all)
# leases query
#lease_md = metadata.details_by_object('lease')
# the key to use at init-time
init_key = main_query_init_key,
checkboxes = True,
- # center on Paris
- latitude = 49.,
- longitude = 9,
- zoom = 8,
+
+ # To center around Europe : 53,9 / 3
+ latitude = 53.,
+ longitude = 9.,
+ zoom = 3,
)
# --------------------------------------------------------------------------
network_md = metadata.details_by_object('network')
network_fields = [column['name'] for column in network_md['column']]
- query_networks = Query.get('network').select(network_fields)
- page.enqueue_query(query_networks)
+ #query_networks = Query.get('network').select(network_fields)
+ #page.enqueue_query(query_networks)
filter_testbeds = TestbedsPlugin(
page = page,
domid = 'testbeds-filter',
title = 'Filter by testbeds',
query = sq_resource,
- query_networks = query_networks,
- init_key = "network_hrn",
- checkboxes = True,
- datatables_options = {
- 'iDisplayLength': 25,
- 'bLengthChange' : True,
- 'bAutoWidth' : True,
- },
+ #query_networks = query_networks,
+ #init_key = "network_hrn",
+ #checkboxes = True,
+ #datatables_options = {
+ # 'iDisplayLength': 25,
+ # 'bLengthChange' : True,
+ # 'bAutoWidth' : True,
+ # },
)
filter_status = FilterStatusPlugin(
query = main_query,
username = request.user,
)
+
+ # Bristol plugin
+ univbrisfoamlist = UnivbrisFoam(
+ page = page,
+ title = 'univbris_foam_ports_selection',
+ domid = 'univbris_foam_ports_selection',
+ query = univbrisfoam_query,
+ query_all = univbrisfoam_query,
+ checkboxes = False,
+ datatables_options = {
+ 'iDisplayLength': 10,
+ 'bLengthChange' : True,
+ 'bAutoWidth' : True,
+ },
+ )
+
+ #plugin which manages the different flowspaces that the user creates, and also sends flowspaces to manifold
+ univbrisfvlist = UnivbrisFv(
+ page = page,
+ title = 'univbris_flowspace_selection',
+ domid = 'univbris_flowspace_selection',
+ query = None,
+ query_all = None,
+ datatables_options = {
+ 'iDisplayLength': 5,
+ 'bLengthChange' : True,
+ 'bAutoWidth' : True,
+ },
+ )
+
+ #plugin which allows the definition of a single flowspace
+ univbrisfvform = UnivbrisFvf(
+ page = page,
+ title = 'univbris_flowspace_form',
+ domid = 'univbris_flowspace_form',
+ query = None,
+ query_all = None,
+ datatables_options = {
+ 'iDisplayLength': 3,
+ 'bLengthChange' : True,
+ 'bAutoWidth' : True,
+ },
+ )
+
+ # --------------------------------------------------------------------------
+ # Ofelia OpenFlow Plugin
+ # Bristol plugin
+
+ # plugin which display a "gathering resources" message
+ # waiting for all resources to be returned by manifold
+ univbriswelcome = Univbris(
+ page = page,
+ title = 'univbris_welcome',
+ domid = 'univbris_welcome',
+ query = query_resource_all,
+ )
+ univbrisfoamlist = UnivbrisFoam(
+ page = page,
+ title = 'univbris_foam_ports_selection',
+ domid = 'univbris_foam_ports_selection',
+ query = query_resource_all,
+ query_all = query_resource_all,
+ checkboxes = False,
+ datatables_options = {
+ 'iDisplayLength': 10,
+ 'bLengthChange' : True,
+ 'bAutoWidth' : True,
+ },
+ )
+
+ #plugin which manages the different flowspaces that the user creates, and also sends flowspaces to manifold
+ univbrisfvlist = UnivbrisFv(
+ page = page,
+ title = 'univbris_flowspace_selection',
+ domid = 'univbris_flowspace_selection',
+ query = None,
+ query_all = None,
+ sync_query = query_resource_all,
+ datatables_options = {
+ 'iDisplayLength': 5,
+ 'bLengthChange' : True,
+ 'bAutoWidth' : True,
+ },
+ )
+
+ #plugin which allows the definition of a single flowspace
+ univbrisfvform = UnivbrisFvf(
+ page = page,
+ title = 'univbris_flowspace_form',
+ domid = 'univbris_flowspace_form',
+ query = query_resource_all,
+ query_all = None,
+ datatables_options = {
+ 'iDisplayLength': 3,
+ 'bLengthChange' : True,
+ 'bAutoWidth' : True,
+ },
+ )
+
+ #plugin which allows the definition the match criteria on a single OPTICAL flowspace
+
+ univbrisofvform = UnivbrisFvfo(
+ page = page,
+ title = 'univbris_oflowspace_form',
+ domid = 'univbris_oflowspace_form',
+ query = None,
+ query_all = None,
+ datatables_options = {
+ 'iDisplayLength': 3,
+ 'bLengthChange' : True,
+ 'bAutoWidth' : True,
+ },
+ )
+
+ #plugin which display the gathered topology
+ univbristopology = UnivbrisTopo(
+ page = page,
+ title = 'univbris_topology',
+ domid = 'univbris_topology',
+ query = query_resource_all,
+ #query = query_resource_all,
+ )
+
# --------------------------------------------------------------------------
# SLA View and accept dialog
template_env['scheduler'] = resources_as_scheduler2.render(self.request)
# Bristol plugin
+ template_env['welcome'] = univbriswelcome.render(self.request)
template_env['resources'] = univbrisfoamlist.render(self.request)
- template_env['flowspaces']= univbrisfvlist.render(self.request)
- template_env['flowspaces_form']= univbrisfvform.render(self.request)
+ template_env['flowspaces'] = univbrisfvlist.render(self.request)
+ template_env['oflowspaces_form'] = univbrisofvform.render(self.request)
+ template_env['flowspaces_form'] = univbrisfvform.render(self.request)
+ template_env['topology'] = univbristopology.render(self.request)
-
+
# template_env['pending_resources'] = pending_resources.render(self.request)
template_env['sla_dialog'] = '' # sla_dialog.render(self.request)
template_env["theme"] = self.theme
<html lang="en"><head>
<title>{{theme}} portal - {{ section }}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
-<link rel="shortcut icon" href="/static/img/favicon.ico">
+<link rel="shortcut icon" href="/static/img/fibre-logo2.ico"height ='16' width='16'>
{# This is where insert_str will end up #}{% media_container prelude %}
{% include 'messages-transient-header.html' %}
<script type="text/javascript"> {# raw js code - use {% insert prelude_js %} ... {% endinsert %} #} {% container prelude_js %}</script>
<body ng-app="ManifoldApp">
{% block container %}
{% block topmenu %}
- {% widget "_widget-topmenu.html" %}
+ {% widget "__widget-topmenu.html" %}
{% endblock topmenu %}
- {% include 'messages-transient.html' %}
{% block base_content %}
{% endblock %}
{% endblock container %}
+ {% widget "_footer.html" %}
<div class="loading">
<div><img src="{{ STATIC_URL }}/img/loading.gif" /> Loading...</div>
<div> </div>
<h1><img src="{{ STATIC_URL }}img/icon_user_small.png" alt="User Registration" />User sign-up</h1>
</div>
<div class="row">
- {%if activation_status == 'success'%}
- <h3>Signup request confirmed.</h3>
+ {% if activation_status == 'success' %}
+ <h3>Signup request confirmed.</h3>
- <p>You are currently able to log in to the portal using your email address and the password that you provided, but your access is still limited.</p>
<p>You will have full access as soon as your account is validated by a manager at your organization. We have sent an email to the managers with a validation request.</p>
+ {% elif activation_status == 'validated' %}
+ <h3>Account validated.</h3>
+ <p>We have identified you as a valid PLE user. Your OneLab account has automatically been approved.</p>
+ <p>You have a full access to OneLab testbeds.</p>
{%else%}
<h3>Signup confirmation failed.</h3>
<p>You have probably arrived at this page by clicking a confirmation link in an email that we have sent to you. However,
<script type="text/javascript">
$(document).ready(function() {
$("li#nav-request").addClass("active");
+ $('table.requests').dataTable({
+ "sDom": "frtiS",
+ "bScrollCollapse": true,
+ "bStateSave": true,
+ "bPaginate": false,
+ "bLengthChange": false,
+ "bFilter": false,
+ "bSort": true,
+ "bInfo": false,
+ "bAutoWidth": true,
+ "bAutoHeight": false,
+ });
});
function on_click_event() {
var ids = [];
}
);
}
- };
- function showMore(buttonId, divId){
- }
- function on_click_reject() {
++ };
++ function showMore(buttonId, divId){
+ var element = document.getElementById(buttonId);
+ var div_element = document.getElementById(divId);
+ if (element.value === '(+)'){
+ element.value = '(-)';
+ $('#'+divId).slideDown('fast');
+ }
+ else {
+ element.value = '(+)';
+ $('#'+divId).slideUp('fast');
+ }
+ return false;
- }
++ }
++ function on_click_reject() {
+ 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/reject_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">Rejected</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="container-fluid">
<div class="col-md-12">
- <h2>Authorities</h2>
+ <h2>From your authorities</h2>
</div>
{% if my_authorities %}
-
+ <div class="col-md-12">
+ <table class="table requests">
+ <thead>
+ <tr>
+ <th>ID</th>
+ <th></th>
+ <th>Type</th>
+ <th>Authority</th>
+ <th>Info</th>
+ <th>Date</th>
+ <th>Status</th>
+ </tr>
+ </thead>
+ <tbody>
{% for authority, requests in my_authorities.items %}
- Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
+ {% if authority == pi_authority or authority == "fibre" %}
++
++<!--
+ <div class="col-md-12">
+ <h2>{{authority}}</h2>
+ <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>
+ {% if request.object_auth == pi_authority %}
+ <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' %}
- Slice name: {{request.slice_name}} -- User_hrn: {{ request.user_hrn }} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
++ Login: {{request.login}} - First name: {{request.first_name}} - Last name: {{request.last_name}} - Email: {{request.email}}
+ <input type = "button" id = "moreBtn_{{request.id}}" value = "(+)" onclick = "showMore('moreBtn_{{request.id}}','reasons_{{request.id}}')" style="color:blue; padding:0; border:none; background:none">
+ <div id="reasons_{{request.id}}" style="display:none"> Reasons for Applying:<br> {{request.reasons}} </div>
+ {% else %}
+ {% if request.type == 'slice' %}
- Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
++ Slice name: {{request.slice_name}} - User_hrn: {{ request.user_hrn }} - Number of nodes: {{request.number_of_nodes}} - Type of nodes: {{request.type_of_nodes}} - Purpose: {{request.purpose}}
+ {% else %} {# authority #}
- <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
++ 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>
+
- {% endfor %}
++ <!- <div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'>
+ {% endif %}
+ </tr>
+ {% endfor %}
+ </table>
+ </div>
+ {% endif %}
++-->
+
+ {% for request in requests %}
+
+ {% if request.type == 'user' %}
+ <tr>
+ {% elif request.type == 'slice' %}
+ <tr class="info">
+ {% else %}
+ <tr class="active">
+ {% endif %}
+ <td><span class="gray small">{{ request.id }}</span></td>
+ <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{% endif %}
+ {% endif %}
+ </td>
+ <td><span class="type">{{ request.type }}</span></td>
+ <td><i>{{authority}}{{request.site_authority}}</i></td>
+ <td>
+ {% if request.type == 'user' %}
+ <b>{{request.first_name}} {{request.last_name}}</b> <<a href="mailto:{{request.email}}">{{request.email}}</a>>
++ <input type = "button" id = "moreBtn_{{request.id}}" value = "(+)" onclick = "showMore('moreBtn_{{request.id}}','reasons_{{request.id}}')" style="color:blue; padding:0; border:none; background:none">
++ <div id="reasons_{{request.id}}" style="display:none"> Reasons for Applying:<br> {{request.reasons}} </div>
+
+ {% elif 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 %}
+ <b>{{request.site_name}}</b> ({{request.site_authority}}) -- {{request.address_city}}, {{request.address_country}}
+ {% 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 %}
+
+ {% endfor %}
+ </tbody>
+ </table>
+ </div>
{% else %}
<div class="col-md-12">
<i>There is no pending request waiting for validation.</i>
</div>
{% endif %}
+ </div>
+
+
<br />
<div class="col-md-12">
- <h2>Sub-Authorities</h2>
+ <h2>From your 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
+ {% if authority == pi_authority or authority == 'fibre'%}
+ <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>
+ {% if request.object_auth == pi_authority %}
+ <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 %}
- {% 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>
-
+ </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>
+ {% endif %}
+ </tr>
+ {% endfor %}
+ </table>
+ </div>
+ {% endif %}
{% endfor %}
{% else %}
<div class="col-md-12">
{% endif %}
<br />
<div class="col-md-12">
- <h2>Authorities with delegation</h2>
+ <h2>From your authorities with delegation</h2>
</div>
{% if delegation_authorities %}
{% for authority, requests in delegation_authorities.items %}
+ {% if authority == pi_authority or authority == 'fibre'%}
<div class="col-md-12">
<h3>{{authority}}</h3>
<table class="table">
</th>
{% for request in requests %}
<tr>
+ {% if request.object_auth == pi_authority %}
<td>
{% if request.allowed == 'allowed' %}
<input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
{% 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 %}'> -->
+
+ <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+ {% endif %}
</tr>
{% endfor %}
</table>
- </div>
- {% endfor %}
+ </div>
+ {% endif %}
+ {% endfor %}
{% else %}
<div class="col-md-12">
<i>There is no pending request waiting for validation.</i>
<br />
<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>
+ <button class="btn btn-danger" type="button" id="portal__reject" onclick="on_click_reject();"><span class="glyphicon glyphicon-remove"></span> Reject</button>
</div>
<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>
+ </div>
</div>
{% if errors %}
- <ul>
- {% for error in errors %}
- <li>{{ error }}</li>
- {% endfor %}
- </ul>
+ <div class="row">
+ <div class="col-md-12">
+ <ul>
+ {% for error in errors %}
+ <li>{{ error }}</li>
+ {% endfor %}
+ </ul>
+ </div>
+ </div>
{% endif %}
<div class="row">
<div class="col-md-12">
</div>
</div>
- <!-- LOGIN
- TODO: Login should be suggested from user email or first/last name, and
- checked for existence. In addition, the full HRN should be shown to the
- user.
- <div class="form-group">
- <label for="login" class="col-xs-2 control-label">Login</label>
- <div class="col-xs-4">
- <input type="text" name="login" size="25" class="form-control" minlength="2" value="{{ login }}" placeholder="Login" required />
- </div>
- <div class="col-xs-6"><p class="form-hint">Enter your login</p></div>
- </div>
- -->
<div class="col-md-6">
<div class="form-group">
<label for="password" class="control-label">Authentication</label>
<p></p>
<input type="password" id="password" name="password" class="form-control" style="width:250px" minlength="4" value="{{ password }}"
title="Your password allows you to log in to this portal."
- placeholder="Password" required/>
+ placeholder="Password" required />
</div>
<div class="form-group">
<input type="password" id="confirmpassword" name="confirmpassword" style="width:250px" minlength="4" class="form-control" value=""
- placeholder="Confirm password" required/>
+ placeholder="Confirm password" required />
</div>
<div class="form-group">
<!--<label for="question" class="control-label">Keys</label> -->
, 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>
- <div id="_com_1">
- </div>
- </div>
- </div>
+ <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">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
- </div>
+ </div>
<script>
{% for authority in authorities %}
{% if authority.name %}
{value:"{{ authority.name }}",label:"{{authority.name}}"},
+ // show hrn if we don't have the name
{% else %}
{value:"{{ authority.authority_hrn }}",label:"{{authority.authority_hrn}}"},
{% endif %}
{value:"",label:"No authority found !!!"}
{% endif %}
];
+
+ console.log(availableTags);
+
// sorting the list
availableTags.sort(function(a,b){
var nameA=a.value.toLowerCase(), nameB=b.value.toLowerCase();
{{filter_testbeds}}
</div>
<div class="col-md-10" style="height:100%;">
- <!-- <div class="row slice-pending">
- <ul class="nav nav-pills">
- <li><a href="">Unreserved</a></li>
- <li><a href="">Reserved</a></li>
- <li><a href="">Pending<span class="badge" id="badge-pending" style="display:none;"></span></a></li>
- <li>
- <button type="button" class="btn btn-primary apply" id="ApplyPendind">Apply</button>
- <button type="button" class="btn btn-default clear">Clear</button>
- </li>
- <li>
- <div id="loading" style="display:none;"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading" /></div>
- </li>
- </ul>
- </div> -->
<div class="row">
{% if msg %}
<div class="col-md-12"><p class="alert-success">{{ msg }}</p></div>
<div class="col-md-6">
{{ filter_status }}
</div>
- <div class="col-md-2">
+ <div class="col-md-1">
{{ apply }}
</div>
</div>
<ul class="nav nav-tabs">
<li class="active"><a href="#resourcelist" role="tab" data-toggle="tab">Table</a></li>
<li> <a href="#resourcemap" role="tab" data-toggle="tab">Map</a></li>
- <li> <a href="#resourceflowspace" role="tab" data-toggle="tab">Flowspace</a></li>
+ <li> <a href="#resourceflowspace" role="tab" data-toggle="tab">Flowspace</a></li>
<li> <a href="#resourcescheduler" role="tab" data-toggle="tab">Scheduler</a></li>
</ul>
</div>
<div class="tab-content" style="height:100%;">
<div class="tab-pane active" id="resourcelist">
<!-- Button trigger modal - columns selector -->
- <button class="btn btn-primary btn-sm" style="float:right;" data-toggle="modal" data-target="#myModal">...</button>
+ <button class="btn btn-default btn-sm" style="float:right;" data-toggle="modal" data-target="#myModal">...</button>
{{list_resources}}
<!-- <table cellpadding="0" cellspacing="0" border="0" class="table" id="objectList"></table> -->
</div>
<div class="tab-pane" id="resourcemap">
{{map_resources}}
</div>
+ <div class="tab-pane" id="resourceflowspace">
+
+ <p>{{welcome}}</p>
+ <p>{{flowspaces}}</p>
+ <p>{{flowspaces_form}}</p>
+ <p>{{oflowspaces_form}}</p>
+ <p>{{topology}}</p>
+ <p>{{resources}}</p>
+
+ <p>{{below_table}}</p>
+
+ </div>
<div class="tab-pane" id="resourcescheduler">
- {{scheduler}}
+ {{scheduler}}
+ </div>
+ <div class="tab-pane" id="resourceflowspace">
+ {{resources}}
+ {{flowspaces}}
+ {{flowspaces_form}}
</div>
<!--