From bc481e954c2c6e1da9bbee630ee37325bad7c8d1 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Thu, 2 May 2013 20:32:21 -0500 Subject: [PATCH] something went wrong with VCS, trying fix it --- VERSION | 2 +- .../admin/static/js/web2py_bootstrap.j | 35 +++ .../examples/static/js/web2py_bootstrap.j | 35 +++ gluon/dal.py | 14 +- gluon/validators.py | 9 +- scripts/setup-web2py-nginx-uwsgi-opensuse.sh | 226 ++++++++++++++++++ 6 files changed, 315 insertions(+), 6 deletions(-) create mode 100644 applications/admin/static/js/web2py_bootstrap.j create mode 100644 applications/examples/static/js/web2py_bootstrap.j create mode 100644 scripts/setup-web2py-nginx-uwsgi-opensuse.sh diff --git a/VERSION b/VERSION index 4abd817f..4928b86a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.4.6-stable+timestamp.2013.04.28.23.09.04 +Version 2.4.6-stable+timestamp.2013.05.02.20.31.34 diff --git a/applications/admin/static/js/web2py_bootstrap.j b/applications/admin/static/js/web2py_bootstrap.j new file mode 100644 index 00000000..0c94fd98 --- /dev/null +++ b/applications/admin/static/js/web2py_bootstrap.j @@ -0,0 +1,35 @@ +// this code improves bootstrap menus and adds dropdown support +jQuery(function(){ + jQuery('.nav>li>a').each(function(){ + if(jQuery(this).parent().find('ul').length) + jQuery(this).attr({'class':'dropdown-toggle','data-toggle':'dropdown'}).append(''); + }); + jQuery('.nav li li').each(function(){ + if(jQuery(this).find('ul').length) + jQuery(this).addClass('dropdown-submenu'); + }); + function adjust_height_of_collapsed_nav() { + var cn = jQuery('div.collapse'); + if (cn.get(0)) { + var cnh = cn.get(0).style.height; + if (cnh>'0px'){ + cn.css('height','auto'); + } + } + } + function hoverMenu(){ + jQuery('ul.nav a.dropdown-toggle').parent().hover(function(){ + adjust_height_of_collapsed_nav(); + mi = jQuery(this).addClass('open'); + mi.children('.dropdown-menu').stop(true, true).delay(200).fadeIn(400); + }, function(){ + mi = jQuery(this); + mi.children('.dropdown-menu').stop(true, true).delay(200).fadeOut(function(){mi.removeClass('open')}); + }); + } + hoverMenu(); // first page load + jQuery(window).resize(hoverMenu); // on resize event + jQuery('ul.nav li.dropdown a').click(function(){window.location=jQuery(this).attr('href');}); + // make all buttons bootstrap buttons + jQuery('button, form input[type="submit"], form input[type="button"]').addClass('btn'); +}); \ No newline at end of file diff --git a/applications/examples/static/js/web2py_bootstrap.j b/applications/examples/static/js/web2py_bootstrap.j new file mode 100644 index 00000000..0c94fd98 --- /dev/null +++ b/applications/examples/static/js/web2py_bootstrap.j @@ -0,0 +1,35 @@ +// this code improves bootstrap menus and adds dropdown support +jQuery(function(){ + jQuery('.nav>li>a').each(function(){ + if(jQuery(this).parent().find('ul').length) + jQuery(this).attr({'class':'dropdown-toggle','data-toggle':'dropdown'}).append(''); + }); + jQuery('.nav li li').each(function(){ + if(jQuery(this).find('ul').length) + jQuery(this).addClass('dropdown-submenu'); + }); + function adjust_height_of_collapsed_nav() { + var cn = jQuery('div.collapse'); + if (cn.get(0)) { + var cnh = cn.get(0).style.height; + if (cnh>'0px'){ + cn.css('height','auto'); + } + } + } + function hoverMenu(){ + jQuery('ul.nav a.dropdown-toggle').parent().hover(function(){ + adjust_height_of_collapsed_nav(); + mi = jQuery(this).addClass('open'); + mi.children('.dropdown-menu').stop(true, true).delay(200).fadeIn(400); + }, function(){ + mi = jQuery(this); + mi.children('.dropdown-menu').stop(true, true).delay(200).fadeOut(function(){mi.removeClass('open')}); + }); + } + hoverMenu(); // first page load + jQuery(window).resize(hoverMenu); // on resize event + jQuery('ul.nav li.dropdown a').click(function(){window.location=jQuery(this).attr('href');}); + // make all buttons bootstrap buttons + jQuery('button, form input[type="submit"], form input[type="button"]').addClass('btn'); +}); \ No newline at end of file diff --git a/gluon/dal.py b/gluon/dal.py index 42019a0c..82ef739b 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -4719,12 +4719,17 @@ class GoogleDatastoreAdapter(NoSQLAdapter): "text and blob field types not allowed in projection queries") else: projection.append(f.name) + elif args_get('filterfields') == True: + projection = [] + for f in fields: + projection.append(f.name) - # projection's can't include 'id'. + # real projection's can't include 'id'. # it will be added to the result later query_projection = [ p for p in projection if \ - p != db[tablename]._id.name] if projection \ + p != db[tablename]._id.name] if projection and \ + args_get('projection') == True\ else None cursor = None @@ -4802,6 +4807,11 @@ class GoogleDatastoreAdapter(NoSQLAdapter): what is accepted imposed by GAE: each field must be indexed, projection queries cannot contain blob or text fields, and you cannot use == and also select that same field. see https://developers.google.com/appengine/docs/python/datastore/queries#Query_Projection + - optional attribute 'filterfields' when set to True web2py will only + parse the explicitly listed fields into the Rows object, even though + all fields are returned in the query. This can be used to reduce + memory usage in cases where true projection queries are not + usable. - optional attribute 'reusecursor' allows use of cursor with queries that have the limitby attribute. Set the attribute to True for the first query, set it to the value of db['_lastcursor'] to continue diff --git a/gluon/validators.py b/gluon/validators.py index b3007de6..10372728 100644 --- a/gluon/validators.py +++ b/gluon/validators.py @@ -706,17 +706,20 @@ class IS_INT_IN_RANGE(Validator): self.minimum = self.maximum = None if minimum is None: if maximum is None: - self.error_message = error_message or 'enter an integer' + self.error_message = translate( + error_message or 'enter an integer') else: self.maximum = int(maximum) if error_message is None: - error_message = 'enter an integer less than or equal to %(max)g' + error_message = \ + 'enter an integer less than or equal to %(max)g' self.error_message = translate( error_message) % dict(max=self.maximum - 1) elif maximum is None: self.minimum = int(minimum) if error_message is None: - error_message = 'enter an integer greater than or equal to %(min)g' + error_message = \ + 'enter an integer greater than or equal to %(min)g' self.error_message = translate( error_message) % dict(min=self.minimum) else: diff --git a/scripts/setup-web2py-nginx-uwsgi-opensuse.sh b/scripts/setup-web2py-nginx-uwsgi-opensuse.sh new file mode 100644 index 00000000..dd9e56dd --- /dev/null +++ b/scripts/setup-web2py-nginx-uwsgi-opensuse.sh @@ -0,0 +1,226 @@ +#!/bin/bash +echo 'setup-web2py-nginx-uwsgi-opensuse.sh' +echo 'Requires OpenSUSE 12.3 32Bits and installs Nginx + uWSGI + Web2py' + + +# Get Web2py Admin Password +echo -e "Web2py Admin Password: \c " +read PW + +zypper clean && zypper refresh && zypper up +zypper in -y nginx python-xml python-pip unzip sudo +zypper in -y gcc python-devel libxml2-devel python-pip unzip +pip install --upgrade pip +PIPPATH=`which pip` +$PIPPATH install --upgrade uwsgi + + +# Prepare folders for uwsgi +mkdir /etc/uwsgi +mkdir /var/log/uwsgi + +usermod -G www nginx + +mkdir -p /etc/nginx/vhosts.d/ +mkdir -p /etc/nginx/ssl/ + + +cd /etc/nginx/ssl +openssl genrsa 1024 > web2py.key +chmod 400 web2py.key +openssl req -new -x509 -nodes -sha1 -days 1780 -key web2py.key > web2py.crt +openssl x509 -noout -fingerprint -text < web2py.crt > web2py.info + + +echo 'server { + listen 80; + server_name $hostname; + #to enable correct use of response.static_version + #location ~* /(\w+)/static(?:/_[\d]+\.[\d]+\.[\d]+)?/(.*)$ { + # alias /srv/www/web2py/applications/$1/static/$2; + # expires max; + #} + location ~* /(\w+)/static/ { + root /srv/www/web2py/applications/; + #remove next comment on production + #expires max; + } + location / { + #uwsgi_pass 127.0.0.1:9001; + uwsgi_pass unix:///tmp/web2py.socket; + include /etc/nginx/uwsgi_params; + uwsgi_param UWSGI_SCHEME $scheme; + uwsgi_param SERVER_SOFTWARE nginx/$nginx_version; + } +} +server { + listen 443 default_server ssl; + server_name $hostname; + ssl_certificate /etc/nginx/ssl/web2py.crt; + ssl_certificate_key /etc/nginx/ssl/web2py.key; + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + ssl_ciphers ECDHE-RSA-AES256-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA; + ssl_protocols SSLv3 TLSv1; + keepalive_timeout 70; + location / { + #uwsgi_pass 127.0.0.1:9001; + uwsgi_pass unix:///tmp/web2py.socket; + include /etc/nginx/uwsgi_params; + uwsgi_param UWSGI_SCHEME $scheme; + uwsgi_param SERVER_SOFTWARE nginx/$nginx_version; + } + +}' >/etc/nginx/vhosts.d/web2py.conf + + + +# Create configuration file /etc/uwsgi/web2py.xml +echo ' + /tmp/web2py.socket + /srv/www/web2py/ + /=wsgihandler:application + + 4 + 60 + 8 + 1 + /tmp/stats.socket + 2000 + 512 + 256 + 192 + nginx + www + 0 0 -1 -1 -1 python /srv/www/web2py/web2py.py -Q -S welcome -M -R scripts/sessions2trash.py -A -o + +' >/etc/uwsgi/web2py.xml + + +cd /srv/www/ +wget http://web2py.com/examples/static/web2py_src.zip +unzip web2py_src.zip +rm web2py_src.zip +# Download latest version of sessions2trash.py +wget http://web2py.googlecode.com/hg/scripts/sessions2trash.py -O /srv/www/web2py/scripts/sessions2trash.py +chown -R nginx:www web2py +cd /srv/www/web2py +sudo -u nginx python -c "from gluon.main import save_password; save_password('$PW',443)" + + + +## Daemons /start/stop + +echo '#!/bin/sh +# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. +# +# Author: James Oakley +# +# /etc/init.d/uwsgi +# and its symbolic link +# /(usr/)sbin/rcuwsgi +# +# LSB compatible service control script; see http://www.linuxbase.org/spec/ +# +### BEGIN INIT INFO +# Provides: uwsgi +# Required-Start: $syslog $remote_fs +# Should-Start: $time ypbind smtp +# Required-Stop: $syslog $remote_fs +# Should-Stop: ypbind smtp +# Default-Start: 3 5 +# Default-Stop: 0 1 2 6 +# Short-Description: Application Container Server for Networked/Clustered Web Applications +# Description: Application Container Server for Networked/Clustered Web Applications +### END INIT INFO + +# Check for missing binaries (stale symlinks should not happen) +UWSGI_BIN=/usr/bin/uwsgi +test -x $UWSGI_BIN || { echo "$UWSGI_BIN not installed"; + if [ "$1" = "stop" ]; then exit 0; + else exit 5; fi; } + +UWSGI_EMPEROR_MODE=true +UWSGI_VASSALS="/etc/uwsgi/" +UWSGI_OPTIONS="--logto /var/log/uwsgi/uwsgi.log" + + +UWSGI_OPTIONS="$UWSGI_OPTIONS --autoload" + +if [ "$UWSGI_EMPEROR_MODE" = "true" ] ; then + UWSGI_OPTIONS="$UWSGI_OPTIONS --emperor $UWSGI_VASSALS" +fi + +. /etc/rc.status + +rc_reset + +case "$1" in + start) + echo -n "Starting uWSGI " + /sbin/startproc $UWSGI_BIN $UWSGI_OPTIONS + rc_status -v + ;; + stop) + echo -n "Shutting down uWSGI " + /sbin/killproc $UWSGI_BIN + rc_status -v + ;; + try-restart|condrestart) + if test "$1" = "condrestart"; then + echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}" + fi + $0 status + if test $? = 0; then + $0 restart + else + rc_reset + fi + rc_status + ;; + restart) + $0 stop + $0 start + rc_status + ;; + force-reload) + echo -n "Reload service uWSGI " + /sbin/killproc -HUP $UWSGI_BIN + rc_status -v + ;; + reload) + echo -n "Reload service uWSGI " + /sbin/killproc -HUP $UWSGI_BIN + rc_status -v + ;; + status) + echo -n "Checking for service uWSGI " + /sbin/checkproc $UWSGI_BIN + rc_status -v + ;; + probe) + echo -n "uWSGI does not support probe " + rc_failed 3 + rc_status -v + ;; + *) + echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}" + exit 1 + ;; +esac +rc_exit '> /etc/init.d/uwsgi + + +chmod +x /etc/init.d/uwsgi +/etc/init.d/uwsgi start +/etc/init.d/nginx restart + + +chkconfig --add uwsgi +chkconfig --add nginx + +## you can reload uwsgi with +#/etc/init.d/uwsgi restart +## to reload web2py only (without restarting uwsgi) +# touch /etc/uwsgi/web2py.xml