Merge branch 'onelab' of ssh://git.onelab.eu/git/myslice into fibre
authorPedro, Carlos and Rezende <pedroeusebio, carlos, rezende@land.ufrj.br>
Fri, 24 Oct 2014 18:00:22 +0000 (16:00 -0200)
committerPedro, Carlos and Rezende <pedroeusebio, carlos, rezende@land.ufrj.br>
Fri, 24 Oct 2014 18:00:22 +0000 (16:00 -0200)
Conflicts:
portal/homeview.py
portal/sliceresourceview.py
portal/templates/slice-resource-view.html

107 files changed:
apache/myslice.wsgi [new symlink]
apache/sp-fibre/default [new file with mode: 0644]
apache/sp-fibre/myslice-django [new file with mode: 0644]
apache/sp-fibre/shibboleth-myslice [new file with mode: 0644]
apache/unfold.conf
apache/unfold.wsgi
auth/manifoldbackend-130314.py [new file with mode: 0644]
auth/manifoldbackend.py
auth/manifoldbackend.py.original [new file with mode: 0644]
manifoldapi/static/js/manifold.js
myslice/configengine.py
myslice/settings.py
myslice/urls.py
old.unfold.sqlite3-110314 [new file with mode: 0644]
plugins/scheduler2/templates/scheduler.html
portal/actions-100314.py [new file with mode: 0644]
portal/actions.py
portal/contactview.py
portal/database.py [new file with mode: 0644]
portal/emailactivationview.py
portal/homeview.py
portal/lsapiclient.py [new file with mode: 0644]
portal/managementtabrequests.py
portal/models.py
portal/registrationview.py
portal/slicerequestview.py
portal/static/css/fibre.css [new file with mode: 0644]
portal/static/css/onelab_edelberto.css [new file with mode: 0644]
portal/static/img/fibre-logo.gif [new file with mode: 0644]
portal/static/img/fibre/br.png [new file with mode: 0644]
portal/static/img/fibre/cafe.jpg [new file with mode: 0644]
portal/static/img/fibre/eu.png [new file with mode: 0644]
portal/static/img/fibre/icon_authority_color.png [new file with mode: 0644]
portal/static/img/fibre/icon_slices.png [new file with mode: 0644]
portal/static/img/fibre/icon_support.png [new file with mode: 0644]
portal/static/img/fibre/icon_testbed_color.png [new file with mode: 0644]
portal/static/img/fibre/icon_user_color.png [new file with mode: 0644]
portal/static/img/fibre/icones.zip [new file with mode: 0644]
portal/static/img/icon_authority_color.png~HEAD [new file with mode: 0644]
portal/static/img/icon_slices.png~HEAD [new file with mode: 0644]
portal/static/img/icon_support.png~HEAD [new file with mode: 0644]
portal/static/img/icon_testbed_color.png~HEAD [new file with mode: 0644]
portal/static/img/icon_user_color.png~HEAD [new file with mode: 0644]
portal/static/img/optical_fibre.jpg [new file with mode: 0644]
portal/static/img/original-backup/authority-icon.png [new file with mode: 0644]
portal/static/img/original-backup/experiments.png [new file with mode: 0644]
portal/static/img/original-backup/f4f-logo.png [new file with mode: 0644]
portal/static/img/original-backup/marker1.png [new file with mode: 0644]
portal/static/img/original-backup/marker2.png [new file with mode: 0644]
portal/static/img/original-backup/ques_icon.png [new file with mode: 0644]
portal/static/img/original-backup/resource-icon.png [new file with mode: 0644]
portal/static/img/original-backup/slice-icon.png [new file with mode: 0644]
portal/static/img/original-backup/testbeds.png [new file with mode: 0644]
portal/static/img/original-backup/user-icon.png [new file with mode: 0644]
portal/static/img/original-backup/user.png [new file with mode: 0644]
portal/static/js/jquery.qtip.min.js
portal/templates/_widget-topmenu.html
portal/templates/base.html
portal/templates/email_activation.html
portal/templates/fibre/fibre__widget-login-fed-manager.html [new file with mode: 0644]
portal/templates/fibre/fibre__widget-login-manager.html [new file with mode: 0644]
portal/templates/fibre/fibre__widget-topmenu.html [new file with mode: 0644]
portal/templates/fibre/fibre_about.html [new file with mode: 0644]
portal/templates/fibre/fibre_account-view.html [new file with mode: 0644]
portal/templates/fibre/fibre_activate_user.html [new file with mode: 0644]
portal/templates/fibre/fibre_activate_user.txt [new file with mode: 0644]
portal/templates/fibre/fibre_activate_user_email_subject.txt [new file with mode: 0644]
portal/templates/fibre/fibre_base.html [new file with mode: 0644]
portal/templates/fibre/fibre_contact.html [new file with mode: 0644]
portal/templates/fibre/fibre_email_default_sender.txt [new file with mode: 0644]
portal/templates/fibre/fibre_home-view.html [new file with mode: 0644]
portal/templates/fibre/fibre_institution.html [new file with mode: 0644]
portal/templates/fibre/fibre_management-tab-about.html [new file with mode: 0644]
portal/templates/fibre/fibre_management-tab-requests.html [new file with mode: 0644]
portal/templates/fibre/fibre_news.html [new file with mode: 0644]
portal/templates/fibre/fibre_registration_view.html [new file with mode: 0644]
portal/templates/fibre/fibre_slice-request-ack-view.html [new file with mode: 0644]
portal/templates/fibre/fibre_slice-request-done-view.html [new file with mode: 0644]
portal/templates/fibre/fibre_slice-resource-view.html
portal/templates/fibre/fibre_slice-tab-users-view.html [new file with mode: 0644]
portal/templates/fibre/fibre_slice-user-view.html [new file with mode: 0644]
portal/templates/fibre/fibre_slice-view.html [new file with mode: 0644]
portal/templates/fibre/fibre_slice_request_email.html [new file with mode: 0644]
portal/templates/fibre/fibre_slice_request_email.txt [new file with mode: 0644]
portal/templates/fibre/fibre_slice_request_email_subject.txt [new file with mode: 0644]
portal/templates/fibre/fibre_slicerequest_view.html [new file with mode: 0644]
portal/templates/fibre/fibre_supportview.html [new file with mode: 0644]
portal/templates/fibre/fibre_termsview.html [new file with mode: 0644]
portal/templates/fibre/fibre_user_register_complete.html [new file with mode: 0644]
portal/templates/fibre/fibre_user_request_email.html [new file with mode: 0644]
portal/templates/fibre/fibre_user_request_email.txt [new file with mode: 0644]
portal/templates/fibre/fibre_user_request_email_subject.txt [new file with mode: 0644]
portal/templates/fibre/fibre_widget-login-user.html [new file with mode: 0644]
portal/templates/fibre/fibre_widget-news.html [new file with mode: 0644]
portal/templates/fibre/fibre_widget-slice-sections.html [new file with mode: 0644]
portal/templates/management-tab-requests.html
portal/templates/onelab/onelab_base.html
portal/templates/registration_view.html
portal/templates/slice-resource-view.html
portal/templates/slice-tab-users-view.html
portal/templates/user_register.html
portal/validationview.py
ui/templates/base2.html [new file with mode: 0644]
unfold.sqlite3-110314 [new file with mode: 0644]
unfold.sqlite3-130314 [new file with mode: 0644]
unfold.sqlite3-140314 [new file with mode: 0644]
unfold.sqlite3.old-120314 [new file with mode: 0644]

diff --git a/apache/myslice.wsgi b/apache/myslice.wsgi
new file mode 120000 (symlink)
index 0000000..69ee492
--- /dev/null
@@ -0,0 +1 @@
+unfold.wsgi
\ No newline at end of file
diff --git a/apache/sp-fibre/default b/apache/sp-fibre/default
new file mode 100644 (file)
index 0000000..ec902c6
--- /dev/null
@@ -0,0 +1,24 @@
+NameVirtualHost *:80
+<VirtualHost *:80>
+        ServerName     200.130.15.182
+        ServerSignature Off
+        # Redirecionamento para SSL
+        #RewriteEngine on
+        #RewriteCond %{HTTPS} !=on
+        #RewriteRule ^(.*) https://%{SERVER_NAME}/$1 [R,L]
+        DocumentRoot /var/www/
+        <Directory /var/www/>
+                Options Indexes FollowSymLinks MultiViews
+                AllowOverride None
+                Order allow,deny
+                allow from all
+        </Directory>
+        ErrorLog /var/log/apache2/error.log
+        # Possible values include: debug, info, notice, warn, error, crit,
+        # alert, emerg.
+        LogLevel info
+        CustomLog /var/log/apache2/sp-access-80.log combined
+</VirtualHost>
diff --git a/apache/sp-fibre/myslice-django b/apache/sp-fibre/myslice-django
new file mode 100644 (file)
index 0000000..bafed8f
--- /dev/null
@@ -0,0 +1,56 @@
+NameVirtualHost *:443
+<IfModule mod_ssl.c>
+<VirtualHost *:443>
+    ServerAdmin support-myslice@myslice.info
+    ServerName portal.fibre.br
+
+    DocumentRoot /var/www/myslice
+    WSGIScriptAlias / /var/www/myslice/apache/unfold.wsgi 
+
+    <Directory /var/www/myslice>
+        Options Indexes FollowSymLinks MultiViews
+        AllowOverride All
+        Order allow,deny
+        allow from all
+    </Directory>
+
+    Alias /static/ /var/www/myslice/static/
+    <Directory /var/www/myslice/static>
+        Order deny,allow
+        Allow from all
+    </Directory>
+
+    #Alias /certificates/ /var/certificates-f4f/
+    ErrorLog ${APACHE_LOG_DIR}/error.log
+
+    LogLevel warn
+
+    CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined
+
+    # SSL
+    SSLEngine on
+    SSLProtocol all -SSLv2
+    SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW
+    SSLCertificateKeyFile   /etc/ssl/private/fibre.key
+    SSLCertificateFile      /etc/ssl/certs/fibre.crt
+    SSLOptions +StdEnvVars +ExportCertData
+    SSLCACertificatePath /etc/sfa/trusted_roots
+    SSLVerifyClient optional_no_ca
+    #SSLVerifyClient require
+    SSLVerifyDepth 5
+    ServerSignature On
+
+    <FilesMatch "\.(cgi|shtml|phtml|php)$">
+        SSLOptions +StdEnvVars
+    </FilesMatch>
+    <Directory /usr/lib/cgi-bin>
+        SSLOptions +StdEnvVars
+    </Directory>
+
+    BrowserMatch "MSIE [2-6]" \
+        nokeepalive ssl-unclean-shutdown \
+        downgrade-1.0 force-response-1.0
+    BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
+
+</VirtualHost>
+</IfModule>
diff --git a/apache/sp-fibre/shibboleth-myslice b/apache/sp-fibre/shibboleth-myslice
new file mode 100644 (file)
index 0000000..fc39e54
--- /dev/null
@@ -0,0 +1,61 @@
+<VirtualHost 200.130.15.182:443>
+        ServerName     200.130.15.182
+        ServerSignature Off
+
+        SSLEngine               on
+        #SSLCertificateFile      /etc/unfold/trusted_roots
+        SSLCertificateFile      /etc/ssl/certs/fibre.crt
+        SSLCertificateKeyFile   /etc/ssl/private/fibre.key
+
+        #ShibURLScheme https
+
+        DocumentRoot /var/www/
+        <Directory /var/www/>
+                Options -Indexes FollowSymLinks -MultiViews
+                AllowOverride None
+                Order deny,allow
+                Allow from all
+        </Directory>
+
+#        WSGIScriptAlias / /usr/share/unfold/apache/myslice.wsgi
+#        <Directory /usr/share/unfold/apache>
+#        <Files myslice.wsgi>
+#        Order deny,allow
+#        Allow from all
+#        </Files>
+#        </Directory>
+#        Alias /static/ /usr/share/unfold/static/
+#        <Directory /usr/share/unfold/static>
+#        Order deny,allow
+#        Allow from all
+#        </Directory>
+
+
+#<Location myslice/secure>
+#      AuthType Shibboleth
+#      ShibRequestSetting requireSession true
+#        ShibRequestSetting applicationId default
+#      Require valid-user
+#</Location>
+
+<Location /Shibboleth.sso>
+  SetHandler shib
+</Location>
+<Location /shibboleth-sp2>
+  SetHandler shib
+</Location>
+
+
+#         <Location /moodle/auth/shibboleth>
+#                 AuthType shibboleth
+#                 ShibRequireSession On
+#                 require valid-user
+#         </Location>
+
+        # Possible values include: debug, info, notice, warn, error, crit,
+        # alert, emerg.
+        ErrorLog /var/log/apache2/error.log
+        LogLevel info
+        CustomLog /var/log/apache2/sp-access-443.log combined
+
+</VirtualHost>
index 357db7e..fed763e 100644 (file)
@@ -1,19 +1,19 @@
 # see also unfold-ssl.conf
 
 <VirtualHost *:80>
-       WSGIDaemonProcess unfold processes=2 threads=25
-       WSGIProcessGroup  unfold
-       CustomLog ${APACHE_LOG_DIR}/unfold-access.log common
-       ErrorLog ${APACHE_LOG_DIR}/unfold-error.log
-        WSGIScriptAlias / /usr/share/unfold/apache/unfold.wsgi
-        <Directory /usr/share/unfold/apache/>
-        <Files unfold.wsgi>
+       WSGIDaemonProcess myslice processes=2 threads=25
+       WSGIProcessGroup  myslice
+       CustomLog ${APACHE_LOG_DIR}/myslice-access.log common
+       ErrorLog ${APACHE_LOG_DIR}/myslice-error.log
+        WSGIScriptAlias / /var/www/myslice/apache/myslice.wsgi
+        <Directory /var/www/myslice/myslice/apache/>
+        <Files myslice.wsgi>
         Order deny,allow
         Allow from all
         </Files>
         </Directory>
-        Alias /static/ /usr/share/unfold/static/
-        <Directory /usr/share/unfold/static>
+        Alias /static/ /var/www/myslice/myslice/static/
+        <Directory /var/www/myslicee/myslice/static>
         Order deny,allow
         Allow from all
         </Directory>
index 4af2e9f..34ffb36 100644 (file)
@@ -1,12 +1,14 @@
 import os
 import sys
 
-path = '/var/myslice-f4f'
+#site.addsitedir('/var/www/myslice')
+
+path = '/var/www/myslice'
 if path not in sys.path:
-    sys.path.append(path)
+    sys.path = [path] + sys.path
+print sys.path
 
 os.environ['DJANGO_SETTINGS_MODULE'] = 'myslice.settings'
 
 import django.core.handlers.wsgi
 application = django.core.handlers.wsgi.WSGIHandler()
-
diff --git a/auth/manifoldbackend-130314.py b/auth/manifoldbackend-130314.py
new file mode 100644 (file)
index 0000000..ee80113
--- /dev/null
@@ -0,0 +1,228 @@
+import time
+
+# import ldap for LDAP authentication - Edelberto
+import ldap
+
+from django.contrib.auth.models import User
+
+from manifoldapi.manifoldapi    import ManifoldAPI, ManifoldException, ManifoldResult
+from manifold.core.query        import Query
+
+# Name my backend 'ManifoldBackend'
+class ManifoldBackend:
+
+
+    # Create an authentication method
+    # This is called by the standard Django login procedure
+    def authenticate(self, token=None):
+    
+        # LDAP local/global var
+        checkldap = None
+
+        if not token:
+            return None
+
+        try:
+            #usernameldap is from LDAP user form. If it is filled - See portal/homeview.py too
+            usernameldap = token['usernameldap']
+            username = token['username']
+            password = token['password']
+            request = token['request']
+
+            # if data are not from LDAP form then normal (local) login
+            if not usernameldap:
+                auth = {'AuthMethod': 'password', 'Username': username, 'AuthString': password}
+                api = ManifoldAPI(auth)
+                sessions_result = api.forward(Query.create('local:session').to_dict())
+                print "result"
+                sessions = sessions_result.ok_value()
+                print "ok"
+                if not sessions:
+                    print "GetSession failed", sessions_result.error()
+                    return
+                print "first", sessions
+                session = sessions[0]
+
+                # Change to session authentication
+                api.auth = {'AuthMethod': 'session', 'session': session['session']}
+                self.api = api
+
+                # Get account details
+                # the new API would expect Get('local:user') instead
+                persons_result = api.forward(Query.get('local:user').to_dict())
+                persons = persons_result.ok_value()
+                if not persons:
+                    print "GetPersons failed",persons_result.error()
+                    return
+                person = persons[0]
+                print "PERSON=", person
+
+                request.session['manifold'] = {'auth': api.auth, 'person': person, 'expires': session['expires']}
+            ################################
+            # Edelberto LDAP authentication
+            # if data are from LDAP form, so
+            else:
+            # XXX UGLY
+            # Needing to create an specific entries at settings.py (or myslice.ini) for these vars
+            ##################################################
+            # Edelberto - UFF - esilva@ic.uff.br
+            # v1 - ldap authentication module
+            # Note: focus on LDAP FIBRE-BR for DN
+            #       if uses other DN, configuration are needed
+            ###################################################
+            #Searching an LDAP Directory
+
+                try:
+                    #uid = "debora@uff.br"
+
+                    # Receiving an email address, how can we split and mount it in DN format?
+                    #mail = "debora@uff.br"
+                    mail = usernameldap
+                    login = mail.split('@')[0]
+                    org = mail.split('@')[1]
+                    o = org.split('.')[0]
+                    dc = org.split('.')[1]
+                    '''
+                    print mail
+                    print login
+                    print org
+                    print o
+                    print dc
+                    '''
+
+                    # DN format to authenticate - IMPORTANT!
+                    #FIBRE-BR format
+                    uid = "uid="+mail+",ou=people,o="+o+",dc="+dc
+                    #uid = "uid=debora@uff.br,ou=people,o=uff,dc=br"
+                    # User password from LDAP form
+                    #userPassword = "fibre"
+                    userPassword = password
+
+                    # testing with:
+                    # wrong password for test
+                    #    userPassword = "fibre2"
+                    
+                    # Parameters to connect on LDAP
+                    ldap.set_option(ldap.OPT_REFERRALS, 0)
+                    # LDAP Server Address
+                    l = ldap.open("127.0.0.1")
+                    # LDAP version
+                    l.protocol_version = ldap.VERSION3
+
+                    #l.simple_bind(uid, userPassword)
+                    # l.bind_s is necessary to do the authentication with a normal LDAP user
+                    l.bind_s(uid, userPassword, ldap.AUTH_SIMPLE)
+                    #print l.bind_s(uid, userPassword, ldap.AUTH_SIMPLE)
+
+                    # DN base - Our root dc (dc=br)
+                    baseDN="dc="+dc
+                    searchScope = ldap.SCOPE_SUBTREE
+                    retrieveAttributes = None
+                    # User only can see its credentials. He search only his attributes
+                    searchFilter = "uid="+mail
+
+                    # Getting all attributes
+                    try:
+                        ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes)
+                        result_set = []
+                        # while exist attributes, save them in a list!
+                        while 1:
+                        #   print l.result(ldap_result_id, 0)
+                            result_type, result_data = l.result(ldap_result_id, 0)
+                            if (result_data == []):
+                            #print ("User %s don't allowed to bind in LDAP", uid)
+                                break
+                            else:
+                                ## Appendng to a list
+                                if result_type == ldap.RES_SEARCH_ENTRY:
+                                    result_set.append(result_data)
+                                    #    print result_set
+                    except ldap.LDAPError, e:
+                        print e
+
+                    # Matching if the user is really who his say
+                    #checkldap = None
+                    if l.compare_s(uid, 'uid', mail):
+                        # DEBUG
+                        checkldap = True
+                        print "match"
+
+                # Now, based on default Manifold Auth
+                        auth = {'AuthMethod': 'password', 'Username': usernameldap, 'AuthString': password}
+                        api = ManifoldAPI(auth)
+                        sessions_result = api.forward(Query.create('local:session').to_dict())
+                        print "result"
+                        sessions = sessions_result.ok_value()
+                        print "ok"
+                        if not sessions:
+                            print "GetSession failed", sessions_result.error()
+                            return
+                        print "first", sessions
+                        session = sessions[0]
+
+                        # Change to session authentication
+                        api.auth = {'AuthMethod': 'session', 'session': session['session']}
+                        self.api = api
+
+                        # Get account details
+                        # the new API would expect Get('local:user') instead
+                        persons_result = api.forward(Query.get('local:user').to_dict())
+                        persons = persons_result.ok_value()
+                        if not persons:
+                            print "GetPersons failed",persons_result.error()
+                            return
+                        person = persons[0]
+                        print "PERSON=", person
+
+                        request.session['manifold'] = {'auth': api.auth, 'person': person, 'expires': session['expires']}
+
+                    else:
+                        print "no match. User doesnt allowed"
+                        checkldap = False
+
+                except ldap.LDAPError, e:
+                    print "E: LDAP Search user", e                      
+        # end of LDAP
+       
+        # Follow the same of Manifold 
+        except ManifoldException, e:
+            print "ManifoldBackend.authenticate caught ManifoldException, returning corresponding ManifoldResult"
+            return e.manifold_result
+        except Exception, e:
+            print "E: manifoldbackend", e
+            import traceback
+            traceback.print_exc()
+            return None
+    
+        if not usernameldap:
+            try:
+                # Check if the user exists in Django's local database
+               user = User.objects.get(username=username)
+            except User.DoesNotExist:
+                # Create a user in Django's local database
+                user = User.objects.create_user(username, usernamep, 'passworddoesntmatter')
+                user.first_name = "DUMMY_FIRST_NAME" #person['first_name']
+                user.last_name = "DUMMY LAST NAME" # person['last_name']
+                user.email = person['email']
+            return user
+        else:
+            if checkldap:
+                try:
+                    # Check if the user exists in Django's local database
+                    user = User.objects.get(username=usernameldap)
+                except User.DoesNotExist:
+                    # Create a user in Django's local database
+                    user = User.objects.create_user(username, usernameldap, 'passworddoesntmatter')
+                    user.first_name = "DUMMY_FIRST_NAME" #person['first_name']
+                    user.last_name = "DUMMY LAST NAME" # person['last_name']
+                    user.email = person['email']
+                return user
+
+    # Required for your backend to work properly - unchanged in most scenarios
+    def get_user(self, user_id):
+        try:
+            return User.objects.get(pk=user_id)
+        except User.DoesNotExist:
+            return None
+
+
index afb8782..0522653 100644 (file)
@@ -1,5 +1,8 @@
 import time
 
+# import ldap for LDAP authentication - Edelberto
+import ldap
+
 from django.contrib.auth.models import User
 
 from manifoldapi.manifoldapi    import ManifoldAPI, ManifoldException, ManifoldResult
@@ -8,44 +11,188 @@ from manifold.core.query        import Query
 # Name my backend 'ManifoldBackend'
 class ManifoldBackend:
 
+
     # Create an authentication method
     # This is called by the standard Django login procedure
     def authenticate(self, token=None):
+    
+        # LDAP local/global var
+        checkldap = None
+
         if not token:
             return None
 
         try:
+            print "ManifoldBackend authenticate()"
+            # Mandatory fields in token
             username = token['username']
-            password = token['password']
             request = token['request']
 
-            auth = {'AuthMethod': 'password', 'Username': username, 'AuthString': password}
-            api = ManifoldAPI(auth)
-            sessions_result = api.forward(Query.create('local:session').to_dict())
-            print "result"
-            sessions = sessions_result.ok_value()
-            print "ok"
-            if not sessions:
-                print "GetSession failed", sessions_result.error()
-                return
-            print "first", sessions
-            session = sessions[0]
-
-            # Change to session authentication
-            api.auth = {'AuthMethod': 'session', 'session': session['session']}
-            self.api = api
-
-            # Get account details
-            # the new API would expect Get('local:user') instead
-            persons_result = api.forward(Query.get('local:user').to_dict())
-            persons = persons_result.ok_value()
-            if not persons:
-                print "GetPersons failed",persons_result.error()
-                return
-            person = persons[0]
-            print "PERSON=", person
-
-            request.session['manifold'] = {'auth': api.auth, 'person': person, 'expires': session['expires']}
+            # usernameldap is optional - from LDAP user form. 
+            # If it is filled - See portal/homeview.py too
+            if 'usernameldap' in token:
+                usernameldap = token['usernameldap']
+            else:
+                usernameldap = None
+            password = token['password']
+            # if data are not from LDAP form then normal (local) login
+            if not usernameldap:
+                print "not userldap ManifoldBackend authenticate()"
+                auth = {'AuthMethod': 'password', 'Username': username, 'AuthString': password}
+                api = ManifoldAPI(auth)
+                sessions_result = api.forward(Query.create('local:session').to_dict())
+                print "result"
+                sessions = sessions_result.ok_value()
+                print "ok"
+                if not sessions:
+                    print "GetSession failed", sessions_result.error()
+                    return
+                print "first", sessions
+                session = sessions[0]
+
+                # Change to session authentication
+                api.auth = {'AuthMethod': 'session', 'session': session['session']}
+                self.api = api
+
+                # Get account details
+                # the new API would expect Get('local:user') instead
+                persons_result = api.forward(Query.get('local:user').to_dict())
+                persons = persons_result.ok_value()
+                if not persons:
+                    print "GetPersons failed",persons_result.error()
+                    return
+                person = persons[0]
+                print "PERSON=", person
+
+                request.session['manifold'] = {'auth': api.auth, 'person': person, 'expires': session['expires']}
+            ################################
+            # Edelberto LDAP authentication
+            # if data are from LDAP form, so
+            else:
+                print "userldap ManifoldBackend authenticate()"
+            # XXX UGLY
+            # Needing to create an specific entries at settings.py (or myslice.ini) for these vars
+            ##################################################
+            # Edelberto - UFF - esilva@ic.uff.br
+            # v1 - ldap authentication module
+            # Note: focus on LDAP FIBRE-BR for DN
+            #       if uses other DN, configuration are needed
+            ###################################################
+            #Searching an LDAP Directory
+
+                try:
+                    #uid = "debora@uff.br"
+
+                    # Receiving an email address, how can we split and mount it in DN format?
+                    #mail = "debora@uff.br"
+                    mail = usernameldap
+                    login = mail.split('@')[0]
+                    org = mail.split('@')[1]
+                    o = org.split('.')[0]
+                    dc = org.split('.')[1]
+                    '''
+                    print mail
+                    print login
+                    print org
+                    print o
+                    print dc
+                    '''
+
+                    # DN format to authenticate - IMPORTANT!
+                    #FIBRE-BR format
+                    uid = "uid="+mail+",ou=people,o="+o+",dc="+dc
+                    #uid = "uid=debora@uff.br,ou=people,o=uff,dc=br"
+                    # User password from LDAP form
+                    #userPassword = "fibre"
+                    userPassword = password
+
+                    # testing with:
+                    # wrong password for test
+                    #    userPassword = "fibre2"
+                    
+                    # Parameters to connect on LDAP
+                    ldap.set_option(ldap.OPT_REFERRALS, 0)
+                    # LDAP Server Address
+                    l = ldap.open("127.0.0.1")
+                    # LDAP version
+                    l.protocol_version = ldap.VERSION3
+
+                    #l.simple_bind(uid, userPassword)
+                    # l.bind_s is necessary to do the authentication with a normal LDAP user
+                    l.bind_s(uid, userPassword, ldap.AUTH_SIMPLE)
+                    #print l.bind_s(uid, userPassword, ldap.AUTH_SIMPLE)
+
+                    # DN base - Our root dc (dc=br)
+                    baseDN="dc="+dc
+                    searchScope = ldap.SCOPE_SUBTREE
+                    retrieveAttributes = None
+                    # User only can see its credentials. He search only his attributes
+                    searchFilter = "uid="+mail
+
+                    # Getting all attributes
+                    try:
+                        ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes)
+                        result_set = []
+                        # while exist attributes, save them in a list!
+                        while 1:
+                        #   print l.result(ldap_result_id, 0)
+                            result_type, result_data = l.result(ldap_result_id, 0)
+                            if (result_data == []):
+                            #print ("User %s don't allowed to bind in LDAP", uid)
+                                break
+                            else:
+                                ## Appendng to a list
+                                if result_type == ldap.RES_SEARCH_ENTRY:
+                                    result_set.append(result_data)
+                                    #    print result_set
+                    except ldap.LDAPError, e:
+                        print e
+
+                    # Matching if the user is really who his say
+                    #checkldap = None
+                    if l.compare_s(uid, 'uid', mail):
+                        # DEBUG
+                        checkldap = True
+                        print "match"
+
+                # Now, based on default Manifold Auth
+                        auth = {'AuthMethod': 'password', 'Username': usernameldap, 'AuthString': password}
+                        api = ManifoldAPI(auth)
+                        sessions_result = api.forward(Query.create('local:session').to_dict())
+                        print "result"
+                        sessions = sessions_result.ok_value()
+                        print "ok"
+                        if not sessions:
+                            print "GetSession failed", sessions_result.error()
+                            return
+                        print "first", sessions
+                        session = sessions[0]
+
+                        # Change to session authentication
+                        api.auth = {'AuthMethod': 'session', 'session': session['session']}
+                        self.api = api
+
+                        # Get account details
+                        # the new API would expect Get('local:user') instead
+                        persons_result = api.forward(Query.get('local:user').to_dict())
+                        persons = persons_result.ok_value()
+                        if not persons:
+                            print "GetPersons failed",persons_result.error()
+                            return
+                        person = persons[0]
+                        print "PERSON=", person
+
+                        request.session['manifold'] = {'auth': api.auth, 'person': person, 'expires': session['expires']}
+
+                    else:
+                        print "no match. User doesnt allowed"
+                        checkldap = False
+
+                except ldap.LDAPError, e:
+                    print "E: LDAP Search user", e                      
+        # end of LDAP
+       
+        # Follow the same of Manifold 
         except ManifoldException, e:
             print "ManifoldBackend.authenticate caught ManifoldException, returning corresponding ManifoldResult"
             return e.manifold_result
@@ -54,14 +201,24 @@ class ManifoldBackend:
             import traceback
             traceback.print_exc()
             return None
-
-        try:
-            # Check if the user exists in Django's local database
-            user = User.objects.get(username=username)
-        except User.DoesNotExist:
-            # Create a user in Django's local database
-            user = User.objects.create_user(username, username, 'passworddoesntmatter')
-            user.email = person['email']
+    
+        if not usernameldap:
+            try:
+                # Check if the user exists in Django's local database
+               user = User.objects.get(username=username)
+            except User.DoesNotExist:
+                # Create a user in Django's local database
+                user = User.objects.create_user(username, usernamep, 'passworddoesntmatter')
+                user.email = person['email']
+        else:
+            if checkldap:
+                try:
+                    # Check if the user exists in Django's local database
+                    user = User.objects.get(username=usernameldap)
+                except User.DoesNotExist:
+                    # Create a user in Django's local database
+                    user = User.objects.create_user(username, usernameldap, 'passworddoesntmatter')
+                    user.email = person['email']
 
         if 'firstname' in person:
             user.first_name = person['firstname']
@@ -69,7 +226,6 @@ class ManifoldBackend:
             user.last_name = person['lastname']
 
         return user
-
     # Required for your backend to work properly - unchanged in most scenarios
     def get_user(self, user_id):
         try:
diff --git a/auth/manifoldbackend.py.original b/auth/manifoldbackend.py.original
new file mode 100644 (file)
index 0000000..eb87ab8
--- /dev/null
@@ -0,0 +1,76 @@
+import time
+
+from django.contrib.auth.models import User
+
+from manifoldapi.manifoldapi    import ManifoldAPI, ManifoldException, ManifoldResult
+from manifold.core.query        import Query
+
+# Name my backend 'ManifoldBackend'
+class ManifoldBackend:
+
+    # Create an authentication method
+    # This is called by the standard Django login procedure
+    def authenticate(self, token=None):
+        if not token:
+            return None
+
+        try:
+            username = token['username']
+            password = token['password']
+            request = token['request']
+
+            auth = {'AuthMethod': 'password', 'Username': username, 'AuthString': password}
+            api = ManifoldAPI(auth)
+            sessions_result = api.forward(Query.create('local:session').to_dict())
+            print "result"
+            sessions = sessions_result.ok_value()
+            print "ok"
+            if not sessions:
+                print "GetSession failed", sessions_result.error()
+                return
+            print "first", sessions
+            session = sessions[0]
+
+            # Change to session authentication
+            api.auth = {'AuthMethod': 'session', 'session': session['session']}
+            self.api = api
+
+            # Get account details
+            # the new API would expect Get('local:user') instead
+            persons_result = api.forward(Query.get('local:user').to_dict())
+            persons = persons_result.ok_value()
+            if not persons:
+                print "GetPersons failed",persons_result.error()
+                return
+            person = persons[0]
+            print "PERSON=", person
+
+            request.session['manifold'] = {'auth': api.auth, 'person': person, 'expires': session['expires']}
+        except ManifoldException, e:
+            print "ManifoldBackend.authenticate caught ManifoldException, returning corresponding ManifoldResult"
+            return e.manifold_result
+        except Exception, e:
+            print "E: manifoldbackend", e
+            import traceback
+            traceback.print_exc()
+            return None
+
+        try:
+            # Check if the user exists in Django's local database
+            user = User.objects.get(username=username)
+        except User.DoesNotExist:
+            # Create a user in Django's local database
+            user = User.objects.create_user(username, username, 'passworddoesntmatter')
+            user.first_name = "DUMMY_FIRST_NAME" #person['first_name']
+            user.last_name = "DUMMY LAST NAME" # person['last_name']
+            user.email = person['email']
+        return user
+
+    # Required for your backend to work properly - unchanged in most scenarios
+    def get_user(self, user_id):
+        try:
+            return User.objects.get(pk=user_id)
+        except User.DoesNotExist:
+            return None
+
+
index ca111de..01b48f5 100644 (file)
@@ -33,13 +33,13 @@ Array.prototype.equals = function (array) {
         if (this[i] instanceof Array && array[i] instanceof Array) {
             // recurse into the nested arrays
             if (!this[i].equals(array[i]))
-                return false;
-        }
-        else if (this[i] != array[i]) {
+                return false;       
+        }           
+        else if (this[i] != array[i]) { 
             // Warning - two different object instances will never be equal: {x:20} != {x:20}
-            return false;
-        }
-    }
+            return false;   
+        }           
+    }       
     return true;
 }
 
@@ -360,6 +360,7 @@ function QueryStore() {
             //var key = manifold.metadata.get_key(query_ext.query.object);
             
             var record_key_value = manifold.record_get_value(record, record_key);
+            
             query_ext.records.put(record_key_value, record);
 
             if (!(query_ext.state.get(record_key_value)))
@@ -1115,6 +1116,9 @@ var manifold = {
          * otherwise, publish the main object as well as subqueries
          * XXX how much recursive are we ?
          */
+        if (records == null){
+            records = Array();
+        }
         if (manifold.pubsub_debug)
              messages.debug (">>>>> publish_result_rec " + query.object);
         if (manifold.query_expects_unique_result(query)) {
index 5ce5260..1a46e6d 100644 (file)
@@ -33,7 +33,7 @@ class ConfigEngine(object):
 
     default_manifold_admin_user     = 'admin'
     default_manifold_admin_password = 'demo'
-    default_myslice_theme           = 'onelab'
+    default_myslice_theme           = 'fibre'
 
 
     def __init__ (self):
@@ -48,7 +48,9 @@ class ConfigEngine(object):
 
         parser.add_section('googlemap')
         parser.set ('googlemap','api_key', None)
+        print os.path.join(ROOT,'myslice/myslice.ini')
         parser.read (os.path.join(ROOT,'myslice/myslice.ini'))
+        print parser
         self.config_parser=parser
 
     def __getattr__(self, section):
index 235a18c..89565dd 100644 (file)
@@ -42,9 +42,9 @@ except:
 # when deployed from a package
 # this code is run by collectstatic too, so we cannot
 # assume we have ./static present already
-HTTPROOT="/var/myslice-f4f"
+HTTPROOT="/var/www/myslice"
 # the place to store local data, like e.g. the sqlite db
-DATAROOT="/var/unfold"
+DATAROOT="/var/www/myslice"
 # if not there, then we assume it's from a devel tree
 if not os.path.isdir (os.path.join(HTTPROOT,"static")):
     HTTPROOT=ROOT
@@ -199,6 +199,7 @@ ROOT_URLCONF = 'myslice.urls'
 
 # Python dotted path to the WSGI application used by Django's runserver.
 WSGI_APPLICATION = 'unfold.wsgi.application'
+#WSGI_APPLICATION = 'myslice.wsgi.application'
 
 TEMPLATE_DIRS = [ ]
 # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
@@ -290,8 +291,10 @@ CSRF_FAILURE_VIEW = 'manifoldapi.manifoldproxy.csrf_failure'
 # put stuff under static/
 # IA_MEDIA_PREFIX = '/code/'
 
+SESSION_ENGINE = 'django.contrib.sessions.backends.file'
+
 ####SLA#####
 
 SLA_MANAGER_URL = "http://157.193.215.125:4000/sla-service"
 SLA_MANAGER_USER = "normal_user"
-SLA_MANAGER_PASSWORD = "password"
\ No newline at end of file
+SLA_MANAGER_PASSWORD = "password"
index 91511b7..7b8dea1 100644 (file)
@@ -17,6 +17,8 @@ import portal.dashboardview
 import portal.homeview
 import portal.newsview
 
+import plugins.cafe.edelberto
+
 from portal.about                   import AboutView
 from portal.registrationview        import RegistrationView
 from portal.accountview             import AccountView, account_process
@@ -134,3 +136,10 @@ for aux in auxiliaries:
         urls.append ( url ( r'^%s/'%aux, include ('%s.urls'%aux )))
 
 urlpatterns = patterns(*urls)
+
+# Shibboleth - Edelberto
+urlpatterns += patterns('',
+   url(r'^cafe/', plugins.cafe.edelberto.EdelbertoView.as_view()),
+   #url(r'^cafe/', 'plugins.cafe.edelberto.index'),
+)
+
diff --git a/old.unfold.sqlite3-110314 b/old.unfold.sqlite3-110314
new file mode 100644 (file)
index 0000000..7c680de
Binary files /dev/null and b/old.unfold.sqlite3-110314 differ
index 259723b..e554f2b 100755 (executable)
             //alert("1");\r
         </script>\r
     </div>\r
+</div>\r
diff --git a/portal/actions-100314.py b/portal/actions-100314.py
new file mode 100644 (file)
index 0000000..62f95bc
--- /dev/null
@@ -0,0 +1,602 @@
+from django.http                import HttpResponse
+from manifold.core.query        import Query
+from manifoldapi.manifoldapi    import execute_query,execute_admin_query
+from portal.models              import PendingUser, PendingSlice, PendingAuthority
+import json
+
+from django.contrib.auth.models import User
+from django.template.loader     import render_to_string
+from django.core.mail           import EmailMultiAlternatives
+
+from theme                      import ThemeView
+
+theme = ThemeView()
+
+# Thierry: moving this right into the code so 
+# most people can use myslice without having to install sfa
+# XXX tmp sfa dependency, should be moved to SFA gateway
+#from sfa.util.xrn                import Xrn 
+
+
+# Get the list of authorities
+
+def authority_get_pis(request, authority_hrn):
+    query = Query.get('authority').filter_by('authority_hrn', '==', authority_hrn).select('pi_users')
+    results = execute_admin_query(request, query)
+    # NOTE: temporarily commented. Because results is giving empty list. 
+    # Needs more debugging
+    #if not results:
+    #    raise Exception, "Authority not found: %s" % authority_hrn
+    #result, = results
+    #return result['pi_users']
+    return results
+
+def authority_get_pi_emails(request, authority_hrn):
+    pi_users = authority_get_pis(request,authority_hrn)
+    if any(d['pi_users'] == None for d in pi_users):
+        theme.template_name = 'email_default_recipients.txt' 
+        default_email = render_to_string(theme.template, request)
+        default_email = default_email.replace('\n', '')
+        return default_email
+    else:
+        pi_user_hrns = [ hrn for x in pi_users for hrn in x['pi_users'] ]
+        query = Query.get('user').filter_by('user_hrn', 'included', pi_user_hrns).select('user_email')
+        results = execute_admin_query(request, query)
+        return [result['user_email'] for result in results]
+
+def is_pi(wsgi_request, user_hrn, authority_hrn):
+    # XXX could be done in a single query !
+
+    # select pi_authorities from user where user_hrn == "ple.upmc.jordan_auge"
+    query = Query.get('user').filter_by('user_hrn', '==', user_hrn).select('pi_authorities')
+    results = execute_admin_query(wsgi_request, query)
+    if not results:
+        # XXX Warning ?
+        return False
+    result = results[0]
+    user_authority_hrns = result.get('pi_authorities', [])
+    return authority_hrn in user_authority_hrns
+    
+# SFA get record
+
+def sfa_get_user(request, user_hrn, pub):
+    query_sfa_user = Query.get('user').filter_by('user_hrn', '==', user_hrn)
+    result_sfa_user = execute_query(request, query_sfa_user)
+    return result_sfa_user                        
+
+def sfa_update_user(request, user_hrn, user_params):
+    # user_params: keys [public_key] 
+    if 'email' in user_params:
+        user_params['user_email'] = user_params['email']
+    query = Query.update('user').filter_by('user_hrn', '==', user_hrn).set(user_params).select('user_hrn')
+    results = execute_query(request,query)
+    return results
+
+def sfa_add_authority(request, authority_params):
+    query = Query.create('authority').set(authority_params).select('authority_hrn')
+    results = execute_query(request, query)
+    print "sfa_add_auth results=",results
+    if not results:
+        raise Exception, "Could not create %s. Already exists ?" % authority_params['hrn']
+    return results
+
+def sfa_add_user_to_slice(request, user_hrn, slice_params):
+# UPDATE myslice:slice SET researcher=['ple.upmc.jordan_auge','ple.inria.thierry_parmentelat','ple.upmc.loic_baron','ple.upmc.ciro_scognamiglio','ple.upmc.mohammed-yasin_rahman','ple.upmc.azerty'] where slice_hrn=='ple.upmc.myslicedemo'
+    query_current_users = Query.get('slice').select('user').filter_by('slice_hrn','==',slice_params['hrn'])
+    results_current_users = execute_query(request, query_current_users)
+    slice_params['researcher'] = slice_params['researcher'] | results_current_users
+    query = Query.update('slice').filter_by('user_hrn', '==', user_hrn).set(slice_params).select('slice_hrn')
+    results = execute_query(request, query)
+# Also possible but not supported yet
+# UPDATE myslice:user SET slice=['ple.upmc.agent','ple.upmc.myslicedemo','ple.upmc.tophat'] where user_hrn=='ple.upmc.azerty'
+    if not results:
+        raise Exception, "Could not create %s. Already exists ?" % slice_params['hrn']
+    return results
+
+# Propose hrn
+
+def manifold_add_user(wsgi_request, request):
+    """Add a Manifold user corresponding to a user request.
+
+    Args:
+        wsgi_request: a WSGIRequest instance
+        request (dict): a dictionary containing the user request built from the
+            form.
+
+    Returns:
+        The user_id of the inserted user.
+
+    Raises:
+        ?
+    
+    """
+    USER_CONFIG = '{"firstname": "%(first_name)s", "lastname": "%(last_name)s", "authority": "%(authority_hrn)s"}'
+
+    user_params = {
+        'email'     : request['email'],
+        'password'  : request['password'],
+        'config'    : USER_CONFIG % request,
+        'status'    : 1,
+    }
+
+    query = Query.create('local:user').set(user_params).select('email')
+    results = execute_admin_query(request, query)
+    if not results:
+        raise Exception, "Failed creating manifold user: %s" % user_params['email']
+    result = results[0]
+    return result['email']
+
+def manifold_update_user(request, email, user_params):
+    # user_params: password, config e.g., 
+    query = Query.update('local:user').filter_by('email', '==', email).set(user_params).select('email')
+    results = execute_admin_query(request,query)
+    # NOTE: results remains empty and goes to Exception. However, it updates the manifold DB.
+    # That's why I commented the exception part. -- Yasin 
+    #if not results:
+    #    raise Exception, "Failed updating manifold user: %s" % user_params['email']
+    #result, = results
+    return results
+
+def manifold_add_account(request, account_params):
+    query = Query.create('local:account').set(account_params).select(['user', 'platform'])
+    results = execute_admin_query(request,query)
+    if not results:
+        raise Exception, "Failed creating manifold account on platform %s for user: %s" % (account_params['platform'], account_params['user'])
+    result, = results
+    return result['user_id']
+
+def manifold_update_account(request,user_id,account_params):
+    # account_params: config
+    query = Query.update('local:account').filter_by('platform', '==', 'myslice').filter_by('user_id', '==', user_id).set(account_params).select('user_id')
+    results = execute_admin_query(request,query)
+    return results
+
+#explicitly mention the platform_id
+def manifold_delete_account(request, platform_id, user_id, account_params):
+    query = Query.delete('local:account').filter_by('platform_id', '==', platform_id).filter_by('user_id', '==', user_id).set(account_params).select('user_id')
+    results = execute_admin_query(request,query)
+    return results
+
+
+#not tested
+def manifold_add_platform(request, platform_params):
+    query = Query.create('local:platform').set(platform_params).select(['user', 'platform'])
+    results = execute_admin_query(request,query)
+    if not results:
+        raise Exception, "Failed creating manifold platform %s for user: %s" % (platform_params['platform'], platform_params['user'])
+    result, = results
+    return result['platform_id']
+
+
+def make_request_user(user):
+    request = {}
+    request['type']          = 'user'
+    request['id']            = user.id
+    request['timestamp']     = user.created # XXX in DB ?
+    request['authority_hrn'] = user.authority_hrn
+    request['first_name']    = user.first_name
+    request['last_name']     = user.last_name
+    request['email']         = user.email
+    request['login']         = user.login
+    request['user_hrn']      = user.user_hrn
+    request['public_key']    = user.public_key
+    request['private_key']   = user.private_key
+    return request
+
+def make_request_slice(slice):
+    request = {}
+    request['type'] = 'slice'
+    request['id'] = slice.id
+    request['user_hrn'] = slice.user_hrn
+    request['timestamp'] = slice.created
+    request['authority_hrn'] = slice.authority_hrn
+    request['slice_name'] = slice.slice_name
+    request['number_of_nodes'] = slice.number_of_nodes
+    request['type_of_nodes'] = slice.type_of_nodes
+    request['purpose'] = slice.purpose
+    return request
+
+def make_request_authority(authority):
+    request = {}
+    request['type']                  = 'authority'
+    request['id']                    = authority.id
+    request['site_name']             = authority.site_name
+    request['site_latitude']         = authority.site_latitude
+    request['site_longitude']        = authority.site_longitude
+    request['site_url']              = authority.site_url
+    request['site_authority']        = authority.site_authority
+    request['site_abbreviated_name'] = authority.site_abbreviated_name
+    request['address_line1']         = authority.address_line1
+    request['address_line2']         = authority.address_line2
+    request['address_line3']         = authority.address_line3
+    request['address_city']          = authority.address_city
+    request['address_postalcode']    = authority.address_postalcode
+    request['address_state']         = authority.address_state
+    request['address_country']       = authority.address_country
+    request['authority_hrn']         = authority.authority_hrn
+    request['timestamp']             = authority.created
+    return request
+
+def make_requests(pending_users, pending_slices, pending_authorities):
+    requests = []
+    for user in pending_users:
+        requests.append(make_request_user(user))
+    for slice in pending_slices:
+        requests.append(make_request_slice(slice))
+    for authority in pending_authorities:
+        requests.append(make_request_authority(authority))
+    return requests   
+
+def get_request_by_id(ids):
+    sorted_ids = { 'user': [], 'slice': [], 'authority': [] }
+    for type__id in ids:
+        type, id = type__id.split('__')
+        sorted_ids[type].append(id)
+        
+    if not ids:
+        pending_users  = PendingUser.objects.all()
+        pending_slices = PendingSlice.objects.all()
+        pending_authorities = PendingAuthority.objects.all()
+    else:
+        pending_users  = PendingUser.objects.filter(id__in=sorted_ids['user']).all()
+        pending_slices = PendingSlice.objects.filter(id__in=sorted_ids['slice']).all()
+        pending_authorities = PendingAuthority.objects.filter(id__in=sorted_ids['authority']).all()
+
+    return make_requests(pending_users, pending_slices, pending_authorities)
+
+def get_requests(authority_hrns=None):
+    print "get_request_by_authority auth_hrns = ", authority_hrns
+    if not authority_hrns:
+        pending_users  = PendingUser.objects.all()
+        pending_slices = PendingSlice.objects.all()
+        pending_authorities = PendingAuthority.objects.all()
+    else:
+        pending_users  = PendingUser.objects.filter(authority_hrn__in=authority_hrns).all()
+        pending_slices = PendingSlice.objects.filter(authority_hrn__in=authority_hrns).all()
+        pending_authorities = PendingAuthority.objects.filter(authority_hrn__in=authority_hrns).all()
+
+    return make_requests(pending_users, pending_slices, pending_authorities)
+
+# XXX Is it in sync with the form fields ?
+
+def portal_validate_request(wsgi_request, request_ids):
+    status = {}
+
+    if not isinstance(request_ids, list):
+        request_ids = [request_ids]
+
+    requests = get_request_by_id(request_ids)
+    for request in requests:
+        # type, id, timestamp, details, allowed -- MISSING: authority_hrn
+        # CAREFUL about details
+        # user  : first name, last name, email, password, keypair
+        # slice : number of nodes, type of nodes, purpose
+        
+        request_status = {}
+
+        if request['type'] == 'user':
+
+            try:
+                create_user(wsgi_request, request)
+                request_status['SFA user'] = {'status': True }
+
+            except Exception, e:
+                 request_status['SFA user'] = {'status': False, 'description': str(e)}
+                       
+#            user_params = {'status':2}
+#            manifold_update_user(request, request['email'], user_params)
+
+            # MANIFOLD user should be added beforehand, during registration
+            #try:
+            #    manifold_user_params = { key: request[key] for key in MANIFOLD_USER_KEYS }
+            #    # XXX # manifold_add_user(manifold_user_params)
+            #    request_status['MySlice user'] = {'status': True }
+            #except Exception, e:
+            #    request_status['MySlice user'] = {'status': False, 'description': str(e)}
+
+            # XXX
+            #manifold_account_params = { key: request[key] for key in MANIFOLD_ACCOUNT_KEYS }
+            #manifold_add_account(manifold_account_params)
+            #request_status['MySlice testbed accounts'] = {'status': False }
+
+        elif request['type'] == 'slice':
+            try:
+                create_slice(wsgi_request, request)
+                request_status['SFA slice'] = {'status': True }
+
+            except Exception, e:
+                request_status['SFA slice'] = {'status': False, 'description': str(e)}
+
+        elif request['type'] == 'authority':
+            try:
+                #hrn = "%s.%s" % (request['authority_hrn'], request['site_authority'])
+                hrn = request['site_authority']
+                # XXX tmp sfa dependency
+                from sfa.util.xrn import Xrn 
+                urn = Xrn(hrn, request['type']).get_urn()
+
+                sfa_authority_params = {
+                    'hrn'        : hrn,
+                    'urn'        : urn,
+                    'type'       : request['type'],
+                    #'pi'        : None,
+                    'enabled'    : True
+                }
+                print "ADD Authority"
+                sfa_add_authority(wsgi_request, sfa_authority_params)
+                request_status['SFA authority'] = {'status': True }
+
+            except Exception, e:
+                request_status['SFA authority'] = {'status': False, 'description': str(e)}
+
+        # XXX Remove from Pendings in database
+
+        status['%s__%s' % (request['type'], request['id'])] = request_status
+
+    return status
+
+
+def validate_action(request, **kwargs):
+    ids = filter(None, kwargs['id'].split('/'))
+    status = portal_validate_request(request, ids)
+    json_answer = json.dumps(status)
+    return HttpResponse (json_answer, mimetype="application/json")
+
+# Django and ajax
+# http://djangosnippets.org/snippets/942/
+
+
+
+#-------------------------------------------------------------------------------
+# REQUESTS - Slices
+#-------------------------------------------------------------------------------
+
+def create_slice(wsgi_request, request):
+    """
+    Arguments:
+        wsgi_request (~ WSGIRequest) : 
+        request (dict) : the slice request in our own dict format
+
+    Raises:
+        Exception
+    """
+    hrn = "%s.%s" % (request['authority_hrn'], request['slice_name'])
+    # XXX tmp sfa dependency
+    from sfa.util.xrn import Xrn 
+    urn = Xrn(hrn, request['type']).get_urn()
+    
+    # Add User to Slice if we have the user_hrn in pendingslice table
+    user_hrn = request.get('user_hrn', None)
+    user_hrns = list([user_hrn]) if user_hrn else list()
+
+    # XXX We should create a slice with Manifold terminology
+    slice_params = {
+        'slice_hrn'        : hrn, 
+        'slice_urn'        : urn,
+        'slice_type'       : request['type'],
+        'users'            : user_hrns,
+        'slice_enabled'    : True
+    }
+    # ignored in request: id, timestamp,  number_of_nodes, type_of_nodes, purpose
+
+    query = Query.create('slice').set(slice_params).select('slice_hrn')
+    results = execute_query(wsgi_request, query)
+    if not results:
+        raise Exception, "Could not create %s. Already exists ?" % slice_params['hrn']
+    return results
+
+def create_pending_slice(wsgi_request, request, email):
+    """
+    """
+
+    # Insert an entry in the PendingSlice table
+    s = PendingSlice(
+        slice_name      = request['slice_name'],
+        user_hrn        = request['user_hrn'],
+        authority_hrn   = request['authority_hrn'],
+        number_of_nodes = request['number_of_nodes'],
+        purpose         = request['purpose'],
+    )
+    s.save()
+
+    try:
+        # Send an email: the recipients are the PI of the authority
+        recipients = authority_get_pi_emails(wsgi_request, request['authority_hrn'])
+    
+        theme.template_name = 'slice_request_email.txt' 
+        text_content = render_to_string(theme.template, request)
+    
+        theme.template_name = 'slice_request_email.html' 
+        html_content = render_to_string(theme.template, request)
+    
+        theme.template_name = 'slice_request_email_subject.txt'
+        subject = render_to_string(theme.template, request)
+        subject = subject.replace('\n', '')
+    
+        sender = email
+        msg = EmailMultiAlternatives(subject, text_content, sender, [recipients])
+        print msg
+        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"
+
+#-------------------------------------------------------------------------------
+# REQUESTS - Users
+#-------------------------------------------------------------------------------
+
+def manifold_add_reference_user_accounts(wsgi_request, request):
+    """When a new user is created, add reference accounts to the reference platform.
+    """
+    # XXX XXX XXX The rest of this function has to be checked XXX XXX XXX
+
+    # Retrieve user information
+    user_query  = Query().get('local:user')             \
+        .select('user_id', 'config', 'email', 'status') \
+        .filter_by('email', '==', request['email'])
+    user_details = execute_admin_query(wsgi_request, user_query)
+
+    # USER MAIN ACCOUNT != reference
+    #print 'USER MAIN ACCOUNT != reference'
+    list_accounts_query = Query().get('local:account')              \
+        .select('user_id', 'platform_id', 'auth_type', 'config')    \
+        .filter_by('user_id', '==', user_details[0]['user_id'])     \
+        .filter_by('auth_type', '!=', 'reference')
+    list_accounts = execute_admin_query(wsgi_request, list_accounts_query)
+
+    # XXX main_platform is being erased several times ???
+    for account in list_accounts:
+        main_platform_query = Query().get('local:platform')         \
+            .select('platform_id', 'platform')                      \
+            .filter_by('platform_id', '==', account['platform_id'])
+        main_platform = execute_admin_query(wsgi_request, main_platform_query)
+
+    # Add reference accounts on SFA enabled platforms
+    platforms_query = Query().get('local:platform') \
+        .filter_by('disabled', '==', '0')           \
+        .filter_by('gateway_type', '==', 'sfa')     \
+        .select('platform_id', 'gateway_type')
+    platforms = execute_admin_query(wsgi_request, platforms_query)
+    for platform in platforms:
+        #print "add reference to platform ",platform
+        manifold_account_params = {
+            'user_id'       : user_details[0]['user_id'],
+            'platform_id'   : platform['platform_id'],
+            'auth_type'     : 'reference',
+            'config'        : '{"reference_platform": "' + main_platform[0]['platform'] + '"}',
+        }
+        manifold_add_account(wsgi_request, manifold_account_params)
+
+def sfa_create_user(wsgi_request, request):
+    """
+    Arguments:
+        wsgi_request (~ WSGIRequest) : 
+        request (dict) : the user request in our own dict format
+
+    Raises:
+        Exception
+    """
+    from sfa.util.xrn import Xrn 
+
+    auth_pi = request.get('pi', None)
+    auth_pi = list([auth_pi]) if auth_pi else list()
+
+    # We create a user request with Manifold terminology
+    sfa_user_params = {
+        'user_hrn'          : request['user_hrn'],
+        'user_email'        : request['email'],
+        'user_urn'          : Xrn(request['user_hrn'], request['type']).get_urn(),
+        'user_type'         : request['type'],
+        'keys'              : request['public_key'],
+        'user_first_name'   : request['first_name'],
+        'user_last_name'    : request['last_name'],
+        'pi_authorities'    : auth_pi,
+        'user_enabled'      : True
+    }
+
+    query = Query.create('user').set(sfa_user_params).select('user_hrn')
+    results = execute_query(wsgi_request, query)
+    if not results:
+        raise Exception, "Could not create %s. Already exists ?" % sfa_user_params['user_hrn']
+    return results
+
+#def ldap_create_user
+
+def create_user(wsgi_request, request):
+    
+    # XXX This has to be stored centrally
+    USER_STATUS_ENABLED = 2
+
+    # NOTE : if we were to create a user directly (just like we create slices,
+    # we would have to perform the steps in create_pending_user too
+
+    # Add the user to the SFA registry
+    sfa_create_user(wsgi_request, request)
+
+    # Update Manifold user status
+    manifold_update_user(wsgi_request, request['email'], {'status': USER_STATUS_ENABLED})
+
+    # Add reference accounts for platforms
+    manifold_add_reference_user_accounts(wsgi_request, request)
+
+def create_pending_user(wsgi_request, request, user_detail):
+    """
+    """
+
+    # Insert an entry in the PendingUser table
+    b = PendingUser(
+        first_name    = request['first_name'],
+        last_name     = request['last_name'],
+        authority_hrn = request['authority_hrn'],
+        email         = request['email'],
+        password      = request['password'],
+        public_key    = request['public_key'],
+        private_key   = request['private_key'],
+        user_hrn      = request['user_hrn'],
+        pi            = '',                         # XXX Why not None ?
+    )
+    b.save()
+
+    # saves the user to django auth_user table [needed for password reset]
+    user = User.objects.create_user(request['email'], request['email'], request['password'])
+
+    # Creating a manifold user
+    user_id = manifold_add_user(wsgi_request, request)
+
+    # Creating a Manifold account on the MySlice platform
+    # Note the JSON representation of public and private keys already includes quotes
+    account_config = {
+        'user_hrn'          : request['user_hrn'],
+        'user_public_key'   : request['public_key'],
+    }
+    if request['private_key']:
+        account_config['user_private_key'] = request['private_key']
+
+    user_id = user_detail['user_id'] + 1 # the user_id for the newly created user in local:user
+
+    # XXX TODO: Require a myslice platform
+    # ALERT: this will disapear with ROUTERV2 of Manifold
+    # We have to consider the case where several registries can be used
+    # Removed hardcoded platform = 5
+    # This platform == 'myslice' is a TMP FIX !!
+    try:
+        reg_platform_query = Query().get('local:platform') \
+            .filter_by('platform', '==', 'myslice')           \
+            .select('platform_id')
+        reg_platform = execute_admin_query(wsgi_request, reg_platform_query)
+
+        registry_platform_id = reg_platform[0]['platform_id']
+        account_params = {
+            'platform_id'   : reg_platform_id, # XXX ALERT !!
+            'user_id'       : user_id, 
+            'auth_type'     : request['auth_type'], 
+            'config'        : json.dumps(account_config),
+        }
+        manifold_add_account(wsgi_request, account_params)
+    except Exception, e:
+        print "Failed creating manifold account on platform %s for user: %s" % ('myslice', request['email'])
+
+    try:
+        # Send an email: the recipients are the PI of the authority
+        # If No PI is defined for this Authority, send to a default email (different for each theme)
+        recipients = authority_get_pi_emails(wsgi_request, request['authority_hrn'])
+        
+        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"
index 400f3a7..a76e3a7 100644 (file)
@@ -12,6 +12,9 @@ from django.core.mail           import EmailMultiAlternatives, send_mail
 
 from myslice.theme              import ThemeView
 
+# LS Client - By Bruno Soares (UFG)
+from lsapiclient                import LaboraSchedulerClient
+
 theme = ThemeView()
 
 import activity.slice
@@ -58,7 +61,7 @@ def clear_user_creds(request, user_email):
     try:
         user_query  = Query().get('local:user').filter_by('email', '==', user_email).select('user_id','email','password','config')
         user_details = execute_admin_query(request, user_query)
-    
+
         # getting the user_id from the session
         for user_detail in user_details:
             user_id = user_detail['user_id']
@@ -158,15 +161,21 @@ def manifold_add_user(wsgi_request, request):
         ?
     
     """
+
+    authority_hrn = request['authority_hrn']
+    request['authority_hrn'] = authority_hrn.split(".")[0]
+
     USER_CONFIG = '{"firstname": "%(first_name)s", "lastname": "%(last_name)s", "authority": "%(authority_hrn)s"}'
 
     user_params = {
-        'email'     : request['email'],
+        'email'     : request['username'],
         'password'  : request['password'],
         'config'    : USER_CONFIG % request,
-        'status'    : 1,
+        'status'    : 1
     }
 
+    request['authority_hrn'] = authority_hrn
+
     query = Query.create('local:user').set(user_params).select('email')
     results = execute_admin_query(request, query)
     if not results:
@@ -234,6 +243,8 @@ def make_request_user(user):
     request['user_hrn']      = user.user_hrn
     request['public_key']    = user.public_key
     request['private_key']   = user.private_key
+    request['username']             = user.login
+    request['reasons']       = user.reasons
     return request
 
 def make_request_slice(slice):
@@ -658,6 +669,21 @@ def create_pending_slice(wsgi_request, request, email):
     try:
         # Send an email: the recipients are the PI of the authority
         recipients = authority_get_pi_emails(wsgi_request, request['authority_hrn'])
+       
+       pis = authority_get_pis(request, request['authority_hrn'])
+        pi_emails = []
+        for x in pis:
+            for e in x['pi_users']:
+                try:
+                    u = e.split(".")[1]
+                    y = User.objects.get(username = u)
+                   print y.username
+                    if y.username.count("@") != 0:
+                        if y.username.split("@")[1] == request['user_hrn'].split("@")[1]:
+                            pi_emails += [y.email]
+                           print y.email
+                except:
+                    print "fail"
 
         theme.template_name = 'slice_request_email.txt' 
         text_content = render_to_string(theme.template, request)
@@ -669,8 +695,12 @@ def create_pending_slice(wsgi_request, request, email):
         subject = render_to_string(theme.template, request)
         subject = subject.replace('\n', '')
     
-        sender = email
-        msg = EmailMultiAlternatives(subject, text_content, sender, recipients)
+        theme.template_name = 'email_default_sender.txt'
+        sender =  render_to_string(theme.template, request)
+        sender = sender.replace('\n', '')
+
+        #sender = email
+        msg = EmailMultiAlternatives(subject, text_content, sender, pi_emails)
         msg.attach_alternative(html_content, "text/html")
         msg.send()
     except Exception, e:
@@ -688,7 +718,7 @@ def manifold_add_reference_user_accounts(wsgi_request, request):
     # Retrieve user information
     user_query  = Query().get('local:user')             \
         .select('user_id', 'config', 'email', 'status') \
-        .filter_by('email', '==', request['email'])
+        .filter_by('email', '==', request['username'])
     user_details = execute_admin_query(wsgi_request, user_query)
 
     # USER MAIN ACCOUNT != reference
@@ -749,6 +779,10 @@ def sfa_create_user(wsgi_request, request, namespace = None, as_admin = False):
         'user_enabled'      : True
     }
 
+    ## Conflict
+    #query = Query.create('user').set(sfa_user_params).select('user_hrn')
+    #results = execute_query(wsgi_request, query)
+
     if namespace is not None:
         query = Query.create('%s:user' % namespace).set(sfa_user_params).select('user_hrn')
     else:
@@ -762,26 +796,64 @@ def sfa_create_user(wsgi_request, request, namespace = None, as_admin = False):
     if not results:
         raise Exception, "Could not create %s. Already exists ?" % sfa_user_params['user_hrn']
     else:
-        try:
-            theme.template_name = 'user_request_validated.txt'
-            text_content = render_to_string(theme.template, request)
-            theme.template_name = 'user_request_validated.html'
-            html_content = render_to_string(theme.template, request)
-        
-            theme.template_name = 'email_default_sender.txt'
-            sender =  render_to_string(theme.template, request)
-            sender = sender.replace('\n', '')
+        subject = 'User validated'
+        msg = 'A manager of your institution has validated your account. You have now full user access to the portal.'
+        send_mail(subject, msg, 'support@fibre.org.br',[request['email']], fail_silently=False)       
+    return results
 
+def ls_create_user(wsgi_request, request, user_detail):
+    organization = request['username'].split('@')[1]
+    lsClient = LaboraSchedulerClient( organization )
 
-            subject = 'User validated'
+    orgGIDNumber = lsClient.get_testbed_info()['gidnumber']
+    userHomeDirectory = "/home/" + organization + "/" + request['username'].split('@')[0]
+    userHomeDirectory = userHomeDirectory.encode('utf-8')
+    
+    userData = {
+        'username'      : request['username'],
+        'email'         : request['email'].encode('utf-8'),
+        'password'      : request['password'].encode('utf-8'),
+        'name'          : str( request['first_name'].encode('latin1') ) + ' ' + str( request['last_name'].encode('latin1') ),
+        'gidnumber'     : orgGIDNumber,
+        'homedirectory' : userHomeDirectory,
+        'created_by'    : "myslice"
+    }
+    
+    # Add user in the island.
+    addUser = lsClient.add_user( userData )
+    
+    # User successfully created, upload user public key.
+    if addUser:
+        ls_update_public_key( wsgi_request, request, lsClient, addUser )
+    
+    return addUser
 
-            msg = EmailMultiAlternatives(subject, text_content, sender, [request['email']])
-            msg.attach_alternative(html_content, "text/html")
-            msg.send()
-        except Exception, e:
-            print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
+def ls_validate_user(wsgi_request, request):
+    organization = request['username'].split('@')[1]
+    lsClient = LaboraSchedulerClient( organization )
+    
+    userId = lsClient.get_user_id_by_username( { 'username': str( request['username'] ) } )
+    
+    validate = False
+    if userId:
+        userData = {
+            'user_id'       : userId,
+            'new_user_data' : { 'enable': 'TRUE' }
+        }
+        
+        validate = lsClient.update_user( userData )
+        
+    return validate and addUserPublicKey
 
-    return results
+def ls_update_public_key( wsgi_request, request, lsClient, userId ):
+    userPbKey = {
+        'user_id'       : userId,
+        'public_key'    : request['public_key']
+    }
+    
+    addUserPublicKey = lsClient.add_user_public_key( userPbKey )
+    
+    return addUserPublicKey
 
 def iotlab_create_user (wsgi_request, request, namespace = None, as_admin=False):
    
@@ -825,15 +897,129 @@ def create_user(wsgi_request, request, namespace = None, as_admin = False):
 
     # NOTE : if we were to create a user directly (just like we create slices,
     # we would have to perform the steps in create_pending_user too
+    
+    # Edelberto - I put this more below
+    # Add the user to the SFA registry
+    #sfa_create_user(wsgi_request, request)
+
+    # Update Manifold user status
+    manifold_update_user(wsgi_request, request['username'], {'status': USER_STATUS_ENABLED})
 
+    # Add reference accounts for platforms
+    manifold_add_reference_user_accounts(wsgi_request, request)
+    
+    # Conflict 
+    # sfa_create_user(wsgi_request, request)
     # Add the user to the SFA registry
     sfa_create_user(wsgi_request, request, namespace, as_admin)
+  
+    # Validate the user using the LS API ( By Bruno - UFG ):
+    try:
+        ls_validate_user( wsgi_request, request )
+    except Exception, e:
+        "Error to validate the user in Labora Scheduler."
+
+def create_user_in_ldap(wsgi_request, request, user_detail):
+    """
+    """
+   
+    # saves the user to django auth_user table [needed for password reset]
+    user = User.objects.create_user(request['username'], request['email'], request['password'])
+
+    # Creating a manifold user
+    user_id = manifold_add_user(wsgi_request, request)
+
+    # Creating a Manifold account on the MySlice platform
+    # Note the JSON representation of public and private keys already includes quotes
+    account_config = {
+        'user_hrn'          : request['user_hrn'],
+        'user_public_key'   : request['public_key'],
+    }
+    if request['private_key']:
+        account_config['user_private_key'] = request['private_key']
+
+    user_id = user_detail['user_id'] + 1 # the user_id for the newly created user in local:user
+
+    # XXX TODO: Require a myslice platform
+    # ALERT: this will disapear with ROUTERV2 of Manifold
+    # We have to consider the case where several registries can be used
+    # Removed hardcoded platform = 5
+    # This platform == 'myslice' is a TMP FIX !!
+    try:
+        reg_platform_query = Query().get('local:platform') \
+            .filter_by('platform', '==', 'myslice')           \
+            .select('platform_id')
+        reg_platform = execute_admin_query(wsgi_request, reg_platform_query)
+        reg_platform_id = reg_platform[0]['platform_id']
+        account_params = {
+            'platform_id'   : reg_platform_id, # XXX ALERT !!
+            'user_id'       : user_id, 
+            'auth_type'     : request['auth_type'], 
+            'config'        : json.dumps(account_config),
+        }
+        manifold_add_account(wsgi_request, account_params)
+    except Exception, e:
+       print "Failed creating manifold account on platform %s for user: %s" % ('myslice', request['email'])
+
+    # XXX This has to be stored centrally
+    USER_STATUS_ENABLED = 2
 
     # Update Manifold user status
-    manifold_update_user(wsgi_request, request['email'], {'status': USER_STATUS_ENABLED})
+    manifold_update_user(wsgi_request, request['username'], {'status': USER_STATUS_ENABLED})
 
     # Add reference accounts for platforms
     manifold_add_reference_user_accounts(wsgi_request, request)
+    
+    organization = request['username'].split('@')[1]
+    lsClient = LaboraSchedulerClient( organization )
+    
+    userId = lsClient.get_user_id_by_username( { 'username': str( request['username'] ) } )
+
+    ls_up_pkey = ls_update_public_key( wsgi_request, request, lsClient, userId )
+    
+    if ls_up_pkey:
+        print "OK PKEY"
+
+    from sfa.util.xrn import Xrn 
+
+    auth_pi = request.get('pi', None)
+    auth_pi = list([auth_pi]) if auth_pi else list()
+
+    # We create a user request with Manifold terminology
+    sfa_user_params = {
+        'user_hrn'          : request['user_hrn'],
+        'user_email'        : request['email'],
+        'user_urn'          : Xrn(request['user_hrn'], request['type']).get_urn(),
+        'user_type'         : request['type'],
+        'keys'              : request['public_key'],
+        'user_first_name'   : request['first_name'],
+        'user_last_name'    : request['last_name'],
+        'pi_authorities'    : auth_pi,
+        'user_enabled'      : True
+    }
+
+    print request['user_hrn']
+    print request['email']
+    print request['first_name']
+    print request['last_name']
+    print request['type']
+    print request['public_key']
+
+    query = Query.create('user').set(sfa_user_params).select('user_hrn')
+
+    print query
+
+    results = execute_admin_query(wsgi_request, query)
+
+    print results
+
+    if not results:
+        raise Exception, "Could not create %s. Already exists ?" % sfa_user_params['user_hrn']
+    else:
+        subject = 'User validated'
+        msg = 'A manager of your institution has validated your account. You have now full user access to the portal.'
+        send_mail(subject, msg, 'support@fibre.org.br',[request['email']], fail_silently=False)       
+    return results
 
     # Add the user to iotlab portal if theme is set to onelab
     if theme.theme == 'onelab':
@@ -849,15 +1035,18 @@ def create_pending_user(wsgi_request, request, user_detail):
         last_name     = request['last_name'],
         authority_hrn = request['authority_hrn'],
         email         = request['email'],
+        login         = request['username'],
         password      = request['password'],
         public_key    = request['public_key'],
         private_key   = request['private_key'],
         user_hrn      = request['user_hrn'],
         pi            = request['pi'],
         email_hash    = request['email_hash'],
+       reasons       = request['reasons'],
         status        = 'False',
     )
     b.save()
+
     # sends email to user to activate the email
     theme.template_name = 'activate_user.html'
     html_content = render_to_string(theme.template, request)
@@ -877,7 +1066,7 @@ def create_pending_user(wsgi_request, request, user_detail):
     msg.send()
    
     # saves the user to django auth_user table [needed for password reset]
-    user = User.objects.create_user(request['email'], request['email'], request['password'])
+    user = User.objects.create_user(request['username'], request['email'], request['password'])
 
     # Creating a manifold user
     user_id = manifold_add_user(wsgi_request, request)
@@ -903,7 +1092,6 @@ def create_pending_user(wsgi_request, request, user_detail):
             .filter_by('platform', '==', 'myslice')           \
             .select('platform_id')
         reg_platform = execute_admin_query(wsgi_request, reg_platform_query)
-
         reg_platform_id = reg_platform[0]['platform_id']
         account_params = {
             'platform_id'   : reg_platform_id, # XXX ALERT !!
@@ -913,13 +1101,32 @@ def create_pending_user(wsgi_request, request, user_detail):
         }
         manifold_add_account(wsgi_request, account_params)
     except Exception, e:
-        print "Failed creating manifold account on platform %s for user: %s" % ('myslice', request['email'])
+       print "Failed creating manifold account on platform %s for user: %s" % ('myslice', request['email'])
+
+    # Add user to island using LS API ( By Bruno - UFG )
+    ls_user_create = ls_create_user( wsgi_request, request, user_detail )
 
     try:
         # Send an email: the recipients are the PI of the authority
         # If No PI is defined for this Authority, send to a default email (different for each theme)
-        recipients = authority_get_pi_emails(wsgi_request, request['authority_hrn'])
-        
+
+        split_authority_hrn = request['authority_hrn'].split(".")[0]
+
+        recipients = authority_get_pi_emails(wsgi_request, split_authority_hrn)
+
+        pis = authority_get_pis(request, split_authority_hrn)
+        pi_emails = []
+        for x in pis:
+            for e in x['pi_users']:
+                try:
+                    u = e.split(".")[1]
+                    y = User.objects.get(username = u)
+                    if y.username.count("@") != 0:
+                        if y.username.split("@")[1] == request['username'].split("@")[1]:
+                            pi_emails += [y.email]
+                except:
+                    print "fail"
+
         theme.template_name = 'user_request_email.html'
         html_content = render_to_string(theme.template, request)
  
@@ -934,9 +1141,11 @@ def create_pending_user(wsgi_request, request, user_detail):
         sender =  render_to_string(theme.template, request)
         sender = sender.replace('\n', '')
     
-        msg = EmailMultiAlternatives(subject, text_content, sender, recipients)
+        msg = EmailMultiAlternatives(subject, text_content, sender, pi_emails)
+
         msg.attach_alternative(html_content, "text/html")
         msg.send()
+       print pi_emails
     except Exception, e:
         print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
         import traceback
index 19cc1b9..24e06eb 100644 (file)
@@ -108,5 +108,6 @@ class ContactView (FreeAccessView, ThemeView):
                 'theme' : self.theme,
                 'username': username,
                 'pi': pi,
-                'section': "Contact"
+                'section': "Contact",
+                'email': request.user.username
                 })
diff --git a/portal/database.py b/portal/database.py
new file mode 100644 (file)
index 0000000..376d18b
--- /dev/null
@@ -0,0 +1,57 @@
+import sys
+import psycopg2
+import psycopg2.extras
+
+class Database():
+    
+    def __init__( self, DbConfigurations ):
+        self.connection = None
+        self.connect( DbConfigurations['dbHost'], DbConfigurations['dbUser'],
+                      DbConfigurations['dbPassword'], DbConfigurations['dbName'] )
+    
+    
+    def connect( self, host, user, password, database ):
+        result = True
+        try:
+            self.connection = psycopg2.connect(        "host=" + host + " dbname=" + database + " user=" +
+                                                user + " password=" + password )
+        except psycopg2.DatabaseError, e:
+            result = False
+            
+        return result
+    
+    
+    def close( self ):
+        if self.connection:
+            self.connection.close()
+            self.connection = None
+    
+    
+    def query( self, queryString ):
+        result = True
+        try:
+            cursor = self.connection.cursor()
+            cursor.execute( queryString )
+            self.connection.commit()
+        except Exception, e:
+            result = False
+            self.rollback()
+            
+        return result
+    
+    
+    def rollback( self ):
+        if self.connection:
+            self.connection.rollback()
+    
+    
+    def fetchRows( self, queryString ):
+        rows = None
+        try:
+            cursor = self.connection.cursor( cursor_factory = psycopg2.extras.RealDictCursor )
+            cursor.execute( queryString )
+            rows = cursor.fetchall()
+        except Exception, e:
+            pass
+            
+        return rows
index 533cccf..3dc388b 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, authority_get_pi_emails, make_request_user, create_user
+from portal.actions                     import manifold_update_user, manifold_update_account, manifold_add_account, manifold_delete_account, sfa_update_user, authority_get_pi_emails, make_request_user, create_user, authority_get_pis
 #
 from unfold.page                        import Page    
 from ui.topmenu                         import topmenu_items_live, the_user
@@ -14,7 +14,7 @@ from myslice.theme                      import ThemeView
 from portal.models                      import PendingUser, PendingAuthority
 from django.core.mail                   import EmailMultiAlternatives, send_mail
 from django.contrib.sites.models        import Site
-
+from django.contrib.auth.models         import User
 #
 import json, os, re, itertools
 
@@ -52,6 +52,45 @@ class ActivateEmailView(FreeAccessView, ThemeView):
                 hash_code=value
         if PendingUser.objects.filter(email_hash__iexact = hash_code).filter(status__iexact = 'False'):           
             activation = 'success'
+            # sending email after activation success
+            try:
+                request = PendingUser.objects.filter(email_hash= hash_code)
+                split_authority_hrn = request[0].authority_hrn.split('.')[0]
+                pis = authority_get_pis(request, split_authority_hrn)
+                pi_emails = []
+                for x in pis:
+                    for e in x['pi_users']:
+                        u = e.split('.')[1]
+                       y = User.Objects.get(username = u)
+                       if y.username.count("@") != 0:
+                           if y.username.split("@")[1] == request[0].user_hrn.split("@")[1]:
+                               pi_emails += [y.email]
+                subject = 'User email activated'
+                msg = 'The user %s has validated his/her email. Now you can validate his/her account' % (request[0].login)
+                send_mail(subject, msg, 'support@fibre.org.br', pi_emails, fail_silently = False)
+           except:
+               print "error sending the email!"    
+                #try:
+                    # Send an email: the recipients are the PI of the authority
+                    # If No PI is defined for this Authority, send to a default email (different for each theme)
+                 #   recipients = authority_get_pi_emails(wsgi_request, authority_hrn)
+                 #   theme.template_name = 'user_request_email.html'
+                 #   html_content = render_to_string(theme.template, request)
+                 #   theme.template_name = 'user_request_email.txt'
+                 #   text_content = render_to_string(theme.template, request)
+                 #   theme.template_name = 'user_request_email_subject.txt'
+                 #   subject = render_to_string(theme.template, request)
+                 #   subject = subject.replace('\n', '')
+                 #   theme.template_name = 'email_default_sender.txt'
+                 #   sender =  render_to_string(theme.template, request)
+                 #   sender = sender.replace('\n', '')
+                 #   msg = EmailMultiAlternatives(subject, text_content, sender, recipients)
+                 #   msg.attach_alternative(html_content, "text/html")
+                 #   msg.send()
+               # except Exception, e:
+                 #   print "Failed to send email, please check the mail templates and the SMTP configuration of your server"
+                 #   import traceback
+                 #   traceback.print_exc()
 
             # AUTO VALIDATION of PLE enabled users (only for OneLab Portal)
             if self.theme == "onelab":
index 00b279d..08f3818 100644 (file)
@@ -1,7 +1,7 @@
 # this somehow is not used anymore - should it not be ?
 from django.core.context_processors import csrf
 from django.http import HttpResponseRedirect
-from django.contrib.auth import authenticate, login, logout
+from django.contrib.auth import authenticate, login, logout, get_user_model
 from django.template import RequestContext
 from django.shortcuts import render_to_response
 from django.shortcuts import render
@@ -11,7 +11,20 @@ import json
 from unfold.loginrequired import FreeAccessView
 
 from manifold.core.query                import Query
-from manifoldapi.manifoldapi            import execute_query
+#from manifoldapi.manifoldapi            import execute_query
+# LDAP query admin // If transfer this code to actions.py maybe don't need more execute_admin_query
+from manifoldapi.manifoldapi            import execute_query, execute_admin_query
+# Edelberto - LDAP XXX
+from portal.models             import PendingUser
+from django.contrib.auth.models import User   #Pedro
+from portal.actions             import create_pending_user, create_user, create_user_in_ldap, clear_user_creds
+from registrationview          import RegistrationView
+from random     import randint
+from hashlib    import md5
+from django.contrib.sites.models import Site
+import os.path, re
+##################
+
 
 from manifoldapi.manifoldresult import ManifoldResult
 from ui.topmenu import topmenu_items, the_user
@@ -19,7 +32,10 @@ from myslice.configengine import ConfigEngine
 
 from myslice.theme import ThemeView
 
-import activity.user
+# Edelberto LDAP authentication XXX
+import ldap
+
+#import activity.user
 
 class HomeView (FreeAccessView, ThemeView):
     template_name = 'home-view.html'
@@ -35,86 +51,271 @@ class HomeView (FreeAccessView, ThemeView):
         env['theme'] = self.theme
         env['section'] = "Dashboard"
         
-        username = request.POST.get('username')
+        username = request.POST.get('username').lower()
         password = request.POST.get('password')
-        
-        # pass request within the token, so manifold session key can be attached to the request session.
-        token = {'username': username, 'password': password, 'request': request}    
-
-        # our authenticate function returns either
-        # . a ManifoldResult - when something has gone wrong, like e.g. backend is unreachable
-        # . a django User in case of success
-        # . or None if the backend could be reached but the authentication failed
-        auth_result = authenticate(token=token)
-        # use one or two columns for the layout - not logged in users will see the login prompt
-        # high-level errors, like connection refused or the like
-        if isinstance (auth_result, ManifoldResult):
-            manifoldresult = auth_result
-            # let's use ManifoldResult.__repr__
-            env['state']="%s"%manifoldresult
-            
-            return render_to_response(self.template,env, context_instance=RequestContext(request))
-        # user was authenticated at the backend
-        elif auth_result is not None:
-            user=auth_result
-            if user.is_active:
-                print "LOGGING IN"
-                login(request, user)
-                
-                if request.user.is_authenticated(): 
-                    env['person'] = self.request.user
-                    env['username'] = self.request.user
-                    
-                    # log user activity
-                    activity.user.login(self.request)
-                    
-                    ## check user is pi or not
-                    platform_details = {}
-                    account_details = {}
-                    acc_auth_cred = {}
-                    acc_user_cred = {}
-                    platform_query  = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled')
-                    account_query  = Query().get('local:account').select('user_id','platform_id','auth_type','config')
-                    platform_details = execute_query(self.request, platform_query)
-                    account_details = execute_query(self.request, account_query)
-                    if platform_details is not None and platform_details != {}:
-                        for platform_detail in platform_details:
-                            for account_detail in account_details:
-                                if platform_detail['platform_id'] == account_detail['platform_id']:
-                                    if 'config' in account_detail and account_detail['config'] is not '':
-                                        account_config = json.loads(account_detail['config'])
-                                        if 'myslice' in platform_detail['platform']:
-                                            acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
-                                            acc_user_cred = account_config.get('delegated_user_credential','N/A')
-                    # assigning values
-                    if acc_auth_cred=={} or acc_auth_cred=='N/A':
-                        pi = "is_not_pi"
-                    else:
-                        pi = "is_pi"
-
-                    # check if the user has creds or not
-                    if acc_user_cred == {} or acc_user_cred == 'N/A':
-                        user_cred = 'no_creds'
-                    else:
-                        user_cred = 'has_creds'
-
-
-                    env['pi'] = pi
-                    env['user_cred'] = user_cred                
-                else: 
-                    env['person'] = None
-                return render_to_response(self.template,env, context_instance=RequestContext(request))
-            else:
-                # log user activity
-                activity.user.login(self.request, "notactive")
-                env['state'] = "Your account is not active, please contact the site admin."
-                env['layout_1_or_2']="layout-unfold2.html"
-                
-                return render_to_response(self.template,env, context_instance=RequestContext(request))
-        # otherwise
+       
+        # LDAP form - If FIBRE, then get the possibilite to authenticate using usernameldap
+        #if self.theme == 'fibre':
+        #usernameldap = request.POST.get('usernameldap')
+        #token = {'usernameldap': usernameldap, 'username': username ,'password': password, 'request': request}    
+
+       ##################################################
+       ########## XXX  Edelberto 010914 XXX
+       #################################################
+       ## first you must open a connection to the server
+       try:
+               # Connect to NOC
+               l = ldap.initialize("ldap://10.128.0.50:389")
+               # Bind/authenticate with a root user to search all objects
+               l.simple_bind_s("cn=Manager,dc=br,dc=fibre","fibre2013")
+               
+               l.protocol_version = ldap.VERSION3
+       except ldap.LDAPError, e:
+               print e
+
+       ## Base directory
+       baseDN = "dc=fibre"
+       searchScope = ldap.SCOPE_SUBTREE
+       ## retrieve all attributes
+       retrieveAttributes = None
+       #retrieveAttributes = ['userEnable']
+       searchFilter = "uid=" + username
+       print searchFilter
+
+        in_ldap = 0
+
+       try:
+            if username != "admin":
+               ldap_result_id = l.search(baseDN, searchScope, searchFilter, retrieveAttributes)
+               result_set = []
+               result_type, result_data = l.result(ldap_result_id, 0)
+               if (result_data == []):
+                       print "User doesnt exist in LDAP"
+                       in_ldap = 0
+               else:
+                       if result_type == ldap.RES_SEARCH_ENTRY:
+                               result_set.append(result_data)
+                       else:
+                               result_set.append(result_data)
+                       # TRUE or FALSE for userEnable attribute
+                       userEnable = result_set[0][0][1]['userEnable'][0]
+                       if userEnable == 'TRUE':
+                               in_ldap = 1
+                               enabled = 1
+                               print "In LDAP and Enabled"
+
+                               dn = result_set[0][0][0]
+                               try:
+                                       l.simple_bind_s(dn,password)
+                                       pwd = 1
+                                       print "User password OK"
+
+                               except:
+                                       pwd = 0
+                                       print "User password WRONG"
+
+                               if in_ldap and enabled and pwd:
+                                       ldap_mail = result_set[0][0][1]['mail'][0]
+
+                                       user_exists =  Query().get('local:user')             \
+                                               .select('status') \
+                                               .filter_by('email', '==', username)
+                                       results = execute_admin_query(request, user_exists)
+                                       print "DEBUG: %s" % user_exists
+                                       if results:
+                                               print "DEBUG: user exists on MySlice DBs"
+                                       else:
+                                               print "DEBUG: user NOT exists on MySlice DBs"
+                                               
+                                               cn              = result_set[0][0][1]['cn'][0] 
+                                               sn              =  result_set[0][0][1]['sn'][0]
+
+                                                fname=None
+                                                lname=None
+
+                                                try:
+                                                    fname =  sn.split(' ')[0]
+                                                    lname =  sn.split(' ')[1]
+                                                except:
+                                                    fname = sn
+                                                    lname = ""
+
+                                               #authority_hrn  =  'fibre' + '.' + username.split('@')[1] 
+                                               authority_hrn   =  'fibre'
+                                               print authority_hrn
+                                               email           = ldap_mail
+                                               print ldap_mail
+                                               username        = username
+                                               print username
+                                               password        = password
+                                               print password
+                                               # user_hrn      = 'fibre' + '.' + username.split('@')[1] + '.' + username
+                                               user_hrn        = 'fibre' + '.' + username
+                                               print user_hrn
+
+                                               # Based on registrationview
+
+
+                                               # get the domain url
+                                               current_site = Site.objects.get_current()
+                                               current_site = current_site.domain
+                                               print current_site
+
+                                               post_email = ldap_mail
+                                               salt = randint(1,100000)
+                                               email_hash = md5(str(salt)+post_email).hexdigest()
+                                               print email_hash
+
+                                               user_request = {
+                                               'first_name'    : fname,
+                                               'last_name'     : lname,
+                                               'organization'  : authority_hrn,
+                                               'authority_hrn' : authority_hrn,
+                                               'email'         : ldap_mail,
+                                               'username'      : username,
+                                               'password'      : password,
+                                               'current_site'  : current_site,
+                                               'email_hash'    : email_hash,
+                                               'pi'            : '',
+                                               'user_hrn'      : user_hrn,
+                                                'reasons'       : 'already exists in the LDAP',
+                                               'type'          : 'user',
+                                               'validation_link': 'https://' + current_site + '/portal/email_activation/'+ email_hash
+                                               }
+
+                                               # Validate input
+                                               errors = []
+                                               UserModel = get_user_model()
+                                               if (re.search(r'^[\w+\s.@+-]+$', user_request['first_name']) == None):
+                                                       errors.append('First name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
+                                               if (re.search(r'^[\w+\s.@+-]+$', user_request['last_name']) == None):
+                                                       errors.append('Last name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
+                                               if (re.search(r'^[\w,]+$' , username) == None):
+                                                       errors.append('Username may contain only letters,numbers and -/_ characters.')
+                                               # checking in django_db !!
+                                               if PendingUser.objects.filter(email__iexact = user_request['email']):
+                                                       errors.append('Email is pending for validation. Please provide a new email address.')
+                                               if User.objects.filter(username__iexact = user_request['username']):
+                                                       errors.append('This username is already in use, try another one')
+                                               # Does the user exist in Manifold?
+                                               user_query  = Query().get('local:user').select('user_id','email')
+                                               user_details = execute_admin_query(request, user_query)
+                                               for user_detail in user_details:
+                                                       if user_detail['email'] == user_request['email']:
+                                                               errors.append('Email already registered in Manifold. Please provide a new email address.')
+                                               # Does the user exist in sfa? [query is very slow!!]
+                                               #user_query  = Query().get('user').select('user_hrn','user_email')
+                                               # XXX Test based on the user_hrn is quick
+                                               #user_query  = Query().get('user').select('user_hrn','user_email').filter_by('user_hrn','==',user_request['user_hrn'])
+                                               user_query  = Query().get('user').select('user_hrn','user_email').filter_by('user_hrn','==',user_hrn)
+                                               user_details_sfa = execute_admin_query(request, user_query)
+
+                                               #if 'generate' in wsgi_request.POST['question']:
+                                               user_request['auth_type'] = 'managed'
+
+                                               # XXX Common code, dependency ?
+                                               from Crypto.PublicKey import RSA
+                                               private = RSA.generate(1024)
+
+                                               # Example: private_key = '-----BEGIN RSA PRIVATE KEY-----\nMIIC...'
+                                               # Example: public_key = 'ssh-rsa AAAAB3...'
+                                               user_request['private_key'] = private.exportKey()
+                                               user_request['public_key']  = private.publickey().exportKey(format='OpenSSH')
+
+                                               # XXX Verify if errors exist - After!
+                                               #if not errors:
+                                               create_user_in_ldap(request, user_request, user_detail)
+                                               #create_pending_user(request, user_request, user_detail)
+
+                                                #create_user(request, user_request)
+                                                            
+                                                env['state'] = "LDAP associated. Please, login again."
+                                                return render_to_response(self.template, env, context_instance=RequestContext(request))
+                                                        
+
+                               else:
+                                       env['state'] = "Access denied. Verify LDAP userEnable and password."
+                                       return render_to_response(self.template, env, context_instance=RequestContext(request))
+
+                       else:
+                               in_ldap = 1
+                               enabled = 0
+                               print "In LDAP but Disabled"
+                               env['state'] = "Access denied. Verify LDAP userEnable."
+                               return render_to_response(self.template, env, context_instance=RequestContext(request))
+
+       #print result_set
+       except ldap.LDAPError, e:
+               print e 
+
+        #else:
+       if in_ldap and enabled and pwd or username=="admin":
+
+################################################################################
+### XXX Edelberto LDAP auth end XXX
+###############################################################################        
+               # Follow original code
+               ## pass request within the token, so manifold session key can be attached to the request session.
+               token = {'username': username, 'password': password, 'request': request}    
+
+               # our authenticate function returns either
+               # . a ManifoldResult - when something has gone wrong, like e.g. backend is unreachable
+               # . a django User in case of success
+               # . or None if the backend could be reached but the authentication failed
+               auth_result = authenticate(token=token)
+               # use one or two columns for the layout - not logged in users will see the login prompt
+               # high-level errors, like connection refused or the like
+               if isinstance (auth_result, ManifoldResult):
+                   manifoldresult = auth_result
+                   # let's use ManifoldResult.__repr__
+                   env['state']="%s"%manifoldresult
+                   
+                   return render_to_response(self.template,env, context_instance=RequestContext(request))
+               # user was authenticated at the backend
+               elif auth_result is not None:
+                   user=auth_result
+                   if user.is_active:
+                       print "LOGGING IN"
+                       login(request, user)
+                       
+                       if request.user.is_authenticated(): 
+                           env['person'] = self.request.user
+                           env['username'] = self.request.user
+                           
+                           ## check user is pi or not
+                           platform_query  = Query().get('local:platform').select('platform_id','platform','gateway_type','disabled')
+                           account_query  = Query().get('local:account').select('user_id','platform_id','auth_type','config')
+
+                           # Edleberto
+                           #cc_auth_cred = {}          
+
+                           platform_details = execute_query(self.request, platform_query)
+                           account_details = execute_query(self.request, account_query)
+                           for platform_detail in platform_details:
+                               for account_detail in account_details:
+                                   if platform_detail['platform_id'] == account_detail['platform_id']:
+                                       if 'config' in account_detail and account_detail['config'] is not '':
+                                           account_config = json.loads(account_detail['config'])
+                                           if 'myslice' in platform_detail['platform']:
+                                               acc_auth_cred = account_config.get('delegated_authority_credentials','N/A')
+                           # assigning values
+                           if acc_auth_cred=={} or acc_auth_cred=='N/A':
+                               pi = "is_not_pi"
+                           else:
+                               pi = "is_pi"
+                           env['pi'] = pi                
+                       else: 
+                           env['person'] = None
+                       return render_to_response(self.template,env, context_instance=RequestContext(request))
+                   else:
+                       env['state'] = "Your account is not active, please contact the site admin."
+                       env['layout_1_or_2']="layout-unfold2.html"
+                       
+                       return render_to_response(self.template,env, context_instance=RequestContext(request))
+               # otherwise
         else:
             # log user activity
-            activity.user.login(self.request, "error")
+            #activity.user.login(self.request, "error")
             env['state'] = "Your username and/or password were incorrect."
             
             return render_to_response(self.template, env, context_instance=RequestContext(request))
diff --git a/portal/lsapiclient.py b/portal/lsapiclient.py
new file mode 100644 (file)
index 0000000..23584ab
--- /dev/null
@@ -0,0 +1,107 @@
+import sys
+import urllib
+import urllib2
+import json
+import socket
+from urlparse import urlparse
+from database import Database
+
+class LaboraSchedulerClient:
+    """
+    A simple rest shell to a Labora Scheduler instance
+    This class can receive Labora API  calls to the underlying testbed
+    """
+                
+    direct_calls = [ 'get_testbed_info', 'get_users', 'add_user', 'delete_user', 'update_user',
+                     'get_user_id_by_username', 'add_user_public_key', 'delete_user_public_key' ]
+
+    def __init__ ( self, organization ):
+       self.url, self.key = self.getOrganizationConfigs( organization )
+
+    def __getattr__(self, name):
+        
+        def func(*args, **kwds):
+            actual_name = None
+            
+            if name in LaboraSchedulerClient.direct_calls:
+                actual_name = name
+            
+            if not actual_name:
+                raise Exception, "Method %s not found in Labora Scheduler"%(name)
+                return
+                
+            if not self.url or not self.key:
+                raise Exception, "Missing Labora Scheduler island url and/or key."
+                return
+                
+            address = self.url + "?method=" + actual_name + "&key=" + self.key
+            
+            # get the direct_call parameters
+            method_parameters = []
+            
+            if actual_name == "get_users":
+                method_parameters.extend(['filter'])
+            elif actual_name == "update_user":
+                method_parameters.extend(['user_id', 'new_user_data'])
+            elif actual_name == "delete_user" or actual_name == "delete_user_public_key":
+                method_parameters.extend(['user_id'])
+            elif actual_name == "get_user_id_by_username":
+                method_parameters.extend(['username'])
+            elif actual_name == "add_user":
+                method_parameters.extend(['username', 'email', 'password', 'name', 'gidnumber',
+                                          'homedirectory', 'created_by'])
+            elif actual_name == "add_user_public_key":
+                method_parameters.extend(['user_id', 'public_key'])
+            
+            for parameter in args:
+                if isinstance(parameter, (frozenset, list, set, tuple, dict)):
+                    for key_name in parameter.keys():
+                        
+                        if key_name in method_parameters:
+                            param_value = parameter[key_name]
+                            
+                            if param_value == None:
+                                continue
+                            
+                            if isinstance(param_value, (frozenset, list, set, tuple, dict)):
+                                param_value = json.dumps(param_value)
+                            
+                            param_value = urllib.quote(param_value.encode('utf-8'))
+                            
+                            address += "&" + key_name + "=" + param_value
+            
+            api_call = urllib2.urlopen(address)
+            api_call = json.load(api_call)
+            
+            if not api_call['call_status']:
+                result = api_call['method_result']
+            else:
+                result = False
+
+
+            return result
+            
+        return func
+        
+        
+    def getOrganizationConfigs( self, organization ):
+        ls_url = None
+        ls_key = None
+        
+        databaseConfig = {
+            'dbHost'        : '10.128.11.200',
+            'dbUser'        : 'postgres',
+            'dbPassword'    : '5e6b70f2e9dc',
+            'dbName'        : 'LaboraSchedulerNOC'
+        }
+        
+        databaseConnection = Database( databaseConfig )
+        
+        query = "SELECT * FROM islands WHERE domain ='" + organization + "'"
+        orgConfig = databaseConnection.fetchRows( query )
+
+        if orgConfig:
+            ls_url = orgConfig[0]["ls_url"]
+            ls_key = orgConfig[0]["ls_key"]
+        
+        return ls_url, ls_key
index 31cbb0d..66f9991 100644 (file)
@@ -18,6 +18,7 @@ from portal.actions                 import get_requests
 from myslice.theme import ThemeView
 
 import json
+import ast
 
 class ManagementRequestsView (LoginRequiredView, ThemeView):
     template_name = "management-tab-requests.html"
@@ -28,15 +29,21 @@ class ManagementRequestsView (LoginRequiredView, ThemeView):
         ctx_delegation_authorities = {}
         ctx_sub_authorities = {}
         dest = {}
-
+       user_username = ''
+       user_authority = ''
 
         # The user need to be logged in
         if (self.request.user):
            
-            user_query = Query().get('local:user').filter_by('email', '==', self.request.user.email).select('user_id')
+            user_query = Query().get('local:user').filter_by('email', '==', self.request.user.username).select('user_id')
             user, = execute_query(self.request, user_query)
             user_id = user['user_id']
-
+           user_query = Query().get('local:user').filter_by('email', '==', self.request.user.username).select('config')
+           user, = execute_query(self.request, user_query)
+           user_config = user['config']
+           user_config = ast.literal_eval(user_config)
+           user_authority = user_config['authority']   
+           user_username = self.request.user.username
             # Query manifold to learn about available SFA platforms for more information
             # In general we will at least have the portal
             # For now we are considering all registries
@@ -120,8 +127,9 @@ class ManagementRequestsView (LoginRequiredView, ThemeView):
             # iterate on the requests and check if the authority matches a prefix 
             # startswith an authority on which the user is PI
             requests = get_requests()
-            for r in requests:
-                auth_hrn = r['authority_hrn']
+           auth_hrn = ''
+           for r in requests:
+               auth_hrn = r['authority_hrn']
                 for my_auth in pi_my_authorities: 
                     if auth_hrn.startswith(my_auth):
                         dest = ctx_my_authorities
@@ -156,10 +164,24 @@ class ManagementRequestsView (LoginRequiredView, ThemeView):
 #         env['pi'] = "is_pi"       
 #         env['theme'] = self.theme
 #         env['section'] = "Requests"
-        
+#        auth_hrn = user_authority + '.' + user_username.split("@")[1]
+           ctx_list = [ctx_my_authorities, ctx_sub_authorities, ctx_delegation_authorities]
+           for ctx in ctx_list:
+               if ctx:
+                   for authorities in ctx:
+                       for requests in ctx[authorities]:
+                           try:
+                               requests['object_auth'] = requests['user_hrn'].split('.')[0] + '.' + requests['user_hrn'].split('@')[1]
+                           except:
+                               print "This object has no user_hrn"
+
+        pi_authority = user_authority + '.' + user_username.split("@")[1]
         context = super(ManagementRequestsView, self).get_context_data(**kwargs)
-        
-            
+        #print "testing"
+        #print ctx_my_authorities
+           #print auth_hrn
+           #print user_username
+           #print pi_authority
         context['my_authorities']   = ctx_my_authorities
         context['sub_authorities']   = ctx_sub_authorities
         context['delegation_authorities'] = ctx_delegation_authorities
@@ -174,6 +196,7 @@ class ManagementRequestsView (LoginRequiredView, ThemeView):
         context['pi'] = "is_pi"       
         context['theme'] = self.theme
         context['section'] = "Requests"
+       context['pi_authority'] = pi_authority
         # XXX We need to prepare the page for queries
         #context.update(page.prelude_env())
 
index cc484b5..acc336b 100644 (file)
@@ -66,7 +66,8 @@ class PendingUser(models.Model):
     login         = models.TextField()
     pi            = models.TextField()
     email_hash    = models.TextField()
-    status        = models.TextField()  
+    status        = models.TextField()
+    reasons       = models.TextField()  
     created       = models.DateTimeField(auto_now_add = True)
     # models.ForeignKey(Institution)
 
index e55e30f..c52689f 100644 (file)
@@ -18,6 +18,8 @@ from manifoldapi.manifoldapi    import execute_admin_query
 from manifold.core.query        import Query
 
 from portal.models              import PendingUser
+from django.contrib.auth.models import User   #Pedro
+
 from portal.actions             import create_pending_user
 
 from myslice.theme import ThemeView
@@ -41,7 +43,7 @@ class RegistrationView (FreeAccessView, ThemeView):
         """
         errors = []
         authority_hrn = None
-        authorities_query = Query.get('authority').select('name', 'authority_hrn')
+        authorities_query = Query.get('authority').select('name','authority_hrn')
         authorities = execute_admin_query(wsgi_request, authorities_query)
         if authorities is not None:
             authorities = sorted(authorities)
@@ -60,9 +62,9 @@ class RegistrationView (FreeAccessView, ThemeView):
             # get the domain url
             current_site = Site.objects.get_current()
             current_site = current_site.domain
-            
+
             print "############ BREAKPOINT 3 #################"
-            
+
             for authority in authorities:
                 if authority['name'] == wsgi_request.POST.get('org_name', ''):
                     authority_hrn = authority['authority_hrn']     
@@ -83,29 +85,50 @@ class RegistrationView (FreeAccessView, ThemeView):
                 'organization'  : wsgi_request.POST.get('org_name', ''),
                 'authority_hrn' : authority_hrn, 
                 'email'         : post_email,
+               'username'      : wsgi_request.POST.get('username','').lower(),
                 'password'      : wsgi_request.POST.get('password',      ''),
+               'reasons'       : wsgi_request.POST.get('reasons', ''),
                 'current_site'  : current_site,
                 'email_hash'    : email_hash,
                 'pi'            : '',
-                'validation_link': 'http://' + current_site + '/portal/email_activation/'+ email_hash
+                'validation_link': 'https://' + current_site + '/portal/email_activation/'+ email_hash
             }
             
             print "############ BREAKPOINT 5 #################"
             
             # Construct user_hrn from email (XXX Should use common code)
-            split_email = user_request['email'].split("@")[0] 
-            split_email = split_email.replace(".", "_")
-            # Replace + by _ => more convenient for testing and validate with a real email
-            split_email = split_email.replace("+", "_")
-            user_request['user_hrn'] = user_request['authority_hrn'] \
-                     + '.' + split_email
+            # split_email = user_request['email'].split("@")[0] 
+            # split_email = split_email.replace(".", "_")
+            # user_request['user_hrn'] = user_request['authority_hrn'] \
+            #         + '.' + split_email
             
+           username = user_request['username']
+
+            if user_request['authority_hrn'] == "fibre" :
+                user_request['username'] = user_request['username'] + "@" + "rnp" # catch-all island
+               split_authority = user_request['authority_hrn']
+            else :
+                split_authority = user_request['authority_hrn'].split(".")[1]
+                user_request['username'] = user_request['username'] + '@' + split_authority
+                split_authority = user_request['authority_hrn'].split(".")[0]
+
+            user_request['user_hrn'] = split_authority + '.' + user_request['username']
+
             # Validate input
             UserModel = get_user_model()
             if (re.search(r'^[\w+\s.@+-]+$', user_request['first_name']) == None):
                 errors.append('First name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
             if (re.search(r'^[\w+\s.@+-]+$', user_request['last_name']) == None):
                 errors.append('Last name may contain only letters, numbers, spaces and @/./+/-/_ characters.')
+           if (re.search(r'^[\w,]+$' , username) == None):
+               errors.append('Username may contain only letters,numbers and -/_ characters.')
+            # checking in django_db !!
+            if PendingUser.objects.filter(email__iexact = user_request['email']):
+                errors.append('Email is pending for validation. Please provide a new email address.')
+            # if UserModel._default_manager.filter(email__iexact = user_request['email']): 
+            #     errors.append('This email is not usable. Please contact the administrator or try with another email.')
+           if User.objects.filter(username__iexact = user_request['username']): 
+               errors.append('This username is already in use, try another one')
             # Does the user exist in Manifold?
             user_query  = Query().get('local:user').select('user_id','email')
             user_details = execute_admin_query(wsgi_request, user_query)
@@ -119,14 +142,14 @@ class RegistrationView (FreeAccessView, ThemeView):
             user_query  = Query().get('user').select('user_hrn','user_email').filter_by('user_hrn','==',user_request['user_hrn'])
             user_details_sfa = execute_admin_query(wsgi_request, user_query)
 
-            for user in user_details_sfa:
-                if user['user_email'] == user_request['email']:
-                    errors.append('Email already registered in OneLab registry. <a href="/contact">Contact OneLab support</a> or use another email.')
-                if user['user_hrn'] == user_request['user_hrn']:
-                    # add random number if user_hrn already exists in the registry
-                    user_request['user_hrn'] = user_request['authority_hrn'] \
-                            + '.' + split_email + str(randint(1,1000000))
-
+            for user in user_details_sfa:
+                if user['user_email'] == user_request['email']:
+            #         errors.append('Email already registered in SFA registry. Please use another email.')
+                if user['user_hrn'] == user_request['user_hrn']:
+                    # add random number if user_hrn already exists in the registry
+                    user_request['user_hrn'] = user_request['authority_hrn'] \
+                            + '.' + split_email + str(randint(1,1000000))
+                
             # checking in django unfold db portal application pending users
             # sqlite3 /var/unfold/unfold.sqlite3
             # select email from portal_pendinguser;
@@ -137,7 +160,7 @@ class RegistrationView (FreeAccessView, ThemeView):
             # sqlite3 /var/unfold/unfold.sqlite3
             # select email from auth_user;
             if UserModel._default_manager.filter(email__iexact = user_request['email']): 
-                errors.append('<a href="/contact">Contact OneLab support</a> or try with another email.')
+                errors.append('Please try with another email.')
 
             # XXX TODO: Factorize with portal/accountview.py
             # XXX TODO: Factorize with portal/registrationview.py
@@ -174,8 +197,9 @@ class RegistrationView (FreeAccessView, ThemeView):
                 create_pending_user(wsgi_request, user_request, user_detail)
                 self.template_name = 'user_register_complete.html'
                 # log user activity
-                activity.user.registered(self.request)
-                return render(wsgi_request, self.template, {'theme': self.theme}) 
+                #activity.user.registered(self.request)
+
+                return render(wsgi_request, self.template, {'theme': self.theme, 'REQINST':wsgi_request.POST.get('org_name', '').split(".")[1].upper()}) 
 
         else:
             print "############ BREAKPOINT A #################"
@@ -194,7 +218,8 @@ class RegistrationView (FreeAccessView, ThemeView):
           'topmenu_items': topmenu_items_live('Register', page),
           'errors': errors,
           'authorities': authorities,
-          'theme': self.theme
+          'theme': self.theme,
+         'section':'Registration'
           }
         template_env.update(user_request)
         template_env.update(reg_form)
index e6683bd..97a11dd 100644 (file)
@@ -181,7 +181,7 @@ class SliceRequestView (LoginRequiredAutoLogoutView, ThemeView):
             'url': url,
             'pi': pi,
             'authority_name': authority_name,        
-            'authority_hrn': user_authority,        
+            'authority_hrn': user_authority,
             'cc_myself': True,
             'authorities': authorities,
             'theme': self.theme,
diff --git a/portal/static/css/fibre.css b/portal/static/css/fibre.css
new file mode 100644 (file)
index 0000000..05526c8
--- /dev/null
@@ -0,0 +1,698 @@
+@import url("../fonts/opensans_bold_macroman/stylesheet.css");
+
+html { height: 100% }
+
+body {
+    background-color:white;
+    color:black;
+    margin:0;
+    padding:0;
+    height: 100%;
+}
+a, a:active, a:focus {
+    outline: 0;
+    text-decoration:none;
+}
+
+h1 {
+    border-bottom:1px solid #DDDDDD;
+    padding:0 0 0 0;
+    margin:15px 0 15px 0;
+    font-size:14pt;
+}
+h1 img {
+    vertical-align:middle;
+    margin-bottom:4px;
+    margin-right:10px;
+}
+h2 {
+    font-size:14pt;
+    color:#333333;
+}
+h3 {
+    font-size:13pt;
+    color:#201E62;
+}
+input[type=text], input[type=password], input[type=email], input[type=tel], input[type=number], select, option {
+    min-width:260px;
+    padding:6px;
+    border:1pt solid #22606D;
+    vertical-align:bottom;
+    border-radius:0;
+}
+
+textarea {
+    padding:6px;
+    border:1pt solid #22606D !important;
+    border-radius:0 !important;
+}
+
+span.label {
+    font-size:11pt;
+    color:gray;
+    font-weight:normal;
+    padding:0;
+}
+div.el {
+    padding-bottom:15px;
+}
+div.breadcrumbs {
+    margin:15px 0;
+    color:gray;
+    font-size:10pt;
+}
+/* buttons */
+button.btn, input.btn {
+    padding:6px 10px;
+    border-radius:5px;
+    font-size:10pt;
+    font-weight:normal;
+}
+button.btn span.glyphicon {
+    margin-right:6px;
+}
+button.btn-default {
+    border-bottom:3px solid #cccccc;
+}
+button.btn-default:hover {
+    background-color:white;
+    border:1px solid #ADADAD;
+    border-bottom:3px solid #ADADAD;
+}
+button.btn-default:active {
+    background-color:white;
+    border:1px solid #ADADAD;
+    border-bottom:1px solid #ADADAD;
+    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;
+}
+button.btn-onelab:hover, input.btn-onelab:hover {
+    border:0;
+    border-bottom:3px solid #760073;
+    background-color:#302562;
+    color:white;
+}
+button.btn-onelab:active, input.btn-onelab:active {
+    box-shadow:none;
+    border-bottom:1px solid #760073;
+    margin-top:2px;
+}
+
+.container-resource button {
+    padding:2px 4px;
+    border-radius:3px;
+    font-size:9pt;
+    font-weight:normal;
+}
+.container-resource select,.container-resource option, .container-resource input {
+    padding:2px 4px;
+    font-size:9pt;
+}
+.badge {
+    font-size:9pt;
+    margin-left:4px;
+}
+/***** Notifications *****/
+.warning {
+    border: 1px solid red;
+    margin: 20px 60px;
+    padding: 10px 20px;
+    color: red;
+    background-color: #f2dbdb;
+    text-align: center;
+}
+
+/* HOME DASHBOARD */
+div#home-dashboard {
+    color:black;
+    margin:0 auto 25px auto;
+}
+div#home-dashboard table {
+    margin:25px;
+    width:100%;
+}
+div#home-dashboard table td {
+    text-align:center;
+    padding:15px 0;
+    width:33%;
+}
+div#home-dashboard table tr:first-child td {
+    font-size:12pt;
+    font-weight:bold;
+    color:#270A5A;
+}
+div#home-dashboard table tr:last-child td {
+    vertical-align:top;
+    padding:25px 0;
+}
+div#home-dashboard table tr:last-child td.logged-in {
+    border-right:1px solid #DDDDDD;
+    padding:25px;
+}
+div#home-dashboard table tr:last-child td.support {
+    border-left:1px solid #DDDDDD;
+    padding:25px;
+}
+div#home-dashboard table tr:last-child td:first-child {
+}
+div#home-dashboard table tr:last-child td:last-child {
+    border-right:0;
+}
+div#home-dashboard table tr:last-child td.logged-in div {
+    text-align:left;
+    padding:25px 0;
+}
+div#home-dashboard table tr:last-child td.support div {
+    text-align:left;
+    padding:25px 0;
+}
+div#home-dashboard div.login-widget {
+    padding:20px;
+}
+div#home-dashboard table td.support {
+}
+div#home-dashboard table td.support a {
+}
+div#home-dashboard table td.support a:hover {
+    text-decoration:none;
+}
+
+div#home-dashboard div#manager {
+    display:none;
+}
+
+div#home-dashboard div#home-slice-list {
+    margin:25px 0;
+    padding:0 25px;
+    text-align:left;
+}
+div#home-dashboard div#home-slice-list ul {
+    list-style: none;
+    padding:0;
+    margin:0;
+}
+div#home-dashboard div#home-slice-list li {
+    
+}
+
+/**/
+
+/**/
+/* WELL */
+div.well {
+}
+/**/
+/* TABLE */
+table.table {
+    margin:0;
+}
+table.table thead {
+    padding:0;
+}
+table.table tbody {
+    padding:0;
+}
+table.table tr {
+    padding:0;
+}
+table.table td {
+    padding:0;
+}
+/* INSTITUTION */
+div#institution {
+    color:black;
+}
+.form-hint {
+    font-size:11pt;
+    font-style:italic;
+    color:gray;
+}
+
+
+.form-hint {
+    font-size:11pt;
+    font-style:italic;
+    color:gray;
+}
+
+
+
+/* TICKET REQUEST */
+div#ticket-request {
+    color:black;
+}
+.form-hint {
+    font-size:11pt;
+    font-style:italic;
+    color:gray;
+}
+div#ticket-request p {
+    margin:20px 0;
+}
+
+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 {
+}
+ul.nav-section li:first-child.active a {
+}
+
+ul.nav-resources {
+    margin:15px 0;
+}
+ul.nav-resources a {
+    padding: 4px 10px 5px 10px;
+}
+
+/* SLICE VIEW */
+div.container-resource, div.container-slice {
+    padding-right:15px;
+    padding-left:15px;
+}
+.table th {
+    border-top:0 !important;
+}
+div#slice-view {
+    margin:0;
+}
+div.list-group-item {
+    border:0;
+    -moz-border-radius: 0;
+    border-radius: 0;
+    background-color:white;
+    font-weight:bold;
+    padding-left:0;
+}
+a.list-group-item {
+    -moz-border-radius: 0;
+    border-radius: 0;
+    border:0;
+    background-color:white;
+    padding:3px 2px 3px 10px;
+    border-left:2pt white solid;
+}
+a.list-group-item.active, a.list-group-item.active:hover, a.list-group-item.active:focus {
+    -moz-border-radius: 0;
+    border-radius: 0;
+    font-weight: bold;
+    color:black;
+    background-color:#F5F5F5;
+    border-left:2pt blue solid;
+}
+
+a.list-group-item:hover {
+    -moz-border-radius: 0;
+    border-radius: 0;
+    border-left:2pt blue solid;
+}
+a.list-group-item p.list-group-item-text {
+    -moz-border-radius: 0;
+    border-radius: 0;
+    font-size:9pt;
+    font-style:italic;
+    font-weight: normal;
+    color: black !important;
+}
+
+span.sl-resources {
+    font-size:9pt;
+    color:gray;
+}
+a.sl-resources, a.sl-resources:hover {
+    font-size:9pt;
+    border:0;
+    padding:2px 4px;
+    -moz-border-radius: 4px;
+    border-radius: 4px;
+    width:125px;
+    text-align: center;
+}
+a.sl-resources.active, a.sl-resources.active:hover, a.sl-resources.active:focus {
+    border:0;
+    -moz-border-radius: 4px;
+    border-radius: 4px;
+}
+
+div#slice-info {
+    margin-top:25px;
+}
+div#slice-info table {
+    width:100%;
+    margin:0 auto;
+}
+div#slice-info table td:first-child {
+    text-align:right;
+    font-weight:bold;
+    padding-right:15px;
+}
+div#slice-info td {
+    padding:5px;
+}
+
+/* SLICE VIEW sections */
+.slice-sections, .slice-pending {
+    margin:0;
+    padding:0;
+}
+.slice-sections ul, .slice-pending ul {
+    margin:0;
+    padding:0;
+}
+.slice-pending ul {
+    width:400px;
+    margin:0 auto 15px auto;
+}
+.slice-sections li {
+    text-align:left;
+    margin:0;
+    padding:0;
+}
+.slice-pending li {
+    padding-right:15px;
+}
+.slice-sections li a, .slice-pending li a {
+    font-size:14px;
+    color:black;
+    padding:0;
+}
+.slice-sections li.active a, .slice-pending li.active a  {
+    color:#201E62;
+    background-color:#EFEFEF;
+    text-decoration:underline;
+    padding:0;
+}
+.slice-sections ul.nav-pills li a:hover, .slice-pending ul.nav-pills li a:hover {
+    text-decoration:underline;
+    background-color:#EFEFEF;
+    color:black;
+}
+.slice-sections ul.nav-pills li.active, .slice-pending ul.nav-pills li.active {
+
+}
+.slice-sections li:first-child, .slice-sections li:first-child a {
+    color:#201E62;
+    font-weight:bold;
+}
+.slice-experiment {
+    text-align:right;
+    padding:0;
+}
+.slice-experiment button {
+    margin:3px 0 0 0;
+    background-color:#CC4125;
+    color:white;
+}
+
+.slice-pending {
+}
+.slice-pending button {
+    font-size:9pt;
+    margin:-2px 0 0 0;
+    padding:3px 5px;
+}
+.slice-pending button.apply {
+}
+.slice-pending button.clear {
+}
+tr.active, tr.active td {
+    background-color:#FFFFCC !important;
+}
+div.dataTables_filter label{
+    float:left;
+    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);
+  box-shadow:         0 0 1px rgba(82,82,82,0.6);
+  height:61px;
+  background-color:white;
+  margin-bottom: 35px;
+}
+
+div.navigation {
+    
+}
+div.navigation ul {
+    margin:26px 0 0 0;
+    padding:0;
+    display: inline-block;
+    list-style-type: none;
+    white-space: nowrap;
+}
+
+div.navigation li {
+    color:#0C0047;
+    font-family:open_sansbold, sans-serif;
+    font-size:9pt;
+    font-weight:normal;
+    line-height:0.8em;
+    letter-spacing:0.4pt;
+    list-style:none;
+    float:left;
+    padding:0 15px;
+    margin:0;
+    text-transform:uppercase;
+}
+div.navigation li:hover {
+}
+div.navigation li a {
+    color:#0C0047;
+}
+div.navigation li a:hover, div.navigation li a.current {
+    color:#760073;
+    text-decoration:none;
+}
+
+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;
+}
+
+div.secondary ul {
+   margin:6px 0 0 0;
+   padding:0;
+}
+
+div.secondary li {
+    font-size:9pt;
+    display:inline;
+    list-style:none;
+    margin:0px;
+    padding:0;
+    margin-right:15px;
+    color:#747474;
+    letter-spacing:0.4px;
+}
+div.secondary li:last-child {
+    margin-right:0;
+}
+div.secondary li a {
+    color:#747474;
+}
+div.secondary li a:hover {
+    text-decoration:none;
+}
+div.secondary .button {    
+    width:300px;
+    margin-top:15px;
+}
+div.secondary .account {
+    margin-top:10px;
+    padding:0;
+    font-size:9pt;
+    color:gray;
+    text-align:right;
+}
+div.secondary .account span {
+    font-size:8pt;
+}
+div.secondary .account a {
+    color:black;
+}
+div.home {
+    font-size:11pt;
+    line-height:1.2em;
+    letter-spacing:0.3pt;
+    min-height:500px;
+    background-image: url('../img/optical_fibre.jpg');
+    background-repeat:no-repeat;
+    background-size:cover;
+    background-position:center top;
+    background-color:#013ADF;
+    padding:100px 0;
+}
+div.home h2 {
+    color:white;
+    line-height:1.2em;
+    font-size:18pt;
+}
+div.home h3 {
+    color:white;
+    line-height:1.4em;
+}
+div.dashboard {
+    text-align:center;
+}
+div.dashboard div {
+    margin:25px 0;
+}
+div.dashboard ul {
+    text-align:left;
+    margin-left:24px;
+    list-style:none;
+}
+div.registration-form {
+    padding-top:150px;
+    text-align:center;
+}
+
+.login-form input {
+    width:320px;
+}
+.login-form input[type=submit] {
+    width:108px;
+}
+
+.login-submit {
+    vertical-align:middle;
+    padding:0;
+}
+.lost-password {
+    font-size:10pt;
+    color:black;
+    text-align:right;
+    padding:0px;
+}
+.lost-password a {
+    color:white;
+    text-shadow:0.5px 0.5px black;
+}
+.login-signup {
+    font-size:12pt;
+    color:white;
+    text-shadow:0.5px 0.5px black;
+    margin-top:45px;
+    padding:5px 0 0 4px;
+    
+}
+.login-signup a {
+    color:white;
+    text-shadow:0.5px 0.5px black;
+    padding-bottom:2px;
+    border-bottom:2pt solid white;
+}
+.login-signup a:hover {
+    text-decoration:none;
+}
+.login-signup button {
+    padding:8px;
+    border:0;
+    border-bottom:2px solid #540086;
+    background-color:#302562;
+    color:white;
+    width:100px;
+    border-radius:5px;
+    font-size:12pt;
+}
+div.slogan {
+    text-align:center;
+    color:white;
+    padding-top:60px;
+    text-shadow: 1px 1px #013540;
+}
diff --git a/portal/static/css/onelab_edelberto.css b/portal/static/css/onelab_edelberto.css
new file mode 100644 (file)
index 0000000..797d79c
--- /dev/null
@@ -0,0 +1,457 @@
+/* @override unfold/static/css/plugin.css */
+
+/*-------------------------------- MARKO'S STYLES -----*/
+
+/* GENERAL */
+
+a, a:visited {
+    color: rgb(13, 187, 255) !important;
+    text-decoration: none !important;
+}
+
+a:hover {
+    color: blue !important;
+    text-decoration: none !important;
+}
+
+.container {
+    /*padding: 0 !important;*/
+    padding-top: 60px !important;
+    color: #fff;
+/*    background: url(http://new.fit-equipex.fr/images/background.jpg) no-repeat; */
+    background-color: rgb(237, 241, 243);
+    margin: 0;
+    width: 100%;
+    max-width: 100%;
+    min-height: 100%;
+    height: 100%;
+}
+
+.container h1, .container h2 {
+    color: #fff !important;
+}
+
+.navbar-brand {
+    padding: 5px !important;
+}
+
+.nav {
+    padding-top: 30px !important;
+    padding-left: 20px !important;
+}
+
+.navbar-default {
+    background-color: #fff !important;
+}
+
+p.login-status {
+    color: blue !important;
+}
+
+div.plugin-outline-complete, 
+div.plugin-outline-body {
+    border: 0px solid;
+    border-radius: 0;
+    border-color: #ccc;
+    -webkit-transition: padding 200ms ease-out;
+    -moz-transition: padding 200ms ease-out;
+    -o-transition: padding 200ms ease-out;
+    transition: padding 0.2s ease-out;
+    padding: 20px;
+    margin: 0;
+}
+/*
+div.plugin-outline-complete:hover, 
+div.plugin-outline-body:hover {
+    padding: 80px 80px 120px 80px; 
+}
+*/
+a.plugin-tooltip { 
+    font-size: 130%;
+    font-style: normal;
+    font-weight: bold;
+    padding: 5px;
+    color: #333;
+    font-family: Ubuntu, Arial, sans-serif;
+    text-transform: uppercase;
+}
+
+a.plugin-tooltip:hover { 
+    color: #fff; 
+    text-decoration: none;
+}
+
+
+
+/* LIST VIEW */
+div.well-lg {
+    background-color: rgba(168, 32, 202, 0.5) !important;
+}
+div.onelab-title {
+    background-color: #3A5FCD !important;
+    /*background-color: rgba(168, 32, 202, 0.5) !important;*/
+}
+div.well {
+    /*background-color: rgba(0, 0, 0, 0.5) !important;*/
+    background-color: #fff !important;
+    color: rgb(37, 37, 37) !important;
+}
+h2.well.well-lg {
+    border-radius:0;
+    border: 0;
+    font-family: Ubuntu, arial, sans-serif;
+    /* text-transform: ; */
+    font-weight: normal;
+    font-size: 40px;
+    /* color: #30196d; */
+    color: white;
+    margin-bottom: 0px;
+    margin-top: 0;
+    padding: 40px;
+    opacity: 1;
+    text-align: center;
+    background-color: #30196d;
+}
+
+#complete-resources {
+/*    background-color: #92f79e !important; */
+    background-color: #B8B2FF !important;
+}
+
+#complete-filters {
+/*    background-color: #4af25d; */
+    background-color: #add7ff;
+}
+
+#complete-users {
+/*    background-color: #ff7394 !important; */
+    background-color: #add7ff !important;
+}
+/*
+#complete-measurements {
+    background-color: !important;
+}
+*/
+#complete-pending {
+/*    background-color: #add7ff !important; */
+    background-color: #B8B2FF !important;
+
+}
+
+#complete-customize-resources {
+    background-color: #efdfdf;
+}
+
+#complete-msgs-pre {
+    background-color: #ccc;
+}
+
+#complete-resources, 
+#complete-filters, 
+#complete-users, 
+#complete-measurements,
+#complete-pending,
+#complete-customize-resources,
+#complete-msgs-pre {
+    opacity: 1;
+    text-align: center;
+    color: #333;
+}
+
+#complete-resources:hover, 
+#complete-filters:hover, 
+#complete-users:hover, 
+#complete-measurements:hover,
+#complete-pending:hover,
+#complete-customize-resources:hover,
+#complete-msgs-pre:hover {
+    opacity: 1;
+}
+
+.nav.nav-tabs {
+    font-family: Ubuntu, Arial, sans-serif;
+    border: 0 !important;
+    border-bottom: 3px solid #fff !important;
+    margin-bottom: 40px;
+}
+
+.nav.nav-tabs li.active a {
+    color: #572bc9;
+    border-left: 0px solid #572bc9;
+    border-top: 0px solid #572bc9;
+    border-right: 0px solid #572bc9;
+}
+
+.nav.nav-tabs li a {
+    color: #333;
+    border: 0 !important;
+    margin-right: 5px;
+}
+
+.nav.nav-tabs li a:hover {
+    color: #333;
+    background: #572bc9;
+    color: #fff;
+    border: 0 !important;
+}
+
+
+
+/* if window enlarged wider than background picture */
+body {
+    background: rgb(237, 241, 243) !important;
+    /*background: black !important;*/
+}
+
+/* TOPMENU.CSS */
+
+/* Thierry : turning this off
+body {
+    *//* background: #30196d !important; *//*
+    background: black !important;
+    padding-top: 60px;
+    padding-bottom: 0px;
+}
+Thierry */
+
+/* Thierry : turning this off
+div.topmenu { 
+    padding-top: 0px;
+    font-family: Ubuntu, Arial, sans-serif;
+    font-weight: bold;
+    background: #fff;
+    -webkit-box-shadow: 0px 10px 10px rgba(50, 50, 50, 0.44);
+    -moz-box-shadow:    0px 10px 10px rgba(50, 50, 50, 0.44);
+    box-shadow:         0px 10px 10px rgba(50, 50, 50, 0.44);
+}
+Thierry */
+
+/* Thierry : turning this off
+.navbar-nav li a,
+.navbar-nav li.other a {
+    padding-top: 25px;
+    padding-bottom: 20px;
+}
+Thierry */
+
+.navbar-nav li a:hover {
+    color: #572bc9 !important;
+}
+
+.navbar-nav li.active a {
+    background: #eee !important;
+}
+
+/* Thierry : turning this off
+ul.logged-in { 
+    padding-top: 25px; 
+}
+Thierry */
+button.logged-in { 
+    font-size: 1em;
+    font-weight: bold; 
+    margin-left: 5px;
+    margin-top: -5px;
+    background: #572bc9;
+    border: 2px solid #572bc9;
+    color: #eee;
+    padding: 5px 15px;
+    border-radius:5px;
+}
+
+button.logged-in:hover { 
+    /* background: #4af25d; */
+    background: #ff7394;
+    border: 2px solid #ff7394;
+    color: #333;
+}
+li.username {
+    margin-bottom: 10px;
+    font-size: 0.8em;
+    text-transform: none;
+    font-weight: normal; 
+    color: #999;
+}
+
+
+/* BOOTSTRAP */
+
+
+ul.pagination li a {
+    /* background: ; */
+    color: #572bc9;
+    font-family: Ubuntu, Arial, sans-serif;
+}
+
+ul.pagination li.active a {
+    background: #572bc9;
+    border: 1px solid #572bc9;
+}
+
+.btn.btn-default {
+    background: #572bc9;
+    color: #ccc;
+    font-family: Ubuntu, Arial, sans-serif;
+    font-weight: bold;
+    border: 0px;
+}
+
+.btn.btn-default:hover {
+    /* background: #4af25d; */
+    background: #ff7394;
+    color: #333;
+    font-family: Ubuntu, Arial, sans-serif;
+    font-weight: bold;
+    border: 0px;
+}
+
+input {
+    border-radius: 3px;
+    border: none;
+    border: 1px solid #ccc;
+}
+
+
+div.dataTables_length label, 
+div.dataTables_filter label,
+div.dataTables_info {
+    font-family: Ubuntu, Arial, sans-serif !important;
+}
+
+
+
+
+/* QUERYTABLE */
+
+div.QueryTable table.dataTable th {
+    font: bold 12px/22px Ubuntu, Arial, sans-serif;
+    color: #333 !important;
+    border-right: 0px solid #333 !important;
+    border-bottom: 0px solid #C1DAD7 !important;
+    border-top: 0px solid #C1DAD7 !important;
+    letter-spacing: 1px;
+    text-transform: uppercase;
+    text-align: left;
+    padding: 8px 12px 4px 20px;
+    vertical-align:middle;
+    background: url('../img/tablesort-header.png') no-repeat !important; 
+}
+
+div.QueryTable table.dataTable td, div.QueryTable table.dataTable textarea, div.QueryTable table.dataTable input [type="text"] {
+    font: normal 12px Ubuntu, Arial, Helvetica, sans-serif;
+    border-right: 0px solid #fff !important;
+    border-bottom: 1px solid #fff !important;
+}
+
+div.QueryTable table.dataTable thead { 
+    background: url('../img/tablesort-header.png') repeat-x !important;
+    background-color: #caebea;
+}
+
+div.QueryTable table.dataTable tfoot { 
+    background: url('../img/tablesort-header.png') repeat-x !important;
+    /* background-color: # !important; */
+}
+
+
+/* QUERY EDITOR */
+
+table.query-editor {
+    margin: 40px auto !important;
+    clear: both;
+    /* width: 80%;*/
+    width: 100% !important;
+    font-family: Ubuntu;
+}
+
+.query-editor-spacer,
+.plugin.QueryUpdater,
+/* Thierry : turning this off
+.plugin.Tabs 
+Thierry */
+{
+    margin-top: 60px !important;
+}
+
+table.query-editor td {
+    padding: 5px 5px !important;
+    font: normal 12px Ubuntu, Arial, sans-serif !important;
+}
+
+
+
+/* DASHBOARD */
+
+#ms-dashboard-profile,
+#ms-dashboard-testbeds,
+#ms-dashboard-slices {
+    -webkit-transition: all 50ms ease-out;
+    -moz-transition: all 50ms ease-out;
+    -o-transition: all 50ms ease-out;
+    transition: all 0.05s ease-out;
+    padding-top: 140px;
+    padding-bottom: 60px;
+    margin-top: 60px;
+    color: #fff;
+    font-family: Ubuntu, Arial, sans-serif;
+    text-align: center;
+       
+}
+
+#ms-dashboard-profile:hover,
+#ms-dashboard-testbeds:hover,
+#ms-dashboard-slices:hover {
+    margin-top: 65px;
+}
+
+#ms-dashboard-profile {
+    background: url("../img/icon_users_color.png") top center no-repeat;
+}
+
+#ms-dashboard-testbeds {
+    background: url("../img/icon_testbed_color.png") top center no-repeat;
+}
+
+#ms-dashboard-slices {
+    background: url("../img/icon_slices_color.png") top center no-repeat;
+}
+
+.ms-dashboard-content ul {
+    list-style-type: none !important;
+    padding-left: 0;
+    text-align: center !important;
+}
+
+.ms-dashboard-content {
+    padding: 0 !important;
+}
+
+.ms-dashboard-content a {
+    color: #ff7394 !important;
+/* color: #ff0099 !important; */
+}
+
+.ms-dashboard-content a:hover {
+    color: white !important;
+}
+.ms-dashboard-caption h2 {
+    font-family: Ubuntu, Arial, sans-serif;
+    border-bottom: 0 !important;
+    text-transform: uppercase;
+}
+
+#ms-dashboard-profile>div.ms-dashboard-caption {
+    background: no-repeat url(#) !important;
+    padding-left: 0 !important;
+}   
+
+#ms-dashboard-testbeds>div.ms-dashboard-caption {
+    background: no-repeat url(#) !important;
+    padding-left: 0 !important;
+}   
+
+#ms-dashboard-slices>div.ms-dashboard-caption {
+    background: no-repeat url(#) !important;
+    padding-left: 0 !important;
+}   
+
diff --git a/portal/static/img/fibre-logo.gif b/portal/static/img/fibre-logo.gif
new file mode 100644 (file)
index 0000000..e215771
Binary files /dev/null and b/portal/static/img/fibre-logo.gif differ
diff --git a/portal/static/img/fibre/br.png b/portal/static/img/fibre/br.png
new file mode 100644 (file)
index 0000000..4225053
Binary files /dev/null and b/portal/static/img/fibre/br.png differ
diff --git a/portal/static/img/fibre/cafe.jpg b/portal/static/img/fibre/cafe.jpg
new file mode 100644 (file)
index 0000000..c73e6f1
Binary files /dev/null and b/portal/static/img/fibre/cafe.jpg differ
diff --git a/portal/static/img/fibre/eu.png b/portal/static/img/fibre/eu.png
new file mode 100644 (file)
index 0000000..03f1d0f
Binary files /dev/null and b/portal/static/img/fibre/eu.png differ
diff --git a/portal/static/img/fibre/icon_authority_color.png b/portal/static/img/fibre/icon_authority_color.png
new file mode 100644 (file)
index 0000000..342a1dd
Binary files /dev/null and b/portal/static/img/fibre/icon_authority_color.png differ
diff --git a/portal/static/img/fibre/icon_slices.png b/portal/static/img/fibre/icon_slices.png
new file mode 100644 (file)
index 0000000..9527461
Binary files /dev/null and b/portal/static/img/fibre/icon_slices.png differ
diff --git a/portal/static/img/fibre/icon_support.png b/portal/static/img/fibre/icon_support.png
new file mode 100644 (file)
index 0000000..54bce1b
Binary files /dev/null and b/portal/static/img/fibre/icon_support.png differ
diff --git a/portal/static/img/fibre/icon_testbed_color.png b/portal/static/img/fibre/icon_testbed_color.png
new file mode 100644 (file)
index 0000000..f3c55e4
Binary files /dev/null and b/portal/static/img/fibre/icon_testbed_color.png differ
diff --git a/portal/static/img/fibre/icon_user_color.png b/portal/static/img/fibre/icon_user_color.png
new file mode 100644 (file)
index 0000000..e88d559
Binary files /dev/null and b/portal/static/img/fibre/icon_user_color.png differ
diff --git a/portal/static/img/fibre/icones.zip b/portal/static/img/fibre/icones.zip
new file mode 100644 (file)
index 0000000..bab607b
Binary files /dev/null and b/portal/static/img/fibre/icones.zip differ
diff --git a/portal/static/img/icon_authority_color.png~HEAD b/portal/static/img/icon_authority_color.png~HEAD
new file mode 100644 (file)
index 0000000..342a1dd
Binary files /dev/null and b/portal/static/img/icon_authority_color.png~HEAD differ
diff --git a/portal/static/img/icon_slices.png~HEAD b/portal/static/img/icon_slices.png~HEAD
new file mode 100644 (file)
index 0000000..9527461
Binary files /dev/null and b/portal/static/img/icon_slices.png~HEAD differ
diff --git a/portal/static/img/icon_support.png~HEAD b/portal/static/img/icon_support.png~HEAD
new file mode 100644 (file)
index 0000000..54bce1b
Binary files /dev/null and b/portal/static/img/icon_support.png~HEAD differ
diff --git a/portal/static/img/icon_testbed_color.png~HEAD b/portal/static/img/icon_testbed_color.png~HEAD
new file mode 100644 (file)
index 0000000..f3c55e4
Binary files /dev/null and b/portal/static/img/icon_testbed_color.png~HEAD differ
diff --git a/portal/static/img/icon_user_color.png~HEAD b/portal/static/img/icon_user_color.png~HEAD
new file mode 100644 (file)
index 0000000..e88d559
Binary files /dev/null and b/portal/static/img/icon_user_color.png~HEAD differ
diff --git a/portal/static/img/optical_fibre.jpg b/portal/static/img/optical_fibre.jpg
new file mode 100644 (file)
index 0000000..a62eb25
Binary files /dev/null and b/portal/static/img/optical_fibre.jpg differ
diff --git a/portal/static/img/original-backup/authority-icon.png b/portal/static/img/original-backup/authority-icon.png
new file mode 100644 (file)
index 0000000..bde603a
Binary files /dev/null and b/portal/static/img/original-backup/authority-icon.png differ
diff --git a/portal/static/img/original-backup/experiments.png b/portal/static/img/original-backup/experiments.png
new file mode 100644 (file)
index 0000000..cd97086
Binary files /dev/null and b/portal/static/img/original-backup/experiments.png differ
diff --git a/portal/static/img/original-backup/f4f-logo.png b/portal/static/img/original-backup/f4f-logo.png
new file mode 100644 (file)
index 0000000..8a72315
Binary files /dev/null and b/portal/static/img/original-backup/f4f-logo.png differ
diff --git a/portal/static/img/original-backup/marker1.png b/portal/static/img/original-backup/marker1.png
new file mode 100644 (file)
index 0000000..5f29aea
Binary files /dev/null and b/portal/static/img/original-backup/marker1.png differ
diff --git a/portal/static/img/original-backup/marker2.png b/portal/static/img/original-backup/marker2.png
new file mode 100644 (file)
index 0000000..9dce718
Binary files /dev/null and b/portal/static/img/original-backup/marker2.png differ
diff --git a/portal/static/img/original-backup/ques_icon.png b/portal/static/img/original-backup/ques_icon.png
new file mode 100644 (file)
index 0000000..4113c12
Binary files /dev/null and b/portal/static/img/original-backup/ques_icon.png differ
diff --git a/portal/static/img/original-backup/resource-icon.png b/portal/static/img/original-backup/resource-icon.png
new file mode 100644 (file)
index 0000000..919bdbe
Binary files /dev/null and b/portal/static/img/original-backup/resource-icon.png differ
diff --git a/portal/static/img/original-backup/slice-icon.png b/portal/static/img/original-backup/slice-icon.png
new file mode 100644 (file)
index 0000000..9e8747b
Binary files /dev/null and b/portal/static/img/original-backup/slice-icon.png differ
diff --git a/portal/static/img/original-backup/testbeds.png b/portal/static/img/original-backup/testbeds.png
new file mode 100644 (file)
index 0000000..ed9aa0e
Binary files /dev/null and b/portal/static/img/original-backup/testbeds.png differ
diff --git a/portal/static/img/original-backup/user-icon.png b/portal/static/img/original-backup/user-icon.png
new file mode 100644 (file)
index 0000000..88f6bf8
Binary files /dev/null and b/portal/static/img/original-backup/user-icon.png differ
diff --git a/portal/static/img/original-backup/user.png b/portal/static/img/original-backup/user.png
new file mode 100644 (file)
index 0000000..fa72bdd
Binary files /dev/null and b/portal/static/img/original-backup/user.png differ
index 3ae7bbe..dc74d29 100644 (file)
@@ -1,4 +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
+//@ sourceMappingURL=https://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.0/jquery.qtip.min.map
index 6236344..01a0c91 100644 (file)
@@ -2,15 +2,13 @@
 <div id="header">
        <div class="wrapper">
                <div class="logo">
-                       <a href="/"><img src="{{ STATIC_URL }}img/onelab-portal.png" alt="OneLab - Future Internet Testbeds" /></a>
+                       <a href="/"><img src="{{ STATIC_URL }}img/fibre-logo.gif" alt="FIBRE - Future Internet Testbeds Experimentation Between Brazil and Europe" width="150px" height="75px" /></a>
                </div>
                
                <div id="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>
-                               <li><a target="_blank" href="http://intranet.onelab.eu">Intranet</a></li>
+                               <li><a target="_blank" href="http://www.fibre-ict.eu/">Public Website</a></li>
                        </ul>
                </div>
        </div>
index 0f2ecb5..a7dc6fd 100644 (file)
@@ -3,7 +3,7 @@
 <html lang="en"><head>
 <title>{{theme}} portal - {{ section }}</title>
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
-<link rel="shortcut icon" href="/static/img/favicon.ico">
+<link rel="shortcut icon" href="/static/img/fibre-logo2.ico"height ='16' width='16'>
 {# This is where insert_str will end up #}{% media_container prelude %}
 {% include 'messages-transient-header.html' %}
 <script type="text/javascript"> {# raw js code - use {% insert prelude_js %} ... {% endinsert %} #} {% container prelude_js %}</script>
@@ -86,7 +86,7 @@ $(document).ready(function() {
 <body ng-app="ManifoldApp">
 {% block container %}
        {% block topmenu %}
-       {% widget "_widget-topmenu.html" %}
+       {% widget "__widget-topmenu.html" %}
        {% endblock topmenu %}
        {% block base_content %}
        {% endblock %}
index ce763ba..49fdbff 100644 (file)
@@ -8,7 +8,6 @@
 <div class="row">
        {% if activation_status == 'success' %}
                <h3>Signup request confirmed.</h3>
-               <p>You are currently able to log in to the portal using your email address and the password that you provided, but your access is still limited.</p> 
                <p>You will have full access as soon as your account is validated by a manager at your organization. We have sent an email to the managers with a validation request.</p>
     {% elif activation_status == 'validated' %}
                <h3>Account validated.</h3>
diff --git a/portal/templates/fibre/fibre__widget-login-fed-manager.html b/portal/templates/fibre/fibre__widget-login-fed-manager.html
new file mode 100644 (file)
index 0000000..181fe83
--- /dev/null
@@ -0,0 +1,35 @@
+<div class="well login-widget" style="background:none;border:none;width:400px;">
+       {% if state %}
+       <span class="help-block">{{ state }}</span>
+       {% endif %}
+       <form action="/login/" method="post" role="form">
+         {% csrf_token %}
+         {% if next %}
+         <input type="hidden" name="next" value="{{ next }}" />
+         {% endif %}
+        <div class="form-group" style="color:white;">
+       <!--<label for="fed"></label>
+       <input type="radio" name="base" value="br" checked>
+               <img src="{{ STATIC_URL }}img/fibre/br.png" alt="Brazil" height="32" width="40" />
+       <input type="radio" name="base" value="eu">
+               <img src="{{ STATIC_URL }}img/fibre/eu.png" alt="Europe Union" height="32" width="32" />
+       <input type="radio" name="base" value="local">&nbsp;Local User -->
+       </div> 
+
+       <div class="form-group">
+       <label for="username">Username</label>
+       <input type="text" class="form-control" name="username" placeholder="Enter username@organization">
+       </div>
+       <div class="form-group">
+       <label for="password">Password</label>
+       <input type="password" class="form-control" name="password" placeholder="Password">
+       </div>
+       <div class="login-submit">
+               <input class="btn btn-default" type="submit" 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">
+               Don't have an account? <a href="/portal/register">Sign up now</a>
+       </div>
+       </form>
+</div>
diff --git a/portal/templates/fibre/fibre__widget-login-manager.html b/portal/templates/fibre/fibre__widget-login-manager.html
new file mode 100644 (file)
index 0000000..7c5f170
--- /dev/null
@@ -0,0 +1,26 @@
+<div class="well">
+       {% if state %}
+       <span class="help-block">{{ state }}</span>
+       {% endif %}
+       <form action="/login/" method="post" role="form">
+         {% csrf_token %}
+         {% if next %}
+         <input type="hidden" name="next" value="{{ next }}" />
+         {% endif %}
+       <div class="form-group">
+       <label for="username">Email address / Username</label>
+       <input type="email" class="form-control" name="username" placeholder="Enter Email / username">
+       </div>
+       <div class="form-group">
+       <label for="password">Password</label>
+       <input type="password" class="form-control" name="password" placeholder="Password">
+       </div>
+       <div class="login-submit">
+               <input class="btn btn-default" type="submit" 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">
+               <a href="/portal/register">Try</a>, <a href="/portal/register">Sign Up</a> or <a href="/portal/join">Join</a>
+       </div>
+       </form>
+</div>
diff --git a/portal/templates/fibre/fibre__widget-topmenu.html b/portal/templates/fibre/fibre__widget-topmenu.html
new file mode 100644 (file)
index 0000000..088ba06
--- /dev/null
@@ -0,0 +1,76 @@
+{% load portal_filters %}
+<div class="header">
+<div class="container">
+       <div class="row">
+               <div class="col-sm-3 col-md-3 logo">
+                       <a href="/"><img src="{{ STATIC_URL }}img/fibre-logo.gif" alt="FIBRE - Future Internet Testbeds Experimentation Between Brazil and Europe" width="150px" height="75px" /></a>
+               </div>
+               {% if username %}
+               <div class="col-sm-4 col-md-4 navigation">
+                       <ul>
+                               <li>
+                                       <a class="dropdown-toggle" data-toggle="dropdown" href="#">
+                                       EXPERIMENT <span class="caret"></span>
+                               </a>
+                                       
+                                       <div class="dropdown-menu" style="z-index:99;">
+                                                       <ul id="dropdown-slice-list">
+                                                               <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>
+                                {%endif%}
+                               <li><a href="/portal/support/">SUPPORT</a></li>
+                       </ul>
+               </div>
+               {% else %}
+               <div class="col-sm-4 col-md-4 navigation">
+               </div>
+               {% endif %}
+               <div class="col-sm-5 col-md-5 secondary">
+                       <ul>
+                               <li><a href="/portal/about">About</a></li>
+                               <li><a target="_blank" href="http://www.fibre-ict.eu/">Public Website</a></li>
+                       </ul>
+                       {% if section != 'Registration' %}
+                               {% if username %}
+                                       {% if person.username %}
+                                               <div class="account" id="username" >You are logged in as &nbsp;<a href="/portal/account/">{{ person.username }}</a> &nbsp;&nbsp;|&nbsp;&nbsp; <a id="logout" style="cursor:pointer;" data-username="{{ person.username }}"><span class="glyphicon glyphicon-off"></span> Logout</a></div>
+                                       {% else %}
+                                               <div class="account"> You are logged in as &nbsp;<a href="/portal/account/">{{ email }}</a> &nbsp;&nbsp;|&nbsp;&nbsp; <a id="logout" style="cursor:pointer;" data-username="{{ email }}"><span class="glyphicon glyphicon-off"></span> Logout</a></div>
+                                       {% endif %}
+                               {% endif %}
+                       {% endif %}
+               </div>
+       </div>
+</div>
+</div>
+
+<div class="row">
+{% widget '_widget-message.html' %}
+</div>
+<script>
+       $(document).ready(function() {
+               $('li.slices').mouseenter(function() {
+                       $('div#menu-slice-list').fadeIn(100);
+               });
+               $('div#menu-slice-list').mouseleave(function(e) {
+                       if (!$('li.slices').is(":hover")) {
+                               $(this).fadeOut(100);
+                       }
+               });
+               // var slices = localStorage.getItem('slices');
+               // if (slices.length == 0) {
+                       // $.post("/rest/user/",{'filters':{'user_hrn':'$user_hrn'}}, function( data ) {
+                       // var items = [];
+                               // localStorage.setItem('slices', data[0].slice);
+                       // });
+               // }
+               // $.each(slices, function( key, val ) {
+                       // items.push( "<li><a href=\"/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></li>" );
+               // });
+               // $("div#home-slice-list").html($( "<ul/>", { html: items.join( "" ) }));
+       });
+</script>
diff --git a/portal/templates/fibre/fibre_about.html b/portal/templates/fibre/fibre_about.html
new file mode 100644 (file)
index 0000000..da64199
--- /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>
+                               FIBRE Portal is a central place to get acess to all FIBRE 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 FIBRE visit:  <a href="http://www.fibre-ict.eu" target="_blank">http://www.fibre-ict.eu/</a>                        
+                       </p>
+                       <p>
+                               If you have any questions regarding using the portal visit: <a href="/portal/support">FIBRE support</a>
+                       </p>
+                       <p>
+                               FIBRE portal is based on MySlice, which is a community effort. To get more information about MySlice 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/fibre/fibre_account-view.html b/portal/templates/fibre/fibre_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/fibre/fibre_activate_user.html b/portal/templates/fibre/fibre_activate_user.html
new file mode 100644 (file)
index 0000000..b5f3e73
--- /dev/null
@@ -0,0 +1,29 @@
+<img src="https://146.164.47.246:27486/static/img/fibre-logo.gif" width="217" height="100">
+<br>
+<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>
+Username : {{ username }} <br>
+Email: {{email}}<br>
+
+<p></p>
+<p>
+ 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 Myslice. You will find answers to frequently asked questions <a href="https://{{current_site}}/portal/support/">here</a>. 
+Please don't hesitate to <a href="https://{{current_site}}/portal/contact/">contact us</a> with any additional questions that you might have.
+</p>
diff --git a/portal/templates/fibre/fibre_activate_user.txt b/portal/templates/fibre/fibre_activate_user.txt
new file mode 100644 (file)
index 0000000..0d3253a
--- /dev/null
@@ -0,0 +1,24 @@
+We have received a user signup request for your email address at {{current_site}}
+
+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 Myslice. 
+Please don't hesitate to contact us at support@fibre.org.br with any additional questions that you might have.
+
+
+
diff --git a/portal/templates/fibre/fibre_activate_user_email_subject.txt b/portal/templates/fibre/fibre_activate_user_email_subject.txt
new file mode 100644 (file)
index 0000000..0e76f7c
--- /dev/null
@@ -0,0 +1 @@
+{{current_site}} Portal user email activation
diff --git a/portal/templates/fibre/fibre_base.html b/portal/templates/fibre/fibre_base.html
new file mode 100644 (file)
index 0000000..2d9d53e
--- /dev/null
@@ -0,0 +1,49 @@
+{# This is required by insert_above #}{% insert_handler %}<!DOCTYPE html>
+<html lang="en"><head>
+<title>OneLab - {{ section }}</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<link rel="shortcut icon" href="/static/img/myslice-icon.png">
+{# This is where insert_str will end up #}{% media_container prelude %}
+{% include 'messages-transient-header.html' %}
+<script type="text/javascript"> {# raw js code - use {% insert prelude_js %} ... {% endinsert %} #} {% container prelude_js %}</script>
+<script src="{{ STATIC_URL }}js/jquery.dataTables.min.js"></script>
+<script src="{{ STATIC_URL }}js/bootstrap.datatables.js"></script>
+<script src="{{ STATIC_URL }}js/myslice.js"></script>
+<script src="{{ STATIC_URL }}js/myslice-ui.js"></script>
+<style type="text/css">{# In case we need to add raw css code #}{% container prelude_css %}</style>
+{{ header_prelude }}
+{% block head %} {% endblock head %}
+{# let's add these ones no matter what #}
+{% insert_str prelude "js/jquery.min.js" %}
+{% insert_str prelude "js/angular/angular.min.js" %}
+{% insert_str prelude "js/jquery.html5storage.min.js" %}
+{% insert_str prelude "js/messages-runtime.js" %}
+{% insert_str prelude "js/class.js" %}
+{% insert_str prelude "js/plugin-helper.js" %}
+{% insert_str prelude "js/mustache.js" %}
+{% insert_str prelude "js/hashtable.js" %}
+{% insert_str prelude "js/plugin.js" %}
+{% insert_str prelude "js/manifold.js" %}
+{% insert_str prelude "css/manifold.css" %}
+{% insert_str prelude "css/plugin.css" %}
+{% insert_str prelude "js/bootstrap.js" %}
+{% insert_str prelude "css/bootstrap.css" %}
+{% insert_str prelude "js/bootstrap-datepicker.js" %}
+{% insert_str prelude "css/datepicker.css" %}
+{% insert_str prelude "js/bootstrap-slider.js" %}
+{% insert_str prelude "css/slider.css" %}
+{% insert_str prelude "css/topmenu.css" %}
+{% insert_str prelude "js/logout.js" %}
+<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/{{ theme }}.css">
+</head>
+<body ng-app="ManifoldApp">
+{% block container %}
+       {% block topmenu %}
+       {% include theme|add:"_widget-topmenu.html" %}
+       {% endblock topmenu %}
+       {% include 'messages-transient.html' %}
+       {% block base_content %}
+       {% endblock %}
+{% endblock container %}
+</body>
+</html>
diff --git a/portal/templates/fibre/fibre_contact.html b/portal/templates/fibre/fibre_contact.html
new file mode 100644 (file)
index 0000000..74f0eb1
--- /dev/null
@@ -0,0 +1,41 @@
+{% 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:info@fibre.org.br">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>
+                <button type="button" class="btn btn-onelab" onclick="window.location.href='/'">  Home  </button>
+               </form>
+       </div>
+</div>
+{% endblock %}
+
diff --git a/portal/templates/fibre/fibre_email_default_sender.txt b/portal/templates/fibre/fibre_email_default_sender.txt
new file mode 100644 (file)
index 0000000..32008b9
--- /dev/null
@@ -0,0 +1 @@
+support@fibre.org.br
diff --git a/portal/templates/fibre/fibre_home-view.html b/portal/templates/fibre/fibre_home-view.html
new file mode 100644 (file)
index 0000000..347be8c
--- /dev/null
@@ -0,0 +1,185 @@
+{% extends "layout_base.html" %}
+{% load portal_filters %}
+
+{% block content %}
+<!-- <div class="row">
+{% widget '_widget-news.html' %}
+</div> -->
+{% if username %}
+<div class="container dashboard">
+       <div class="row">
+               {%if 'is_pi'  in pi %}
+               <div class="col-md-3">
+                       <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-3">
+                       <h3>MANAGEMENT</h3>
+                       <div>
+                               <a href="/portal/institution"><img src="{{ STATIC_URL }}img/icon_authority_color.png" alt="" /></a>
+                       </div>
+                       <div>
+                               <button id="validaterequestbtn" type="button" class="btn btn-default"><span class="glyphicon glyphicon-ok"></span> Validate Requests</button>
+                       </div>
+               </div>
+               <div class="col-md-3">
+                       <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-3">
+                       <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="{{ person.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">Email:</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'. 
+                                       However, on the OneLab portal, you will only see slices that you have created through OneLab. If you have created slices elsewhere, 
+                                       such as on the PlanetLab Europe portal, those slices will not appear here."
+                                       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">Email:</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 class="">
+               <div class="col-sm-1"></div>
+               <div class="col-sm-5 slogan">
+                       <h2>
+                               FIBRE: Future Internet testbeds experimentation between Brazil and Europe
+                       </h2>
+                       <h3>
+                               Access variety of testbeds through your account
+                       </h3>
+               </div>
+               <div class="col-sm-5 col-sm-offset-1">
+                       <div class="row">
+                           {% include 'fibre__widget-login-fed-manager.html' %}
+                               <!--<a href="/cafe" style="margin-left:80px;"><img src="{{ STATIC_URL }}img/fibre/cafe.jpg" alt="CAFe authentication" /></a>-->
+                               <a href="/cafe" style="margin-left:80px;"><img src="{{ STATIC_URL }}img/fibre/expresso.png" alt="CAFe Expresso authentication" /></a>
+                       </div>
+               </div>
+               <div class="col-sm-1"></div>
+       </div>
+</div>
+{% endif %}
+
+
+<script type="text/javascript">
+       $(document).ready(function() {
+               $('a.home-tab').click(function() {
+                       $('ul.nav-tabs li').removeClass('active');
+                       $(this).parent().addClass('active');
+                       $('div.home-panel').hide();
+                       $('div#'+$(this).data('panel')).show();
+               });
+               $('button#validaterequestbtn').click(function() {
+                       window.location="/portal/institution#requests";
+               });
+               $('button#ticketbtn').click(function() {
+                       window.location="/portal/contact/";
+               });
+               $('button#signupbtn').click(function() {
+                       window.location="/portal/register/";
+               });
+               $('button#slicerequestbtn').click(function() {
+                       window.location="/portal/slice_request/";
+               });
+/*-------
+List of slices has been moved in 
+portal/templates/base.html
+This should go into session
+--------*/
+});
+</script>
+{% endblock %}
diff --git a/portal/templates/fibre/fibre_institution.html b/portal/templates/fibre/fibre_institution.html
new file mode 100644 (file)
index 0000000..1d6cf97
--- /dev/null
@@ -0,0 +1,196 @@
+{% extends "layout_wide.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">
+                        <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="#about">About</a></li>-->
+                               <li class="active"><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="about">
+       </div>
+-->
+       <div class="tab-pane row" id="users" data-authority="{{user_details.parent_authority}}">
+               <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" class="table">
+                                       <tr>
+                                       <th>+/-</th>
+                                       <th>User hrn </th>
+                                       <th>Email</th>
+                                       <th>First name</th>
+                                       <th>Last name</th>
+                                       <th>Enabled</th>
+                                       </tr>
+                               </table>
+                               
+                       </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>
+                       <p></p>
+                        <p></p>
+                        <div> <button type="button" class="btn btn-onelab" onclick="window.location.href='/'">Home</button> </div>
+                       {% endif %}
+               </div>
+       </div>
+
+       <div class="tab-pane row" id="slices">
+               <div class="col-md-12 el">
+           <div id="slice-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Slices" /></div>
+           <div id="slice-tab-loaded" style="display:none;">
+               <table id="slice-tab" class="table">
+                   <tr>
+                       <th>+/-</th>
+                       <th>Slice hrn</th>
+                       <th>Users</th>
+                       <th>Url</th>
+                       <!-- <th>nodes</th> -->
+                       <th>Expiration</th>
+                   </tr>
+               </table>                        
+           </div>
+       {% if 'is_pi'  in pi %}
+        <div>
+               {% if 'is_pi'  in pi %}
+                       <button id="createslice" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Create slice</button>
+                       {% else %}
+                       <button id="createslice" type="button" class="btn btn-default"><span class="glyphicon glyphicon-plus"></span> Request slice</button>
+                       {% endif %}
+            <button id="renewslices" type="button" class="btn btn-primary"><span class="glyphicon glyphicon-refresh"></span> Renew Slices</button>
+            <button id="deleteslices" type="button" class="btn btn-danger"><span class="glyphicon glyphicon-remove"></span> Delete Slices</button>
+           <p></p>
+           <p></p>
+           <div><button type="button" class="btn btn-onelab" onclick="window.location.href='/'">Home</button></div>
+        </div>
+               {% endif %} 
+          </div>
+       </div>
+       <div class="tab-pane row" id="requests">
+       </div>
+</div>
+<script>
+$(document).ready(function() {
+    {% if person %}
+    {% if user_details.parent_authority %}
+
+        $.post("/rest/slice/",{'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
+           var username = "{{person.username}}";
+            var list_slices = [];
+            var table_slices = [];
+            /* "slice_hrn", "slice_description", "slice_type", "parent_authority", "created", "nodes", "slice_url", "slice_last_updated", "users", "slice_urn", "slice_expires" */
+            $.each( data, function( key, val ) {
+               if(String(val.users[0]).indexOf("@") != -1){
+               if(String(val.users[0]).split("@")[1] == username.split("@")[1]){
+                list_slices.push( "<li><a href=\"portal/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></li>" );
+                if(val.nodes=="undefined" || val.nodes==null){
+                    nodes_length=0;
+                }else{
+                    nodes_length=val.nodes.length;
+                }
+                console.log(val);
+                if(val.users=="undefined" || val.users==null){
+                    users_length=0;
+                }else{
+                    users_length=val.users.length;
+                }
+
+                if(val.slice_url=="undefined" || val.slice_url==null){
+                    slice_url="";
+                }else{
+                    slice_url="<a href='"+val.slice_url+"' target='_blank'>"+val.slice_url+"</a>";
+                }
+                
+                slice_row = "<tr id='"+val.slice_hrn+"'>";
+                slice_row += "<td><input type='checkbox' class='slice' id='"+val.slice_hrn+"'></td>";
+                slice_row += "<td><a href=\"/slice/"+val.slice_hrn+"\">" + val.slice_hrn + "</a></td>";
+                slice_row += "<td>"+val.users[0]+"</td>";
+                slice_row += "<td>"+slice_url+"</td>";
+                //slice_row += "<td>"+nodes_length+"</td>";
+                slice_row += "<td>"+val.slice_expires+"</td>";
+                slice_row += "</tr>";
+                table_slices.push(slice_row);
+               }
+              }
+            });
+           
+            /* $("div#slice-list").html($( "<ul/>", { html: list_slices.join( "" ) })); */
+            $("table#slice-tab tr:last").after(table_slices.join( "" ));
+            $("div#slice-tab-loaded").css("display","block");
+            $("div#slice-tab-loading").css("display","none");
+        });
+               
+               
+        $.post("/rest/user/",{'filters':{'parent_authority':'{{user_details.parent_authority}}'}}, function( data ) {
+           var username ="{{person.username}}";
+           var list_users = [];
+            var table_users = [];
+                   /* Available fields
+                   user_gid, user_enabled, slices, pi_authorities, keys, parent_authority, user_first_name,
+                   user_urn, user_last_name, user_phone, user_hrn, user_email, user_type
+                   */
+            $.each( data, function( key, val ) {
+               if (val.user_hrn.indexOf('@') != -1 ){
+                 if (val.user_hrn.split("@")[1] == username.split("@")[1]){
+                    list_users.push( "<li><a href=\"portal/user/"+val.user_email+"\">" + val.user_email + "</a></li>" );
+                    user_row = "<tr id='"+val.user_hrn+"'>";
+                    user_row += "<td><input type='checkbox' class='user' id='"+val.user_hrn+"'></td>";
+                    user_row += "<td>"+val.user_hrn+"</td>";
+                    user_row += "<td>"+val.user_email+"</td>";
+                    user_row += "<td>"+val.user_first_name+"</td>";
+                    user_row += "<td>"+val.user_last_name+"</td>";
+                               user_row += "<td>"+val.user_enabled+"</td>";
+                    user_row += "</tr>";
+                table_users.push(user_row);}
+               }
+            });
+            $("table#user-tab tr:last").after(table_users.join( "" ));
+            $("div#user-tab-loaded").css("display","block");
+            $("div#user-tab-loading").css("display","none");
+        });
+
+    {% endif %}
+    {% 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 == 'about'))
+               $("#" + id).load('/management/' + id);
+       });
+       var hash = window.location.hash;
+       if (hash) {
+               $('.nav-tabs a[href='+hash+']').click();
+       } else {
+               $('.nav-tabs a[href=#about]').click();
+       }
+});
+</script>
+{% endblock %}
diff --git a/portal/templates/fibre/fibre_management-tab-about.html b/portal/templates/fibre/fibre_management-tab-about.html
new file mode 100644 (file)
index 0000000..687b7de
--- /dev/null
@@ -0,0 +1,49 @@
+{% load portal_filters %}
+<div class="col-md-6">
+       <div>
+               <img src="{{ STATIC_URL|add:'img/institutions/'|add:authority.authority_hrn|add:'.gif'|file_exists }}" alt="{{authority.name}}">
+       </div>
+       <br />
+       <h3><a href="{{authority.url}}">{{authority.name}}</a></h3>
+       <p>
+               {{authority.address}} <br />
+               {{authority.postcode}} {{authority.city}} <br />
+               {{authority.country}}
+       </p>
+       <br />
+       <h4>Onelab membership</h4> 
+       <p>
+               {{ authority.onelab_membership }}
+       </p>
+</div>
+<div class="col-md-6">
+       <h4>Legal Contact:</h4>
+       <p>
+       {% for c in authority_contacts.legal %}
+                {{ c }} <br />
+       {% endfor %}
+       </p>
+       <br />
+       <h4>Scientific Contact:</h4>
+       <p>
+       {% for c in authority_contacts.scientific %}
+               {{ c }} <br />
+       {% endfor %}
+       </p>
+       <br />
+       <h4>Technical Contact:</h4>
+       <p>
+       {% for c in authority_contacts.technical %}
+               {{ c }} <br />
+       {% endfor %}
+       </p>
+</div>
+<script>$(document).ready(function() {
+{% if authority.name %}
+    auth_name = "{{authority.name}}";
+{% else %}
+    auth_name = "{{authority.authority_hrn}}";
+{% endif %}
+    $('#authority_name').text(auth_name);
+});
+</script>
diff --git a/portal/templates/fibre/fibre_management-tab-requests.html b/portal/templates/fibre/fibre_management-tab-requests.html
new file mode 100644 (file)
index 0000000..8023e7c
--- /dev/null
@@ -0,0 +1,227 @@
+<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>
+       {% endfor %}
+
+{% else %}
+       <div class="col-md-12">
+               <i>There is no pending request waiting for validation.</i>
+       </div>
+{% endif %}
+<div>nnllknjkn<br /><br /></div>
+<div class="col-md-12">
+       <h2>Sub-Authorities</h2>
+</div>
+{% if sub_authorities %}
+       
+       {% for authority, requests in sub_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>
+       {% 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>
+       </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>
+               {% endfor %}
+{% else %}
+<div class="col-md-12">
+       <i>There is no pending request waiting for validation.</i>
+</div>
+{% endif %}
+<div class="col-md-12">
+       <button class="btn btn-onelab" type="button" id="portal__validate" onclick="on_click_event();"><span class="glyphicon glyphicon-ok"></span> Validate</button>
+       <button type="button" class="btn btn-onelab" onclick="window.location.href='/'">Home</button>
+</div>
diff --git a/portal/templates/fibre/fibre_news.html b/portal/templates/fibre/fibre_news.html
new file mode 100644 (file)
index 0000000..69b417d
--- /dev/null
@@ -0,0 +1,21 @@
+{% extends "layout_wide.html" %}
+
+{% block content %}
+<div class="container">
+    <div class="row">
+        <div class="col-md-12">
+               <h1><img src="{{ STATIC_URL }}icons/slices-xs.png" alt="News" />News</h1>
+               <br />
+        </div>
+    </div>
+       <div class="row">
+        <div class="col-md-12">
+               <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>
+{% endblock %}
diff --git a/portal/templates/fibre/fibre_registration_view.html b/portal/templates/fibre/fibre_registration_view.html
new file mode 100644 (file)
index 0000000..baa2e25
--- /dev/null
@@ -0,0 +1,277 @@
+{% 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 %}
+
+
+<form action="/register" class="cmxform form-horizontal" method="post" enctype="multipart/form-data">
+<div class="row">
+       
+       <div class="col-md-12">
+                       
+                       <div class="form-group">
+                               {% 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 choose the FIBRE organization. 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 class="form-group">
+                       <label for="Reasons" class="control-label" >Reasons for Applying</label>
+                       <p></p>
+                       <textarea type="text" rows="4" cols="70" name="reasons" size="25" class="form-control" style="width:350px;height:60px"  minlength="5" maxlength="250" value="{{reasons}}" placeholder="Reasons for applying" title="Identify yourself and tell us more about your expectations to use the testbed." required ></textarea>
+               </div>
+       </div>  
+
+       <div class="col-md-6">
+           <div class="form-group">
+             <label for="password" class="control-label">Authentication</label>
+                 <p></p>       
+                       <input type="text" name="username" size="25" class="form-control" style="width:350px" minlength="5" value="{{ username }}" placeholder="Username" required />
+           </div>
+            <div class="form-group">
+                       <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">
+                       <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" />
+               <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-12">
+               <div class="form-group" id="register">
+                       <p></p> 
+               <input class="submit btn btn-onelab" type="submit" value="Request My Account" />
+
+           </div>
+       </div>
+</div>
+</form>
+
+       <!-- 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">
+                                       Fibre: Future Internet testbeds experimentation between Brazil and Europe
+                                       <br/>
+                                               <a href="/portal/terms" target="_blank">[Printable format]</a>
+                                               </p>
+                                       <h1 align="left">1 Context</h1>
+                                       <p align="left">
+                    The main goal of the FIBRE project is the design, implementation and validation of a shared Future Internet research facility, supporting the joint experimentation of European and Brazilian researchers. In order to achieve this goal the project will carry out four main activities:
+                    </p>
+                                       <p align="left">
+                    The development and operation of a new experimental facility in Brazil, including the setup of equipment to support experimentation with various technologies (fixed layer 2 and layer 3, wireless, optical) as well as the design and implementation of a control framework to automate the use and operation of the testbed.
+                    </p>
+                                       <p align="left">
+                    The development and operation of a Future Internet facility in Europe based on enhancements and the federation of two existing infrastructures: OFELIA and OneLab. Two OFELIA islands (i2CAT and University of Bristol (UNIVBRIS)) and the UTH's NITOS testbed will be enhanced by i) adding more physical resources (servers, OpenFlow-enabled switches and access points) to be able to cope with a bigger number ofusers and different use cases, ii) improving its respective control frameworks (based on the OFELIA control framework and OMF) and iii) adding more manpower to operate the facilities.
+                    </p>
+                                       <p align="left">
+                    The federation of the Brazilian and European experimental facilities, both at the physical connectivity and control framework level, to support the provisioning of slices using resources from both testbeds.
+                    </p>
+<h2>PROCEDURE OVERVIEW</h2>
+<p>If your institution is willing to join the FIBRE Consortium, you are kindly requested to follow the steps below:<br></p>
+<p>1. <a mce_href="http://www.fibre-ict.eu/images/stories/docs/fibre_mou_v0.3.doc" href="http://www.fibre-ict.eu/images/stories/docs/fibre_mou_v0.3.doc">Download the MoU model</a>  to understand the framework of collaboration between your institution and FIBRE project. The content of the MoU shall be discussed in case-by-case basis between the two parties.&nbsp;<span style="line-height: 1.3em;" mce_style="line-height: 1.3em;">&nbsp;</span></p>
+<p>2. Contact the Project office at <a href="mailto:info@fibre.org.br">info@fibre.org.br</a> to schedule a call to clarify all your questions concerning the duties, responsibilities and advantages of joining the FIBRE project.</p>
+<p>3. If your institution understand and agree on the commitment stated in the MoU, please submit the application by editing the <a href="http://www.fibre-ict.eu/images/fibre_mou_v0.2_ff.doc" mce_href="http://www.fibre-ict.eu/images/fibre_mou_v0.2_ff.doc" style="style" mce_style="style">MoU template</a> and sending it to 
+ <a href="mailto:info@fibre.org.br">info@fibre.org.br</a></p>
+<p>4. Application Approval: the FIBRE General Assembly will decide based on the application and information gathered during the call. The approval process will normally take around one month.</p><p>5. By mutual agreement of both parties, MoU will be prepared and signed.</p>
+<p><span style="line-height: 1.3em;" mce_style="line-height: 1.3em;">6. Testbed usage / island installation: FIBRE will provide instructions and support to help your institution to carry out the activities described in the MoU.</span></p>
+<p><br></p>
+<p><span style="line-height: 1.3em;" mce_style="line-height: 1.3em;"><a mce_href="http://webconf2.rnp.br/p27egdf20y7/" href="http://webconf2.rnp.br/p27egdf20y7/">Watch the webconference meeting about the MoU details</a><br> (Held on 5/July 2013, in Portuguese)<br></span></p>
+<p><br></p>
+                               </div>
+                               <div class="modal-footer">
+                                       <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
+                               </div>
+                       </div>
+                       </div>
+</div>
+
+    
+<script>
+$(document).ready(function(){
+    var availableTags = [
+    {% if authorities %}
+        {% for authority in authorities %}
+            {% if authority.name %}
+                {value:"{{ authority.name }}",label:"{{authority.name}}"},
+            {% else %}
+               {% if authority.authority_hrn == "fibre.ufrj" %}
+                        {value:"{{ authority.authority_hrn }}",label:"UFRJ - UNIVERSIDADE FEDERAL DO RIO DE JANEIRO"},
+                {% else %}
+                      {% if authority.authority_hrn == "fibre.ufg" %}
+                              {value:"{{ authority.authority_hrn }}",label:"UFG - UNIVERSIDADE FEDERAL DE GOIAS"},
+                      {% else %}
+                              {% if authority.authority_hrn == "fibre.uff" %}
+                                     {value:"{{ authority.authority_hrn }}",label:"UFF - UNIVERSIDADE FEDERAL FLUMINENSE"},
+                              {% else %}
+                                     {% if authority.authority_hrn == "fibre.ufpa" %}
+                                             {value:"{{ authority.authority_hrn }}",label:"UFPA - UNIVERSIDADE FEDERAL DO PARA"},
+                                     {% else %}
+                                             {% if authority.authority_hrn == "fibre.ufpe" %}
+                                                     {value:"{{ authority.authority_hrn }}",label:"UFPE - UNIVERSIDADE FEDERAL DE PERNAMBUCO"},
+                                             {% else %}
+                                                     {% if authority.authority_hrn == "fibre.ufscar" %}
+                                                            {value:"{{ authority.authority_hrn }}",label:"UFSCAR - UNIVERSIDADE FEDERAL DE SAO CARLOS"},
+                                                     {% else %}
+                                                            {% if authority.authority_hrn == "fibre.unifacs" %}
+                                                                     {value:"{{ authority.authority_hrn }}",label:"UNIFACS - UNIVERSIDADE SALVADOR"},
+                                                            {% else %}
+                                                                     {% if authority.authority_hrn == "fibre.usp" %}
+                                                                            {value:"{{ authority.authority_hrn }}",label:"USP - UNIVERSIDADE DE SAO PAULO"},
+                                                                     {% else %}
+                                                                            {% if authority.authority_hrn == "fibre.cpqd" %}
+                                                                                    {value:"{{ authority.authority_hrn }}",label:"CPQD - CENTRO DE PESQUISA E DESENVOLVIMENTO EM TELECOMUNICACOES"},
+                                                                            {% else %}
+                                                                                    {% if authority.authority_hrn == "fibre.rnp" %}
+                                                                                             {value:"{{ authority.authority_hrn }}",label:"(Catch-all) RNP - REDE NACIONAL DE ENSINO E PESQUISA"},
+                                                                                    {% else %}
+                                                                                       {% if authority.authority_hrn == "fibre.i2cat" %}
+                                                                                               {value:"{{ authority.authority_hrn }}",label:"I2CAT - FOUNDATION, RESEARCH AND INNOVATION IN THE INTERNET AREA"},
+                                                                                       {% else %}
+                                                                                               {% if authority.authority_hrn == "fibre.uth" %}
+                                                                                                        {value:"{{ authority.authority_hrn }}",label:"UTH - UNIVERSITY OF THESSALY"},
+                                                                                               {% else %}
+                                                                                                     {% if authority.authority_hrn == "fibre.bristol" %}
+                                                                                                            {value:"{{ authority.authority_hrn }}",label:"UNIBRIS - UNIVERSITY OF BRISTOL"},
+                                                                                                      {% else %}
+                                                                                                            {% if authority.authority_hrn == "fibre.upmc" %}
+                                                                                                                   {value:"{{ authority.authority_hrn }}",label:"UPMC - UNIVERSITE PIERRE ET MARIE CURIE"},
+                                                                                                            {% else %}
+                                                                                                                   {value:"{{ authority.authority_hrn }}",label:"FIBRE"},
+                                                                                                               {% endif %}
+                                                                                               {% endif %}
+                                                                                       {% endif %}
+                                                                               {% endif %}
+                                                                            {% endif %}
+                                                                         {% endif %}
+                                                                     {% endif %}
+                                                            {% endif %}
+                                                    {% endif %}
+                                             {% endif %}
+                                    {% endif %}
+                              {% endif %}
+                      {% endif %}
+                {% endif %}
+            {% 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
+    $( "#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
+       $('[title!=""]').qtip();
+       $("form").validate();
+       $("form").submit(function() {
+               if ($('select option:selected').val() == 'upload') {
+                       if ($('input[name=user_public_key]').val() == '') {
+                               alert('Please specify the key file to upload');
+                               return false;
+                       }
+               }
+       });
+});
+</script>
+{% endblock %}
+
diff --git a/portal/templates/fibre/fibre_slice-request-ack-view.html b/portal/templates/fibre/fibre_slice-request-ack-view.html
new file mode 100644 (file)
index 0000000..083693b
--- /dev/null
@@ -0,0 +1,13 @@
+{% extends "layout.html" %}
+
+{% block content %}
+
+<h1><img src="{{ STATIC_URL }}icons/slices-xs.png" alt="Slice" /> Slice request sent</h1>
+
+We will process your request and get back to you as soon as possible.
+<p></p>
+<p></p>
+<button type="button" class="btn btn-onelab" onclick="window.location.href='/'">Home</button>
+
+{% endblock %}
+
diff --git a/portal/templates/fibre/fibre_slice-request-done-view.html b/portal/templates/fibre/fibre_slice-request-done-view.html
new file mode 100644 (file)
index 0000000..b4f4b78
--- /dev/null
@@ -0,0 +1,12 @@
+{% extends "layout-unfold1.html" %}
+
+{% block unfold_main %}
+
+  <h1>Slice created !</h1>
+
+As you are a PI of the site, you slice has directly been created.
+<p></p>
+<p></p>
+<button type="button" class="btn btn-onelab" onclick="window.location.href='/'">Home</button>
+{% endblock %}
+
index 17e1383..bc2a2ed 100644 (file)
@@ -54,6 +54,7 @@ $(document).ready(function() {
                        <ul class="nav nav-tabs">
                          <li class="active"><a href="#resourcelist" role="tab" data-toggle="tab">Table</a></li>
                          <li> <a href="#resourcemap" role="tab" data-toggle="tab">Map</a></li>
+              <li> <a href="#openflowcontroller" role="tab" data-toggle="tab">OpenFlow Controller</a></li>
               <li> <a href="#resourceflowspace" role="tab" data-toggle="tab">Flowspace</a></li>
                          <li> <a href="#resourcescheduler" role="tab" data-toggle="tab">Scheduler</a></li>
                        </ul>
@@ -91,8 +92,12 @@ $(document).ready(function() {
                                <div class="tab-pane" id="resourcemap">
                        {{map_resources}}
                                </div>
+                <div class="tab-pane" id="openflowcontroller">
+                    <p>{{vms_list}}</p>
+                    <p>{{vm_form}}</p>
+                    <p>{{below_table}}</p>
+                </div>
                 <div class="tab-pane" id="resourceflowspace">
-
                     <p>{{welcome}}</p>
                     <p>{{flowspaces}}</p>
                     <p>{{flowspaces_form}}</p>
@@ -101,12 +106,11 @@ $(document).ready(function() {
                     <p>{{resources}}</p>
 
                     <p>{{below_table}}</p>
-
                 </div>
                                <div class="tab-pane" id="resourcescheduler">
                        {{scheduler}}
                                </div>
-       
+
                                <!--
                                <div id="reserved" class="tab-pane" style="height:370px;display:none;">
                        <table width="80%">
diff --git a/portal/templates/fibre/fibre_slice-tab-users-view.html b/portal/templates/fibre/fibre_slice-tab-users-view.html
new file mode 100644 (file)
index 0000000..46f4c58
--- /dev/null
@@ -0,0 +1,130 @@
+<script type="text/javascript" src="{{STATIC_URL}}/js/jquery-ui.js"></script>
+<script type="text/javascript" src="{{STATIC_URL}}/js/jquery.qtip.min.js"></script>
+<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/jquery.qtip.min.css">
+<link rel="stylesheet" href="{{ STATIC_URL }}css/jquery-ui.css">
+<script>
+    function get_users_in_slice(authority_hrn){
+        $("table#user-tab").html("<tr><th>+/-</th><th>Email</th><th>User hrn</th></tr>");
+       var slice_users = [];
+       $.post("/rest/user/",{'filters':{'parent_authority': authority_hrn}}, function( data ) {
+               var list_users = [];
+               var table_users = [];
+               /* Available fields
+               user_gid, user_enabled, slices, pi_authorities, keys, parent_authority, user_first_name,
+           user_urn, user_last_name, user_phone, user_hrn, user_email, user_type
+               */
+               $.each( data, function( key, val ) {
+               list_users.push( "<li><a href=\"portal/user/"+val.user_email+"\">" + val.user_email + "</a></li>" );
+               user_row = "<tr>";
+                       // checking the box for the users that belong to the selected slice
+                       var flag_checkbox = 0;
+                       for(var data in val.slices) {
+                               var element = val.slices[data];
+                               if (element == "{{slice}}"){
+                                       //console.log("the slice is: "+ element);       
+                                       flag_checkbox = 1;
+                                       slice_users.push (val.user_hrn)
+                                       user_row += "<td><input type='checkbox' checked='True' class='user'></td>";
+                               }
+                       }
+                       if(flag_checkbox != 1){
+                       user_row += "<td><input type='checkbox' class='user'></td>";
+                       }
+               user_row += "<td>"+val.user_email+"</td>";
+               user_row += "<td>"+val.user_hrn+"</td>";
+                       //user_row += "<td>"+val.user_enabled+"</td>";
+               user_row += "</tr>";
+               table_users.push(user_row);
+            
+               });
+               $("table#user-tab tr:first").after(table_users.join( "" ));
+               $("div#user-tab-loaded").css("display","block");
+               $("div#user-tab-loading").css("display","none");
+            $("input:checkbox.user").click(function() {
+                user_hrn = $(this).closest('tr').find('td:eq(2)').html();
+                if(this.checked){
+                    var record_id = this.id;
+                    slice_users.push (user_hrn);
+                }else{
+                    console.log(slice_users);
+                }
+            });
+       }); // post rest/user
+    }
+
+    $(document).ready(function() {
+            // TODO: Add a filter based on the list of authorities
+               $.post("/rest/authority/",{'fields':['authority_hrn']}, function( data ) {
+                var list_authorities = [];
+                $.each( data, function( key, val ) {
+                    auth_hrn = val.authority_hrn;
+                    // Keep only the sub authorities, remove root auth
+                    //if(auth_hrn.indexOf(".") > -1){
+                        list_authorities.push(auth_hrn);
+                                               list_authorities.sort();
+                        if(auth_hrn=="{{user_details.parent_authority}}"){
+                                                       $('#auth_list').val(auth_hrn);
+                                               }
+                    //}
+                });
+                               $( "#auth_list" ).autocomplete({
+                               source: list_authorities,
+                               minLength: 0,
+                               select: function (event, ui) {
+                                               get_users_in_slice(ui.item.value);
+                               }
+                               //select: function( event, ui ) {console.log(jQuery(this))}
+                       });
+            }); // post rest/authority
+
+            get_users_in_slice("{{user_details.parent_authority}}");
+
+               $('button#addusers').click(function() {
+                $.post("/update/slice/",{'filters':{'slice_hrn':'{{slice}}'},'params':{'users':slice_users}}, function(data) {
+                       if(data.success){
+                       // TODO: highlight row after success
+                       //$('tr[id="'+record_id+'"]').highlight();
+                       mysliceAlert('Success: slice updated','success', true);
+                       }else{
+                       mysliceAlert('Rest Error for: '+data.error,'warning', true);
+                       }
+                }); // post update slice
+            
+               // TODO: refresh table
+               //window.location="/portal/institution#slices";
+
+            }); // button#addusers click
+       $('[title!=""]').qtip();
+    }); // document ready
+</script>
+
+       <div class="col-md-2">
+               <div id="select-platform" class="list-group">
+               </div>
+                       
+               <ul class="list-group">
+                 <li class="list-group-item">Authority</li>
+                 <li class="list-group-item" style="padding-left:5px;">
+                       <input type="text" id="auth_list"  style ="min-width:190px;" 
+                       title="The default value is  the authority that you belong to and the selected users belong to this slice.
+                                  You can view users of other authorities (organizations) 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."/>
+          </li>
+               </ul>
+       
+       </div>
+       <div class="col-md-10">
+               <div class="row">
+               </div>
+               <div id="user-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Useres" /></div>
+               <div id="user-tab-loaded" style="display:none;">
+               <table id="user-tab" class="table">
+               </table>
+
+                <!-- XXX TODO: for the moment only PIs have access to Update but users that have slice credentials should also have access to that -->
+
+                               {% if 'is_pi'  in pi %}
+                               <button id="addusers" type="button" class="btn btn-default"><span class="glyphicon glyphicon-ok"></span> Update users</button>
+                               {%endif%}
+               </div>
+
diff --git a/portal/templates/fibre/fibre_slice-user-view.html b/portal/templates/fibre/fibre_slice-user-view.html
new file mode 100644 (file)
index 0000000..0a239f1
--- /dev/null
@@ -0,0 +1,73 @@
+
+<div class="col-md-2">
+       <div id="select-platform" class="list-group">
+       </div>
+               
+       <ul class="list-group">
+         <li class="list-group-item">Authority:<b> {{user_details.parent_authority}}</b>
+               <!--<select id="auth_list">
+                       <option value="ple.upmc">UPMC</option>
+                       <option value="ple.inria">INRIA</option>
+                       <option value="ple.nitos">NITOS</option>
+                       <option value="ple.iminds">iMinds</option>
+               </select> -->
+         </li>
+         <li class="list-group-item">Filter: slice</li>
+         
+       </ul>
+
+</div>
+<div class="col-md-10">
+       <div id="user-tab-loading"><img src="{{ STATIC_URL }}img/loading.gif" alt="Loading Useres" /></div>
+       <div id="user-tab-loaded" style="display:none;">
+               <table id="user-tab" class="table">
+               <tr>
+                       <th>+/-</th>
+                       <th>Email</th>
+                       <th>User hrn</th>
+                       <th>Enabled</th>
+               </tr>
+               </table>
+       </div>
+</div>
+<script>
+    $(document).ready(function() {
+                       //console.log("the value you selected: " + selectedValue);
+               $.post("/rest/user/",{'filters':{'parent_authority': "{{user_details.parent_authority}}"}}, function( data ) {
+               var list_users = [];
+               var table_users = [];
+                               /* Available fields
+                               user_gid, user_enabled, slices, pi_authorities, keys, parent_authority, user_first_name,
+                           user_urn, user_last_name, user_phone, user_hrn, user_email, user_type
+                               */
+               $.each( data, function( key, val ) {
+                       //list_users.push( "<li><a href=\"portal/user/"+val.user_email+"\">" + val.user_email + "</a></li>" );
+                       user_row = "<tr>";
+                                       // checking the box for the users that belong to the selected slice
+                                       var flag_checkbox = 0;
+                                       for(var data in val.slices) {
+                                       var element = val.slices[data];
+                                               if (element == "{{slice}}"){
+                                                       //console.log("the slice is: "+ element);       
+                                                       flag_checkbox = 1;
+                                                       user_row += "<td><input type='checkbox' checked='True'></td>";
+                                               }
+                                       }
+                                       if(flag_checkbox != 1){
+                               user_row += "<td><input type='checkbox'></td>";
+                                       }
+                       user_row += "<td>"+val.user_email+"</td>";
+                       user_row += "<td>"+val.user_hrn+"</td>";
+                                       user_row += "<td>"+val.user_enabled+"</td>";
+                       user_row += "</tr>";
+                       table_users.push(user_row);
+                
+               });
+                               $("table#user-tab tr:last").after(table_users.join( "" ));
+               $("div#user-tab-loaded").css("display","block");
+               $("div#user-tab-loading").css("display","none");
+               });
+       //      });
+    });
+</script>
+
diff --git a/portal/templates/fibre/fibre_slice-view.html b/portal/templates/fibre/fibre_slice-view.html
new file mode 100644 (file)
index 0000000..8057609
--- /dev/null
@@ -0,0 +1,20 @@
+{% extends "layout_wide.html" %}
+
+{% block head %}
+
+{% endblock %}
+
+{% block content %}
+
+{% include theme|add:"_widget-slice-sections.html" %}
+         
+<div class="container-fluid tab-content container-slice">
+  <div class="tab-pane active row" id="info">...</div>
+  <div class="tab-pane row" id="testbeds">...</div>
+  <div class="tab-pane row" id="resources">...</div>
+  <div class="tab-pane row" id="users">...</div>
+  <!-- <div class="tab-pane row" id="statistics">...</div> -->
+  <!-- <div class="tab-pane row" id="measurements">...</div> -->
+  <div class="tab-pane row" id="experiment">...</div>
+</div>         
+{% endblock %}
diff --git a/portal/templates/fibre/fibre_slice_request_email.html b/portal/templates/fibre/fibre_slice_request_email.html
new file mode 100644 (file)
index 0000000..fd140d7
--- /dev/null
@@ -0,0 +1,11 @@
+<img src="https://146.164.47.246:27486/static/img/fibre-logo.gif" width="217" height="100">
+<br>
+<h1>NEW SLICE REQUEST</h1>
+<br>
+<b>Slice name      :</b> {{slice_name}}</br>
+<b>URL                            :</b> {{exp_url}}</br>
+<b>Purpose         :</b> {{purpose}}</br>
+<b>Organization           :</b> {{organization}}</br>
+<b>Email           :</b> {{email}}</br>
+<b>Portal url     :</b> {{current_site}}</br> 
+
diff --git a/portal/templates/fibre/fibre_slice_request_email.txt b/portal/templates/fibre/fibre_slice_request_email.txt
new file mode 100644 (file)
index 0000000..c8a51b5
--- /dev/null
@@ -0,0 +1,9 @@
+NEW SLICE REQUEST
+
+Slice name      : {{slice_name}}
+URL                    : {{exp_url}}
+Purpose         : {{purpose}}
+Email           : {{email}}
+Organization   : {{organization}}
+Portal url             : {{current_site}}
+
diff --git a/portal/templates/fibre/fibre_slice_request_email_subject.txt b/portal/templates/fibre/fibre_slice_request_email_subject.txt
new file mode 100644 (file)
index 0000000..e3988df
--- /dev/null
@@ -0,0 +1 @@
+Slice request submitted 
diff --git a/portal/templates/fibre/fibre_slicerequest_view.html b/portal/templates/fibre/fibre_slicerequest_view.html
new file mode 100644 (file)
index 0000000..c71e3a7
--- /dev/null
@@ -0,0 +1,109 @@
+{% 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" value="{{slice_name}}" 
+                               title="Please enter a name for your slice"required="required">
+                         </div>
+                         <div class="form-group">
+                               {%if 'is_pi'  in pi %}
+                               <input style='display:none' type="text" class="form-control" id="authority_hrn" name="org_name" style="width:300px" placeholder="Organization" 
+                               title="An authority responsible for vetting your slice" required="required" readonly>
+                               {%else%}
+                           <input style='display:none' type="text" class="form-control" display=none  id="authority_hrn" name="org_name" placeholder="Organization" style="width:300px;" 
+                               title="An authority responsible for vetting your slice" required="required" readonly>
+                               {%endif%}
+                         </div>
+                         <div class="form-group">
+                           <input type="text" class="form-control" name="exp_url" id="exp_url" style="width:300px" placeholder="Experiment URL (if one exists)"
+                               title="Please provide the url of your experiment if you have one." value="{{exp_url}}">
+                         </div>
+                         <div class="form-group">
+                               <textarea id="purpose" name="purpose" class="form-control" rows="6" placeholder="Experiment purpose" style="width:300px" 
+                               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>
+                         <button type="button" class="btn btn-onelab" onclick="window.location.href='/'">Home</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']);
+    });*/
+    console.log("test");
+    test = "{{authority.name}}";
+    if(test){
+        console.log("true");
+           $("#authority_hrn").val("{{authority_name}}");
+    }else{
+        console.log("false");
+           $("#authority_hrn").val("{{authority_hrn}}");
+    }
+
+       var availableTags = [
+    {% if authorities %}
+        {% for authority in authorities %}
+            {% if authority.name %}
+                {value:"{{ authority.name }}",label:"{{authority.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;
+       }); 
+    $( "#authority_hrn" ).autocomplete({
+      source: availableTags,
+      minLength: 0,
+      select: function( event, ui ) {console.log(jQuery(this));}
+    });
+});
+</script>
+{% endblock %}
+
diff --git a/portal/templates/fibre/fibre_supportview.html b/portal/templates/fibre/fibre_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 %}
+
diff --git a/portal/templates/fibre/fibre_termsview.html b/portal/templates/fibre/fibre_termsview.html
new file mode 100644 (file)
index 0000000..a82e2b1
--- /dev/null
@@ -0,0 +1,56 @@
+{% 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/>
+    Fibre: Future Internet testbeds experimentation between Brazil and Europe
+    <br/>
+</p>
+<h2 align="left">Context</h2>
+                                       <p align="left">
+                    The main goal of the FIBRE project is the design, implementation and validation of a shared Future Internet research facility, supporting the joint experimentation of European and Brazilian researchers. In order to achieve this goal the project will carry out four main activities:
+                    </p>
+                                       <p align="left">
+                    The development and operation of a new experimental facility in Brazil, including the setup of equipment to support experimentation with various technologies (fixed layer 2 and layer 3, wireless, optical) as well as the design and implementation of a control framework to automate the use and operation of the testbed.
+                    </p>
+                                       <p align="left">
+                    The development and operation of a Future Internet facility in Europe based on enhancements and the federation of two existing infrastructures: OFELIA and OneLab. Two OFELIA islands (i2CAT and University of Bristol (UNIVBRIS)) and the UTH's NITOS testbed will be enhanced by i) adding more physical resources (servers, OpenFlow-enabled switches and access points) to be able to cope with a bigger number ofusers and different use cases, ii) improving its respective control frameworks (based on the OFELIA control framework and OMF) and iii) adding more manpower to operate the facilities.
+                    </p>
+                                       <p align="left">
+                    The federation of the Brazilian and European experimental facilities, both at the physical connectivity and control framework level, to support the provisioning of slices using resources from both testbeds.
+                    </p>
+<h2>PROCEDURE OVERVIEW</h2>
+<p>If your institution is willing to join the FIBRE Consortium, you are kindly requested to follow the steps below:<br></p>
+<p>1. <a mce_href="http://www.fibre-ict.eu/images/stories/docs/fibre_mou_v0.3.doc" href="http://www.fibre-ict.eu/images/stories/docs/fibre_mou_v0.3.doc">Download the MoU model</a>  to understand the framework of collaboration between your institution and FIBRE project. The content of the MoU shall be discussed in case-by-case basis between the two parties.&nbsp;<span style="line-height: 1.3em;" mce_style="line-height: 1.3em;">&nbsp;</span></p>
+<p>2. Contact the Project office at <a href="mailto:info@fibre.org.br">info@fibre.org.br</a> to schedule a call to clarify all your questions concerning the duties, responsibilities and advantages of joining the FIBRE project.</p>
+<p>3. If your institution understand and agree on the commitment stated in the MoU, please submit the application by editing the <a href="http://www.fibre-ict.eu/images/fibre_mou_v0.2_ff.doc" mce_href="http://www.fibre-ict.eu/images/fibre_mou_v0.2_ff.doc" style="style" mce_style="style">MoU template</a> and sending it to 
+ <a href="mailto:info@fibre.org.br">info@fibre.org.br</a></p>
+<p>4. Application Approval: the FIBRE General Assembly will decide based on the application and information gathered during the call. The approval process will normally take around one month.</p><p>5. By mutual agreement of both parties, MoU will be prepared and signed.</p>
+<p><span style="line-height: 1.3em;" mce_style="line-height: 1.3em;">6. Testbed usage / island installation: FIBRE will provide instructions and support to help your institution to carry out the activities described in the MoU.</span></p>
+<p><br></p>
+<p><span style="line-height: 1.3em;" mce_style="line-height: 1.3em;"><a mce_href="http://webconf2.rnp.br/p27egdf20y7/" href="http://webconf2.rnp.br/p27egdf20y7/">Watch the webconference meeting about the MoU details</a><br> (Held on 5/July 2013, in Portuguese)<br></span></p>
+<p><br></p>
+<div>
+    <div>
+        <div id="_com_1">
+        </div>
+    </div>
+</div> 
+</div>
+</div>
+<div class="row">
+       <div class="col-md-12">
+
+</div>
+</div>
+{% endblock %}
+
diff --git a/portal/templates/fibre/fibre_user_register_complete.html b/portal/templates/fibre/fibre_user_register_complete.html
new file mode 100644 (file)
index 0000000..cc360eb
--- /dev/null
@@ -0,0 +1,20 @@
+{% extends "layout.html" %}
+
+{% block content %}
+
+<div class="row">
+       <h1><img src="{{ STATIC_URL }}img/icon_user_small.png" alt="User Registration" /> User sign-up</h1>
+</div>
+<div class="row">
+  <h3>Sign up information received.</h3>
+    <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.( Please verify your spam folder. )</li>
+       <li>2. A manager from the {{ REQINST }} will analize your request. (We have sent email to your organization's registered managers.)</li>
+  </ul>
+       <p></p>
+       <p></p>
+       <div><button type="button" class="btn btn-onelab" onclick="window.location.href='/'">Home</button></div>                
+</div>
+
+{% endblock %}
diff --git a/portal/templates/fibre/fibre_user_request_email.html b/portal/templates/fibre/fibre_user_request_email.html
new file mode 100644 (file)
index 0000000..8a6da3d
--- /dev/null
@@ -0,0 +1,19 @@
+<img src="https://146.164.47.246:27486/static/img/fibre-logo.gif" width="217" height="100">
+<br>
+<h1>NEW USER REQUEST</h1>
+<br>
+<p>You are receiving this request because we have you listed as a manager at an organization that uses Myslice portal.</p> 
+<p>If you believe that you have received this message in error, or if you have any questions, kindly contact support@fibre.org.br.</p>
+<br>
+<b>First name   :</b> {{first_name}}<br>
+<b>Last name    :</b> {{last_name}}<br>
+<b>Organization :</b> {{organization}}<br>
+<b>Authority hrn:</b> {{authority_hrn}}<br>
+<b>Public key   :</b> {{public_key}}<br>
+<b>Email        :</b> {{email}}<br>
+<b>User hrn     :</b> {{user_hrn}}<br>
+<b>Reasons for applying :</b> {{ reasons }}<br>
+<b>Portal url  :</b> {{ current_site }}<br>
+<p></p>
+<p>You can validate the user <a href="https://{{current_site}}/portal/validate">here</a>.<p>
+<p>Please note that the validation request will only become visible to you on the Myslice portal once the user has confirmed his/her email address.</p>
diff --git a/portal/templates/fibre/fibre_user_request_email.txt b/portal/templates/fibre/fibre_user_request_email.txt
new file mode 100644 (file)
index 0000000..e3a0418
--- /dev/null
@@ -0,0 +1,19 @@
+NEW USER REQUEST
+
+You are receiving this request because we have you listed as a manager at an organization that uses Myslice portal. 
+If you believe that you have received this message in error, or if you have any questions, kindly contact support@fibre.org.br.
+
+First name   : {{first_name}}
+Last name    : {{last_name}} 
+Organization :{{organization}}
+Authority hrn: {{authority_hrn}}
+Public key   : {{public_key}}
+Email        : {{email}}
+User hrn     : {{user_hrn}}
+Portal url   : {{ current_site }}
+
+You can validate the user here: https://{{current_site}}/portal/validate
+
+Please note that the validation request will only become visible to you on the Myslice portal once the user has confirmed his/her email address.
+
+
diff --git a/portal/templates/fibre/fibre_user_request_email_subject.txt b/portal/templates/fibre/fibre_user_request_email_subject.txt
new file mode 100644 (file)
index 0000000..a373b60
--- /dev/null
@@ -0,0 +1 @@
+User request submitted
diff --git a/portal/templates/fibre/fibre_widget-login-user.html b/portal/templates/fibre/fibre_widget-login-user.html
new file mode 100644 (file)
index 0000000..d7342f8
--- /dev/null
@@ -0,0 +1,26 @@
+<div class="login-form">
+       {% if state %}
+       <span class="help-block">{{ state }}</span>
+       {% endif %}
+       <form action="/login/" method="post" role="form">
+         {% csrf_token %}
+         {% if next %}
+         <input type="hidden" name="next" value="{{ next }}" />
+         {% endif %}
+       <div class="form-group">
+       <input type="email" name="username" placeholder="Enter Email / Username">
+       </div>
+       <div class="form-group">
+       <input type="password" name="password" placeholder="Password">
+       </div>
+       <div class="login-submit">
+               <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">
+               You don't have yet an account? 
+               
+               <a href="/portal/register">Sign Up!</a>
+       </div>
+       </form>
+</div>
diff --git a/portal/templates/fibre/fibre_widget-news.html b/portal/templates/fibre/fibre_widget-news.html
new file mode 100644 (file)
index 0000000..83cec76
--- /dev/null
@@ -0,0 +1,5 @@
+<div class="alert alert-info alert-dismissable">
+<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
+<span class="glyphicon glyphicon-globe"></span>
+The <b>OneLab</b> Portal opens with the <b>PlanetLab Europe</b>, <b>IOTLab</b> and <b>NITOS</b> testbeds!
+</div>
\ No newline at end of file
diff --git a/portal/templates/fibre/fibre_widget-slice-sections.html b/portal/templates/fibre/fibre_widget-slice-sections.html
new file mode 100644 (file)
index 0000000..01c8d82
--- /dev/null
@@ -0,0 +1,55 @@
+<div class="container">
+       <div class="row">
+               <div class="col-md-12">
+                        <div class="breadcrumbs">
+                                Experiment &nbsp;>&nbsp; {{ slice }}
+                        </div>
+               </div>
+       </div>
+</div>
+<div class="container-fluid container-slice">
+<div class="row">
+               <div class="col-md-12">
+{% if section == "resources" %}
+<ul class="nav nav-tabs nav-section">
+       <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">Tools</a></li>
+</ul>
+{% else %}
+<ul class="nav nav-tabs nav-section">
+       <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">Tools</a></li>
+</ul>
+
+<script>
+$(document).ready(function() {
+       $('.nav-tabs a').click(function (e) {
+               if ($(this).hasClass('link')) return;
+               e.preventDefault();
+               $(this).tab('show');
+       var id = $(this).attr('href').substr(1);        
+       $("#" + id).load('/' + id + '/{{ slice }}/');
+       });
+       
+       var hash = window.location.hash;
+       if (hash) {
+               $('.nav-tabs a[href='+hash+']').click();
+       } else {
+               $('div#info').load('/info/{{ slice }}/');
+       }
+});
+</script>
+{% endif %}
+</div>
+</div>
+</div>
\ No newline at end of file
index ddac594..d22bdeb 100644 (file)
                                }
                        );
                }
-       }
-       function on_click_reject() {
+     };
+     function showMore(buttonId, divId){
+          var element = document.getElementById(buttonId);
+          var div_element = document.getElementById(divId);
+          if (element.value === '(+)'){
+            element.value = '(-)';
+            $('#'+divId).slideDown('fast');
+          }
+          else {
+            element.value = '(+)';
+            $('#'+divId).slideUp('fast');
+          }
+          return false;
+     }
+        function on_click_reject() {
                var ids = []; 
                $('.portal__validate__checkbox').each(function(i, el) {
                        if ($(el).prop('checked')) {
         </thead>
         <tbody>
        {% for authority, requests in my_authorities.items %}
+       {% if authority == pi_authority or authority == "fibre" %}
+
+<!--
+       <div class="col-md-12">
+               <h2>{{authority}}</h2>
+               <table class="table">
+                             <th>
+                               <td>Type</td>
+                               <td>Id</td>
+                               <td>Details</td>
+                               <td>Timestamp</td>
+                               <td>Status</td>
+                             </th>
+                       {% for request in requests %} 
+                               <tr>
+                                       {% if request.object_auth == pi_authority %}
+                                               <td>
+                                               {% if request.allowed == 'allowed' %}
+                                               <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
+                                               {% else %}
+                                                       {% if request.allowed == 'expired' %}
+                                                               expired
+                                                       {% else %} {# denied #}
+                                                               denied
+                                                       {% endif %}
+                                               {% endif %}
+                                               </td>
+                                               <td>{{ request.type }}</td>
+                                               <td>{{ request.id }}</td>
+                                               <td>
+                                               {% if request.type == 'user' %}
+                                                       Login: {{request.login}} - First name: {{request.first_name}} - Last name: {{request.last_name}} - Email: {{request.email}}
+                                                       <input type = "button" id = "moreBtn_{{request.id}}" value = "(+)" onclick = "showMore('moreBtn_{{request.id}}','reasons_{{request.id}}')" style="color:blue; padding:0; border:none; background:none">
+                                                       <div id="reasons_{{request.id}}" style="display:none"> Reasons for Applying:<br> {{request.reasons}} </div> 
+                                               {% else %}
+                                               {% if request.type == 'slice' %}
+                                                               Slice name: {{request.slice_name}} - User_hrn: {{ request.user_hrn }} - Number of nodes: {{request.number_of_nodes}} - Type of nodes: {{request.type_of_nodes}} - Purpose: {{request.purpose}}
+                                                       {% else %} {# authority #}
+                                                               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 %}'> 
+                               {% endif %}
+                               </tr>
+                       {% endfor %}
+               </table>
+       </div>
+       {% endif %}
+-->
        
         {% for request in requests %}
         
                <td>
             {% if request.type == 'user' %}
                 <b>{{request.first_name}} {{request.last_name}}</b> &lt;<a href="mailto:{{request.email}}">{{request.email}}</a>&gt;
+                       <input type = "button" id = "moreBtn_{{request.id}}" value = "(+)" onclick = "showMore('moreBtn_{{request.id}}','reasons_{{request.id}}')" style="color:blue; padding:0; border:none; background:none">
+               <div id="reasons_{{request.id}}" style="display:none"> Reasons for Applying:<br> {{request.reasons}} </div> 
+
             {% elif request.type == 'slice' %}
             <b>{{request.slice_name}}</b> -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
             {% else %}
 {% if sub_authorities %}
        
        {% for authority, requests in sub_authorities.items %}
-       <div class="col-md-12">
-       <h3>{{authority}}</h3>
-           <table class="table">
-             <th>
-               <td>Type</td>
-               <td>Id</td>
-               <td>Details</td>
-               <td>Timestamp</td>
-               <td>Status</td>
-             </th>
-           {% for request in requests %}
-                 <tr>
-                       <td>
-                       {% if request.allowed == 'allowed' %}
-                       <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
-                       {% else %}
-                               {% if request.allowed == 'expired' %}
-                                       expired
-                               {% else %} {# denied #}
-                                       denied
+       {% if authority == pi_authority or authority == 'fibre'%}
+               <div class="col-md-12">
+               <h3>{{authority}}</h3>
+                   <table class="table">
+                     <th>
+                       <td>Type</td>
+                       <td>Id</td>
+                       <td>Details</td>
+                       <td>Timestamp</td>
+                       <td>Status</td>
+                     </th>
+                   {% for request in requests %}
+                         <tr>
+                               {% if request.object_auth == pi_authority %}
+                               <td>
+                               {% if request.allowed == 'allowed' %}
+                               <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
+                               {% else %}
+                                       {% if request.allowed == 'expired' %}
+                                               expired
+                                       {% else %} {# denied #}
+                                               denied
+                                       {% endif %}
                                {% endif %}
-                       {% endif %}
-                       </td>
-                       <td>{{ request.type }}</td>
-                       <td>{{ request.id }}</td>
-                       <td>
-               {% if request.type == 'user' %}
-               Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
-               {% else %}
-                   {% if request.type == 'slice' %}
-               Slice name: {{request.slice_name}} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
-                   {% else %} {# authority #}
-               Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
-                   {% endif %}
-               {% endif %}
-                       </td>
-                       <td>{{ request.timestamp }}</td>
-                       
-                       <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
-       
+                               </td>           
+                               <td>{{ request.type }}</td>
+                               <td>{{ request.id }}</td>
+                               <td>
+                       {% if request.type == 'user' %}
+                       Login: {{request.login}} -- First name: {{request.first_name}} -- Last name: {{request.last_name}} -- Email: {{request.email}}
+                       {% else %}
+                           {% if request.type == 'slice' %}
+                       Slice name: {{request.slice_name}} -- Number of nodes: {{request.number_of_nodes}} -- Type of nodes: {{request.type_of_nodes}} -- Purpose: {{request.purpose}}
+                           {% else %} {# authority #}
+                       Authority name: {{request.site_name}} -- authority_hrn: {{request.site_authority}} -- City: {{request.address_city}} -- Country: {{request.address_country}}
+                           {% endif %}
+                       {% endif %}
+                               </td>
+                               <td>{{ request.timestamp }}</td>
+                               
+                               <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
+               
            <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
-                 </tr>
-           {% endfor %}
-           </table>
-       </div>
+                       {% endif %}
+                         </tr>
+                   {% endfor %}
+                   </table>
+               </div>
+       {% endif %}
        {% endfor %}
 {% else %}
 <div class="col-md-12">
 {% if delegation_authorities %}
        
        {% for authority, requests in delegation_authorities.items %}
+       {% if authority == pi_authority  or authority == 'fibre'%}
        <div class="col-md-12">
                <h3>{{authority}}</h3>
                    <table class="table">
                      </th>
                    {% for request in requests %}
                          <tr>
+                               {% if request.object_auth == pi_authority %}
                                <td>
                                {% if request.allowed == 'allowed' %}
                                <input class='portal__validate__checkbox' id='portal__validate__checkbox__{{request.type}}__{{request.id}}' type='checkbox'/>
                       {% endif %}
                                </td>
                                <td>{{ request.timestamp }}</td>
-                               
+                       
                                <td><span id='portal__status__{{request.type}}__{{request.id}}'></span></td>
-               
-                   <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+       
+           <!--<div class='portal_validate_request {{request.type}} {% if forloop.counter|divisibleby:2 %}even{% else %}odd{% endif %}'> -->
+                       {% endif %}
                          </tr>
                    {% endfor %}
                    </table>
-               </div>
-               {% endfor %}
+       </div>
+       {% endif %}
+       {% endfor %}
 {% else %}
 <div class="col-md-12">
        <i>There is no pending request waiting for validation.</i>
index fdab352..2d9d53e 100644 (file)
@@ -39,7 +39,7 @@
 <body ng-app="ManifoldApp">
 {% block container %}
        {% block topmenu %}
-       {% include theme|add:"__widget-topmenu.html" %}
+       {% include theme|add:"_widget-topmenu.html" %}
        {% endblock topmenu %}
        {% include 'messages-transient.html' %}
        {% block base_content %}
index ef29d3d..3520359 100644 (file)
@@ -490,6 +490,9 @@ jQuery(document).ready(function(){
         {value:"",label:"No authority found !!!"}
     {% endif %}
     ];
+
+    console.log(availableTags);
+
        // sorting the list
        availableTags.sort(function(a,b){
                var nameA=a.value.toLowerCase(), nameB=b.value.toLowerCase();
index ff1fc3e..dcca68c 100644 (file)
@@ -111,7 +111,7 @@ $(document).ready(function() {
                 </div>
 
                                <div class="tab-pane" id="resourcescheduler">
-                       {{scheduler}}
+                    {{scheduler}}
                                </div>
        
                                <!--
index 82acd01..74fadeb 100644 (file)
@@ -4,7 +4,6 @@
 <link rel="stylesheet" href="{{ STATIC_URL }}css/jquery-ui.css">
 <script>
     function get_users_in_slice(authority_hrn){
-        console.log(authority_hrn);
         $("table#user-tab").html("<tr><th>+/-</th><th>Email</th><th>User hrn</th></tr>");
        var slice_users = [];
        var slice_users_removed = [];
                 $.each( data, function( key, val ) {
                     auth_hrn = val.authority_hrn;
                     // Keep only the sub authorities, remove root auth
-                    if(auth_hrn.indexOf(".") > -1){
+                    //if(auth_hrn.indexOf(".") > -1){
                         list_authorities.push(auth_hrn);
                                                list_authorities.sort();
                         if(auth_hrn=="{{user_details.parent_authority}}"){
                                                        $('#auth_list').val(auth_hrn);
                                                }
-                    }
+                    //}
                 });
                                $( "#auth_list" ).autocomplete({
                                source: list_authorities,
index a1295c1..bb2836f 100644 (file)
@@ -8,7 +8,7 @@
 {% block content %}
 
 <div class="row">
-       <h1><img src="{{ STATIC_URL }}img/icon_user_small.png" alt="User Registration" /> OneLab Experimenter Registration</h1>
+       <h1><img src="{{ STATIC_URL }}img/icon_user_small.png" alt="User Registration" /> FIBRE Experimenter Registration</h1>
 </div>
 <div class="row">
 
index b26ba0f..1047130 100644 (file)
@@ -262,6 +262,7 @@ class ValidatePendingView(LoginRequiredAutoLogoutView, ThemeView):
         context = super(ValidatePendingView, self).get_context_data(**kwargs)
         print "testing"
         print ctx_my_authorities
+       print auth_hrn
         context['my_authorities']   = ctx_my_authorities
         context['sub_authorities']   = ctx_sub_authorities
         context['delegation_authorities'] = ctx_delegation_authorities
diff --git a/ui/templates/base2.html b/ui/templates/base2.html
new file mode 100644 (file)
index 0000000..499ed88
--- /dev/null
@@ -0,0 +1,38 @@
+{# This is required by insert_above #}{% insert_handler %}<!DOCTYPE html>
+<html lang="en"><head>
+<title>FIBRE - {{ section }}</title>
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<link rel="shortcut icon" href="/static/img/myslice-icon.png">
+{# This is where insert_str will end up #}{% media_container prelude %}
+{% include 'messages-transient-header.html' %}
+<script type="text/javascript"> {# raw js code - use {% insert prelude_js %} ... {% endinsert %} #} {% container prelude_js %}</script>
+<script src="{{ STATIC_URL }}js/jquery.dataTables.min.js"></script>
+<script src="{{ STATIC_URL }}js/bootstrap.datatables.js"></script>
+<script src="{{ STATIC_URL }}js/myslice-ui.js"></script>
+<style type="text/css">{# In case we need to add raw css code #}{% container prelude_css %}</style>
+{{ header_prelude }}
+{% block head %} {% endblock head %}
+{# let's add these ones no matter what #}
+{% insert_str prelude "js/jquery.min.js" %}
+{% insert_str prelude "js/jquery.html5storage.min.js" %}
+{% insert_str prelude "js/messages-runtime.js" %}
+{% insert_str prelude "js/class.js" %}
+{% insert_str prelude "js/plugin-helper.js" %}
+{% insert_str prelude "js/mustache.js" %}
+{% insert_str prelude "js/plugin.js" %}
+{% insert_str prelude "js/manifold.js" %}
+{% insert_str prelude "css/manifold.css" %}
+{% insert_str prelude "css/plugin.css" %}
+<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/{{ theme }}.css">
+</head>
+<body>
+{% block container %}
+       {% block topmenu %}
+       {% include theme|add:"__widget-topmenu.html" %}
+       {% endblock topmenu %}
+       {% include 'messages-transient.html' %}
+       {% block base_content %}
+       {% endblock %}
+{% endblock container %}
+</body>
+</html>
diff --git a/unfold.sqlite3-110314 b/unfold.sqlite3-110314
new file mode 100644 (file)
index 0000000..b3018f1
Binary files /dev/null and b/unfold.sqlite3-110314 differ
diff --git a/unfold.sqlite3-130314 b/unfold.sqlite3-130314
new file mode 100644 (file)
index 0000000..0ccc69e
Binary files /dev/null and b/unfold.sqlite3-130314 differ
diff --git a/unfold.sqlite3-140314 b/unfold.sqlite3-140314
new file mode 100644 (file)
index 0000000..4e36199
Binary files /dev/null and b/unfold.sqlite3-140314 differ
diff --git a/unfold.sqlite3.old-120314 b/unfold.sqlite3.old-120314
new file mode 100644 (file)
index 0000000..815d818
Binary files /dev/null and b/unfold.sqlite3.old-120314 differ