Merge branch 'master' of ssh://git.onelab.eu/git/myslice
authorLoic Baron <loic.baron@lip6.fr>
Wed, 13 Nov 2013 05:29:26 +0000 (06:29 +0100)
committerLoic Baron <loic.baron@lip6.fr>
Wed, 13 Nov 2013 05:29:26 +0000 (06:29 +0100)
Conflicts:
unfold/page.py
unfold/static/css/onelab_marko.css

37 files changed:
Makefile
README
apache/myslice.conf
apache/unfold-init-ssl.sh [new file with mode: 0755]
auth/manifoldbackend.py
debian/control
manifold/manifoldapi.py
manifold/manifoldproxy.py
manifold/manifoldresult.py
manifold/metadata.py
myslice.spec
myslice/config.py
myslice/myslice.ini.localhost
portal/contactview.py
portal/dashboardview.py
portal/forms.py
portal/homeview.py
portal/platformsview.py
portal/platformview.py
portal/registrationview.py
portal/resourceview.py
portal/static/css/registration.css
portal/templates/contact.html
portal/templates/dashboard.html
portal/templates/registration_view.html
portal/templates/slice-request-view.html
portal/util.py [deleted file]
portal/views.py
setup.py
trash/templates/view-unfold2.html [moved from ui/templates/view-unfold2.html with 100% similarity]
ui/templates/base.html
ui/templates/layout-unfold2.html
ui/templates/widget-topmenu.html
ui/topmenu.py
unfold/loginrequired.py
unfold/page.py
unfold/static/css/onelab_marko.css

index 31ee234..9f3a563 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -28,6 +28,7 @@ install:
            --install-scripts=$(DESTDIR)/$(datadir)/unfold \
            --install-data=$(DESTDIR)/$(datadir)/unfold
 
+#################### third-party layout is managed as art of collectstatic
 static: force
        ./manage.py collectstatic --noinput
 
@@ -66,73 +67,6 @@ debian.clean:
        find . -name '*.pyc' -delete
 
 
-### #################### third-party layout is kind of special 
-### # because we have differents versions, and also we 
-### # try to preserve the file structure from upstream
-### # so let's handle this manually
-### THIRD-PARTY-RESOURCES =
-### # ignore variants, use the main symlink    third-party/bootstrap
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/bootstrap/*/*)
-### # just the single js as identified with a symlink
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/datatables/js/dataTables.js)
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/datatables/js/dataTables.bootstrap.js)
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/datatables/css/dataTables.bootstrap.css)
-### # likewise
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/jquery/js/jquery.js)
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/jquery/js/jquery.min.js)
-### # for storing the visible status of plugins
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/jquery-html5storage/jquery.html5storage.js)
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/jquery-html5storage/jquery.html5storage.min.js)
-### # creating queries uuids on the fly
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/uuid/Math.uuid.js)
-### # spin comes in plain or min, + the jquery plugin, and our own settings
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/spin/*.js)
-### # used in QueryCode
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/syntaxhighlighter/scripts/shCore.js)
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/syntaxhighlighter/scripts/shAutoloader.js)
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/syntaxhighlighter/scripts/shBrushPython.js)
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/syntaxhighlighter/scripts/shBrushRuby.js)
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/syntaxhighlighter/styles/shCore.css)
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/syntaxhighlighter/styles/shCoreDefault.css)
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/syntaxhighlighter/styles/shThemeDefault.css)
-### # wizard plugin
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/smartwizard-1636c86/js/jquery.smartWizard-2.0.js)
-### #THIRD-PARTY-RESOURCES += $(shell ls third-party/smartwizard-1636c86/js/jquery.smartWizard-2.0.min.js)
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/smartwizard-1636c86/styles/smart_wizard.css)
-### # jquery.notify
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/jquery-notify/jquery.notify.js)
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/jquery-notify/jquery.notify.min.js)
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/jquery-notify/ui.notify.css)
-### # CodeMirror
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/codemirror-3.15/lib/codemirror.js) 
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/codemirror-3.15/lib/codemirror.css) 
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/codemirror-3.15/mode/sql/sql.js)
-### # Mustache.js
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/mustache/mustache.js)
-### # markerclustererplus for the googlemap plugin
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/markerclusterer/markerclusterer.js)
-### THIRD-PARTY-RESOURCES += $(shell ls third-party/markerclusterer/markerclusterer_packed.js)
-### 
-### thirdparty-js:
-###    @find $(THIRD-PARTY-RESOURCES) -name '*.js'
-### thirdparty-css:
-###    @find $(THIRD-PARTY-RESOURCES) -name '*.css'
-### thirdparty-img:
-###    @find $(THIRD-PARTY-RESOURCES) -name '*.png' -o -name '*.ico'
-### 
-### # we might have any of these as templates - e.g. ./unfold/templates/plugin-init.js
-### # so if there's a /templates/ in the path ignore the file
-### local-js: force
-###    @find . -type f -name '*.js' | egrep -v '/all-(static|templates)/|/third-party/|/templates/'
-### local-css: force
-###    @find . -type f -name '*.css' | egrep -v 'all-(static|templates)/|/third-party/|/templates/'
-### local-img: force
-###    @find . -type f -name '*.png' -o -name '*.ico' | egrep -v 'all-(static|templates)/|/third-party/|/templates/'
-### 
-### list-js: thirdparty-js local-js
-### list-css: thirdparty-css local-css
-### list-img: thirdparty-img local-img
-
 # having templates in a templates/ subdir is fine most of the time except for plugins
 plugins-templates: force
        @find plugins -type f -name '*.html' 
@@ -167,14 +101,22 @@ tags: force
 ftags: force
        find . -type f | fgrep -v '/.git/' | xargs etags
 
-#################### sync : push current code on a (devel) box running myslice
+########################################
+### devel-oriented
+########################################
+
+#################### sync : push current code on a box running myslice
+# this for now targets deployments based on the debian packaging
 SSHURL:=root@$(MYSLICEBOX):/
 SSHCOMMAND:=ssh root@$(MYSLICEBOX)
 
 ### rsync options
 # the config file should probably not be overridden ??
 # --exclude settings.py 
-LOCAL_RSYNC_EXCLUDES   := --exclude '*.pyc' --exclude config.py --exclude static --exclude templates --exclude '*.sqlite3'  --exclude play/ 
+LOCAL_RSYNC_EXCLUDES   := --exclude '*.pyc'
+LOCAL_RSYNC_EXCLUDES   += --exclude '*.sqlite3' --exclude myslice.ini
+LOCAL_RSYNC_EXCLUDES   += --exclude static --exclude templates --exclude build
+LOCAL_RSYNC_EXCLUDES   += --exclude to-be-integrated --exclude third-party --exclude 'offline*'
 # usual excludes
 RSYNC_EXCLUDES         := --exclude .git --exclude '*~' --exclude TAGS --exclude .DS_Store $(LOCAL_RSYNC_EXCLUDES) 
 # make -n will propagate as rsync -n 
@@ -182,27 +124,39 @@ RSYNC_COND_DRY_RUN        := $(if $(findstring n,$(MAKEFLAGS)),--dry-run,)
 # putting it together
 RSYNC                  := rsync -a -v $(RSYNC_COND_DRY_RUN) $(RSYNC_EXCLUDES)
 
-##### convenience for development only, push code on a specific test box
+#################### minimal convenience for pushing work-in-progress in an apache-based depl.
 # xxx until we come up with a packaging this is going to be a wild guess
 # on debian04 I have stuff in /usr/share/myslice and a symlink in /root/myslice
-#INSTALLED=/usr/share/myslice
-INSTALLED=/root/myslice
+INSTALLED_MAIN         =/usr/share/unfold
+# this is for a debian box
+INSTALLED_APACHE       =/etc/apache2/sites-available/
+
+sync: sync-main sync-apache
+
+sync-main:
+ifeq (,$(MYSLICEBOX))
+       @echo "you need to set MYSLICEBOX, like in e.g."
+       @echo "  $(MAKE) MYSLICEBOX=debian04.pl.sophia.inria.fr "$@""
+       @exit 1
+else
+       +$(RSYNC) ./ $(SSHURL)/$(INSTALLED_MAIN)/
+endif
 
-sync:
+sync-apache:
 ifeq (,$(MYSLICEBOX))
        @echo "you need to set MYSLICEBOX, like in e.g."
        @echo "  $(MAKE) MYSLICEBOX=debian04.pl.sophia.inria.fr "$@""
        @exit 1
 else
-       +$(RSYNC) ./ $(SSHURL)/$(INSTALLED)/
+       +$(RSYNC) ./apache/myslice.conf $(SSHURL)/$(INSTALLED_APACHE)/
+       +$(RSYNC) ./apache/init-ssl.sh ./apache/init-ssl.py $(SSHURL)/$(bindir)/
 endif
 
-# xxx likewise until we run this under apache it's probably hard to restart from here
 restart:
 ifeq (,$(MYSLICEBOX))
        @echo "you need to set MYSLICEBOX, like in e.g."
        @echo "  $(MAKE) MYSLICEBOX=debian04.pl.sophia.inria.fr "$@""
        @exit 1
 else
-       @echo "$@" target not yet implemented - for an apache based depl it would read ...; exit; @$(SSHCOMMAND) /etc/init.d/apache2 restart
+       +$(SSHCOMMAND) apachectl restart
 endif
diff --git a/README b/README
index d05ded4..3a894cc 100644 (file)
--- a/README
+++ b/README
@@ -32,6 +32,16 @@ $ make static (which is a shorthand for cleaning up and run manage collectstatic
   that creates templates/ 
 $ make templates [$ make redo (each time when you pull, do that and restart the server)]
 
+
+## Whenever doing a git pull the following operations are recommended:
+
+$ make static # will refresh static/ from all the pieces in the project
+$ make templates # same, for templates
+$ make redo-static # clears up (rm -rf) static/ first, then make static
+$ make redo-templates # ditto for templates
+$ make redo == make redo-static redo-templates
+
+
 * run a local server:
 $ manage.py runserver 0.0.0.0:8000
 -- or -- my advice:
index b782452..b36a75e 100644 (file)
         Allow from all
         </Directory>
 </VirtualHost>
+
+# This port (not necessarily well picked) is configured 
+# with client-certificate required
+# corresponding trusted roots (e.g. ple.gid and plc.gid) should be 
+# configured in /etc/unfold/trusted_roots
+# check Jordan's email and pointer to trac, although we do not want 
+# this to be optional on that port
+
+<VirtualHost *:443>
+        WSGIScriptAlias / /usr/share/unfold/myslice/wsgi.py
+        <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>
+
+       SSLEngine on
+       SSLVerifyClient require
+       SSLVerifyDepth 5
+# make this a symlink to /etc/sfa/trusted_roots if that makes sense in your env.
+       SSLCACertificatePath /etc/unfold/trusted_roots
+# see init-ssl.sh for how to create self-signed stuff in here
+       SSLCertificateFile    /etc/unfold/myslice.cert
+       SSLCertificateKeyFile /etc/unfold/myslice.key
+
+#      SSLOptions +StdEnvVars +ExportCertData
+       SSLOptions +StdEnvVars
+</VirtualHost>
diff --git a/apache/unfold-init-ssl.sh b/apache/unfold-init-ssl.sh
new file mode 100755 (executable)
index 0000000..74c1c32
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/bash
+
+COMMAND=$(basename $0)
+
+# minimal script for initializing SSL material for myslice
+# you probably want to take care of this yourself instead,
+# but until somebody gets around to that apache will at least start up
+# 
+trusted_roots=/etc/unfold/trusted_roots
+key=/etc/unfold/myslice.key
+cert=/etc/unfold/myslice.cert
+
+if [[ -n "$@" ]] ; then hostname=$1; shift; else hostname=$(hostname); fi
+
+function init_trusted_roots () {
+    if [ ! -d $trusted_roots ] ; then
+       echo "Creating empty" $trusted_roots
+       mkdir -p $trusted_roots
+       echo "You will wish to populate that with e.g. ple.gid or the like"
+       echo "Make sure to re-run this command $COMMAND if you add gids"
+    fi
+    ### c_rehash will consider only files ending in .pem or .crt
+    # so, we create symlinks from *.gid to *.pem
+    pushd $trusted_roots >& /dev/null
+    for gid in *.gid; do
+       base=$(basename $gid .gid)
+       pem=$base.pem
+       [ -f $pem ] && ln -s $gid $pem 
+    done
+    ### invoke c_rehash 
+    # on debian c_rehash comes with openssl
+    # on fedora this is part of openssl-perl
+    echo -n "Invoking c_rehash in $(pwd) .. "; c_rehash .
+    popd  >& /dev/null
+}
+
+function init_server_cert () {
+    # both present : we have nothing to do
+    [ -f $key -a -f $cert ] && return
+    # exactly one present : we have a problem
+    [ -f $key -o -f $cert ] && { echo "server key or cert missing ?!?" ; return ; }
+    # create both
+    echo "Creating server key and cert for hostname ${hostname}"
+    openssl req -new -x509 -days 365 -set_serial $RANDOM -batch \
+       -subj "/CN=${hostname}" -nodes -keyout $key -out $cert
+}
+
+
+function main () {
+    init_trusted_roots
+    init_server_cert
+}
+
+main "$@"
index 14abb74..ab224a3 100644 (file)
@@ -47,7 +47,7 @@ class ManifoldBackend:
 
             request.session['manifold'] = {'auth': api.auth, 'person': person, 'expires': session['expires']}
         except ManifoldException, e:
-            print "Caught ManifoldException, returning corresponding ManifoldResult"
+            print "ManifoldBackend.authenticate caught ManifoldException, returning corresponding ManifoldResult"
             return e.manifold_result
         except Exception, e:
             print "E: manifoldbackend", e
index b3b54ac..207b30d 100644 (file)
@@ -13,5 +13,5 @@ Description: Myslice plugins, based on django and unfold frontend
 # Thierry: the recipe I'm using somehow only works with several packages
 Package: unfold
 Architecture: any
-Depends: python, python-django, python-pyparsing, apache2, libapache2-mod-wsgi
+Depends: python, python-django, python-pyparsing, apache2, libapache2-mod-wsgi, openssl
 Description: Generic django-based frontend for manifold backends
index 35fd3d7..1ffcace 100644 (file)
@@ -52,15 +52,28 @@ class ManifoldAPI:
     # a SESSION_EXPIRED code
     def __getattr__(self, methodName):
         def func(*args, **kwds):
+            # how to display a call
+            def repr ():
+                # most of the time, we run 'forward'
+                if methodName=='forward':
+                    try:    action="forward(%s)"%args[0]['action']
+                    except: action="forward(??)"
+                else: action=methodName
+                return action
             try:
                 if debug:
-                    print "====> ManifoldAPI.%s"%methodName,"auth",self.auth,"args",args,"kwds",kwds
-                result=getattr(self.server, methodName)(self.auth, *args, **kwds)
+                    print "====> ManifoldAPI.%s"%repr(),"url",self.url
+                    print "=> auth",self.auth
+                    print "=> args",args,"kwds",kwds
+                annotations = {
+                    'authentication': self.auth
+                }
+                args += (annotations,)
+                result=getattr(self.server, methodName)(*args, **kwds)
                 if debug:
-                    print '<==== backend call %s(*%s,**%s) returned'%(methodName,args,kwds),
-                    print '.ctd. Authmethod=',self.auth['AuthMethod'], self.url,'->',
+                    print '<= result=',
                     self._print_result(result)
-                    print '===== ManifoldAPI call done'
+                    print '<==== backend call %s returned'%(repr()),
 
                 return ResultValue(**result)
 
@@ -70,11 +83,12 @@ class ManifoldAPI:
                     raise ManifoldException ( ManifoldResult (code=ManifoldCode.SERVER_UNREACHABLE,
                                                               output="%s answered %s"%(self.url,error)))
                 # otherwise
-                print "====> ERROR On ManifoldAPI.%s"%methodName,"auth",self.auth,"args",args,"kwds",kwds
-                import traceback
-                traceback.print_exc()
-                if debug: print "KO (unexpected exception)",error
-                raise ManifoldException ( ManifoldResult (code=ManifoldCode.UNKNOWN_ERROR, output="%s"%error) )
+                if debug: 
+                    print "===== xmlrpc catch-all exception:",error
+                    import traceback
+                    traceback.print_exc(limit=3)
+                print "<==== ERROR On ManifoldAPI.%s"%repr()
+                raise ManifoldException ( ManifoldResult (code=ManifoldCode.SERVER_UNREACHABLE, output="%s"%error) )
 
         return func
 
index 6eb67c3..05486cb 100644 (file)
@@ -11,6 +11,7 @@ from manifold.core.result_value import ResultValue
 from manifold.manifoldapi       import ManifoldAPI
 from manifold.manifoldresult    import ManifoldException
 from manifold.util.log          import Log
+from myslice.config             import Config
 
 debug=False
 debug=True
@@ -24,7 +25,10 @@ debug_spin=0
 debug_empty=False
 #debug_empty=True
 
-# turn this on if you want the fastest possible (locally cached) feedback
+# Historically we had a feature for developing without an Internet connection
+# However this won't work anymore as the python layer itself does manifold calls
+# before javascript has a chance to do so.
+# Might still come in handy if you want the fastest possible (locally cached) feedback
 # beware that this is very rough though...
 work_offline=False
 #work_offline=True
@@ -59,9 +63,10 @@ with the query passed using POST"""
         # retrieve session for request
 
         # We allow some requests to use the ADMIN user account
-        if (manifold_query.get_from() == 'local:user' and manifold_query.get_action() == 'create') or (manifold_query.get_from() == 'local:platform' and manifold_query.get_action() == 'get'):
-            print "W: Used hardcoded demo account for admin queries"
-            manifold_api_session_auth = {'AuthMethod': 'password', 'Username': 'demo', 'AuthString': 'demo'}
+        if (manifold_query.get_from() == 'local:user' and manifold_query.get_action() == 'create') \
+                or (manifold_query.get_from() == 'local:platform' and manifold_query.get_action() == 'get'):
+            admin_user, admin_password = Config().manifold_admin_user_password()
+            manifold_api_session_auth = {'AuthMethod': 'password', 'Username': admin_user, 'AuthString': admin_password}
         else:
             manifold_api_session_auth = request.session['manifold']['auth']
 
@@ -92,7 +97,8 @@ with the query passed using POST"""
         result = manifold_api.forward(manifold_query.to_dict())
 
         # XXX TEMP HACK
-        if 'description' in result and result['description'] and isinstance(result['description'], (tuple, list, set, frozenset)):
+        if 'description' in result and result['description'] \
+                and isinstance(result['description'], (tuple, list, set, frozenset)):
             result [ 'description' ] = [ ResultValue.to_html (x) for x in result['description'] ]
 
         json_answer=json.dumps(result)
index dcf1a2e..4ffe072 100644 (file)
@@ -41,7 +41,7 @@ class ManifoldResult (dict):
 
     def __repr__ (self):
         code=self['code']
-        result="[[MFresult %s (code=%s)"%(_messages_.get(code,"???"),code)
+        result="[MFresult %s (code=%s)"%(_messages_.get(code,"???"),code)
         if code==0:
             value=self['value']
             if isinstance(value,list): result += " [value=list with %d elts]"%len(value)
@@ -49,7 +49,7 @@ class ManifoldResult (dict):
             else: result += " [value=%s: %s]"%(type(value).__name__,value)
         else:
             result += " [output=%s]"%self['output']
-        result += "]]"
+        result += "]"
         return result
 
 # probably simpler to use a single class and transport the whole result there
index 420821c..4fbbc06 100644 (file)
@@ -34,7 +34,8 @@ class MetaData:
         #          'column.resource_type', 'column.value_type',
         #          'column.allowed_values', 'column.platforms.platform',
         #          'column.platforms.platform_url']
-        result = manifold_api.Get({
+        result = manifold_api.forward({
+            'action': 'get',
             'object': 'local:object', # proposed to replace metadata:table
             'fields':     fields 
         })
index e0504ea..291ce6d 100644 (file)
@@ -21,6 +21,8 @@ Requires: python >= 2.7
 Requires: python-django
 Requires: httpd
 Requires: mod_wsgi
+# for c_rehash
+Requires: openssl-perl
 BuildRequires: python-setuptools make
 
 %description 
index 53295c4..04f4aaf 100644 (file)
@@ -18,10 +18,10 @@ class Config(object):
 
     # the OpenLab-wide backend as managed by UPMC
     # xxx production should probably use https of course
-    default_manifold_url = "http://test.myslice.info:7080/"
-    # the devel/unstable version runs on "http://dev.myslice.info:7080/"
+    default_manifold_url = "https://test.myslice.info:7080/"
+    # the devel/unstable version runs on "https://dev.myslice.info:7080/"
     # if you use a development backend running on this box, use "http://localhost:7080/"
-    # the INRIA setup is with "http://manifold.pl.sophia.inria.fr:7080/"
+    # the INRIA setup is with "https://manifold.pl.sophia.inria.fr:7080/"
 
     default_manifold_admin_user     = 'admin'
     default_manifold_admin_password = 'demo'
index c22836e..0467c0b 100644 (file)
@@ -1,4 +1,4 @@
 [manifold]
-url = http://localhost:7080
+url = https://localhost:7080
 admin_user = admin
 admin_password = admin
index c07f397..796c8b0 100644 (file)
@@ -3,6 +3,7 @@ from django.template.loader     import render_to_string
 from django.views.generic       import View
 from django.core.mail           import send_mail
 
+from unfold.loginrequired       import FreeAccessView
 from ui.topmenu                 import topmenu_items, the_user
 
 from portal.forms               import ContactForm
@@ -10,7 +11,7 @@ from portal.forms               import ContactForm
 # splitting the 2 functions done here
 # GET is for displaying the empty form
 # POST is to process it once filled - or show the form again if anything is missing
-class ContactView (View):
+class ContactView (FreeAccessView):
     def post (self, request):
         form = ContactForm(request.POST) # A form bound to the POST data
         if form.is_valid(): # All validation rules pass
index 91f4016..1cc12e0 100644 (file)
@@ -24,7 +24,7 @@ class DashboardView (LoginRequiredAutoLogoutView):
         #slice_query = Query().get('slice').filter_by('user.user_hrn', 'contains', user_hrn).select('slice_hrn')
         auth_query  = Query().get('network').select('network_hrn','platform')
         # DEMO GEC18 Query only PLE
-        slice_query = Query().get('ple:user').filter_by('user_hrn', '==', '$user_hrn').select('user_hrn', 'slice.slice_hrn')
+        slice_query = Query().get('user').filter_by('user_hrn', '==', '$user_hrn').select('user_hrn', 'slice.slice_hrn')
         page.enqueue_query(slice_query)
         page.enqueue_query(auth_query)
 
index 6a23e78..9bcf8fa 100644 (file)
@@ -64,27 +64,27 @@ class SliceRequestForm(forms.Form):
 
     slice_name = forms.CharField(
         widget=forms.TextInput(attrs={'class':'form-control'}), 
-        help_text="Enter a name for the slice you wish to create")
+        help_text="The name for the slice you wish to create")
     authority_hrn = forms.ChoiceField(
         widget    = forms.Select(attrs={'class':'form-control'}),
         choices   = [],
-        help_text = "Please select an authority responsible for vetting your slice")
+        help_text = "An authority responsible for vetting your slice")
     number_of_nodes = forms.DecimalField(
         widget    = forms.TextInput(attrs={'class':'form-control'}),
-        help_text = "Enter the number of nodes you expect to request (informative only)")
+        help_text = "The number of nodes you expect to request (informative)")
     type_of_nodes = forms.CharField(
         widget    = forms.TextInput(attrs={'class':'form-control'}),
-        help_text = "Enter the type of nodes you expect to request (informative only)")
+        help_text = "The type of nodes you expect to request (informative)")
     purpose = forms.CharField(
         widget    = forms.Textarea(attrs={'class':'form-control'}),
-        help_text = "Enter the purpose of your experiment (informative only)")
+        help_text = "The purpose of your experiment (informative)")
     email = forms.EmailField(
         widget    = forms.TextInput(attrs={'class':'form-control'}),
-        help_text = "Enter your email address")
+        help_text = "Your email address")
     cc_myself = forms.BooleanField(
         widget    = forms.CheckboxInput(attrs={'class':'form-control'}),
         required  = False,
-        help_text = "Please indicate whether you would like to be CC'ed to the request email")
+        help_text = "If you'd like to be cc'ed on the request email")
 
     def __init__(self, *args, **kwargs):
         initial =  kwargs.get('initial', {})
@@ -106,5 +106,5 @@ class SliceRequestForm(forms.Form):
             self.fields['authority_hrn'] = forms.ChoiceField(
                 widget    = forms.Select(attrs={'class':'form-control'}),
                 choices   = authority_hrn,
-                help_text = "Please select an authority responsible for vetting your slice")
+                help_text = "An authority responsible for vetting your slice")
     
index 960c8f0..b6af064 100644 (file)
@@ -1,16 +1,17 @@
 # this somehow is not used anymore - should it not be ?
-from django.views.generic import View
 from django.core.context_processors import csrf
 from django.http import HttpResponseRedirect
 from django.contrib.auth import authenticate, login, logout
 from django.template import RequestContext
 from django.shortcuts import render_to_response
 
+from unfold.loginrequired import FreeAccessView
+
 from manifold.manifoldresult import ManifoldResult
 from ui.topmenu import topmenu_items, the_user
 from myslice.config import Config
 
-class HomeView (View):
+class HomeView (FreeAccessView):
 
     # expose this so we can mention the backend URL on the welcome page
     def default_env (self):
index 0a1e9ad..0a6677e 100644 (file)
@@ -1,14 +1,13 @@
-from django.views.generic.base   import TemplateView
-
 from manifold.core.query         import Query
 from unfold.page                 import Page
 
+from unfold.loginrequired       import FreeAccessView
 from ui.topmenu                  import topmenu_items, the_user
 
 from plugins.hazelnut            import Hazelnut
 
 # View for platforms
-class PlatformsView(TemplateView):
+class PlatformsView(FreeAccessView):
     template_name = "platforms.html"
 
     def get_context_data(self, **kwargs):
index 4d133e1..69fd1b0 100644 (file)
@@ -1,14 +1,13 @@
-from django.views.generic.base   import TemplateView
-
 from manifold.core.query         import Query
 from unfold.page                 import Page
 
+from unfold.loginrequired        import FreeAccessView
 from ui.topmenu                  import topmenu_items, the_user
 
 from plugins.hazelnut            import Hazelnut
 
 # View for 1 platform and its details
-class PlatformView(TemplateView):
+class PlatformView(FreeAccessView):
     template_name = "platform.html"
 
     def get_context_data(self, **kwargs):
index 9ecba0d..e27dfb4 100644 (file)
@@ -8,6 +8,7 @@ from django.template.loader     import render_to_string
 from django.shortcuts           import render
 
 from unfold.page                import Page
+from unfold.loginrequired       import FreeAccessView
 from ui.topmenu                 import topmenu_items
 
 from manifold.manifoldapi       import execute_admin_query
@@ -16,17 +17,18 @@ from manifold.core.query        import Query
 from portal.models              import PendingUser
 from portal.actions             import authority_get_pi_emails 
 
-# This is a rough porting from views.py
-# the former function-based view is now made a class
-# we redefine dispatch as it is simple
-# and coincidentally works since we do not need LoginRequiredAutoLogoutView
-# a second stab should redefine post and get instead
-# also this was not thoroughly tested either, might miss some imports
-# to be continued...
+# since we inherit from FreeAccessView we cannot redefine 'dispatch'
+# so let's override 'get' and 'post' instead
+#
+class RegistrationView (FreeAccessView):
 
-class RegistrationView (View):
+    def post (self, request):
+        return self.get_or_post (request, 'POST')
 
-    def dispatch (self, request):
+    def get (self, request):
+        return self.get_or_post (request, 'GET')
+
+    def get_or_post  (self, request, method):
         errors = []
 
         #authorities_query = Query.get('authority').\
@@ -49,9 +51,9 @@ class RegistrationView (View):
         page.add_js_files  ( [ "js/jquery.validate.js", "js/my_account.register.js" ] )
         page.add_css_files ( [ "css/onelab.css", "css/registration.css" ] )
 
-        print 'registration view, method',request.method
+        print 'registration view, method',method
 
-        if request.method == 'POST':
+        if method == 'POST':
             # We shall use a form here
 
             #get_email = PendingUser.objects.get(email)
index 0ba8a26..c9fa5ba 100644 (file)
@@ -1,8 +1,7 @@
-from django.views.generic.base   import TemplateView
-
 from manifold.core.query         import Query
 from unfold.page                 import Page
 
+from unfold.loginrequired        import FreeAccessView
 from ui.topmenu                  import topmenu_items, the_user
 
 from plugins.googlemap           import GoogleMap
@@ -11,7 +10,7 @@ from plugins.lists.simplelist    import SimpleList
 from plugins.slicestat           import SliceStat
 
 # View for 1 platform and its details
-class ResourceView(TemplateView):
+class ResourceView(FreeAccessView):
     template_name = "resource.html"
 
     def get_context_data(self, **kwargs):
index 1a274a2..5fe8321 100644 (file)
@@ -29,3 +29,8 @@ div.form-group:hover p.form-hint {
     -webkit-border-radius: 7px;
     border-radius: 7px;
 }
+
+/* avoid blinking effect with the rhs hints */
+select#auth_list {
+    height: 34px;
+}
index 624fac3..8ffbf9c 100644 (file)
   or <a href="http://trac.myslice.info/" >visit us</a></h4>
 </div>
 
+<!-- no hint for this form, moreover we need more space to write stuff down
+     so we use a 3-6-3 layout -->
 <div class='well'>
   <form class="cmxform form-horizontal" id="commentForm" action="#" method="post" role="form">{% csrf_token %}
   <fieldset>
     {% for field in form %}
     <div class="form-group">
-      <label for="{{ field.html_name }}" class="col-xs-4 control-label">{{ field.label }}</label>
-      <div class="col-xs-4"> {{ field.errors }} {{ field }} <p class="form-hint">{{ field.help_text }}</p> </div>
+      <label for="{{ field.html_name }}" class="col-xs-3 control-label">{{ field.label }}</label>
+      <div class="col-xs-6"> {{ field.errors }} {{ field }} <p class="form-hint">{{ field.help_text }}</p> </div>
     </div>
     {% endfor %}
-    <button class="submit btn btn-default col-md-offset-4 col-xs-4" type="submit">Send to Support</button>
+    <button class="submit btn btn-default col-xs-12" type="submit">Send to Support</button>
   </fieldset>
   </form>
 </div>
index 56d4ab8..5ca062d 100644 (file)
@@ -17,7 +17,7 @@
        <div class='ms-dashboard-content'>
          <ul>
            {% if person.last_name %} <li><span id='username'>{{person.first_name}} {{person.last_name}}</span></li> {% endif %}
-           <li><b>Email: </b><a href='mailto:#'>{{person.email}}</a></li>
+           <li><b>Email: </b><a href='mailto:{{person.email}}'>{{person.email}}</a></li>
          </ul>
          <button id="account" onclick="location.href='/portal/account/'" class="btn btn-default">Modify</button>
        </div>
index 3d19def..b0bb389 100644 (file)
     <fieldset>
     {% csrf_token %}
     <div class="form-group">
-      <label for="firstname" class="col-xs-4 control-label">First Name</label>
+      <label for="firstname" class="col-xs-2 control-label">First Name</label>
       <div class="col-xs-4">
        <input type="text" name="firstname" class="form-control" minlength="2" value="{{ firstname }}" placeholder="First Name" required />
       </div>
-      <div class="col-xs-4"> <p class="form-hint">Enter your first name</p> </div>
+      <div class="col-xs-6"> <p class="form-hint">Enter your first name</p> </div>
     </div>
     <div class="form-group">
-      <label for="lastname" class="col-xs-4 control-label">Last Name</label>
+      <label for="lastname" class="col-xs-2 control-label">Last Name</label>
       <div class="col-xs-4">
        <input type="text" name="lastname" size="25" class="form-control" minlength="2" value="{{ lastname }}" placeholder="Last Name" required />
       </div>
-      <div class="col-xs-4"><p class="form-hint">Enter your last name</p></div>
+      <div class="col-xs-6"><p class="form-hint">Enter your last name</p></div>
     </div>
     <div class="form-group">
-      <label for="auth_list" class="col-xs-4 control-label">Authority</label>
+      <label for="auth_list" class="col-xs-2 control-label">Authority</label>
       <div class="col-xs-4">
        <select id="auth_list" name="authority_hrn" size="1" class="form-control" required>
          {% if authorities %}
@@ -47,7 +47,7 @@
          {% endif %}
        </select>
       </div>
-      <div class="col-xs-4"><p class="form-hint">Please select an authority responsible for vetting your account</p></div>
+      <div class="col-xs-6"><p class="form-hint">An authority responsible for vetting your account</p></div>
     </div>
 
        <!-- LOGIN
        user.
        -->
     <div class="form-group">
-      <label for="login" class="col-xs-4 control-label">Login</label>
+      <label for="login" class="col-xs-2 control-label">Login</label>
       <div class="col-xs-4">
          <input type="text" name="login" size="25" class="form-control" minlength="2" value="{{ login }}" placeholder="Login" required />
       </div>
-      <div class="col-xs-4"><p class="form-hint">Enter your login</p></div>
+      <div class="col-xs-6"><p class="form-hint">Enter your login</p></div>
     </div>
     
     <div class="form-group">
-      <label for="email" class="col-xs-4 control-label">Email</label>
+      <label for="email" class="col-xs-2 control-label">Email</label>
       <div class="col-xs-4">
        <input type="email" name="email" size="25"  class="form-control" value="{{ email }}" required/> 
       </div>
-      <div class="col-xs-4"><p class="form-hint">Enter a valid email address</p></div>
+      <div class="col-xs-6"><p class="form-hint">Enter a valid email address</p></div>
     </div>
     <div class="form-group">
-      <label for="password" class="col-xs-4 control-label">Password</label>
+      <label for="password" class="col-xs-2 control-label">Password</label>
       <div class="col-xs-4">
        <input type="password"  id="password" name="password"   class="form-control" minlength="4" value="{{ password }}" required/> 
       </div>
-      <div class="col-xs-4"><p class="form-hint">Enter password</p></div>
+      <div class="col-xs-6"><p class="form-hint">Enter password</p></div>
     </div>
     <div class="form-group">
-      <label for="password" class="col-xs-4 control-label">Confirm Password</label>
+      <label for="password" class="col-xs-2 control-label">Confirm Password</label>
       <div class="col-xs-4">
        <input type="password"  id="confirmpassword" name="confirmpassword"   minlength="4" class="form-control" 
               value="" placeholder="Confirm Password" required/>
       </div>
-      <div class="col-xs-4"><p class="form-hint">Retype the password</p></div>
+      <div class="col-xs-6"><p class="form-hint">Retype the password</p></div>
     </div>
     <div class="form-group">
-      <label for="question" class="col-xs-4 control-label">My Keys</label>
+      <label for="question" class="col-xs-2 control-label">My Keys</label>
       <div class="col-xs-4">
        <select name="question" class="form-control" id="key-policy" required>        
          <option value="generate">Generate key pairs for me </option>
          <option value="upload">Upload my public key </option>
        </select>
       </div>
-      <div class="col-xs-4"><p class="form-hint">Genkey: Account Delegation Automatic (Recommended)</p> </div>
+      <div class="col-xs-6"><p class="form-hint">Genkey: Account Delegation Automatic (Recommended)</p> </div>
     </div>
     <div class="form-group" style="display:none;" id="upload_key">
-      <label for="file" class="col-xs-4 control-label">Upload public key</label>
+      <label for="file" class="col-xs-2 control-label">Upload public key</label>
       <div class="col-xs-4">
        <input type="file" name="user_public_key" class="form-control" id="user_public_key" required/>
        <p class="warning" id="pkey_del_msg">Once your account is validated, you will have to delegate your credentials manually using SFA [Advanced users only]</p>
       </div>
-      <div class="col-xs-4"><p class="form-hint">Account Delegation: Manual (Advanced Users)</p></div>
+      <div class="col-xs-6"><p class="form-hint">Account Delegation: Manual (Advanced Users)</p></div>
     </div>
     <div class="form-group" id="register">
-      <button class="submit btn btn-default col-md-offset-4 col-xs-4" type="submit">Register</button>
+      <button class="submit btn btn-default col-xs-12" type="submit">Register</button>
     </div>
     </div>
   </fieldset>
index 3b3a01f..b9e0e22 100644 (file)
   <fieldset>
     {% for field in form %}
     <div class="form-group">
-      <label for="{{ field.html_name }}" class="col-xs-4 control-label">{{ field.label }}</label>
+      <label for="{{ field.html_name }}" class="col-xs-2 control-label">{{ field.label }}</label>
       <div class="col-xs-4"> {{ field.errors }} {{ field }} </div>
-      <div class="col-xs-4"> <p class="form-hint">{{ field.help_text }}</p> </div>
+      <div class="col-xs-6"> <p class="form-hint">{{ field.help_text }}</p> </div>
     </div>
     {% endfor %}
-    <button class="submit btn btn-default col-md-offset-4 col-xs-4" type="submit">Request Slice</button>
+    <button class="submit btn btn-default col-xs-12" type="submit">Request Slice</button>
   </fieldset>
   </form>
 </div>
diff --git a/portal/util.py b/portal/util.py
deleted file mode 100644 (file)
index 9a6239f..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# Code borrowed from the django-registration application
-# https://bitbucket.org/ubernostrum/django-registration
-
-from django.shortcuts import redirect
-from django.views.generic.edit import FormView
-from django.views.generic.base  import TemplateView
-
-class _RequestPassingFormView(FormView):
-    """
-    A version of FormView which passes extra arguments to certain
-    methods, notably passing the HTTP request nearly everywhere, to
-    enable finer-grained processing.
-    
-    """
-    def get(self, request, *args, **kwargs):
-        # Pass request to get_form_class and get_form for per-request
-        # form control.
-        form_class = self.get_form_class(request)
-        form = self.get_form(form_class)
-        return self.render_to_response(self.get_context_data(form=form))
-
-    def post(self, request, *args, **kwargs):
-        # Pass request to get_form_class and get_form for per-request
-        # form control.
-        form_class = self.get_form_class(request)
-        form = self.get_form(form_class)
-        if form.is_valid():
-            # Pass request to form_valid.
-            return self.form_valid(request, form)
-        else:
-            return self.form_invalid(form)
-
-    def get_form_class(self, request=None):
-        return super(_RequestPassingFormView, self).get_form_class()
-
-    def get_form_kwargs(self, request=None, form_class=None):
-        return super(_RequestPassingFormView, self).get_form_kwargs()
-
-    def get_initial(self, request=None):
-        return super(_RequestPassingFormView, self).get_initial()
-
-    def get_success_url(self, request=None, user=None):
-        # We need to be able to use the request and the new user when
-        # constructing success_url.
-        return super(_RequestPassingFormView, self).get_success_url()
-
-    def form_valid(self, form, request=None):
-        return super(_RequestPassingFormView, self).form_valid(form)
-
-    def form_invalid(self, form, request=None):
-        return super(_RequestPassingFormView, self).form_invalid(form)
-
-class RegistrationView(_RequestPassingFormView):
-    """
-    Base class for user registration views.
-    
-    """
-    disallowed_url = 'registration_disallowed'
-    #form_class =  RegistrationForm
-    http_method_names = ['get', 'post', 'head', 'options', 'trace']
-    success_url = None
-    template_name = 'user_register.html' #registration/registration_form.html'
-
-    def dispatch(self, request, *args, **kwargs):
-        """
-        Check that user signup is allowed before even bothering to
-        dispatch or do other processing.
-        
-        """
-        if not self.registration_allowed(request):
-            return redirect(self.disallowed_url)
-        return super(RegistrationView, self).dispatch(request, *args, **kwargs)
-
-    def form_valid(self, request, form):
-        new_user = self.register(request, **form.cleaned_data)
-        success_url = self.get_success_url(request, new_user)
-        
-        # success_url may be a simple string, or a tuple providing the
-        # full argument set for redirect(). Attempting to unpack it
-        # tells us which one it is.
-        try:
-            to, args, kwargs = success_url
-            return redirect(to, *args, **kwargs)
-        except ValueError:
-            return redirect(success_url)
-
-    def registration_allowed(self, request):
-        """
-        Override this to enable/disable user registration, either
-        globally or on a per-request basis.
-        
-        """
-        return True
-
-    def register(self, request, **cleaned_data):
-        """
-        Implement user-registration logic here. Access to both the
-        request and the full cleaned_data of the registration form is
-        available here.
-        
-        """
-        raise NotImplementedError
-
-class ActivationView(TemplateView):
-    """
-    Base class for user activation views.
-    
-    """
-    http_method_names = ['get']
-    template_name = 'registration/activate.html'
-
-    def get(self, request, *args, **kwargs):
-        activated_user = self.activate(request, *args, **kwargs)
-        if activated_user:
-            signals.user_activated.send(sender=self.__class__,
-                                        user=activated_user,
-                                        request=request)
-            success_url = self.get_success_url(request, activated_user)
-            try:
-                to, args, kwargs = success_url
-                return redirect(to, *args, **kwargs)
-            except ValueError:
-                return redirect(success_url)
-        return super(ActivationView, self).get(request, *args, **kwargs)
-
-    def activate(self, request, *args, **kwargs):
-        """
-        Implement account-activation logic here.
-        
-        """
-        raise NotImplementedError
-
-    def get_success_url(self, request, user):
-        raise NotImplementedError
-
-
-# DEPRECATED #def user_register(request):
-# DEPRECATED #    if request.method == 'POST':
-# DEPRECATED #        form = UserRegisterForm(request.POST)
-# DEPRECATED #        if form.is_valid():
-# DEPRECATED #            first_name = form.cleaned_data['first_name']
-# DEPRECATED #            last_name  = form.cleaned_data['last_name']
-# DEPRECATED #            email      = form.cleaned_data['email']
-# DEPRECATED #            password   = form.cleaned_data['password']
-# DEPRECATED #            password2  = form.cleaned_data['password2']
-# DEPRECATED #            keypair    = form.cleaned_data['keypair']
-# DEPRECATED #            ## Ici nous pouvons traiter les données du formulaire
-# DEPRECATED #            #sujet = form.cleaned_data['sujet']
-# DEPRECATED #            #message = form.cleaned_data['message']
-# DEPRECATED #            #envoyeur = form.cleaned_data['envoyeur']
-# DEPRECATED #            #renvoi = form.cleaned_data['renvoi']
-# DEPRECATED #            ## Nous pourrions ici envoyer l'e-mail grâce aux données que nous venons de récupérer
-# DEPRECATED #            #envoi = True
-# DEPRECATED #
-# DEPRECATED #            
-# DEPRECATED #    else:
-# DEPRECATED #        form = UserRegisterForm()
-# DEPRECATED #    return render(request, 'user_register.html', locals())
-# DEPRECATED #
-# DEPRECATED #def user_validate(request):
-# DEPRECATED #    pass
-# DEPRECATED #
-# DEPRECATED #def slice_request(request):
-# DEPRECATED #    if request.method == 'POST':
-# DEPRECATED #        form = SliceRequestForm(request.POST)
-# DEPRECATED #        if form.is_valid():
-# DEPRECATED #            slice_name = form.cleaned_data['slice_name']
-# DEPRECATED #    else:
-# DEPRECATED #        form = SliceRequestForm()
-# DEPRECATED #    return render(request, 'slice-request-view.html', locals())
-# DEPRECATED #
-# DEPRECATED #def slice_validate(request):
-# DEPRECATED #    pass
index da69220..167f324 100644 (file)
 import json
 
 from django.http                import HttpResponseRedirect, HttpResponse
-from django.views.generic.base  import TemplateView
 from django.shortcuts           import render
 from django.template.loader     import render_to_string
 
+from unfold.loginrequired       import FreeAccessView
 from ui.topmenu                 import topmenu_items, the_user
 
 from portal.event               import Event
@@ -49,7 +49,7 @@ from unfold.page                import Page
 # all the other ones have now migrated into separate classes/files for more convenience
 # I'm leaving these ones here for now as I could not exactly figure what the purpose was 
 # (i.e. what the correct name should be, as presviewview was a bit cryptic)
-class PresViewView(TemplateView):
+class PresViewView(FreeAccessView):
     template_name = "view-unfold1.html"
 
     def get_context_data(self, **kwargs):
@@ -222,7 +222,7 @@ def pres_view_static(request, constraints, id):
     json_answer = json.dumps(cmd)
     return HttpResponse (json_answer, mimetype="application/json")
 
-class ValidatePendingView(TemplateView):
+class ValidatePendingView(FreeAccessView):
     template_name = "validate_pending.html"
 
     def get_context_data(self, **kwargs):
@@ -272,7 +272,14 @@ class ValidatePendingView(TemplateView):
                 platform_ids.append(sfa_platform['platform_id'])
 
             print "W: Hardcoding platform myslice"
-            platform_ids.append(5);
+            # There has been a tweak on how new platforms are referencing a
+            # so-called 'myslice' platform for storing authentication tokens.
+            # XXX This has to be removed in final versions.
+            myslice_platforms_query = Query().get('local:platform').filter_by('platform', '==', 'myslice').select('platform_id')
+            myslice_platforms = execute_query(self.request, myslice_platforms_query)
+            if myslice_platforms:
+                myslice_platform, = myslice_platforms
+                platform_ids.append(myslice_platform['platform_id'])
 
             # We can check on which the user has authoritity credentials = PI rights
             credential_authorities = set()
@@ -313,7 +320,7 @@ class ValidatePendingView(TemplateView):
 
             # ** Where am I a PI **
             # For this we need to ask SFA (of all authorities) = PI function
-            pi_authorities_query = Query.get('ple:user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
+            pi_authorities_query = Query.get('user').filter_by('user_hrn', '==', '$user_hrn').select('pi_authorities')
             pi_authorities_tmp = execute_query(self.request, pi_authorities_query)
             pi_authorities = set()
             for pa in pi_authorities_tmp:
index 157641a..e902e32 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -13,7 +13,7 @@ from distutils.core import setup
 packages= [ os.path.dirname(init) for init in (glob("*/__init__.py")+glob("*/*/__init__.py")) ]
 
 setup(packages = packages,
-      scripts = [],
+      scripts = [ 'apache/unfold-init-ssl.sh' ],
       data_files = [ 
         ( 'static/js', glob ('static/js/*')),
         ( 'static/css', glob ('static/css/*')),
index 96c0420..b551df7 100644 (file)
@@ -11,7 +11,6 @@
 {{ header_prelude }}
 {% block head %} {% endblock head %}
 </head>{# let's add these ones no matter what #}
-{% insert_str prelude "css/layout-unfold2.css" %}
 {% 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/plugin.js" %}
 {% insert_str prelude "js/manifold.js" %}
 {% insert_str prelude "js/topmenu.js" %}
+{% insert_str prelude "css/layout-unfold2.css" %}
 {% insert_str prelude "css/manifold.css" %}
+{% insert_str prelude "css/plugin.css" %}
+{% insert_str prelude "css/onelab_marko.css" %}
 <body>
 {% block container %}
   {% block topmenu %}
index 954ce22..345f57f 100644 (file)
@@ -8,7 +8,7 @@
     </div><!--col-xs-9-->
     <div id='unfold2-margin' class='col-xs-3'>
       {% block unfold2_margin %}
-      "The related content area (define block 'related_main')"
+      "The related content area (define block 'unfold2_margin')"
       {% endblock unfold2_margin %}
     </div><!--col-xs-3-->
 {% endblock %}
index c465a84..dbcbe1f 100644 (file)
@@ -18,7 +18,7 @@
     <ul class="nav navbar-nav">
        {% for d in topmenu_items %} 
        {% if d.dropdown %}
-       <li class="other">
+       {% if d.is_active %} <li class='active'> {% else %} <li class='other'> {% endif %}
          <a class="dropdown-toggle" data-toggle="dropdown" href="{{ d.href }}">{{ d.label }}<b class="caret"></b></a>
          <ul class="dropdown-menu">
            {% for dd in d.contents %}
index e6250f0..3a94a21 100644 (file)
@@ -31,12 +31,14 @@ def topmenu_items (current,request=None):
     if current is not None:
         current=current.lower()
         curlen=len(current)
-        def mark_active(d):
-            if d['label'][:curlen].lower() == current: d['is_active']=True
+        def mark_active(d,up=None):
+            if d['label'][:curlen].lower() == current: 
+                d['is_active']=True
+                if up is not None: up['is_active']=True
         for d in result:
             mark_active(d)
             if 'dropdown' in d:
-                for dd in d['contents']: mark_active(dd)
+                for dd in d['contents']: mark_active(dd,d)
     return result
 
 def the_user (request):
index ebe33d5..92f9ddb 100644 (file)
@@ -6,6 +6,13 @@ from django.views.generic.base          import TemplateView
 
 from manifold.manifoldresult            import ManifoldException
 
+###
+# IMPORTANT NOTE
+# the implementation of the classes in this file rely on redefining 'dispatch'
+# for this reason if you inherit any of these, please do not redefine 'dispatch' yourself,
+# but rather redefine 'get' and 'post' instead
+###
+
 ########## the base class for views that require a login
 class LoginRequiredView (TemplateView):
 
@@ -26,7 +33,7 @@ class LoginRequiredView (TemplateView):
 
 def logout_on_manifold_exception (fun_that_returns_httpresponse):
     def wrapped (request, *args, **kwds):
-        print 'wrapped by logout_on_manifold_exception'
+#        print 'wrapped by logout_on_manifold_exception'
         try:
             return fun_that_returns_httpresponse(request,*args, **kwds)
         except ManifoldException, manifold_result:
@@ -53,3 +60,11 @@ class LoginRequiredAutoLogoutView (TemplateView):
     @method_decorator(login_required)
     def dispatch (self, request, *args, **kwds):
         return super(LoginRequiredAutoLogoutView,self).dispatch(request,*args,**kwds)
+
+# we have more and more views that actually send manifold queries
+# so for these we need to protect against manifold exceptions
+# even though login is not required
+class FreeAccessView (TemplateView):
+
+    def dispatch (self, request, *args, **kwds):
+        return super(FreeAccessView,self).dispatch(request,*args,**kwds)
index 024bd44..7c6d60b 100644 (file)
@@ -36,6 +36,7 @@ class Page:
         self.prelude=Prelude(css_files='css/plugin.css')
         print "Loading... CSS OneLab"
         self.prelude=Prelude(css_files='css/onelab_marko.css')
+#        self.prelude=Prelude(css_files=['css/plugin.css','css/onelab_marko.css',])
 
     # record known plugins hashed on their domid
     def record_plugin (self, plugin):
index 7cab5e0..ab82706 100644 (file)
@@ -1,8 +1,4 @@
-/* @override 
-       http://test.myslice.info/static/css/plugin.css
-*/
-
-
+/* @override unfold/static/css/plugin.css */
 
 /*-------------------------------- MARKO'S STYLES -----*/
 
     height: 100%;
 }
 
-.container h1 {
-       color: #fff !important;
-       font-family: Ubuntu;
-       margin-top: 60px;
+.container h1, .container h2 {
+    color: #fff !important;
 }
 
 div.plugin-outline-complete, 
@@ -71,20 +65,20 @@ div.well {
     background-color: rgba(0, 0, 0, 0.5) !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; */
+    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;
+    margin-bottom: 0px;
+    margin-top: 0;
+    padding: 40px;
+    opacity: 1;
+    text-align: center;
+    background-color: #30196d;
 }
 
 #complete-resources {
@@ -127,9 +121,9 @@ h2.well.well-lg {
 #complete-pending,
 #complete-customize-resources,
 #complete-msgs-pre {
-       opacity: 1;
-       text-align: center;
-       color: #333;
+    opacity: 1;
+    text-align: center;
+    color: #333;
 }
 
 #complete-resources:hover, 
@@ -139,34 +133,34 @@ h2.well.well-lg {
 #complete-pending:hover,
 #complete-customize-resources:hover,
 #complete-msgs-pre:hover {
-       opacity: 1;
+    opacity: 1;
 }
 
 .nav.nav-tabs {
-       font-family: Ubuntu, Arial, sans-serif;
-       border: 0 !important;
-       border-bottom: 3px solid #fff !important;
-       margin-bottom: 40px;
+    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;
+    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;
+    color: #333;
+    border: 0 !important;
+    margin-right: 5px;
 }
 
 .nav.nav-tabs li a:hover {
-       color: #333;
-       background: #572bc9;
-       color: #fff;
-       border: 0 !important;
+    color: #333;
+    background: #572bc9;
+    color: #fff;
+    border: 0 !important;
 }
 
 
@@ -182,34 +176,39 @@ body {
     padding-bottom: 0px;
 }
 
+/* Thierry : turning this off
 div.topmenu { 
-       padding-top: 0px;
-       font-family: Ubuntu, Arial, sans-serif;
-       font-weight: bold;
-       /* text-transform: ; */
-       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);
+    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;
+    padding-top: 25px;
+    padding-bottom: 20px;
 }
+Thierry */
 
 .navbar-nav li a:hover {
-       color: #572bc9 !important;
+    color: #572bc9 !important;
 }
 
 .navbar-nav li.active a {
-       background: #eee !important;
+    background: #eee !important;
 }
 
+/* Thierry : turning this off
 ul.logged-in { 
     padding-top: 25px; 
 }
+Thierry */
 button.logged-in { 
     font-size: 1em;
     font-weight: bold; 
@@ -241,44 +240,44 @@ li.username {
 
 
 ul.pagination li a {
-       /* background: ; */
-       color: #572bc9;
-       font-family: Ubuntu, Arial, sans-serif;
+    /* background: ; */
+    color: #572bc9;
+    font-family: Ubuntu, Arial, sans-serif;
 }
 
 ul.pagination li.active a {
-       background: #572bc9;
-       border: 1px solid #572bc9;
+    background: #572bc9;
+    border: 1px solid #572bc9;
 }
 
 .btn.btn-default {
-       background: #572bc9;
-       color: #ccc;
-       font-family: Ubuntu, Arial, sans-serif;
-       font-weight: bold;
-       border: 0px;
+    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;
+    /* 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;
+    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;
+    font-family: Ubuntu, Arial, sans-serif !important;
 }
 
 
@@ -345,59 +344,59 @@ table.query-editor td {
 #ms-dashboard-profile,
 #ms-dashboard-testbeds,
 #ms-dashboard-slices {
-       -webkit-transition: all 50ms ease-out;
+    -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;
+    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;
+    margin-top: 65px;
 }
 
 #ms-dashboard-profile {
-       background: url("../img/icon_users_color.png") top center no-repeat;
+    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;
+    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;
+    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;
+    list-style-type: none !important;
+    padding-left: 0;
+    text-align: center !important;
 }
 
 .ms-dashboard-content {
-       padding: 0 !important;
+    padding: 0 !important;
 }
 
 .ms-dashboard-content a {
-       color: #ff7394 !important;
-       /* color: #ff0099 !important; */
+    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;
+    font-family: Ubuntu, Arial, sans-serif;
+    border-bottom: 0 !important;
+    text-transform: uppercase;
 }
 
 #ms-dashboard-profile>div.ms-dashboard-caption {
@@ -416,13 +415,7 @@ table.query-editor td {
 }   
 
 .simplelist {
-       font-size: 100%;
-       text-align: center !important;
-       margin: 0 auto;
+    font-size: 100%;
+    text-align: center !important;
+    margin: 0 auto;
 }
-
-
-
-
-
-