[FIX] replaced <TAB> with four white space.
bzr revid: hmo@tinyerp.com-20091124144405-9mzd91chohvf0uu7
This commit is contained in:
parent
dda5ed6bb1
commit
d8ce3f1e2a
|
@ -52,10 +52,10 @@ sys.path.insert(1, _ad)
|
|||
ad_cnt=1
|
||||
for adp in ad_paths:
|
||||
if adp != _ad:
|
||||
sys.path.insert(ad_cnt, adp)
|
||||
ad_cnt+=1
|
||||
sys.path.insert(ad_cnt, adp)
|
||||
ad_cnt+=1
|
||||
|
||||
ad_paths.append(_ad) # for get_module_path
|
||||
ad_paths.append(_ad) # for get_module_path
|
||||
|
||||
# Modules already loaded
|
||||
loaded = []
|
||||
|
@ -289,7 +289,7 @@ def get_modules():
|
|||
|
||||
plist = []
|
||||
for ad in ad_paths:
|
||||
plist.extend(listdir(ad))
|
||||
plist.extend(listdir(ad))
|
||||
return list(set(plist))
|
||||
|
||||
def get_modules_with_version():
|
||||
|
@ -318,7 +318,7 @@ def upgrade_graph(graph, cr, module_list, force=None):
|
|||
mod_path = get_module_path(module)
|
||||
terp_file = get_module_resource(module, '__terp__.py')
|
||||
if not mod_path or not terp_file:
|
||||
logger.notifyChannel('init', netsvc.LOG_WARNING, 'module %s: not installable' % (module))
|
||||
logger.notifyChannel('init', netsvc.LOG_WARNING, 'module %s: not installable' % (module))
|
||||
cr.execute("update ir_module_module set state=%s where name=%s", ('uninstallable', module))
|
||||
continue
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
|
||||
# $Id$
|
||||
#
|
||||
|
|
|
@ -47,15 +47,15 @@ class ir_sequence(osv.osv):
|
|||
'number_next': fields.integer('Next Number', required=True),
|
||||
'number_increment': fields.integer('Increment Number', required=True),
|
||||
'padding' : fields.integer('Number padding', required=True),
|
||||
'condition': fields.char('Condition', size=250, help="If set, sequence will only be used in case this python expression matches, and will precede other sequences."),
|
||||
'weight': fields.integer('Weight',required=True, help="If two sequences match, the highest weight will be used.")
|
||||
'condition': fields.char('Condition', size=250, help="If set, sequence will only be used in case this python expression matches, and will precede other sequences."),
|
||||
'weight': fields.integer('Weight',required=True, help="If two sequences match, the highest weight will be used.")
|
||||
}
|
||||
_defaults = {
|
||||
'active': lambda *a: True,
|
||||
'number_increment': lambda *a: 1,
|
||||
'number_next': lambda *a: 1,
|
||||
'padding' : lambda *a : 0,
|
||||
'weight' : lambda *a: 10,
|
||||
'weight' : lambda *a: 10,
|
||||
}
|
||||
|
||||
def _process(self, s):
|
||||
|
@ -74,28 +74,28 @@ class ir_sequence(osv.osv):
|
|||
}
|
||||
|
||||
def get_id(self, cr, uid, sequence_id, test='id=%s', context=None):
|
||||
if not context:
|
||||
context = {}
|
||||
if not context:
|
||||
context = {}
|
||||
try:
|
||||
cr.execute('SELECT id, number_next, prefix, suffix, padding, condition \
|
||||
FROM ir_sequence \
|
||||
WHERE '+test+' AND active=%s ORDER BY weight DESC, length(COALESCE(condition,\'\')) DESC \
|
||||
FOR UPDATE', (sequence_id, True))
|
||||
FROM ir_sequence \
|
||||
WHERE '+test+' AND active=%s ORDER BY weight DESC, length(COALESCE(condition,\'\')) DESC \
|
||||
FOR UPDATE', (sequence_id, True))
|
||||
for res in cr.dictfetchall():
|
||||
if res['condition']:
|
||||
print "ir_seq: %s has condition:" %res['id'], res['condition'],
|
||||
try:
|
||||
bo = safe_eval(res['condition'],context)
|
||||
if not bo:
|
||||
print "not matched"
|
||||
continue
|
||||
except Exception,e:
|
||||
# it would be normal to have exceptions, because
|
||||
# the domain may contain errors
|
||||
print "Exception.\ne:",e
|
||||
print "Context:", context
|
||||
continue
|
||||
print "Matched!"
|
||||
if res['condition']:
|
||||
print "ir_seq: %s has condition:" %res['id'], res['condition'],
|
||||
try:
|
||||
bo = safe_eval(res['condition'],context)
|
||||
if not bo:
|
||||
print "not matched"
|
||||
continue
|
||||
except Exception,e:
|
||||
# it would be normal to have exceptions, because
|
||||
# the domain may contain errors
|
||||
print "Exception.\ne:",e
|
||||
print "Context:", context
|
||||
continue
|
||||
print "Matched!"
|
||||
|
||||
cr.execute('UPDATE ir_sequence SET number_next=number_next+number_increment WHERE id=%s AND active=%s', (res['id'], True))
|
||||
if res['number_next']:
|
||||
|
|
|
@ -147,7 +147,7 @@ showpage'''
|
|||
inst_id = inst_id[0]
|
||||
graph = pydot.Dot(fontsize='16', label="""\\\n\\nWorkflow: %s\\n OSV: %s""" % (wkfinfo['name'],wkfinfo['osv']),
|
||||
size='7.3, 10.1', center='1', ratio='auto', rotate='0', rankdir='TB',
|
||||
ordering='out'
|
||||
ordering='out'
|
||||
)
|
||||
graph_instance_get(cr, graph, inst_id, data.get('nested', False))
|
||||
ps_string = graph.create(prog='dot', format='ps')
|
||||
|
|
|
@ -29,37 +29,37 @@ class ir_module_reference_print(report_sxw.rml_parse):
|
|||
'time': time,
|
||||
'findobj': self._object_find,
|
||||
'objdoc': self._object_doc,
|
||||
'objdoc2': self._object_doc2,
|
||||
'objdoc2': self._object_doc2,
|
||||
'findflds': self._fields_find,
|
||||
})
|
||||
def _object_doc(self, obj):
|
||||
modobj = self.pool.get(obj)
|
||||
strdocs= modobj.__doc__
|
||||
if not strdocs:
|
||||
return None
|
||||
else:
|
||||
strdocs=strdocs.strip().splitlines(True)
|
||||
res = ''
|
||||
for stre in strdocs:
|
||||
if not stre or stre.isspace():
|
||||
break
|
||||
res += stre
|
||||
strdocs= modobj.__doc__
|
||||
if not strdocs:
|
||||
return None
|
||||
else:
|
||||
strdocs=strdocs.strip().splitlines(True)
|
||||
res = ''
|
||||
for stre in strdocs:
|
||||
if not stre or stre.isspace():
|
||||
break
|
||||
res += stre
|
||||
return res
|
||||
|
||||
def _object_doc2(self, obj):
|
||||
modobj = self.pool.get(obj)
|
||||
strdocs= modobj.__doc__
|
||||
if not strdocs:
|
||||
return None
|
||||
else:
|
||||
strdocs=strdocs.strip().splitlines(True)
|
||||
res = []
|
||||
fou = False
|
||||
for stre in strdocs:
|
||||
if fou:
|
||||
res.append(stre.strip())
|
||||
elif not stre or stre.isspace():
|
||||
fou = True
|
||||
strdocs= modobj.__doc__
|
||||
if not strdocs:
|
||||
return None
|
||||
else:
|
||||
strdocs=strdocs.strip().splitlines(True)
|
||||
res = []
|
||||
fou = False
|
||||
for stre in strdocs:
|
||||
if fou:
|
||||
res.append(stre.strip())
|
||||
elif not stre or stre.isspace():
|
||||
fou = True
|
||||
return res
|
||||
|
||||
def _object_find(self, module):
|
||||
|
|
|
@ -80,7 +80,7 @@ class wizard_export_lang(osv.osv_memory):
|
|||
) ),
|
||||
}
|
||||
_defaults = { 'state': lambda *a: 'choose',
|
||||
'name': lambda *a: 'lang.tar.gz'
|
||||
'name': lambda *a: 'lang.tar.gz'
|
||||
}
|
||||
wizard_export_lang()
|
||||
|
||||
|
|
|
@ -72,10 +72,10 @@ class groups(osv.osv):
|
|||
return gid
|
||||
|
||||
def copy(self, cr, uid, id, default={}, context={}, done_list=[], local=False):
|
||||
group = self.browse(cr, uid, id, context=context)
|
||||
group = self.browse(cr, uid, id, context=context)
|
||||
default = default.copy()
|
||||
if not 'name' in default:
|
||||
default['name'] = group['name']
|
||||
if not 'name' in default:
|
||||
default['name'] = group['name']
|
||||
default['name'] = default['name'] + _(' (copy)')
|
||||
return super(groups, self).copy(cr, uid, id, default, context=context)
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ import release
|
|||
class Service(object):
|
||||
""" Base class for *Local* services
|
||||
|
||||
Functionality here is trusted, no authentication.
|
||||
Functionality here is trusted, no authentication.
|
||||
"""
|
||||
_services = {}
|
||||
def __init__(self, name, audience=''):
|
||||
|
@ -48,11 +48,11 @@ class Service(object):
|
|||
self._methods = {}
|
||||
|
||||
def joinGroup(self, name):
|
||||
raise Exception("No group for local services")
|
||||
raise Exception("No group for local services")
|
||||
#GROUPS.setdefault(name, {})[self.__name] = self
|
||||
|
||||
def service_exist(self,name):
|
||||
return Service._services.has_key(name)
|
||||
return Service._services.has_key(name)
|
||||
|
||||
def exportMethod(self, method):
|
||||
if callable(method):
|
||||
|
@ -67,9 +67,9 @@ class Service(object):
|
|||
class LocalService(object):
|
||||
""" Proxy for local services.
|
||||
|
||||
Any instance of this class will behave like the single instance
|
||||
of Service(name)
|
||||
"""
|
||||
Any instance of this class will behave like the single instance
|
||||
of Service(name)
|
||||
"""
|
||||
def __init__(self, name):
|
||||
self.__name = name
|
||||
try:
|
||||
|
@ -158,12 +158,12 @@ def init_logger():
|
|||
dirname = os.path.dirname(logf)
|
||||
if dirname and not os.path.isdir(dirname):
|
||||
os.makedirs(dirname)
|
||||
if tools.config['logrotate'] is not False:
|
||||
if tools.config['logrotate'] is not False:
|
||||
handler = logging.handlers.TimedRotatingFileHandler(logf,'D',1,30)
|
||||
elif os.name == 'posix':
|
||||
handler = logging.handlers.WatchedFileHandler(logf)
|
||||
else:
|
||||
handler = logging.handlers.FileHandler(logf)
|
||||
elif os.name == 'posix':
|
||||
handler = logging.handlers.WatchedFileHandler(logf)
|
||||
else:
|
||||
handler = logging.handlers.FileHandler(logf)
|
||||
except Exception, ex:
|
||||
sys.stderr.write("ERROR: couldn't create the logfile directory. Logging to the standard output.\n")
|
||||
handler = logging.StreamHandler(sys.stdout)
|
||||
|
@ -223,27 +223,27 @@ class Logger(object):
|
|||
if isinstance(msg, Exception):
|
||||
msg = tools.exception_to_unicode(msg)
|
||||
|
||||
try:
|
||||
msg = tools.ustr(msg).strip()
|
||||
try:
|
||||
msg = tools.ustr(msg).strip()
|
||||
if level in (LOG_ERROR,LOG_CRITICAL) and tools.config.get_misc('debug','env_info',True):
|
||||
msg = common().exp_get_server_environment() + "\n" + msg
|
||||
|
||||
result = msg.split('\n')
|
||||
except UnicodeDecodeError:
|
||||
result = msg.strip().split('\n')
|
||||
try:
|
||||
except UnicodeDecodeError:
|
||||
result = msg.strip().split('\n')
|
||||
try:
|
||||
if len(result)>1:
|
||||
for idx, s in enumerate(result):
|
||||
level_method('[%02d]: %s' % (idx+1, s,))
|
||||
elif result:
|
||||
level_method(result[0])
|
||||
except IOError,e:
|
||||
# TODO: perhaps reset the logger streams?
|
||||
#if logrotate closes our files, we end up here..
|
||||
pass
|
||||
except:
|
||||
# better ignore the exception and carry on..
|
||||
pass
|
||||
except IOError,e:
|
||||
# TODO: perhaps reset the logger streams?
|
||||
#if logrotate closes our files, we end up here..
|
||||
pass
|
||||
except:
|
||||
# better ignore the exception and carry on..
|
||||
pass
|
||||
|
||||
def set_loglevel(self, level):
|
||||
log = logging.getLogger()
|
||||
|
@ -364,10 +364,10 @@ class OpenERPDispatcher:
|
|||
self.log('service', service_name)
|
||||
self.log('method', method)
|
||||
self.log('params', params)
|
||||
if hasattr(self,'auth_provider'):
|
||||
auth = self.auth_provider
|
||||
else:
|
||||
auth = None
|
||||
if hasattr(self,'auth_provider'):
|
||||
auth = self.auth_provider
|
||||
else:
|
||||
auth = None
|
||||
result = ExportService.getService(service_name).dispatch(method, auth, params)
|
||||
self.log('result', result)
|
||||
# We shouldn't marshall None,
|
||||
|
|
|
@ -56,8 +56,8 @@ __version__ = release.version
|
|||
# We DON't log this using the standard logger, because we might mess
|
||||
# with the logfile's permissions. Just do a quick exit here.
|
||||
if pwd.getpwuid(os.getuid())[0] == 'root' :
|
||||
sys.stderr.write("Attempted to run OpenERP server as root. This is not good, aborting.\n")
|
||||
sys.exit(1)
|
||||
sys.stderr.write("Attempted to run OpenERP server as root. This is not good, aborting.\n")
|
||||
sys.exit(1)
|
||||
|
||||
#----------------------------------------------------------
|
||||
# get logger
|
||||
|
@ -114,13 +114,13 @@ import addons
|
|||
import service.http_server
|
||||
|
||||
if not ( tools.config["stop_after_init"] or \
|
||||
tools.config["translate_in"] or \
|
||||
tools.config["translate_out"] ):
|
||||
service.http_server.init_servers()
|
||||
service.http_server.init_xmlrpc()
|
||||
tools.config["translate_in"] or \
|
||||
tools.config["translate_out"] ):
|
||||
service.http_server.init_servers()
|
||||
service.http_server.init_xmlrpc()
|
||||
|
||||
import service.netrpc_server
|
||||
service.netrpc_server.init_servers()
|
||||
import service.netrpc_server
|
||||
service.netrpc_server.init_servers()
|
||||
|
||||
if tools.config['db_name']:
|
||||
for db in tools.config['db_name'].split(','):
|
||||
|
|
|
@ -585,14 +585,14 @@ class many2many(_column):
|
|||
|
||||
|
||||
def get_nice_size(a):
|
||||
(x,y) = a
|
||||
if isinstance(y, (int,long)):
|
||||
size = y
|
||||
elif y:
|
||||
y = len(y)
|
||||
else:
|
||||
y = 0
|
||||
return (x, tools.human_size(size))
|
||||
(x,y) = a
|
||||
if isinstance(y, (int,long)):
|
||||
size = y
|
||||
elif y:
|
||||
y = len(y)
|
||||
else:
|
||||
y = 0
|
||||
return (x, tools.human_size(size))
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Function fields
|
||||
|
|
|
@ -205,9 +205,9 @@ class browse_record(object):
|
|||
d[n].set_value(self._cr, self._uid, d[n], self, f, lang_obj)
|
||||
|
||||
|
||||
if not datas:
|
||||
# Where did those ids come from? Perhaps old entries in ir_model_data?
|
||||
raise except_orm('NoDataError', 'Field %s in %s%s'%(name,self._table_name,str(ids)))
|
||||
if not datas:
|
||||
# Where did those ids come from? Perhaps old entries in ir_model_data?
|
||||
raise except_orm('NoDataError', 'Field %s in %s%s'%(name,self._table_name,str(ids)))
|
||||
# create browse records for 'remote' objects
|
||||
for data in datas:
|
||||
for n, f in ffields:
|
||||
|
@ -228,12 +228,12 @@ class browse_record(object):
|
|||
elif f._type in ('one2many', 'many2many') and len(data[n]):
|
||||
data[n] = self._list_class([browse_record(self._cr, self._uid, id, self._table.pool.get(f._obj), self._cache, context=self._context, list_class=self._list_class, fields_process=self._fields_process) for id in data[n]], self._context)
|
||||
self._data[data['id']].update(data)
|
||||
if not name in self._data[self._id]:
|
||||
#how did this happen?
|
||||
logger = netsvc.Logger()
|
||||
logger.notifyChannel("browse_record", netsvc.LOG_ERROR,"Ffields: %s, datas: %s"%(str(fffields),str(datas)))
|
||||
logger.notifyChannel("browse_record", netsvc.LOG_ERROR,"Data: %s, Table: %s"%(str(self._data[self._id]),str(self._table)))
|
||||
raise AttributeError(_('Unknown attribute %s in %s ') % (str(name),self._table_name))
|
||||
if not name in self._data[self._id]:
|
||||
#how did this happen?
|
||||
logger = netsvc.Logger()
|
||||
logger.notifyChannel("browse_record", netsvc.LOG_ERROR,"Ffields: %s, datas: %s"%(str(fffields),str(datas)))
|
||||
logger.notifyChannel("browse_record", netsvc.LOG_ERROR,"Data: %s, Table: %s"%(str(self._data[self._id]),str(self._table)))
|
||||
raise AttributeError(_('Unknown attribute %s in %s ') % (str(name),self._table_name))
|
||||
return self._data[self._id][name]
|
||||
|
||||
def __getattr__(self, name):
|
||||
|
@ -671,10 +671,10 @@ class orm_template(object):
|
|||
else:
|
||||
module, xml_id = current_module, line[i]
|
||||
id = ir_model_data_obj._get_id(cr, uid, module, xml_id)
|
||||
res_res_id = ir_model_data_obj.read(cr, uid, [id],
|
||||
['res_id'])
|
||||
if res_res_id:
|
||||
res_id = res_res_id[0]['res_id']
|
||||
res_res_id = ir_model_data_obj.read(cr, uid, [id],
|
||||
['res_id'])
|
||||
if res_res_id:
|
||||
res_id = res_res_id[0]['res_id']
|
||||
row[field[-1][:-3]] = res_id or False
|
||||
continue
|
||||
if (len(field) == len(prefix)+1) and \
|
||||
|
@ -962,7 +962,7 @@ class orm_template(object):
|
|||
and getattr(self._columns[f], arg):
|
||||
res[f][arg] = getattr(self._columns[f], arg)
|
||||
|
||||
#TODO: optimize
|
||||
#TODO: optimize
|
||||
res_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'field', context.get('lang', False) or 'en_US')
|
||||
if res_trans:
|
||||
res[f]['string'] = res_trans
|
||||
|
@ -1373,7 +1373,7 @@ class orm_template(object):
|
|||
result['name'] = 'default'
|
||||
result['field_parent'] = False
|
||||
result['view_id'] = 0
|
||||
|
||||
|
||||
xarch, xfields = self.__view_look_dom_arch(cr, user, result['arch'], view_id, context=context)
|
||||
result['arch'] = xarch
|
||||
result['fields'] = xfields
|
||||
|
@ -1454,7 +1454,7 @@ class orm_template(object):
|
|||
self.pool.get('ir.model.access').check(cr, uid, 'ir.translation', 'read', context=context)
|
||||
if not fields:
|
||||
fields = self._columns.keys() + self._inherit_fields.keys()
|
||||
#FIXME: collect all calls to _get_source into one SQL call.
|
||||
#FIXME: collect all calls to _get_source into one SQL call.
|
||||
for lang in langs:
|
||||
res[lang] = {'code': lang}
|
||||
for f in fields:
|
||||
|
@ -1476,7 +1476,7 @@ class orm_template(object):
|
|||
|
||||
def write_string(self, cr, uid, id, langs, vals, context=None):
|
||||
self.pool.get('ir.model.access').check(cr, uid, 'ir.translation', 'write', context=context)
|
||||
#FIXME: try to only call the translation in one SQL
|
||||
#FIXME: try to only call the translation in one SQL
|
||||
for lang in langs:
|
||||
for field in vals:
|
||||
if field in self._columns:
|
||||
|
@ -1897,20 +1897,20 @@ class orm(orm_template):
|
|||
"AND c.oid=a.attrelid " \
|
||||
"AND a.atttypid=t.oid", (self._table, k))
|
||||
res = cr.dictfetchall()
|
||||
if not res and hasattr(f,'oldname'):
|
||||
cr.execute("SELECT c.relname,a.attname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,t.typname,CASE WHEN a.attlen=-1 THEN a.atttypmod-4 ELSE a.attlen END as size " \
|
||||
"FROM pg_class c,pg_attribute a,pg_type t " \
|
||||
"WHERE c.relname=%s " \
|
||||
"AND a.attname=%s " \
|
||||
"AND c.oid=a.attrelid " \
|
||||
"AND a.atttypid=t.oid", (self._table, f.oldname))
|
||||
res_old = cr.dictfetchall()
|
||||
logger.notifyChannel('orm', netsvc.LOG_DEBUG, 'trying to rename %s(%s) to %s'% (self._table, f.oldname, k))
|
||||
if res_old and len(res_old)==1:
|
||||
cr.execute('ALTER TABLE "%s" RENAME "%s" TO "%s"' % ( self._table,f.oldname, k))
|
||||
res = res_old
|
||||
res[0]['attname'] = k
|
||||
|
||||
if not res and hasattr(f,'oldname'):
|
||||
cr.execute("SELECT c.relname,a.attname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,t.typname,CASE WHEN a.attlen=-1 THEN a.atttypmod-4 ELSE a.attlen END as size " \
|
||||
"FROM pg_class c,pg_attribute a,pg_type t " \
|
||||
"WHERE c.relname=%s " \
|
||||
"AND a.attname=%s " \
|
||||
"AND c.oid=a.attrelid " \
|
||||
"AND a.atttypid=t.oid", (self._table, f.oldname))
|
||||
res_old = cr.dictfetchall()
|
||||
logger.notifyChannel('orm', netsvc.LOG_DEBUG, 'trying to rename %s(%s) to %s'% (self._table, f.oldname, k))
|
||||
if res_old and len(res_old)==1:
|
||||
cr.execute('ALTER TABLE "%s" RENAME "%s" TO "%s"' % ( self._table,f.oldname, k))
|
||||
res = res_old
|
||||
res[0]['attname'] = k
|
||||
|
||||
if not res:
|
||||
if not isinstance(f, fields.function) or f.store:
|
||||
|
||||
|
@ -2342,7 +2342,7 @@ class orm(orm_template):
|
|||
continue
|
||||
if self._columns[f].translate:
|
||||
ids = map(lambda x: x['id'], res)
|
||||
#TODO: optimize out of this loop
|
||||
#TODO: optimize out of this loop
|
||||
res_trans = self.pool.get('ir.translation')._get_ids(cr, user, self._name+','+f, 'model', context.get('lang', False) or 'en_US', ids)
|
||||
for r in res:
|
||||
r[f] = res_trans.get(r['id'], False) or r[f]
|
||||
|
@ -2658,7 +2658,7 @@ class orm(orm_template):
|
|||
'where id in ('+ids_str+')', upd1)
|
||||
|
||||
if totranslate:
|
||||
# TODO: optimize
|
||||
# TODO: optimize
|
||||
for f in direct:
|
||||
if self._columns[f].translate:
|
||||
src_trans = self.pool.get(self._name).read(cr,user,ids,[f])
|
||||
|
@ -3189,7 +3189,7 @@ class orm(orm_template):
|
|||
data[f] = [(6, 0, data[f])]
|
||||
|
||||
trans_obj = self.pool.get('ir.translation')
|
||||
#TODO: optimize translations
|
||||
#TODO: optimize translations
|
||||
trans_name=''
|
||||
for f in fields:
|
||||
trans_flag=True
|
||||
|
|
|
@ -80,7 +80,7 @@ class report_rml(report_int):
|
|||
'html': self.create_html,
|
||||
'raw': self.create_raw,
|
||||
'sxw': self.create_sxw,
|
||||
'txt': self.create_txt,
|
||||
'txt': self.create_txt,
|
||||
'odt': self.create_odt,
|
||||
'html2html' : self.create_html2html,
|
||||
'makohtml2html' :self.create_makohtml2html,
|
||||
|
|
|
@ -22,28 +22,28 @@
|
|||
|
||||
|
||||
CustomTTFonts = [ ('Helvetica',"DejaVu Sans", "DejaVuSans.ttf", 'normal'),
|
||||
('Helvetica',"DejaVu Sans Bold", "DejaVuSans-Bold.ttf", 'bold'),
|
||||
('Helvetica',"DejaVu Sans Oblique", "DejaVuSans-Oblique.ttf", 'italic'),
|
||||
('Helvetica',"DejaVu Sans BoldOblique", "DejaVuSans-BoldOblique.ttf", 'bolditalic'),
|
||||
('Times',"Liberation Serif", "LiberationSerif-Regular.ttf", 'normal'),
|
||||
('Times',"Liberation Serif Bold", "LiberationSerif-Bold.ttf", 'bold'),
|
||||
('Times',"Liberation Serif Italic", "LiberationSerif-Italic.ttf", 'italic'),
|
||||
('Times',"Liberation Serif BoldItalic", "LiberationSerif-BoldItalic.ttf", 'bolditalic'),
|
||||
('Times-Roman',"Liberation Serif", "LiberationSerif-Regular.ttf", 'normal'),
|
||||
('Times-Roman',"Liberation Serif Bold", "LiberationSerif-Bold.ttf", 'bold'),
|
||||
('Times-Roman',"Liberation Serif Italic", "LiberationSerif-Italic.ttf", 'italic'),
|
||||
('Times-Roman',"Liberation Serif BoldItalic", "LiberationSerif-BoldItalic.ttf", 'bolditalic'),
|
||||
('ZapfDingbats',"DejaVu Serif", "DejaVuSerif.ttf", 'normal'),
|
||||
('ZapfDingbats',"DejaVu Serif Bold", "DejaVuSerif-Bold.ttf", 'bold'),
|
||||
('ZapfDingbats',"DejaVu Serif Italic", "DejaVuSerif-Italic.ttf", 'italic'),
|
||||
('ZapfDingbats',"DejaVu Serif BoldItalic", "DejaVuSerif-BoldItalic.ttf", 'bolditalic'),
|
||||
('Courier',"FreeMono", "FreeMono.ttf", 'normal'),
|
||||
('Courier',"FreeMono Bold", "FreeMonoBold.ttf", 'bold'),
|
||||
('Courier',"FreeMono Oblique", "FreeMonoOblique.ttf", 'italic'),
|
||||
('Courier',"FreeMono BoldOblique", "FreeMonoBoldOblique.ttf", 'bolditalic'),]
|
||||
('Helvetica',"DejaVu Sans Bold", "DejaVuSans-Bold.ttf", 'bold'),
|
||||
('Helvetica',"DejaVu Sans Oblique", "DejaVuSans-Oblique.ttf", 'italic'),
|
||||
('Helvetica',"DejaVu Sans BoldOblique", "DejaVuSans-BoldOblique.ttf", 'bolditalic'),
|
||||
('Times',"Liberation Serif", "LiberationSerif-Regular.ttf", 'normal'),
|
||||
('Times',"Liberation Serif Bold", "LiberationSerif-Bold.ttf", 'bold'),
|
||||
('Times',"Liberation Serif Italic", "LiberationSerif-Italic.ttf", 'italic'),
|
||||
('Times',"Liberation Serif BoldItalic", "LiberationSerif-BoldItalic.ttf", 'bolditalic'),
|
||||
('Times-Roman',"Liberation Serif", "LiberationSerif-Regular.ttf", 'normal'),
|
||||
('Times-Roman',"Liberation Serif Bold", "LiberationSerif-Bold.ttf", 'bold'),
|
||||
('Times-Roman',"Liberation Serif Italic", "LiberationSerif-Italic.ttf", 'italic'),
|
||||
('Times-Roman',"Liberation Serif BoldItalic", "LiberationSerif-BoldItalic.ttf", 'bolditalic'),
|
||||
('ZapfDingbats',"DejaVu Serif", "DejaVuSerif.ttf", 'normal'),
|
||||
('ZapfDingbats',"DejaVu Serif Bold", "DejaVuSerif-Bold.ttf", 'bold'),
|
||||
('ZapfDingbats',"DejaVu Serif Italic", "DejaVuSerif-Italic.ttf", 'italic'),
|
||||
('ZapfDingbats',"DejaVu Serif BoldItalic", "DejaVuSerif-BoldItalic.ttf", 'bolditalic'),
|
||||
('Courier',"FreeMono", "FreeMono.ttf", 'normal'),
|
||||
('Courier',"FreeMono Bold", "FreeMonoBold.ttf", 'bold'),
|
||||
('Courier',"FreeMono Oblique", "FreeMonoOblique.ttf", 'italic'),
|
||||
('Courier',"FreeMono BoldOblique", "FreeMonoBoldOblique.ttf", 'bolditalic'),]
|
||||
|
||||
def SetCustomFonts(rmldoc):
|
||||
for name, font, fname, mode in CustomTTFonts:
|
||||
rmldoc.setTTFontMapping(name, font,fname, mode)
|
||||
for name, font, fname, mode in CustomTTFonts:
|
||||
rmldoc.setTTFontMapping(name, font,fname, mode)
|
||||
|
||||
#eof
|
||||
#eof
|
||||
|
|
|
@ -167,21 +167,21 @@ class _rml_doc(object):
|
|||
from reportlab.lib.fonts import addMapping
|
||||
from reportlab.pdfbase import pdfmetrics
|
||||
from reportlab.pdfbase.ttfonts import TTFont
|
||||
|
||||
pdfmetrics.registerFont(TTFont(fontname, filename ))
|
||||
if (mode == 'all'):
|
||||
addMapping(face, 0, 0, fontname) #normal
|
||||
addMapping(face, 0, 1, fontname) #italic
|
||||
addMapping(face, 1, 0, fontname) #bold
|
||||
addMapping(face, 1, 1, fontname) #italic and bold
|
||||
elif (mode== 'normal') or (mode == 'regular'):
|
||||
addMapping(face, 0, 0, fontname) #normal
|
||||
elif (mode == 'italic'):
|
||||
addMapping(face, 0, 1, fontname) #italic
|
||||
elif (mode == 'bold'):
|
||||
addMapping(face, 1, 0, fontname) #bold
|
||||
elif (mode == 'bolditalic'):
|
||||
addMapping(face, 1, 1, fontname) #italic and bold
|
||||
|
||||
pdfmetrics.registerFont(TTFont(fontname, filename ))
|
||||
if (mode == 'all'):
|
||||
addMapping(face, 0, 0, fontname) #normal
|
||||
addMapping(face, 0, 1, fontname) #italic
|
||||
addMapping(face, 1, 0, fontname) #bold
|
||||
addMapping(face, 1, 1, fontname) #italic and bold
|
||||
elif (mode== 'normal') or (mode == 'regular'):
|
||||
addMapping(face, 0, 0, fontname) #normal
|
||||
elif (mode == 'italic'):
|
||||
addMapping(face, 0, 1, fontname) #italic
|
||||
elif (mode == 'bold'):
|
||||
addMapping(face, 1, 0, fontname) #bold
|
||||
elif (mode == 'bolditalic'):
|
||||
addMapping(face, 1, 1, fontname) #italic and bold
|
||||
|
||||
def _textual_image(self, node):
|
||||
rc = ''
|
||||
|
@ -797,10 +797,10 @@ def parseNode(rml, localcontext = {},fout=None, images={}, path='.',title=None):
|
|||
r = _rml_doc(node, localcontext, images, path, title=title)
|
||||
#try to override some font mappings
|
||||
try:
|
||||
from customfonts import SetCustomFonts
|
||||
SetCustomFonts(r)
|
||||
from customfonts import SetCustomFonts
|
||||
SetCustomFonts(r)
|
||||
except:
|
||||
pass
|
||||
pass
|
||||
fp = cStringIO.StringIO()
|
||||
r.render(fp)
|
||||
return fp.getvalue()
|
||||
|
@ -811,10 +811,10 @@ def parseString(rml, localcontext = {},fout=None, images={}, path='.',title=None
|
|||
|
||||
#try to override some font mappings
|
||||
try:
|
||||
from customfonts import SetCustomFonts
|
||||
SetCustomFonts(r)
|
||||
from customfonts import SetCustomFonts
|
||||
SetCustomFonts(r)
|
||||
except:
|
||||
pass
|
||||
pass
|
||||
|
||||
if fout:
|
||||
fp = file(fout,'wb')
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
|
||||
# $Id$
|
||||
#
|
||||
|
@ -49,93 +49,93 @@ import utils
|
|||
Font_size= 10.0
|
||||
|
||||
def verbose(text):
|
||||
sys.stderr.write(text+"\n");
|
||||
sys.stderr.write(text+"\n");
|
||||
|
||||
class textbox():
|
||||
"""A box containing plain text.
|
||||
It can have an offset, in chars.
|
||||
Lines can be either text strings, or textbox'es, recursively.
|
||||
"""
|
||||
def __init__(self,x=0, y=0):
|
||||
self.posx = x
|
||||
self.posy = y
|
||||
self.lines = []
|
||||
self.curline = ''
|
||||
self.endspace = False
|
||||
|
||||
def newline(self):
|
||||
if isinstance(self.curline, textbox):
|
||||
self.lines.extend(self.curline.renderlines())
|
||||
else:
|
||||
self.lines.append(self.curline)
|
||||
self.curline = ''
|
||||
|
||||
def fline(self):
|
||||
if isinstance(self.curline, textbox):
|
||||
self.lines.extend(self.curline.renderlines())
|
||||
elif len(self.curline):
|
||||
self.lines.append(self.curline)
|
||||
self.curline = ''
|
||||
|
||||
def appendtxt(self,txt):
|
||||
"""Append some text to the current line.
|
||||
Mimic the HTML behaviour, where all whitespace evaluates to
|
||||
a single space """
|
||||
if not txt:
|
||||
return
|
||||
bs = es = False
|
||||
if txt[0].isspace():
|
||||
bs = True
|
||||
if txt[len(txt)-1].isspace():
|
||||
es = True
|
||||
if bs and not self.endspace:
|
||||
self.curline += " "
|
||||
self.curline += txt.strip().replace("\n"," ").replace("\t"," ")
|
||||
if es:
|
||||
self.curline += " "
|
||||
self.endspace = es
|
||||
"""A box containing plain text.
|
||||
It can have an offset, in chars.
|
||||
Lines can be either text strings, or textbox'es, recursively.
|
||||
"""
|
||||
def __init__(self,x=0, y=0):
|
||||
self.posx = x
|
||||
self.posy = y
|
||||
self.lines = []
|
||||
self.curline = ''
|
||||
self.endspace = False
|
||||
|
||||
def newline(self):
|
||||
if isinstance(self.curline, textbox):
|
||||
self.lines.extend(self.curline.renderlines())
|
||||
else:
|
||||
self.lines.append(self.curline)
|
||||
self.curline = ''
|
||||
|
||||
def fline(self):
|
||||
if isinstance(self.curline, textbox):
|
||||
self.lines.extend(self.curline.renderlines())
|
||||
elif len(self.curline):
|
||||
self.lines.append(self.curline)
|
||||
self.curline = ''
|
||||
|
||||
def appendtxt(self,txt):
|
||||
"""Append some text to the current line.
|
||||
Mimic the HTML behaviour, where all whitespace evaluates to
|
||||
a single space """
|
||||
if not txt:
|
||||
return
|
||||
bs = es = False
|
||||
if txt[0].isspace():
|
||||
bs = True
|
||||
if txt[len(txt)-1].isspace():
|
||||
es = True
|
||||
if bs and not self.endspace:
|
||||
self.curline += " "
|
||||
self.curline += txt.strip().replace("\n"," ").replace("\t"," ")
|
||||
if es:
|
||||
self.curline += " "
|
||||
self.endspace = es
|
||||
|
||||
def rendertxt(self,xoffset=0):
|
||||
result = ''
|
||||
lineoff = ""
|
||||
for i in range(self.posy):
|
||||
result +="\n"
|
||||
for i in range(self.posx+xoffset):
|
||||
lineoff+=" "
|
||||
for l in self.lines:
|
||||
result+= lineoff+ l +"\n"
|
||||
return result
|
||||
|
||||
def renderlines(self,pad=0):
|
||||
"""Returns a list of lines, from the current object
|
||||
pad: all lines must be at least pad characters.
|
||||
"""
|
||||
result = []
|
||||
lineoff = ""
|
||||
for i in range(self.posx):
|
||||
lineoff+=" "
|
||||
for l in self.lines:
|
||||
lpad = ""
|
||||
if pad and len(l) < pad :
|
||||
for i in range(pad - len(l)):
|
||||
lpad += " "
|
||||
#elif pad and len(l) > pad ?
|
||||
result.append(lineoff+ l+lpad)
|
||||
return result
|
||||
|
||||
|
||||
def haplines(self,arr,offset,cc= ''):
|
||||
""" Horizontaly append lines
|
||||
"""
|
||||
while (len(self.lines) < len(arr)):
|
||||
self.lines.append("")
|
||||
|
||||
for i in range(len(self.lines)):
|
||||
while (len(self.lines[i]) < offset):
|
||||
self.lines[i] += " "
|
||||
for i in range(len(arr)):
|
||||
self.lines[i] += cc +arr[i]
|
||||
|
||||
def rendertxt(self,xoffset=0):
|
||||
result = ''
|
||||
lineoff = ""
|
||||
for i in range(self.posy):
|
||||
result +="\n"
|
||||
for i in range(self.posx+xoffset):
|
||||
lineoff+=" "
|
||||
for l in self.lines:
|
||||
result+= lineoff+ l +"\n"
|
||||
return result
|
||||
|
||||
def renderlines(self,pad=0):
|
||||
"""Returns a list of lines, from the current object
|
||||
pad: all lines must be at least pad characters.
|
||||
"""
|
||||
result = []
|
||||
lineoff = ""
|
||||
for i in range(self.posx):
|
||||
lineoff+=" "
|
||||
for l in self.lines:
|
||||
lpad = ""
|
||||
if pad and len(l) < pad :
|
||||
for i in range(pad - len(l)):
|
||||
lpad += " "
|
||||
#elif pad and len(l) > pad ?
|
||||
result.append(lineoff+ l+lpad)
|
||||
return result
|
||||
|
||||
|
||||
def haplines(self,arr,offset,cc= ''):
|
||||
""" Horizontaly append lines
|
||||
"""
|
||||
while (len(self.lines) < len(arr)):
|
||||
self.lines.append("")
|
||||
|
||||
for i in range(len(self.lines)):
|
||||
while (len(self.lines[i]) < offset):
|
||||
self.lines[i] += " "
|
||||
for i in range(len(arr)):
|
||||
self.lines[i] += cc +arr[i]
|
||||
|
||||
|
||||
class _flowable(object):
|
||||
def __init__(self, template, doc,localcontext):
|
||||
|
@ -143,8 +143,8 @@ class _flowable(object):
|
|||
'1title': self._tag_title,
|
||||
'1spacer': self._tag_spacer,
|
||||
'para': self._tag_para,
|
||||
'font': self._tag_font,
|
||||
'section': self._tag_section,
|
||||
'font': self._tag_font,
|
||||
'section': self._tag_section,
|
||||
'1nextFrame': self._tag_next_frame,
|
||||
'blockTable': self._tag_table,
|
||||
'1pageBreak': self._tag_page_break,
|
||||
|
@ -152,15 +152,15 @@ class _flowable(object):
|
|||
}
|
||||
self.template = template
|
||||
self.doc = doc
|
||||
self.localcontext = localcontext
|
||||
self.nitags = []
|
||||
self.tbox = None
|
||||
self.localcontext = localcontext
|
||||
self.nitags = []
|
||||
self.tbox = None
|
||||
|
||||
def warn_nitag(self,tag):
|
||||
if tag not in self.nitags:
|
||||
verbose("Unknown tag \"%s\", please implement it." % tag)
|
||||
self.nitags.append(tag)
|
||||
|
||||
if tag not in self.nitags:
|
||||
verbose("Unknown tag \"%s\", please implement it." % tag)
|
||||
self.nitags.append(tag)
|
||||
|
||||
def _tag_page_break(self, node):
|
||||
return "\f"
|
||||
|
||||
|
@ -182,79 +182,79 @@ class _flowable(object):
|
|||
return "\n"*length
|
||||
|
||||
def _tag_table(self, node):
|
||||
self.tb.fline()
|
||||
saved_tb = self.tb
|
||||
self.tb = None
|
||||
sizes = None
|
||||
self.tb.fline()
|
||||
saved_tb = self.tb
|
||||
self.tb = None
|
||||
sizes = None
|
||||
if node.get('colWidths'):
|
||||
sizes = map(lambda x: utils.unit_get(x), node.get('colWidths').split(','))
|
||||
trs = []
|
||||
for n in utils._child_get(node,self):
|
||||
if n.tag == 'tr':
|
||||
tds = []
|
||||
for m in utils._child_get(n,self):
|
||||
if m.tag == 'td':
|
||||
self.tb = textbox()
|
||||
self.rec_render_cnodes(m)
|
||||
tds.append(self.tb)
|
||||
self.tb = None
|
||||
if len(tds):
|
||||
trs.append(tds)
|
||||
|
||||
if not sizes:
|
||||
verbose("computing table sizes..")
|
||||
for tds in trs:
|
||||
trt = textbox()
|
||||
off=0
|
||||
for i in range(len(tds)):
|
||||
p = int(sizes[i]/Font_size)
|
||||
trl = tds[i].renderlines(pad=p)
|
||||
trt.haplines(trl,off)
|
||||
off += sizes[i]/Font_size
|
||||
saved_tb.curline = trt
|
||||
saved_tb.fline()
|
||||
|
||||
self.tb = saved_tb
|
||||
trs = []
|
||||
for n in utils._child_get(node,self):
|
||||
if n.tag == 'tr':
|
||||
tds = []
|
||||
for m in utils._child_get(n,self):
|
||||
if m.tag == 'td':
|
||||
self.tb = textbox()
|
||||
self.rec_render_cnodes(m)
|
||||
tds.append(self.tb)
|
||||
self.tb = None
|
||||
if len(tds):
|
||||
trs.append(tds)
|
||||
|
||||
if not sizes:
|
||||
verbose("computing table sizes..")
|
||||
for tds in trs:
|
||||
trt = textbox()
|
||||
off=0
|
||||
for i in range(len(tds)):
|
||||
p = int(sizes[i]/Font_size)
|
||||
trl = tds[i].renderlines(pad=p)
|
||||
trt.haplines(trl,off)
|
||||
off += sizes[i]/Font_size
|
||||
saved_tb.curline = trt
|
||||
saved_tb.fline()
|
||||
|
||||
self.tb = saved_tb
|
||||
return
|
||||
|
||||
def _tag_para(self, node):
|
||||
#TODO: styles
|
||||
self.rec_render_cnodes(node)
|
||||
self.tb.newline()
|
||||
#TODO: styles
|
||||
self.rec_render_cnodes(node)
|
||||
self.tb.newline()
|
||||
|
||||
def _tag_section(self, node):
|
||||
#TODO: styles
|
||||
self.rec_render_cnodes(node)
|
||||
self.tb.newline()
|
||||
#TODO: styles
|
||||
self.rec_render_cnodes(node)
|
||||
self.tb.newline()
|
||||
|
||||
def _tag_font(self, node):
|
||||
"""We do ignore fonts.."""
|
||||
self.rec_render_cnodes(node)
|
||||
"""We do ignore fonts.."""
|
||||
self.rec_render_cnodes(node)
|
||||
|
||||
def rec_render_cnodes(self,node):
|
||||
self.tb.appendtxt(utils._process_text(self, node.text or ''))
|
||||
for n in utils._child_get(node,self):
|
||||
self.rec_render(n)
|
||||
self.tb.appendtxt(utils._process_text(self, node.tail or ''))
|
||||
self.rec_render(n)
|
||||
self.tb.appendtxt(utils._process_text(self, node.tail or ''))
|
||||
|
||||
def rec_render(self,node):
|
||||
""" Recursive render: fill outarr with text of current node
|
||||
"""
|
||||
if node.tag != None:
|
||||
if node.tag in self._tags:
|
||||
self._tags[node.tag](node)
|
||||
else:
|
||||
self.warn_nitag(node.tag)
|
||||
"""
|
||||
if node.tag != None:
|
||||
if node.tag in self._tags:
|
||||
self._tags[node.tag](node)
|
||||
else:
|
||||
self.warn_nitag(node.tag)
|
||||
|
||||
def render(self, node):
|
||||
self.tb= textbox()
|
||||
self.tb= textbox()
|
||||
#result = self.template.start()
|
||||
#result += self.template.frame_start()
|
||||
self.rec_render_cnodes(node)
|
||||
self.rec_render_cnodes(node)
|
||||
#result += self.template.frame_stop()
|
||||
#result += self.template.end()
|
||||
result = self.tb.rendertxt()
|
||||
del self.tb
|
||||
result = self.tb.rendertxt()
|
||||
del self.tb
|
||||
return result
|
||||
|
||||
class _rml_tmpl_tag(object):
|
||||
|
@ -274,12 +274,12 @@ class _rml_tmpl_frame(_rml_tmpl_tag):
|
|||
self.width = width
|
||||
self.posx = posx
|
||||
def tag_start(self):
|
||||
return "frame start"
|
||||
return "frame start"
|
||||
return '<table border="0" width="%d"><tr><td width="%d"> </td><td>' % (self.width+self.posx,self.posx)
|
||||
def tag_end(self):
|
||||
return True
|
||||
def tag_stop(self):
|
||||
return "frame stop"
|
||||
return "frame stop"
|
||||
return '</td></tr></table><br/>'
|
||||
def tag_mergeable(self):
|
||||
return False
|
||||
|
@ -301,7 +301,7 @@ class _rml_tmpl_draw_string(_rml_tmpl_tag):
|
|||
self.pos = [(self.posx, self.posy, align, utils.text_get(node), style.get('td'), style.font_size_get('td'))]
|
||||
|
||||
def tag_start(self):
|
||||
return "draw string \"%s\" @(%d,%d)..\n" %("txt",self.posx,self.posy)
|
||||
return "draw string \"%s\" @(%d,%d)..\n" %("txt",self.posx,self.posy)
|
||||
self.pos.sort()
|
||||
res = '\\table ...'
|
||||
posx = 0
|
||||
|
@ -335,7 +335,7 @@ class _rml_tmpl_draw_lines(_rml_tmpl_tag):
|
|||
self.style = style.get('hr')
|
||||
|
||||
def tag_start(self):
|
||||
return "draw lines..\n"
|
||||
return "draw lines..\n"
|
||||
if self.ok:
|
||||
return '<table border="0" cellpadding="0" cellspacing="0" width="%d"><tr><td width="%d"></td><td><hr width="100%%" style="margin:0px; %s"></td></tr></table>' % (self.posx+self.width,self.posx,self.style)
|
||||
else:
|
||||
|
@ -475,7 +475,7 @@ class _rml_template(object):
|
|||
return ''
|
||||
|
||||
def end(self):
|
||||
return "template end\n"
|
||||
return "template end\n"
|
||||
result = ''
|
||||
while not self.loop:
|
||||
result += self.frame_start()
|
||||
|
@ -498,16 +498,16 @@ class _rml_doc(object):
|
|||
#self.styles = _rml_styles(el,self.localcontext)
|
||||
|
||||
el = self.etree.findall('template')
|
||||
self.result =""
|
||||
self.result =""
|
||||
if len(el):
|
||||
pt_obj = _rml_template(self.localcontext, out, el[0], self)
|
||||
stories = utils._child_get(self.etree, self, 'story')
|
||||
for story in stories:
|
||||
if self.result:
|
||||
self.result += '\f'
|
||||
f = _flowable(pt_obj,story,self.localcontext)
|
||||
self.result += f.render(story)
|
||||
del f
|
||||
for story in stories:
|
||||
if self.result:
|
||||
self.result += '\f'
|
||||
f = _flowable(pt_obj,story,self.localcontext)
|
||||
self.result += f.render(story)
|
||||
del f
|
||||
else:
|
||||
self.result = "<cannot render w/o template>"
|
||||
self.result += '\n'
|
||||
|
|
|
@ -46,15 +46,15 @@ except ImportError:
|
|||
fcntl = None
|
||||
|
||||
try:
|
||||
from ssl import SSLError
|
||||
from ssl import SSLError
|
||||
except ImportError:
|
||||
class SSLError(Exception): pass
|
||||
class SSLError(Exception): pass
|
||||
|
||||
class ThreadedHTTPServer(ConnThreadingMixIn, SimpleXMLRPCDispatcher, HTTPServer):
|
||||
""" A threaded httpd server, with all the necessary functionality for us.
|
||||
|
||||
It also inherits the xml-rpc dispatcher, so that some xml-rpc functions
|
||||
will be available to the request handler
|
||||
It also inherits the xml-rpc dispatcher, so that some xml-rpc functions
|
||||
will be available to the request handler
|
||||
"""
|
||||
encoding = None
|
||||
allow_none = False
|
||||
|
@ -81,46 +81,46 @@ class ThreadedHTTPServer(ConnThreadingMixIn, SimpleXMLRPCDispatcher, HTTPServer)
|
|||
""" Override the error handler
|
||||
"""
|
||||
import traceback
|
||||
netsvc.Logger().notifyChannel("init", netsvc.LOG_ERROR,"Server error in request from %s:\n%s" %
|
||||
(client_address,traceback.format_exc()))
|
||||
netsvc.Logger().notifyChannel("init", netsvc.LOG_ERROR,"Server error in request from %s:\n%s" %
|
||||
(client_address,traceback.format_exc()))
|
||||
|
||||
class MultiHandler2(MultiHTTPHandler):
|
||||
def log_message(self, format, *args):
|
||||
netsvc.Logger().notifyChannel('http',netsvc.LOG_DEBUG,format % args)
|
||||
netsvc.Logger().notifyChannel('http',netsvc.LOG_DEBUG,format % args)
|
||||
|
||||
def log_error(self, format, *args):
|
||||
netsvc.Logger().notifyChannel('http',netsvc.LOG_ERROR,format % args)
|
||||
netsvc.Logger().notifyChannel('http',netsvc.LOG_ERROR,format % args)
|
||||
|
||||
|
||||
class SecureMultiHandler2(SecureMultiHTTPHandler):
|
||||
def log_message(self, format, *args):
|
||||
netsvc.Logger().notifyChannel('https',netsvc.LOG_DEBUG,format % args)
|
||||
netsvc.Logger().notifyChannel('https',netsvc.LOG_DEBUG,format % args)
|
||||
|
||||
def getcert_fnames(self):
|
||||
tc = tools.config
|
||||
fcert = tc.get_misc('httpsd','sslcert', 'ssl/server.cert')
|
||||
fkey = tc.get_misc('httpsd','sslkey', 'ssl/server.key')
|
||||
return (fcert,fkey)
|
||||
fkey = tc.get_misc('httpsd','sslkey', 'ssl/server.key')
|
||||
return (fcert,fkey)
|
||||
|
||||
def log_message(self, format, *args):
|
||||
netsvc.Logger().notifyChannel('http',netsvc.LOG_DEBUG,format % args)
|
||||
netsvc.Logger().notifyChannel('http',netsvc.LOG_DEBUG,format % args)
|
||||
|
||||
def log_error(self, format, *args):
|
||||
netsvc.Logger().notifyChannel('http',netsvc.LOG_ERROR,format % args)
|
||||
netsvc.Logger().notifyChannel('http',netsvc.LOG_ERROR,format % args)
|
||||
|
||||
class HttpDaemon(threading.Thread, netsvc.Server):
|
||||
def __init__(self, interface, port):
|
||||
threading.Thread.__init__(self)
|
||||
netsvc.Server.__init__(self)
|
||||
netsvc.Server.__init__(self)
|
||||
self.__port = port
|
||||
self.__interface = interface
|
||||
|
||||
try:
|
||||
self.server = ThreadedHTTPServer((interface, port), MultiHandler2)
|
||||
self.server.vdirs = []
|
||||
self.server.logRequests = True
|
||||
netsvc.Logger().notifyChannel("web-services", netsvc.LOG_INFO,
|
||||
"starting HTTP service at %s port %d" % (interface or '0.0.0.0', port,))
|
||||
self.server.vdirs = []
|
||||
self.server.logRequests = True
|
||||
netsvc.Logger().notifyChannel("web-services", netsvc.LOG_INFO,
|
||||
"starting HTTP service at %s port %d" % (interface or '0.0.0.0', port,))
|
||||
except Exception, e:
|
||||
netsvc.Logger().notifyChannel('httpd', netsvc.LOG_CRITICAL, "Error occur when starting the server daemon: %s" % (e,))
|
||||
raise
|
||||
|
@ -146,16 +146,16 @@ class HttpDaemon(threading.Thread, netsvc.Server):
|
|||
class HttpSDaemon(threading.Thread, netsvc.Server):
|
||||
def __init__(self, interface, port):
|
||||
threading.Thread.__init__(self)
|
||||
netsvc.Server.__init__(self)
|
||||
netsvc.Server.__init__(self)
|
||||
self.__port = port
|
||||
self.__interface = interface
|
||||
|
||||
try:
|
||||
self.server = ThreadedHTTPServer((interface, port), SecureMultiHandler2)
|
||||
self.server.vdirs = []
|
||||
self.server.logRequests = True
|
||||
netsvc.Logger().notifyChannel("web-services", netsvc.LOG_INFO,
|
||||
"starting HTTPS service at %s port %d" % (interface or '0.0.0.0', port,))
|
||||
self.server = ThreadedHTTPServer((interface, port), SecureMultiHandler2)
|
||||
self.server.vdirs = []
|
||||
self.server.logRequests = True
|
||||
netsvc.Logger().notifyChannel("web-services", netsvc.LOG_INFO,
|
||||
"starting HTTPS service at %s port %d" % (interface or '0.0.0.0', port,))
|
||||
except SSLError, e:
|
||||
netsvc.Logger().notifyChannel('httpd-ssl', netsvc.LOG_CRITICAL, "Can not load the certificate and/or the private key files")
|
||||
raise
|
||||
|
@ -184,32 +184,32 @@ httpd = None
|
|||
httpsd = None
|
||||
|
||||
def init_servers():
|
||||
global httpd, httpsd
|
||||
if tools.config.get_misc('httpd','enable', True):
|
||||
httpd = HttpDaemon(tools.config.get_misc('httpd','interface', ''), \
|
||||
tools.config.get_misc('httpd','port', 8069))
|
||||
global httpd, httpsd
|
||||
if tools.config.get_misc('httpd','enable', True):
|
||||
httpd = HttpDaemon(tools.config.get_misc('httpd','interface', ''), \
|
||||
tools.config.get_misc('httpd','port', 8069))
|
||||
|
||||
if tools.config.get_misc('httpsd','enable', False):
|
||||
httpsd = HttpSDaemon(tools.config.get_misc('httpsd','interface', ''), \
|
||||
tools.config.get_misc('httpsd','port', 8071))
|
||||
if tools.config.get_misc('httpsd','enable', False):
|
||||
httpsd = HttpSDaemon(tools.config.get_misc('httpsd','interface', ''), \
|
||||
tools.config.get_misc('httpsd','port', 8071))
|
||||
|
||||
def reg_http_service(hts, secure_only = False):
|
||||
""" Register some handler to httpd.
|
||||
hts must be an HTTPDir
|
||||
"""
|
||||
global httpd, httpsd
|
||||
if not isinstance(hts, HTTPDir):
|
||||
raise Exception("Wrong class for http service")
|
||||
|
||||
if httpd and not secure_only:
|
||||
httpd.server.vdirs.append(hts)
|
||||
|
||||
if httpsd:
|
||||
httpsd.server.vdirs.append(hts)
|
||||
|
||||
if (not httpd) and (not httpsd):
|
||||
netsvc.Logger().notifyChannel('httpd',netsvc.LOG_WARNING,"No httpd available to register service %s" % hts.path)
|
||||
return
|
||||
""" Register some handler to httpd.
|
||||
hts must be an HTTPDir
|
||||
"""
|
||||
global httpd, httpsd
|
||||
if not isinstance(hts, HTTPDir):
|
||||
raise Exception("Wrong class for http service")
|
||||
|
||||
if httpd and not secure_only:
|
||||
httpd.server.vdirs.append(hts)
|
||||
|
||||
if httpsd:
|
||||
httpsd.server.vdirs.append(hts)
|
||||
|
||||
if (not httpd) and (not httpsd):
|
||||
netsvc.Logger().notifyChannel('httpd',netsvc.LOG_WARNING,"No httpd available to register service %s" % hts.path)
|
||||
return
|
||||
|
||||
import SimpleXMLRPCServer
|
||||
class XMLRPCRequestHandler(netsvc.OpenERPDispatcher,FixSendError,SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
|
||||
|
@ -223,7 +223,7 @@ class XMLRPCRequestHandler(netsvc.OpenERPDispatcher,FixSendError,SimpleXMLRPCSer
|
|||
raise xmlrpclib.Fault(tools.exception_to_unicode(e.exception), e.traceback)
|
||||
|
||||
def log_message(self, format, *args):
|
||||
netsvc.Logger().notifyChannel('xmlrpc',netsvc.LOG_DEBUG_RPC,format % args)
|
||||
netsvc.Logger().notifyChannel('xmlrpc',netsvc.LOG_DEBUG_RPC,format % args)
|
||||
|
||||
def handle(self):
|
||||
pass
|
||||
|
@ -233,87 +233,87 @@ class XMLRPCRequestHandler(netsvc.OpenERPDispatcher,FixSendError,SimpleXMLRPCSer
|
|||
|
||||
def setup(self):
|
||||
self.connection = dummyconn()
|
||||
if not len(XMLRPCRequestHandler.rpc_paths):
|
||||
XMLRPCRequestHandler.rpc_paths = map(lambda s: '/%s' % s, netsvc.ExportService._services.keys())
|
||||
if not len(XMLRPCRequestHandler.rpc_paths):
|
||||
XMLRPCRequestHandler.rpc_paths = map(lambda s: '/%s' % s, netsvc.ExportService._services.keys())
|
||||
pass
|
||||
|
||||
|
||||
def init_xmlrpc():
|
||||
if not tools.config.get_misc('xmlrpc','enable', True):
|
||||
return
|
||||
reg_http_service(HTTPDir('/xmlrpc/',XMLRPCRequestHandler))
|
||||
# Example of http file serving:
|
||||
# reg_http_service(HTTPDir('/test/',HTTPHandler))
|
||||
netsvc.Logger().notifyChannel("web-services", netsvc.LOG_INFO,
|
||||
"Registered XML-RPC over HTTP")
|
||||
|
||||
if not tools.config.get_misc('xmlrpc','enable', True):
|
||||
return
|
||||
reg_http_service(HTTPDir('/xmlrpc/',XMLRPCRequestHandler))
|
||||
# Example of http file serving:
|
||||
# reg_http_service(HTTPDir('/test/',HTTPHandler))
|
||||
netsvc.Logger().notifyChannel("web-services", netsvc.LOG_INFO,
|
||||
"Registered XML-RPC over HTTP")
|
||||
|
||||
|
||||
class OerpAuthProxy(AuthProxy):
|
||||
""" Require basic authentication..
|
||||
|
||||
This is a copy of the BasicAuthProxy, which however checks/caches the db
|
||||
as well.
|
||||
"""
|
||||
def __init__(self,provider):
|
||||
AuthProxy.__init__(self,provider)
|
||||
self.auth_creds = {}
|
||||
self.auth_tries = 0
|
||||
self.last_auth = None
|
||||
""" Require basic authentication..
|
||||
|
||||
This is a copy of the BasicAuthProxy, which however checks/caches the db
|
||||
as well.
|
||||
"""
|
||||
def __init__(self,provider):
|
||||
AuthProxy.__init__(self,provider)
|
||||
self.auth_creds = {}
|
||||
self.auth_tries = 0
|
||||
self.last_auth = None
|
||||
|
||||
def checkRequest(self,handler,path = '/'):
|
||||
if self.auth_creds:
|
||||
return True
|
||||
auth_str = handler.headers.get('Authorization',False)
|
||||
try:
|
||||
db = handler.get_db_from_path(path)
|
||||
print "Got db:",db
|
||||
except:
|
||||
if path.startswith('/'):
|
||||
path = path[1:]
|
||||
psp= path.split('/')
|
||||
if len(psp)>1:
|
||||
db = psp[0]
|
||||
else:
|
||||
#FIXME!
|
||||
self.provider.log("Wrong path: %s, failing auth" %path)
|
||||
raise AuthRejectedExc("Authorization failed. Wrong sub-path.")
|
||||
def checkRequest(self,handler,path = '/'):
|
||||
if self.auth_creds:
|
||||
return True
|
||||
auth_str = handler.headers.get('Authorization',False)
|
||||
try:
|
||||
db = handler.get_db_from_path(path)
|
||||
print "Got db:",db
|
||||
except:
|
||||
if path.startswith('/'):
|
||||
path = path[1:]
|
||||
psp= path.split('/')
|
||||
if len(psp)>1:
|
||||
db = psp[0]
|
||||
else:
|
||||
#FIXME!
|
||||
self.provider.log("Wrong path: %s, failing auth" %path)
|
||||
raise AuthRejectedExc("Authorization failed. Wrong sub-path.")
|
||||
|
||||
if auth_str and auth_str.startswith('Basic '):
|
||||
auth_str=auth_str[len('Basic '):]
|
||||
(user,passwd) = base64.decodestring(auth_str).split(':')
|
||||
self.provider.log("Found user=\"%s\", passwd=\"***\" for db=\"%s\"" %(user,db))
|
||||
acd = self.provider.authenticate(db,user,passwd,handler.client_address)
|
||||
if acd != False:
|
||||
self.auth_creds[db] = acd
|
||||
self.last_auth=db
|
||||
return True
|
||||
if self.auth_tries > 5:
|
||||
self.provider.log("Failing authorization after 5 requests w/o password")
|
||||
raise AuthRejectedExc("Authorization failed.")
|
||||
self.auth_tries += 1
|
||||
raise AuthRequiredExc(atype = 'Basic', realm=self.provider.realm)
|
||||
if auth_str and auth_str.startswith('Basic '):
|
||||
auth_str=auth_str[len('Basic '):]
|
||||
(user,passwd) = base64.decodestring(auth_str).split(':')
|
||||
self.provider.log("Found user=\"%s\", passwd=\"***\" for db=\"%s\"" %(user,db))
|
||||
acd = self.provider.authenticate(db,user,passwd,handler.client_address)
|
||||
if acd != False:
|
||||
self.auth_creds[db] = acd
|
||||
self.last_auth=db
|
||||
return True
|
||||
if self.auth_tries > 5:
|
||||
self.provider.log("Failing authorization after 5 requests w/o password")
|
||||
raise AuthRejectedExc("Authorization failed.")
|
||||
self.auth_tries += 1
|
||||
raise AuthRequiredExc(atype = 'Basic', realm=self.provider.realm)
|
||||
|
||||
import security
|
||||
class OpenERPAuthProvider(AuthProvider):
|
||||
def __init__(self,realm = 'OpenERP User'):
|
||||
self.realm = realm
|
||||
def __init__(self,realm = 'OpenERP User'):
|
||||
self.realm = realm
|
||||
|
||||
def setupAuth(self, multi, handler):
|
||||
if not multi.sec_realms.has_key(self.realm):
|
||||
multi.sec_realms[self.realm] = OerpAuthProxy(self)
|
||||
handler.auth_proxy = multi.sec_realms[self.realm]
|
||||
def setupAuth(self, multi, handler):
|
||||
if not multi.sec_realms.has_key(self.realm):
|
||||
multi.sec_realms[self.realm] = OerpAuthProxy(self)
|
||||
handler.auth_proxy = multi.sec_realms[self.realm]
|
||||
|
||||
def authenticate(self, db, user, passwd, client_address):
|
||||
try:
|
||||
uid = security.login(db,user,passwd)
|
||||
if uid is False:
|
||||
return False
|
||||
return (user, passwd, db, uid)
|
||||
except Exception,e:
|
||||
netsvc.Logger().notifyChannel("auth",netsvc.LOG_DEBUG,"Fail auth:"+ str(e))
|
||||
return False
|
||||
|
||||
def log(self, msg):
|
||||
netsvc.Logger().notifyChannel("auth",netsvc.LOG_INFO,msg)
|
||||
def authenticate(self, db, user, passwd, client_address):
|
||||
try:
|
||||
uid = security.login(db,user,passwd)
|
||||
if uid is False:
|
||||
return False
|
||||
return (user, passwd, db, uid)
|
||||
except Exception,e:
|
||||
netsvc.Logger().notifyChannel("auth",netsvc.LOG_DEBUG,"Fail auth:"+ str(e))
|
||||
return False
|
||||
|
||||
def log(self, msg):
|
||||
netsvc.Logger().notifyChannel("auth",netsvc.LOG_INFO,msg)
|
||||
|
||||
#eof
|
||||
|
|
|
@ -141,23 +141,23 @@ class TinySocketServerThread(threading.Thread,netsvc.Server):
|
|||
return False
|
||||
|
||||
def stats(self):
|
||||
res = "Net-RPC: " + ( (self.running and "running") or "stopped")
|
||||
i = 0
|
||||
for t in self.threads:
|
||||
i += 1
|
||||
res += "\nNet-RPC #%d: %s " % (i, t.name)
|
||||
if t.isAlive():
|
||||
res += "running"
|
||||
else:
|
||||
res += "finished"
|
||||
if t.sock:
|
||||
res += ", socket"
|
||||
return res
|
||||
res = "Net-RPC: " + ( (self.running and "running") or "stopped")
|
||||
i = 0
|
||||
for t in self.threads:
|
||||
i += 1
|
||||
res += "\nNet-RPC #%d: %s " % (i, t.name)
|
||||
if t.isAlive():
|
||||
res += "running"
|
||||
else:
|
||||
res += "finished"
|
||||
if t.sock:
|
||||
res += ", socket"
|
||||
return res
|
||||
|
||||
netrpcd = None
|
||||
|
||||
def init_servers():
|
||||
global netrpcd
|
||||
if tools.config.get_misc('netrpcd','enable', True):
|
||||
netrpcd = TinySocketServerThread(tools.config.get_misc('netrpcd','interface', ''), \
|
||||
tools.config.get_misc('netrpcd','port', 8070))
|
||||
global netrpcd
|
||||
if tools.config.get_misc('netrpcd','enable', True):
|
||||
netrpcd = TinySocketServerThread(tools.config.get_misc('netrpcd','interface', ''), \
|
||||
tools.config.get_misc('netrpcd','port', 8070))
|
||||
|
|
|
@ -51,23 +51,23 @@ class db(netsvc.ExportService):
|
|||
self._pg_psw_env_var_is_set = False # on win32, pg_dump need the PGPASSWORD env var
|
||||
|
||||
def dispatch(self, method, auth, params):
|
||||
if method in [ 'create', 'get_progress', 'drop', 'dump',
|
||||
'restore', 'rename',
|
||||
'change_admin_password', 'migrate_databases' ]:
|
||||
passwd = params[0]
|
||||
params = params[1:]
|
||||
security.check_super(passwd)
|
||||
elif method in [ 'db_exist', 'list', 'list_lang', 'server_version' ]:
|
||||
# params = params
|
||||
# No security check for these methods
|
||||
pass
|
||||
else:
|
||||
raise KeyError("Method not found: %s" % method)
|
||||
fn = getattr(self, 'exp_'+method)
|
||||
return fn(*params)
|
||||
|
||||
if method in [ 'create', 'get_progress', 'drop', 'dump',
|
||||
'restore', 'rename',
|
||||
'change_admin_password', 'migrate_databases' ]:
|
||||
passwd = params[0]
|
||||
params = params[1:]
|
||||
security.check_super(passwd)
|
||||
elif method in [ 'db_exist', 'list', 'list_lang', 'server_version' ]:
|
||||
# params = params
|
||||
# No security check for these methods
|
||||
pass
|
||||
else:
|
||||
raise KeyError("Method not found: %s" % method)
|
||||
fn = getattr(self, 'exp_'+method)
|
||||
return fn(*params)
|
||||
|
||||
def new_dispatch(self,method,auth,params):
|
||||
pass
|
||||
pass
|
||||
|
||||
def exp_create(self, db_name, demo, lang, user_password='admin'):
|
||||
self.id_protect.acquire()
|
||||
|
@ -366,15 +366,15 @@ class _ObjectService(netsvc.ExportService):
|
|||
"A common base class for those who have fn(db, uid, password,...) "
|
||||
|
||||
def common_dispatch(self, method, auth, params):
|
||||
(db, uid, passwd ) = params[0:3]
|
||||
params = params[3:]
|
||||
security.check(db,uid,passwd)
|
||||
cr = pooler.get_db(db).cursor()
|
||||
fn = getattr(self, 'exp_'+method)
|
||||
res = fn(cr, uid, *params)
|
||||
cr.commit()
|
||||
cr.close()
|
||||
return res
|
||||
(db, uid, passwd ) = params[0:3]
|
||||
params = params[3:]
|
||||
security.check(db,uid,passwd)
|
||||
cr = pooler.get_db(db).cursor()
|
||||
fn = getattr(self, 'exp_'+method)
|
||||
res = fn(cr, uid, *params)
|
||||
cr.commit()
|
||||
cr.close()
|
||||
return res
|
||||
|
||||
class common(_ObjectService):
|
||||
def __init__(self,name="common"):
|
||||
|
@ -382,36 +382,36 @@ class common(_ObjectService):
|
|||
self.joinGroup("web-services")
|
||||
|
||||
def dispatch(self, method, auth, params):
|
||||
logger = netsvc.Logger()
|
||||
if method in [ 'ir_set','ir_del', 'ir_get' ]:
|
||||
return self.common_dispatch(method,auth,params)
|
||||
if method == 'login':
|
||||
# At this old dispatcher, we do NOT update the auth proxy
|
||||
res = security.login(params[0], params[1], params[2])
|
||||
msg = res and 'successful login' or 'bad login or password'
|
||||
# TODO log the client ip address..
|
||||
logger.notifyChannel("web-service", netsvc.LOG_INFO, "%s from '%s' using database '%s'" % (msg, params[1], params[0].lower()))
|
||||
return res or False
|
||||
elif method == 'logout':
|
||||
if auth:
|
||||
auth.logout(params[1])
|
||||
logger.notifyChannel("web-service", netsvc.LOG_INFO,'Logout %s from database %s'%(login,db))
|
||||
return True
|
||||
elif method in ['about', 'timezone_get', 'get_server_environment', 'login_message', 'get_stats' ]:
|
||||
pass
|
||||
elif method in ['get_available_updates', 'get_migration_scripts', 'set_loglevel']:
|
||||
passwd = params[0]
|
||||
params = params[1:]
|
||||
security.check_super(passwd)
|
||||
else:
|
||||
raise Exception("Method not found: %s" % method)
|
||||
|
||||
fn = getattr(self, 'exp_'+method)
|
||||
return fn(*params)
|
||||
logger = netsvc.Logger()
|
||||
if method in [ 'ir_set','ir_del', 'ir_get' ]:
|
||||
return self.common_dispatch(method,auth,params)
|
||||
if method == 'login':
|
||||
# At this old dispatcher, we do NOT update the auth proxy
|
||||
res = security.login(params[0], params[1], params[2])
|
||||
msg = res and 'successful login' or 'bad login or password'
|
||||
# TODO log the client ip address..
|
||||
logger.notifyChannel("web-service", netsvc.LOG_INFO, "%s from '%s' using database '%s'" % (msg, params[1], params[0].lower()))
|
||||
return res or False
|
||||
elif method == 'logout':
|
||||
if auth:
|
||||
auth.logout(params[1])
|
||||
logger.notifyChannel("web-service", netsvc.LOG_INFO,'Logout %s from database %s'%(login,db))
|
||||
return True
|
||||
elif method in ['about', 'timezone_get', 'get_server_environment', 'login_message', 'get_stats' ]:
|
||||
pass
|
||||
elif method in ['get_available_updates', 'get_migration_scripts', 'set_loglevel']:
|
||||
passwd = params[0]
|
||||
params = params[1:]
|
||||
security.check_super(passwd)
|
||||
else:
|
||||
raise Exception("Method not found: %s" % method)
|
||||
|
||||
fn = getattr(self, 'exp_'+method)
|
||||
return fn(*params)
|
||||
|
||||
|
||||
def new_dispatch(self,method,auth,params):
|
||||
pass
|
||||
pass
|
||||
|
||||
def exp_ir_set(self, cr, uid, keys, args, name, value, replace=True, isobject=False):
|
||||
res = ir.ir_set(cr,uid, keys, args, name, value, replace, isobject)
|
||||
|
@ -574,7 +574,7 @@ GNU Public Licence.
|
|||
def exp_get_stats(self):
|
||||
import threading
|
||||
res = "OpenERP server: %d threads\n" % threading.active_count()
|
||||
res += netsvc.Server.allStats()
|
||||
res += netsvc.Server.allStats()
|
||||
return res
|
||||
|
||||
common()
|
||||
|
@ -585,19 +585,19 @@ class objects_proxy(netsvc.ExportService):
|
|||
self.joinGroup('web-services')
|
||||
|
||||
def dispatch(self, method, auth, params):
|
||||
(db, uid, passwd ) = params[0:3]
|
||||
params = params[3:]
|
||||
if method not in ['execute','exec_workflow','obj_list']:
|
||||
raise KeyError("Method not supported %s" % method)
|
||||
security.check(db,uid,passwd)
|
||||
ls = netsvc.LocalService('object_proxy')
|
||||
fn = getattr(ls, method)
|
||||
res = fn(db, uid, *params)
|
||||
return res
|
||||
(db, uid, passwd ) = params[0:3]
|
||||
params = params[3:]
|
||||
if method not in ['execute','exec_workflow','obj_list']:
|
||||
raise KeyError("Method not supported %s" % method)
|
||||
security.check(db,uid,passwd)
|
||||
ls = netsvc.LocalService('object_proxy')
|
||||
fn = getattr(ls, method)
|
||||
res = fn(db, uid, *params)
|
||||
return res
|
||||
|
||||
|
||||
|
||||
def new_dispatch(self,method,auth,params):
|
||||
pass
|
||||
pass
|
||||
|
||||
objects_proxy()
|
||||
|
||||
|
@ -623,17 +623,17 @@ class wizard(netsvc.ExportService):
|
|||
self.wiz_uid = {}
|
||||
|
||||
def dispatch(self, method, auth, params):
|
||||
(db, uid, passwd ) = params[0:3]
|
||||
params = params[3:]
|
||||
if method not in ['execute','create']:
|
||||
raise KeyError("Method not supported %s" % method)
|
||||
security.check(db,uid,passwd)
|
||||
fn = getattr(self, 'exp_'+method)
|
||||
res = fn(db, uid, *params)
|
||||
return res
|
||||
|
||||
(db, uid, passwd ) = params[0:3]
|
||||
params = params[3:]
|
||||
if method not in ['execute','create']:
|
||||
raise KeyError("Method not supported %s" % method)
|
||||
security.check(db,uid,passwd)
|
||||
fn = getattr(self, 'exp_'+method)
|
||||
res = fn(db, uid, *params)
|
||||
return res
|
||||
|
||||
def new_dispatch(self,method,auth,params):
|
||||
pass
|
||||
pass
|
||||
|
||||
def _execute(self, db, uid, wiz_id, datas, action, context):
|
||||
self.wiz_datas[wiz_id].update(datas)
|
||||
|
@ -685,18 +685,18 @@ class report_spool(netsvc.ExportService):
|
|||
self.id_protect = threading.Semaphore()
|
||||
|
||||
def dispatch(self, method, auth, params):
|
||||
(db, uid, passwd ) = params[0:3]
|
||||
params = params[3:]
|
||||
if method not in ['report','report_get']:
|
||||
raise KeyError("Method not supported %s" % method)
|
||||
security.check(db,uid,passwd)
|
||||
fn = getattr(self, 'exp_' + method)
|
||||
res = fn(db, uid, *params)
|
||||
return res
|
||||
(db, uid, passwd ) = params[0:3]
|
||||
params = params[3:]
|
||||
if method not in ['report','report_get']:
|
||||
raise KeyError("Method not supported %s" % method)
|
||||
security.check(db,uid,passwd)
|
||||
fn = getattr(self, 'exp_' + method)
|
||||
res = fn(db, uid, *params)
|
||||
return res
|
||||
|
||||
|
||||
|
||||
def new_dispatch(self,method,auth,params):
|
||||
pass
|
||||
pass
|
||||
|
||||
def exp_report(self, db, uid, object, ids, datas=None, context=None):
|
||||
if not datas:
|
||||
|
|
|
@ -37,115 +37,115 @@ from BaseHTTPServer import *
|
|||
from SimpleHTTPServer import SimpleHTTPRequestHandler
|
||||
|
||||
class AuthRequiredExc(Exception):
|
||||
def __init__(self,atype,realm):
|
||||
Exception.__init__(self)
|
||||
self.atype = atype
|
||||
self.realm = realm
|
||||
|
||||
def __init__(self,atype,realm):
|
||||
Exception.__init__(self)
|
||||
self.atype = atype
|
||||
self.realm = realm
|
||||
|
||||
class AuthRejectedExc(Exception):
|
||||
pass
|
||||
pass
|
||||
|
||||
class AuthProvider:
|
||||
def __init__(self,realm):
|
||||
self.realm = realm
|
||||
def __init__(self,realm):
|
||||
self.realm = realm
|
||||
|
||||
def setupAuth(self, multi,handler):
|
||||
""" Attach an AuthProxy object to handler
|
||||
"""
|
||||
pass
|
||||
def setupAuth(self, multi,handler):
|
||||
""" Attach an AuthProxy object to handler
|
||||
"""
|
||||
pass
|
||||
|
||||
def authenticate(self, user, passwd, client_address):
|
||||
return False
|
||||
|
||||
def log(self, msg):
|
||||
print msg
|
||||
def authenticate(self, user, passwd, client_address):
|
||||
return False
|
||||
|
||||
def log(self, msg):
|
||||
print msg
|
||||
|
||||
class BasicAuthProvider(AuthProvider):
|
||||
def setupAuth(self, multi, handler):
|
||||
if not multi.sec_realms.has_key(self.realm):
|
||||
multi.sec_realms[self.realm] = BasicAuthProxy(self)
|
||||
|
||||
def setupAuth(self, multi, handler):
|
||||
if not multi.sec_realms.has_key(self.realm):
|
||||
multi.sec_realms[self.realm] = BasicAuthProxy(self)
|
||||
|
||||
|
||||
class AuthProxy:
|
||||
""" This class will hold authentication information for a handler,
|
||||
i.e. a connection
|
||||
"""
|
||||
def __init__(self, provider):
|
||||
self.provider = provider
|
||||
""" This class will hold authentication information for a handler,
|
||||
i.e. a connection
|
||||
"""
|
||||
def __init__(self, provider):
|
||||
self.provider = provider
|
||||
|
||||
def checkRequest(self,handler,path = '/'):
|
||||
""" Check if we are allowed to process that request
|
||||
"""
|
||||
pass
|
||||
def checkRequest(self,handler,path = '/'):
|
||||
""" Check if we are allowed to process that request
|
||||
"""
|
||||
pass
|
||||
|
||||
class BasicAuthProxy(AuthProxy):
|
||||
""" Require basic authentication..
|
||||
"""
|
||||
def __init__(self,provider):
|
||||
AuthProxy.__init__(self,provider)
|
||||
self.auth_creds = None
|
||||
self.auth_tries = 0
|
||||
""" Require basic authentication..
|
||||
"""
|
||||
def __init__(self,provider):
|
||||
AuthProxy.__init__(self,provider)
|
||||
self.auth_creds = None
|
||||
self.auth_tries = 0
|
||||
|
||||
def checkRequest(self,handler,path = '/'):
|
||||
if self.auth_creds:
|
||||
return True
|
||||
auth_str = handler.headers.get('Authorization',False)
|
||||
if auth_str and auth_str.startswith('Basic '):
|
||||
auth_str=auth_str[len('Basic '):]
|
||||
(user,passwd) = base64.decodestring(auth_str).split(':')
|
||||
self.provider.log("Found user=\"%s\", passwd=\"%s\"" %(user,passwd))
|
||||
self.auth_creds = self.provider.authenticate(user,passwd,handler.client_address)
|
||||
if self.auth_creds:
|
||||
return True
|
||||
if self.auth_tries > 5:
|
||||
self.provider.log("Failing authorization after 5 requests w/o password")
|
||||
raise AuthRejectedExc("Authorization failed.")
|
||||
self.auth_tries += 1
|
||||
raise AuthRequiredExc(atype = 'Basic', realm=self.provider.realm)
|
||||
def checkRequest(self,handler,path = '/'):
|
||||
if self.auth_creds:
|
||||
return True
|
||||
auth_str = handler.headers.get('Authorization',False)
|
||||
if auth_str and auth_str.startswith('Basic '):
|
||||
auth_str=auth_str[len('Basic '):]
|
||||
(user,passwd) = base64.decodestring(auth_str).split(':')
|
||||
self.provider.log("Found user=\"%s\", passwd=\"%s\"" %(user,passwd))
|
||||
self.auth_creds = self.provider.authenticate(user,passwd,handler.client_address)
|
||||
if self.auth_creds:
|
||||
return True
|
||||
if self.auth_tries > 5:
|
||||
self.provider.log("Failing authorization after 5 requests w/o password")
|
||||
raise AuthRejectedExc("Authorization failed.")
|
||||
self.auth_tries += 1
|
||||
raise AuthRequiredExc(atype = 'Basic', realm=self.provider.realm)
|
||||
|
||||
|
||||
class HTTPHandler(SimpleHTTPRequestHandler):
|
||||
def __init__(self,request, client_address, server):
|
||||
SimpleHTTPRequestHandler.__init__(self,request,client_address,server)
|
||||
# print "Handler for %s inited" % str(client_address)
|
||||
self.protocol_version = 'HTTP/1.1'
|
||||
self.connection = dummyconn()
|
||||
|
||||
def handle(self):
|
||||
""" Classes here should NOT handle inside their constructor
|
||||
"""
|
||||
pass
|
||||
|
||||
def finish(self):
|
||||
pass
|
||||
|
||||
def setup(self):
|
||||
pass
|
||||
def __init__(self,request, client_address, server):
|
||||
SimpleHTTPRequestHandler.__init__(self,request,client_address,server)
|
||||
# print "Handler for %s inited" % str(client_address)
|
||||
self.protocol_version = 'HTTP/1.1'
|
||||
self.connection = dummyconn()
|
||||
|
||||
def handle(self):
|
||||
""" Classes here should NOT handle inside their constructor
|
||||
"""
|
||||
pass
|
||||
|
||||
def finish(self):
|
||||
pass
|
||||
|
||||
def setup(self):
|
||||
pass
|
||||
|
||||
class HTTPDir:
|
||||
""" A dispatcher class, like a virtual folder in httpd
|
||||
"""
|
||||
def __init__(self,path,handler, auth_provider = None):
|
||||
self.path = path
|
||||
self.handler = handler
|
||||
self.auth_provider = auth_provider
|
||||
|
||||
def matches(self, request):
|
||||
""" Test if some request matches us. If so, return
|
||||
the matched path. """
|
||||
if request.startswith(self.path):
|
||||
return self.path
|
||||
return False
|
||||
""" A dispatcher class, like a virtual folder in httpd
|
||||
"""
|
||||
def __init__(self,path,handler, auth_provider = None):
|
||||
self.path = path
|
||||
self.handler = handler
|
||||
self.auth_provider = auth_provider
|
||||
|
||||
def matches(self, request):
|
||||
""" Test if some request matches us. If so, return
|
||||
the matched path. """
|
||||
if request.startswith(self.path):
|
||||
return self.path
|
||||
return False
|
||||
|
||||
class noconnection:
|
||||
""" a class to use instead of the real connection
|
||||
"""
|
||||
def makefile(self, mode, bufsize):
|
||||
return None
|
||||
""" a class to use instead of the real connection
|
||||
"""
|
||||
def makefile(self, mode, bufsize):
|
||||
return None
|
||||
|
||||
class dummyconn:
|
||||
def shutdown(self, tru):
|
||||
pass
|
||||
def shutdown(self, tru):
|
||||
pass
|
||||
|
||||
def _quote_html(html):
|
||||
return html.replace("&", "&").replace("<", "<").replace(">", ">")
|
||||
|
@ -168,7 +168,7 @@ class FixSendError:
|
|||
self.send_response(code, message)
|
||||
self.send_header("Content-Type", self.error_content_type)
|
||||
self.send_header('Connection', 'close')
|
||||
self.send_header('Content-Length', len(content) or 0)
|
||||
self.send_header('Content-Length', len(content) or 0)
|
||||
self.end_headers()
|
||||
if self.command != 'HEAD' and code >= 200 and code not in (204, 304):
|
||||
self.wfile.write(content)
|
||||
|
@ -176,65 +176,65 @@ class FixSendError:
|
|||
class MultiHTTPHandler(FixSendError,BaseHTTPRequestHandler):
|
||||
""" this is a multiple handler, that will dispatch each request
|
||||
to a nested handler, iff it matches
|
||||
|
||||
The handler will also have *one* dict of authentication proxies,
|
||||
groupped by their realm.
|
||||
|
||||
The handler will also have *one* dict of authentication proxies,
|
||||
groupped by their realm.
|
||||
"""
|
||||
|
||||
protocol_version = "HTTP/1.1"
|
||||
default_request_version = "HTTP/0.9" # compatibility with py2.5
|
||||
default_request_version = "HTTP/0.9" # compatibility with py2.5
|
||||
|
||||
auth_required_msg = """ <html><head><title>Authorization required</title></head>
|
||||
<body>You must authenticate to use this service</body><html>\r\r"""
|
||||
|
||||
def __init__(self, request, client_address, server):
|
||||
self.in_handlers = {}
|
||||
self.sec_realms = {}
|
||||
SocketServer.StreamRequestHandler.__init__(self,request,client_address,server)
|
||||
self.log_message("MultiHttpHandler init for %s" %(str(client_address)))
|
||||
self.in_handlers = {}
|
||||
self.sec_realms = {}
|
||||
SocketServer.StreamRequestHandler.__init__(self,request,client_address,server)
|
||||
self.log_message("MultiHttpHandler init for %s" %(str(client_address)))
|
||||
|
||||
def _handle_one_foreign(self,fore, path, auth_provider):
|
||||
""" This method overrides the handle_one_request for *children*
|
||||
handlers. It is required, since the first line should not be
|
||||
read again..
|
||||
read again..
|
||||
|
||||
"""
|
||||
fore.raw_requestline = "%s %s %s\n" % (self.command, path, self.version)
|
||||
if not fore.parse_request(): # An error code has been sent, just exit
|
||||
return
|
||||
self.request_version = fore.request_version
|
||||
if auth_provider and auth_provider.realm:
|
||||
try:
|
||||
self.sec_realms[auth_provider.realm].checkRequest(fore,path)
|
||||
except AuthRequiredExc,ae:
|
||||
if self.request_version != 'HTTP/1.1':
|
||||
self.log_error("Cannot require auth at %s",self.request_version)
|
||||
self.send_error(401)
|
||||
return
|
||||
self._get_ignore_body(fore) # consume any body that came, not loose sync with input
|
||||
self.send_response(401,'Authorization required')
|
||||
self.send_header('WWW-Authenticate','%s realm="%s"' % (ae.atype,ae.realm))
|
||||
self.send_header('Connection', 'keep-alive')
|
||||
self.send_header('Content-Type','text/html')
|
||||
self.send_header('Content-Length',len(self.auth_required_msg))
|
||||
self.end_headers()
|
||||
self.wfile.write(self.auth_required_msg)
|
||||
return
|
||||
except AuthRejectedExc,e:
|
||||
self.log_error("Rejected auth: %s" % e.args[0])
|
||||
self.send_error(401,e.args[0])
|
||||
self.close_connection = 1
|
||||
return
|
||||
self.request_version = fore.request_version
|
||||
if auth_provider and auth_provider.realm:
|
||||
try:
|
||||
self.sec_realms[auth_provider.realm].checkRequest(fore,path)
|
||||
except AuthRequiredExc,ae:
|
||||
if self.request_version != 'HTTP/1.1':
|
||||
self.log_error("Cannot require auth at %s",self.request_version)
|
||||
self.send_error(401)
|
||||
return
|
||||
self._get_ignore_body(fore) # consume any body that came, not loose sync with input
|
||||
self.send_response(401,'Authorization required')
|
||||
self.send_header('WWW-Authenticate','%s realm="%s"' % (ae.atype,ae.realm))
|
||||
self.send_header('Connection', 'keep-alive')
|
||||
self.send_header('Content-Type','text/html')
|
||||
self.send_header('Content-Length',len(self.auth_required_msg))
|
||||
self.end_headers()
|
||||
self.wfile.write(self.auth_required_msg)
|
||||
return
|
||||
except AuthRejectedExc,e:
|
||||
self.log_error("Rejected auth: %s" % e.args[0])
|
||||
self.send_error(401,e.args[0])
|
||||
self.close_connection = 1
|
||||
return
|
||||
mname = 'do_' + fore.command
|
||||
if not hasattr(fore, mname):
|
||||
fore.send_error(501, "Unsupported method (%r)" % fore.command)
|
||||
return
|
||||
fore.close_connection = 0
|
||||
fore.close_connection = 0
|
||||
method = getattr(fore, mname)
|
||||
method()
|
||||
if fore.close_connection:
|
||||
# print "Closing connection because of handler"
|
||||
self.close_connection = fore.close_connection
|
||||
if fore.close_connection:
|
||||
# print "Closing connection because of handler"
|
||||
self.close_connection = fore.close_connection
|
||||
|
||||
def parse_rawline(self):
|
||||
"""Parse a request (internal).
|
||||
|
@ -295,67 +295,67 @@ class MultiHTTPHandler(FixSendError,BaseHTTPRequestHandler):
|
|||
else:
|
||||
self.send_error(400, "Bad request syntax (%r)" % requestline)
|
||||
return False
|
||||
self.request_version = version
|
||||
self.command, self.path, self.version = command, path, version
|
||||
return True
|
||||
self.request_version = version
|
||||
self.command, self.path, self.version = command, path, version
|
||||
return True
|
||||
|
||||
def handle_one_request(self):
|
||||
"""Handle a single HTTP request.
|
||||
Dispatch to the correct handler.
|
||||
Dispatch to the correct handler.
|
||||
"""
|
||||
self.request.setblocking(True)
|
||||
self.request.setblocking(True)
|
||||
self.raw_requestline = self.rfile.readline()
|
||||
if not self.raw_requestline:
|
||||
self.close_connection = 1
|
||||
# self.log_message("no requestline, connection closed?")
|
||||
return
|
||||
if not self.parse_rawline():
|
||||
self.log_message("Could not parse rawline.")
|
||||
return
|
||||
if not self.raw_requestline:
|
||||
self.close_connection = 1
|
||||
# self.log_message("no requestline, connection closed?")
|
||||
return
|
||||
if not self.parse_rawline():
|
||||
self.log_message("Could not parse rawline.")
|
||||
return
|
||||
# self.parse_request(): # Do NOT parse here. the first line should be the only
|
||||
for vdir in self.server.vdirs:
|
||||
p = vdir.matches(self.path)
|
||||
if p == False:
|
||||
continue
|
||||
npath = self.path[len(p):]
|
||||
if not npath.startswith('/'):
|
||||
npath = '/' + npath
|
||||
for vdir in self.server.vdirs:
|
||||
p = vdir.matches(self.path)
|
||||
if p == False:
|
||||
continue
|
||||
npath = self.path[len(p):]
|
||||
if not npath.startswith('/'):
|
||||
npath = '/' + npath
|
||||
|
||||
if not self.in_handlers.has_key(p):
|
||||
self.in_handlers[p] = vdir.handler(noconnection(),self.client_address,self.server)
|
||||
if vdir.auth_provider:
|
||||
vdir.auth_provider.setupAuth(self, self.in_handlers[p])
|
||||
hnd = self.in_handlers[p]
|
||||
hnd.rfile = self.rfile
|
||||
hnd.wfile = self.wfile
|
||||
self.rlpath = self.raw_requestline
|
||||
self._handle_one_foreign(hnd,npath, vdir.auth_provider)
|
||||
# print "Handled, closing = ", self.close_connection
|
||||
return
|
||||
# if no match:
|
||||
if not self.in_handlers.has_key(p):
|
||||
self.in_handlers[p] = vdir.handler(noconnection(),self.client_address,self.server)
|
||||
if vdir.auth_provider:
|
||||
vdir.auth_provider.setupAuth(self, self.in_handlers[p])
|
||||
hnd = self.in_handlers[p]
|
||||
hnd.rfile = self.rfile
|
||||
hnd.wfile = self.wfile
|
||||
self.rlpath = self.raw_requestline
|
||||
self._handle_one_foreign(hnd,npath, vdir.auth_provider)
|
||||
# print "Handled, closing = ", self.close_connection
|
||||
return
|
||||
# if no match:
|
||||
self.send_error(404, "Path not found: %s" % self.path)
|
||||
return
|
||||
|
||||
def _get_ignore_body(self,fore):
|
||||
if not fore.headers.has_key("content-length"):
|
||||
return
|
||||
max_chunk_size = 10*1024*1024
|
||||
size_remaining = int(fore.headers["content-length"])
|
||||
got = ''
|
||||
while size_remaining:
|
||||
chunk_size = min(size_remaining, max_chunk_size)
|
||||
got = fore.rfile.read(chunk_size)
|
||||
size_remaining -= len(got)
|
||||
if not fore.headers.has_key("content-length"):
|
||||
return
|
||||
max_chunk_size = 10*1024*1024
|
||||
size_remaining = int(fore.headers["content-length"])
|
||||
got = ''
|
||||
while size_remaining:
|
||||
chunk_size = min(size_remaining, max_chunk_size)
|
||||
got = fore.rfile.read(chunk_size)
|
||||
size_remaining -= len(got)
|
||||
|
||||
|
||||
class SecureMultiHTTPHandler(MultiHTTPHandler):
|
||||
def getcert_fnames(self):
|
||||
""" Return a pair with the filenames of ssl cert,key
|
||||
|
||||
Override this to direct to other filenames
|
||||
"""
|
||||
return ('server.cert','server.key')
|
||||
|
||||
""" Return a pair with the filenames of ssl cert,key
|
||||
|
||||
Override this to direct to other filenames
|
||||
"""
|
||||
return ('server.cert','server.key')
|
||||
|
||||
def setup(self):
|
||||
import ssl
|
||||
certfile, keyfile = self.getcert_fnames()
|
||||
|
@ -386,10 +386,10 @@ import threading
|
|||
class ConnThreadingMixIn:
|
||||
"""Mix-in class to handle each _connection_ in a new thread.
|
||||
|
||||
This is necessary for persistent connections, where multiple
|
||||
requests should be handled synchronously at each connection, but
|
||||
multiple connections can run in parallel.
|
||||
"""
|
||||
This is necessary for persistent connections, where multiple
|
||||
requests should be handled synchronously at each connection, but
|
||||
multiple connections can run in parallel.
|
||||
"""
|
||||
|
||||
# Decides how threads will act upon termination of the
|
||||
# main process
|
||||
|
@ -401,7 +401,7 @@ class ConnThreadingMixIn:
|
|||
if self.daemon_threads:
|
||||
t.setDaemon (1)
|
||||
t.start()
|
||||
|
||||
|
||||
def _handle_request2(self):
|
||||
"""Handle one request, without blocking.
|
||||
|
||||
|
|
|
@ -119,14 +119,14 @@ class Cursor(object):
|
|||
try:
|
||||
params = params or None
|
||||
res = self._obj.execute(query, params)
|
||||
except psycopg2.ProgrammingError, pe:
|
||||
logger= netsvc.Logger()
|
||||
logger.notifyChannel('sql_db', netsvc.LOG_ERROR, "Programming error: %s, in query %s" % (pe, query))
|
||||
raise
|
||||
except psycopg2.ProgrammingError, pe:
|
||||
logger= netsvc.Logger()
|
||||
logger.notifyChannel('sql_db', netsvc.LOG_ERROR, "Programming error: %s, in query %s" % (pe, query))
|
||||
raise
|
||||
except Exception, e:
|
||||
log("bad query: %s" % self._obj.query)
|
||||
log(e)
|
||||
raise
|
||||
raise
|
||||
|
||||
if self.sql_log:
|
||||
log("query: %s" % self._obj.query)
|
||||
|
@ -144,8 +144,8 @@ class Cursor(object):
|
|||
return res
|
||||
|
||||
def print_log(self):
|
||||
global sql_counter
|
||||
sql_counter += self.count
|
||||
global sql_counter
|
||||
sql_counter += self.count
|
||||
def process(type):
|
||||
sqllogs = {'from':self.sql_from_log, 'into':self.sql_into_log}
|
||||
sum = 0
|
||||
|
|
|
@ -66,7 +66,7 @@ class configmanager(object):
|
|||
'import_partial': "",
|
||||
'pidfile': None,
|
||||
'logfile': None,
|
||||
'logrotate': '1',
|
||||
'logrotate': '1',
|
||||
'smtp_server': 'localhost',
|
||||
'smtp_user': False,
|
||||
'smtp_port':25,
|
||||
|
@ -82,8 +82,8 @@ class configmanager(object):
|
|||
'login_message': False,
|
||||
'list_db' : True,
|
||||
}
|
||||
|
||||
self.misc = {}
|
||||
|
||||
self.misc = {}
|
||||
|
||||
hasSSL = check_ssl()
|
||||
|
||||
|
@ -135,7 +135,7 @@ class configmanager(object):
|
|||
group = optparse.OptionGroup(parser, "Logging Configuration")
|
||||
group.add_option("--logfile", dest="logfile", help="file where the server log will be stored")
|
||||
group.add_option("--no-logrotate", dest="logrotate", action="store_false",
|
||||
default=None, help="do not rotate the logfile")
|
||||
default=None, help="do not rotate the logfile")
|
||||
group.add_option("--syslog", action="store_true", dest="syslog",
|
||||
default=False, help="Send the log to the syslog server")
|
||||
group.add_option('--log-level', dest='log_level', type='choice', choices=self._LOGLEVELS.keys(),
|
||||
|
@ -226,7 +226,7 @@ class configmanager(object):
|
|||
'db_port', 'list_db', 'logfile', 'pidfile', 'smtp_port', 'cache_timeout',
|
||||
'email_from', 'smtp_server', 'smtp_user', 'smtp_password', 'price_accuracy',
|
||||
'netinterface', 'netport', 'db_maxconn', 'import_partial', 'addons_path',
|
||||
'netrpc', 'xmlrpc', 'syslog', 'without_demo']
|
||||
'netrpc', 'xmlrpc', 'syslog', 'without_demo']
|
||||
|
||||
if hasSSL:
|
||||
keys.extend(['smtp_ssl', 'secure_cert_file', 'secure_pkey_file'])
|
||||
|
@ -341,18 +341,18 @@ class configmanager(object):
|
|||
if value=='False' or value=='false':
|
||||
value = False
|
||||
self.options[name] = value
|
||||
#parse the other sections, as well
|
||||
for sec in p.sections():
|
||||
if sec == 'options':
|
||||
continue
|
||||
if not self.misc.has_key(sec):
|
||||
self.misc[sec]= {}
|
||||
for (name, value) in p.items(sec):
|
||||
if value=='True' or value=='true':
|
||||
value = True
|
||||
if value=='False' or value=='false':
|
||||
value = False
|
||||
self.misc[sec][name] = value
|
||||
#parse the other sections, as well
|
||||
for sec in p.sections():
|
||||
if sec == 'options':
|
||||
continue
|
||||
if not self.misc.has_key(sec):
|
||||
self.misc[sec]= {}
|
||||
for (name, value) in p.items(sec):
|
||||
if value=='True' or value=='true':
|
||||
value = True
|
||||
if value=='False' or value=='false':
|
||||
value = False
|
||||
self.misc[sec][name] = value
|
||||
except IOError:
|
||||
pass
|
||||
except ConfigParser.NoSectionError:
|
||||
|
@ -369,10 +369,10 @@ class configmanager(object):
|
|||
p.set('options', opt, loglevelnames.get(self.options[opt], self.options[opt]))
|
||||
else:
|
||||
p.set('options', opt, self.options[opt])
|
||||
|
||||
for sec in self.misc.keys():
|
||||
for opt in self.misc[sec].keys():
|
||||
p.set(sec,opt,self.misc[sec][opt])
|
||||
|
||||
for sec in self.misc.keys():
|
||||
for opt in self.misc[sec].keys():
|
||||
p.set(sec,opt,self.misc[sec][opt])
|
||||
|
||||
# try to create the directories and write the file
|
||||
try:
|
||||
|
|
|
@ -386,15 +386,15 @@ def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=Non
|
|||
smtp_server = config['smtp_server']
|
||||
if smtp_server.startswith('maildir:/'):
|
||||
from mailbox import Maildir
|
||||
maildir_path = smtp_server[8:]
|
||||
try:
|
||||
mdir = Maildir(maildir_path,factory=None, create = True)
|
||||
mdir.add(msg.as_string(True))
|
||||
return True
|
||||
except Exception,e:
|
||||
netsvc.Logger().notifyChannel('email_send (maildir)', netsvc.LOG_ERROR, e)
|
||||
return False
|
||||
|
||||
maildir_path = smtp_server[8:]
|
||||
try:
|
||||
mdir = Maildir(maildir_path,factory=None, create = True)
|
||||
mdir.add(msg.as_string(True))
|
||||
return True
|
||||
except Exception,e:
|
||||
netsvc.Logger().notifyChannel('email_send (maildir)', netsvc.LOG_ERROR, e)
|
||||
return False
|
||||
|
||||
try:
|
||||
oldstderr = smtplib.stderr
|
||||
s = smtplib.SMTP()
|
||||
|
|
|
@ -29,38 +29,38 @@ __export_bis = {}
|
|||
import sys
|
||||
|
||||
def __init_ebis():
|
||||
global __export_bis
|
||||
|
||||
_evars = [ 'abs', 'all', 'any', 'basestring' , 'bool',
|
||||
'chr', 'cmp','complex', 'dict', 'divmod', 'enumerate',
|
||||
'float', 'frozenset', 'getattr', 'hasattr', 'hash',
|
||||
'hex', 'id','int', 'iter', 'len', 'list', 'long', 'map', 'max',
|
||||
'min', 'oct', 'ord','pow', 'range', 'reduce', 'repr',
|
||||
'reversed', 'round', 'set', 'setattr', 'slice','sorted', 'str',
|
||||
'sum', 'tuple','type', 'unichr','unicode', 'xrange',
|
||||
'True','False', 'None', 'NotImplemented', 'Ellipsis', ]
|
||||
|
||||
if sys.version_info[0:2] >= (2,6):
|
||||
_evars.extend(['bin', 'format', 'next'])
|
||||
for v in _evars:
|
||||
__export_bis[v] = __builtins__[v]
|
||||
|
||||
global __export_bis
|
||||
|
||||
_evars = [ 'abs', 'all', 'any', 'basestring' , 'bool',
|
||||
'chr', 'cmp','complex', 'dict', 'divmod', 'enumerate',
|
||||
'float', 'frozenset', 'getattr', 'hasattr', 'hash',
|
||||
'hex', 'id','int', 'iter', 'len', 'list', 'long', 'map', 'max',
|
||||
'min', 'oct', 'ord','pow', 'range', 'reduce', 'repr',
|
||||
'reversed', 'round', 'set', 'setattr', 'slice','sorted', 'str',
|
||||
'sum', 'tuple','type', 'unichr','unicode', 'xrange',
|
||||
'True','False', 'None', 'NotImplemented', 'Ellipsis', ]
|
||||
|
||||
if sys.version_info[0:2] >= (2,6):
|
||||
_evars.extend(['bin', 'format', 'next'])
|
||||
for v in _evars:
|
||||
__export_bis[v] = __builtins__[v]
|
||||
|
||||
|
||||
__init_ebis()
|
||||
|
||||
|
||||
def safe_eval(expr,sglobals,slocals = None):
|
||||
""" A little safer version of eval().
|
||||
This one, will use fewer builtin functions, so that only
|
||||
arithmetic and logic expressions can really work """
|
||||
|
||||
global __export_bis
|
||||
""" A little safer version of eval().
|
||||
This one, will use fewer builtin functions, so that only
|
||||
arithmetic and logic expressions can really work """
|
||||
|
||||
global __export_bis
|
||||
|
||||
if not sglobals.has_key('__builtins__'):
|
||||
# we copy, because we wouldn't want successive calls to safe_eval
|
||||
# to be able to alter the builtins.
|
||||
sglobals['__builtins__'] = __export_bis.copy()
|
||||
|
||||
return eval(expr,sglobals,slocals)
|
||||
|
||||
#eof
|
||||
if not sglobals.has_key('__builtins__'):
|
||||
# we copy, because we wouldn't want successive calls to safe_eval
|
||||
# to be able to alter the builtins.
|
||||
sglobals['__builtins__'] = __export_bis.copy()
|
||||
|
||||
return eval(expr,sglobals,slocals)
|
||||
|
||||
#eof
|
||||
|
|
|
@ -133,12 +133,12 @@ class GettextAlias(object):
|
|||
return source
|
||||
|
||||
cr = frame.f_locals.get('cr')
|
||||
try:
|
||||
lang = (frame.f_locals.get('context') or {}).get('lang', False)
|
||||
if not (lang and cr):
|
||||
return source
|
||||
except:
|
||||
return source
|
||||
try:
|
||||
lang = (frame.f_locals.get('context') or {}).get('lang', False)
|
||||
if not (lang and cr):
|
||||
return source
|
||||
except:
|
||||
return source
|
||||
|
||||
cr.execute('select value from ir_translation where lang=%s and type=%s and src=%s', (lang, 'code', source))
|
||||
res_trans = cr.fetchone()
|
||||
|
@ -154,7 +154,7 @@ class TinyPoFile(object):
|
|||
def __iter__(self):
|
||||
self.buffer.seek(0)
|
||||
self.lines = self._get_lines()
|
||||
self.lines_count = len(self.lines);
|
||||
self.lines_count = len(self.lines);
|
||||
|
||||
self.first = True
|
||||
self.tnrs= []
|
||||
|
@ -170,7 +170,7 @@ class TinyPoFile(object):
|
|||
return lines
|
||||
|
||||
def cur_line(self):
|
||||
return (self.lines_count - len(self.lines))
|
||||
return (self.lines_count - len(self.lines))
|
||||
|
||||
def next(self):
|
||||
def unquote(str):
|
||||
|
@ -185,30 +185,30 @@ class TinyPoFile(object):
|
|||
else:
|
||||
tmp_tnrs = []
|
||||
line = None
|
||||
fuzzy = False
|
||||
fuzzy = False
|
||||
while (not line):
|
||||
if 0 == len(self.lines):
|
||||
raise StopIteration()
|
||||
line = self.lines.pop(0).strip()
|
||||
if line.startswith('#:'):
|
||||
if ' ' in line[2:].strip():
|
||||
for lpart in line[2:].strip().split(' '):
|
||||
tmp_tnrs.append(lpart.strip().split(':',2))
|
||||
else:
|
||||
if ' ' in line[2:].strip():
|
||||
for lpart in line[2:].strip().split(' '):
|
||||
tmp_tnrs.append(lpart.strip().split(':',2))
|
||||
else:
|
||||
tmp_tnrs.append( line[2:].strip().split(':',2) )
|
||||
elif line.startswith('#,') and (line[2:].strip() == 'fuzzy'):
|
||||
fuzzy = True
|
||||
elif line.startswith('#,') and (line[2:].strip() == 'fuzzy'):
|
||||
fuzzy = True
|
||||
line = self.lines.pop(0).strip()
|
||||
while not line:
|
||||
# allow empty lines between comments and msgid
|
||||
line = self.lines.pop(0).strip()
|
||||
if line.startswith('#~ '):
|
||||
while line.startswith('#~ ') or not line.strip():
|
||||
if 0 == len(self.lines):
|
||||
if line.startswith('#~ '):
|
||||
while line.startswith('#~ ') or not line.strip():
|
||||
if 0 == len(self.lines):
|
||||
raise StopIteration()
|
||||
line = self.lines.pop(0)
|
||||
# This has been a deprecated entry, don't return anything
|
||||
return self.next()
|
||||
line = self.lines.pop(0)
|
||||
# This has been a deprecated entry, don't return anything
|
||||
return self.next()
|
||||
|
||||
|
||||
if not line.startswith('msgid'):
|
||||
|
@ -242,9 +242,9 @@ class TinyPoFile(object):
|
|||
self.tnrs.append((t, n, r, source, trad))
|
||||
|
||||
self.first = False
|
||||
|
||||
if name == None:
|
||||
return self.next()
|
||||
|
||||
if name == None:
|
||||
return self.next()
|
||||
return type, name, res_id, source, trad
|
||||
|
||||
def write_infos(self, modules):
|
||||
|
@ -279,7 +279,7 @@ class TinyPoFile(object):
|
|||
def quote(s):
|
||||
return '"%s"' % s.replace('"','\\"') \
|
||||
.replace('\n', '\\n"\n"') \
|
||||
.replace(' \\ ',' \\\\ ')
|
||||
.replace(' \\ ',' \\\\ ')
|
||||
|
||||
|
||||
plurial = len(modules) > 1 and 's' or ''
|
||||
|
@ -490,9 +490,9 @@ def trans_generate(lang, modules, dbname=None):
|
|||
}
|
||||
|
||||
# export fields
|
||||
if not result.has_key('fields'):
|
||||
logger.notifyChannel("db",netsvc.LOG_WARNING,"res has no fields: %r" % result)
|
||||
continue
|
||||
if not result.has_key('fields'):
|
||||
logger.notifyChannel("db",netsvc.LOG_WARNING,"res has no fields: %r" % result)
|
||||
continue
|
||||
for field_name, field_def in result['fields'].iteritems():
|
||||
res_name = name + ',' + field_name
|
||||
|
||||
|
@ -517,11 +517,11 @@ def trans_generate(lang, modules, dbname=None):
|
|||
push_translation(module, 'wizard_button', res_name, 0, button_label)
|
||||
|
||||
elif model=='ir.model.fields':
|
||||
try:
|
||||
try:
|
||||
field_name = encode(obj.name)
|
||||
except AttributeError, exc:
|
||||
logger.notifyChannel("db", netsvc.LOG_ERROR, "name error in %s: %s" % (xml_name,str(exc)))
|
||||
continue
|
||||
except AttributeError, exc:
|
||||
logger.notifyChannel("db", netsvc.LOG_ERROR, "name error in %s: %s" % (xml_name,str(exc)))
|
||||
continue
|
||||
objmodel = pool.get(obj.model)
|
||||
if not objmodel or not field_name in objmodel._columns:
|
||||
continue
|
||||
|
@ -578,28 +578,28 @@ def trans_generate(lang, modules, dbname=None):
|
|||
for field_name,field_def in pool.get(model)._columns.items():
|
||||
if field_def.translate:
|
||||
name = model + "," + field_name
|
||||
try:
|
||||
try:
|
||||
trad = getattr(obj, field_name) or ''
|
||||
except:
|
||||
trad = ''
|
||||
except:
|
||||
trad = ''
|
||||
push_translation(module, 'model', name, xml_name, encode(trad))
|
||||
|
||||
# parse source code for _() calls
|
||||
def get_module_from_path(path,mod_paths=None):
|
||||
if not mod_paths:
|
||||
# First, construct a list of possible paths
|
||||
def_path = os.path.abspath(os.path.join(tools.config['root_path'], 'addons')) # default addons path (base)
|
||||
ad_paths= map(lambda m: os.path.abspath(m.strip()),tools.config['addons_path'].split(','))
|
||||
mod_paths=[def_path]
|
||||
for adp in ad_paths:
|
||||
mod_paths.append(adp)
|
||||
if not adp.startswith('/'):
|
||||
mod_paths.append(os.path.join(def_path,adp))
|
||||
elif adp.startswith(def_path):
|
||||
mod_paths.append(adp[len(def_path)+1:])
|
||||
|
||||
for mp in mod_paths:
|
||||
if path.startswith(mp) and (os.path.dirname(path) != mp):
|
||||
if not mod_paths:
|
||||
# First, construct a list of possible paths
|
||||
def_path = os.path.abspath(os.path.join(tools.config['root_path'], 'addons')) # default addons path (base)
|
||||
ad_paths= map(lambda m: os.path.abspath(m.strip()),tools.config['addons_path'].split(','))
|
||||
mod_paths=[def_path]
|
||||
for adp in ad_paths:
|
||||
mod_paths.append(adp)
|
||||
if not adp.startswith('/'):
|
||||
mod_paths.append(os.path.join(def_path,adp))
|
||||
elif adp.startswith(def_path):
|
||||
mod_paths.append(adp[len(def_path)+1:])
|
||||
|
||||
for mp in mod_paths:
|
||||
if path.startswith(mp) and (os.path.dirname(path) != mp):
|
||||
path = path[len(mp)+1:]
|
||||
return path.split(os.path.sep)[0]
|
||||
return 'base' # files that are not in a module are considered as being in 'base' module
|
||||
|
@ -760,8 +760,8 @@ def trans_load_data(db_name, fileobj, fileformat, lang, strict=False, lang_name=
|
|||
|
||||
# if the resource id (res_id) is in that list, use it,
|
||||
# otherwise use the whole list
|
||||
if not ids:
|
||||
ids = []
|
||||
if not ids:
|
||||
ids = []
|
||||
ids = (dic['res_id'] in ids) and [dic['res_id']] or ids
|
||||
for id in ids:
|
||||
dic['res_id'] = id
|
||||
|
|
Loading…
Reference in New Issue