--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
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'
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
# 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
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:
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>
--- /dev/null
+#!/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 "$@"
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
# 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
# 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)
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
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
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
# 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']
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)
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)
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
# '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
})
Requires: python-django
Requires: httpd
Requires: mod_wsgi
+# for c_rehash
+Requires: openssl-perl
BuildRequires: python-setuptools make
%description
# 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'
[manifold]
-url = http://localhost:7080
+url = https://localhost:7080
admin_user = admin
admin_password = admin
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
# 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
#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)
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', {})
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")
# 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):
-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):
-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):
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
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').\
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)
-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
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):
-webkit-border-radius: 7px;
border-radius: 7px;
}
+
+/* avoid blinking effect with the rhs hints */
+select#auth_list {
+ height: 34px;
+}
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>
<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>
<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 %}
{% 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>
<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>
+++ /dev/null
-# -*- 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
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
# 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):
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):
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()
# ** 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:
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/*')),
{{ 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 %}
</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 %}
<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 %}
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):
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):
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:
@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)
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):
-/* @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,
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 {
#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,
#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;
}
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;
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;
}
#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 {
}
.simplelist {
- font-size: 100%;
- text-align: center !important;
- margin: 0 auto;
+ font-size: 100%;
+ text-align: center !important;
+ margin: 0 auto;
}
-
-
-
-
-
-