Merge branch 'onelab' of ssh://git.onelab.eu/git/myslice into onelab
authorJordan Augé <jordan.auge@lip6.fr>
Sun, 6 Jul 2014 17:56:52 +0000 (19:56 +0200)
committerJordan Augé <jordan.auge@lip6.fr>
Sun, 6 Jul 2014 17:56:52 +0000 (19:56 +0200)
Conflicts:
portal/sliceresourceview.py

53 files changed:
myslice/urls.py
portal/accountview.py
portal/contactview.py
portal/emailactivationview.py
portal/forms.py
portal/homeview.py
portal/institution.py
portal/joinview.py
portal/managementtabrequests.py [new file with mode: 0644]
portal/registrationview.py
portal/slicerequestview.py
portal/sliceresourceview.py
portal/sliceview.py
portal/static/css/jquery.qtip.min.css [new file with mode: 0644]
portal/static/css/onelab.css
portal/static/js/join.js
portal/static/js/jquery.qtip.min.js [new file with mode: 0644]
portal/supportview.py
portal/templates/activate_user.html
portal/templates/activate_user.txt
portal/templates/base.html
portal/templates/contact.html
portal/templates/email_activation.html
portal/templates/institution.html
portal/templates/join_complete.html [new file with mode: 0644]
portal/templates/join_view.html
portal/templates/onelab/onelab_about.html [new file with mode: 0644]
portal/templates/onelab/onelab_account-view.html [new file with mode: 0644]
portal/templates/onelab/onelab_contact.html [new file with mode: 0644]
portal/templates/onelab/onelab_home-view.html
portal/templates/onelab/onelab_institution.html
portal/templates/onelab/onelab_management-tab-requests.html [new file with mode: 0644]
portal/templates/onelab/onelab_news.html
portal/templates/onelab/onelab_registration_view.html [new file with mode: 0644]
portal/templates/onelab/onelab_slicerequest_view.html [new file with mode: 0644]
portal/templates/onelab/onelab_supportview.html [new file with mode: 0644]
portal/templates/onelab/onelab_widget-login-user.html
portal/templates/onelab/onelab_widget-slice-sections.html
portal/templates/onelab/onelab_widget-topmenu.html
portal/templates/password_reset_confirm.html
portal/templates/password_reset_form.html
portal/templates/registration_view.html
portal/templates/slice-request-view.html
portal/templates/slicerequest_view.html
portal/templates/supportview.html
portal/templates/termsview.html [new file with mode: 0644]
portal/templates/user_register_complete.html
portal/templates/user_request_email.html
portal/templates/user_request_email.txt
portal/termsview.py [new file with mode: 0644]
portal/urls.py
portal/validationview.py
setup.py

index a49156e..403db6a 100644 (file)
@@ -31,6 +31,8 @@ import portal.slicetabtestbeds
 import portal.slicetabusers
 import portal.slicetabmeasurements 
 
+import portal.managementtabrequests
+
 #### high level choices
 # main entry point (set to the / URL)
 # beware that if this view is broken you end up in an endless cycle...
@@ -90,6 +92,9 @@ urls = [
     (r'^testbeds/(?P<slicename>[^/]+)/?$', portal.slicetabtestbeds.SliceTabTestbeds.as_view()),
     (r'^measurements/(?P<slicename>[^/]+)/?$', portal.slicetabmeasurements.SliceTabMeasurements.as_view()),
     (r'^experiment/(?P<slicename>[^/]+)/?$', portal.slicetabexperiment.ExperimentView.as_view()),
+    #
+    (r'^management/requests/?$', portal.managementtabrequests.ManagementRequestsView.as_view()),
+    #
     url(r'^portal/', include('portal.urls')),
 
     # SLA
index 4f4ecbf..c88ac0e 100644 (file)
@@ -184,11 +184,32 @@ class AccountView(LoginRequiredAutoLogoutView, ThemeView):
         # we could use zip. this one is used if columns have unequal rows 
         platform_list = [{'platform_no_access': t[0]}
             for t in itertools.izip_longest(total_platform_list)]
+
+
+        ## check user is pi or not
+        platform_query  = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled')
+        account_query  = Query().get('local:account').select('user_id','platform_id','auth_type','config')
+        platform_details = execute_query(self.request, platform_query)
+        account_details = execute_query(self.request, account_query)
+        for platform_detail in platform_details:
+            for account_detail in account_details:
+                if platform_detail['platform_id'] == account_detail['platform_id']:
+                    if 'config' in account_detail and account_detail['config'] is not '':
+                        account_config = json.loads(account_detail['config'])
+                        if 'myslice' in platform_detail['platform']:
+                            acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
+        # assigning values
+        if acc_auth_cred == {} or acc_auth_cred == 'N/A':
+            pi = "is_not_pi"
+        else:
+            pi = "is_pi"
+
         context = super(AccountView, self).get_context_data(**kwargs)
         context['principal_acc'] = principal_acc_list
         context['ref_acc'] = ref_acc_list
         context['platform_list'] = platform_list
         context['my_users'] = my_users
+        context['pi'] = pi
         context['my_slices'] = my_slices
         context['my_auths'] = my_auths
         context['user_status'] = user_status
index 3da2e05..c41ee74 100644 (file)
@@ -6,6 +6,9 @@ from unfold.loginrequired       import FreeAccessView
 from ui.topmenu                 import topmenu_items, the_user
 from django.core.mail           import EmailMultiAlternatives, send_mail
 from portal.forms               import ContactForm
+from manifold.core.query                import Query
+from manifoldapi.manifoldapi            import execute_query
+import json
 
 from myslice.theme import ThemeView
 theme = ThemeView()
@@ -32,7 +35,7 @@ class ContactView (FreeAccessView, ThemeView):
             #theme.template_name = 'email_support.txt'
             #recipients = render_to_string(theme.template, form.cleaned_data)
             #recipients = subject.replace('\n', '')
-            recipients = ['support@myslice.info','contact@fed4fire.eu']
+            recipients = ['support@myslice.info']
             if cc_myself:
                 recipients.append(email)
             #recipients = ['support@myslice.info']
@@ -71,14 +74,33 @@ class ContactView (FreeAccessView, ThemeView):
         return self._display (request, ContactForm()) # A fresh unbound form
         
     def _display (self, request, form):
-        if request.user.is_authenticated() :
+        if request.user.is_authenticated():
             username = request.user.email
+            ## check user is pi or not
+            platform_query  = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled')
+            account_query  = Query().get('local:account').select('user_id','platform_id','auth_type','config')
+            platform_details = execute_query(self.request, platform_query)
+            account_details = execute_query(self.request, account_query)
+            for platform_detail in platform_details:
+                for account_detail in account_details:
+                    if platform_detail['platform_id'] == account_detail['platform_id']:
+                        if 'config' in account_detail and account_detail['config'] is not '':
+                            account_config = json.loads(account_detail['config'])
+                            if 'myslice' in platform_detail['platform']:
+                                acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
+            # assigning values
+            if acc_auth_cred == {} or acc_auth_cred == 'N/A':
+                pi = "is_not_pi"
+            else:
+                pi = "is_pi"
         else :
             username = None
+            pi = "is_not_pi"
         return render(request, self.template, {
                 'form': form,
                 'topmenu_items': topmenu_items('Contact', request),
                 'theme' : self.theme,
                 'username': username,
+                'pi': pi,
                 'section': "Contact"
                 })
index dd3788a..2a3e617 100644 (file)
@@ -2,7 +2,7 @@ from unfold.loginrequired               import FreeAccessView
 #
 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
+from portal.actions                     import manifold_update_user, manifold_update_account, manifold_add_account, manifold_delete_account, sfa_update_user, authority_get_pi_emails
 #
 from unfold.page                        import Page    
 from ui.topmenu                         import topmenu_items_live, the_user
@@ -12,6 +12,9 @@ from django.contrib                     import messages
 from django.contrib.auth.decorators     import login_required
 from myslice.theme                      import ThemeView
 from portal.models                      import PendingUser
+from django.core.mail                   import EmailMultiAlternatives, send_mail
+from django.contrib.sites.models        import Site
+
 #
 import json, os, re, itertools
 
@@ -33,15 +36,50 @@ class ActivateEmailView(FreeAccessView, ThemeView):
             if key == "hash_code":
                 hash_code=value
        
-        if PendingUser.objects.filter(email_hash__iexact = hash_code):
+        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')
             activation = 'success'
+            # sending email after activation success
+            #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()
+
         else:
             activation = 'failed'
+        
+        # get the domain url
+        current_site = Site.objects.get_current()
+        current_site = current_site.domain
 
+        
         context = super(ActivateEmailView, self).get_context_data(**kwargs)
         context['activation_status'] = activation
         # XXX This is repeated in all pages
@@ -51,6 +89,13 @@ class ActivateEmailView(FreeAccessView, ThemeView):
         context['topmenu_items'] = topmenu_items_live('My Account', page)
         # so we can sho who is logged
         context['username'] = the_user(self.request)
+        #context['first_name'] = first_name
+        #context['last_name'] = last_name
+        #context['authority_hrn'] = authority_hrn
+        #context['public_key'] = public_key
+        #context['email'] = email
+        #context['user_hrn'] = user_hrn
+        #context['current_site'] = current_site
         context['theme'] = self.theme
 #        context ['firstname'] = config['firstname']
         prelude_env = page.prelude_env()
index ecd2e6c..683cffb 100644 (file)
@@ -99,7 +99,7 @@ class ContactForm(forms.Form):
 class PassResetForm(forms.Form):
     email = forms.EmailField(widget=forms.TextInput(attrs={'class':'form-control'}))
 
-class SliceRequestForm(forms.Form):
+#class SliceRequestForm(forms.Form):
 #    slice_name = forms.CharField()
 #    authority_hrn = forms.ChoiceField(choices=[(1, 'un')])
 #    number_of_nodes  = forms.DecimalField()
@@ -107,52 +107,52 @@ class SliceRequestForm(forms.Form):
 #    purpose = forms.CharField(widget=forms.Textarea)
 #    email = forms.EmailField()
 #    cc_myself = forms.BooleanField(required=False)
-
-    slice_name = forms.CharField(
-        widget=forms.TextInput(attrs={'class':'form-control'}), 
-        help_text="The name for the slice you wish to create")
-    authority_hrn = forms.ChoiceField(
-        widget    = forms.Select(attrs={'class':'form-control'}),
-        choices   = [],
-        help_text = "An authority responsible for vetting your slice")
-    number_of_nodes = forms.DecimalField(
-        widget    = forms.TextInput(attrs={'class':'form-control'}),
-        help_text = "The number of nodes you expect to request (informative)")
-    type_of_nodes = forms.CharField(
-        widget    = forms.TextInput(attrs={'class':'form-control'}),
-        help_text = "The type of nodes you expect to request (informative)")
-    purpose = forms.CharField(
-        widget    = forms.Textarea(attrs={'class':'form-control'}),
-        help_text = "The purpose of your experiment (informative)")
-    email = forms.EmailField(
-        widget    = forms.TextInput(attrs={'class':'form-control'}),
-        help_text = "Your email address")
-    cc_myself = forms.BooleanField(
-        widget    = forms.CheckboxInput(attrs={'class':'form-control'}),
-        required  = False,
-        help_text = "If you'd like to be cc'ed on the request email")
-
-    def __init__(self, *args, **kwargs):
-        initial =  kwargs.get('initial', {})
-        authority_hrn = initial.get('authority_hrn', None)
-
-        # set just the initial value
-        # in the real form needs something like this {'authority_hrn':'a'}
-        # but in this case you want {'authority_hrn':('a', 'letter_a')}
-        if authority_hrn:
-            kwargs['initial']['authority_hrn'] = authority_hrn[0]
-
-        # create the form
-        super(SliceRequestForm, self).__init__(*args, **kwargs)
-
-        # self.fields only exist after, so a double validation is needed
-        if authority_hrn:# and authority_hrn[0] not in (c[0] for c in authority_hrn):
-            # XXX This does not work, the choicefield is not updated...
-            #self.fields['authority_hrn'].choices.extend(authority_hrn)
-            self.fields['authority_hrn'] = forms.ChoiceField(
-                widget    = forms.Select(attrs={'class':'form-control'}),
-                choices   = authority_hrn,
-                help_text = "An authority responsible for vetting your slice")
+#
+#    slice_name = forms.CharField(
+#        widget=forms.TextInput(attrs={'class':'form-control'}), 
+#        help_text="The name for the slice you wish to create")
+#    authority_hrn = forms.ChoiceField(
+#        widget    = forms.Select(attrs={'class':'form-control'}),
+#        choices   = [],
+#        help_text = "An authority responsible for vetting your slice")
+#    number_of_nodes = forms.DecimalField(
+#        widget    = forms.TextInput(attrs={'class':'form-control'}),
+#        help_text = "The number of nodes you expect to request (informative)")
+#    type_of_nodes = forms.CharField(
+#        widget    = forms.TextInput(attrs={'class':'form-control'}),
+#        help_text = "The type of nodes you expect to request (informative)")
+#    purpose = forms.CharField(
+#        widget    = forms.Textarea(attrs={'class':'form-control'}),
+#        help_text = "The purpose of your experiment (informative)")
+#    email = forms.EmailField(
+#        widget    = forms.TextInput(attrs={'class':'form-control'}),
+#        help_text = "Your email address")
+#    cc_myself = forms.BooleanField(
+#        widget    = forms.CheckboxInput(attrs={'class':'form-control'}),
+#        required  = False,
+#        help_text = "If you'd like to be cc'ed on the request email")
+#
+#    def __init__(self, *args, **kwargs):
+#        initial =  kwargs.get('initial', {})
+#        authority_hrn = initial.get('authority_hrn', None)
+#
+#        # set just the initial value
+#        # in the real form needs something like this {'authority_hrn':'a'}
+#        # but in this case you want {'authority_hrn':('a', 'letter_a')}
+#        if authority_hrn:
+#            kwargs['initial']['authority_hrn'] = authority_hrn[0]
+#
+#        # create the form
+#        super(SliceRequestForm, self).__init__(*args, **kwargs)
+#
+#        # self.fields only exist after, so a double validation is needed
+#        if authority_hrn:# and authority_hrn[0] not in (c[0] for c in authority_hrn):
+#            # XXX This does not work, the choicefield is not updated...
+#            #self.fields['authority_hrn'].choices.extend(authority_hrn)
+#            self.fields['authority_hrn'] = forms.ChoiceField(
+#                widget    = forms.Select(attrs={'class':'form-control'}),
+#                choices   = authority_hrn,
+#                help_text = "An authority responsible for vetting your slice")
 
 
 class PasswordResetForm(forms.Form):
index 1097570..d46ed65 100644 (file)
@@ -5,6 +5,7 @@ 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
+import json
 
 from unfold.loginrequired import FreeAccessView
 
@@ -60,6 +61,26 @@ class HomeView (FreeAccessView, ThemeView):
                 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')
+                    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))
@@ -76,8 +97,26 @@ class HomeView (FreeAccessView, ThemeView):
 
     def get (self, request, state=None):
         env = self.default_env()
+        if request.user.is_authenticated():
+            ## check user is pi or not
+            platform_query  = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled')
+            account_query  = Query().get('local:account').select('user_id','platform_id','auth_type','config')
+            platform_details = execute_query(self.request, platform_query)
+            account_details = execute_query(self.request, account_query)
+            for platform_detail in platform_details:
+                for account_detail in account_details:
+                    if platform_detail['platform_id'] == account_detail['platform_id']:
+                        if 'config' in account_detail and account_detail['config'] is not '':
+                            account_config = json.loads(account_detail['config'])
+                            if 'myslice' in platform_detail['platform']:
+                                acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
+            # assigning values
+            if acc_auth_cred=={} or acc_auth_cred=='N/A':
+                pi = "is_not_pi"
+            else:
+                pi = "is_pi"
 
-        if request.user.is_authenticated(): 
+            env['pi'] = pi     
             env['person'] = self.request.user
         else: 
             env['person'] = None
index c53318b..6dd1b20 100644 (file)
@@ -66,7 +66,7 @@ class InstitutionView (LoginRequiredAutoLogoutView, ThemeView):
                             if 'myslice' in platform_detail['platform']:
                                 acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
             # assigning values
-            if acc_auth_cred == {}:
+            if acc_auth_cred == {} or acc_auth_cred == 'N/A':
                 pi = "is_not_pi"
             else:
                 pi = "is_pi"
index 65d8351..5dd04c2 100644 (file)
@@ -43,8 +43,8 @@ class JoinView (FreeAccessView, ThemeView):
         root_authorities = sorted([a for a in authorities if '.' not in a['authority_hrn']])
 
         page = Page(request)
-        page.add_js_files  ( [ "js/jquery.validate.js", "js/join.js" ] )
-        page.add_css_files ( [ "css/onelab.css", "css/registration.css" ] )
+        page.add_js_files  ( [ "js/jquery.validate.js", "js/join.js", "js/jquery.qtip.min.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" ] )
 
         if method == 'POST':
@@ -216,8 +216,10 @@ class JoinView (FreeAccessView, ThemeView):
     
                 except Exception, e:
                     print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
-
-                return render(request, 'user_register_complete.html') 
+                
+                self.template_name = 'join_complete.html'
+                return render(request, self.template, {'theme': self.theme})
+                #return render(request, 'user_register_complete.html') 
 
         template_env = {
           'topmenu_items': topmenu_items_live('join', page),
diff --git a/portal/managementtabrequests.py b/portal/managementtabrequests.py
new file mode 100644 (file)
index 0000000..f2cea92
--- /dev/null
@@ -0,0 +1,159 @@
+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 django.views.generic.base      import TemplateView
+
+from unfold.loginrequired           import LoginRequiredView
+from django.http import HttpResponse
+from django.shortcuts import render
+
+from manifold.core.query             import Query, AnalyzedQuery
+from manifoldapi.manifoldapi         import execute_query
+
+from portal.actions             import get_requests
+
+from myslice.theme import ThemeView
+
+import json
+
+class ManagementRequestsView (LoginRequiredView, ThemeView):
+    template_name = "management-tab-requests.html"
+    
+    def get(self, request):
+       
+        ctx_my_authorities = {}
+        ctx_delegation_authorities = {}
+        ctx_sub_authorities = {}
+        dest = {}
+
+
+        # The user need to be logged in
+        if (request.user):
+           
+            user_query = Query().get('local:user').filter_by('email', '==', self.request.user.email).select('user_id')
+            user, = execute_query(self.request, user_query)
+            user_id = user['user_id']
+
+            # 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
+            all_authorities = []
+            platform_ids = []
+            sfa_platforms_query = Query().get('local:platform').filter_by('gateway_type', '==', 'sfa').select('platform_id', 'platform', 'auth_type')
+            sfa_platforms = execute_query(self.request, sfa_platforms_query)
+            for sfa_platform in sfa_platforms:
+                print "SFA PLATFORM > ", sfa_platform['platform']
+                if not 'auth_type' in sfa_platform:
+                    continue
+                auth = sfa_platform['auth_type']
+                if not auth in all_authorities:
+                    all_authorities.append(auth)
+                platform_ids.append(sfa_platform['platform_id'])
+
+            print "W: Hardcoding platform myslice"
+            # There has been a tweak on how new platforms are referencing a
+            # so-called 'myslice' platform for storing authentication tokens.
+            # XXX This has to be removed in final versions.
+            myslice_platforms_query = Query().get('local:platform').filter_by('platform', '==', 'myslice').select('platform_id')
+            myslice_platforms = execute_query(self.request, myslice_platforms_query)
+            if myslice_platforms:
+                myslice_platform, = myslice_platforms
+                platform_ids.append(myslice_platform['platform_id'])
+
+            # We can check on which the user has authoritity credentials = PI rights
+            credential_authorities = set()
+            credential_authorities_expired = set()
+
+            # User account on these registries
+            user_accounts_query = Query.get('local:account').filter_by('user_id', '==', user_id).filter_by('platform_id', 'included', platform_ids).select('auth_type', 'config')
+            user_accounts = execute_query(self.request, user_accounts_query)
+            
+            for user_account in user_accounts:
+
+                print "USER ACCOUNT", user_account
+                if user_account['auth_type'] == 'reference':
+                    continue # we hardcoded the myslice platform...
+
+                config = json.loads(user_account['config'])
+                creds = []
+                print "CONFIG KEYS", config.keys()
+                if 'authority_credentials' in config:
+                    print "***", config['authority_credentials'].keys()
+                    for authority_hrn, credential in config['authority_credentials'].items():
+                        credential_authorities.add(authority_hrn)
+                if 'delegated_authority_credentials' in config:
+                    print "***", config['delegated_authority_credentials'].keys()
+                    for authority_hrn, credential in config['delegated_authority_credentials'].items():
+                        credential_authorities.add(authority_hrn)
+
+            print 'credential_authorities =', credential_authorities
+            print 'credential_authorities_expired =', credential_authorities_expired
+
+            # ** Where am I a PI **
+            # For this we need to ask SFA (of all authorities) = PI function
+            pi_authorities_query = Query.get('user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
+            pi_authorities_tmp = execute_query(self.request, pi_authorities_query)
+            pi_authorities = set()
+            try:
+                for pa in pi_authorities_tmp:
+                    pi_authorities |= set(pa['pi_authorities'])
+            except:
+                print 'No pi_authorities'
+
+            pi_credential_authorities = pi_authorities & credential_authorities
+            pi_no_credential_authorities = pi_authorities - credential_authorities - credential_authorities_expired
+            pi_expired_credential_authorities = pi_authorities & credential_authorities_expired
+            # Authorities I've been delegated PI rights
+            pi_delegation_credential_authorities = credential_authorities - pi_authorities
+            pi_delegation_expired_authorities = credential_authorities_expired - pi_authorities
+
+            # Summary intermediary
+            pi_my_authorities = pi_credential_authorities | pi_no_credential_authorities | pi_expired_credential_authorities
+            pi_delegation_authorities = pi_delegation_credential_authorities | pi_delegation_expired_authorities
+
+            # Summary all
+            queried_pending_authorities = pi_my_authorities | pi_delegation_authorities #| pi_subauthorities
+
+            # 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']
+                for my_auth in pi_my_authorities: 
+                    if auth_hrn.startswith(my_auth):
+                        dest = ctx_my_authorities
+                        r['allowed'] = 'allowed'
+                for my_auth in pi_delegation_authorities:
+                    if auth_hrn.startswith(my_auth):
+                        dest = ctx_delegation_authorities
+                        r['allowed'] = 'allowed'
+                if auth_hrn in pi_expired_credential_authorities:
+                    r['allowed'] = 'expired'
+                if 'allowed' not in r:
+                    r['allowed'] = 'denied'
+
+
+                if not auth_hrn in dest:
+                    dest[auth_hrn] = []
+                dest[auth_hrn].append(request)
+                
+              
+        env = {}
+        env['my_authorities']   = ctx_my_authorities
+        env['sub_authorities']   = ctx_sub_authorities
+        env['delegation_authorities'] = ctx_delegation_authorities
+
+        # XXX This is repeated in all pages
+        # more general variables expected in the template
+        # the menu items on the top
+        #env['topmenu_items'] = topmenu_items_live('Validation', page) 
+        # so we can sho who is logged
+        env['username'] = request.user
+        env['pi'] = "is_pi"       
+        env['theme'] = self.theme
+        env['section'] = "Requests"
+        
+        return render_to_response(self.template, env, context_instance=RequestContext(request))
index f731447..46c64b1 100644 (file)
@@ -45,17 +45,25 @@ class RegistrationView (FreeAccessView, ThemeView):
         
         # Page rendering
         page = Page(wsgi_request)
-        page.add_js_files  ( [ "js/jquery.validate.js", "js/my_account.register.js" ] )
-        page.add_css_files ( [ "css/onelab.css", "css/registration.css" ] )
+        page.add_js_files  ( [ "js/jquery.validate.js", "js/my_account.register.js", "js/jquery.qtip.min.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" ] )
 
         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)
+    
+            for authority in authorities:
+                if authority['name'] == wsgi_request.POST.get('org_name', ''):
+                    authority_hrn = authority['authority_hrn']     
+
             post_email = wsgi_request.POST.get('email','').lower()
             salt = randint(1,100000)
             email_hash = md5(str(salt)+post_email).hexdigest()
@@ -63,12 +71,13 @@ class RegistrationView (FreeAccessView, ThemeView):
             user_request = {
                 'first_name'    : wsgi_request.POST.get('firstname',     ''),
                 'last_name'     : wsgi_request.POST.get('lastname',      ''),
-                'authority_hrn' : wsgi_request.POST.get('authority_hrn', ''),
+                'organization'  : wsgi_request.POST.get('org_name', ''),
+                'authority_hrn' : authority_hrn, 
                 'email'         : post_email,
                 'password'      : wsgi_request.POST.get('password',      ''),
                 'current_site'  : current_site,
                 'email_hash'    : email_hash,
-                'validation_link': 'https://' + current_site + '/portal/email_activation/'+ email_hash
+                'validation_link': 'http://' + current_site + '/portal/email_activation/'+ email_hash
             }
 
             # Construct user_hrn from email (XXX Should use common code)
@@ -144,6 +153,12 @@ class RegistrationView (FreeAccessView, ThemeView):
 
         else:
             user_request = {}
+            ## this is coming from onelab website onelab.eu
+            reg_form = {
+                'first_name':  wsgi_request.GET.get('first_name', ''),
+                'last_name': wsgi_request.GET.get('last_name', ''),
+                'email': wsgi_request.GET.get('email', ''),
+                }
 
         template_env = {
           'topmenu_items': topmenu_items_live('Register', page),
@@ -152,5 +167,6 @@ class RegistrationView (FreeAccessView, ThemeView):
           'theme': self.theme
           }
         template_env.update(user_request)
+        template_env.update(reg_form)
         template_env.update(page.prelude_env ())
         return render(wsgi_request, self.template,template_env)
index 5eb0725..bc8c203 100644 (file)
@@ -8,7 +8,7 @@ from manifold.core.query        import Query
 from manifoldapi.manifoldapi    import execute_admin_query, execute_query
 
 from portal.actions             import is_pi, create_slice, create_pending_slice
-from portal.forms               import SliceRequestForm
+#from portal.forms               import SliceRequestForm
 from unfold.loginrequired       import LoginRequiredAutoLogoutView
 from ui.topmenu                 import topmenu_items_live, the_user
 
@@ -62,7 +62,7 @@ class SliceRequestView (LoginRequiredAutoLogoutView, ThemeView):
 
 
         # checking if pi or not
-        if acc_auth_cred == {}:
+        if acc_auth_cred == {} or acc_auth_cred == 'N/A':
             pi = "is_not_pi"
         else:
             pi = "is_pi"
index 49230df..da362d3 100644 (file)
@@ -1,8 +1,9 @@
 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
 
@@ -247,7 +248,25 @@ class SliceResourceView (LoginRequiredView, ThemeView):
             outline_complete    = True,
             username            = 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')
+        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"
+        
         template_env = {}
         template_env['list_resources'] = list_resources.render(self.request)
         template_env['list_reserved_resources'] = list_reserved_resources.render(self.request)
@@ -265,6 +284,7 @@ class SliceResourceView (LoginRequiredView, ThemeView):
         template_env['sla_dialog'] = '' # sla_dialog.render(self.request)
         template_env["theme"] = self.theme
         template_env["username"] = request.user
+        template_env["pi"] = pi
         template_env["slice"] = slicename
         template_env["section"] = "resources"
         template_env["msg"] = msg
index e79b48e..309347c 100644 (file)
@@ -13,11 +13,28 @@ from django.shortcuts import render
 from unfold.page                     import Page
 from manifold.core.query             import Query, AnalyzedQuery
 from manifoldapi.manifoldapi         import execute_query
-
+import json
 from myslice.theme import ThemeView
 
 class SliceView (LoginRequiredView, ThemeView):
     template_name = "slice-view.html"
     
     def get(self, request, slicename):
-        return render_to_response(self.template, {"slice": slicename, "theme": self.theme, "username": request.user, "section": "Slice %s" % slicename }, context_instance=RequestContext(request))
+        ## check user is pi or not
+        platform_query  = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled')
+        account_query  = Query().get('local:account').select('user_id','platform_id','auth_type','config')
+        platform_details = execute_query(self.request, platform_query)
+        account_details = execute_query(self.request, account_query)
+        for platform_detail in platform_details:
+            for account_detail in account_details:
+                if platform_detail['platform_id'] == account_detail['platform_id']:
+                    if 'config' in account_detail and account_detail['config'] is not '':
+                        account_config = json.loads(account_detail['config'])
+                        if 'myslice' in platform_detail['platform']:
+                            acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
+        # assigning values
+        if acc_auth_cred == {} or acc_auth_cred == 'N/A':
+            pi = "is_not_pi"
+        else:
+            pi = "is_pi"
+        return render_to_response(self.template, {"slice": slicename, "theme": self.theme, "username": request.user,"pi":pi, "section": "Slice %s" % slicename }, context_instance=RequestContext(request))
diff --git a/portal/static/css/jquery.qtip.min.css b/portal/static/css/jquery.qtip.min.css
new file mode 100644 (file)
index 0000000..fc172a4
--- /dev/null
@@ -0,0 +1,2 @@
+/* qTip2 v2.2.0 basic css3 | qtip2.com | Licensed MIT, GPL | Thu Nov 21 2013 20:35:00 */
+.qtip{position:absolute;left:-28000px;top:-28000px;display:none;max-width:280px;min-width:50px;font-size:10.5px;line-height:12px;direction:ltr;box-shadow:none;padding:0}.qtip-content{position:relative;padding:5px 9px;overflow:hidden;text-align:left;word-wrap:break-word}.qtip-titlebar{position:relative;padding:5px 35px 5px 10px;overflow:hidden;border-width:0 0 1px;font-weight:700}.qtip-titlebar+.qtip-content{border-top-width:0!important}.qtip-close{position:absolute;right:-9px;top:-9px;cursor:pointer;outline:medium none;border-width:1px;border-style:solid;border-color:transparent}.qtip-titlebar .qtip-close{right:4px;top:50%;margin-top:-9px}* html .qtip-titlebar .qtip-close{top:16px}.qtip-titlebar .ui-icon,.qtip-icon .ui-icon{display:block;text-indent:-1000em;direction:ltr}.qtip-icon,.qtip-icon .ui-icon{-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;text-decoration:none}.qtip-icon .ui-icon{width:18px;height:14px;line-height:14px;text-align:center;text-indent:0;font:400 bold 10px/13px Tahoma,sans-serif;color:inherit;background:transparent none no-repeat -100em -100em}.qtip-focus{}.qtip-hover{}.qtip-default{border-width:1px;border-style:solid;border-color:#F1D031;background-color:#FFFFA3;color:#555}.qtip-default .qtip-titlebar{background-color:#FFEF93}.qtip-default .qtip-icon{border-color:#CCC;background:#F1F1F1;color:#777}.qtip-default .qtip-titlebar .qtip-close{border-color:#AAA;color:#111} .qtip-light{background-color:#fff;border-color:#E2E2E2;color:#454545}.qtip-light .qtip-titlebar{background-color:#f1f1f1} .qtip-dark{background-color:#505050;border-color:#303030;color:#f3f3f3}.qtip-dark .qtip-titlebar{background-color:#404040}.qtip-dark .qtip-icon{border-color:#444}.qtip-dark .qtip-titlebar .ui-state-hover{border-color:#303030} .qtip-cream{background-color:#FBF7AA;border-color:#F9E98E;color:#A27D35}.qtip-cream .qtip-titlebar{background-color:#F0DE7D}.qtip-cream .qtip-close .qtip-icon{background-position:-82px 0} .qtip-red{background-color:#F78B83;border-color:#D95252;color:#912323}.qtip-red .qtip-titlebar{background-color:#F06D65}.qtip-red .qtip-close .qtip-icon{background-position:-102px 0}.qtip-red .qtip-icon{border-color:#D95252}.qtip-red .qtip-titlebar .ui-state-hover{border-color:#D95252} .qtip-green{background-color:#CAED9E;border-color:#90D93F;color:#3F6219}.qtip-green .qtip-titlebar{background-color:#B0DE78}.qtip-green .qtip-close .qtip-icon{background-position:-42px 0} .qtip-blue{background-color:#E5F6FE;border-color:#ADD9ED;color:#5E99BD}.qtip-blue .qtip-titlebar{background-color:#D0E9F5}.qtip-blue .qtip-close .qtip-icon{background-position:-2px 0}.qtip-shadow{-webkit-box-shadow:1px 1px 3px 1px rgba(0,0,0,.15);-moz-box-shadow:1px 1px 3px 1px rgba(0,0,0,.15);box-shadow:1px 1px 3px 1px rgba(0,0,0,.15)}.qtip-rounded,.qtip-tipsy,.qtip-bootstrap{-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.qtip-rounded .qtip-titlebar{-moz-border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.qtip-youtube{-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 0 3px #333;-moz-box-shadow:0 0 3px #333;box-shadow:0 0 3px #333;color:#fff;border-width:0;background:#4A4A4A;background-image:-webkit-gradient(linear,left top,left bottom,color-stop(0,#4A4A4A),color-stop(100%,#000));background-image:-webkit-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-moz-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-ms-linear-gradient(top,#4A4A4A 0,#000 100%);background-image:-o-linear-gradient(top,#4A4A4A 0,#000 100%)}.qtip-youtube .qtip-titlebar{background-color:#4A4A4A;background-color:rgba(0,0,0,0)}.qtip-youtube .qtip-content{padding:.75em;font:12px arial,sans-serif;filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=#4a4a4a, EndColorStr=#000000);-ms-filter:"progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=#4a4a4a, EndColorStr=#000000);"}.qtip-youtube .qtip-icon{border-color:#222}.qtip-youtube .qtip-titlebar .ui-state-hover{border-color:#303030}.qtip-jtools{background:#232323;background:rgba(0,0,0,.7);background-image:-webkit-gradient(linear,left top,left bottom,from(#717171),to(#232323));background-image:-moz-linear-gradient(top,#717171,#232323);background-image:-webkit-linear-gradient(top,#717171,#232323);background-image:-ms-linear-gradient(top,#717171,#232323);background-image:-o-linear-gradient(top,#717171,#232323);border:2px solid #ddd;border:2px solid rgba(241,241,241,1);-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-webkit-box-shadow:0 0 12px #333;-moz-box-shadow:0 0 12px #333;box-shadow:0 0 12px #333}.qtip-jtools .qtip-titlebar{background-color:transparent;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171, endColorstr=#4A4A4A);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#717171, endColorstr=#4A4A4A)"}.qtip-jtools .qtip-content{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A, endColorstr=#232323);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#4A4A4A, endColorstr=#232323)"}.qtip-jtools .qtip-titlebar,.qtip-jtools .qtip-content{background:transparent;color:#fff;border:0 dashed transparent}.qtip-jtools .qtip-icon{border-color:#555}.qtip-jtools .qtip-titlebar .ui-state-hover{border-color:#333}.qtip-cluetip{-webkit-box-shadow:4px 4px 5px rgba(0,0,0,.4);-moz-box-shadow:4px 4px 5px rgba(0,0,0,.4);box-shadow:4px 4px 5px rgba(0,0,0,.4);background-color:#D9D9C2;color:#111;border:0 dashed transparent}.qtip-cluetip .qtip-titlebar{background-color:#87876A;color:#fff;border:0 dashed transparent}.qtip-cluetip .qtip-icon{border-color:#808064}.qtip-cluetip .qtip-titlebar .ui-state-hover{border-color:#696952;color:#696952}.qtip-tipsy{background:#000;background:rgba(0,0,0,.87);color:#fff;border:0 solid transparent;font-size:11px;font-family:'Lucida Grande',sans-serif;font-weight:700;line-height:16px;text-shadow:0 1px #000}.qtip-tipsy .qtip-titlebar{padding:6px 35px 0 10px;background-color:transparent}.qtip-tipsy .qtip-content{padding:6px 10px}.qtip-tipsy .qtip-icon{border-color:#222;text-shadow:none}.qtip-tipsy .qtip-titlebar .ui-state-hover{border-color:#303030}.qtip-tipped{border:3px solid #959FA9;-moz-border-radius:3px;-webkit-border-radius:3px;border-radius:3px;background-color:#F9F9F9;color:#454545;font-weight:400;font-family:serif}.qtip-tipped .qtip-titlebar{border-bottom-width:0;color:#fff;background:#3A79B8;background-image:-webkit-gradient(linear,left top,left bottom,from(#3A79B8),to(#2E629D));background-image:-webkit-linear-gradient(top,#3A79B8,#2E629D);background-image:-moz-linear-gradient(top,#3A79B8,#2E629D);background-image:-ms-linear-gradient(top,#3A79B8,#2E629D);background-image:-o-linear-gradient(top,#3A79B8,#2E629D);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8, endColorstr=#2E629D);-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#3A79B8, endColorstr=#2E629D)"}.qtip-tipped .qtip-icon{border:2px solid #285589;background:#285589}.qtip-tipped .qtip-icon .ui-icon{background-color:#FBFBFB;color:#555}.qtip-bootstrap{font-size:14px;line-height:20px;color:#333;padding:1px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,.2);box-shadow:0 5px 10px rgba(0,0,0,.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.qtip-bootstrap .qtip-titlebar{padding:8px 14px;margin:0;font-size:14px;font-weight:400;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.qtip-bootstrap .qtip-titlebar .qtip-close{right:11px;top:45%;border-style:none}.qtip-bootstrap .qtip-content{padding:9px 14px}.qtip-bootstrap .qtip-icon{background:transparent}.qtip-bootstrap .qtip-icon .ui-icon{width:auto;height:auto;float:right;font-size:20px;font-weight:700;line-height:18px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.qtip-bootstrap .qtip-icon .ui-icon:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}.qtip:not(.ie9haxors) div.qtip-content,.qtip:not(.ie9haxors) div.qtip-titlebar{filter:none;-ms-filter:none}.qtip .qtip-tip{margin:0 auto;overflow:hidden;z-index:10}x:-o-prefocus,.qtip .qtip-tip{visibility:hidden}.qtip .qtip-tip,.qtip .qtip-tip .qtip-vml,.qtip .qtip-tip canvas{position:absolute;color:#123456;background:transparent;border:0 dashed transparent}.qtip .qtip-tip canvas{top:0;left:0}.qtip .qtip-tip .qtip-vml{behavior:url(#default#VML);display:inline-block;visibility:visible}#qtip-overlay{position:fixed;left:0;top:0;width:100%;height:100%}#qtip-overlay.blurs{cursor:pointer}#qtip-overlay div{position:absolute;left:0;top:0;width:100%;height:100%;background-color:#000;opacity:.7;filter:alpha(opacity=70);-ms-filter:"alpha(Opacity=70)"}.qtipmodal-ie6fix{position:absolute!important}
\ No newline at end of file
index 434a089..3486d15 100644 (file)
@@ -11,12 +11,13 @@ body {
 }
 a, a:active, a:focus {
     outline: 0;
+    text-decoration:none;
 }
 
 h1 {
     border-bottom:1px solid #DDDDDD;
     padding:0 0 0 0;
-    margin:0 0 0 0;
+    margin:15px 0 15px 0;
     font-size:14pt;
 }
 h1 img {
@@ -32,19 +33,18 @@ h3 {
     font-size:13pt;
     color:#201E62;
 }
-
-div.wrapper {
-    width:980px;
-    margin:0 auto;
-    position:relative;
-}
-div.container {
-    /*width:980px;
-    margin:25px auto;*/
+input[type=text], input[type=password], input[type=email],input[type=number], select, option {
+    min-width:260px;
+    padding:6px;
+    border:1pt solid #22606D;
+    vertical-align:bottom;
+    border-radius:0;
 }
-div.wide {
-    margin:25px auto;
-    padding:0 25px;
+
+textarea {
+    padding:6px;
+    border:1pt solid #22606D !important;
+    border-radius:0 !important;
 }
 
 span.label {
@@ -53,101 +53,94 @@ span.label {
     font-weight:normal;
     padding:0;
 }
-/***** Notifications *****/
-.warning {
-    border: 1px solid red;
-    margin: 20px 60px;
-    padding: 10px 20px;
-    color: red;
-    background-color: #f2dbdb;
-    text-align: center;
+div.el {
+    padding-bottom:15px;
 }
-/* HEADER */
-#header {
-  -moz-box-shadow:    0 0 1px rgba(82,82,82,0.6);
-  -webkit-box-shadow: 0 0 1px rgba(82,82,82,0.6);
-  box-shadow:         0 0 1px rgba(82,82,82,0.6);
-  
-  height:61px;
-  background-color:white;
-  z-index:2;
-}
-
-
-div#navigation {
-    background-color:black;
-    width:100%;
-    height:40px;
-}
-div#navigation div.wrapper {
-    text-align:center;
-}
-div#navigation ul {
-    margin:0;
-    padding:0;
-    display: inline-block;
-    list-style-type: none;
-    white-space: nowrap;
+div.breadcrumbs {
+    margin:15px 0;
+    color:gray;
+    font-size:10pt;
 }
-
-div#navigation li {
-    color:white;
-    font-family:helvetica, sans-serif;
-    font-size:10pt ;
+/* buttons */
+button.btn, input.btn {
+    padding:6px 10px;
+    border-radius:5px;
+    font-size:10pt;
     font-weight:normal;
-    line-height:0.8em;
-    letter-spacing:0.6pt;
-    list-style:none;
-    float:left;
-    padding:0;
-    margin:15px 50px 0 0;
-}
-div#navigation li a {
-    color:white;
 }
-div#navigation li a:hover {
-    text-decoration:none;
-    color:#B8B2FF;
+button.btn span.glyphicon {
+    margin-right:6px;
 }
-div#navigation li:last-child {
-    margin-right:0;
+button.btn-default {
+    border-bottom:3px solid #cccccc;
 }
-
-div#navigation li.active {
-       padding:5px;
-    padding-top: 15px;
-    min-height: 40px;
-    margin-top: 0px;
-       background-color:gray;
-       color:#FF0000;
+button.btn-default:hover {
+    background-color:white;
+    border:1px solid #ADADAD;
+    border-bottom:3px solid #ADADAD;
 }
-div#navigation li.slices {
-    position:relative;
-    cursor:pointer;
+button.btn-default:active {
+    background-color:white;
+    border:1px solid #ADADAD;
+    border-bottom:1px solid #ADADAD;
+    margin-top:2px;
+    box-shadow:none;
+}
+button.btn-primary {
+    border-bottom:3px solid #3071A9;
+}
+button.btn-primary:hover {
+    box-shadow:none;
+    background-color:#428bca;
+    border:1px solid #357ebd;
+    border-bottom:3px solid #3071A9;
+}
+button.btn-primary:active {
+    box-shadow:none;
+    border-bottom:1px solid #3071A9;
+    margin-top:2px;
+}
+button.btn-danger {
+    border-bottom:3px solid #A13F3A;
+}
+button.btn-danger:hover {
+    box-shadow:none;
+    background-color:#d9534f;
+    border:1px solid #d43f3a;
+    border-bottom:3px solid #A13F3A;
+}
+button.btn-danger:active {
+    border:1px solid #d43f3a;
+    box-shadow:none;
+    margin-top:2px;
+}
+button.btn-onelab, input.btn-onelab {
+    border:0;
+    border-bottom:3px solid #760073;
+    background-color:#302562;
+    color:white;
 }
-div.navigation .dropdown-menu {
-    color:black;
-    padding:0 15px 15px 15px;
-    margin-top:5px;
-    margin-left:-16px;
+button.btn-onelab:hover, input.btn-onelab:hover {
+    border:0;
+    border-bottom:3px solid #760073;
+    background-color:#302562;
+    color:white;
 }
-div.navigation .dropdown-menu a {
-    color:black;
+button.btn-onelab:active, input.btn-onelab:active {
+    box-shadow:none;
+    border-bottom:1px solid #760073;
+    margin-top:2px;
 }
-
-div.menu-slice-list {
-    display:none;
-    position:absolute;
-    padding:15px;
-    left:-15px;
-    z-index:10;
+/***** Notifications *****/
+.warning {
+    border: 1px solid red;
+    margin: 20px 60px;
+    padding: 10px 20px;
+    color: red;
+    background-color: #f2dbdb;
+    text-align: center;
 }
 
-div.navigation .dropdown-menu li:first-child {
-    border-bottom:1px solid white;
-    padding-bottom:5px;
-     
-}
 /* HOME DASHBOARD */
 div#home-dashboard {
     color:black;
@@ -228,15 +221,6 @@ div#home-dashboard div#home-slice-list li {
 div.well {
 }
 /**/
-/* BUTTON */
-.btn.btn-default {
-    font-weight: bold;
-}
-
-.btn.btn-default:hover {
-    font-weight: bold;
-}
-/**/
 /* TABLE */
 table.table {
     margin:0;
@@ -285,26 +269,22 @@ div#ticket-request p {
     margin:20px 0;
 }
 
-ul.nav-tabs {}
+ul.nav-tabs {
+    margin:0 0 15px 0;
+}
 ul.nav-tabs ul {}
 ul.nav-tabs li {}
 
 ul.nav-section li a {
+    color:black;
     border-bottom:0;
 }
 ul.nav-section li:first-child {
     padding:0;
 }
 ul.nav-section li:first-child a {
-    font-weight:bold;
-    padding:6px 15px 4px 15px;
 }
 ul.nav-section li:first-child.active a {
-    padding:6px 15px 3px 15px;
-}
-ul.nav-section li:first-child img {
-    margin:0 4px 1px 0;
-    padding:0;
 }
 
 ul.nav-resources {
@@ -448,7 +428,9 @@ div.dataTables_filter label{
     width:400px;
 }
 
-/**/
+/* HEADER */
+
+
 .header {
   -moz-box-shadow:    0 0 1px rgba(82,82,82,0.6);
   -webkit-box-shadow: 0 0 1px rgba(82,82,82,0.6);
@@ -456,6 +438,7 @@ div.dataTables_filter label{
   height:61px;
   background-color:white;
 }
+
 div.navigation {
     
 }
@@ -493,6 +476,50 @@ div.navigation li a:hover, div.navigation li a.current {
 div.navigation li:last-child {
     margin-right:0;
 }
+
+
+div.navigation .dropdown-menu {
+    color:black;
+    -moz-box-shadow:    1px 1px 0px 0 rgba(58, 48, 100,0.8);
+    -webkit-box-shadow: 1px 1px 0px 0 rgba(58, 48, 100,0.8);
+    box-shadow:         1px 1px 0px 0 rgba(58, 48, 100,0.8);
+    border-radius:2px;
+    padding:0 5px 5px 5px;
+    margin-top:5px;
+    margin-left:20px;
+}
+div.navigation .dropdown-menu ul {
+    margin:0;
+    padding:15px 5px 5px 5px;
+    display:list-item;
+}
+div.navigation .dropdown-menu li {
+    margin:0 10px 0 0;
+    padding:0 0 8px 0;
+    display:list-item;
+    float:none;
+    text-transform: none;
+}
+
+div.navigation .dropdown-menu a {
+    font-family:Helvetica,sans-serif;
+    font-size:10pt;
+    color:black;
+}
+div.navigation .dropdown-menu li.title {
+    margin-bottom:10px;
+}
+div.navigation .dropdown-menu li.title a {
+    font-family:open_sansbold, sans-serif;
+}
+
+
+div.navigation .dropdown-menu li:first-child {
+    border-bottom:1px solid white;
+    padding-bottom:5px;
+     
+}
+
 div.secondary {
     text-align:right;
 }
@@ -574,25 +601,12 @@ div.registration-form {
     padding-top:150px;
     text-align:center;
 }
-div.login-form input[type=text] {
-    
-    
 
-}
 .login-form input {
-    font-size:12pt;
     width:320px;
-    padding:8px;
-    border:1pt solid #22606D;
 }
 .login-form input[type=submit] {
-    border:0;
-    border-bottom:2px solid #540086;
-    background-color:#302562;
-    color:white;
-    width:100px;
-    border-radius:5px;
-    font-size:12pt;
+    width:108px;
 }
 
 .login-submit {
index 193a00a..44d8c75 100644 (file)
@@ -1,5 +1,7 @@
 jQuery(document).ready(function(){
 
+    jQuery('[title!=""]').qtip();
+    
     jQuery("#joinForm").validate({
         rules: {
           pi_password: {
diff --git a/portal/static/js/jquery.qtip.min.js b/portal/static/js/jquery.qtip.min.js
new file mode 100644 (file)
index 0000000..3ae7bbe
--- /dev/null
@@ -0,0 +1,4 @@
+/* qTip2 v2.2.0 tips modal viewport svg imagemap ie6 | qtip2.com | Licensed MIT, GPL | Thu Nov 21 2013 20:34:59 */
+(function(t,e,i){(function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):jQuery&&!jQuery.fn.qtip&&t(jQuery)})(function(s){"use strict";function o(t,e,i,o){this.id=i,this.target=t,this.tooltip=E,this.elements={target:t},this._id=X+"-"+i,this.timers={img:{}},this.options=e,this.plugins={},this.cache={event:{},target:s(),disabled:k,attr:o,onTooltip:k,lastClass:""},this.rendered=this.destroyed=this.disabled=this.waiting=this.hiddenDuringWait=this.positioning=this.triggering=k}function n(t){return t===E||"object"!==s.type(t)}function r(t){return!(s.isFunction(t)||t&&t.attr||t.length||"object"===s.type(t)&&(t.jquery||t.then))}function a(t){var e,i,o,a;return n(t)?k:(n(t.metadata)&&(t.metadata={type:t.metadata}),"content"in t&&(e=t.content,n(e)||e.jquery||e.done?e=t.content={text:i=r(e)?k:e}:i=e.text,"ajax"in e&&(o=e.ajax,a=o&&o.once!==k,delete e.ajax,e.text=function(t,e){var n=i||s(this).attr(e.options.content.attr)||"Loading...",r=s.ajax(s.extend({},o,{context:e})).then(o.success,E,o.error).then(function(t){return t&&a&&e.set("content.text",t),t},function(t,i,s){e.destroyed||0===t.status||e.set("content.text",i+": "+s)});return a?n:(e.set("content.text",n),r)}),"title"in e&&(n(e.title)||(e.button=e.title.button,e.title=e.title.text),r(e.title||k)&&(e.title=k))),"position"in t&&n(t.position)&&(t.position={my:t.position,at:t.position}),"show"in t&&n(t.show)&&(t.show=t.show.jquery?{target:t.show}:t.show===W?{ready:W}:{event:t.show}),"hide"in t&&n(t.hide)&&(t.hide=t.hide.jquery?{target:t.hide}:{event:t.hide}),"style"in t&&n(t.style)&&(t.style={classes:t.style}),s.each(R,function(){this.sanitize&&this.sanitize(t)}),t)}function h(t,e){for(var i,s=0,o=t,n=e.split(".");o=o[n[s++]];)n.length>s&&(i=o);return[i||t,n.pop()]}function l(t,e){var i,s,o;for(i in this.checks)for(s in this.checks[i])(o=RegExp(s,"i").exec(t))&&(e.push(o),("builtin"===i||this.plugins[i])&&this.checks[i][s].apply(this.plugins[i]||this,e))}function c(t){return G.concat("").join(t?"-"+t+" ":" ")}function d(i){return i&&{type:i.type,pageX:i.pageX,pageY:i.pageY,target:i.target,relatedTarget:i.relatedTarget,scrollX:i.scrollX||t.pageXOffset||e.body.scrollLeft||e.documentElement.scrollLeft,scrollY:i.scrollY||t.pageYOffset||e.body.scrollTop||e.documentElement.scrollTop}||{}}function p(t,e){return e>0?setTimeout(s.proxy(t,this),e):(t.call(this),i)}function u(t){return this.tooltip.hasClass(ee)?k:(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this.timers.show=p.call(this,function(){this.toggle(W,t)},this.options.show.delay),i)}function f(t){if(this.tooltip.hasClass(ee))return k;var e=s(t.relatedTarget),i=e.closest(U)[0]===this.tooltip[0],o=e[0]===this.options.show.target[0];if(clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this!==e[0]&&"mouse"===this.options.position.target&&i||this.options.hide.fixed&&/mouse(out|leave|move)/.test(t.type)&&(i||o))try{t.preventDefault(),t.stopImmediatePropagation()}catch(n){}else this.timers.hide=p.call(this,function(){this.toggle(k,t)},this.options.hide.delay,this)}function g(t){return this.tooltip.hasClass(ee)||!this.options.hide.inactive?k:(clearTimeout(this.timers.inactive),this.timers.inactive=p.call(this,function(){this.hide(t)},this.options.hide.inactive),i)}function m(t){this.rendered&&this.tooltip[0].offsetWidth>0&&this.reposition(t)}function v(t,i,o){s(e.body).delegate(t,(i.split?i:i.join(he+" "))+he,function(){var t=T.api[s.attr(this,H)];t&&!t.disabled&&o.apply(t,arguments)})}function y(t,i,n){var r,h,l,c,d,p=s(e.body),u=t[0]===e?p:t,f=t.metadata?t.metadata(n.metadata):E,g="html5"===n.metadata.type&&f?f[n.metadata.name]:E,m=t.data(n.metadata.name||"qtipopts");try{m="string"==typeof m?s.parseJSON(m):m}catch(v){}if(c=s.extend(W,{},T.defaults,n,"object"==typeof m?a(m):E,a(g||f)),h=c.position,c.id=i,"boolean"==typeof c.content.text){if(l=t.attr(c.content.attr),c.content.attr===k||!l)return k;c.content.text=l}if(h.container.length||(h.container=p),h.target===k&&(h.target=u),c.show.target===k&&(c.show.target=u),c.show.solo===W&&(c.show.solo=h.container.closest("body")),c.hide.target===k&&(c.hide.target=u),c.position.viewport===W&&(c.position.viewport=h.container),h.container=h.container.eq(0),h.at=new z(h.at,W),h.my=new z(h.my),t.data(X))if(c.overwrite)t.qtip("destroy",!0);else if(c.overwrite===k)return k;return t.attr(Y,i),c.suppress&&(d=t.attr("title"))&&t.removeAttr("title").attr(se,d).attr("title",""),r=new o(t,c,i,!!l),t.data(X,r),t.one("remove.qtip-"+i+" removeqtip.qtip-"+i,function(){var t;(t=s(this).data(X))&&t.destroy(!0)}),r}function b(t){return t.charAt(0).toUpperCase()+t.slice(1)}function w(t,e){var s,o,n=e.charAt(0).toUpperCase()+e.slice(1),r=(e+" "+be.join(n+" ")+n).split(" "),a=0;if(ye[e])return t.css(ye[e]);for(;s=r[a++];)if((o=t.css(s))!==i)return ye[e]=s,o}function _(t,e){return Math.ceil(parseFloat(w(t,e)))}function x(t,e){this._ns="tip",this.options=e,this.offset=e.offset,this.size=[e.width,e.height],this.init(this.qtip=t)}function q(t,e){this.options=e,this._ns="-modal",this.init(this.qtip=t)}function C(t){this._ns="ie6",this.init(this.qtip=t)}var T,j,z,M,I,W=!0,k=!1,E=null,S="x",L="y",A="width",B="height",D="top",F="left",O="bottom",P="right",N="center",$="flipinvert",V="shift",R={},X="qtip",Y="data-hasqtip",H="data-qtip-id",G=["ui-widget","ui-tooltip"],U="."+X,Q="click dblclick mousedown mouseup mousemove mouseleave mouseenter".split(" "),J=X+"-fixed",K=X+"-default",Z=X+"-focus",te=X+"-hover",ee=X+"-disabled",ie="_replacedByqTip",se="oldtitle",oe={ie:function(){for(var t=3,i=e.createElement("div");(i.innerHTML="<!--[if gt IE "+ ++t+"]><i></i><![endif]-->")&&i.getElementsByTagName("i")[0];);return t>4?t:0/0}(),iOS:parseFloat((""+(/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent)||[0,""])[1]).replace("undefined","3_2").replace("_",".").replace("_",""))||k};j=o.prototype,j._when=function(t){return s.when.apply(s,t)},j.render=function(t){if(this.rendered||this.destroyed)return this;var e,i=this,o=this.options,n=this.cache,r=this.elements,a=o.content.text,h=o.content.title,l=o.content.button,c=o.position,d=("."+this._id+" ",[]);return s.attr(this.target[0],"aria-describedby",this._id),this.tooltip=r.tooltip=e=s("<div/>",{id:this._id,"class":[X,K,o.style.classes,X+"-pos-"+o.position.my.abbrev()].join(" "),width:o.style.width||"",height:o.style.height||"",tracking:"mouse"===c.target&&c.adjust.mouse,role:"alert","aria-live":"polite","aria-atomic":k,"aria-describedby":this._id+"-content","aria-hidden":W}).toggleClass(ee,this.disabled).attr(H,this.id).data(X,this).appendTo(c.container).append(r.content=s("<div />",{"class":X+"-content",id:this._id+"-content","aria-atomic":W})),this.rendered=-1,this.positioning=W,h&&(this._createTitle(),s.isFunction(h)||d.push(this._updateTitle(h,k))),l&&this._createButton(),s.isFunction(a)||d.push(this._updateContent(a,k)),this.rendered=W,this._setWidget(),s.each(R,function(t){var e;"render"===this.initialize&&(e=this(i))&&(i.plugins[t]=e)}),this._unassignEvents(),this._assignEvents(),this._when(d).then(function(){i._trigger("render"),i.positioning=k,i.hiddenDuringWait||!o.show.ready&&!t||i.toggle(W,n.event,k),i.hiddenDuringWait=k}),T.api[this.id]=this,this},j.destroy=function(t){function e(){if(!this.destroyed){this.destroyed=W;var t=this.target,e=t.attr(se);this.rendered&&this.tooltip.stop(1,0).find("*").remove().end().remove(),s.each(this.plugins,function(){this.destroy&&this.destroy()}),clearTimeout(this.timers.show),clearTimeout(this.timers.hide),this._unassignEvents(),t.removeData(X).removeAttr(H).removeAttr(Y).removeAttr("aria-describedby"),this.options.suppress&&e&&t.attr("title",e).removeAttr(se),this._unbind(t),this.options=this.elements=this.cache=this.timers=this.plugins=this.mouse=E,delete T.api[this.id]}}return this.destroyed?this.target:(t===W&&"hide"!==this.triggering||!this.rendered?e.call(this):(this.tooltip.one("tooltiphidden",s.proxy(e,this)),!this.triggering&&this.hide()),this.target)},M=j.checks={builtin:{"^id$":function(t,e,i,o){var n=i===W?T.nextid:i,r=X+"-"+n;n!==k&&n.length>0&&!s("#"+r).length?(this._id=r,this.rendered&&(this.tooltip[0].id=this._id,this.elements.content[0].id=this._id+"-content",this.elements.title[0].id=this._id+"-title")):t[e]=o},"^prerender":function(t,e,i){i&&!this.rendered&&this.render(this.options.show.ready)},"^content.text$":function(t,e,i){this._updateContent(i)},"^content.attr$":function(t,e,i,s){this.options.content.text===this.target.attr(s)&&this._updateContent(this.target.attr(i))},"^content.title$":function(t,e,s){return s?(s&&!this.elements.title&&this._createTitle(),this._updateTitle(s),i):this._removeTitle()},"^content.button$":function(t,e,i){this._updateButton(i)},"^content.title.(text|button)$":function(t,e,i){this.set("content."+e,i)},"^position.(my|at)$":function(t,e,i){"string"==typeof i&&(t[e]=new z(i,"at"===e))},"^position.container$":function(t,e,i){this.rendered&&this.tooltip.appendTo(i)},"^show.ready$":function(t,e,i){i&&(!this.rendered&&this.render(W)||this.toggle(W))},"^style.classes$":function(t,e,i,s){this.rendered&&this.tooltip.removeClass(s).addClass(i)},"^style.(width|height)":function(t,e,i){this.rendered&&this.tooltip.css(e,i)},"^style.widget|content.title":function(){this.rendered&&this._setWidget()},"^style.def":function(t,e,i){this.rendered&&this.tooltip.toggleClass(K,!!i)},"^events.(render|show|move|hide|focus|blur)$":function(t,e,i){this.rendered&&this.tooltip[(s.isFunction(i)?"":"un")+"bind"]("tooltip"+e,i)},"^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)":function(){if(this.rendered){var t=this.options.position;this.tooltip.attr("tracking","mouse"===t.target&&t.adjust.mouse),this._unassignEvents(),this._assignEvents()}}}},j.get=function(t){if(this.destroyed)return this;var e=h(this.options,t.toLowerCase()),i=e[0][e[1]];return i.precedance?i.string():i};var ne=/^position\.(my|at|adjust|target|container|viewport)|style|content|show\.ready/i,re=/^prerender|show\.ready/i;j.set=function(t,e){if(this.destroyed)return this;var o,n=this.rendered,r=k,c=this.options;return this.checks,"string"==typeof t?(o=t,t={},t[o]=e):t=s.extend({},t),s.each(t,function(e,o){if(n&&re.test(e))return delete t[e],i;var a,l=h(c,e.toLowerCase());a=l[0][l[1]],l[0][l[1]]=o&&o.nodeType?s(o):o,r=ne.test(e)||r,t[e]=[l[0],l[1],o,a]}),a(c),this.positioning=W,s.each(t,s.proxy(l,this)),this.positioning=k,this.rendered&&this.tooltip[0].offsetWidth>0&&r&&this.reposition("mouse"===c.position.target?E:this.cache.event),this},j._update=function(t,e){var i=this,o=this.cache;return this.rendered&&t?(s.isFunction(t)&&(t=t.call(this.elements.target,o.event,this)||""),s.isFunction(t.then)?(o.waiting=W,t.then(function(t){return o.waiting=k,i._update(t,e)},E,function(t){return i._update(t,e)})):t===k||!t&&""!==t?k:(t.jquery&&t.length>0?e.empty().append(t.css({display:"block",visibility:"visible"})):e.html(t),this._waitForContent(e).then(function(t){t.images&&t.images.length&&i.rendered&&i.tooltip[0].offsetWidth>0&&i.reposition(o.event,!t.length)}))):k},j._waitForContent=function(t){var e=this.cache;return e.waiting=W,(s.fn.imagesLoaded?t.imagesLoaded():s.Deferred().resolve([])).done(function(){e.waiting=k}).promise()},j._updateContent=function(t,e){this._update(t,this.elements.content,e)},j._updateTitle=function(t,e){this._update(t,this.elements.title,e)===k&&this._removeTitle(k)},j._createTitle=function(){var t=this.elements,e=this._id+"-title";t.titlebar&&this._removeTitle(),t.titlebar=s("<div />",{"class":X+"-titlebar "+(this.options.style.widget?c("header"):"")}).append(t.title=s("<div />",{id:e,"class":X+"-title","aria-atomic":W})).insertBefore(t.content).delegate(".qtip-close","mousedown keydown mouseup keyup mouseout",function(t){s(this).toggleClass("ui-state-active ui-state-focus","down"===t.type.substr(-4))}).delegate(".qtip-close","mouseover mouseout",function(t){s(this).toggleClass("ui-state-hover","mouseover"===t.type)}),this.options.content.button&&this._createButton()},j._removeTitle=function(t){var e=this.elements;e.title&&(e.titlebar.remove(),e.titlebar=e.title=e.button=E,t!==k&&this.reposition())},j.reposition=function(i,o){if(!this.rendered||this.positioning||this.destroyed)return this;this.positioning=W;var n,r,a=this.cache,h=this.tooltip,l=this.options.position,c=l.target,d=l.my,p=l.at,u=l.viewport,f=l.container,g=l.adjust,m=g.method.split(" "),v=h.outerWidth(k),y=h.outerHeight(k),b=0,w=0,_=h.css("position"),x={left:0,top:0},q=h[0].offsetWidth>0,C=i&&"scroll"===i.type,T=s(t),j=f[0].ownerDocument,z=this.mouse;if(s.isArray(c)&&2===c.length)p={x:F,y:D},x={left:c[0],top:c[1]};else if("mouse"===c)p={x:F,y:D},!z||!z.pageX||!g.mouse&&i&&i.pageX?i&&i.pageX||((!g.mouse||this.options.show.distance)&&a.origin&&a.origin.pageX?i=a.origin:(!i||i&&("resize"===i.type||"scroll"===i.type))&&(i=a.event)):i=z,"static"!==_&&(x=f.offset()),j.body.offsetWidth!==(t.innerWidth||j.documentElement.clientWidth)&&(r=s(e.body).offset()),x={left:i.pageX-x.left+(r&&r.left||0),top:i.pageY-x.top+(r&&r.top||0)},g.mouse&&C&&z&&(x.left-=(z.scrollX||0)-T.scrollLeft(),x.top-=(z.scrollY||0)-T.scrollTop());else{if("event"===c?i&&i.target&&"scroll"!==i.type&&"resize"!==i.type?a.target=s(i.target):i.target||(a.target=this.elements.target):"event"!==c&&(a.target=s(c.jquery?c:this.elements.target)),c=a.target,c=s(c).eq(0),0===c.length)return this;c[0]===e||c[0]===t?(b=oe.iOS?t.innerWidth:c.width(),w=oe.iOS?t.innerHeight:c.height(),c[0]===t&&(x={top:(u||c).scrollTop(),left:(u||c).scrollLeft()})):R.imagemap&&c.is("area")?n=R.imagemap(this,c,p,R.viewport?m:k):R.svg&&c&&c[0].ownerSVGElement?n=R.svg(this,c,p,R.viewport?m:k):(b=c.outerWidth(k),w=c.outerHeight(k),x=c.offset()),n&&(b=n.width,w=n.height,r=n.offset,x=n.position),x=this.reposition.offset(c,x,f),(oe.iOS>3.1&&4.1>oe.iOS||oe.iOS>=4.3&&4.33>oe.iOS||!oe.iOS&&"fixed"===_)&&(x.left-=T.scrollLeft(),x.top-=T.scrollTop()),(!n||n&&n.adjustable!==k)&&(x.left+=p.x===P?b:p.x===N?b/2:0,x.top+=p.y===O?w:p.y===N?w/2:0)}return x.left+=g.x+(d.x===P?-v:d.x===N?-v/2:0),x.top+=g.y+(d.y===O?-y:d.y===N?-y/2:0),R.viewport?(x.adjusted=R.viewport(this,x,l,b,w,v,y),r&&x.adjusted.left&&(x.left+=r.left),r&&x.adjusted.top&&(x.top+=r.top)):x.adjusted={left:0,top:0},this._trigger("move",[x,u.elem||u],i)?(delete x.adjusted,o===k||!q||isNaN(x.left)||isNaN(x.top)||"mouse"===c||!s.isFunction(l.effect)?h.css(x):s.isFunction(l.effect)&&(l.effect.call(h,this,s.extend({},x)),h.queue(function(t){s(this).css({opacity:"",height:""}),oe.ie&&this.style.removeAttribute("filter"),t()})),this.positioning=k,this):this},j.reposition.offset=function(t,i,o){function n(t,e){i.left+=e*t.scrollLeft(),i.top+=e*t.scrollTop()}if(!o[0])return i;var r,a,h,l,c=s(t[0].ownerDocument),d=!!oe.ie&&"CSS1Compat"!==e.compatMode,p=o[0];do"static"!==(a=s.css(p,"position"))&&("fixed"===a?(h=p.getBoundingClientRect(),n(c,-1)):(h=s(p).position(),h.left+=parseFloat(s.css(p,"borderLeftWidth"))||0,h.top+=parseFloat(s.css(p,"borderTopWidth"))||0),i.left-=h.left+(parseFloat(s.css(p,"marginLeft"))||0),i.top-=h.top+(parseFloat(s.css(p,"marginTop"))||0),r||"hidden"===(l=s.css(p,"overflow"))||"visible"===l||(r=s(p)));while(p=p.offsetParent);return r&&(r[0]!==c[0]||d)&&n(r,1),i};var ae=(z=j.reposition.Corner=function(t,e){t=(""+t).replace(/([A-Z])/," $1").replace(/middle/gi,N).toLowerCase(),this.x=(t.match(/left|right/i)||t.match(/center/)||["inherit"])[0].toLowerCase(),this.y=(t.match(/top|bottom|center/i)||["inherit"])[0].toLowerCase(),this.forceY=!!e;var i=t.charAt(0);this.precedance="t"===i||"b"===i?L:S}).prototype;ae.invert=function(t,e){this[t]=this[t]===F?P:this[t]===P?F:e||this[t]},ae.string=function(){var t=this.x,e=this.y;return t===e?t:this.precedance===L||this.forceY&&"center"!==e?e+" "+t:t+" "+e},ae.abbrev=function(){var t=this.string().split(" ");return t[0].charAt(0)+(t[1]&&t[1].charAt(0)||"")},ae.clone=function(){return new z(this.string(),this.forceY)},j.toggle=function(t,i){var o=this.cache,n=this.options,r=this.tooltip;if(i){if(/over|enter/.test(i.type)&&/out|leave/.test(o.event.type)&&n.show.target.add(i.target).length===n.show.target.length&&r.has(i.relatedTarget).length)return this;o.event=d(i)}if(this.waiting&&!t&&(this.hiddenDuringWait=W),!this.rendered)return t?this.render(1):this;if(this.destroyed||this.disabled)return this;var a,h,l,c=t?"show":"hide",p=this.options[c],u=(this.options[t?"hide":"show"],this.options.position),f=this.options.content,g=this.tooltip.css("width"),m=this.tooltip.is(":visible"),v=t||1===p.target.length,y=!i||2>p.target.length||o.target[0]===i.target;return(typeof t).search("boolean|number")&&(t=!m),a=!r.is(":animated")&&m===t&&y,h=a?E:!!this._trigger(c,[90]),this.destroyed?this:(h!==k&&t&&this.focus(i),!h||a?this:(s.attr(r[0],"aria-hidden",!t),t?(o.origin=d(this.mouse),s.isFunction(f.text)&&this._updateContent(f.text,k),s.isFunction(f.title)&&this._updateTitle(f.title,k),!I&&"mouse"===u.target&&u.adjust.mouse&&(s(e).bind("mousemove."+X,this._storeMouse),I=W),g||r.css("width",r.outerWidth(k)),this.reposition(i,arguments[2]),g||r.css("width",""),p.solo&&("string"==typeof p.solo?s(p.solo):s(U,p.solo)).not(r).not(p.target).qtip("hide",s.Event("tooltipsolo"))):(clearTimeout(this.timers.show),delete o.origin,I&&!s(U+'[tracking="true"]:visible',p.solo).not(r).length&&(s(e).unbind("mousemove."+X),I=k),this.blur(i)),l=s.proxy(function(){t?(oe.ie&&r[0].style.removeAttribute("filter"),r.css("overflow",""),"string"==typeof p.autofocus&&s(this.options.show.autofocus,r).focus(),this.options.show.target.trigger("qtip-"+this.id+"-inactive")):r.css({display:"",visibility:"",opacity:"",left:"",top:""}),this._trigger(t?"visible":"hidden")},this),p.effect===k||v===k?(r[c](),l()):s.isFunction(p.effect)?(r.stop(1,1),p.effect.call(r,this),r.queue("fx",function(t){l(),t()})):r.fadeTo(90,t?1:0,l),t&&p.target.trigger("qtip-"+this.id+"-inactive"),this))},j.show=function(t){return this.toggle(W,t)},j.hide=function(t){return this.toggle(k,t)},j.focus=function(t){if(!this.rendered||this.destroyed)return this;var e=s(U),i=this.tooltip,o=parseInt(i[0].style.zIndex,10),n=T.zindex+e.length;return i.hasClass(Z)||this._trigger("focus",[n],t)&&(o!==n&&(e.each(function(){this.style.zIndex>o&&(this.style.zIndex=this.style.zIndex-1)}),e.filter("."+Z).qtip("blur",t)),i.addClass(Z)[0].style.zIndex=n),this},j.blur=function(t){return!this.rendered||this.destroyed?this:(this.tooltip.removeClass(Z),this._trigger("blur",[this.tooltip.css("zIndex")],t),this)},j.disable=function(t){return this.destroyed?this:("toggle"===t?t=!(this.rendered?this.tooltip.hasClass(ee):this.disabled):"boolean"!=typeof t&&(t=W),this.rendered&&this.tooltip.toggleClass(ee,t).attr("aria-disabled",t),this.disabled=!!t,this)},j.enable=function(){return this.disable(k)},j._createButton=function(){var t=this,e=this.elements,i=e.tooltip,o=this.options.content.button,n="string"==typeof o,r=n?o:"Close tooltip";e.button&&e.button.remove(),e.button=o.jquery?o:s("<a />",{"class":"qtip-close "+(this.options.style.widget?"":X+"-icon"),title:r,"aria-label":r}).prepend(s("<span />",{"class":"ui-icon ui-icon-close",html:"&times;"})),e.button.appendTo(e.titlebar||i).attr("role","button").click(function(e){return i.hasClass(ee)||t.hide(e),k})},j._updateButton=function(t){if(!this.rendered)return k;var e=this.elements.button;t?this._createButton():e.remove()},j._setWidget=function(){var t=this.options.style.widget,e=this.elements,i=e.tooltip,s=i.hasClass(ee);i.removeClass(ee),ee=t?"ui-state-disabled":"qtip-disabled",i.toggleClass(ee,s),i.toggleClass("ui-helper-reset "+c(),t).toggleClass(K,this.options.style.def&&!t),e.content&&e.content.toggleClass(c("content"),t),e.titlebar&&e.titlebar.toggleClass(c("header"),t),e.button&&e.button.toggleClass(X+"-icon",!t)},j._storeMouse=function(t){(this.mouse=d(t)).type="mousemove"},j._bind=function(t,e,i,o,n){var r="."+this._id+(o?"-"+o:"");e.length&&s(t).bind((e.split?e:e.join(r+" "))+r,s.proxy(i,n||this))},j._unbind=function(t,e){s(t).unbind("."+this._id+(e?"-"+e:""))};var he="."+X;s(function(){v(U,["mouseenter","mouseleave"],function(t){var e="mouseenter"===t.type,i=s(t.currentTarget),o=s(t.relatedTarget||t.target),n=this.options;e?(this.focus(t),i.hasClass(J)&&!i.hasClass(ee)&&clearTimeout(this.timers.hide)):"mouse"===n.position.target&&n.hide.event&&n.show.target&&!o.closest(n.show.target[0]).length&&this.hide(t),i.toggleClass(te,e)}),v("["+H+"]",Q,g)}),j._trigger=function(t,e,i){var o=s.Event("tooltip"+t);return o.originalEvent=i&&s.extend({},i)||this.cache.event||E,this.triggering=t,this.tooltip.trigger(o,[this].concat(e||[])),this.triggering=k,!o.isDefaultPrevented()},j._bindEvents=function(t,e,o,n,r,a){if(n.add(o).length===n.length){var h=[];e=s.map(e,function(e){var o=s.inArray(e,t);return o>-1?(h.push(t.splice(o,1)[0]),i):e}),h.length&&this._bind(o,h,function(t){var e=this.rendered?this.tooltip[0].offsetWidth>0:!1;(e?a:r).call(this,t)})}this._bind(o,t,r),this._bind(n,e,a)},j._assignInitialEvents=function(t){function e(t){return this.disabled||this.destroyed?k:(this.cache.event=d(t),this.cache.target=t?s(t.target):[i],clearTimeout(this.timers.show),this.timers.show=p.call(this,function(){this.render("object"==typeof t||o.show.ready)},o.show.delay),i)}var o=this.options,n=o.show.target,r=o.hide.target,a=o.show.event?s.trim(""+o.show.event).split(" "):[],h=o.hide.event?s.trim(""+o.hide.event).split(" "):[];/mouse(over|enter)/i.test(o.show.event)&&!/mouse(out|leave)/i.test(o.hide.event)&&h.push("mouseleave"),this._bind(n,"mousemove",function(t){this._storeMouse(t),this.cache.onTarget=W}),this._bindEvents(a,h,n,r,e,function(){clearTimeout(this.timers.show)}),(o.show.ready||o.prerender)&&e.call(this,t)},j._assignEvents=function(){var i=this,o=this.options,n=o.position,r=this.tooltip,a=o.show.target,h=o.hide.target,l=n.container,c=n.viewport,d=s(e),p=(s(e.body),s(t)),v=o.show.event?s.trim(""+o.show.event).split(" "):[],y=o.hide.event?s.trim(""+o.hide.event).split(" "):[];s.each(o.events,function(t,e){i._bind(r,"toggle"===t?["tooltipshow","tooltiphide"]:["tooltip"+t],e,null,r)}),/mouse(out|leave)/i.test(o.hide.event)&&"window"===o.hide.leave&&this._bind(d,["mouseout","blur"],function(t){/select|option/.test(t.target.nodeName)||t.relatedTarget||this.hide(t)}),o.hide.fixed?h=h.add(r.addClass(J)):/mouse(over|enter)/i.test(o.show.event)&&this._bind(h,"mouseleave",function(){clearTimeout(this.timers.show)}),(""+o.hide.event).indexOf("unfocus")>-1&&this._bind(l.closest("html"),["mousedown","touchstart"],function(t){var e=s(t.target),i=this.rendered&&!this.tooltip.hasClass(ee)&&this.tooltip[0].offsetWidth>0,o=e.parents(U).filter(this.tooltip[0]).length>0;e[0]===this.target[0]||e[0]===this.tooltip[0]||o||this.target.has(e[0]).length||!i||this.hide(t)}),"number"==typeof o.hide.inactive&&(this._bind(a,"qtip-"+this.id+"-inactive",g),this._bind(h.add(r),T.inactiveEvents,g,"-inactive")),this._bindEvents(v,y,a,h,u,f),this._bind(a.add(r),"mousemove",function(t){if("number"==typeof o.hide.distance){var e=this.cache.origin||{},i=this.options.hide.distance,s=Math.abs;(s(t.pageX-e.pageX)>=i||s(t.pageY-e.pageY)>=i)&&this.hide(t)}this._storeMouse(t)}),"mouse"===n.target&&n.adjust.mouse&&(o.hide.event&&this._bind(a,["mouseenter","mouseleave"],function(t){this.cache.onTarget="mouseenter"===t.type}),this._bind(d,"mousemove",function(t){this.rendered&&this.cache.onTarget&&!this.tooltip.hasClass(ee)&&this.tooltip[0].offsetWidth>0&&this.reposition(t)})),(n.adjust.resize||c.length)&&this._bind(s.event.special.resize?c:p,"resize",m),n.adjust.scroll&&this._bind(p.add(n.container),"scroll",m)},j._unassignEvents=function(){var i=[this.options.show.target[0],this.options.hide.target[0],this.rendered&&this.tooltip[0],this.options.position.container[0],this.options.position.viewport[0],this.options.position.container.closest("html")[0],t,e];this._unbind(s([]).pushStack(s.grep(i,function(t){return"object"==typeof t})))},T=s.fn.qtip=function(t,e,o){var n=(""+t).toLowerCase(),r=E,h=s.makeArray(arguments).slice(1),l=h[h.length-1],c=this[0]?s.data(this[0],X):E;return!arguments.length&&c||"api"===n?c:"string"==typeof t?(this.each(function(){var t=s.data(this,X);if(!t)return W;if(l&&l.timeStamp&&(t.cache.event=l),!e||"option"!==n&&"options"!==n)t[n]&&t[n].apply(t,h);else{if(o===i&&!s.isPlainObject(e))return r=t.get(e),k;t.set(e,o)}}),r!==E?r:this):"object"!=typeof t&&arguments.length?i:(c=a(s.extend(W,{},t)),this.each(function(t){var e,o;return o=s.isArray(c.id)?c.id[t]:c.id,o=!o||o===k||1>o.length||T.api[o]?T.nextid++:o,e=y(s(this),o,c),e===k?W:(T.api[o]=e,s.each(R,function(){"initialize"===this.initialize&&this(e)}),e._assignInitialEvents(l),i)}))},s.qtip=o,T.api={},s.each({attr:function(t,e){if(this.length){var i=this[0],o="title",n=s.data(i,"qtip");if(t===o&&n&&"object"==typeof n&&n.options.suppress)return 2>arguments.length?s.attr(i,se):(n&&n.options.content.attr===o&&n.cache.attr&&n.set("content.text",e),this.attr(se,e))}return s.fn["attr"+ie].apply(this,arguments)},clone:function(t){var e=(s([]),s.fn["clone"+ie].apply(this,arguments));return t||e.filter("["+se+"]").attr("title",function(){return s.attr(this,se)}).removeAttr(se),e}},function(t,e){if(!e||s.fn[t+ie])return W;var i=s.fn[t+ie]=s.fn[t];s.fn[t]=function(){return e.apply(this,arguments)||i.apply(this,arguments)}}),s.ui||(s["cleanData"+ie]=s.cleanData,s.cleanData=function(t){for(var e,i=0;(e=s(t[i])).length;i++)if(e.attr(Y))try{e.triggerHandler("removeqtip")}catch(o){}s["cleanData"+ie].apply(this,arguments)}),T.version="2.2.0",T.nextid=0,T.inactiveEvents=Q,T.zindex=15e3,T.defaults={prerender:k,id:k,overwrite:W,suppress:W,content:{text:W,attr:"title",title:k,button:k},position:{my:"top left",at:"bottom right",target:k,container:k,viewport:k,adjust:{x:0,y:0,mouse:W,scroll:W,resize:W,method:"flipinvert flipinvert"},effect:function(t,e){s(this).animate(e,{duration:200,queue:k})}},show:{target:k,event:"mouseenter",effect:W,delay:90,solo:k,ready:k,autofocus:k},hide:{target:k,event:"mouseleave",effect:W,delay:0,fixed:k,inactive:k,leave:"window",distance:k},style:{classes:"",widget:k,width:k,height:k,def:W},events:{render:E,move:E,show:E,hide:E,toggle:E,visible:E,hidden:E,focus:E,blur:E}};var le,ce="margin",de="border",pe="color",ue="background-color",fe="transparent",ge=" !important",me=!!e.createElement("canvas").getContext,ve=/rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i,ye={},be=["Webkit","O","Moz","ms"];if(me)var we=t.devicePixelRatio||1,_e=function(){var t=e.createElement("canvas").getContext("2d");return t.backingStorePixelRatio||t.webkitBackingStorePixelRatio||t.mozBackingStorePixelRatio||t.msBackingStorePixelRatio||t.oBackingStorePixelRatio||1}(),xe=we/_e;else var qe=function(t,e,i){return"<qtipvml:"+t+' xmlns="urn:schemas-microsoft.com:vml" class="qtip-vml" '+(e||"")+' style="behavior: url(#default#VML); '+(i||"")+'" />'};s.extend(x.prototype,{init:function(t){var e,i;i=this.element=t.elements.tip=s("<div />",{"class":X+"-tip"}).prependTo(t.tooltip),me?(e=s("<canvas />").appendTo(this.element)[0].getContext("2d"),e.lineJoin="miter",e.miterLimit=1e5,e.save()):(e=qe("shape",'coordorigin="0,0"',"position:absolute;"),this.element.html(e+e),t._bind(s("*",i).add(i),["click","mousedown"],function(t){t.stopPropagation()},this._ns)),t._bind(t.tooltip,"tooltipmove",this.reposition,this._ns,this),this.create()},_swapDimensions:function(){this.size[0]=this.options.height,this.size[1]=this.options.width},_resetDimensions:function(){this.size[0]=this.options.width,this.size[1]=this.options.height},_useTitle:function(t){var e=this.qtip.elements.titlebar;return e&&(t.y===D||t.y===N&&this.element.position().top+this.size[1]/2+this.options.offset<e.outerHeight(W))},_parseCorner:function(t){var e=this.qtip.options.position.my;return t===k||e===k?t=k:t===W?t=new z(e.string()):t.string||(t=new z(t),t.fixed=W),t},_parseWidth:function(t,e,i){var s=this.qtip.elements,o=de+b(e)+"Width";return(i?_(i,o):_(s.content,o)||_(this._useTitle(t)&&s.titlebar||s.content,o)||_(s.tooltip,o))||0},_parseRadius:function(t){var e=this.qtip.elements,i=de+b(t.y)+b(t.x)+"Radius";return 9>oe.ie?0:_(this._useTitle(t)&&e.titlebar||e.content,i)||_(e.tooltip,i)||0},_invalidColour:function(t,e,i){var s=t.css(e);return!s||i&&s===t.css(i)||ve.test(s)?k:s},_parseColours:function(t){var e=this.qtip.elements,i=this.element.css("cssText",""),o=de+b(t[t.precedance])+b(pe),n=this._useTitle(t)&&e.titlebar||e.content,r=this._invalidColour,a=[];return a[0]=r(i,ue)||r(n,ue)||r(e.content,ue)||r(e.tooltip,ue)||i.css(ue),a[1]=r(i,o,pe)||r(n,o,pe)||r(e.content,o,pe)||r(e.tooltip,o,pe)||e.tooltip.css(o),s("*",i).add(i).css("cssText",ue+":"+fe+ge+";"+de+":0"+ge+";"),a},_calculateSize:function(t){var e,i,s,o=t.precedance===L,n=this.options.width,r=this.options.height,a="c"===t.abbrev(),h=(o?n:r)*(a?.5:1),l=Math.pow,c=Math.round,d=Math.sqrt(l(h,2)+l(r,2)),p=[this.border/h*d,this.border/r*d];return p[2]=Math.sqrt(l(p[0],2)-l(this.border,2)),p[3]=Math.sqrt(l(p[1],2)-l(this.border,2)),e=d+p[2]+p[3]+(a?0:p[0]),i=e/d,s=[c(i*n),c(i*r)],o?s:s.reverse()},_calculateTip:function(t,e,i){i=i||1,e=e||this.size;var s=e[0]*i,o=e[1]*i,n=Math.ceil(s/2),r=Math.ceil(o/2),a={br:[0,0,s,o,s,0],bl:[0,0,s,0,0,o],tr:[0,o,s,0,s,o],tl:[0,0,0,o,s,o],tc:[0,o,n,0,s,o],bc:[0,0,s,0,n,o],rc:[0,0,s,r,0,o],lc:[s,0,s,o,0,r]};return a.lt=a.br,a.rt=a.bl,a.lb=a.tr,a.rb=a.tl,a[t.abbrev()]},_drawCoords:function(t,e){t.beginPath(),t.moveTo(e[0],e[1]),t.lineTo(e[2],e[3]),t.lineTo(e[4],e[5]),t.closePath()},create:function(){var t=this.corner=(me||oe.ie)&&this._parseCorner(this.options.corner);return(this.enabled=!!this.corner&&"c"!==this.corner.abbrev())&&(this.qtip.cache.corner=t.clone(),this.update()),this.element.toggle(this.enabled),this.corner},update:function(e,i){if(!this.enabled)return this;var o,n,r,a,h,l,c,d,p=this.qtip.elements,u=this.element,f=u.children(),g=this.options,m=this.size,v=g.mimic,y=Math.round;e||(e=this.qtip.cache.corner||this.corner),v===k?v=e:(v=new z(v),v.precedance=e.precedance,"inherit"===v.x?v.x=e.x:"inherit"===v.y?v.y=e.y:v.x===v.y&&(v[e.precedance]=e[e.precedance])),n=v.precedance,e.precedance===S?this._swapDimensions():this._resetDimensions(),o=this.color=this._parseColours(e),o[1]!==fe?(d=this.border=this._parseWidth(e,e[e.precedance]),g.border&&1>d&&!ve.test(o[1])&&(o[0]=o[1]),this.border=d=g.border!==W?g.border:d):this.border=d=0,c=this.size=this._calculateSize(e),u.css({width:c[0],height:c[1],lineHeight:c[1]+"px"}),l=e.precedance===L?[y(v.x===F?d:v.x===P?c[0]-m[0]-d:(c[0]-m[0])/2),y(v.y===D?c[1]-m[1]:0)]:[y(v.x===F?c[0]-m[0]:0),y(v.y===D?d:v.y===O?c[1]-m[1]-d:(c[1]-m[1])/2)],me?(r=f[0].getContext("2d"),r.restore(),r.save(),r.clearRect(0,0,6e3,6e3),a=this._calculateTip(v,m,xe),h=this._calculateTip(v,this.size,xe),f.attr(A,c[0]*xe).attr(B,c[1]*xe),f.css(A,c[0]).css(B,c[1]),this._drawCoords(r,h),r.fillStyle=o[1],r.fill(),r.translate(l[0]*xe,l[1]*xe),this._drawCoords(r,a),r.fillStyle=o[0],r.fill()):(a=this._calculateTip(v),a="m"+a[0]+","+a[1]+" l"+a[2]+","+a[3]+" "+a[4]+","+a[5]+" xe",l[2]=d&&/^(r|b)/i.test(e.string())?8===oe.ie?2:1:0,f.css({coordsize:c[0]+d+" "+(c[1]+d),antialias:""+(v.string().indexOf(N)>-1),left:l[0]-l[2]*Number(n===S),top:l[1]-l[2]*Number(n===L),width:c[0]+d,height:c[1]+d}).each(function(t){var e=s(this);e[e.prop?"prop":"attr"]({coordsize:c[0]+d+" "+(c[1]+d),path:a,fillcolor:o[0],filled:!!t,stroked:!t}).toggle(!(!d&&!t)),!t&&e.html(qe("stroke",'weight="'+2*d+'px" color="'+o[1]+'" miterlimit="1000" joinstyle="miter"'))})),t.opera&&setTimeout(function(){p.tip.css({display:"inline-block",visibility:"visible"})},1),i!==k&&this.calculate(e,c)},calculate:function(t,e){if(!this.enabled)return k;var i,o,n=this,r=this.qtip.elements,a=this.element,h=this.options.offset,l=(r.tooltip.hasClass("ui-widget"),{});return t=t||this.corner,i=t.precedance,e=e||this._calculateSize(t),o=[t.x,t.y],i===S&&o.reverse(),s.each(o,function(s,o){var a,c,d;o===N?(a=i===L?F:D,l[a]="50%",l[ce+"-"+a]=-Math.round(e[i===L?0:1]/2)+h):(a=n._parseWidth(t,o,r.tooltip),c=n._parseWidth(t,o,r.content),d=n._parseRadius(t),l[o]=Math.max(-n.border,s?c:h+(d>a?d:-a)))
+}),l[t[i]]-=e[i===S?0:1],a.css({margin:"",top:"",bottom:"",left:"",right:""}).css(l),l},reposition:function(t,e,s){function o(t,e,i,s,o){t===V&&l.precedance===e&&c[s]&&l[i]!==N?l.precedance=l.precedance===S?L:S:t!==V&&c[s]&&(l[e]=l[e]===N?c[s]>0?s:o:l[e]===s?o:s)}function n(t,e,o){l[t]===N?g[ce+"-"+e]=f[t]=r[ce+"-"+e]-c[e]:(a=r[o]!==i?[c[e],-r[e]]:[-c[e],r[e]],(f[t]=Math.max(a[0],a[1]))>a[0]&&(s[e]-=c[e],f[e]=k),g[r[o]!==i?o:e]=f[t])}if(this.enabled){var r,a,h=e.cache,l=this.corner.clone(),c=s.adjusted,d=e.options.position.adjust.method.split(" "),p=d[0],u=d[1]||d[0],f={left:k,top:k,x:0,y:0},g={};this.corner.fixed!==W&&(o(p,S,L,F,P),o(u,L,S,D,O),l.string()===h.corner.string()||h.cornerTop===c.top&&h.cornerLeft===c.left||this.update(l,k)),r=this.calculate(l),r.right!==i&&(r.left=-r.right),r.bottom!==i&&(r.top=-r.bottom),r.user=this.offset,(f.left=p===V&&!!c.left)&&n(S,F,P),(f.top=u===V&&!!c.top)&&n(L,D,O),this.element.css(g).toggle(!(f.x&&f.y||l.x===N&&f.y||l.y===N&&f.x)),s.left-=r.left.charAt?r.user:p!==V||f.top||!f.left&&!f.top?r.left+this.border:0,s.top-=r.top.charAt?r.user:u!==V||f.left||!f.left&&!f.top?r.top+this.border:0,h.cornerLeft=c.left,h.cornerTop=c.top,h.corner=l.clone()}},destroy:function(){this.qtip._unbind(this.qtip.tooltip,this._ns),this.qtip.elements.tip&&this.qtip.elements.tip.find("*").remove().end().remove()}}),le=R.tip=function(t){return new x(t,t.options.style.tip)},le.initialize="render",le.sanitize=function(t){if(t.style&&"tip"in t.style){var e=t.style.tip;"object"!=typeof e&&(e=t.style.tip={corner:e}),/string|boolean/i.test(typeof e.corner)||(e.corner=W)}},M.tip={"^position.my|style.tip.(corner|mimic|border)$":function(){this.create(),this.qtip.reposition()},"^style.tip.(height|width)$":function(t){this.size=[t.width,t.height],this.update(),this.qtip.reposition()},"^content.title|style.(classes|widget)$":function(){this.update()}},s.extend(W,T.defaults,{style:{tip:{corner:W,mimic:k,width:6,height:6,border:W,offset:0}}});var Ce,Te,je="qtip-modal",ze="."+je;Te=function(){function t(t){if(s.expr[":"].focusable)return s.expr[":"].focusable;var e,i,o,n=!isNaN(s.attr(t,"tabindex")),r=t.nodeName&&t.nodeName.toLowerCase();return"area"===r?(e=t.parentNode,i=e.name,t.href&&i&&"map"===e.nodeName.toLowerCase()?(o=s("img[usemap=#"+i+"]")[0],!!o&&o.is(":visible")):!1):/input|select|textarea|button|object/.test(r)?!t.disabled:"a"===r?t.href||n:n}function i(t){1>c.length&&t.length?t.not("body").blur():c.first().focus()}function o(t){if(h.is(":visible")){var e,o=s(t.target),a=n.tooltip,l=o.closest(U);e=1>l.length?k:parseInt(l[0].style.zIndex,10)>parseInt(a[0].style.zIndex,10),e||o.closest(U)[0]===a[0]||i(o),r=t.target===c[c.length-1]}}var n,r,a,h,l=this,c={};s.extend(l,{init:function(){return h=l.elem=s("<div />",{id:"qtip-overlay",html:"<div></div>",mousedown:function(){return k}}).hide(),s(e.body).bind("focusin"+ze,o),s(e).bind("keydown"+ze,function(t){n&&n.options.show.modal.escape&&27===t.keyCode&&n.hide(t)}),h.bind("click"+ze,function(t){n&&n.options.show.modal.blur&&n.hide(t)}),l},update:function(e){n=e,c=e.options.show.modal.stealfocus!==k?e.tooltip.find("*").filter(function(){return t(this)}):[]},toggle:function(t,o,r){var c=(s(e.body),t.tooltip),d=t.options.show.modal,p=d.effect,u=o?"show":"hide",f=h.is(":visible"),g=s(ze).filter(":visible:not(:animated)").not(c);return l.update(t),o&&d.stealfocus!==k&&i(s(":focus")),h.toggleClass("blurs",d.blur),o&&h.appendTo(e.body),h.is(":animated")&&f===o&&a!==k||!o&&g.length?l:(h.stop(W,k),s.isFunction(p)?p.call(h,o):p===k?h[u]():h.fadeTo(parseInt(r,10)||90,o?1:0,function(){o||h.hide()}),o||h.queue(function(t){h.css({left:"",top:""}),s(ze).length||h.detach(),t()}),a=o,n.destroyed&&(n=E),l)}}),l.init()},Te=new Te,s.extend(q.prototype,{init:function(t){var e=t.tooltip;return this.options.on?(t.elements.overlay=Te.elem,e.addClass(je).css("z-index",T.modal_zindex+s(ze).length),t._bind(e,["tooltipshow","tooltiphide"],function(t,i,o){var n=t.originalEvent;if(t.target===e[0])if(n&&"tooltiphide"===t.type&&/mouse(leave|enter)/.test(n.type)&&s(n.relatedTarget).closest(Te.elem[0]).length)try{t.preventDefault()}catch(r){}else(!n||n&&"tooltipsolo"!==n.type)&&this.toggle(t,"tooltipshow"===t.type,o)},this._ns,this),t._bind(e,"tooltipfocus",function(t,i){if(!t.isDefaultPrevented()&&t.target===e[0]){var o=s(ze),n=T.modal_zindex+o.length,r=parseInt(e[0].style.zIndex,10);Te.elem[0].style.zIndex=n-1,o.each(function(){this.style.zIndex>r&&(this.style.zIndex-=1)}),o.filter("."+Z).qtip("blur",t.originalEvent),e.addClass(Z)[0].style.zIndex=n,Te.update(i);try{t.preventDefault()}catch(a){}}},this._ns,this),t._bind(e,"tooltiphide",function(t){t.target===e[0]&&s(ze).filter(":visible").not(e).last().qtip("focus",t)},this._ns,this),i):this},toggle:function(t,e,s){return t&&t.isDefaultPrevented()?this:(Te.toggle(this.qtip,!!e,s),i)},destroy:function(){this.qtip.tooltip.removeClass(je),this.qtip._unbind(this.qtip.tooltip,this._ns),Te.toggle(this.qtip,k),delete this.qtip.elements.overlay}}),Ce=R.modal=function(t){return new q(t,t.options.show.modal)},Ce.sanitize=function(t){t.show&&("object"!=typeof t.show.modal?t.show.modal={on:!!t.show.modal}:t.show.modal.on===i&&(t.show.modal.on=W))},T.modal_zindex=T.zindex-200,Ce.initialize="render",M.modal={"^show.modal.(on|blur)$":function(){this.destroy(),this.init(),this.qtip.elems.overlay.toggle(this.qtip.tooltip[0].offsetWidth>0)}},s.extend(W,T.defaults,{show:{modal:{on:k,effect:W,blur:W,stealfocus:W,escape:W}}}),R.viewport=function(i,s,o,n,r,a,h){function l(t,e,i,o,n,r,a,h,l){var c=s[n],p=_[t],b=x[t],w=i===V,q=p===n?l:p===r?-l:-l/2,C=b===n?h:b===r?-h:-h/2,T=v[n]+y[n]-(f?0:u[n]),j=T-c,z=c+l-(a===A?g:m)-T,M=q-(_.precedance===t||p===_[e]?C:0)-(b===N?h/2:0);return w?(M=(p===n?1:-1)*q,s[n]+=j>0?j:z>0?-z:0,s[n]=Math.max(-u[n]+y[n],c-M,Math.min(Math.max(-u[n]+y[n]+(a===A?g:m),c+M),s[n],"center"===p?c-q:1e9))):(o*=i===$?2:0,j>0&&(p!==n||z>0)?(s[n]-=M+o,d.invert(t,n)):z>0&&(p!==r||j>0)&&(s[n]-=(p===N?-M:M)+o,d.invert(t,r)),v>s[n]&&-s[n]>z&&(s[n]=c,d=_.clone())),s[n]-c}var c,d,p,u,f,g,m,v,y,b=o.target,w=i.elements.tooltip,_=o.my,x=o.at,q=o.adjust,C=q.method.split(" "),T=C[0],j=C[1]||C[0],z=o.viewport,M=o.container,I=i.cache,W={left:0,top:0};return z.jquery&&b[0]!==t&&b[0]!==e.body&&"none"!==q.method?(u=M.offset()||W,f="static"===M.css("position"),c="fixed"===w.css("position"),g=z[0]===t?z.width():z.outerWidth(k),m=z[0]===t?z.height():z.outerHeight(k),v={left:c?0:z.scrollLeft(),top:c?0:z.scrollTop()},y=z.offset()||W,("shift"!==T||"shift"!==j)&&(d=_.clone()),W={left:"none"!==T?l(S,L,T,q.x,F,P,A,n,a):0,top:"none"!==j?l(L,S,j,q.y,D,O,B,r,h):0},d&&I.lastClass!==(p=X+"-pos-"+d.abbrev())&&w.removeClass(i.cache.lastClass).addClass(i.cache.lastClass=p),W):W},R.polys={polygon:function(t,e){var i,s,o,n={width:0,height:0,position:{top:1e10,right:0,bottom:0,left:1e10},adjustable:k},r=0,a=[],h=1,l=1,c=0,d=0;for(r=t.length;r--;)i=[parseInt(t[--r],10),parseInt(t[r+1],10)],i[0]>n.position.right&&(n.position.right=i[0]),i[0]<n.position.left&&(n.position.left=i[0]),i[1]>n.position.bottom&&(n.position.bottom=i[1]),i[1]<n.position.top&&(n.position.top=i[1]),a.push(i);if(s=n.width=Math.abs(n.position.right-n.position.left),o=n.height=Math.abs(n.position.bottom-n.position.top),"c"===e.abbrev())n.position={left:n.position.left+n.width/2,top:n.position.top+n.height/2};else{for(;s>0&&o>0&&h>0&&l>0;)for(s=Math.floor(s/2),o=Math.floor(o/2),e.x===F?h=s:e.x===P?h=n.width-s:h+=Math.floor(s/2),e.y===D?l=o:e.y===O?l=n.height-o:l+=Math.floor(o/2),r=a.length;r--&&!(2>a.length);)c=a[r][0]-n.position.left,d=a[r][1]-n.position.top,(e.x===F&&c>=h||e.x===P&&h>=c||e.x===N&&(h>c||c>n.width-h)||e.y===D&&d>=l||e.y===O&&l>=d||e.y===N&&(l>d||d>n.height-l))&&a.splice(r,1);n.position={left:a[0][0],top:a[0][1]}}return n},rect:function(t,e,i,s){return{width:Math.abs(i-t),height:Math.abs(s-e),position:{left:Math.min(t,i),top:Math.min(e,s)}}},_angles:{tc:1.5,tr:7/4,tl:5/4,bc:.5,br:.25,bl:.75,rc:2,lc:1,c:0},ellipse:function(t,e,i,s,o){var n=R.polys._angles[o.abbrev()],r=0===n?0:i*Math.cos(n*Math.PI),a=s*Math.sin(n*Math.PI);return{width:2*i-Math.abs(r),height:2*s-Math.abs(a),position:{left:t+r,top:e+a},adjustable:k}},circle:function(t,e,i,s){return R.polys.ellipse(t,e,i,i,s)}},R.svg=function(t,i,o){for(var n,r,a,h,l,c,d,p,u,f,g,m=s(e),v=i[0],y=s(v.ownerSVGElement),b=1,w=1,_=!0;!v.getBBox;)v=v.parentNode;if(!v.getBBox||!v.parentNode)return k;n=y.attr("width")||y.width()||parseInt(y.css("width"),10),r=y.attr("height")||y.height()||parseInt(y.css("height"),10);var x=(parseInt(i.css("stroke-width"),10)||0)/2;switch(x&&(b+=x/n,w+=x/r),v.nodeName){case"ellipse":case"circle":f=R.polys.ellipse(v.cx.baseVal.value,v.cy.baseVal.value,(v.rx||v.r).baseVal.value+x,(v.ry||v.r).baseVal.value+x,o);break;case"line":case"polygon":case"polyline":for(u=v.points||[{x:v.x1.baseVal.value,y:v.y1.baseVal.value},{x:v.x2.baseVal.value,y:v.y2.baseVal.value}],f=[],p=-1,c=u.numberOfItems||u.length;c>++p;)d=u.getItem?u.getItem(p):u[p],f.push.apply(f,[d.x,d.y]);f=R.polys.polygon(f,o);break;default:f=v.getBoundingClientRect(),f={width:f.width,height:f.height,position:{left:f.left,top:f.top}},_=!1}return g=f.position,y=y[0],_&&(y.createSVGPoint&&(a=v.getScreenCTM(),u=y.createSVGPoint(),u.x=g.left,u.y=g.top,h=u.matrixTransform(a),g.left=h.x,g.top=h.y),y.viewBox&&(l=y.viewBox.baseVal)&&l.width&&l.height&&(b*=n/l.width,w*=r/l.height)),g.left+=m.scrollLeft(),g.top+=m.scrollTop(),f},R.imagemap=function(t,e,i){e.jquery||(e=s(e));var o,n,r,a,h,l=e.attr("shape").toLowerCase().replace("poly","polygon"),c=s('img[usemap="#'+e.parent("map").attr("name")+'"]'),d=s.trim(e.attr("coords")),p=d.replace(/,$/,"").split(",");if(!c.length)return k;if("polygon"===l)a=R.polys.polygon(p,i);else{if(!R.polys[l])return k;for(r=-1,h=p.length,n=[];h>++r;)n.push(parseInt(p[r],10));a=R.polys[l].apply(this,n.concat(i))}return o=c.offset(),o.left+=Math.ceil((c.outerWidth(k)-c.width())/2),o.top+=Math.ceil((c.outerHeight(k)-c.height())/2),a.position.left+=o.left,a.position.top+=o.top,a};var Me,Ie='<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:\'\';"  style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=0); -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";"></iframe>';s.extend(C.prototype,{_scroll:function(){var e=this.qtip.elements.overlay;e&&(e[0].style.top=s(t).scrollTop()+"px")},init:function(i){var o=i.tooltip;1>s("select, object").length&&(this.bgiframe=i.elements.bgiframe=s(Ie).appendTo(o),i._bind(o,"tooltipmove",this.adjustBGIFrame,this._ns,this)),this.redrawContainer=s("<div/>",{id:X+"-rcontainer"}).appendTo(e.body),i.elements.overlay&&i.elements.overlay.addClass("qtipmodal-ie6fix")&&(i._bind(t,["scroll","resize"],this._scroll,this._ns,this),i._bind(o,["tooltipshow"],this._scroll,this._ns,this)),this.redraw()},adjustBGIFrame:function(){var t,e,i=this.qtip.tooltip,s={height:i.outerHeight(k),width:i.outerWidth(k)},o=this.qtip.plugins.tip,n=this.qtip.elements.tip;e=parseInt(i.css("borderLeftWidth"),10)||0,e={left:-e,top:-e},o&&n&&(t="x"===o.corner.precedance?[A,F]:[B,D],e[t[1]]-=n[t[0]]()),this.bgiframe.css(e).css(s)},redraw:function(){if(1>this.qtip.rendered||this.drawing)return this;var t,e,i,s,o=this.qtip.tooltip,n=this.qtip.options.style,r=this.qtip.options.position.container;return this.qtip.drawing=1,n.height&&o.css(B,n.height),n.width?o.css(A,n.width):(o.css(A,"").appendTo(this.redrawContainer),e=o.width(),1>e%2&&(e+=1),i=o.css("maxWidth")||"",s=o.css("minWidth")||"",t=(i+s).indexOf("%")>-1?r.width()/100:0,i=(i.indexOf("%")>-1?t:1)*parseInt(i,10)||e,s=(s.indexOf("%")>-1?t:1)*parseInt(s,10)||0,e=i+s?Math.min(Math.max(e,s),i):e,o.css(A,Math.round(e)).appendTo(r)),this.drawing=0,this},destroy:function(){this.bgiframe&&this.bgiframe.remove(),this.qtip._unbind([t,this.qtip.tooltip],this._ns)}}),Me=R.ie6=function(t){return 6===oe.ie?new C(t):k},Me.initialize="render",M.ie6={"^content|style$":function(){this.redraw()}}})})(window,document);
+//@ sourceMappingURL=http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.0/jquery.qtip.min.map
\ No newline at end of file
index 5bd0d75..80653e8 100644 (file)
@@ -5,10 +5,12 @@ 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
-
+import json
 from unfold.loginrequired import FreeAccessView
 
 from manifoldapi.manifoldresult import ManifoldResult
+from manifold.core.query                import Query
+from manifoldapi.manifoldapi            import execute_query
 from ui.topmenu import topmenu_items, the_user
 from myslice.configengine import ConfigEngine
 
@@ -29,6 +31,24 @@ class SupportView (FreeAccessView, ThemeView):
 
         if request.user.is_authenticated(): 
             env['person'] = 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')
+            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
     
index 362f879..cbad91c 100644 (file)
@@ -1,8 +1,28 @@
 <img src="https://onelab.eu/templates/onelab2/images/logo.png">
 <br>
-<h1>You have registered to {{current_site}}</h1>
-<br>
-<h1>Please validate your email address by clicking the following link</h1>
-<br>
-<a href={{validation_link}}>{{validation_link}}</a>
+<p>We have received a user signup request for your email address at {{current_site}}</p>
+<p>You have the following user details:</p>
+
+Organization: {{organization}}<br>
+First name: {{first_name}}<br>
+Last name: {{last_name}}<br>
+Email: {{email}}<br>
+
+<p></p>
+<p>
+You may now log in to the portal using your email address and the password that you provided, but your access will be limited. To gain full access, two steps are required:
+</p>
 
+<ul>
+<li>1. You confirm that you have indeed made this request by clicking on the following link: <br>
+       <a href={{validation_link}}>{{validation_link}}</a> 
+               <ul><li>If you did not make this request, we apologise. You may disregard this email or you may advise us the error by replying to this email.</li></ul>
+</li>
+<li>
+2. A manager from your organization validates your request. Upon confirmation of your signup request, we will send an email to the managers at your organization with a validation request.
+</li>
+</ul>
+<p>
+We look forward to welcoming you to OneLab. You will find answers to frequently asked questions <a href="http://{{current_site}}/portal/support/">here</a>. 
+Please don't hesitate to <a href="http://{{current_site}}/portal/contact/">contact us</a> with any additional questions that you might have.
+</p>
index b5eb224..ac31ec2 100644 (file)
@@ -1,7 +1,24 @@
-You have registered to {{current_site}}
-Please validate your email address by clicking the following link:
+We have received a user signup request for your email address at {{current_site}}
 
-{{validation_link}}
+You have the following user details:
+
+Organization: {{organization}}
+First name: {{first_name}}
+Last name: {{last_name}}
+Email: {{email}}
+
+You may now log in to the portal using your email address and the password that you provided, but your access will be limited. To gain full access, two steps are required:
+
+       1. You confirm that you have indeed made this request by clicking on the following link:
+
+               {{validation_link}}
+
+               If you did not make this request, we apologise. You may disregard this email or you may advise us the error by replying to this email.
+
+       2. A manager from your organization validates your request. Upon confirmation of your signup request, we will send an email to the managers at your organization with a validation request.
+
+We look forward to welcoming you to OneLab. 
+Please don't hesitate to contact us at support@myslice.info with any additional questions that you might have.
 
 
 
index 66eb509..b42834b 100644 (file)
@@ -8,6 +8,7 @@
 {% include 'messages-transient-header.html' %}
 <script type="text/javascript"> {# raw js code - use {% insert prelude_js %} ... {% endinsert %} #} {% container prelude_js %}</script>
 <script src="{{ STATIC_URL }}js/jquery.dataTables.min.js"></script>
+<script src="{{ STATIC_URL }}js/jquery.qtip.min.js"></script>
 <script src="{{ STATIC_URL }}js/bootstrap.datatables.js"></script>
 <!-- <script src="{{ STATIC_URL }}js/stash.min.js"></script> -->
 <script src="{{ STATIC_URL }}js/myslice.js"></script>
@@ -37,6 +38,8 @@
 {% insert_str prelude "css/topmenu.css" %}
 {% insert_str prelude "js/logout.js" %}
 <link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/{{ theme }}.css">
+<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/jquery.qtip.min.css">
+
 
 <script type="text/javascript">
 /*
@@ -53,11 +56,13 @@ $(document).ready(function() {
     if($.isEmptyObject(user)){
         $.post("/rest/user/",{'filters':{'user_hrn':'$user_hrn'}}, function( data ) {
             if(data.length > 0){
-                slices = data[0].slices;  
+                drawSlices(data[0].slices);  
             }else{
+               $("div#home-slice-list").html(
+                                       "<div>You do not yet have a slice</div>");
+                       $("ul#dropdown-slice-list").append("<li>no slice</li>");
                 slices.push("no slice");
             }
-            drawSlices(slices);
        });
     }else{
         slices = user.slices;
@@ -65,13 +70,15 @@ $(document).ready(function() {
     }
     function drawSlices(slices){
         var items = [];
+               
         $.each( slices, function(i, val) {
-            items.push( "<li><a href=\"/slice/"+val+"\">" + val + "</a></li>" );
+            items.push( "<li><a href=\"/resources/"+val+"\">" + val + "</a></li>" );
         });
         $("div#home-slice-list").html($( "<ul/>", { html: items.join( "" ) }));
         $("ul#dropdown-slice-list").append(items.join( "" ));
     }
     {% endif %}
+       jQuery('[title!=""]').qtip();
 });
 </script>
 </head>
index d9d2c51..fdb5d0d 100644 (file)
@@ -33,7 +33,7 @@
                {{ field.errors }} {{ field }}
            </div>
            {% endfor %}
-               <button type="submit" class="btn btn-primary">Create Ticket</button>
+               <button type="submit" class="btn btn-onelab">Create Ticket</button>
                </form>
        </div>
 </div>
index b9df80e..43feab2 100644 (file)
@@ -3,20 +3,18 @@
 {% block content %}
 
 <div class="row">
-       <h1><img src="{{ STATIC_URL }}img/icon_user_small.png" alt="User Registration" /> Experimenter registration</h1>
+       <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>Email activation complete !</h3>
-               <p>Your account is pending for validation.</p>
-               <p>PI of your institution is responsible for validating your account.</p>
-               <p>You will be notified once your account is validated.</p>
-               <p>In the meantime, you can login to the portal with your email and password and browse through the limited access features.</p>
+               <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>
        {%else%}
-               <h3>Email activation Failed !</h3>
-               <p>Your email address is not registered in our server.</p>
-               <p>Please <a href="/portal/register">register</a> to get access to the portal.</p> 
-               <p>If you have already registered and still having this message, please <a href="/portal/contact/">contact support.</a> </p>
+               <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, 
+               we have been unable to match the link that you have clicked to a signup request in our database.</p>
+               <p>Please <a href="/portal/contact/">contact support</a> so that we can help you complete the signup process.</p>
        {%endif%}
  </div>
 
index a127595..c627e5b 100644 (file)
@@ -1,22 +1,20 @@
-{% extends "layout_wide.html" %}
+{% extends "layout.html" %}
 
 {% block head %} 
 <script type="text/javascript" src="{{STATIC_URL}}/js/institution.js"></script>
 {% endblock head %}
 
 {% block content %}
-<div class="container">
-       <div class="row">
-               <div class="col-md-12">
-                       <ul class="nav nav-tabs nav-section">
-                               <li class="active"><a href="#info"><img src="{{ STATIC_URL }}icons/authority-xs.png" alt="Institution" /> Institution {{user_details.parent_authority}}</a></li>
-                               <li><a href="#users">Users</a></li>
-                               <li><a href="#slices">Slices</a></li>
-                       </ul>
-           </div>
-       </div>
+<div class="row">
+       <div class="col-md-12">
+               <ul class="nav nav-tabs nav-section">
+                       <li class="active"><a href="#info"><img src="{{ STATIC_URL }}icons/authority-xs.png" alt="Institution" /> Institution {{user_details.parent_authority}}</a></li>
+                       <li><a href="#users">Users</a></li>
+                       <li><a href="#slices">Slices</a></li>
+               </ul>
+    </div>
 </div>
-<div class="container tab-content">
+<div class="tab-content">
        <div class="tab-pane active row" id="info">
                <div class="col-md-12">
                        <div id="authority-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Authority" /></div>
diff --git a/portal/templates/join_complete.html b/portal/templates/join_complete.html
new file mode 100644 (file)
index 0000000..43be76e
--- /dev/null
@@ -0,0 +1,17 @@
+{% extends "layout.html" %}
+
+{% block content %}
+
+<div class="row">
+       <h1><img src="{{ STATIC_URL }}img/icon_user_small.png" alt="User Registration" />Request to add organization</h1>
+</div>
+<div class="row">
+  <h3>Organization information received.</h3>
+<p>
+We will contact the manager that you have listed with any questions that we might have.<br> 
+Once we have added the organization to the list, we will alert the manager.<br>
+At that time users from your organization will be able to sign up to join OneLab.
+</p>
+</div>
+
+{% endblock %}
index fecc7fb..9cba9f7 100644 (file)
@@ -5,7 +5,7 @@
 
 <div class="row">
        <div class="col-md-12">
-       <h1><img src="{{ STATIC_URL }}icons/testbed-xs.png" alt="Join Federation" /> Add organization</h1>
+       <h1><img src="{{ STATIC_URL }}icons/testbed-xs.png" alt="Join Federation" /> Request to add organization</h1>
        </div>
 </div>
 <div class="row">
diff --git a/portal/templates/onelab/onelab_about.html b/portal/templates/onelab/onelab_about.html
new file mode 100644 (file)
index 0000000..5b7eb96
--- /dev/null
@@ -0,0 +1,104 @@
+{% extends "layout.html" %}
+
+{% block content %}
+<div class="row">
+       <div class="col-md-12">
+                <div class="breadcrumbs">
+                </div>
+       </div>
+</div>
+<div class="row">
+    <div class="col-md-12">
+        <ul class="nav nav-tabs nav-section">
+            <li class="active"><a href="#about">About</a></li>
+            <li><a href="#components">Underlying technologies</a></li>
+        </ul>
+    </div>
+</div>
+
+
+<div class="tab-content">
+    <div class="tab-pane active row" id="about">
+               <div class="col-md-12">
+                       <p>
+                               OneLab Portal is a central place to get acess to all OneLab testbeds.In order to get access to the portal,
+                               an experimenter needs to  <a href="/portal/register">register</a> to the portal. The portal administrative body
+                               is responsible to accept or reject newly registered users.   
+                       </p>
+                       <p>
+                               To learn more about OneLab visit:  <a href="http://onelab.eu/" target="_blank">http://onelab.eu/</a>                    
+                       </p>
+                       <p>
+                               If you have any questions regarding using the portal visit: <a href="/portal/support">OneLab support</a>
+                       </p>
+                       <p>
+                               OneLab portal is a community effot. To get more information about OneLab portal team visit: 
+                               <a href="http://myslice.info/community" target="_blank">http://myslice.info/community</a>
+                       </p>
+               </div>
+       </div>
+       <div class="tab-pane row" id="components">
+               <div class="col-md-12">
+                       <h3>A ready-made and easily customisable user interface for your testbed.</h3>
+                               <p>
+                                       MySlice is an ambitious project aiming to support researchers throughout the lifecycle of experiments that can run on a variety 
+                                       of testbeds spanning different administrative domains and networking technologies. Its basic principle is to bring together 
+                                       available resources with useful information (characteristics, performance, network measurements).
+                               </p>
+                               <p>
+                                       MySlice inititiave started in Janury 2011 by offering annotation services for the first ederated experimental resources. Today, 
+                                       MySlice has taken a big step toward becoming a tand-alone web framework, which will present all available resources from testbeds 
+                                       across the world, interconnected through the Slice-based Facility Architecture (SFA) and annotated by the TopHat measurement system.
+                               </p>
+                               <p>
+                                       Our framework is built with standard programming tools (python and javascript for the front-end and python for the back-end) 
+                                       and has a modular structure based on the concept of plugins for implementing different core functionalities (query editing, 
+                                       data display, and resource allocation).
+                               </p>
+                               <p>
+                                       The goal is to enable developers with expertise on different testbed technologies and different experimental 
+                                       practices to work in parallel for optimizing the tools presented to the users allowing them for a wide range of choices 
+                                       according to their own requirements. Opening in this way the development of web-based user tools for experimentation and 
+                                       sharing effort and information can increase significantly the chances for the achievement of our challenging objective.
+                               </p>
+               </div>
+               <div class="col-md-12">
+                       <h3>Portal Components</h3>
+                               <h5>Myslice (Web Frontend)</h5>
+                                       <p>
+                                               A full-fledged and modular web portal for a testbed federation allowing user to register, 
+                                               request slices and browse and book resources, with a strong emphasis on measurements.
+                                       </p>
+                                       <p> More Info: <a href="http://myslice.info/" target="_blank">http://myslice.info/</a></p>
+                                       <p> Code: <a href="http://git.onelab.eu/?p=myslice.git;a=summary" target="_blank">Git Repository</a> (read only)</p> 
+                                       <p> 
+                                               If you need write access to the git repository you need first to send your public key to <a href="mailto:support@myslice.info">support@myslice.info</a>.
+                                       </p>
+
+
+                               <h5>Manifold (Portal backend)</h5>
+                                       <p>
+                                               Manifold is the backend that is running behind the portal. It is a component allowing the integration of distributed 
+                                               and heterogeneous data sources, such as measurement platforms or data repositories.
+                                       </p>
+                                       <p> Documentation: <a href="http://trac.myslice.info/" target="_blank">http://trac.myslice.info/</a></p>
+                                       <p> Code: <a href="https://git.top-hat.info/?p=tophat.git;a=shortlog;h=refs/heads/devel" target="_blank">Git Repository</a> (read only)</p>     
+
+                               <h5>OneLab Registry</h5>
+                                       <p>It's a SFA registry. SFA Registry is a specific installation mode of the SFAWrapper (Registry Only mode).</p>
+                                       <p> More Info: <a href="http://svn.planet-lab.org/wiki/SfaDeveloperRegistryTutorial#RunninginRegistry-Onlymode" target="_blank">SFA Registry</a></p>
+       </div>
+   </div>
+</div>
+
+<script>
+$(document).ready(function() {
+    $('.nav-tabs a').click(function (e) {
+        e.preventDefault();
+        $(this).tab('show');
+    });
+});
+</script>
+
+
+{% endblock %}
diff --git a/portal/templates/onelab/onelab_account-view.html b/portal/templates/onelab/onelab_account-view.html
new file mode 100644 (file)
index 0000000..9941e97
--- /dev/null
@@ -0,0 +1,332 @@
+{% extends "layout.html" %}
+{% block content %}
+
+<div class="row">
+       <div class="col-md-12">
+                <div class="breadcrumbs">
+                        Account &nbsp;>&nbsp; {{ person.email }}
+                </div>
+       </div>
+</div>
+{% if messages %}
+<ul class="messages">
+    {% for message in messages %}
+    <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
+    {% endfor %}
+</ul>
+{% endif %}
+<div class="row">
+       <div class="col-md-12">
+               <ul class="nav nav-tabs nav-section">
+                       <li class="active"><a href="#profile">User Profile</a></li>
+                       <li><a href="#account">Account</a></li>
+                       <li><a href="#access">Testbed Access</a></li>
+               </ul>
+    </div>
+</div>
+<div class="tab-content">
+       <div class="tab-pane active row" id="profile">
+               
+               <div class="col-md-12">
+
+                       <form id="editForm" method="post" action="account_process" enctype="multipart/form-data">
+                               {% csrf_token %}
+                                       <table class="profile">          
+                                       <tr>
+                                               <td colspan="2">
+                                                               <div><h3>Platform: Myslice</h3></div>
+                                               </td>
+                                       </tr>
+                                       <tr>
+                                               <td class="key">Email</td>
+                                               <td class="value">
+                                                               <span id="emailval" class="value" >{{ person.email }}</span>
+                                                               <button class="btn btn-default" type="button" id="edit_email" onclick="editAlert();"  title="To change your affiliation please contact the administrator">
+                                                               <span class="glyphicon glyphicon-question-sign"></span> Edit
+                                                               </button>
+                                                       </td>
+                                       </tr>
+                                       <tr class="odd">
+                                                       <td class="key">Password</td>
+                                                       <td class="value"> 
+                                                               <button class="btn btn-default btn-xs" type="button" title="Password" name="edit_pass" id="edit_pass">
+                                                                       <span class="glyphicon glyphicon-edit"></span> Edit
+                                                               </button>
+                                                               <span id="passval"class="value">******** </span>
+                                                               <span class="hide_this" id="span_pass">
+                                                               <button type="button" class="btn btn-default btn-xs" title="Cancel" id="cancel_pass_change"> Cancel </button>
+                                                               <div style='display:none;' id="pass_form">
+                                                               <input type='hidden'  value='' /></div>
+                                                               <table id="edit_password">
+                                                                       <tr>
+                                                                                       <td>Enter password: </td>
+                                                                                       <td class="field"> <input type="password" name="password" id="password" /> </td>
+                                                                               </tr>
+                                                                               <tr>
+                                                                                       <td>Confirm password: </td>
+                                                                                       <td class="field"> 
+                                                                                               <input type="password" name="confirmpassword" id="confirmpassword" /> 
+                                                                                               <input type="submit" class="btn btn-default btn-xs" name="submit_pass" value="Save"/> 
+                                                                                       </td>
+                                                                       </tr>
+                                                               </table>
+                                                               </span> 
+                                                       </td>
+                                       </tr>
+                                       <tr class="even">
+                                                       <td class="key">Full Name</td>
+                                                       <td class="value">
+                                                               <span id="nameval" class="value" >{{ fullname }} </span>
+                                                               <span class="hide_this" id="span_name">
+                                                               <button type="button" class="btn btn-default btn-xs" title="Cancel" id="cancel_name_change"> Cancel </button> 
+                                                               <div style='display:none;'><input type='hidden'  name='nameform'  /></div>
+                                                               <input id="fname" type="text" name="fname" class="required"  maxlength="200" value="{{firstname}}" />
+                                                               <input id="lname" type="text" name="lname" class="required"  maxlength="200" value="{{lastname}}" />
+                                                               <input type="submit" class="btn btn-default btn-xs" name="submit_name" value="Save"/>
+                                                               </span>
+                                                               <button class="btn btn-default btn-xs" type="button"title="Full Name" id="edit_name">
+                                                                       <span class="glyphicon glyphicon-edit"></span> Edit
+                                                               </button>
+                                                       </td>
+                                       </tr>
+                                       <tr class="odd">
+                                                       <td class="key">Authority</td>
+                                                       <td class="value">
+                                                               <span id="affval" class="value">{{ authority }}</span>
+                                                                <button class="btn btn-default btn-xs" type="button" id="edit_auth" onclick="editAlert()"  title="To change your authority please contact the administrator">
+                                                               <span class="glyphicon glyphicon-question-sign"></span> Edit
+                                                                </button>
+                                                       </td>
+                                               </tr>
+                                               {%if 'Enabled'  in user_status %}
+                                               <tr class="even">
+                                                       <td class="key">Generate Keys</td>
+                                                       <td>
+                                                               <input type="submit" name="generate" class="btn btn-primary" value="Generate a new Key Pair" id="generate_keypair" 
+                                                                          onclick="return confirm('Are you sure? If you do so, your current credentials will be overwritten.');" 
+                                                                          title="It will generate a new key Pair and your current credentials will be overwritten."/>
+                                               </td> 
+                                       </tr>
+                                       <tr class="odd">
+                                               <td class="key">Public Key</td>
+                                               <td class="value">
+                                                               <span id="keyval" class="value">******** </span>
+                                                               <span class="hide_this" id="span_upload">
+                                                                       <button type="button" class="btn btn-default" title="Cancel" id="cancel_upload"> Cancel </button>
+                                                                       <div style='display:none;'>
+                                                                               <input type='hidden'  name='upload'  /></div>
+                                                                               <input type="file" name="pubkey" class="required" id="pubkey"/>  
+                                                                               <input class="btn btn-default btn-xs" name="upload_key" id="upload_key"  type="submit" title="Upload your public key" value="Upload"
+                                                                                  onclick="return confirm('Are you sure? It will overwrite your current credentials and you have delegate it manually.');"/>
+                                                               </span>
+                                                               <div style='display:none;'> <input type='hidden'  name='dload'  /> </div> 
+                                                               <button type="submit" name="dl_pubkey" class="btn btn-default btn-xs" title="Download your public key" id="dl_file">
+                                                                       <span class="glyphicon glyphicon-download"></span> Download
+                                                               </button>
+                                                               <button class="btn btn-default btn-xs" id="upload_file" type="button" title="Upload a public key">
+                                                                       <span class="glyphicon glyphicon-upload"></span> Upload
+                                                               </button>       
+                                               </td>
+                                       </tr>
+                                       <tr class="even" id="pkey_row">
+                                                {%if 'N/A' not in user_private_key%}
+                                               <td class="key">Private Key </td> <!-- Hide if priv_key doesn't exist in myslice platform   -->
+                                               <td class="value">********<a href="#"></a>
+                                                       <button type="submit" name="dl_pkey" class="btn btn-default" title="Download your privaye key" id="dl_pkey">
+                                                                       <span class="glyphicon glyphicon-download"></span> Download     
+                                                               </button>
+                                                       <input class="btn btn-danger btn-xs" id="delete" name="delete" type="submit"  value="Delete" title="Delete your private key"
+                                                                               onclick="return confirm('Are you sure? If you do so, you have to delegate your credentials manually.');"/> 
+                                               </td>
+                                                 {%else%}
+                                                       <td class="key">Private Key </td> <!-- Hide if priv_key doesn't exist in myslice platform   -->
+                                                       <td class="value">********<a href="#"></a>
+                                                       <button type="submit" name="dl_pkey" class="btn btn-default disabled" title="Download your privaye key" id="dl_pkey">
+                                                               <span class="glyphicon glyphicon-download"></span> Download 
+                                                       </button>
+                                                       <input class="btn btn-danger btn-xs disabled" id="delete" name="delete" type="submit" title="Delete your private key" value="Delete" />
+                                                       </td>
+                                                {%endif%}              
+                                               </tr>
+                                               <tr class="even">
+                                               <td colspan="2">
+                                                       <p class="message" id="pkey_del_msg"><b> Tradeoff:</b> Ease-of-use vs Security.<br>
+                                                                       <b>Ease-of-use:</b> Automatic account delegation. Don't delete private key.<br>
+                                                                       <b>Security:</b> Manual account delegation. Download & Delete private key.
+                                                               </p>
+                                               </td>
+                                               </tr>
+                                               {%endif%}
+                                       </table>
+                       
+               </div>
+       </div>
+
+       <div class="tab-pane row" id="account">
+               <div class="col-md-12">
+       
+               <h3>Principal Account <small>Account used for delegating credentials</small></h3>
+               <table class="table"> 
+                       <tr class="odd"> 
+                       <th>Platform</th> 
+                       <th>Account Type</th>
+                               <th>Account Delegation</th>
+                       <th>User hrn</th>
+                               <th>User Status</th>
+                       <!--<th>Pub Key</th> -->
+               </tr>   
+                       {% for row in principal_acc %}         
+                       <tr class="border_bottom">
+                       <td class="odd"> {{ row.platform_name }} </td>
+                       <td class="odd"> {{ row.account_type }} </td>
+                               <td class="odd"> {{ row.delegation_type }} </td>
+                               <td class="odd"> {{ row.usr_hrn }}  </td>
+                               <td class="odd"> {{ row.user_status }}  </td>
+               <!--    <td class="even"> {{ row.usr_pubkey }} </td> -->
+               </tr> 
+                       {%endfor%}               
+               </table>
+       
+               </div>
+       
+
+       {%if 'Enabled'  in user_status %}
+               <div class="col-md-12">
+               <h3>Credentials <small>Delegated to Principal Account</small></h3>
+                       <table class="table">
+                                       <caption><b>Delegated User Credential</b></caption> 
+                           <tr class="odd"> 
+                               <th>Expiration Date</th>
+                                               <th>Download</th>
+                           </tr>
+                                       {% for row in my_users %}         
+                                       <tr class="border_bottom">
+                                       <td class="odd"> {{ row.cred_exp }} </td>
+                                               <td class="odd">
+                                                       <button class="btn btn-default btn-xs" name= "dl_user_cred" type="submit" title="Download User Credential">
+                                                               <span class="glyphicon glyphicon-download"></span> Credential
+                                                       </button>
+                                                       <button class="btn btn-default btn-xs" name= "dl_user_cert" type="submit" title="Download User Certificate">
+                                                               <span class="glyphicon glyphicon-download"></span> Certificate
+                                                       </button>
+                             <button class="btn btn-default btn-xs" name= "dl_user_p12" type="submit" title="Download User PKCS12">
+                                 <span class="glyphicon glyphicon-download"></span> PKCS p12
+                             </button>
+                                               </td>
+                                       </tr>
+                                       {%endfor%}
+                                </table>
+                               <p></p>
+                               <table class="mytable table table-bordered table-hover">
+                                       <caption><b>Delegated Slice Credentials</b></caption>  
+                               <tr class="odd"> 
+                                               <th>Slice Name</th> 
+                                       <th>Expiration Date</th>
+                                               <th>Download</th>
+                               </tr>
+                                       {% for row in my_slices %}     
+                               <tr class="border_bottom">
+                                       <td class="odd"> {{ row.slice_name }} </td>
+                                               <td class="odd"> {{ row.cred_exp }} </td>
+                                               <td class="odd"> 
+                                                       <button class="btn btn-default btn-xs" name= "dl_{{row.slice_name}}" type="submit" title="Download Slice Credentials">
+                                                               <span class="glyphicon glyphicon-download"></span> Download
+                                                       </button> 
+                                               </td>
+                               </tr>
+                               {%endfor%}
+                               </table>
+                               <p></p>
+                               <table class="mytable table table-bordered table-hover">
+                                       <caption><b>Delegated Authority Credentials</b></caption>
+                                       <tr class="odd"> 
+                                       <th>Authority Name</th> 
+                                       <th>Expiration Date</th>
+                                               <th>Download</th>
+                                       </tr>
+                                       {% for row in my_auths %}
+                                       <tr class="border_bottom">
+                                       <td class="odd"> {{ row.auth_name }} </td>
+                                       <td class="odd"> {{ row.cred_exp }} </td>
+                                               <td class="odd">
+                                                       <button class="btn btn-default btn-xs" name= "dl_{{row.auth_name}}" type="submit" title="Download Authority Credentials">
+                                                               <span class="glyphicon glyphicon-download"></span> Download
+                                                       </button>
+                                               </td>
+                                       </tr>
+                                       {%endfor%}
+                               </table>
+                               <p></p>
+                                {%if '' not in my_users%}      
+                               <p><button class="btn btn-danger btn-lg btn-block"   name= "clear_cred" type="submit" title="Clear All Credentials">Clear Credentials</button></p>
+                               {%else%}
+                               <p><button class="btn btn-danger btn-lg btn-block disabled"   name= "clear_cred" type="submit" title="Clear All Credentials">Clear Credentials</button></p>
+                               {%endif%}
+               </div>
+       </div>
+
+       <div class="tab-pane row" id="access">
+               <div class="col-md-12">
+       
+               <h3>Testbed Access <small>Reference Accounts in the following testbeds</small></h3>
+        <table class="mytable table table-bordered table-hover"> 
+            <tr class="odd"> 
+                <th>Platform</th> 
+                <th>Account Type</th>
+                               <th>Reference to</th>
+                               <th>Remove Account</th>
+            </tr>   
+            {% for row in ref_acc %}         
+            <tr class="border_bottom">
+                <td class="odd"> {{ row.platform_name }} </td>
+                <td class="odd"> {{ row.account_type }} </td>
+                               <td class="odd"> {{ row.account_reference }} </td>
+                               <td class="odd">
+                               <button class="btn btn-danger" name="delete_{{row.platform_name}}" type="submit" title="Delete account from this platform">
+                                               <span class="glyphicon glyphicon-minus"></span>
+                                       </button>
+                               </td>
+            </tr> 
+            {%endfor%}               
+        </table>               
+               
+               
+               <h3>Add reference account to the following testbeds</h3>
+        <table class="mytable table table-bordered table-hover"> 
+            <tr class="odd"> 
+                <th>Platforms</th> 
+                <th>Add Account</th>
+            </tr>   
+            {% for platform in platform_list %}         
+            <tr class="border_bottom">
+                <td class="odd"> {{ platform.platform_no_access }} </td>
+                <td class="odd">
+                                       <button class="btn btn-success btn-sm" name= "add_{{platform.platform_no_access}}" type="submit" title="Add account to this platform">
+                                               <span class="glyphicon glyphicon-plus"></span>
+                                       </button>
+                               </td>
+            </tr> 
+            {%endfor%}               
+        </table>
+       </div>
+{%endif%} 
+</div>
+</form>
+</div>
+
+<script>
+    $(document).ready(function() {
+       $('.nav-tabs a').click(function (e) {
+                       e.preventDefault();
+                       $(this).tab('show');
+                       id = $(this).attr('href').substr(1);
+               
+               });
+               
+        $('button#createslice').click(function() {
+            window.location="/portal/slice_request/";
+        });
+    });
+</script>
+
+{% endblock %}
diff --git a/portal/templates/onelab/onelab_contact.html b/portal/templates/onelab/onelab_contact.html
new file mode 100644 (file)
index 0000000..21608da
--- /dev/null
@@ -0,0 +1,40 @@
+{% extends "layout.html" %}
+
+{% block head %}
+{{ wizard.form.media }}
+{% endblock %}
+
+{% block content %}
+<div class="row">
+       <div class="col-md-12">
+                <div class="breadcrumbs">
+                        Support &nbsp;>&nbsp; Contact
+                </div>
+       </div>
+</div>
+<div class="row">
+       <div class="col-md-12">
+       <p>Please check our <a href="/portal/support/">FAQ</a> section. Most of the basic problems are explained there.</p>
+       <p>
+       If you haven't find your answes in the FAQ, please contact us by filling the form below.<br />
+       You can also <a href="mailto:support@myslice.info">e-mail</a> us directly.
+       </p>
+       </div>
+</div>
+
+<div class="row">
+       <div class="col-md-4">
+               <form role="form" method="post">
+               {% csrf_token %}
+               {% for field in form %}
+           <div class="form-group">
+               <label for="{{ field.html_name }}" class="control-label">{{ field.label }}</label>
+               {{ field.errors }} {{ field }}
+           </div>
+           {% endfor %}
+               <button type="submit" class="btn btn-onelab">Create ticket</button>
+               </form>
+       </div>
+</div>
+{% endblock %}
+
index 11fa2ee..f5d6cf1 100644 (file)
@@ -8,6 +8,7 @@
 {% if username %}
 <div class="container dashboard">
        <div class="row">
+               {%if 'is_pi'  in pi %}
                <div class="col-md-3">
                        <h3>
                                EXPERIMENT
                        <div>
                                <button id="slicerequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request Slice</button>
                        </div>
+                       <div>
+                               <p><strong>Your slices </strong>
+                                       <span title="A slice is a set of testbed resources on which you can conduct an experiment. 
+                                       Either ask your colleagues to give you access to an existing slice or request a new slice by clicking 'Request Slice'." 
+                                       class="glyphicon glyphicon-info-sign">
+                                       </span>
+                               </p>
+                       </div>
                        <div>   
                                <div id="home-slice-list"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
                        </div>
                                {% if person.last_name %}
                                        {{person.first_name}} {{person.last_name}}<br />
                                {% endif %}
-                       <span class="label">Email:</span> <a href='/portal/account/'>{{person.email}}</a>
+                       <span class="label">Username:</span> <a href='/portal/account/' title="Click here to see and edit your account details.">{{person.email}}</a>
+               </div>
+               </div>
+       </div>
+       {%else%}
+       <div class="row">
+               <div class="col-md-4">
+                       <h3>
+                               EXPERIMENT
+                       </h3>
+                       <div>
+                               <a href="#"><img src="{{ STATIC_URL }}img/icon_slices.png" alt="" /></a>
+                       </div>
+                       <div>
+                               <button id="slicerequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request Slice</button>
+                       </div>
+                       <div>
+                               <p><strong>Your slices </strong>
+                               <span title="A slice is a set of testbed resources on which you can conduct an experiment. 
+                                       Either ask your colleagues to give you access to an existing slice or request a new slice by clicking 'Request Slice'." 
+                                       class="glyphicon glyphicon-info-sign">
+                               </span>
+                               </p>
+                       </div>
+                       <div>   
+                               <div id="home-slice-list"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
+                       </div>
+               </div>
+               <div class="col-md-4">
+                       <h3>
+                               SUPPORT
+                       </h3>
+                       <div>
+                               <a href="/portal/support"><img src="{{ STATIC_URL }}img/icon_support.png" alt="" /></a>
+                       </div>
+                       <div>
+                               <button id="ticketbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-envelope"></span> Contact</button>
+                       </div>
+               </div>
+               
+               <div class="col-md-4">
+                       <h3>
+                               ACCOUNT
+                       </h3>
+                       <div>
+                               <a href="/portal/account/"><img src="{{ STATIC_URL }}img/icon_user_color.png" alt="" /></a>
+                       </div>
+                       <div>
+                               <button id="logoutbtn" type="button" class="btn btn-default" data-username="{{ username }}"><span class="glyphicon glyphicon-off"></span> Logout</button>
+                       </div>
+                       <div>
+                               {% if person.last_name %}
+                                       {{person.first_name}} {{person.last_name}}<br />
+                               {% endif %}
+                       <span class="label">Username:</span> <a href='/portal/account/' title="Click here to see and edit your account details.">{{person.email}}</a>
                </div>
                </div>
        </div>
+       {%endif%}
+
 </div>
 {% else %}
 <div class="container-fluid home">
                        $('div#'+$(this).data('panel')).show();
                });
                $('button#validaterequestbtn').click(function() {
-                       window.location="/portal/validate/";
+                       window.location="/portal/institution#requests";
                });
                $('button#ticketbtn').click(function() {
                        window.location="/portal/contact/";
index 409c13f..6c35812 100644 (file)
@@ -5,20 +5,30 @@
 {% endblock head %}
 
 {% block content %}
+<div class="container">
+       <div class="row">
+               <div class="col-md-12">
+                        <div class="breadcrumbs">
+                                Management &nbsp;>&nbsp; Institution: <span id="authority_name"></span>
+                        </div>
+               </div>
+       </div>
+</div>
 <div class="container">
        <div class="row">
                <div class="col-md-12">
                        <ul class="nav nav-tabs nav-section">
-                               <li class="active"><a href="#info"><img src="{{ STATIC_URL }}icons/authority-xs.png" alt="Institution" /> Institution {{user_details.parent_authority}}</a></li>
+                               <li class="active"><a href="#info">About</a></li>
                                <li><a href="#users">Users</a></li>
                                <li><a href="#slices">Slices</a></li>
+                               <li><a href="#requests">Requests</a></li>
                        </ul>
            </div>
        </div>
 </div>
 <div class="container tab-content">
        <div class="tab-pane active row" id="info">
-               <div class="col-md-12">
+               <div class="col-md-12 el">
                        <div id="authority-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Authority" /></div>
                    <div id="authority-tab-loaded" style="display:none;">
                        <div id="authority-data" style="float:left; width:50%;"></div>
        </div>
        
        <div class="tab-pane row" id="users" data-authority="{{user_details.parent_authority}}">
-               <div class="col-md-12">
+               <div class="col-md-12 el">
                        <div id="user-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
                                <div id="user-tab-loaded" style="display:none;">
-                               <table id="user-tab">
+                               <table id="user-tab" class="table">
                                        <tr>
                                        <th>+/-</th>
-                                       <th>email</th>
-                                       <th>user_hrn</th>
-                                       <th>first name</th>
-                                       <th>last name</th>
-                                       <th>enabled</th>
+                                       <th>Email</th>
+                                       <th>User hrn</th>
+                                       <th>First name</th>
+                                       <th>Last name</th>
+                                       <th>Enabled</th>
                                        </tr>
                                </table>
-                               {%if 'is_pi'  in pi %}  
-                               <div>
-                                       <button id="deleteusers" type="button" class="btn btn-default"><span class="glyphicon glyphicon-remove"></span> Delete Users</button>
-                               </div>
-                               {%endif%}
+                               
+                       </div>
+                       {%if 'is_pi'  in pi %}  
+                       <div>
+                               <button id="deleteusers" type="button" class="btn btn-danger"><span class="glyphicon glyphicon-remove"></span> Delete selected users</button>
                        </div>
+                       {% endif %}
                </div>
        </div>
 
        <div class="tab-pane row" id="slices">
-               {%if 'is_pi'  in pi %}
-               <button id="createslice" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> create slice</button>
-               {%else%}
-               <button id="createslice" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> request slice</button>
-               {%endif%}
+               <div class="col-md-12 el">
+               {% if 'is_pi'  in pi %}
+               <button id="createslice" type="button" class="btn btn-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">
+               <table id="slice-tab" class="table">
                    <tr>
                        <th>+/-</th>
-                       <th>slice_hrn</th>
-                       <th>users</th>
-                       <th>url</th>
+                       <th>Slice hrn</th>
+                       <th>Users</th>
+                       <th>Url</th>
                        <!-- <th>nodes</th> -->
-                       <th>expiration</th>
+                       <th>Expiration</th>
                    </tr>
-               </table>
-               <br>
-                       {%if 'is_pi'  in pi %}
-               <div>
-                   <button id="renewslices" type="button" class="btn btn-default"><span class="glyphicon glyphicon-refresh"></span> Renew Slices</button>
-                   <button id="deleteslices" type="button" class="btn btn-default"><span class="glyphicon glyphicon-remove"></span> Delete Slices</button>
-               </div>
-                       {%endif%} 
+               </table>                        
            </div>
+       {% if 'is_pi'  in pi %}
+        <div>
+            <button id="renewslices" type="button" class="btn btn-primary"><span class="glyphicon glyphicon-refresh"></span> Renew Slices</button>
+            <button id="deleteslices" type="button" class="btn btn-danger"><span class="glyphicon glyphicon-remove"></span> Delete Slices</button>
+        </div>
+               {% endif %} 
+          </div>
+       </div>
+       <div class="tab-pane row" id="requests">
        </div>
 </div>
 <script>
@@ -87,11 +102,13 @@ $(document).ready(function() {
     {% 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>";
@@ -213,5 +230,19 @@ $(document).ready(function() {
     {% endif %}
 
 }); // End document.ready
+
+$(document).ready(function() {
+       $('.nav-tabs a').click(function (e) {
+               e.preventDefault();
+               $(this).tab('show');
+       var id = $(this).attr('href').substr(1);
+       if (id == 'requests') 
+               $("#" + id).load('/management/' + id);
+       });
+       var hash = window.location.hash;
+       if (hash) {
+               $('.nav-tabs a[href='+hash+']').click();
+       }
+});
 </script>
 {% endblock %}
diff --git a/portal/templates/onelab/onelab_management-tab-requests.html b/portal/templates/onelab/onelab_management-tab-requests.html
new file mode 100644 (file)
index 0000000..1356ef5
--- /dev/null
@@ -0,0 +1,228 @@
+<script type="text/javascript">
+       $(document).ready(function() {
+               $("li#nav-request").addClass("active");
+       });
+       function on_click_event() {
+               var ids = []; 
+               $('.portal__validate__checkbox').each(function(i, el) {
+                       if ($(el).prop('checked')) {
+                               // portal__validate__checkbox__slice__2
+                               var id_array = $(el).attr('id').split('__');
+                               // push(slice__2)
+                               ids.push(id_array[3] + '__' + id_array[4]);
+                       }
+               });
+               if (ids.length > 0) {
+                       var id_str = ids.join('/');
+
+                       // XXX spinner
+
+                       $.getJSON('/portal/validate_action/' + id_str,
+                               function(status) {
+                                       $.each(status, function(request_type__id, request_status) {
+                                               // request_status: NAME -> dict (status, description)
+                                               var status_str = '';
+                                               $.each(request_status, function(name, result) {
+                                                       if (status_str != '')
+                                                               status_str += ' -- ';
+
+                                                       if (result.status) {
+                                                               status_str += '<font color="green">OK</font>';
+                                                               $('#portal__validate__checkbox__' + request_type__id).hide();
+                                                       } else {
+                                                               status_str += '<font color="red">ERROR: ' + result.description + '</font>';
+                                                       }
+                                               });
+                                               $('#portal__status__' + request_type__id).html(status_str);
+
+
+                                       });
+                               }
+                       );
+               }
+       }
+</script>
+
+<div class="col-md-12">
+       <h2>Authorities</h2>
+</div>
+{% if my_authorities %}
+       
+       {% for authority, requests in my_authorities.items %}
+       
+       <div class="col-md-12">
+               <h2>{{authority}}</h2>
+       </div>
+       
+    <table class="table">
+      <th>
+        <td>Type</td>
+        <td>Id</td>
+        <td>Details</td>
+        <td>Timestamp</td>
+        <td>Status</td>
+      </th>
+    {% for request in requests %}
+
+         <tr>
+               <td>
+               {% if request.allowed == 'allowed' %}
+               <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
+               {% else %}
+                       {% if request.allowed == 'expired' %}
+                               expired
+                       {% else %} {# denied #}
+                               denied
+                       {% endif %}
+               {% endif %}
+               </td>
+               <td>{{ request.type }}</td>
+               <td>{{ request.id }}</td>
+               <td>
+        {% if request.type == 'user' %}
+        Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
+        {% else %}
+            {% if request.type == 'slice' %}
+        Slice name: {{request.slice_name}} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+            {% else %} {# authority #}
+        Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
+            {% endif %}
+        {% endif %}
+               </td>
+               <td>{{ request.timestamp }}</td>
+               
+               <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
+
+    <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+         </tr>
+
+    {% endfor %}
+       </table>
+       </div>
+       {% endfor %}
+
+{% else %}
+       <div class="col-md-12">
+               <i>There is no pending request waiting for validation.</i>
+       </div>
+{% endif %}
+
+<div class="col-md-12">
+       <h2>Sub-Authorities</h2>
+</div>
+{% if sub_authorities %}
+       
+       {% for authority, requests in sub_authorities.items %}
+       <div class="col-md-12">
+       <h3>{{authority}}</h3>
+           <table class="table">
+             <th>
+               <td>Type</td>
+               <td>Id</td>
+               <td>Details</td>
+               <td>Timestamp</td>
+               <td>Status</td>
+             </th>
+           {% for request in requests %}
+                 <tr>
+                       <td>
+                       {% if request.allowed == 'allowed' %}
+                       <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
+                       {% else %}
+                               {% if request.allowed == 'expired' %}
+                                       expired
+                               {% else %} {# denied #}
+                                       denied
+                               {% endif %}
+                       {% endif %}
+                       </td>
+                       <td>{{ request.type }}</td>
+                       <td>{{ request.id }}</td>
+                       <td>
+               {% if request.type == 'user' %}
+               Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
+               {% else %}
+                   {% if request.type == 'slice' %}
+               Slice name: {{request.slice_name}} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+                   {% else %} {# authority #}
+               Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
+                   {% endif %}
+               {% endif %}
+                       </td>
+                       <td>{{ request.timestamp }}</td>
+                       
+                       <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
+       
+           <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+                 </tr>
+           {% endfor %}
+           </table>
+       </div>
+       {% endfor %}
+{% else %}
+<div class="col-md-12">
+       <i>There is no pending request waiting for validation.</i>
+</div>
+{% endif %}
+
+<div class="col-md-12">
+       <h2>Authorities with delegation</h2>
+</div>
+
+{% if delegation_authorities %}
+       
+       {% for authority, requests in delegation_authorities.items %}
+       <div class="col-md-12">
+               <h3>{{authority}}</h3>
+                   <table class="table">
+                     <th>
+                       <td>Type</td>
+                       <td>Id</td>
+                       <td>Details</td>
+                       <td>Timestamp</td>
+                       <td>Status</td>
+                     </th>
+                   {% for request in requests %}
+                         <tr>
+                               <td>
+                               {% if request.allowed == 'allowed' %}
+                               <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
+                               {% else %}
+                                       {% if request.allowed == 'expired' %}
+                                               expired
+                                       {% else %} {# denied #}
+                                               denied
+                                       {% endif %}
+                               {% endif %}
+                               </td>
+                               <td>{{ request.type }}</td>
+                               <td>{{ request.id }}</td>
+                               <td>
+                       {% if request.type == 'user' %}
+                       Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
+                       {% else %}
+                           {% if request.type == 'slice' %}
+                       Slice name: {{request.slice_name}} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+                           {% else %} {# authority #}
+                       Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
+                           {% endif %}
+                      {% endif %}
+                               </td>
+                               <td>{{ request.timestamp }}</td>
+                               
+                               <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
+               
+                   <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+                         </tr>
+                   {% endfor %}
+                   </table>
+               </div>
+               {% endfor %}
+{% else %}
+<div class="col-md-12">
+       <i>There is no pending request waiting for validation.</i>
+</div>
+{% endif %}
+<div class="col-md-12">
+       <button class="btn btn-primary" type="button" id="portal__validate" onclick="on_click_event();"><span class="glyphicon glyphicon-ok"></span> Validate</button>
+</div>
index a06b125..69b417d 100644 (file)
@@ -4,15 +4,17 @@
 <div class="container">
     <div class="row">
         <div class="col-md-12">
-               <h1><a href="#about"><img src="{{ STATIC_URL }}icons/slices-xs.png" alt="News" />News</a></h1>
+               <h1><img src="{{ STATIC_URL }}icons/slices-xs.png" alt="News" />News</h1>
                <br />
         </div>
     </div>
  
        <div class="row">
         <div class="col-md-12">
-
-               The <b>OneLab</b> Portal opens with the <b>PlanetLab Europe</b>, <b>IOTLab</b> and <b>NITOS</b> testbeds!
+               <b>15 July 2014</b> - The <b>OneLab</b> Portal opens with the <b>PlanetLab Europe</b>, <b>IOTLab</b> and <b>NITOS</b> testbeds!
+               <p>
+                       Existing PlanetLab users will be able to open an account with their existing PLE credentials.
+               </p>
                </div>
        </div>
 </div>
diff --git a/portal/templates/onelab/onelab_registration_view.html b/portal/templates/onelab/onelab_registration_view.html
new file mode 100644 (file)
index 0000000..2efee42
--- /dev/null
@@ -0,0 +1,547 @@
+{% extends "layout.html" %}
+
+{% block content %}        
+
+<div class="row">
+       <div class="col-md-12">
+       <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>
+{% if errors %}
+<ul>
+  {% for error in errors %}
+  <li>{{ error }}</li>
+  {% endfor %}
+</ul>
+{% endif %}
+<div class="row">
+       <div class="col-md-12">
+               
+                       <div class="form-group">
+                               <form class="cmxform form-horizontal" id="registrationForm" method="post" enctype="multipart/form-data" role="form">
+                       {% csrf_token %}
+                               <label for="authority_hrn" class="control-label">Organization</label>
+                               <p></p>
+                               <input id="authority_hrn" name="org_name" class="form-control" style="width:590px" value="{{ organization }}" 
+                               title="Choose your organization (company/university) from the list that apears when you click in the field and start to type.
+                                Use the arrow keys to scroll through the list; type part of the name to narrow down the list. If it is not in the list, 
+                               please request its addition by clicking the link below. We will send an email to the managers that we have on record for 
+                               your organization, asking them to validate your sign-up request." required/>
+                               <p></p>
+                               <p>Organization not listed? <a href="/portal/join">Request its addition now.</a></p>
+                       </div>
+       </div>
+</div>
+
+<div class="row">
+       <div class="col-md-6">
+       
+           <div class="form-group">
+                       <label for="firstname" class="control-label">Personal information</label>
+                       <p></p>
+                       <input type="text" name="firstname" class="form-control" style="width:350px" minlength="2" value="{{ first_name }}" placeholder="First name" required />
+           </div>
+           <div class="form-group">
+                       <input type="text" name="lastname" size="25" class="form-control" style="width:350px" minlength="2" value="{{ last_name }}" placeholder="Last name" required />
+           </div>
+               <div class="form-group">
+               <input type="email" name="email" size="25"  class="form-control" style="width:350px" value="{{ email }}" 
+                       title="Your e-mail address will be your identifier for logging in. We contact you to verify your account and then, occasionally, for important issues."
+                       placeholder="Email" required/>
+               </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/>
+           </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/>
+           </div>
+           <div class="form-group">
+               <!--<label for="question" class="control-label">Keys</label> -->
+                       <select name="question" class="form-control" style="width:350px" id="key-policy" 
+                               title="Your public/private key pair allows you to access the testbeds." required>        
+                               <option value="generate">Generate my keys for me (recommended)</option>
+                               <option value="upload">Upload my public key (advanced users only)</option>
+                       </select>
+           </div>
+           <div class="form-group" style="display:none;" id="upload_key">
+               <label for="file" class="control-label">Upload public key</label>
+               <input type="file" name="user_public_key" class="form-control" style="width:200px" id="user_public_key" required/>
+               <br />
+                       <div class="alert alert-danger" id="pkey_del_msg">
+                               In order for the portal to contact testbeds on your behalf, so as to list and reserve resources, you will need to 
+                               <a href="http://trac.myslice.info/wiki/InstallSfa" target="_blank">delegate your public key to the portal.</a>
+                       </div>
+           </div>
+       </div>
+</div>
+<div class="row">
+       <div class="col-md-12">
+               <div class="form-group">
+                       <p></p>
+                       <input type="checkbox" name="agreement" value="agreement" required/>&nbsp;&nbsp; I agree to the 
+                       <a href="#" data-toggle="modal" data-target="#myModal">terms and conditions.</a> 
+               </div>
+       </div>
+</div>
+<div class="row">
+       <div class="col-md-10">
+               <div class="form-group" id="register">
+                       <span class="glyphicon glyphicon-info-sign"></span> &nbsp;
+               If you are a <b>PlanetLab Europe</b> fill in this form using the same email address that you currently use for your PlanetLab Europe account,
+               your existing credentials will be used to validate your OneLab account.
+               Please be sure to specify a different password for your new OneLab account.
+           </div>
+       </form> 
+       </div>
+</div>
+<div class="row">
+       <div class="col-md-12">
+               <div class="form-group" id="register">
+                       <p></p> 
+               <button class="submit btn btn-onelab" type="submit">Sign up</button>
+           </div>
+       </form> 
+       </div>
+</div>
+       
+       
+       <!-- Modal - columns selector -->
+               <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
+                       <div class="modal-dialog">
+                       <div class="modal-content">
+                               <div class="modal-header">
+                                       <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+                                               <h4 class="modal-title" id="myModalLabel">Terms & Conditions</h4>
+                               </div>
+                               <div class="modal-body">
+                                               <p align="left">
+                                       for OneLab Basic level service
+                                       <br/>
+                                       Version 0.6 of 20 May 2014
+                                               <br>
+                                               <a href="/portal/terms" target="_blank">[Printable format]</a>
+                                               </p>
+                                       <h1 align="left">1 Context</h1>
+                                       <h2 align="left">1.1 OneLab</h2>
+                                       <p align="left">
+                               OneLab is an experimental facility for testing new ideas and new technologies in the area of computer networking. It consists of a variety of types of
+                               platforms, including:</p>
+                                       <ul type="disc">
+                               <li>
+                               <strong>internet overlay testbeds</strong>
+                               , testbeds that offer virtual machines distributed across locations in different countries, allowing users to deploy overlays on the internet;
+                               </li>
+                               <li>
+                               <strong>wireless testbeds</strong>
+                               , testbeds that consist of clusters of computers that are within Wi-Fi communication range of each other, either in an office environment or in an
+                               isolated setting;
+                               </li>
+                               <li>
+                               <strong>internet of things testbeds</strong>
+                               , testbeds that consist of embedded computing nodes with sensor capabilities, communicating wirelessly in an isolated environment;
+                               </li>
+                               <li>
+                               <strong>emulation testbeds,</strong>
+                               computing clusters that offer virtual machines on servers that are interconnected by a high speed switch, enabling large scale network emulation.
+                               </li>
+                                       </ul>
+                                       <p align="left">
+                               This list of types of platforms is subject to change, and the current list, along with the identities of the specific platforms of each type, can be found
+                               on the OneLab website (onelab.eu).</p>
+                                       <p align="left">
+                               Each platform has its own owners, and OneLab is the grouping of these platforms through a consortium of institutions. The OneLab consortium is coordinated
+                               by UPMC Sorbonne Universités. It operates on a not-for-profit basis.</p>
+                                       <p align="left">
+                               Access to OneLab may also provide access to additional platforms that are not part of OneLab, due to a federation agreement between OneLab and the owners
+                               of those platforms.</p>
+                                       <h2 align="left">1.2 Fee-free Basic level service</h2>
+                                       <p align="left">These terms and conditions define and apply to OneLab's Basic level service, which is available free of charge.</p>
+                                       <p align="left">
+                               Users who would like additional services are encouraged to contact support@onelab.eu. Some additional services require a written agreement, but are
+                               otherwise free. Others require the payment of fees or in-kind contributions. (An example of an in-kind contribution is the hosting of a PlanetLab Europe
+                               server node.)</p>
+                                       <h2 align="left">1.3 Managers and standard users</h2>
+                                       <p align="left">
+                               There are two classes of OneLab user: the manager and the standard user. OneLab grants access rights to managers, who, in turn, provide access rights to
+                                       standard users. Examples are: for a small enterprise, an executive may be the manager and the employees may be standard users; for a research team, a
+                               senior scientist (faculty member or research scientist) may be a manager and doctoral students and other members of the team may be standard users; for a
+                               university course, a professor may be a manager and the students may be standard users.</p>
+                                       <h2 align="left">1.4 These terms and conditions</h2>
+                                       <p align="left">
+                               Acceptance of these terms and conditions is a condition of obtaining OneLab Basic level user service. They are posted to the OneLab portal site
+                               (portal.onelab.eu). They may be changed without other notice than the posting of a new version to the portal site.</p>
+                                       <h1 align="left">2 Services provided by OneLab</h1>
+                                       <h2 align="left">2.1 Access to the experimental facility</h2>
+                                       <p align="left">
+                               OneLab provides users with access to the platforms that make up the experimental facility. Each platform owner determines the specifics of this access (for
+                               example, how many nodes are available to a user, what happens in case of oversubscription, etc.), with the proviso that Basic level service requires that
+                                       users be able to conduct meaningful experiments on every OneLab testbed.</p>
+                                       <p align="left">
+                               Basic level service may also provide access to platforms that are federated with OneLab, but such access depends upon the terms of the federation
+                               agreements with those platforms, which may require that the user have a higher level of service in order to gain access. For example, Basic level service
+                               provides access to PlanetLab Europe, a OneLab platform, without providing access to PlanetLab Central, a federated platform. Users wanting full access
+                               across the global PlanetLab system should contact support@onelab.eu to arrange to enter into a PlanetLab Europe membership agreement.</p>
+                                       <p align="left">OneLab's role is to facilitate access to the platforms. Specifically, it provides each user with:</p>
+                                       <ul>
+                               <li align="left">
+                               <strong>a single account,</strong>
+                               the credentials for which can be used to access all of the OneLab testbeds;
+                               </li>
+                               <li align="left">
+                               <strong>tools through which to access the testbeds</strong>
+                               , including, notably, a web-based portal (portal.onelab.eu) that allows a user to see the resources available on each testbed and to reserve them,
+                               along with a number of experiment control tools that a user can employ to deploy an experiment on those resources;
+                               </li>
+                               <li align="left">
+                               <strong>support</strong>
+                               , with documentation on how to use the tools, pointers to documentation for individual testbeds, and a helpdesk to respond to user questions.
+                               </li>
+                                       </ul>
+<p align="left">
+    Additional support, such as accompaniment through the design and deployment of experiments and the interpretation of their results, is available through
+    higher levels of service.
+</p>
+<h2 align="left">
+    2.2 Best effort, without guarantees
+</h2>
+<p align="left">
+    OneLab and the owners of the individual OneLab testbeds do their best to provide the services outlined here, with the understanding that Basic level
+    service offers no guarantees. Users should clearly understand the following limitations.
+</p>
+<ul type="disc">
+    <li>
+        <strong>Reliability:</strong>
+        OneLab does not provide any guarantees with respect to the reliability of the portal, of other tools, or of the individual nodes on platforms. These
+        may be taken down for maintenance, rebooted, or reinstalled at any time. Reinstallation implies that disks are wiped, meaning that users should not
+        consider a local disk to be a persistent form of storage.
+    </li>
+    <li>
+        <strong>Fitness:</strong>
+        OneLab does not guarantee that the platforms are suitable for the experiments that users intend to conduct. There may be limitations in the
+        technologies that are offered that prevent certain types of experiments from being carried out.
+    </li>
+    <li>
+        <strong>Privacy</strong>
+        : OneLab does not guarantee the privacy of traffic generated on the platforms (e.g., wireless signals, packets). Unless otherwise specified by an
+        individual platform owner, users should assume that traffic is monitored and logged. Such monitoring may be done intentionally, for example, to allow
+        platform administrators as well as other users to investigate abuse.
+    </li>
+</ul>
+<p align="left">
+    Users who seek such guarantees are invited to consider a higher level of service.
+</p>
+<h2 align="left">
+    2.3 Limitedliability
+</h2>
+<p align="left">
+    In no event shall the partners of the OneLab consortium be liable to any user for any consequential, incidental, punitive, or lost profit damages, or for
+    any damages arising out of loss of use or loss of data, to the extent that such damages arise out of the activities of OneLab consortium partners, or any
+    breach of the present terms and conditions, even if the consortium partner has been advised of the possibility of such damages.
+</p>
+<p align="left">
+    Nothing contained in these terms and conditions shall be deemed as creating any rights or liabilities in or for third parties who are not Basic level users
+    of OneLab.
+</p>
+<h1 align="left">
+    3 Acceptable use policy
+</h1>
+<h2 align="left">
+    3.1 Responsibilities of managers and standard users
+</h2>
+<p align="left">
+    OneLab creates and administers accounts for managers and delegates to managers the responsibility for creating and administering accounts for standard
+    users. Both managers and standard users are required to follow OneLab's acceptable use policy. In addition, managers are fully responsible for the
+    activities of the standard users whose accounts they create.
+</p>
+<p align="left">
+    A manager is expected to grant user access only an individual with whom he or she has a working relationship. In general, this means an individual who
+    works for the same institution as the manager, or, in the case of higher education and research, an individual who is a student at the university where the
+    manager works. Managers may also grant access to individuals from other institutions, provided that they are collaborating on a common project on OneLab.
+    If there is a doubt, a manager should refer the question to support@onelab.eu.
+</p>
+<h2 align="left">
+    3.2 Types of use
+</h2>
+<p align="left">
+    OneLab may be used by enterprise, by scientific researchers, and by educators.
+</p>
+<p align="left">
+    OneLab may be used for pre-commercial research and development. In keeping with OneLab's not-for-profit status, it may not be used to deploy services that
+    are designed to generate a commercial profit.
+</p>
+<p align="left">
+    Not-for-profit use of OneLab to deploy services that are designed to generate revenue requires prior approval through a written agreement, and thus may not
+    be carried out on a Basic level account. Interested users are invited to contact support@onelab.eu.
+</p>
+<p align="left">
+    OneLab may be used for scientific research.
+</p>
+<p align="left">
+    OneLab may be used to host lab exercises for university courses.
+</p>
+<p align="left">
+    Questions about other types of use should be addressed to support@onelab.eu.
+</p>
+<h2 align="left">
+    3.3 Applicable laws and regulations
+</h2>
+<p align="left">
+    OneLab is managed, and the portal is hosted, in France. Information regarding the countries in which individual testbeds are managed and hosted is
+    available from those testbeds. Users are responsible for being aware of the countries in which their experiments are deployed and for ensuring that their
+    use of OneLab fully conforms to the laws and regulations of those countries, as well as the laws and regulations of the country in which they themselves
+    are present when conducting their experiments.
+</p>
+<p align="left">
+    Above and beyond specific national laws, the activities email spamming, phishing through web services, and all types of Internet fraud are prohibited on
+    OneLab.
+</p>
+<h2>
+    3.4 Security and accounting mechanisms
+</h2>
+<p align="left">
+    Users are expected to respect the security and accounting mechanisms put in place by OneLab, its platforms, and federated platforms. For example, access to
+    PlanetLab Europe is designed to take place through the SSH cryptographically-secured connection protocol, which uses public/private key pair
+    authentication, and so users should not attempt to bypass this mechanism. As another example, OneLab's notion of a "slice" associates a set of resources
+    with the group of users who have reserved those resources, and users should not attempt to obscure the identities of participants in a slice.
+</p>
+<p align="left">
+    Hacking attempts against the OneLab portal and testbeds are not permitted. This includes "red team" (hacker test) experiments.
+</p>
+<h2>
+    3.5 Sharing of resources
+</h2>
+<p align="left">
+    OneLab is intended for ambitious experiments. Large numbers of resources and extended leases on resources may legitimately be granted in order to carry
+    these out. At the same time, OneLab and its testbeds are shared environments, and when there is contention for resources, limits must be imposed.
+</p>
+<p align="left">
+    Each OneLab platform sets its own policies for handling resource contention. As a general rule, users are encouraged to design their experiments to use
+    resources efficiently. In particular, spinning/busy-waiting techniques for extended periods of time are strongly discouraged. Some resource contention
+    policies (e.g., PlanetLab Europe's) terminate the jobs that are using the most resources in the case of contention.
+</p>
+<h2>
+    3.6 Internet-connected platforms
+</h2>
+<p align="left">
+    Some of OneLab's platforms allow experiments to take place on resources that have access to the public internet. These experiments can potentially generate
+    traffic to, and receive traffic from, any host or router in the internet.<a></a><a id="_anchor_1" href="#_msocom_1" name="_msoanchor_1">[LB1]</a>
+</p>
+<p align="left">
+    Furthermore, some internet-connected platforms (e.g., PlanetLab Europe) consist of servers that are hosted by a large number of member institutions.
+</p>
+<p align="left">
+    The accessibility of internet-connected platforms and the distributed hosting model of some of these platforms imply certain responsibilities on the part
+    of users, as detailed below.
+</p>
+<h3>
+    3.6.1 General guidance
+</h3>
+<p align="left">
+    A good litmus test when considering whether an experiment is appropriate for such internet-connected platforms is to ask what the network administrator at
+    one's own organisation would say about the experiment running locally. If the experiment disrupts local activity (e.g., uses more than its share of the
+    site's internet bandwidth) or triggers complaints from remote network administrators (e.g., performs systematic port scans), then it is not appropriate for
+    such internet-connected platforms.
+</p>
+<p align="left">
+    It is the responsibility of the user and the user's manager to ensure that an application that will run on an internet-connected platform is tested and
+    debugged in a controlled environment, to better understand its behaviour prior to deployment.
+</p>
+<h3>
+    3.6.2 Standards of network etiquette
+</h3>
+<p align="left">
+    Internet-connected platforms are designed to support experiments that generate unusual traffic, such as network measurements. However, it is expected that
+    all users adhere to widely accepted standards of network etiquette in an effort to minimise complaints from network administrators. Activities that have
+    been interpreted as worm and denial-of-service attacks in the past (and should be avoided) include sending SYN packets to port 80 on random machines,
+    probing random IP addresses, repeatedly pinging routers, overloading bottleneck links with measurement traffic, and probing a single target machine from
+    many nodes.
+</p>
+<p align="left">
+    For internet-connected platforms that have a distributed hosting model, each host institution will have its own acceptable use policy. Users should not
+    knowingly violate such local policies. Conflicts between local policies and OneLab's stated goal of supporting research into wide-area networks should be
+    brought to the attention of OneLab administrators at support@onelab.eu.
+</p>
+<h3>
+    3.6.3 Specific network usage rules
+</h3>
+<p align="left">
+    It is not allowed to use one or more nodes of an internet-connected platform to generate a high number of network flows or flood a site with high traffic
+    to the point of interfering with its normal operation. Use of congestion-controlled flows for large transfers is highly encouraged.
+</p>
+<p align="left">
+    It is not allowed to perform systematic or random port or address block scans from an internet-connected platform.
+</p>
+<p align="left">
+    For internet-connected platforms that use a distributed hosting model, it is not allowed to spoof or sniff traffic on a hosted server or on the network the
+    server belongs to.
+</p>
+<p align="left">
+    Access to a server on a distributed hosting platform may not be used to gain access to other servers or networked equipment that are not part of the
+    testbed.
+</p>
+<h2>
+    3.7 Wireless platforms
+</h2>
+<p align="left">
+    Wireless-connected platforms give users access to nodes that communicate via Wi-Fi and other wireless technologies. They may be capable of detecting
+    wireless activity in the neighbourhood of those nodes: traffic generated by other users of the platform or by individuals not associated with the platform.
+    In general, much of the traffic will be encrypted, with certain aspects (such as SSIDs) not encrypted, but it is also possible that there will be fully
+    unencrypted traffic. They may also be capable of generating wireless activity that reaches equipment outside of the testbed.
+</p>
+<p align="left">
+    Furthermore, some wireless-connected platforms may have built-in limitations to prevent them from generating signals at a strength that exceeds health and
+    safety regulations.
+</p>
+<p align="left">
+    These characteristics of wireless-connected platforms imply certain responsibilities on the part of users, as detailed below.
+</p>
+<h3>
+    3.7.1 Specific network usage rules
+</h3>
+<p align="left">
+    Experimenters may make no attempt to defeat the encryption of encrypted third-party traffic. Furthermore, experimenters must treat with utmost discretion
+    any unencrypted traffic. Limited metadata can be recorded for the bona fide purposes of an experiment, but under no case should third party communications
+    be recorded.
+</p>
+<p align="left">
+    No attempt may be made to reverse engineer traffic in order to learn the identities of the parties who have generated the traffic.
+</p>
+<p align="left">
+    Wireless-connected platforms may not be used to gain access to any network equipment that is not part of the testbed itself.
+</p>
+<p align="left">
+    It is not allowed to perform systematic or random scans of wireless networks that are not part of a wireless-connected platform. Similarly, it is not
+    allowed to spoof or sniff wireless traffic of the institution that hosts a wireless-connected platform or of other networks in the proximity.
+</p>
+<p align="left">
+    Care must be taken so that traffic on wireless-connected platforms does not interfere with the normal functioning of network equipment that is not part of
+    the testbed itself.
+</p>
+<p align="left">
+    No attempt may be made to defeat the mechanisms that limit signal strength on wireless-connected platforms.
+</p>
+<h2>
+    3.8 Handling suspected violations
+</h2>
+<p align="left">
+    Suspected violations of the OneLab acceptable use policy should be reported to support@onelab.eu.
+</p>
+<p align="left">
+    Upon notification or detection of a possible violation, OneLab management will attempt to understand if a violation has in fact occurred. To do so,
+    management will freely communicate with the users concerned, the operators of the platforms concerned, as well as any third parties that might be involved.
+    An example of a third party is a network operator who detects what they believe to be unauthorized traffic emanating from a OneLab platform.
+</p>
+<p align="left">
+    The priority is to resolve any real or apparent violations amicably. However, if OneLab management believes that a violation may have occurred, it can, at
+    its sole discretion, and without prior notice, apply any of the following measures:
+</p>
+<ul type="disc">
+    <li>
+        notification of the users of the concerned slice (set of resources);
+    </li>
+    <li>
+        disabling of the concerned slice;
+    </li>
+    <li>
+        disabling an individual user's account;
+    </li>
+    <li>
+        reporting of the user's activity to his/her manager;
+    </li>
+    <li>
+        disabling of the manager's account and all user accounts for which the manager is responsible;
+    </li>
+    <li>
+        disabling of all accounts associated with the user's institution.
+    </li>
+</ul>
+<p align="left">
+    In the case of suspected illegal activity, OneLab management might need, without prior notice, to notify the relevant authorities.
+</p>
+<div>
+    <div>
+        <div id="_com_1">
+        </div>
+    </div>
+</div>
+                               </div>
+                               <div class="modal-footer">
+                                       <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                               </div>
+                       </div>
+                       </div>
+               </div>
+
+    
+<script>
+jQuery(document).ready(function(){
+    var availableTags = [
+    {% if authorities %}
+        {% for authority in authorities %}
+            {% if authority.name %}
+                {value:"{{ authority.name }}",label:"{{authority.name}}"},
+                       // to show only full name
+           // {% else %}
+           //     {value:"{{ authority.authority_hrn }}",label:"{{authority.authority_hrn}}"},
+            {% endif %}
+        {% endfor %}    
+    {% else %}
+        {value:"",label:"No authority found !!!"}
+    {% endif %}
+    ];
+       // sorting the list
+       availableTags.sort(function(a,b){
+               var nameA=a.value.toLowerCase(), nameB=b.value.toLowerCase();
+               if (nameA < nameB) {
+               return -1;
+               }
+               if (nameA > nameB) {
+               return 1;
+               }
+       return 0;
+       }); 
+       // auto-complete the form
+    jQuery( "#authority_hrn" ).autocomplete({
+      source: availableTags,
+      minLength: 0,
+      change: function (event, ui) {
+          if(!ui.item){
+              //http://api.jqueryui.com/autocomplete/#event-change -
+              // The item selected from the menu, if any. Otherwise the property is null
+              //so clear the item for force selection
+              jQuery("#authority_hrn").val("");
+          }
+      }
+      //select: function( event, ui ) {console.log(jQuery(this))}
+    });
+       // for hover texts
+       jQuery('[title!=""]').qtip();
+});
+</script>
+{% endblock %}
+
diff --git a/portal/templates/onelab/onelab_slicerequest_view.html b/portal/templates/onelab/onelab_slicerequest_view.html
new file mode 100644 (file)
index 0000000..ef0ca28
--- /dev/null
@@ -0,0 +1,87 @@
+{% extends "layout.html" %}
+{% load i18n %}
+
+{% block content %}
+       <div class="row">
+               <div class="col-md-12">
+                        <div class="breadcrumbs">
+                                Experiment &nbsp;>&nbsp; Request a new Slice
+                        </div>
+               </div>
+       </div>
+
+       {% if errors %}
+       <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-8 el">
+                       <form role="form" method="post">
+                       {% csrf_token %}
+                         <div class="form-group" style="display:none">
+                           <input type="email" class="form-control" id="email" style="width:300px" value="{{ email }}" readonly="readonly">
+                         </div>
+                         <div class="form-group">
+                           <input type="text" class="form-control" name="slice_name" id="slice_name" style="width:300px" placeholder="Slice Name" 
+                               title="Please enter a name for your slice"required="required">
+                         </div>
+                         <div class="form-group">
+                               {%if 'is_pi'  in pi %}
+                               <input type="text" class="form-control" id="authority_hrn" name="authority_hrn" style="width:300px" placeholder="Authority" 
+                               title="An authority responsible for vetting your slice" required="required">
+                               {%else%}
+                           <input type="text" class="form-control" id="authority_hrn" name="authority_hrn" placeholder="Authority" style="width:300px; display:none;" 
+                               title="An authority responsible for vetting your slice" required="required" readonly="readonly">
+                               {%endif%}
+                         </div>
+                         <div class="form-group">
+                           <input type="number" class="form-control" name="number_of_nodes" id="number_of_nodes" style="width:300px" placeholder="Number of Nodes"
+                               title="Number of nodes you expect to request (informative)">
+                         </div>
+                         <div class="form-group">
+                               <textarea id="purpose" name="purpose" class="form-control" rows="6" placeholder="Experiment Purpose" style="width:300px" 
+                               title="Purpose of your experiment (informative)" required="required">{{ purpose }}</textarea>
+                         </div>
+                         <button type="submit" class="btn btn-onelab"><span class="glyphicon glyphicon-plus"></span> Request Slice</button>
+                       </form>
+       
+               </div>
+       </div>
+               
+<script>
+jQuery(document).ready(function(){
+       
+       $("#authority_hrn").load("/rest/user/", {"fields" : ["parent_authority"], "filters": {"user_hrn": "{{ user_hrn }}"}}, function(data) {
+               var jsonData = JSON.parse(data);
+        $(this).attr("value", jsonData[0]['parent_authority']);
+    });
+    var availableTags = [
+     {% if authorities %}
+         {% for authority in authorities %}
+             {% if authority.name %}
+                 {value:"{{ authority.authority_hrn }}",label:"{{authority.name}}"},
+             {% else %}
+                 {value:"{{ authority.authority_hrn }}",label:"{{authority.authority_hrn}}"},
+             {% endif %}
+         {% endfor %}    
+     {% else %}
+         {value:"",label:"No authority found !!!"}
+     {% endif %}
+    ];
+    $( "#authority_hrn" ).autocomplete({
+      source: availableTags,
+      minLength: 0,
+      select: function( event, ui ) {console.log(jQuery(this));}
+    });
+});
+</script>
+{% endblock %}
+
diff --git a/portal/templates/onelab/onelab_supportview.html b/portal/templates/onelab/onelab_supportview.html
new file mode 100644 (file)
index 0000000..e33127c
--- /dev/null
@@ -0,0 +1,143 @@
+{% extends "layout_wide.html" %}
+
+{% block content %}
+<div class="container">
+       <div class="row">
+               <div class="col-md-12">
+                        <div class="breadcrumbs">
+                                Support
+                        </div>
+               </div>
+       </div>
+</div>
+<div class="container">
+       <div class="row">
+               <div class="col-md-12">
+                       <ul class="nav nav-tabs nav-section">
+                               <li class="active"><a href="#support">Tickets</a></li>
+                               <li><a href="#faq">FAQ</a></li>
+                               <li><a href="#contact">Contact</a></li>
+                       </ul>
+           </div>
+       </div>
+</div>
+
+<div class="container tab-content">
+       <div class="tab-pane active row" id="support">
+               <div class="col-md-12">
+                       <h2>Report a Bug</h2>
+                       <p>If you have found a bug or having difficulties accesing some features or found some anomalies, please report it using our ticketing system.</p>
+                       <button id="ticketbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create Ticket</button>
+<!--                   <h3>Unresolved Tickets</h3>
+                       <table class="mytable table table-bordered table-hover">
+                       <tr>
+                           <th>Ticket No</th>
+                                       <th>Reported By</th>
+                                       <th>Description</th>
+                           <th>Status</th>
+                       </tr>
+                       <tr>
+                           <td>1</td>
+                                       <td>yasin.upmc@gmail.com</td>
+                                       <td> Slice_request page is not working </td>
+                                       <td> Unresolved</td>
+                       </tr>
+                               <tr>
+                                       <td>2</td>
+                                       <td>azerty@lip6.fr</td>
+                                       <td>Unable to Register</td>
+                                       <td>Unresolved</td>
+                               </tr> 
+               
+                   </table> -->
+               </div>
+         </div>
+       <div class="tab-pane row" id="faq">
+               <div class="col-md-12">
+                       <h2>Frequently Asked Questions (FAQs)<h2>
+
+                       <h3>Users</h3>
+                       <ul>
+                       <li><h4>Who is a user?</h4></li>
+                       <p>A user is an experimenter who registers to the OneLab portal and able to use all the facilites that the portal has to offer. However, a user does not
+                       have the right to do any admin operation such as managing slices, users and resources.</p>
+                       
+                       
+                       <li><h4>How do I register?</h4></li>
+                       <p>In order to register you must go to the <a href="/portal/register">Registration</a> page. You have to choose your corresponding institution (authority). After registration you have to wait until the PI validates your account. However upon registration, you will be able login to the portal with a limited access. Do not try to re-register with the same email address.</p>
+                       
+                       <li><h4>Why can't I register with my email?</h4></li>
+                       <p>If you have already registered then you won't be able to register again with the same email address. However, if you have never registered and still you are not able to use your email then please 
+                       <a href="/portal/contact">Contact Support</a> and mention the error message that you are getting while trying to register.</p>
+                       
+                       <li><h4>In registration, in "My keys" option, what should i choose?</h4></li>
+                       <p>There are two choices.</p> 
+                               <p class="text-justify"><b>1. Generate Key Pairs:</b> This option is for users who have no knowledge about SFA and MySlice i.e., new users. We offer convenience to the new users in order to avoid addtional efforts to delegate keys manually. If you choose this option, the portal will automatically handle your credentials and you would be able use the portal as soon as the PI validates your account. However, you can delete your private key from the portal if you are concerned about privacy issues. In that case once your current credentials expire, you have to delegate your credentials manually using <a href="http://trac.myslice.info/wiki/InstallSfa" target="_blank">SFA</a>. As this needs advance knowledge about SFA and Myslice, we highly recommend to the new users to keep both private and public keys in the portal in order to keep the process automatic. </p>
+                               <p class="text-justify"><b>2. Upload My Public Key:</b> This option is for users who have experience with MySlice and SFA. If you choose this option, once the PI validates your account, you have to delegate your credentials manually using <a href="http://trac.myslice.info/wiki/InstallSfa" target="_blank">SFA</a>. You have to repeat the same process everytime your credentials expire. Normally, credentials expire every one month. You can see the expiration date in your Account page. </p>
+                       
+                       <li><h4>Who is responsible for validating my account?</h4></li>
+                       <p>When you register, you choose an authority fromt he list of authorities. For each authority there is a Principal Investigator (PI). PI of your authority will verify your identity and if he finds that you are from his institution, he will validate your account otherwise he will reject your account.</p>
+                       
+                       <li><h4>How long I have to wait for validation?</h4></li>
+                       <p>It depends on the PI of your authority. In general, it should not take more than a week. If you are waiting more than usual, please <a href="/portal/contact">Contact Support</a> and explain your problem.</p>
+                       <li><h4>I just registered. Why can't I see any slices and resources?</h4></li>
+                       <p>Once you register, you can login to your account with limited access. It means that you can view your account details, modify your name and password. You can also view other pages. However, you will not be able to see any slices as well as resources before your account validation. But you can <a href="/portal/slice_request/">Request Slice</a> before being validated. Therefore, the PI will validate your account as well as your requested slice. Once validated, you will be able to see your slice and if you click on your slice, you will be able to see resources in that slice and you can reserve nodes and start your experiment.</p>
+                       
+                       <li><h4>How can I get access to a slice?</h4></li>
+                       <p>If you are a completely new user, you have to <a href="/portal/slice_request/">Request Slice</a>. It is upto the PI of your authority to accept/reject your slice request. </br>On the other hand, if you are a new user to the portal but you already have an account in OneLab SFA registry and you have access to slices, you will be able to see all your slices once your account is validated by the PI.</p> 
+                       
+                       <li><h4>I forgot my password, how to recover it?</h4></li>
+                       <p>If you have an account in the portal but you forgot the password, you can always <a href="/portal/pass_reset/">Reset your password</a>.</p></ul>
+                       
+                       <h3>Managers</h3>
+                       <ul>
+                       <li><h4>Who is a manager?</h4></li>
+                       <p>A manager is the Principal Investigator (PI) of the institution. Each PI has authority over his own institution. A PI can add, delete, validate users/ 
+                       slices that belong to his institution.</p>
+                       
+                       <li><h4>What is pending users/slices?</h4></li>
+                       <p>In <a href="/portal/validate">Requests</a> page you will be able to see all the users that registered under your authority and the slices that users of your authority has requested. Therefore, pending users/slices are those users and slices that are yet to be validated. You can validate/reject these requests based on the policy of your institution.</p>
+                       
+                       <li><h4>How can I manage the users/slices that belong to my institution?</h4></li>
+                       <p>In <a href="/portal/institution">Instution</a> page, under "Users" tab, you will be able to see all the users that belong to your authority. You can delete the users that you don't want anymore. Under "Slices" tab, you will be able to see all the slices that belong to your authority. You can renew/delete the slices based on your requirements. As a PI you can also <a href="/portal/slice_request/">Create Slice</a>. Just fill the form of request slice and the slice will be automatically validated if it is requested by a PI. </p>
+                       
+                       </ul>
+               </div>
+         </div>
+
+       <div class="tab-pane row" id="contact">
+               <div class="col-md-12">
+                       <h2>Contact Us</h2>
+               
+                       <h3>Mailing List</h3>
+                       <p>You can subscribe to our mailing list by sending a request to: <b>support</b> AT <b>myslice</b> DOT <b>info</b></p>
+                       <p>Also you can adress any issues in the same email address.</p>
+                       
+                       <h3>Mailing Address</h3>
+                       <address>
+                       UPMC - LIP6<br> 
+                       Boîte courrier 16 <br>
+                       Couloir 26-00, Etage 01, Bureau 102<br>
+                       4 place Jussieu<br>
+                       75252 PARIS CEDEX 05<br>
+                       France<br> 
+                       </address>
+               </div>
+         </div>
+</div>
+
+<script>
+$(document).ready(function() {
+    $('button#ticketbtn').click(function() {
+        window.location="/portal/contact/";
+    });
+       $('.nav-tabs a').click(function (e) {
+               e.preventDefault();
+               $(this).tab('show');
+       });
+});
+</script>
+
+
+{% endblock %}
+
index fad0c26..d7342f8 100644 (file)
@@ -14,7 +14,7 @@
        <input type="password" name="password" placeholder="Password">
        </div>
        <div class="login-submit">
-               <input type="submit" value="Sign In" />
+               <input type="submit" class="btn btn-onelab" value="Sign In" />
                <span class="lost-password">&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;<a href="/portal/pass_reset/">Can't access your account?</a></span>
        </div>
        <div class="login-signup">
index 0d0673f..bef7c00 100644 (file)
@@ -1,22 +1,29 @@
+<div class="row">
+       <div class="col-md-12">
+                <div class="breadcrumbs">
+                        Experiment &nbsp;>&nbsp; {{ slice }}
+                </div>
+       </div>
+</div>
 {% if section == "resources" %}
 <ul class="nav nav-tabs nav-section">
-       <li><a href="/slice/{{ slice }}#info"><img src="{{ STATIC_URL }}icons/slices-xs.png" alt="About MySlice" /> {{ slice }}</a></li>
+       <li><a href="/slice/{{ slice }}#info">Information</a></li>
        <!-- <li><a href="/slice/{{ slice }}#testbeds">Testbeds</a></li> -->
        <li class="active"><a class="link" href="/resources/{{ slice }}">Resources</a></li>
        <li><a href="/slice/{{ slice }}#users">Users</a></li>
        <!-- <li><a href="/slice/{{ slice }}#experiment">Statistics</a></li> -->
        <!-- <li><a href="/slice/{{ slice }}#experiment">Measurements</a></li> -->
-       <li><a href="/slice/{{ slice }}#experiment" data-toggle="tab">Experiment</a></li>
+       <li><a href="/slice/{{ slice }}#experiment">Tools</a></li>
 </ul>
 {% else %}
 <ul class="nav nav-tabs nav-section">
-       <li class="active"><a href="#info"><img src="{{ STATIC_URL }}icons/slices-xs.png" alt="About MySlice" /> {{ slice }}</a></li>
+       <li class="active"><a href="#info">Information</a></li>
        <!-- <li class="testbeds"><a href="#testbeds">Testbeds</a></li> -->
        <li><a class="link" href="/resources/{{ slice }}">Resources</a></li>
        <li class="users"><a href="#users">Users</a></li>
        <!-- <li class="statistics"><a href="#experiment">Statistics</a></li> -->
        <!-- <li class="measurements"><a href="#experiment">Measurements</a></li> -->
-       <li class="experiment"><a href="#experiment" data-toggle="tab">Experiment</a></li>
+       <li class="experiment"><a href="#experiment">Tools</a></li>
 </ul>
 <script>
 $(document).ready(function() {
@@ -27,7 +34,13 @@ $(document).ready(function() {
        var id = $(this).attr('href').substr(1);        
        $("#" + id).load('/' + id + '/{{ slice }}/');
        });
-       $('div#info').load('/info/{{ slice }}/');
+       
+       var hash = window.location.hash;
+       if (hash) {
+               $('.nav-tabs a[href='+hash+']').click();
+       } else {
+               $('div#info').load('/info/{{ slice }}/');
+       }
 });
 </script>
 {% endif %}
\ No newline at end of file
index e81121b..dcde2ca 100644 (file)
@@ -6,7 +6,7 @@
                        <a href="/"><img src="{{ STATIC_URL }}img/onelab-portal.png" alt="OneLab Portal - Future Internet Testbeds" /></a>
                </div>
                {% if username %}
-               <div class="col-sm-5 col-md-5 navigation">
+               <div class="col-sm-4 col-md-4 navigation">
                        <ul>
                                <li>
                                        <a class="dropdown-toggle" data-toggle="dropdown" href="#">
                                        
                                        <div class="dropdown-menu" style="z-index:99;">
                                                        <ul id="dropdown-slice-list">
-                                                               <li><a href="/portal/slice_request/">Request Slice</a></li>
+                                                               <li class="title"><a href="/portal/slice_request/">Request Slice</a></li>
                                                        </ul>
                                        </div>
                                </li>
+                               {%if 'is_pi'  in pi %}  
                                <li id="nav-institution" class=""><a href="/portal/institution">MANAGEMENT</a></li>
-                               <li id="nav-request"><a href="/portal/validate">REQUESTS</a></li>
+                                {%endif%}
                                <li><a href="/portal/support/">SUPPORT</a></li>
-                               
-                               
-
                        </ul>
                </div>
                {% else %}
-               <div class="col-sm-5 col-md-5 navigation">
+               <div class="col-sm-4 col-md-4 navigation">
                </div>
                {% endif %}
-               <div class="col-sm-4 col-md-4 secondary">
+               <div class="col-sm-5 col-md-5 secondary">
                        <ul>
-                               
                                <li><a href="/news">News</a></li>
                                <li><a href="/portal/about">About</a></li>
                                <li><a target="_blank" href="http://www.onelab.eu">Public Website</a></li>
index 955193b..dde2181 100644 (file)
@@ -19,7 +19,7 @@
        <p class="aligned wide"><label for="id_new_password1">{% trans 'New password:' %}</label>{{ form.new_password1 }}</p>
        {{ form.new_password2.errors }}
        <p class="aligned wide"><label for="id_new_password2">{% trans 'Confirm password:' %}</label>{{ form.new_password2 }}</p>
-       <p><input type="submit" value="{% trans 'Change my password' %}" /></p>
+       <p><input type="submit" class="btn btn-onelab" value="{% trans 'Change my password' %}" /></p>
        </form>
 
 {% else %}
index 6198523..0e0de7e 100644 (file)
@@ -13,7 +13,7 @@
        
        <form action="/portal/pass_reset/" method="post">{% csrf_token %}
        {{ form.email.errors }}
-       <p><label for="id_email">Email address:</label> {{ form.email }} <input type="submit" value="Reset my password" /></p>
+       <p><label for="id_email">Email address:</label> {{ form.email }} <input type="submit" class="btn btn-onelab" value="Reset my password" /></p>
        </form>
        </div>
 </div>
index 3ab8efc..ab6776c 100644 (file)
@@ -3,11 +3,14 @@
 {% block content %}        
 
 <div class="row">
+       <div class="col-md-12">
        <h1><img src="{{ STATIC_URL }}icons/user-xs.png" alt="User Registration" />User sign-up</h1>
+       </div>
 </div>
 <div class="row">
-               <p></p>
+       <div class="col-md-12">
                <p><strong>Questions? <a href="/portal/contact" >Contact us.</a></strong></p>
+  </div>
 </div>
 {% if errors %}
 <ul>
   {% endfor %}
 </ul>
 {% endif %}
-<div class="row"><div class="col-sm-12">
-<form class="cmxform form-horizontal" id="registrationForm" method="post" enctype="multipart/form-data" role="form">
-{% csrf_token %}
-       <div class="form-group">
-               <label for="authority_hrn" class="control-label">Organization</label>
-               <p></p>
-               <input id="authority_hrn" name="authority_hrn" class="form-control" style="width:530px" value="{{ authority_hrn }}" required>
-               <p class="help-block">Choose your organization (company/university) from the list that apears when you<br> click in the field above and start to type.
-                Use the arrow keys to scroll through the list;<br>type part of the name to narrow down the list. If it is not in the list, 
-               <a href="/portal/join">please add it.</a></p>
+<div class="row">
+       <div class="col-md-12">
+               
+                       <div class="form-group">
+                               <form class="cmxform form-horizontal" id="registrationForm" method="post" enctype="multipart/form-data" role="form">
+                       {% csrf_token %}
+                               <label for="authority_hrn" class="control-label">Organization</label>
+                               <p></p>
+                               <input id="authority_hrn" name="org_name" class="form-control" style="width:590px" value="{{ organization }}" 
+                               title="Choose your organization (company/university) from the list that apears when you click in the field and start to type.
+                                Use the arrow keys to scroll through the list; type part of the name to narrow down the list. If it is not in the list, 
+                               please request its addition by clicking the link below. We will send an email to the managers that we have on record for 
+                               your organization, asking them to validate your sign-up request." required/>
+                               <p></p>
+                               <p>Organization not listed? <a href="/portal/join">Request its addition now.</a></p>
+                       </div>
        </div>
+</div>
 
-       <div class="row">
-       <div class="col-md-4">
+<div class="row">
+       <div class="col-md-6">
        
            <div class="form-group">
                        <label for="firstname" class="control-label">Personal information</label>
                        <p></p>
-                       <input type="text" name="firstname" class="form-control" style="width:200px" minlength="2" value="{{ first_name }}" placeholder="First name" required />
+                       <input type="text" name="firstname" class="form-control" style="width:350px" minlength="2" value="{{ first_name }}" placeholder="First name" required />
            </div>
            <div class="form-group">
-                       <input type="text" name="lastname" size="25" class="form-control" style="width:200px" minlength="2" value="{{ last_name }}" placeholder="Last name" required />
+                       <input type="text" name="lastname" size="25" class="form-control" style="width:350px" minlength="2" value="{{ last_name }}" placeholder="Last name" required />
            </div>
                <div class="form-group">
-               <input type="email" name="email" size="25"  class="form-control" style="width:200px" value="{{ email }}" 
+               <input type="email" name="email" size="25"  class="form-control" style="width:350px" value="{{ email }}" 
                        title="Your e-mail address will be your identifier for logging in. We contact you to verify your account and then, occasionally, for important issues."
                        placeholder="Email" required/>
                </div>
       <div class="col-xs-6"><p class="form-hint">Enter your login</p></div>
     </div>
        -->
-       <div class="col-md-4">
+       <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:200px" minlength="4" value="{{ password }}" 
+             <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/>
            </div>
            <div class="form-group">
-                       <input type="password"  id="confirmpassword" name="confirmpassword" style="width:200px"  minlength="4" class="form-control" value="" 
+                       <input type="password"  id="confirmpassword" name="confirmpassword" style="width:250px"  minlength="4" class="form-control" value="" 
                                placeholder="Confirm password" required/>
            </div>
            <div class="form-group">
                <!--<label for="question" class="control-label">Keys</label> -->
-                       <select name="question" class="form-control" style="width:200px" id="key-policy" 
+                       <select name="question" class="form-control" style="width:350px" id="key-policy" 
                                title="Your public/private key pair allows you to access the testbeds." required>        
                                <option value="generate">Generate my keys for me (recommended)</option>
                                <option value="upload">Upload my public key (advanced users only)</option>
                        </div>
            </div>
        </div>
+</div>
+<div class="row">
+       <div class="col-md-12">
+               <div class="form-group">
+                       <p></p>
+                       <input type="checkbox" name="agreement" value="agreement" required/>&nbsp;&nbsp; I agree to the 
+                       <a href="#" data-toggle="modal" data-target="#myModal">terms and conditions.</a> 
+               </div>
        </div>
-
-       <div class="form-group">
-               <p></p>
-               <input type="checkbox" name="agreement" value="agreement" required/> I agree to the 
-               <button class="btn btn-default btn-xs" data-toggle="modal" data-target="#myModal">terms and conditions.</button> 
+</div>
+<div class="row">
+       <div class="col-md-12">
+               <div class="form-group" id="register">
+                       <p></p> 
+               <button class="submit btn btn-onelab" type="submit">Sign up</button>
+           </div>
+       </form> 
        </div>
+</div>
+       
+       
        <!-- Modal - columns selector -->
                <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
                        <div class="modal-dialog">
                                </div>
                                <div class="modal-body">
                                                <p align="left">
-                                       TERMS AND CONDITIONS
-                                       <br/>
                                        for OneLab Basic level service
                                        <br/>
                                        Version 0.6 of 20 May 2014
+                                               <br>
+                                               <a href="/portal/terms" target="_blank">[Printable format]</a>
                                                </p>
                                        <h1 align="left">1 Context</h1>
                                        <h2 align="left">1.1 OneLab</h2>
     Users who seek such guarantees are invited to consider a higher level of service.
 </p>
 <h2 align="left">
-    <a name="_Toc261537715">2.3 Limited</a>
-    liability
+    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
                        </div>
                </div>
 
-    <div class="form-group" id="register">
-               <p></p> 
-       <button class="submit btn btn-primary" type="submit">Sign up</button>
-    </div>
-</form>  
-</div>
+    
 <script>
 jQuery(document).ready(function(){
     var availableTags = [
     {% if authorities %}
         {% for authority in authorities %}
             {% if authority.name %}
-                {value:"{{ authority.authority_hrn }}",label:"{{authority.name}}"},
-            {% else %}
-                {value:"{{ authority.authority_hrn }}",label:"{{authority.authority_hrn}}"},
+                {value:"{{ authority.name }}",label:"{{authority.name}}"},
+                       // to show only full name
+           // {% else %}
+           //     {value:"{{ authority.authority_hrn }}",label:"{{authority.authority_hrn}}"},
             {% endif %}
         {% endfor %}    
     {% else %}
         {value:"",label:"No authority found !!!"}
     {% endif %}
     ];
+       // sorting the list
+       availableTags.sort(function(a,b){
+               var nameA=a.value.toLowerCase(), nameB=b.value.toLowerCase();
+               if (nameA < nameB) {
+               return -1;
+               }
+               if (nameA > nameB) {
+               return 1;
+               }
+       return 0;
+       }); 
+       // auto-complete the form
     jQuery( "#authority_hrn" ).autocomplete({
       source: availableTags,
       minLength: 0,
@@ -497,6 +528,8 @@ jQuery(document).ready(function(){
       }
       //select: function( event, ui ) {console.log(jQuery(this))}
     });
+       // for hover texts
+       jQuery('[title!=""]').qtip();
 });
 </script>
 {% endblock %}
index 838b9b4..830c7ee 100644 (file)
@@ -3,13 +3,12 @@
 
 {% block head %}
 {{ wizard.form.media }}
+<link rel="stylesheet" type="text/css" href="{{STATIC_URL}}/css/registration.css" />
 {% endblock %}
 
 {% block content %}
 
-<link rel="stylesheet" type="text/css" href="{{STATIC_URL}}/css/onelab.css" />
-<!-- xxx ideally only onelab.css but ... xxx -->
-<link rel="stylesheet" type="text/css" href="{{STATIC_URL}}/css/registration.css" />
+
 
 <div class="onelab-title well-lg">
   <h2>Request a Slice</h2>
@@ -25,7 +24,7 @@
       <div class="col-xs-6"> <p class="form-hint">{{ field.help_text }}</p> </div>
     </div>
     {% endfor %}
-    <button class="submit btn btn-default col-xs-12" type="submit">Request Slice</button>
+    <button class="submit btn btn-default" type="submit"><span class="glyphicon glyphicon-plus"></span> Request Slice</button>
   </fieldset>
   </form>
 </div>
index 9bbc22b..880521b 100644 (file)
@@ -4,55 +4,51 @@
 {% block content %}
        <div class="row">
                <div class="col-md-12">
-               <h1><img src="{{ STATIC_URL }}icons/slices-xs.png" alt="Request a Slice" /> Request a new Slice</h1>
+                       <h1><img src="{{ STATIC_URL }}icons/slices-xs.png" alt="Request a Slice" /> Request a new slice</h1>
                </div>
        </div>
 
        {% if errors %}
-       <ul>
-         {% for error in errors %}
-         <li>{{ error }}</li>
-         {% endfor %}
-       </ul>
-       {% endif %}
        <div class="row">
-               <div class="col-md-12">&nbsp;</div>
+               <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-2"></div>
-               <div class="col-md-8">
+               <div class="col-md-8 el">
                        <form role="form" method="post">
                        {% csrf_token %}
-                         <div class="form-group">
-                           <label for="email">Experimenter</label>
-                           <input type="email" class="form-control" id="email" value="{{ email }}" readonly="readonly">
+                         <div class="form-group" style="display:none">
+                           <input type="email" class="form-control" id="email" style="width:300px" value="{{ email }}" readonly="readonly">
                          </div>
                          <div class="form-group">
-                           <label for="slice_name">Slice Name</label>
-                           <input type="text" class="form-control" name="slice_name" id="slice_name" placeholder="Slice Name" required="required">
-                               <p class="help-block"></p>
+                           <input type="text" class="form-control" name="slice_name" id="slice_name" style="width:300px" placeholder="Slice name" 
+                               title="Please enter a name for your slice"required="required">
                          </div>
                          <div class="form-group">
-                           <label for="authority">Authority</label>
                                {%if 'is_pi'  in pi %}
-                               <input type="text" class="form-control" id="authority_hrn" name="authority_hrn" placeholder="Authority" required="required">
-                               <p class="help-block">An authority responsible for vetting your slice</p>
+                               <input type="text" class="form-control" id="authority_hrn" name="authority_hrn" style="width:300px" placeholder="Authority" 
+                               title="An authority responsible for vetting your slice" required="required">
                                {%else%}
-                           <input type="text" class="form-control" id="authority_hrn" name="authority_hrn" placeholder="Authority" required="required" readonly="readonly">
-                               <p class="help-block">An authority responsible for vetting your slice</p>
+                           <input type="text" class="form-control" id="authority_hrn" name="authority_hrn" placeholder="Authority" style="width:300px; display:none;" 
+                               title="An authority responsible for vetting your slice" required="required" readonly="readonly">
                                {%endif%}
                          </div>
                          <div class="form-group">
-                           <label for="number_of_nodes">Number of Nodes</label>
-                           <input type="number" class="form-control" name="number_of_nodes" id="number_of_nodes" placeholder="Number of Nodes">
-                               <p class="help-block">Number of nodes you expect to request (informative)</p>
+                           <input type="number" class="form-control" name="number_of_nodes" id="number_of_nodes" style="width:300px" placeholder="Number of nodes"
+                               title="Number of nodes you expect to request (informative)">
                          </div>
                          <div class="form-group">
-                           <label for="purpose">Experiment Purpose</label>
-                               <textarea id="purpose" name="purpose" class="form-control" rows="6" placeholder="Experiment Purpose" required="required">{{ purpose }}</textarea>
-                           <p class="help-block">Purpose of your experiment (informative)</p>
+                               <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-default">Request Slice</button>
+                         <button type="submit" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request Slice</button>
                        </form>
        
                </div>
@@ -62,7 +58,7 @@
 jQuery(document).ready(function(){
        
        $("#authority_hrn").load("/rest/user/", {"fields" : ["parent_authority"], "filters": {"user_hrn": "{{ user_hrn }}"}}, function(data) {
-               var jsonData = JSON.parse(data)
+               var jsonData = JSON.parse(data);
         $(this).attr("value", jsonData[0]['parent_authority']);
     });
     var availableTags = [
@@ -81,7 +77,7 @@ jQuery(document).ready(function(){
     $( "#authority_hrn" ).autocomplete({
       source: availableTags,
       minLength: 0,
-      select: function( event, ui ) {console.log(jQuery(this))}
+      select: function( event, ui ) {console.log(jQuery(this));}
     });
 });
 </script>
index e9768b7..ff51376 100644 (file)
@@ -19,7 +19,7 @@
                        <h2>Report a Bug</h2>
                        <p>If you have found a bug or having difficulties accesing some features or found some anomalies, please report it using our ticketing system.</p>
                        <button id="ticketbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create Ticket</button>
-                       <h3>Unresolved Tickets</h3>
+<!--                   <h3>Unresolved Tickets</h3>
                        <table class="mytable table table-bordered table-hover">
                        <tr>
                            <th>Ticket No</th>
@@ -27,7 +27,7 @@
                                        <th>Description</th>
                            <th>Status</th>
                        </tr>
-                       <!-- <tr>
+                       <tr>
                            <td>1</td>
                                        <td>yasin.upmc@gmail.com</td>
                                        <td> Slice_request page is not working </td>
@@ -38,9 +38,9 @@
                                        <td>azerty@lip6.fr</td>
                                        <td>Unable to Register</td>
                                        <td>Unresolved</td>
-                               </tr> -->
+                               </tr> 
                
-                   </table>
+                   </table> -->
                </div>
          </div>
        <div class="tab-pane row" id="faq">
diff --git a/portal/templates/termsview.html b/portal/templates/termsview.html
new file mode 100644 (file)
index 0000000..d89e8fb
--- /dev/null
@@ -0,0 +1,395 @@
+{% extends "layout.html" %}
+
+{% block content %}
+<div class="row">
+       <div class="col-md-12">
+       <h1> Terms and conditions</h1>
+       <p align="left">
+    <a name="_Ref238698453"></a>
+    <a name="_Ref238699060"></a>
+    <a name="_Ref249598367"></a>
+    <a name="_Ref254443731"></a>
+    <a name="_Ref254443916"></a>
+    TERMS AND CONDITIONS
+    <br/>
+    for OneLab Basic level service
+    <br/>
+    Version 0.6 of 20 May 2014
+</p>
+<h1 align="left">Context</h1>
+<h2 align="left">
+    1.1 OneLab
+</h2>
+<p align="left">
+    OneLab is an experimental facility for testing new ideas and new technologies in the area of computer networking. It consists of a variety of types of
+    platforms, including:
+</p>
+<ul type="disc">
+    <li>
+        <strong>internet overlay testbeds</strong>
+        , testbeds that offer virtual machines distributed across locations in different countries, allowing users to deploy overlays on the internet;
+    </li>
+    <li>
+        <strong>wireless testbeds</strong>
+        , testbeds that consist of clusters of computers that are within Wi-Fi communication range of each other, either in an office environment or in an
+        isolated setting;
+    </li>
+    <li>
+        <strong>internet of things testbeds</strong>
+        , testbeds that consist of embedded computing nodes with sensor capabilities, communicating wirelessly in an isolated environment;
+    </li>
+    <li>
+        <strong>emulation testbeds,</strong>
+        computing clusters that offer virtual machines on servers that are interconnected by a high speed switch, enabling large scale network emulation.
+    </li>
+</ul>
+<p align="left">
+    This list of types of platforms is subject to change, and the current list, along with the identities of the specific platforms of each type, can be found
+    on the OneLab website (onelab.eu).
+</p>
+<p align="left">
+    Each platform has its own owners, and OneLab is the grouping of these platforms through a consortium of institutions. The OneLab consortium is coordinated
+    by UPMC Sorbonne Universités. It operates on a not-for-profit basis.
+</p>
+<p align="left">
+    Access to OneLab may also provide access to additional platforms that are not part of OneLab, due to a federation agreement between OneLab and the owners
+    of those platforms.
+</p>
+<h2 align="left">
+    1.2 Fee-free Basic level service
+</h2>
+<p align="left">
+    These terms and conditions define and apply to OneLab's Basic level service, which is available free of charge.
+</p>
+<p align="left">
+    Users who would like additional services are encouraged to contact support@onelab.eu. Some additional services require a written agreement, but are
+    otherwise free. Others require the payment of fees or in-kind contributions. (An example of an in-kind contribution is the hosting of a PlanetLab Europe
+    server node.)
+</p>
+<h2 align="left">
+    1.3 Managers and standard users
+</h2>
+<p align="left">
+    There are two classes of OneLab user: the manager and the standard user. OneLab grants access rights to managers, who, in turn, provide access rights to
+    standard users. Examples are: for a small enterprise, an executive may be the manager and the employees may be standard users; for a research team, a
+    senior scientist (faculty member or research scientist) may be a manager and doctoral students and other members of the team may be standard users; for a
+    university course, a professor may be a manager and the students may be standard users.
+</p>
+<h2 align="left">
+    1.4 These terms and conditions
+</h2>
+<p align="left">
+    Acceptance of these terms and conditions is a condition of obtaining OneLab Basic level user service. They are posted to the OneLab portal site
+    (portal.onelab.eu). They may be changed without other notice than the posting of a new version to the portal site.
+</p>
+<h1 align="left">
+    2 Services provided by OneLab
+</h1>
+<h2 align="left">
+    2.1 Access to the experimental facility
+</h2>
+<p align="left">
+    OneLab provides users with access to the platforms that make up the experimental facility. Each platform owner determines the specifics of this access (for
+    example, how many nodes are available to a user, what happens in case of oversubscription, etc.), with the proviso that Basic level service requires that
+    users be able to conduct meaningful experiments on every OneLab testbed.
+</p>
+<p align="left">
+    Basic level service may also provide access to platforms that are federated with OneLab, but such access depends upon the terms of the federation
+    agreements with those platforms, which may require that the user have a higher level of service in order to gain access. For example, Basic level service
+    provides access to PlanetLab Europe, a OneLab platform, without providing access to PlanetLab Central, a federated platform. Users wanting full access
+    across the global PlanetLab system should contact support@onelab.eu to arrange to enter into a PlanetLab Europe membership agreement.
+</p>
+<p align="left">
+    OneLab's role is to facilitate access to the platforms. Specifically, it provides each user with:
+</p>
+<ul>
+    <li align="left">
+        <strong>a single account,</strong>
+        the credentials for which can be used to access all of the OneLab testbeds;
+    </li>
+    <li align="left">
+        <strong>tools through which to access the testbeds</strong>
+        , including, notably, a web-based portal (portal.onelab.eu) that allows a user to see the resources available on each testbed and to reserve them,
+        along with a number of experiment control tools that a user can employ to deploy an experiment on those resources;
+    </li>
+    <li align="left">
+        <strong>support</strong>
+        , with documentation on how to use the tools, pointers to documentation for individual testbeds, and a helpdesk to respond to user questions.
+    </li>
+</ul>
+<p align="left">
+    Additional support, such as accompaniment through the design and deployment of experiments and the interpretation of their results, is available through
+    higher levels of service.
+</p>
+<h2 align="left">
+    2.2 Best effort, without guarantees
+</h2>
+<p align="left">
+    OneLab and the owners of the individual OneLab testbeds do their best to provide the services outlined here, with the understanding that Basic level
+    service offers no guarantees. Users should clearly understand the following limitations.
+</p>
+<ul type="disc">
+    <li>
+        <strong>Reliability:</strong>
+        OneLab does not provide any guarantees with respect to the reliability of the portal, of other tools, or of the individual nodes on platforms. These
+        may be taken down for maintenance, rebooted, or reinstalled at any time. Reinstallation implies that disks are wiped, meaning that users should not
+        consider a local disk to be a persistent form of storage.
+    </li>
+    <li>
+        <strong>Fitness:</strong>
+        OneLab does not guarantee that the platforms are suitable for the experiments that users intend to conduct. There may be limitations in the
+        technologies that are offered that prevent certain types of experiments from being carried out.
+    </li>
+    <li>
+        <strong>Privacy</strong>
+        : OneLab does not guarantee the privacy of traffic generated on the platforms (e.g., wireless signals, packets). Unless otherwise specified by an
+        individual platform owner, users should assume that traffic is monitored and logged. Such monitoring may be done intentionally, for example, to allow
+        platform administrators as well as other users to investigate abuse.
+    </li>
+</ul>
+<p align="left">
+    Users who seek such guarantees are invited to consider a higher level of service.
+</p>
+<h2 align="left">
+    2.3 Limitedliability
+</h2>
+<p align="left">
+    In no event shall the partners of the OneLab consortium be liable to any user for any consequential, incidental, punitive, or lost profit damages, or for
+    any damages arising out of loss of use or loss of data, to the extent that such damages arise out of the activities of OneLab consortium partners, or any
+    breach of the present terms and conditions, even if the consortium partner has been advised of the possibility of such damages.
+</p>
+<p align="left">
+    Nothing contained in these terms and conditions shall be deemed as creating any rights or liabilities in or for third parties who are not Basic level users
+    of OneLab.
+</p>
+<h1 align="left">
+    3 Acceptable use policy
+</h1>
+<h2 align="left">
+    3.1 Responsibilities of managers and standard users
+</h2>
+<p align="left">
+    OneLab creates and administers accounts for managers and delegates to managers the responsibility for creating and administering accounts for standard
+    users. Both managers and standard users are required to follow OneLab's acceptable use policy. In addition, managers are fully responsible for the
+    activities of the standard users whose accounts they create.
+</p>
+<p align="left">
+    A manager is expected to grant user access only an individual with whom he or she has a working relationship. In general, this means an individual who
+    works for the same institution as the manager, or, in the case of higher education and research, an individual who is a student at the university where the
+    manager works. Managers may also grant access to individuals from other institutions, provided that they are collaborating on a common project on OneLab.
+    If there is a doubt, a manager should refer the question to support@onelab.eu.
+</p>
+<h2 align="left">
+    3.2 Types of use
+</h2>
+<p align="left">
+    OneLab may be used by enterprise, by scientific researchers, and by educators.
+</p>
+<p align="left">
+    OneLab may be used for pre-commercial research and development. In keeping with OneLab's not-for-profit status, it may not be used to deploy services that
+    are designed to generate a commercial profit.
+</p>
+<p align="left">
+    Not-for-profit use of OneLab to deploy services that are designed to generate revenue requires prior approval through a written agreement, and thus may not
+    be carried out on a Basic level account. Interested users are invited to contact support@onelab.eu.
+</p>
+<p align="left">
+    OneLab may be used for scientific research.
+</p>
+<p align="left">
+    OneLab may be used to host lab exercises for university courses.
+</p>
+<p align="left">
+    Questions about other types of use should be addressed to support@onelab.eu.
+</p>
+<h2 align="left">
+    3.3 Applicable laws and regulations
+</h2>
+<p align="left">
+    OneLab is managed, and the portal is hosted, in France. Information regarding the countries in which individual testbeds are managed and hosted is
+    available from those testbeds. Users are responsible for being aware of the countries in which their experiments are deployed and for ensuring that their
+    use of OneLab fully conforms to the laws and regulations of those countries, as well as the laws and regulations of the country in which they themselves
+    are present when conducting their experiments.
+</p>
+<p align="left">
+    Above and beyond specific national laws, the activities email spamming, phishing through web services, and all types of Internet fraud are prohibited on
+    OneLab.
+</p>
+<h2>
+    3.4 Security and accounting mechanisms
+</h2>
+<p align="left">
+    Users are expected to respect the security and accounting mechanisms put in place by OneLab, its platforms, and federated platforms. For example, access to
+    PlanetLab Europe is designed to take place through the SSH cryptographically-secured connection protocol, which uses public/private key pair
+    authentication, and so users should not attempt to bypass this mechanism. As another example, OneLab's notion of a "slice" associates a set of resources
+    with the group of users who have reserved those resources, and users should not attempt to obscure the identities of participants in a slice.
+</p>
+<p align="left">
+    Hacking attempts against the OneLab portal and testbeds are not permitted. This includes "red team" (hacker test) experiments.
+</p>
+<h2>
+    3.5 Sharing of resources
+</h2>
+<p align="left">
+    OneLab is intended for ambitious experiments. Large numbers of resources and extended leases on resources may legitimately be granted in order to carry
+    these out. At the same time, OneLab and its testbeds are shared environments, and when there is contention for resources, limits must be imposed.
+</p>
+<p align="left">
+    Each OneLab platform sets its own policies for handling resource contention. As a general rule, users are encouraged to design their experiments to use
+    resources efficiently. In particular, spinning/busy-waiting techniques for extended periods of time are strongly discouraged. Some resource contention
+    policies (e.g., PlanetLab Europe's) terminate the jobs that are using the most resources in the case of contention.
+</p>
+<h2>
+    3.6 Internet-connected platforms
+</h2>
+<p align="left">
+    Some of OneLab's platforms allow experiments to take place on resources that have access to the public internet. These experiments can potentially generate
+    traffic to, and receive traffic from, any host or router in the internet.<a></a><a id="_anchor_1" href="#_msocom_1" name="_msoanchor_1">[LB1]</a>
+</p>
+<p align="left">
+    Furthermore, some internet-connected platforms (e.g., PlanetLab Europe) consist of servers that are hosted by a large number of member institutions.
+</p>
+<p align="left">
+    The accessibility of internet-connected platforms and the distributed hosting model of some of these platforms imply certain responsibilities on the part
+    of users, as detailed below.
+</p>
+<h3>
+    3.6.1 General guidance
+</h3>
+<p align="left">
+    A good litmus test when considering whether an experiment is appropriate for such internet-connected platforms is to ask what the network administrator at
+    one's own organisation would say about the experiment running locally. If the experiment disrupts local activity (e.g., uses more than its share of the
+    site's internet bandwidth) or triggers complaints from remote network administrators (e.g., performs systematic port scans), then it is not appropriate for
+    such internet-connected platforms.
+</p>
+<p align="left">
+    It is the responsibility of the user and the user's manager to ensure that an application that will run on an internet-connected platform is tested and
+    debugged in a controlled environment, to better understand its behaviour prior to deployment.
+</p>
+<h3>
+    3.6.2 Standards of network etiquette
+</h3>
+<p align="left">
+    Internet-connected platforms are designed to support experiments that generate unusual traffic, such as network measurements. However, it is expected that
+    all users adhere to widely accepted standards of network etiquette in an effort to minimise complaints from network administrators. Activities that have
+    been interpreted as worm and denial-of-service attacks in the past (and should be avoided) include sending SYN packets to port 80 on random machines,
+    probing random IP addresses, repeatedly pinging routers, overloading bottleneck links with measurement traffic, and probing a single target machine from
+    many nodes.
+</p>
+<p align="left">
+    For internet-connected platforms that have a distributed hosting model, each host institution will have its own acceptable use policy. Users should not
+    knowingly violate such local policies. Conflicts between local policies and OneLab's stated goal of supporting research into wide-area networks should be
+    brought to the attention of OneLab administrators at support@onelab.eu.
+</p>
+<h3>
+    3.6.3 Specific network usage rules
+</h3>
+<p align="left">
+    It is not allowed to use one or more nodes of an internet-connected platform to generate a high number of network flows or flood a site with high traffic
+    to the point of interfering with its normal operation. Use of congestion-controlled flows for large transfers is highly encouraged.
+</p>
+<p align="left">
+    It is not allowed to perform systematic or random port or address block scans from an internet-connected platform.
+</p>
+<p align="left">
+    For internet-connected platforms that use a distributed hosting model, it is not allowed to spoof or sniff traffic on a hosted server or on the network the
+    server belongs to.
+</p>
+<p align="left">
+    Access to a server on a distributed hosting platform may not be used to gain access to other servers or networked equipment that are not part of the
+    testbed.
+</p>
+<h2>
+    3.7 Wireless platforms
+</h2>
+<p align="left">
+    Wireless-connected platforms give users access to nodes that communicate via Wi-Fi and other wireless technologies. They may be capable of detecting
+    wireless activity in the neighbourhood of those nodes: traffic generated by other users of the platform or by individuals not associated with the platform.
+    In general, much of the traffic will be encrypted, with certain aspects (such as SSIDs) not encrypted, but it is also possible that there will be fully
+    unencrypted traffic. They may also be capable of generating wireless activity that reaches equipment outside of the testbed.
+</p>
+<p align="left">
+    Furthermore, some wireless-connected platforms may have built-in limitations to prevent them from generating signals at a strength that exceeds health and
+    safety regulations.
+</p>
+<p align="left">
+    These characteristics of wireless-connected platforms imply certain responsibilities on the part of users, as detailed below.
+</p>
+<h3>
+    3.7.1 Specific network usage rules
+</h3>
+<p align="left">
+    Experimenters may make no attempt to defeat the encryption of encrypted third-party traffic. Furthermore, experimenters must treat with utmost discretion
+    any unencrypted traffic. Limited metadata can be recorded for the bona fide purposes of an experiment, but under no case should third party communications
+    be recorded.
+</p>
+<p align="left">
+    No attempt may be made to reverse engineer traffic in order to learn the identities of the parties who have generated the traffic.
+</p>
+<p align="left">
+    Wireless-connected platforms may not be used to gain access to any network equipment that is not part of the testbed itself.
+</p>
+<p align="left">
+    It is not allowed to perform systematic or random scans of wireless networks that are not part of a wireless-connected platform. Similarly, it is not
+    allowed to spoof or sniff wireless traffic of the institution that hosts a wireless-connected platform or of other networks in the proximity.
+</p>
+<p align="left">
+    Care must be taken so that traffic on wireless-connected platforms does not interfere with the normal functioning of network equipment that is not part of
+    the testbed itself.
+</p>
+<p align="left">
+    No attempt may be made to defeat the mechanisms that limit signal strength on wireless-connected platforms.
+</p>
+<h2>
+    3.8 Handling suspected violations
+</h2>
+<p align="left">
+    Suspected violations of the OneLab acceptable use policy should be reported to support@onelab.eu.
+</p>
+<p align="left">
+    Upon notification or detection of a possible violation, OneLab management will attempt to understand if a violation has in fact occurred. To do so,
+    management will freely communicate with the users concerned, the operators of the platforms concerned, as well as any third parties that might be involved.
+    An example of a third party is a network operator who detects what they believe to be unauthorized traffic emanating from a OneLab platform.
+</p>
+<p align="left">
+    The priority is to resolve any real or apparent violations amicably. However, if OneLab management believes that a violation may have occurred, it can, at
+    its sole discretion, and without prior notice, apply any of the following measures:
+</p>
+<ul type="disc">
+    <li>
+        notification of the users of the concerned slice (set of resources);
+    </li>
+    <li>
+        disabling of the concerned slice;
+    </li>
+    <li>
+        disabling an individual user's account;
+    </li>
+    <li>
+        reporting of the user's activity to his/her manager;
+    </li>
+    <li>
+        disabling of the manager's account and all user accounts for which the manager is responsible;
+    </li>
+    <li>
+        disabling of all accounts associated with the user's institution.
+    </li>
+</ul>
+<p align="left">
+    In the case of suspected illegal activity, OneLab management might need, without prior notice, to notify the relevant authorities.
+</p>
+<div>
+    <div>
+        <div id="_com_1">
+        </div>
+    </div>
+</div> 
+</div>
+</div>
+<div class="row">
+       <div class="col-md-12">
+
+</div>
+</div>
+{% endblock %}
+
index fb48e00..2bd2f0a 100644 (file)
@@ -11,8 +11,7 @@
   <p>To gain full access, two steps are required:</p>
   <ul>
        <li>1. You confirm your signup request by clicking on the link in the email that we have sent to your email address.</li>
-       <li>2. A manager from your organization validates your request. Upon confirmation of your signup request,<br> 
-               we will send an email to the managers at your organization with a validation request.</li>
+       <li>2. A manager from your organization validates your request. (We have sent email to your organisation's registered managers.)</li>
   </ul>                
 </div>
 
index 4e332ff..c198fee 100644 (file)
@@ -4,8 +4,13 @@
 <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>
+<br>
+<p>Please note that the validation request will only become visible once the user has confirmed his/her email address.</p>
index cce80cb..17ce184 100644 (file)
@@ -2,8 +2,13 @@ NEW USER REQUEST
 
 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 }}
+
+Please note that the validation request will only become visible once the user has confirmed his/her email address.
+
+
diff --git a/portal/termsview.py b/portal/termsview.py
new file mode 100644 (file)
index 0000000..1705369
--- /dev/null
@@ -0,0 +1,51 @@
+# 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 manifoldapi.manifoldresult import ManifoldResult
+from ui.topmenu import topmenu_items, the_user
+from myslice.configengine import ConfigEngine
+
+from myslice.theme import ThemeView
+
+class TermsView (FreeAccessView, ThemeView):
+    template_name = 'termsview.html'
+        
+    # expose this so we can mention the backend URL on the welcome page
+    def default_env (self):
+        return { 
+                 'MANIFOLD_URL':ConfigEngine().manifold_url(),
+                 }
+
+    def post (self,request):
+        env = self.default_env()
+        env['theme'] = self.theme
+        return render_to_response(self.template, env, context_instance=RequestContext(request))
+
+    def get (self, request, state=None):
+        env = self.default_env()
+
+        if request.user.is_authenticated(): 
+            env['person'] = self.request.user
+        else: 
+            env['person'] = None
+    
+        env['theme'] = self.theme
+        env['section'] = "About"
+
+        env['username']=the_user(request)
+        env['topmenu_items'] = topmenu_items(None, request)
+        if state: env['state'] = state
+        elif not env['username']: env['state'] = None
+        # use one or two columns for the layout - not logged in users will see the login prompt
+        env['layout_1_or_2']="layout-unfold2.html" if not env['username'] else "layout-unfold1.html"
+        
+        
+        return render_to_response(self.template, env, context_instance=RequestContext(request))
+
index 157c6dd..e6e63e6 100644 (file)
@@ -42,7 +42,7 @@ from portal.joinview                import JoinView
 from portal.sliceviewold            import SliceView
 from portal.validationview          import ValidatePendingView
 #from portal.experimentview         import ExperimentView
-
+from portal.termsview               import TermsView
 from portal.univbrisview            import UnivbrisView
 
 from portal.servicedirectory         import ServiceDirectoryView
@@ -93,6 +93,7 @@ urlpatterns = patterns('',
     #url(r'^pass_reset/?$', PassResetView.as_view(), name='pass_rest'),
     # Slice request
     url(r'^slice_request/?$', SliceRequestView.as_view(), name='slice_request'),
+    url(r'^terms/?$', TermsView.as_view(), name='terms'),
     # Validate pending requests
     url(r'^validate/?$', ValidatePendingView.as_view()),
     # http://stackoverflow.com/questions/2360179/django-urls-how-to-pass-a-list-of-items-via-clean-urls
index f8788d0..b26ba0f 100644 (file)
@@ -50,6 +50,7 @@ class ValidatePendingView(LoginRequiredAutoLogoutView, ThemeView):
     template_name = "validate_pending.html"
 
     def get_context_data(self, **kwargs):
+        pi = ""
         # We might have slices on different registries with different user accounts 
         # We note that this portal could be specific to a given registry, to which we register users, but i'm not sure that simplifies things
         # Different registries mean different identities, unless we identify via SFA HRN or have associated the user email to a single hrn
@@ -256,9 +257,11 @@ class ValidatePendingView(LoginRequiredAutoLogoutView, ThemeView):
 
                 if not auth_hrn in dest:
                     dest[auth_hrn] = []
-                dest[auth_hrn].append(request) 
+                dest[auth_hrn].append(request)
         
         context = super(ValidatePendingView, self).get_context_data(**kwargs)
+        print "testing"
+        print ctx_my_authorities
         context['my_authorities']   = ctx_my_authorities
         context['sub_authorities']   = ctx_sub_authorities
         context['delegation_authorities'] = ctx_delegation_authorities
@@ -270,7 +273,7 @@ class ValidatePendingView(LoginRequiredAutoLogoutView, ThemeView):
         context['topmenu_items'] = topmenu_items_live('Validation', page) 
         # so we can sho who is logged
         context['username'] = the_user(self.request) 
-        
+        context['pi'] = "is_pi"       
         context['theme'] = self.theme
         context['section'] = "Requests"
         # XXX We need to prepare the page for queries
index 07e121b..a63e0cc 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -12,7 +12,6 @@ from distutils.core import setup
 
 # we don't have a final list so let's keep it simple for now
 packages= [ os.path.dirname(init) for init in (glob("*/__init__.py")+glob("*/*/__init__.py")) ]
-print packages
 
 # Avoid troubles : clean /usr/share/unfold/
 #shutil.rmtree('/usr/share/unfold/')
@@ -24,6 +23,24 @@ def javascript (dir):
 def stylesheets (dir):
     return glob( dir+"/*.css")
 
+# looks like data_files requires actual files and cannot cope with 
+# a whole subdir like we have for fonts
+# returns a list of tuples suitable to add to data_files
+from operator import add
+
+def scan_fonts (install_topdir, topdir, extensions):
+    def subdir_tuples (subdir, extensions):
+        return [ (install_topdir+subdir, glob (subdir+"/*.%s"%extension), ) 
+                 for extension in extensions 
+                 if glob(subdir+"/*.%s"%extension)
+             ]
+    def subdirs (topdir):
+        return [x[0] for x in os.walk(topdir)]
+    return reduce (add, [ subdir_tuples (subdir, extensions) for subdir in subdirs(topdir) ] )
+
+fonts_tuples = scan_fonts ('/usr/share/unfold/static/fonts', 
+                           'static/fonts',
+                           ('otf','eot','svg','ttf','woff'))
 
 setup(packages = packages,
       # xxx somehow this does not seem to show up in debian packaging
@@ -35,9 +52,8 @@ setup(packages = packages,
 # for portal/          
           ( '/usr/share/unfold/static/img/institutions', images ('static/img/institutions')),
           ( '/usr/share/unfold/static/img/testbeds', images ('static/img/testbeds')),
-          ( '/usr/share/unfold/static/fonts', glob ('static/fonts/*')),
           ( '/usr/share/unfold/templates', glob ('templates/*')),
           ( 'apache', [ 'apache/unfold.conf', 'apache/unfold-ssl.conf', 'apache/unfold.wsgi' ]),
           ( '/etc/unfold/trusted_roots', []),
           ( '/var/unfold', []),
-        ])
+        ] + fonts_tuples )