From: Loic Baron Date: Wed, 13 Nov 2013 05:29:26 +0000 (+0100) Subject: Merge branch 'master' of ssh://git.onelab.eu/git/myslice X-Git-Tag: myslice-0.3-0~113^2~9 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=e6184193b74ac6d5c52289546dae9121bdd99008;hp=3167207804460a2c42e1e5a8346c597f9832d295;p=unfold.git Merge branch 'master' of ssh://git.onelab.eu/git/myslice Conflicts: unfold/page.py unfold/static/css/onelab_marko.css --- diff --git a/Makefile b/Makefile index 31ee234b..9f3a563b 100644 --- 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 d05ded49..3a894cc0 100644 --- 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: diff --git a/apache/myslice.conf b/apache/myslice.conf index b7824520..b36a75ec 100644 --- a/apache/myslice.conf +++ b/apache/myslice.conf @@ -12,3 +12,37 @@ Allow from all + +# 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 + + + WSGIScriptAlias / /usr/share/unfold/myslice/wsgi.py + + + Order deny,allow + Allow from all + + + Alias /static/ /usr/share/unfold/static/ + + Order deny,allow + Allow from all + + + 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 + diff --git a/apache/unfold-init-ssl.sh b/apache/unfold-init-ssl.sh new file mode 100755 index 00000000..74c1c32a --- /dev/null +++ b/apache/unfold-init-ssl.sh @@ -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 "$@" diff --git a/auth/manifoldbackend.py b/auth/manifoldbackend.py index 14abb748..ab224a35 100644 --- a/auth/manifoldbackend.py +++ b/auth/manifoldbackend.py @@ -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 diff --git a/debian/control b/debian/control index b3b54ace..207b30dc 100644 --- a/debian/control +++ b/debian/control @@ -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 diff --git a/manifold/manifoldapi.py b/manifold/manifoldapi.py index 35fd3d74..1ffcacee 100644 --- a/manifold/manifoldapi.py +++ b/manifold/manifoldapi.py @@ -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 diff --git a/manifold/manifoldproxy.py b/manifold/manifoldproxy.py index 6eb67c3a..05486cba 100644 --- a/manifold/manifoldproxy.py +++ b/manifold/manifoldproxy.py @@ -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) diff --git a/manifold/manifoldresult.py b/manifold/manifoldresult.py index dcf1a2e8..4ffe072b 100644 --- a/manifold/manifoldresult.py +++ b/manifold/manifoldresult.py @@ -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 diff --git a/manifold/metadata.py b/manifold/metadata.py index 420821c8..4fbbc066 100644 --- a/manifold/metadata.py +++ b/manifold/metadata.py @@ -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 }) diff --git a/myslice.spec b/myslice.spec index e0504ea4..291ce6d4 100644 --- a/myslice.spec +++ b/myslice.spec @@ -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 diff --git a/myslice/config.py b/myslice/config.py index 53295c4a..04f4aaf8 100644 --- a/myslice/config.py +++ b/myslice/config.py @@ -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' diff --git a/myslice/myslice.ini.localhost b/myslice/myslice.ini.localhost index c22836e9..0467c0ba 100644 --- a/myslice/myslice.ini.localhost +++ b/myslice/myslice.ini.localhost @@ -1,4 +1,4 @@ [manifold] -url = http://localhost:7080 +url = https://localhost:7080 admin_user = admin admin_password = admin diff --git a/portal/contactview.py b/portal/contactview.py index c07f3977..796c8b04 100644 --- a/portal/contactview.py +++ b/portal/contactview.py @@ -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 diff --git a/portal/dashboardview.py b/portal/dashboardview.py index 91f4016a..1cc12e0e 100644 --- a/portal/dashboardview.py +++ b/portal/dashboardview.py @@ -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) diff --git a/portal/forms.py b/portal/forms.py index 6a23e784..9bcf8fa6 100644 --- a/portal/forms.py +++ b/portal/forms.py @@ -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") diff --git a/portal/homeview.py b/portal/homeview.py index 960c8f0d..b6af0644 100644 --- a/portal/homeview.py +++ b/portal/homeview.py @@ -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): diff --git a/portal/platformsview.py b/portal/platformsview.py index 0a1e9ad3..0a6677e3 100644 --- a/portal/platformsview.py +++ b/portal/platformsview.py @@ -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): diff --git a/portal/platformview.py b/portal/platformview.py index 4d133e1d..69fd1b02 100644 --- a/portal/platformview.py +++ b/portal/platformview.py @@ -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): diff --git a/portal/registrationview.py b/portal/registrationview.py index 9ecba0dc..e27dfb4d 100644 --- a/portal/registrationview.py +++ b/portal/registrationview.py @@ -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) diff --git a/portal/resourceview.py b/portal/resourceview.py index 0ba8a26c..c9fa5ba8 100644 --- a/portal/resourceview.py +++ b/portal/resourceview.py @@ -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): diff --git a/portal/static/css/registration.css b/portal/static/css/registration.css index 1a274a24..5fe83215 100644 --- a/portal/static/css/registration.css +++ b/portal/static/css/registration.css @@ -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; +} diff --git a/portal/templates/contact.html b/portal/templates/contact.html index 624fac30..8ffbf9c9 100644 --- a/portal/templates/contact.html +++ b/portal/templates/contact.html @@ -13,16 +13,18 @@ or visit us +
{% csrf_token %}
{% for field in form %}
- -
{{ field.errors }} {{ field }}

{{ field.help_text }}

+ +
{{ field.errors }} {{ field }}

{{ field.help_text }}

{% endfor %} - +
diff --git a/portal/templates/dashboard.html b/portal/templates/dashboard.html index 56d4ab8d..5ca062db 100644 --- a/portal/templates/dashboard.html +++ b/portal/templates/dashboard.html @@ -17,7 +17,7 @@
diff --git a/portal/templates/registration_view.html b/portal/templates/registration_view.html index 3d19def7..b0bb3896 100644 --- a/portal/templates/registration_view.html +++ b/portal/templates/registration_view.html @@ -20,21 +20,21 @@
{% csrf_token %}
- +
-

Enter your first name

+

Enter your first name

- +
-

Enter your last name

+

Enter your last name

- +
-

Please select an authority responsible for vetting your account

+

An authority responsible for vetting your account

- +
-

Enter your login

+

Enter your login

- +
-

Enter a valid email address

+

Enter a valid email address

- +
-

Enter password

+

Enter password

- +
-

Retype the password

+

Retype the password

- +
-

Genkey: Account Delegation Automatic (Recommended)

+

Genkey: Account Delegation Automatic (Recommended)

- +
diff --git a/portal/templates/slice-request-view.html b/portal/templates/slice-request-view.html index 3b3a01ff..b9e0e22d 100644 --- a/portal/templates/slice-request-view.html +++ b/portal/templates/slice-request-view.html @@ -20,12 +20,12 @@
{% for field in form %}
- +
{{ field.errors }} {{ field }}
-

{{ field.help_text }}

+

{{ field.help_text }}

{% endfor %} - +
diff --git a/portal/util.py b/portal/util.py deleted file mode 100644 index 9a6239f8..00000000 --- a/portal/util.py +++ /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 diff --git a/portal/views.py b/portal/views.py index da692206..167f324e 100644 --- a/portal/views.py +++ b/portal/views.py @@ -24,10 +24,10 @@ 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: diff --git a/setup.py b/setup.py index 157641a9..e902e32f 100644 --- 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/*')), diff --git a/ui/templates/view-unfold2.html b/trash/templates/view-unfold2.html similarity index 100% rename from ui/templates/view-unfold2.html rename to trash/templates/view-unfold2.html diff --git a/ui/templates/base.html b/ui/templates/base.html index 96c04209..b551df76 100644 --- a/ui/templates/base.html +++ b/ui/templates/base.html @@ -11,7 +11,6 @@ {{ header_prelude }} {% block head %} {% endblock 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" %} @@ -21,7 +20,10 @@ {% 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" %} {% block container %} {% block topmenu %} diff --git a/ui/templates/layout-unfold2.html b/ui/templates/layout-unfold2.html index 954ce22d..345f57f2 100644 --- a/ui/templates/layout-unfold2.html +++ b/ui/templates/layout-unfold2.html @@ -8,7 +8,7 @@
{% block unfold2_margin %} - "The related content area (define block 'related_main')" + "The related content area (define block 'unfold2_margin')" {% endblock unfold2_margin %}
{% endblock %} diff --git a/ui/templates/widget-topmenu.html b/ui/templates/widget-topmenu.html index c465a849..dbcbe1fc 100644 --- a/ui/templates/widget-topmenu.html +++ b/ui/templates/widget-topmenu.html @@ -18,7 +18,7 @@