Compare commits

...
6 Commits
9 changed files with 129 additions and 16 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
## 2.3.1 ## 2.3.1 - 2.3.2
- new virtual fields syntax: - new virtual fields syntax:
``db.define_table('person',Field('name'),Field.Virtual('namey',lambda row: row.person.name+'y'))`` ``db.define_table('person',Field('name'),Field.Virtual('namey',lambda row: row.person.name+'y'))``
+1 -1
View File
@@ -29,7 +29,7 @@ update:
wget -O gluon/contrib/simplejsonrpc.py http://rad2py.googlecode.com/hg/ide2py/simplejsonrpc.py wget -O gluon/contrib/simplejsonrpc.py http://rad2py.googlecode.com/hg/ide2py/simplejsonrpc.py
echo "remember that pymysql was tweaked" echo "remember that pymysql was tweaked"
src: src:
echo 'Version 2.3.1 ('`date +%Y-%m-%d\ %H:%M:%S`') stable' > VERSION echo 'Version 2.3.2 ('`date +%Y-%m-%d\ %H:%M:%S`') stable' > VERSION
### rm -f all junk files ### rm -f all junk files
make clean make clean
### clean up baisc apps ### clean up baisc apps
+1 -1
View File
@@ -1 +1 @@
Version 2.3.1 (2012-12-14 09:21:31) stable Version 2.3.2 (2012-12-17 08:59:58) stable
@@ -1,3 +1,4 @@
def hello1(): def hello1():
""" simple page without template """ """ simple page without template """
@@ -99,7 +100,7 @@ def rss_aggregator():
pubDate=datetime.datetime.now()) for entry in pubDate=datetime.datetime.now()) for entry in
d.entries]) d.entries])
response.headers['Content-Type'] = 'application/rss+xml' response.headers['Content-Type'] = 'application/rss+xml'
return rss2.dumps(rss) return rss.to_xml(encoding='utf-8')
def ajaxwiki(): def ajaxwiki():
+1 -1
View File
@@ -27,7 +27,7 @@ jQuery(function(){
jQuery('body').append(tbar); jQuery('body').append(tbar);
var st = jQuery('#socialdrawer'); var st = jQuery('#socialdrawer');
st.css({'opacity':'.7','z-index':'3000','background':'#FFF','border':'solid 1px #666','border-width':' 1px 0 0 1px','height':'20px','width':'40px','position':'fixed','bottom':'0','right':'0','padding':'2px 5px','overflow':'hidden','-webkit-border-top-left-radius':' 12px','-moz-border-radius-topleft':' 12px','border-top-left-radius':' 12px','-moz-box-shadow':' -3px -3px 3px rgba(0,0,0,0.5)','-webkit-box-shadow':' -3px -3px 3px rgba(0,0,0,0.5)','box-shadow':' -3px -3px 3px rgba(0,0,0,0.5)'}); st.css({'opacity':'.7','z-index':'3000','background':'#FFF','border':'solid 1px #666','border-width':' 1px 0 0 1px','height':'20px','width':'40px','position':'fixed','bottom':'0','right':'0','padding':'2px 5px','overflow':'hidden','-webkit-border-top-left-radius':' 12px','-moz-border-radius-topleft':' 12px','border-top-left-radius':' 12px','-moz-box-shadow':' -3px -3px 3px rgba(0,0,0,0.5)','-webkit-box-shadow':' -3px -3px 3px rgba(0,0,0,0.5)','box-shadow':' -3px -3px 3px rgba(0,0,0,0.5)'});
jQuery('#socialdrawer a').css({'float':'left','width':'32px','margin':'3px 2px 2px 2px','padding':'0'}); jQuery('#socialdrawer a').css({'float':'left','width':'32px','margin':'3px 2px 2px 2px','padding':'0','cursor':'pointer'});
jQuery('#socialdrawer span').css({'float':'left','margin':'2px 3px','text-shadow':' 1px 1px 1px #FFF','color':'#444','font-size':'12px','line-height':'1em'}); jQuery('#socialdrawer span').css({'float':'left','margin':'2px 3px','text-shadow':' 1px 1px 1px #FFF','color':'#444','font-size':'12px','line-height':'1em'});
jQuery('#socialdrawer img').hide(); jQuery('#socialdrawer img').hide();
// hover // hover
@@ -0,0 +1,107 @@
#!/usr/bin/env python
# coding: utf8
"""
Oneall Authentication for web2py
Developed by Nathan Freeze (Copyright © 2013)
Email <nathan@freezable.com>
This file contains code to allow using onall.com
authentication services with web2py
"""
import os
import base64
from gluon import *
from gluon.storage import Storage
from gluon.contrib.simplejson import JSONDecodeError
from gluon.tools import fetch
import gluon.contrib.simplejson as json
class OneallAccount(object):
"""
from gluon.contrib.login_methods.oneall_account import OneallAccount
auth.settings.actions_disabled=['register','change_password',
'request_reset_password']
auth.settings.login_form = OneallAccount(request,
public_key="...",
private_key="...",
domain="...",
url = "http://localhost:8000/%s/default/user/login" % request.application)
"""
def __init__(self, request, public_key="", private_key="", domain="",
url=None, providers=None, on_login_failure=None):
self.request = request
self.public_key = public_key
self.private_key = private_key
self.url = url
self.domain = domain
self.profile = None
self.on_login_failure = on_login_failure
self.providers = providers or ["facebook", "google", "yahoo", "openid"]
self.mappings = Storage()
def defaultmapping(profile):
name = profile.get('name',{})
dname = name.get('formatted',profile.get('displayName'))
email=profile.get('emails', [{}])[0].get('value')
reg_id=profile.get('identity_token','')
username=profile.get('preferredUsername',email)
first_name=name.get('givenName', dname.split(' ')[0])
last_name=profile.get('familyName',dname.split(' ')[1])
return dict(registration_id=reg_id,username=username,email=email,
first_name=first_name,last_name=last_name)
self.mappings.default = defaultmapping
def get_user(self):
request = self.request
user = None
if request.vars.connection_token:
auth_url = "https://%s.api.oneall.com/connections/%s.json" % \
(self.domain, request.vars.connection_token)
auth_pw = "%s:%s" % (self.public_key,self.private_key)
auth_pw = base64.b64encode(auth_pw)
headers = dict(Authorization="Basic %s" % auth_pw)
try:
auth_info_json = fetch(auth_url,headers=headers)
auth_info = json.loads(auth_info_json)
data = auth_info['response']['result']['data']
if data['plugin']['key'] == 'social_login':
if data['plugin']['data']['status'] == 'success':
userdata = data['user']
self.profile = userdata['identity']
source = self.profile['source']['key']
mapping = self.mappings.get(source,self.mappings['default'])
user = mapping(self.profile)
except (JSONDecodeError, KeyError):
pass
if user is None and self.on_login_failure:
redirect(self.on_login_failure)
return user
def login_form(self):
scheme = self.request.env.wsgi_url_scheme
oneall_url = scheme + "://%s.api.oneall.com/socialize/library.js" % self.domain
oneall_lib = SCRIPT(_src=oneall_url,_type='text/javascript')
container = DIV(_id="oa_social_login_container")
widget = SCRIPT('oneall.api.plugins.social_login.build("oa_social_login_container",',
'{providers : %s,' % self.providers,
'callback_uri: "%s"});' % self.url,
_type="text/javascript")
form = DIV(oneall_lib,container,widget)
return form
def use_oneall(auth, filename='private/oneall.key', **kwargs):
path = os.path.join(current.request.folder, filename)
if os.path.exists(path):
request = current.request
domain, public_key, private_key = open(path, 'r').read().strip().split(':')
url = URL('default', 'user', args='login', scheme=True)
auth.settings.actions_disabled =\
['register', 'change_password', 'request_reset_password']
auth.settings.login_form = OneallAccount(
request, public_key=public_key,private_key=private_key,
domain=domain, url=url, **kwargs)
+10 -8
View File
@@ -15,6 +15,7 @@ import tarfile
import glob import glob
import time import time
import datetime import datetime
import logging
from http import HTTP from http import HTTP
from gzip import open as gzopen from gzip import open as gzopen
@@ -240,19 +241,20 @@ def w2p_pack(filename, path, compiled=False):
tarfp.close() tarfp.close()
os.unlink(tarname) os.unlink(tarname)
def create_welcome_w2p():
def w2p_unpack(filename, path, delete_tar=True): if not os.path.exists('welcome.w2p') or os.path.exists('NEWINSTALL'):
if filename=='welcome.w2p' and (
not os.path.exists('welcome.w2p') or \
os.path.exists('NEWINSTALL')):
try: try:
w2p_pack('welcome.w2p', 'applications/welcome') w2p_pack('welcome.w2p', 'applications/welcome')
os.unlink('NEWINSTALL') os.unlink('NEWINSTALL')
logging.info("New installation: created welcome.w2p file")
except: except:
msg = "New installation: unable to create welcome.w2p file" logging.error("New installation error: unable to create welcome.w2p file")
sys.stderr.write(msg)
def w2p_unpack(filename, path, delete_tar=True):
if filename=='welcome.w2p':
create_welcome_w2p()
filename = abspath(filename) filename = abspath(filename)
path = abspath(path) path = abspath(path)
if filename[-4:] == '.w2p' or filename[-3:] == '.gz': if filename[-4:] == '.w2p' or filename[-3:] == '.gz':
+3 -2
View File
@@ -468,8 +468,9 @@ class PasswordWidget(FormWidget):
requires = [requires] requires = [requires]
is_strong = [r for r in requires if isinstance(r, IS_STRONG)] is_strong = [r for r in requires if isinstance(r, IS_STRONG)]
if is_strong: if is_strong:
output.append(SCRIPT("web2py_validate_entropy(jQuery('#%s'),%s);" output.append(SCRIPT("web2py_validate_entropy(jQuery('#%s'),%s);" % (
% (attr['_id'], is_strong[0].entropy))) attr['_id'], is_strong[0].entropy
if is_strong[0].entropy else "null")))
# end entropy check # end entropy check
return output return output
+3 -1
View File
@@ -25,7 +25,7 @@ import newcron
import getpass import getpass
import main import main
from fileutils import w2p_pack, read_file, write_file from fileutils import w2p_pack, read_file, write_file, create_welcome_w2p
from settings import global_settings from settings import global_settings
from shell import run, test from shell import run, test
from utils import is_valid_ip_address, is_loopback_ip_address from utils import is_valid_ip_address, is_loopback_ip_address
@@ -969,6 +969,8 @@ def console():
if options.numthreads is not None and options.minthreads is None: if options.numthreads is not None and options.minthreads is None:
options.minthreads = options.numthreads # legacy options.minthreads = options.numthreads # legacy
create_welcome_w2p()
if not options.cronjob: if not options.cronjob:
# If we have the applications package or if we should upgrade # If we have the applications package or if we should upgrade
if not os.path.exists('applications/__init__.py'): if not os.path.exists('applications/__init__.py'):