Merge branch 'onelab' of ssh://git.onelab.eu/git/myslice into onelab
authorLoic Baron <loic.baron@lip6.fr>
Tue, 15 Jul 2014 17:17:51 +0000 (19:17 +0200)
committerLoic Baron <loic.baron@lip6.fr>
Tue, 15 Jul 2014 17:17:51 +0000 (19:17 +0200)
23 files changed:
activity/__init__.py [new file with mode: 0644]
myslice/urls.py
plugins/scheduler2/static/css/scheduler2.css
plugins/scheduler2/static/img/forbidden.png [new file with mode: 0644]
plugins/scheduler2/static/js/scheduler2.js
portal/actions.py
portal/managementtababout.py [new file with mode: 0644]
portal/managementtabrequests.py
portal/registrationview.py
portal/slicerequestview.py
portal/sliceresourceview.py
portal/templates/institution-tab-info.html [deleted file]
portal/templates/management-tab-requests.html
portal/templates/onelab/onelab_institution.html
portal/templates/onelab/onelab_management-tab-about.html [new file with mode: 0644]
portal/templates/onelab/onelab_management-tab-requests.html
portal/templates/onelab/onelab_slicerequest_view.html
portal/templates/onelab/onelab_user_request_email.html [new file with mode: 0644]
portal/templates/onelab/onelab_user_request_email.txt [new file with mode: 0644]
portal/templates/password_reset_confirm.html
portal/templates/slice_request_email.html
portal/templates/slice_request_email.txt
portal/templatetags/portal_filters.py

diff --git a/activity/__init__.py b/activity/__init__.py
new file mode 100644 (file)
index 0000000..d570662
--- /dev/null
@@ -0,0 +1,61 @@
+#
+# Activity monitor
+#
+
+import urllib, urllib2
+import threading
+from datetime import datetime
+
+
+def logWrite(request, action, message):
+    url = "http://localhost:5000/log"
+    log = {
+        "date" : datetime.today(),
+        "client_ip" : getClientIp(request),
+        "host" : request.get_host(),
+        "referrer" : request.META.get('HTTP_REFERER'),
+        "user" : request.user
+    }
+    
+    try :
+        result = urllib2.urlopen(url, urllib.urlencode(log))
+        content = result.read()
+    except urllib2.URLError as e:
+        print "Error: connection to " + url + " impossible, logging disabled"
+
+def spawnThread(request, action, message):
+    print "aaaaaaaaa"
+    # Create a new thread in Daemon mode to send the log entry
+    t = threading.Thread(target=logWrite, args=(request, action, message))
+    t.setDaemon(True)
+    t.start()
+
+def userLogin(request):
+    spawnThread(request, 'userlogin', 'User logged in')
+
+def userLogout(request):
+    spawnThread(request, 'userlogout', 'User logged out')
+
+def userRegistration(request):
+    spawnThread(request, 'userregistration', 'User registered')
+
+def userSliceRequest(request):
+    spawnThread(request, 'userslicerequest', 'User requested a slice')
+
+def userContactSupport(request):
+    spawnThread(request, 'usercontactsupport', 'User contacted suppport')
+
+def userAddResource(request):
+    spawnThread(request, 'useraddresource', 'User added resource to slice')
+
+def userDelResource(request):
+    spawnThread(request, 'userdelresource', 'User removed resource from slice')
+
+
+def getClientIp(request):
+    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
+    if x_forwarded_for:
+        ip = x_forwarded_for.split(',')[0]
+    else:
+        ip = request.META.get('REMOTE_ADDR')
+    return ip
\ No newline at end of file
index 32d343b..dacebde 100644 (file)
@@ -34,6 +34,7 @@ import portal.slicetabtestbeds
 import portal.slicetabusers
 import portal.slicetabmeasurements 
 
+import portal.managementtababout
 import portal.managementtabrequests
 
 #### high level choices
@@ -97,6 +98,7 @@ urls = [
     (r'^experiment/(?P<slicename>[^/]+)/?$', portal.slicetabexperiment.ExperimentView.as_view()),
     #
     (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'^terms/?$', TermsView.as_view(), name='terms'),
index b16eb80..2fcf063 100755 (executable)
     cursor: not-allowed;\r
 }\r
 \r
+#scheduler-reservation-table tbody tr td.disabled {\r
+    background: url("../img/forbidden.png") no-repeat scroll 50% 50%; /* #DD4444;*/\r
+    cursor: not-allowed;\r
+}\r
+\r
 #scheduler-reservation-table tbody tr td.success {\r
        content: "✓";\r
 }\r
diff --git a/plugins/scheduler2/static/img/forbidden.png b/plugins/scheduler2/static/img/forbidden.png
new file mode 100644 (file)
index 0000000..fba5664
Binary files /dev/null and b/plugins/scheduler2/static/img/forbidden.png differ
index fbfcfa0..0b294b4 100755 (executable)
@@ -495,6 +495,7 @@ var SCHEDULER_COLWIDTH = 50;
             do_resize: function()\r
             {\r
                 var scope = this._get_scope();\r
+                var num_hidden_cells, new_max;\r
 \r
                 $('#' + schedulerTblId + ' thead tr th:eq(0)').css("width", SCHEDULER_FIRST_COLWIDTH);\r
                 //self get width might need fix depending on the template \r
@@ -511,12 +512,15 @@ var SCHEDULER_COLWIDTH = 50;
                 scope.lcm_colspan = this._lcm_colspan;\r
 \r
                 // Slider max value\r
-\r
                 if ($('#tblSlider').data('slider') != undefined) {\r
-                    var new_max = (this._all_slots.length - this._num_visible_cells) / this._lcm_colspan;\r
-                    $('#tblSlider').slider('setAttribute', 'max', new_max);\r
+                    num_hidden_cells = this._all_slots.length - this._num_visible_cells;\r
+\r
+                    $('#tblSlider').slider('setAttribute', 'max', num_hidden_cells);\r
+                    $('#tblSlider').slider('setValue', scope.from, true);\r
+                    this._get_scope().$apply();\r
                 }\r
 \r
+\r
             },\r
 \r
             on_show: function(e)\r
@@ -567,18 +571,23 @@ var SCHEDULER_COLWIDTH = 50;
 \r
             _scope_clear_leases: function()\r
             {\r
+                var time, now;\r
                 var self = this;\r
                 var scope = this._get_scope();\r
 \r
+                now = new Date().getTime();\r
+\r
                 // Setup leases with a default free status...\r
                 $.each(this.scope_resources_by_key, function(resource_key, resource) {\r
                     resource.leases = [];\r
                     var colspan_lease = resource.granularity / self._granularity; //eg. 3600 / 1800 => 2 cells\r
+                    time = SchedulerDateSelected.getTime();\r
                     for (i=0; i < self._all_slots.length / colspan_lease; i++) { // divide by granularity\r
                         resource.leases.push({\r
                             id:     'coucou',\r
-                            status: 'free', // 'selected', 'reserved', 'maintenance' XXX pending ??\r
+                            status: (time < now) ? 'disabled':  'free', // 'selected', 'reserved', 'maintenance' XXX pending ??\r
                         });\r
+                        time += resource.granularity * 1000;\r
                     }\r
                 });\r
 \r
@@ -586,15 +595,20 @@ var SCHEDULER_COLWIDTH = 50;
 \r
             _scope_set_leases: function()\r
             {\r
+                    var status;\r
                 var self = this;\r
                 var scope = this._get_scope();\r
             \r
                 manifold.query_store.iter_records(this.options.query_lease_uuid, function(lease_key, lease) {\r
-\r
                     console.log("SET LEASES", lease.resource, new Date(lease.start_time* 1000), new Date(lease.end_time* 1000));\r
                     // XXX We should ensure leases are correctly merged, otherwise our algorithm won't work\r
 \r
                     // Populate leases by resource array: this will help us merging leases later\r
+\r
+                    // let's only put _our_ leases\r
+                    lease_status = manifold.query_store.get_record_state(self.options.query_lease_uuid, lease_key, STATE_SET);\r
+                    if (lease_status != STATE_SET_IN)\r
+                        return true; // ~continue\r
                     if (!(lease.resource in scope._leases_by_resource))\r
                         scope._leases_by_resource[lease.resource] = [];\r
                     scope._leases_by_resource[lease.resource].push(lease);\r
@@ -732,11 +746,11 @@ var SCHEDULER_COLWIDTH = 50;
                             lease_success = '';\r
                             break;\r
                         case STATE_SET_OUT_SUCCESS:\r
-                            lease_class = 'reserved'; // other leases\r
+                            lease_class = 'free'; // other leases\r
                             lease_success = 'success';\r
                             break;\r
                         case STATE_SET_IN_FAILURE:\r
-                            lease_class = 'reserved'; // other leases\r
+                            lease_class = 'free'; // other leases\r
                             lease_success = 'failure';\r
                             break;\r
                         case STATE_SET_IN_PENDING:\r
@@ -777,6 +791,9 @@ var SCHEDULER_COLWIDTH = 50;
             _initUI: function() \r
             {\r
                 var self = this;\r
+                var scope = self._get_scope();\r
+\r
+                var num_hidden_cells;\r
 \r
                 $("#DateToRes").datepicker({\r
                     onRender: function(date) {\r
@@ -786,7 +803,7 @@ var SCHEDULER_COLWIDTH = 50;
                     SchedulerDateSelected = new Date(ev.date);\r
                     SchedulerDateSelected.setHours(0,0,0,0);\r
                     // Set slider to origin\r
-                    $('#tblSlider').slider('setValue', 0); // XXX\r
+                    //$('#tblSlider').slider('setValue', 0); // XXX\r
                     // Refresh leases\r
                     self._scope_clear_leases();\r
                     self._set_all_lease_slots();\r
@@ -795,15 +812,22 @@ var SCHEDULER_COLWIDTH = 50;
                 }).datepicker('setValue', SchedulerDateSelected); //.data('datepicker');\r
 \r
                 //init Slider\r
+                num_hidden_cells = self._all_slots.length - self._num_visible_cells;\r
+                init_cell = (new Date().getHours() - 1) * 3600 / self._granularity;\r
+                if (init_cell > num_hidden_cells)\r
+                    init_cell = num_hidden_cells;\r
+                \r
                 $('#tblSlider').slider({\r
                     min: 0,\r
-                    max: (self._all_slots.length - self._num_visible_cells) / self._lcm_colspan,\r
-                    value: 0,\r
+                    max: num_hidden_cells, // / self._lcm_colspan,\r
+                    value: init_cell,\r
                 }).on('slide', function(ev) {\r
                     var scope = self._get_scope();\r
                     scope.from = ev.value * self._lcm_colspan;\r
                     scope.$apply();\r
                 });\r
+                scope.from = init_cell;\r
+                scope.$apply();\r
 \r
                 $("#plugin-scheduler-loader").hide();\r
                 $("#plugin-scheduler").show();\r
index baf4cca..e218126 100644 (file)
@@ -402,7 +402,7 @@ def create_pending_slice(wsgi_request, request, email):
         slice_name      = request['slice_name'],
         user_hrn        = request['user_hrn'],
         authority_hrn   = request['authority_hrn'],
-        number_of_nodes = request['number_of_nodes'],
+        number_of_nodes = request['exp_url'],
         purpose         = request['purpose'],
     )
     s.save()
diff --git a/portal/managementtababout.py b/portal/managementtababout.py
new file mode 100644 (file)
index 0000000..8a5f97a
--- /dev/null
@@ -0,0 +1,50 @@
+# 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.template import RequestContext
+from django.shortcuts import render_to_response
+from django.shortcuts import render
+
+from unfold.loginrequired import FreeAccessView
+
+from manifold.core.query            import Query
+from manifoldapi.manifoldapi        import execute_query
+from manifoldapi.manifoldresult import ManifoldResult
+from myslice.configengine import ConfigEngine
+
+from myslice.theme import ThemeView
+import json
+
+class ManagementAboutView (FreeAccessView, ThemeView):
+    template_name = 'management-tab-about.html'
+
+    def get (self, request):
+        if request.user.is_authenticated(): 
+            user_query  = Query().get('user').select('user_hrn','parent_authority').filter_by('user_hrn','==','$user_hrn')
+            user_details = execute_query(self.request, user_query)
+            
+            user_local_query  = Query().get('local:user').select('config').filter_by('email','==',str(self.request.user))
+            user_local_details = execute_query(self.request, user_local_query)
+            user_authority = json.loads(user_local_details[0]['config']).get('authority')
+            
+            authority_query = Query().get('authority').select('description', 'authority_hrn', 'legal', 'address', 'abbreviated_name', 
+                                                              'scientific', 'city', 'name', 'url', 'country', 'enabled', 'longitude', 
+                                                              'tech', 'latitude', 'pi_users', 'parent_authority', 'onelab_membership', 
+                                                              'postcode').filter_by('authority_hrn','==',user_authority)
+            authority_details = execute_query(self.request, authority_query)
+            
+            authority_contacts = {}
+            authority_contacts['scientific'] = [ x.strip()[1:-1] for x in authority_details[0]['scientific'][1:-1].split(',') ]
+            authority_contacts['technical'] = [ x.strip()[1:-1] for x in authority_details[0]['tech'][1:-1].split(',') ]
+            
+            authority_contacts['legal'] = [ x.strip().replace('"','') for x in authority_details[0]['legal'][1:-1].split(',') ]
+            print authority_contacts['legal']
+            
+            
+            print "#######",authority_contacts
+            print "$$$$$$$",user_local_details
+            print "@@@@@@@",authority_details
+            
+        return render_to_response(self.template, { 'theme' : self.theme, 'authority' : authority_details[0], 'authority_contacts' : authority_contacts }, context_instance=RequestContext(request))
+
index 50801e9..850bbc6 100644 (file)
@@ -7,13 +7,13 @@ from manifoldapi.manifoldapi         import execute_query
 from django.views.generic.base      import TemplateView
 
 from unfold.loginrequired           import LoginRequiredView
-from django.http import HttpResponse
-from django.shortcuts import render
+from django.http                    import HttpResponse
+from django.shortcuts               import render
 
-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
 
-from portal.actions             import get_requests
+from portal.actions                 import get_requests
 
 from myslice.theme import ThemeView
 
index 6a8322d..7967a91 100644 (file)
@@ -89,9 +89,9 @@ class RegistrationView (FreeAccessView, ThemeView):
             # 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.')
+                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.')
+                errors.append('Last name may contain only letters, numbers, spaces 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.')
index 8cd0af4..449147c 100644 (file)
@@ -14,7 +14,7 @@ from ui.topmenu                 import topmenu_items_live, the_user
 
 from myslice.theme import ThemeView
 
-import json, time
+import json, time, re
 
 class SliceRequestView (LoginRequiredAutoLogoutView, ThemeView):
     template_name = 'slicerequest_view.html'
@@ -31,7 +31,9 @@ class SliceRequestView (LoginRequiredAutoLogoutView, ThemeView):
         """
         """
         errors = []
-
+        slice_name =''
+        purpose=''
+        exp_url=''
         # Retrieve the list of authorities
         authorities_query = Query.get('authority').select('name', 'authority_hrn')
         authorities = execute_admin_query(wsgi_request, authorities_query)
@@ -89,7 +91,8 @@ class SliceRequestView (LoginRequiredAutoLogoutView, ThemeView):
             current_site = Site.objects.get_current()
             current_site = current_site.domain
             
-            # getting the authority_hrn from the selected organization           
+            # getting the authority_hrn from the selected organization
+            authority_hrn = ''           
             for authority in authorities:
                 if authority['name'] == wsgi_request.POST.get('org_name', ''):
                     authority_hrn = authority['authority_hrn']
@@ -105,23 +108,40 @@ class SliceRequestView (LoginRequiredAutoLogoutView, ThemeView):
                 'authority_hrn'     : authority_hrn,
                 'organization'      : wsgi_request.POST.get('org_name', ''),
                 'slice_name'        : wsgi_request.POST.get('slice_name', ''),
-                'number_of_nodes'   : wsgi_request.POST.get('number_of_nodes', ''),
+                'exp_url'           : wsgi_request.POST.get('exp_url', ''),
                 'purpose'           : wsgi_request.POST.get('purpose', ''),
                 'current_site'      : current_site
             }
             
-            authority_hrn = slice_request['authority_hrn']
-            if (authority_hrn is None or authority_hrn == ''):
-                errors.append('Please, select an authority')
+            # create slice_hrn based on authority_hrn and slice_name
+            slice_name = slice_request['slice_name']
+            req_slice_hrn = authority_hrn + '.' + slice_name
+            # comparing requested slice_hrn with the existing slice_hrn 
+            slice_query  = Query().get('slice').select('slice_hrn','parent_authority').filter_by('parent_authority','==',authority_hrn)
+            slice_details_sfa = execute_admin_query(wsgi_request, slice_query)
+            for _slice in slice_details_sfa:
+                if _slice['slice_hrn'] == req_slice_hrn:
+                    errors.append('Slice already exists. Please use a different slice name.')
+            
 
             # What kind of slice name is valid?
-            slice_name = slice_request['slice_name']
             if (slice_name is None or slice_name == ''):
-                errors.append('Slice Name is mandatory')
+                errors.append('Slice name is mandatory')
+            
+            if (re.search(r'^[A-Za-z0-9_]*$', slice_name) == None):
+                errors.append('Slice name may contain only letters, numbers, and underscore.')
+            
+            organization = slice_request['organization']    
+            if (organization is None or organization == ''):
+                errors.append('Organization is mandatory')
+
+
     
             purpose = slice_request['purpose']
             if (purpose is None or purpose == ''):
-                errors.append('Purpose is mandatory')
+                errors.append('Experiment purpose is mandatory')
+
+            exp_url = slice_request['exp_url']
 
             if not errors:
                 if is_pi(wsgi_request, user_hrn, authority_hrn):
@@ -141,8 +161,11 @@ class SliceRequestView (LoginRequiredAutoLogoutView, ThemeView):
             'username': wsgi_request.user.email,
             'topmenu_items': topmenu_items_live('Request a slice', page),
             'errors': errors,
+            'slice_name': slice_name,
+            'purpose': purpose,
             'email': user_email,
             'user_hrn': user_hrn,
+            'exp_url': exp_url,
             'pi': pi,
             'authority_name': authority_name,        
             'cc_myself': True,
index 8289f9e..db72dca 100644 (file)
@@ -60,6 +60,7 @@ class SliceResourceView (LoginRequiredView, ThemeView):
                 'lease.resource',
                 'lease.start_time',
                 'lease.end_time',
+                'lease.lease_id', # Important for NITOS identify already existing leases
                 #'user.user_hrn',
                 #'application.measurement_point.counter'
         )
diff --git a/portal/templates/institution-tab-info.html b/portal/templates/institution-tab-info.html
deleted file mode 100644 (file)
index e69de29..0000000
index 3679796..d534915 100644 (file)
                <i>There is no pending request waiting for validation.</i>
        </div>
 {% endif %}
-
+<br />
 <div class="col-md-12">
        <h2>Sub-Authorities</h2>
 </div>
        <i>There is no pending request waiting for validation.</i>
 </div>
 {% endif %}
-
+<br />
 <div class="col-md-12">
        <h2>Authorities with delegation</h2>
 </div>
        <i>There is no pending request waiting for validation.</i>
 </div>
 {% endif %}
+<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>
 </div>
index 6c35812..c8a668f 100644 (file)
@@ -18,7 +18,7 @@
        <div class="row">
                <div class="col-md-12">
                        <ul class="nav nav-tabs nav-section">
-                               <li class="active"><a href="#info">About</a></li>
+                               <li class="active"><a href="#about">About</a></li>
                                <li><a href="#users">Users</a></li>
                                <li><a href="#slices">Slices</a></li>
                                <li><a href="#requests">Requests</a></li>
        </div>
 </div>
 <div class="container tab-content">
-       <div class="tab-pane active row" id="info">
-               <div class="col-md-12 el">
-                       <div id="authority-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Authority" /></div>
-                   <div id="authority-tab-loaded" style="display:none;">
-                       <div id="authority-data" style="float:left; width:50%;"></div>
-                               <div id="onelab_membership" style="float:right; width:50%;">
-                                   <img src="{{ STATIC_URL }}img/onelab-logo.png" alt="" /><br>
-                               <div id="onelab-data"></div>
-                               </div>
-                   </div>
-          </div>
+       <div class="tab-pane active row" id="about">
        </div>
        
        <div class="tab-pane row" id="users" data-authority="{{user_details.parent_authority}}">
 
        <div class="tab-pane row" id="slices">
                <div class="col-md-12 el">
-               {% if 'is_pi'  in pi %}
-               <button id="createslice" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create slice</button>
-               {% else %}
-               <button id="createslice" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request slice</button>
-               {% endif %}
-               <br /><br />
            <div id="slice-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
            <div id="slice-tab-loaded" style="display:none;">
                <table id="slice-tab" class="table">
            </div>
        {% if 'is_pi'  in pi %}
         <div>
+               {% if 'is_pi'  in pi %}
+                       <button id="createslice" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create slice</button>
+                       {% else %}
+                       <button id="createslice" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request slice</button>
+                       {% endif %}
             <button id="renewslices" type="button" class="btn btn-primary"><span class="glyphicon glyphicon-refresh"></span> Renew Slices</button>
             <button id="deleteslices" type="button" class="btn btn-danger"><span class="glyphicon glyphicon-remove"></span> Delete Slices</button>
         </div>
 $(document).ready(function() {
     {% if person %}
     {% if user_details.parent_authority %}
-        
-        $.post("/rest/authority/",{'filters':{'authority_hrn':'{{user_details.parent_authority}}'}}, function( data ) {
-               
-            var authority_data = [];
-            var onelab_data = [];
-                       /* 'city','enabled','legal','longitude','onelab_membership','address','parent_authority','slice','user','country',
-            'tech','abbreviated_name','url','postcode','description','scientific','authority_hrn','latitude','name'    */
-            $.each( data, function( key, val ) {
-               $('#authority_name').text(val.name);
-                authority_row = "<img src='{{ STATIC_URL }}img/institutions/{{user_details.parent_authority}}.gif' alt='' /><br>";
-                authority_row += "<br>";
-                authority_row += "<b>authority:</b> "+val.authority_hrn+"<br>";
-                               authority_row += "<br>";
-                authority_row += "<b>"+val.name+"</b><br>";
-                authority_row += "<br>";
-                authority_row += "<b>Address:</b> "+val.address+"<br>";
-                authority_row += "<b>City:</b> "+val.postcode+" "+val.city+"<br>";
-                authority_row += "<br>";
-                authority_row += "<b>Country:</b> "+val.country+"<br>";
-                authority_row += "<br>";
-                authority_row += "<br>";
-                authority_row += "<h2>Contacts</h2>";
-                authority_row += "<b>Legal:</b> ";
-                               /*
-
-                TODO: find a way to express JSON correctly given the constrains: CSV / JSON
-
-                legal = jQuery.parseJSON(val.legal);
-                if($.isArray(legal)){
-                    $.each(legal, function(k,v){
-                        authority_row += k+" "+v+"<br>";
-                    });
-                }else{
-                */
-                    authority_row += val.legal+"<br>";
-                //}
-                authority_row += "<br>";
-                authority_row += "<b>Scientific:</b> ";
-                /*
-                scientific = jQuery.parseJSON(val.scientific);
-                if($.isArray(scientific)){
-                    $.each(scientific, function(v){
-                        authority_row += v+", ";
-                    });
-                }else{
-                */
-                    authority_row += val.scientific+"<br>";
-                //}
-                onelab_membership = "<b>Status: </b>"+val.onelab_membership;
-                onelab_data.push(onelab_membership);
-                authority_data.push(authority_row);
-
-            });
-            $("div#authority-data").html(authority_data.join( "" ));
-            $("div#onelab-data").html(onelab_data.join( "" ));
-            $("div#authority-tab-loaded").css("display","block");
-            $("div#authority-tab-loading").css("display","none");
-         });
 
         $.post("/rest/slice/",{'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
             var list_slices = [];
@@ -236,12 +167,14 @@ $(document).ready(function() {
                e.preventDefault();
                $(this).tab('show');
        var id = $(this).attr('href').substr(1);
-       if (id == 'requests') 
+       if ((id == 'requests') || (id == 'about'))
                $("#" + id).load('/management/' + id);
        });
        var hash = window.location.hash;
        if (hash) {
                $('.nav-tabs a[href='+hash+']').click();
+       } else {
+               $('.nav-tabs a[href=#about]').click();
        }
 });
 </script>
diff --git a/portal/templates/onelab/onelab_management-tab-about.html b/portal/templates/onelab/onelab_management-tab-about.html
new file mode 100644 (file)
index 0000000..0c0a94f
--- /dev/null
@@ -0,0 +1,41 @@
+{% load portal_filters %}
+<div class="col-md-6">
+       <div>
+               <img src="{{ STATIC_URL|add:'img/institutions/'|add:authority.authority_hrn|add:'.gif'|file_exists }}" alt="{{authority.name}}">
+       </div>
+       <br />
+       <h3><a href="{{authority.url}}">{{authority.name}}</a></h3>
+       <p>
+               {{authority.address}} <br />
+               {{authority.postcode}} {{authority.city}} <br />
+               {{authority.country}}
+       </p>
+       <br />
+       <h4>Onelab membership</h4> 
+       <p>
+               {{ authority.onelab_membership }}
+       </p>
+</div>
+<div class="col-md-6">
+       <h4>Legal Contact:</h4>
+       <p>
+       {% for c in authority_contacts.legal %}
+                {{ c }} <br />
+       {% endfor %}
+       </p>
+       <br />
+       <h4>Scientific Contact:</h4>
+       <p>
+       {% for c in authority_contacts.scientific %}
+               {{ c }} <br />
+       {% endfor %}
+       </p>
+       <br />
+       <h4>Technical Contact:</h4>
+       <p>
+       {% for c in authority_contacts.technical %}
+               {{ c }} <br />
+       {% endfor %}
+       </p>
+</div>
+<script>$(document).ready(function() {$('#authority_name').text('{{authority.name}}')});</script>
\ No newline at end of file
index 3679796..488e63e 100644 (file)
@@ -14,9 +14,7 @@
                });
                if (ids.length > 0) {
                        var id_str = ids.join('/');
-
                        // XXX spinner
-
                        $.getJSON('/portal/validate_action/' + id_str,
                                function(status) {
                                        $.each(status, function(request_type__id, request_status) {
@@ -98,7 +96,6 @@
 
     {% endfor %}
        </table>
-       </div>
        {% endfor %}
 
 {% else %}
                <i>There is no pending request waiting for validation.</i>
        </div>
 {% endif %}
-
+<div>nnllknjkn<br /><br /></div>
 <div class="col-md-12">
        <h2>Sub-Authorities</h2>
 </div>
        
        {% for authority, requests in sub_authorities.items %}
        <div class="col-md-12">
-       <h3>{{authority}}</h3>
-           <table class="table">
+               <h2>{{authority}}</h2>
+       </div>
+       
+       <table class="table">
              <th>
                <td>Type</td>
                <td>Id</td>
            <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
                  </tr>
            {% endfor %}
-           </table>
-       </div>
+       </table>
        {% endfor %}
 {% else %}
 <div class="col-md-12">
        {% for authority, requests in delegation_authorities.items %}
        <div class="col-md-12">
                <h3>{{authority}}</h3>
-                   <table class="table">
+       </div>
+       <table class="table">
                      <th>
                        <td>Type</td>
                        <td>Id</td>
                    <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
                          </tr>
                    {% endfor %}
-                   </table>
-               </div>
+       </table>
                {% endfor %}
 {% else %}
 <div class="col-md-12">
index 3c38346..47068c4 100644 (file)
@@ -30,7 +30,7 @@
                            <input type="email" class="form-control" id="email" style="width:300px" value="{{ email }}" readonly="readonly">
                          </div>
                          <div class="form-group">
-                           <input type="text" class="form-control" name="slice_name" id="slice_name" style="width:300px" placeholder="Slice Name
+                           <input type="text" class="form-control" name="slice_name" id="slice_name" style="width:300px" placeholder="Slice name" value="{{slice_name}}
                                title="Please enter a name for your slice"required="required">
                          </div>
                          <div class="form-group">
                                {%endif%}
                          </div>
                          <div class="form-group">
-                           <input type="text" class="form-control" name="number_of_nodes" id="number_of_nodes" style="width:300px" placeholder="Experiment URL (if one exists)"
-                               title="Please provide the url of your experiment if you have one.">
+                           <input type="text" class="form-control" name="exp_url" id="exp_url" style="width:300px" placeholder="Experiment URL (if one exists)"
+                               title="Please provide the url of your experiment if you have one." value="{{exp_url}}">
                          </div>
                          <div class="form-group">
-                               <textarea id="purpose" name="purpose" class="form-control" rows="6" placeholder="Experiment Purpose" style="width:300px" 
+                               <textarea id="purpose" name="purpose" class="form-control" rows="6" placeholder="Experiment purpose" style="width:300px" 
                                title="Purpose of your experiment (informative)" required="required">{{ purpose }}</textarea>
                          </div>
                          <button type="submit" class="btn btn-onelab"><span class="glyphicon glyphicon-plus"></span> Request Slice</button>
 <script>
 jQuery(document).ready(function(){
        
-       $("#authority_hrn").load("/rest/user/", {"fields" : ["parent_authority"], "filters": {"user_hrn": "{{ user_hrn }}"}}, function(data) {
+       /*$("#authority_hrn").load("/rest/user/", {"fields" : ["parent_authority"], "filters": {"user_hrn": "{{ user_hrn }}"}}, function(data) {
                var jsonData = JSON.parse(data);
-               // getting the authority from the view not rest
-        $(this).attr("value", "{{authority_name}}");
-    });
+        $(this).attr("value", jsonData[0]['parent_authority']);
+    });*/
+       $("#authority_hrn").val("{{authority_name}}");
        var availableTags = [
     {% if authorities %}
         {% for authority in authorities %}
diff --git a/portal/templates/onelab/onelab_user_request_email.html b/portal/templates/onelab/onelab_user_request_email.html
new file mode 100644 (file)
index 0000000..fa0e896
--- /dev/null
@@ -0,0 +1,18 @@
+<img src="https://onelab.eu/templates/onelab2/images/logo.png">
+<br>
+<h1>NEW USER REQUEST</h1>
+<br>
+<p>You are receiving this request because we have you listed as a manager at an organization that uses OneLab.</p> 
+<p>If you believe that you have received this message in error, or if you have any questions, kindly contact support@onelab.eu.</p>
+<br>
+<b>First name   :</b> {{first_name}}<br>
+<b>Last name    :</b> {{last_name}}<br>
+<b>Organization :</b> {{organization}}<br>
+<b>Authority hrn:</b> {{authority_hrn}}<br>
+<b>Public key   :</b> {{public_key}}<br>
+<b>Email        :</b> {{email}}<br>
+<b>User hrn     :</b> {{user_hrn}}<br>
+<b>Portal url  :</b> {{ current_site }}<br>
+<p></p>
+<p>You can validate the user <a href="http://{{current_site}}/portal/validate">here</a>.<p>
+<p>Please note that the validation request will only become visible to you on the OneLab portal once the user has confirmed his/her email address.</p>
diff --git a/portal/templates/onelab/onelab_user_request_email.txt b/portal/templates/onelab/onelab_user_request_email.txt
new file mode 100644 (file)
index 0000000..b782e71
--- /dev/null
@@ -0,0 +1,19 @@
+NEW USER REQUEST
+
+You are receiving this request because we have you listed as a manager at an organization that uses OneLab. 
+If you believe that you have received this message in error, or if you have any questions, kindly contact support@onelab.eu.
+
+First name   : {{first_name}}
+Last name    : {{last_name}} 
+Organization :{{organization}}
+Authority hrn: {{authority_hrn}}
+Public key   : {{public_key}}
+Email        : {{email}}
+User hrn     : {{user_hrn}}
+Portal url   : {{ current_site }}
+
+You can validate the user here: http://{{current_site}}/portal/validate
+
+Please note that the validation request will only become visible to you on the OneLab portal once the user has confirmed his/her email address.
+
+
index 868f818..eed94a0 100644 (file)
@@ -19,7 +19,7 @@
        <div class="col-md-3">
                <form action="" method="post">{% csrf_token %}
                {{ form.new_password1.errors }}
-               <label for="id_new_password1">{% trans 'New password:' %}</label>
+               <label for="id_new_password1">New password:</label>
        </div>
        <div class="col-md-3">
                {{ form.new_password1 }}
@@ -28,7 +28,7 @@
 <div class="row">
        <div class="col-md-3">
                {{ form.new_password2.errors }}
-               <label for="id_new_password2">{% trans 'Confirm password:' %}</label>
+               <label for="id_new_password2">Confirm password:</label>
        </div>
        <div class="col-md-3">  
                {{ form.new_password2 }}
index 417a8bd..8306c2b 100644 (file)
@@ -2,10 +2,10 @@
 <br>
 <h1>NEW SLICE REQUEST</h1>
 <br>
-<b>slice name      :</b> {{slice_name}}</br>
-<b>number of nodes :</b> {{number_of_nodes}}</br>
-<b>purpose         :</b> {{purpose}}</br>
-<b>organization           :</b> {{organization}}
-<b>email           :</b> {{email}}</br>
+<b>Slice name      :</b> {{slice_name}}</br>
+<b>URL                            :</b> {{exp_url}}</br>
+<b>Purpose         :</b> {{purpose}}</br>
+<b>Organization           :</b> {{organization}}</br>
+<b>Email           :</b> {{email}}</br>
 <b>Portal url     :</b> {{current_site}}</br> 
 
index 6cd5a2d..c8a51b5 100644 (file)
@@ -1,9 +1,9 @@
 NEW SLICE REQUEST
 
-slice name      : {{slice_name}}
-number of nodes : {{number_of_nodes}}
-purpose         : {{purpose}}
-email           : {{email}}
-organization   : {{organization}}
+Slice name      : {{slice_name}}
+URL                    : {{exp_url}}
+Purpose         : {{purpose}}
+Email           : {{email}}
+Organization   : {{organization}}
 Portal url             : {{current_site}}
 
index 9bd0175..74f113a 100644 (file)
@@ -1,5 +1,6 @@
 from django import template
 from django.template.loader_tags import do_include
+from django.core.files.storage import default_storage
 from myslice.settings import theme
 
 register = template.Library()
@@ -37,4 +38,13 @@ def widget(parser, token):
         raise template.TemplateSyntaxError, \
             "%r tag requires a single argument" % token.contents.split()[0]
 
-    return IncludeNode(template_name[1:-1])
\ No newline at end of file
+    return IncludeNode(template_name[1:-1])
+
+@register.filter(name='file_exists')
+def file_exists(filepath):
+    if default_storage.exists('portal' + filepath):
+        return filepath
+    else:
+        index = filepath.rfind('/')
+        new_filepath = filepath[:index] + '/image.png'
+        return new_filepath
\ No newline at end of file