Merge branch 'onelab' of ssh://git.onelab.eu/git/myslice into fibre
authorPedro, Carlos and Rezende <pedroeusebio, carlos, rezende@land.ufrj.br>
Fri, 3 Oct 2014 19:51:36 +0000 (16:51 -0300)
committerPedro, Carlos and Rezende <pedroeusebio, carlos, rezende@land.ufrj.br>
Fri, 3 Oct 2014 19:51:36 +0000 (16:51 -0300)
Conflicts:
manifoldapi/manifoldproxy.py
manifoldapi/static/js/manifold.js
myslice/urls.py
portal/actions.py
portal/emailactivationview.py
portal/homeview.py
portal/managementtabrequests.py
portal/registrationview.py
portal/sliceresourceview.py
portal/templates/email_activation.html
portal/templates/management-tab-requests.html
portal/templates/registration_view.html
portal/templates/slice-resource-view.html

16 files changed:
1  2 
manifoldapi/static/js/manifold.js
myslice/urls.py
plugins/scheduler2/templates/scheduler.html
portal/actions.py
portal/contactview.py
portal/emailactivationview.py
portal/homeview.py
portal/managementtabrequests.py
portal/registrationview.py
portal/slicerequestview.py
portal/sliceresourceview.py
portal/templates/base.html
portal/templates/email_activation.html
portal/templates/management-tab-requests.html
portal/templates/registration_view.html
portal/templates/slice-resource-view.html

@@@ -33,13 -33,13 +33,13 @@@ Array.prototype.equals = function (arra
          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;
  }
  
@@@ -344,15 -344,22 +344,23 @@@ function QueryStore() 
          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");
  
      }
  
@@@ -1202,7 -1214,15 +1215,15 @@@ var manifold = 
      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);
  
diff --combined myslice/urls.py
@@@ -17,9 -17,14 +17,16 @@@ import portal.dashboardvie
  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()
@@@ -85,7 -90,7 +92,7 @@@ urls = 
      (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')),
  
@@@ -122,10 -134,3 +136,10 @@@ for aux in auxiliaries
          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'),
 +)
 +
@@@ -8,22 -8,28 +8,28 @@@
  </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
diff --combined portal/actions.py
@@@ -4,17 -4,18 +4,21 @@@ from manifoldapi.manifoldapi    import 
  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
@@@ -45,7 -46,7 +49,7 @@@ def authority_get_pi_emails(request, au
          #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')
@@@ -57,7 -58,7 +61,7 @@@ def clear_user_creds(request, user_emai
      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']
@@@ -74,7 -75,8 +78,8 @@@
                  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'))
@@@ -156,21 -158,15 +161,21 @@@ def manifold_add_user(wsgi_request, req
          ?
      
      """
 +
 +    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:
@@@ -209,6 -205,11 +214,11 @@@ def manifold_delete_account(request, pl
      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):
@@@ -233,8 -234,6 +243,8 @@@ def make_request_user(user)
      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):
@@@ -393,13 -392,177 +403,177 @@@ def portal_validate_request(wsgi_reques
  
      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/
  
@@@ -427,13 -590,23 +601,23 @@@ def create_slice(wsgi_request, request)
      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
  
@@@ -461,8 -649,9 +660,9 @@@ def create_pending_slice(wsgi_request, 
          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()
@@@ -503,7 -688,7 +703,7 @@@ def manifold_add_reference_user_account
      # 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
diff --combined portal/contactview.py
@@@ -11,6 -11,9 +11,9 @@@ from manifoldapi.manifoldap
  import json
  
  from myslice.theme import ThemeView
+ import activity.user
  theme = ThemeView()
  
  # splitting the 2 functions done here
@@@ -28,17 -31,18 +31,18 @@@ class ContactView (FreeAccessView, Them
              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)
          
@@@ -56,7 -60,7 +60,7 @@@
              #    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:
@@@ -66,6 -70,8 +70,8 @@@
                  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
                  })
@@@ -2,7 -2,7 +2,7 @@@ from unfold.loginrequire
  #
  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
@@@ -11,20 -11,35 +11,35 @@@ from django.htt
  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'
          
diff --combined portal/homeview.py
@@@ -1,29 -1,17 +1,30 @@@
  # 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
@@@ -31,9 -19,8 +32,11 @@@ from myslice.configengine import Config
  
  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
@@@ -18,7 -18,6 +18,7 @@@ from portal.actions                 imp
  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())
  
@@@ -5,6 -5,7 +5,7 @@@ from hashlib    import md
  
  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
@@@ -17,12 -18,12 +18,14 @@@ from manifoldapi.manifoldapi    import 
  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
  #
@@@ -40,17 -41,18 +43,18 @@@ class RegistrationView (FreeAccessView
          """
          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']     
@@@ -69,7 -70,9 +72,9 @@@
              # 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)
@@@ -16,6 -16,8 +16,8 @@@ from myslice.theme import ThemeVie
  
  import json, time, re
  
+ import activity.user
  class SliceRequestView (LoginRequiredAutoLogoutView, ThemeView):
      template_name = 'slicerequest_view.html'
      
@@@ -33,7 -35,7 +35,7 @@@
          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,
@@@ -1,8 -1,8 +1,8 @@@
  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
@@@ -24,10 -24,14 +24,13 @@@ from plugins.testbed
  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
@@@ -48,11 -52,6 +51,11 @@@ class SliceResourceView (LoginRequiredV
          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'
          )
@@@ -84,7 -94,7 +98,7 @@@
          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
@@@ -3,7 -3,7 +3,7 @@@
  <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>
@@@ -86,12 -86,12 +86,12 @@@ $(document).ready(function() 
  <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>&nbsp;</div>
@@@ -6,9 -6,14 +6,13 @@@
        <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, 
@@@ -1,6 -1,18 +1,18 @@@
  <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> &lt;<a href="mailto:{{request.email}}">{{request.email}}</a>&gt;
++                      <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>
@@@ -4,20 -4,24 +4,24 @@@
  
  <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>
@@@ -494,6 -481,7 +481,7 @@@ jQuery(document).ready(function()
          {% 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();
@@@ -26,20 -26,6 +26,6 @@@ $(document).ready(function() 
                {{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>
@@@ -50,7 -36,7 +36,7 @@@
                        <div class="col-md-6">
                                {{ filter_status }}
                        </div>
-                       <div class="col-md-2">
+                       <div class="col-md-1">
                                {{ apply }}
                        </div>
                </div>
@@@ -68,7 -54,7 +54,7 @@@
                        <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>
        
                                <!--