From a5f883c2f08fe8ac82879992bd9a6d987c52d2dd Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sun, 28 Oct 2012 12:01:09 -0500 Subject: [PATCH 01/17] following Joe and Jonathan's advice, None value is formatted --- VERSION | 2 +- gluon/dal.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 01f6408e..b28ed3b3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-27 14:37:32) stable +Version 2.2.1 (2012-10-28 12:01:03) stable diff --git a/gluon/dal.py b/gluon/dal.py index fafe0727..701bd269 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -8622,7 +8622,7 @@ class Field(Expression): def formatter(self, value): requires = self.requires - if value is None or not requires: + if not requires: return value if not isinstance(requires, (list, tuple)): requires = [requires] From aa149d2e7b9a61a17b8342f53b49429dc977f025 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 29 Oct 2012 08:53:50 -0500 Subject: [PATCH 02/17] fixed bug in sessions2trach.py, issue 1111, thanks Szimszon --- VERSION | 2 +- scripts/sessions2trash.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index b28ed3b3..c93f8d4a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-28 12:01:03) stable +Version 2.2.1 (2012-10-29 08:53:44) stable diff --git a/scripts/sessions2trash.py b/scripts/sessions2trash.py index 3995014e..8609c480 100755 --- a/scripts/sessions2trash.py +++ b/scripts/sessions2trash.py @@ -95,8 +95,9 @@ class SessionSetDb(SessionSet): """Return list of SessionDb instances for existing sessions.""" sessions = [] table = current.response.session_db_table - for row in table._db(table.id > 0).select(): - sessions.append(SessionDb(row)) + if table: + for row in table._db(table.id > 0).select(): + sessions.append(SessionDb(row)) return sessions From 83321067548612817bb5ca9b439f797bf7cbb2df Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 29 Oct 2012 08:57:43 -0500 Subject: [PATCH 03/17] fixed issue 1121, appadmin interface to cache, thanks Paolo --- VERSION | 2 +- gluon/cache.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c93f8d4a..20cd35e4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-29 08:53:44) stable +Version 2.2.1 (2012-10-29 08:57:40) stable diff --git a/gluon/cache.py b/gluon/cache.py index 6c52c418..60eaed00 100644 --- a/gluon/cache.py +++ b/gluon/cache.py @@ -147,6 +147,7 @@ class CacheInRam(CacheAbstract): def __init__(self, request=None): self.initialized = False self.request = request + self.storage = {} def initialize(self): if self.initialized: @@ -303,6 +304,7 @@ class CacheOnDisk(CacheAbstract): self.initialized = False self.request = request self.folder = folder + self.storage = {} def initialize(self): if self.initialized: From fe5a1c6a8d8f13df5c9cfd692b0d1c1984a4cd1d Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 29 Oct 2012 08:59:54 -0500 Subject: [PATCH 04/17] fixed issue 1120, bug introduced in latest utils.py import. thanks Yair --- VERSION | 2 +- gluon/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 20cd35e4..40b6cc5b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-29 08:57:40) stable +Version 2.2.1 (2012-10-29 08:59:50) stable diff --git a/gluon/utils.py b/gluon/utils.py index 52f8a58b..d2ee474d 100644 --- a/gluon/utils.py +++ b/gluon/utils.py @@ -37,7 +37,7 @@ try: except ImportError: try: from .aes import AES - except ImportError: + except (ImportError, ValueError): from contrib.aes import AES try: From 6e0e48e1503ad08a076e041158879910e0f08729 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 29 Oct 2012 09:06:52 -0500 Subject: [PATCH 05/17] fixed toolbar issue 1111, thanks niphlod --- VERSION | 2 +- gluon/globals.py | 30 ++++++++++++++++-------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/VERSION b/VERSION index 40b6cc5b..c9a3333a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-29 08:59:50) stable +Version 2.2.1 (2012-10-29 09:06:49) stable diff --git a/gluon/globals.py b/gluon/globals.py index 7f588357..a015db93 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -435,21 +435,23 @@ class Response(Storage): admin = URL("admin", "default", "design", args=current.request.application) from gluon.dal import THREAD_LOCAL - if hasattr(THREAD_LOCAL, 'instances'): - dbstats = [TABLE(*[TR(PRE(row[0]), '%.2fms' % (row[1] * 1000)) - for row in i.db._timings]) - for i in THREAD_LOCAL.instances] - dbtables = dict([(regex_nopasswd.sub('******', i.uri), - {'defined': - sorted(list(set(i.db.tables) - - set(i.db._LAZY_TABLES.keys()))) or + dbs = getattr(THREAD_LOCAL,'db_instances',{}).items() + dbstats = [] + dbtables = {} + for db_uid, db_group in dbs: + for db in db_group: + if not db._uri: + continue + k = regex_nopasswd.sub('******',db._uri) + dbstats.append(TABLE(*[TR(PRE(row[0]),'%.2fms' % + (row[1]*1000)) \ + for row in db._timings])) + dbtables[k] = {'defined': + sorted(list(set(db.tables) - + set(db._LAZY_TABLES.keys()))) or '[no defined tables]', - 'lazy': sorted(i.db._LAZY_TABLES.keys()) or - '[no lazy tables]'}) - for i in THREAD_LOCAL.instances]) - else: - dbstats = [] # if no db or on GAE - dbtables = {} + 'lazy': sorted(db._LAZY_TABLES.keys()) or + '[no lazy tables]'} u = web2py_uuid() backtotop = A('Back to top', _href="#totop-%s" % u) return DIV( From 54b98b4e058e2d27ccc4c2e655f1d48df1fc805a Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 29 Oct 2012 09:28:19 -0500 Subject: [PATCH 06/17] fixed issue 1118, reload page when called by component, thanks Paolo --- VERSION | 2 +- gluon/http.py | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index c9a3333a..1dc141f8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-29 09:06:49) stable +Version 2.2.1 (2012-10-29 09:28:14) stable diff --git a/gluon/http.py b/gluon/http.py index 831c04d6..bd1f1411 100644 --- a/gluon/http.py +++ b/gluon/http.py @@ -140,7 +140,7 @@ class HTTP(BaseException): return self.message -def redirect(location, how=303, client_side=False): +def redirect(location='', how=303, client_side=False): if location: from gluon import current loc = location.replace('\r', '%0D').replace('\n', '%0A') @@ -150,3 +150,8 @@ def redirect(location, how=303, client_side=False): raise HTTP(how, 'You are being redirected here' % loc, Location=loc) + else: + from gluon import current + if client_side and current.request.ajax: + raise HTTP(200, **{'web2py-component-command': 'window.location.reload(true)'}) + \ No newline at end of file From 5ee2ab9b6bd4589ecc9893cb22b0c1d3bd18d084 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 29 Oct 2012 09:31:51 -0500 Subject: [PATCH 07/17] fixed redirection after change password, issue 1112, thanks Friedrich --- VERSION | 2 +- gluon/tools.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 1dc141f8..6e7dddc3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-29 09:28:14) stable +Version 2.2.1 (2012-10-29 09:31:46) stable diff --git a/gluon/tools.py b/gluon/tools.py index e70723dd..44eabe2d 100644 --- a/gluon/tools.py +++ b/gluon/tools.py @@ -2717,7 +2717,7 @@ class Auth(object): next = self.url(args=request.args) else: next = replace_id(next, form) - redirect(next) + redirect(next) return form def profile( From 7549f77edcc46b4e83561d18de54a463178c7ad5 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 29 Oct 2012 10:09:07 -0500 Subject: [PATCH 08/17] validator.formatter checks None --- VERSION | 2 +- gluon/validators.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6e7dddc3..2fa142a9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-29 09:31:46) stable +Version 2.2.1 (2012-10-29 10:09:01) stable diff --git a/gluon/validators.py b/gluon/validators.py index af3f6629..ff3c0509 100644 --- a/gluon/validators.py +++ b/gluon/validators.py @@ -778,6 +778,8 @@ class IS_FLOAT_IN_RANGE(Validator): return (value, self.error_message) def formatter(self, value): + if values is None: + return None return str2dec(value).replace('.', self.dot) @@ -882,6 +884,8 @@ class IS_DECIMAL_IN_RANGE(Validator): return (value, self.error_message) def formatter(self, value): + if value is None: + return None return str2dec(value).replace('.', self.dot) @@ -2170,6 +2174,8 @@ class IS_DATE(Validator): return (value, translate(self.error_message) % self.extremes) def formatter(self, value): + if value is None: + return None format = self.format year = value.year y = '%.4i' % year @@ -2228,6 +2234,8 @@ class IS_DATETIME(Validator): return (value, translate(self.error_message) % self.extremes) def formatter(self, value): + if value is None: + return None format = self.format year = value.year y = '%.4i' % year From 9d7e009c0ffef8bdf1db3c42b5f6bc44684fab52 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 29 Oct 2012 11:36:04 -0500 Subject: [PATCH 09/17] csv can return a generator, thanks Jonathan --- VERSION | 2 +- gluon/tools.py | 28 +++++++++++++--------------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/VERSION b/VERSION index 2fa142a9..42184285 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-29 10:09:01) stable +Version 2.2.1 (2012-10-29 11:35:59) stable diff --git a/gluon/tools.py b/gluon/tools.py index 44eabe2d..0e31f494 100644 --- a/gluon/tools.py +++ b/gluon/tools.py @@ -1365,13 +1365,13 @@ class Auth(object): archive_names='%(tablename)s_archive', current_record='current_record'): """ - to enable full record vernionioning (including auth tables): + to enable full record versioning (including auth tables): auth = Auth(db) auth.define_tables(signature=True) # define our own tables db.define_table('mything',Field('name'),auth.signature) - auth.enable_record_vernining(tables=db) + auth.enable_record_versioning(tables=db) tables can be the db (all table) or a list of tables. only tables with modified_by and modified_on fiels (as created @@ -1386,7 +1386,7 @@ class Auth(object): Important: If you use auth.enable_record_versioning, do not use auth.archive or you will end up with duplicates. - auth.archive does explicitely what enable_record_versioning + auth.archive does explicitly what enable_record_versioning does automatically. """ @@ -1489,7 +1489,7 @@ class Auth(object): IS_NOT_IN_DB(db, '%s.username' % settings.table_user_name)] if not settings.username_case_sensitive: is_unique_username.insert(1, IS_LOWER()) - table = db.define_table( + db.define_table( settings.table_user_name, Field('first_name', length=128, default='', label=self.messages.label_first_name, @@ -1522,7 +1522,7 @@ class Auth(object): fake_migrate=fake_migrate, format='%(username)s')) else: - table = db.define_table( + db.define_table( settings.table_user_name, Field('first_name', length=128, default='', label=self.messages.label_first_name, @@ -1555,7 +1555,7 @@ class Auth(object): if not settings.table_group_name in db.tables: extra_fields = settings.extra_fields.get( settings.table_group_name, []) + signature_list - table = db.define_table( + db.define_table( settings.table_group_name, Field('role', length=512, default='', label=self.messages.label_role, @@ -1573,7 +1573,7 @@ class Auth(object): if not settings.table_membership_name in db.tables: extra_fields = settings.extra_fields.get( settings.table_membership_name, []) + signature_list - table = db.define_table( + db.define_table( settings.table_membership_name, Field('user_id', reference_table_user, label=self.messages.label_user_id), @@ -1587,7 +1587,7 @@ class Auth(object): if not settings.table_permission_name in db.tables: extra_fields = settings.extra_fields.get( settings.table_permission_name, []) + signature_list - table = db.define_table( + db.define_table( settings.table_permission_name, Field('group_id', reference_table_group, label=self.messages.label_group_id), @@ -1605,7 +1605,7 @@ class Auth(object): settings.table_permission_name, migrate), fake_migrate=fake_migrate)) if not settings.table_event_name in db.tables: - table = db.define_table( + db.define_table( settings.table_event_name, Field('time_stamp', 'datetime', default=current.request.now, @@ -1629,7 +1629,7 @@ class Auth(object): now = current.request.now if settings.cas_domains: if not settings.table_cas_name in db.tables: - table = db.define_table( + db.define_table( settings.table_cas_name, Field('user_id', reference_table_user, default=None, label=self.messages.label_user_id), @@ -1773,8 +1773,6 @@ class Auth(object): """ logins user as specified by usernname (or email) and password """ - request = current.request - session = current.session table_user = self.table_user() if self.settings.login_userfield: userfield = self.settings.login_userfield @@ -2669,7 +2667,6 @@ class Auth(object): redirect(self.settings.login_url) db = self.db table_user = self.table_user() - usern = self.settings.table_user_name s = db(table_user.id == self.user.id) request = current.request @@ -4139,12 +4136,13 @@ class Service(object): return '' return value if args and args[0] in self.run_procedures: + import types r = universal_caller(self.run_procedures[args[0]], *args[1:], **dict(request.vars)) s = cStringIO.StringIO() if hasattr(r, 'export_to_csv_file'): r.export_to_csv_file(s) - elif r and isinstance(r[0], (dict, Storage)): + elif r and not isinstance(r, types.GeneratorType) and isinstance(r[0], (dict, Storage)): import csv writer = csv.writer(s) writer.writerow(r[0].keys()) @@ -4656,7 +4654,7 @@ class Wiki(object): html = page.body # @///function -> http://..../function html = replace_at_urls(html, URL) - # http://...jpg -> or embed html = replace_autolinks(html, lambda link: expand_one(link, {})) # @{component:name} -> html = replace_components(html, self.env) From 4357edb1d490889a29a80699f4a9dd7c37f06917 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 29 Oct 2012 14:00:29 -0500 Subject: [PATCH 10/17] if user_group_name is None, user_group_role is also None --- VERSION | 2 +- gluon/tools.py | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/VERSION b/VERSION index 42184285..679bb7fc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-29 11:35:59) stable +Version 2.2.1 (2012-10-29 14:00:21) stable diff --git a/gluon/tools.py b/gluon/tools.py index 0e31f494..4c1e118d 100644 --- a/gluon/tools.py +++ b/gluon/tools.py @@ -2987,10 +2987,12 @@ class Auth(object): return self.id_group(self.user_group_role(user_id)) def user_group_role(self, user_id=None): + if not self.settings.create_user_groups: + return None if user_id: user = self.table_user()[user_id] else: - user = self.user + user = self.user return self.settings.create_user_groups % user def has_membership(self, group_id=None, user_id=None, role=None): @@ -4896,7 +4898,8 @@ class Wiki(object): % self.force_prefix redirect(URL(args=('_edit', self.force_prefix + slug))) db.wiki_page.can_read.default = [Wiki.everybody] - db.wiki_page.can_edit.default = [auth.user_group_role()] + user_group_role = auth.user_group_role() + db.wiki_page.can_edit.default = [user_group_role] db.wiki_page.title.default = title_guess db.wiki_page.slug.default = slug if slug == 'wiki-menu': From 6a13c33c70745461497d66cff857ceef5320fc1d Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 29 Oct 2012 18:11:52 -0500 Subject: [PATCH 11/17] added informix to list, thanks Christopher --- VERSION | 2 +- gluon/dal.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 679bb7fc..1918e953 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-29 14:00:21) stable +Version 2.2.1 (2012-10-29 18:11:45) stable diff --git a/gluon/dal.py b/gluon/dal.py index 701bd269..f783092d 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -26,6 +26,7 @@ including: - DB2 - Interbase - Ingres +- Informix - SapDB (experimental) - Cubrid (experimental) - CouchDB (experimental) From 04caa5f4e4a432f350367fe269b6312d285853f3 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 29 Oct 2012 18:13:58 -0500 Subject: [PATCH 12/17] moved toolbar logic to dal, thanks Niphlod --- VERSION | 2 +- gluon/dal.py | 34 ++++++++++++++++++++++++++++++++-- gluon/globals.py | 32 +++++++++++++------------------- 3 files changed, 46 insertions(+), 22 deletions(-) diff --git a/VERSION b/VERSION index 1918e953..5c09e0eb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-29 18:11:45) stable +Version 2.2.1 (2012-10-29 18:13:39) stable diff --git a/gluon/dal.py b/gluon/dal.py index f783092d..e458d677 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -180,7 +180,7 @@ if PYTHON_VERSION == 2: bytes, unicode = str, unicode else: import pickle - from io import StringIO as StringIO + from io import StringIO as StringIO import copyreg long = int hashlib_md5 = lambda s: hashlib.md5(bytes(s,'utf8')) @@ -256,6 +256,7 @@ REGEX_STORE_PATTERN = re.compile('\.(?P\w{1,5})$') REGEX_QUOTES = re.compile("'[^']*'") REGEX_ALPHANUMERIC = re.compile('^[0-9a-zA-Z]\w*$') REGEX_PASSWORD = re.compile('\://([^:@]*)\:') +REGEX_NOPASSWD = re.compile('(?<=\:)([^:@/]+)(?=@.+)') # list of drivers will be built on the fly # and lists only what is available @@ -2106,7 +2107,7 @@ class SQLiteAdapter(BaseAdapter): dbpath = pjoin( self.folder.decode(path_encoding).encode('utf8'), dbpath) else: - dbpath = pjoin(self.folder, dbpath) + dbpath = pjoin(self.folder, dbpath) if not 'check_same_thread' in driver_args: driver_args['check_same_thread'] = False if not 'detect_types' in driver_args: @@ -6661,6 +6662,35 @@ class DAL(object): """ BaseAdapter.set_folder(folder) + @staticmethod + def get_instances(): + """ + Returns a dictionary with uri as key with timings and defined tables + {'sqlite://storage.sqlite': { + 'dbstats': [(select auth_user.email from auth_user, 0.02009)], + 'dbtables': { + 'defined': ['auth_cas', 'auth_event', 'auth_group', + 'auth_membership', 'auth_permission', 'auth_user'], + 'lazy': '[]' + } + } + } + """ + dbs = getattr(THREAD_LOCAL,'db_instances',{}).items() + infos = {} + for db_uid, db_group in dbs: + for db in db_group: + if not db._uri: + continue + k = REGEX_NOPASSWD.sub('******',db._uri) + infos[k] = dict(dbstats = [(row[0], row[1]) for row in db._timings], + dbtables = {'defined': + sorted(list(set(db.tables) - + set(db._LAZY_TABLES.keys()))), + 'lazy': sorted(db._LAZY_TABLES.keys())} + ) + return infos + @staticmethod def distributed_transaction_begin(*instances): if not instances: diff --git a/gluon/globals.py b/gluon/globals.py index a015db93..60cc86a6 100644 --- a/gluon/globals.py +++ b/gluon/globals.py @@ -48,7 +48,6 @@ except ImportError: have_minify = False regex_session_id = re.compile('^([\w\-]+/)?[\w\-\.]+$') -regex_nopasswd = re.compile('(?<=\:)([^:@/]+)(?=@.+)') __all__ = ['Request', 'Response', 'Session'] @@ -127,7 +126,10 @@ class Request(Storage): If request comes in over HTTP, redirect it to HTTPS and secure the session. """ - if not global_settings.cronjob and not self.is_https: + cmd_opts = global_settings.cmd_options + #checking if this is called within the scheduler or within the shell + #in addition to checking if it's not a cronjob + if not cmd_opts.shell and not cmd_opts.scheduler and not global_settings.cronjob and not self.is_https: current.session.forget() redirect(URL(scheme='https', args=self.args, vars=self.vars)) @@ -434,24 +436,16 @@ class Response(Storage): BUTTON = TAG.button admin = URL("admin", "default", "design", args=current.request.application) - from gluon.dal import THREAD_LOCAL - dbs = getattr(THREAD_LOCAL,'db_instances',{}).items() + from gluon.dal import DAL dbstats = [] dbtables = {} - for db_uid, db_group in dbs: - for db in db_group: - if not db._uri: - continue - k = regex_nopasswd.sub('******',db._uri) - dbstats.append(TABLE(*[TR(PRE(row[0]),'%.2fms' % - (row[1]*1000)) \ - for row in db._timings])) - dbtables[k] = {'defined': - sorted(list(set(db.tables) - - set(db._LAZY_TABLES.keys()))) or - '[no defined tables]', - 'lazy': sorted(db._LAZY_TABLES.keys()) or - '[no lazy tables]'} + infos = DAL.get_instances() + for k,v in infos.iteritems(): + dbstats.append(TABLE(*[TR(PRE(row[0]),'%.2fms' % + (row[1]*1000)) + for row in v['dbstats']])) + dbtables[k] = dict(defined=v['dbtables']['defined'] or '[no defined tables]', + lazy=v['dbtables']['lazy'] or '[no lazy tables]') u = web2py_uuid() backtotop = A('Back to top', _href="#totop-%s" % u) return DIV( @@ -509,7 +503,7 @@ class Session(Storage): request = current.request if response is None: response = current.response - if separate == True: + if separate is True: separate = lambda session_name: session_name[-2:] self._unlock(response) if not masterapp: From c61e0e11bb1a343214135cf83bc22b252dd2d97e Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 29 Oct 2012 21:38:09 -0500 Subject: [PATCH 13/17] page and media preview in wiki, thanks Niphlod --- VERSION | 2 +- gluon/tools.py | 30 +++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/VERSION b/VERSION index 5c09e0eb..557596d6 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-29 18:13:39) stable +Version 2.2.1 (2012-10-29 21:38:03) stable diff --git a/gluon/tools.py b/gluon/tools.py index 4c1e118d..b6fb9ace 100644 --- a/gluon/tools.py +++ b/gluon/tools.py @@ -4906,7 +4906,7 @@ class Wiki(object): db.wiki_page.body.default = \ '- Menu Item > @////index\n- - Submenu > http://web2py.com' else: - db.wiki_page.body.default = '## %s\n\npage content' % title_guess + db.wiki_page.body.default = '## %s\n\npage content\n\n[[new page @////new_page]]\n' % title_guess vars = current.request.post_vars if vars.body: vars.body = vars.body.replace('://%s' % self.host, '://HOSTNAME') @@ -4925,12 +4925,20 @@ class Wiki(object): pagecontent.css('font-family', 'Monaco,Menlo,Consolas,"Courier New",monospace'); var prevbutton = $(''); + var mediabutton = $(''); var preview = $('
').hide(); + var previewmedia = $('
'); var table = $('form'); - prevbutton.insertBefore(table); preview.insertBefore(table); - prevbutton.on('click', function(e) { - e.preventDefault(); + prevbutton.insertBefore(table); + mediabutton.insertBefore(table); + previewmedia.insertBefore(table); + mediabutton.toggle(function() { + web2py_component('%(urlmedia)s', 'previewmedia'); + }, function() { + previewmedia.empty(); + }); + prevbutton.click(function() { if (prevbutton.hasClass('nopreview')) { prevbutton.addClass('preview').removeClass( 'nopreview').html('Edit Source'); @@ -4943,7 +4951,7 @@ class Wiki(object): } }) }) - """ % dict(url=URL(args=('_preview'))) + """ % dict(url=URL(args=('_preview')), urlmedia=URL(extension='load',args=('_editmedia'),vars=dict(embedded=1))) return dict(content=TAG[''](form, SCRIPT(script))) def editmedia(self, slug): @@ -4959,9 +4967,21 @@ class Wiki(object): row.filename.split('.')[-1])) self.auth.db.wiki_media.wiki_page.default = page.id self.auth.db.wiki_media.wiki_page.writable = False + links = [] + csv = True + if current.request.vars.embedded: + script = "var c = $('#wiki_page_body'); c.val(c.val() + $('%s').text()); return false;" + fragment = self.auth.db.wiki_media.id.represent + csv = False + links=[ + lambda row: + A('copy into source', _href='#', _onclick=script % (fragment(row.id, row))) + ] content = SQLFORM.grid( self.auth.db.wiki_media.wiki_page == page.id, orderby=self.auth.db.wiki_media.title, + links = links, + csv = csv, args=['_editmedia', slug], user_signature=False) return dict(content=content) From 8dae3f832d113bee5cf23980d01119f8234cb694 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 29 Oct 2012 22:22:36 -0500 Subject: [PATCH 14/17] gluon/contrib/login_methods/dropbox_account.py, get client --- VERSION | 2 +- gluon/contrib/login_methods/dropbox_account.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 557596d6..32811d39 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-29 21:38:03) stable +Version 2.2.1 (2012-10-29 22:22:31) stable diff --git a/gluon/contrib/login_methods/dropbox_account.py b/gluon/contrib/login_methods/dropbox_account.py index 8bfc7079..597320ee 100644 --- a/gluon/contrib/login_methods/dropbox_account.py +++ b/gluon/contrib/login_methods/dropbox_account.py @@ -99,13 +99,21 @@ class DropboxAccount(object): redirect('https://www.dropbox.com/logout') return next + def get_client(self): + access_token = current.session.dropbox_access_token + self.sess.set_token(access_token[0], access_token[1]) + self.client = client.DropboxClient(self.sess) + def put(self, filename, file): + if not hasattr(self,'client'): self.get_client() return json.loads(self.client.put_file(filename, file))['bytes'] def get(self, filename, file): + if not hasattr(self,'client'): self.get_client() return self.client.get_file(filename) def dir(self, path): + if not hasattr(self,'client'): self.get_client() return json.loads(self.client.metadata(path)) From 7b2afa109eff90882e844bc38213230797daa312 Mon Sep 17 00:00:00 2001 From: mdipierro Date: Mon, 29 Oct 2012 22:25:19 -0500 Subject: [PATCH 15/17] reverted changes about formatting None --- VERSION | 2 +- gluon/dal.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 32811d39..906ddeb9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-29 22:22:31) stable +Version 2.2.1 (2012-10-29 22:25:15) stable diff --git a/gluon/dal.py b/gluon/dal.py index e458d677..1082aa1f 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -8653,7 +8653,7 @@ class Field(Expression): def formatter(self, value): requires = self.requires - if not requires: + if value is None or not requires: return value if not isinstance(requires, (list, tuple)): requires = [requires] From 2f881085ef5e81dc677c110bdbe3462bacb9745d Mon Sep 17 00:00:00 2001 From: Massimo Date: Tue, 30 Oct 2012 09:42:03 -0500 Subject: [PATCH 16/17] fixed validator recent typo --- VERSION | 2 +- gluon/validators.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 906ddeb9..d2c68af0 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-29 22:25:15) stable +Version 2.2.1 (2012-10-30 09:41:34) stable diff --git a/gluon/validators.py b/gluon/validators.py index ff3c0509..0280126a 100644 --- a/gluon/validators.py +++ b/gluon/validators.py @@ -778,7 +778,7 @@ class IS_FLOAT_IN_RANGE(Validator): return (value, self.error_message) def formatter(self, value): - if values is None: + if value is None: return None return str2dec(value).replace('.', self.dot) From 96eee74f5686de09f0eebc4806ea9e534015ac75 Mon Sep 17 00:00:00 2001 From: Massimo Date: Tue, 30 Oct 2012 11:09:50 -0500 Subject: [PATCH 17/17] fixed sync languages, thanks Yair --- VERSION | 2 +- scripts/sync_languages.py | 71 +++++++++++++++++++++------------------ 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/VERSION b/VERSION index d2c68af0..d6b339bd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.2.1 (2012-10-30 09:41:34) stable +Version 2.2.1 (2012-10-30 11:09:19) stable diff --git a/scripts/sync_languages.py b/scripts/sync_languages.py index ff36c779..b3212d5b 100755 --- a/scripts/sync_languages.py +++ b/scripts/sync_languages.py @@ -7,14 +7,10 @@ import sys import shutil import os -from gluon.languages import findT, utf8_repr +from gluon.languages import findT sys.path.insert(0, '.') -file = sys.argv[1] -apps = sys.argv[2:] - - def sync_language(d, data): ''' this function makes sure a translated string will be prefered over an untranslated string when syncing languages between apps. when both are translated, it prefers the @@ -37,35 +33,46 @@ def sync_language(d, data): return d -d = {} -for app in apps: - path = 'applications/%s/' % app - findT(path, file) - langfile = open(os.path.join(path, 'languages', '%s.py' % file)) +def sync_main(file, apps): + d = {} + for app in apps: + path = 'applications/%s/' % app + findT(path, file) + langfile = open(os.path.join(path, 'languages', '%s.py' % file)) + try: + data = eval(langfile.read()) + finally: + langfile.close() + + d = sync_language(d, data) + + + path = 'applications/%s/' % apps[-1] + file1 = os.path.join(path, 'languages', '%s.py' % file) + + f = open(file1, 'w') try: - data = eval(langfile.read()) + f.write('# coding: utf8\n') + f.write('{\n') + keys = d.keys() + keys.sort() + for key in keys: + f.write("'''%s''':'''%s''',\n" % (key.replace("'", "\\'"), str(d[key].replace("'", "\\'")))) + f.write('}\n') finally: - langfile.close() + f.close() + + oapps = reversed(apps[:-1]) + for app in oapps: + path2 = 'applications/%s/' % app + file2 = os.path.join(path2, 'languages', '%s.py' % file) + if file1 != file2: + shutil.copyfile(file1, file2) - d = sync_language(d, data) +if __name__ == "__main__": -path = 'applications/%s/' % apps[-1] -file1 = os.path.join(path, 'languages', '%s.py' % file) + file = sys.argv[1] + apps = sys.argv[2:] -f = open(file1, 'w') -try: - f.write('# coding: utf8\n') - f.write('{\n') - keys = d.keys() - keys.sort() - for key in keys: - f.write('%s:%s,\n' % (utf8_repr(key), utf8_repr(str(d[key])))) - f.write('}\n') -finally: - f.close() - -oapps = reversed(apps[:-1]) -for app in oapps: - path2 = 'applications/%s/' % app - file2 = os.path.join(path2, 'languages', '%s.py' % file) - shutil.copyfile(file1, file2) + sync_main(file, apps) + \ No newline at end of file