[MERGE]with main branch

bzr revid: jpr@tinyerp.com-20140327063821-n85232vzt06v8mo9
This commit is contained in:
Jitendra Prajapati (OpenERP) 2014-03-27 12:08:21 +05:30
commit 6e9c73de0d
19 changed files with 192 additions and 408 deletions

View File

@ -58,6 +58,7 @@ The kernel of OpenERP, needed for all installation.
'ir/osv_memory_autovacuum.xml',
'ir/ir_model_report.xml',
'ir/ir_logging_view.xml',
'ir/ir_qweb.xml',
'workflow/workflow_view.xml',
'module/module_view.xml',
'module/module_data.xml',

View File

@ -141,12 +141,12 @@ class ir_actions_report_xml(osv.osv):
'model': fields.char('Model', required=True),
'report_type': fields.selection([('qweb-pdf', 'PDF'),
('qweb-html', 'HTML'),
('other', 'Other'),
('controller', 'Controller'),
('pdf', 'RML pdf (deprecated)'),
('sxw', 'RML sxw (deprecated)'),
('webkit', 'Webkit (deprecated)'),
], 'Report Type', required=True, help="PDF will use wkhtmltopdf to render html to pdf, HTML will directly show html, Other will force download the controller output keeping the MIME type."),
'report_name': fields.char('Controller Name', required=True, help="URL of the report will be /report/<controller name>/<ids>, the default controller also use this field to get the name of the qweb ir.ui.view to render. For RML reports, this is the LocalService name."),
], 'Report Type', required=True, help="HTML will open the report directly in your browser, PDF will use wkhtmltopdf to render the HTML into a PDF file and let you download it, Controller allows you to define the url of a custom controller outputting any kind of report."),
'report_name': fields.char('Template Name', required=True, help="For QWeb reports, name of the template used in the rendering. The method 'render_html' of the model 'report.template_name' will be called (if any) to give the html. For RML reports, this is the LocalService name."),
'groups_id': fields.many2many('res.groups', 'res_groups_report_rel', 'uid', 'gid', 'Groups'),
# options
@ -163,7 +163,7 @@ class ir_actions_report_xml(osv.osv):
'report_xsl': fields.char('XSL Path'),
'report_xml': fields.char('XML Path'),
'report_rml': fields.char('Main Report File Path', help="The path to the main report file (depending on Report Type) or NULL if the content is in another data field"),
'report_rml': fields.char('Main Report File Path/controller', help="The path to the main report file/controller (depending on Report Type) or NULL if the content is in another data field"),
'report_file': fields.related('report_rml', type="char", required=False, readonly=False, string='Report File', help="The path to the main report file (depending on Report Type) or NULL if the content is in another field", store=True),
'report_sxw': fields.function(_report_sxw, type='char', string='SXW Path'),

View File

@ -59,12 +59,13 @@
<field name="name"/>
<field name="model"/>
<field name="report_type"/>
<field name="report_name"/>
<field name="report_name" attrs="{'invisible':[('report_type','=', 'controller')]}"/>
<field name="report_rml" attrs="{'invisible':[('report_type','!=', 'controller')]}"/>
</group>
<group>
<field name="multi"/>
<field name="attachment_use"/>
<field name="attachment"/>
<field name="attachment_use" attrs="{'invisible':[('report_type','=', 'controller')]}"/>
<field name="attachment" attrs="{'invisible':[('report_type','=', 'controller')]}"/>
</group>
</group>
<notebook>

View File

@ -69,7 +69,7 @@ class ir_attachment(osv.osv):
@tools.ormcache()
def _filestore(self, cr, uid, context=None):
return os.path.join(tools.config['data_dir'], 'filestore', cr.dbname)
return tools.config.filestore(cr.dbname)
# 'data' field implementation
def _full_path(self, cr, uid, location, path):

View File

@ -808,6 +808,38 @@ class RelativeDatetimeConverter(osv.AbstractModel):
return babel.dates.format_timedelta(
value - reference, add_direction=True, locale=locale)
class Contact(orm.AbstractModel):
_name = 'ir.qweb.field.contact'
_inherit = 'ir.qweb.field.many2one'
def record_to_html(self, cr, uid, field_name, record, column, options=None, context=None):
opf = options.get('fields') or ["name", "address", "phone", "mobile", "fax", "email"]
if not getattr(record, field_name):
return None
id = getattr(record, field_name).id
field_browse = self.pool[column._obj].browse(cr, openerp.SUPERUSER_ID, id, context={"show_address": True})
value = werkzeug.utils.escape( field_browse.name_get()[0][1] )
val = {
'name': value.split("\n")[0],
'address': werkzeug.utils.escape("\n".join(value.split("\n")[1:])),
'phone': field_browse.phone,
'mobile': field_browse.mobile,
'fax': field_browse.fax,
'city': field_browse.city,
'country_id': field_browse.country_id and field_browse.country_id.name_get()[0][1],
'email': field_browse.email,
'fields': opf,
'options': options
}
html = self.pool["ir.ui.view"].render(cr, uid, "base.contact", val, engine='ir.qweb', context=context).decode('utf8')
return HTMLSafe(html)
class HTMLSafe(object):
""" HTMLSafe string wrapper, Werkzeug's escape() has special handling for
objects with a ``__html__`` methods but AFAIK does not provide any such

View File

@ -0,0 +1,21 @@
<openerp>
<data>
<template id="contact">
<address t-ignore="true" class="mb0" itemscope="itemscope" itemtype="http://schema.org/Organization">
<div t-att-class="'name' not in fields and 'css_non_editable_mode_hidden'"><span itemprop="name" t-esc="name"/></div>
<div itemprop="address" itemscope="itemscope" itemtype="http://schema.org/PostalAddress">
<div t-if="address and 'address' in fields" class='css_editable_mode_hidden'>
<i t-if="not options.get('no_marker')" class='fa fa-map-marker'/> <span itemprop="streetAddress" t-raw="address.replace('\n', options.get('no_tag_br') and ', ' or ('&lt;br/&gt;%s' % ('' if options.get('no_marker') else '&amp;nbsp; &amp;nbsp; ')))"/>
</div>
<div t-if="city and 'city' in fields" class='css_editable_mode_hidden'>
<i t-if="not options.get('no_marker')" class='fa fa-map-marker'/> <span itemprop="addressLocality" t-raw="city"/>, <span itemprop="addressCountry" t-raw="country_id"/>
</div>
<div t-if="phone and 'phone' in fields" class='css_editable_mode_hidden'><i t-if="not options.get('no_marker')" class='fa fa-phone'/> <span itemprop="telephone" t-esc="phone"/></div>
<div t-if="mobile and 'mobile' in fields" class='css_editable_mode_hidden'><i t-if="not options.get('no_marker')" class='fa fa-mobile-phone'/> <span itemprop="telephone" t-esc="mobile"/></div>
<div t-if="fax and 'fax' in fields" class='css_editable_mode_hidden'><i t-if="not options.get('no_marker')" class='fa fa-file-text-o'/> <span itemprop="faxNumber" t-esc="fax"/></div>
<div t-if="email and 'email' in fields" class='css_editable_mode_hidden'><i t-if="not options.get('no_marker')" class='fa fa-envelope'/> <span itemprop="email" t-esc="email"/></div>
</div>
</address>
</template>
</data>
</openerp>

View File

@ -493,6 +493,10 @@ class res_config_settings(osv.osv_memory, res_config_module_installation_mixin):
return res
def execute(self, cr, uid, ids, context=None):
if context is None:
context = {}
context = dict(context, active_test=False)
if uid != SUPERUSER_ID and not self.pool['res.users'].has_group(cr, uid, 'base.group_erp_manager'):
raise openerp.exceptions.AccessError(_("Only administrators can change the settings"))
@ -500,7 +504,7 @@ class res_config_settings(osv.osv_memory, res_config_module_installation_mixin):
ir_module = self.pool['ir.module.module']
res_groups = self.pool['res.groups']
classified = self._get_classified_fields(cr, uid, context)
classified = self._get_classified_fields(cr, uid, context=context)
config = self.browse(cr, uid, ids[0], context)

View File

@ -586,7 +586,7 @@ class groups_implied(osv.osv):
res = super(groups_implied, self).write(cr, uid, ids, values, context)
if values.get('users') or values.get('implied_ids'):
# add all implied groups (to all users of each group)
for g in self.browse(cr, uid, ids):
for g in self.browse(cr, uid, ids, context=context):
gids = map(int, g.trans_implied_ids)
vals = {'users': [(4, u.id) for u in g.users]}
super(groups_implied, self).write(cr, uid, gids, vals, context)

View File

@ -127,7 +127,6 @@ def main(args):
check_root_user()
openerp.tools.config.parse_config(args)
check_postgres_user()
openerp.netsvc.init_logger()
report_configuration()
config = openerp.tools.config

View File

@ -36,6 +36,7 @@ import werkzeug.wsgi
import openerp
from openerp.service import security, model as service_model
from openerp.tools.func import lazy_property
_logger = logging.getLogger(__name__)
@ -286,7 +287,7 @@ class WebRequest(object):
def checked_call(___dbname, *a, **kw):
# The decorator can call us more than once if there is an database error. In this
# case, the request cursor is unusable. Rollback transaction to create a new one.
if self._cr:
if self._cr and not openerp.tools.config['test_enable']:
self._cr.rollback()
return self.endpoint(*a, **kw)
@ -1077,22 +1078,25 @@ class Root(object):
path = openerp.tools.config.session_dir
_logger.debug('HTTP sessions stored in: %s', path)
self.session_store = werkzeug.contrib.sessions.FilesystemSessionStore(path, session_class=OpenERPSession)
self._loaded = False
# TODO should we move this to ir.http so that only configured modules are served ?
_logger.info("HTTP Configuring static files")
self.load_addons()
@lazy_property
def nodb_routing_map(self):
_logger.info("Generating nondb routing")
self.nodb_routing_map = routing_map([''] + openerp.conf.server_wide_modules, True)
return routing_map([''] + openerp.conf.server_wide_modules, True)
def __call__(self, environ, start_response):
""" Handle a WSGI request
"""
if not self._loaded:
self._loaded = True
self.load_addons()
return self.dispatch(environ, start_response)
def load_addons(self):
""" Load all addons from addons patch containg static files and
controllers and configure them. """
# TODO should we move this to ir.http so that only configured modules are served ?
statics = {}
for addons_path in openerp.modules.module.ad_paths:
@ -1106,12 +1110,16 @@ class Root(object):
_logger.debug("Loading %s", module)
if 'openerp.addons' in sys.modules:
m = __import__('openerp.addons.' + module)
else:
m = None
addons_module[module] = m
addons_manifest[module] = manifest
statics['/%s/static' % module] = path_static
app = werkzeug.wsgi.SharedDataMiddleware(self.dispatch, statics)
self.dispatch = DisableCacheMiddleware(app)
if statics:
_logger.info("HTTP Configuring static files")
app = werkzeug.wsgi.SharedDataMiddleware(self.dispatch, statics)
self.dispatch = DisableCacheMiddleware(app)
def setup_session(self, httprequest):
# recover or create session
@ -1284,11 +1292,8 @@ class CommonController(Controller):
""" Method used by client APIs to contact OpenERP. """
return dispatch_rpc(service, method, args)
root = None
def wsgi_postload():
global root
root = Root()
openerp.service.wsgi_server.register_wsgi_handler(root)
# register main wsgi handler
root = Root()
openerp.service.wsgi_server.register_wsgi_handler(root)
# vim:et:ts=4:sw=4:

View File

@ -42,6 +42,7 @@ from openerp import SUPERUSER_ID
from openerp.tools.translate import _
from openerp.modules.module import initialize_sys_path, \
load_openerp_module, init_module_models, adapt_version
from module import runs_post_install
_logger = logging.getLogger(__name__)
_test_logger = logging.getLogger('openerp.tests')
@ -425,8 +426,13 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
for model in registry.models.values():
model._register_hook(cr)
# STEP 9: Run the post-install tests
cr.commit()
if openerp.tools.config['test_enable']:
cr.execute("SELECT name FROM ir_module_module WHERE state='installed'")
for module_name in cr.fetchall():
report.record_result(openerp.modules.module.run_unit_tests(module_name[0], cr.dbname, position=runs_post_install))
finally:
cr.close()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -356,30 +356,6 @@ class TestStream(object):
current_test = None
def run_unit_tests(module_name, dbname):
"""
:returns: ``True`` if all of ``module_name``'s tests succeeded, ``False``
if any of them failed.
:rtype: bool
"""
global current_test
current_test = module_name
mods = get_test_modules(module_name)
r = True
for m in mods:
tests = unwrap_suite(unittest2.TestLoader().loadTestsFromModule(m))
suite = unittest2.TestSuite(itertools.ifilter(runs_at_install, tests))
_logger.info('running %s tests.', m.__name__)
result = unittest2.TextTestRunner(verbosity=2, stream=TestStream(m.__name__)).run(suite)
if not result.wasSuccessful():
r = False
_logger.error("Module %s: %d failures, %d errors",
module_name, len(result.failures), len(result.errors))
current_test = None
return r
def runs_at(test, hook, default):
# by default, tests do not run post install
test_runs = getattr(test, hook, default)
@ -396,6 +372,30 @@ def runs_at(test, hook, default):
runs_at_install = functools.partial(runs_at, hook='at_install', default=True)
runs_post_install = functools.partial(runs_at, hook='post_install', default=False)
def run_unit_tests(module_name, dbname, position=runs_at_install):
"""
:returns: ``True`` if all of ``module_name``'s tests succeeded, ``False``
if any of them failed.
:rtype: bool
"""
global current_test
current_test = module_name
mods = get_test_modules(module_name)
r = True
for m in mods:
tests = unwrap_suite(unittest2.TestLoader().loadTestsFromModule(m))
suite = unittest2.TestSuite(itertools.ifilter(position, tests))
_logger.info('running %s tests.', m.__name__)
result = unittest2.TextTestRunner(verbosity=2, stream=TestStream(m.__name__)).run(suite)
if not result.wasSuccessful():
r = False
_logger.error("Module %s: %d failures, %d errors",
module_name, len(result.failures), len(result.errors))
current_test = None
return r
def unwrap_suite(test):
"""
Attempts to unpack testsuites (holding suites or cases) in order to

View File

@ -126,6 +126,11 @@ def exp_duplicate_database(db_original_name, db_name):
with closing(db.cursor()) as cr:
cr.autocommit(True) # avoid transaction block
cr.execute("""CREATE DATABASE "%s" ENCODING 'unicode' TEMPLATE "%s" """ % (db_name, db_original_name))
from_fs = openerp.tools.config.filestore(db_original_name)
to_fs = openerp.tools.config.filestore(db_name)
if os.path.exists(from_fs) and not os.path.exists(to_fs):
shutil.copy(from_fs, to_fs)
return True
def exp_get_progress(id):
@ -178,6 +183,10 @@ def exp_drop(db_name):
raise Exception("Couldn't drop database %s: %s" % (db_name, e))
else:
_logger.info('DROP DB: %s', db_name)
fs = openerp.tools.config.filestore(db_name)
if os.path.exists(fs):
shutil.rmtree(fs)
return True
def _set_pg_password_in_environment(func):
@ -328,6 +337,11 @@ def exp_rename(old_name, new_name):
except Exception, e:
_logger.error('RENAME DB: %s -> %s failed:\n%s', old_name, new_name, e)
raise Exception("Couldn't rename database %s to %s: %s" % (old_name, new_name, e))
old_fs = openerp.tools.config.filestore(old_name)
new_fs = openerp.tools.config.filestore(new_name)
if os.path.exists(old_fs) and not os.path.exists(new_fs):
shutil.move(old_fs, new_fs)
return True
@openerp.tools.mute_logger('openerp.sql_db')

View File

@ -1,178 +0,0 @@
# -*- coding: utf-8 -*-
#
# Copyright P. Christeas <p_christ@hol.gr> 2008-2010
# Copyright 2010 OpenERP SA. (http://www.openerp.com)
#
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
###############################################################################
""" This module offers the family of HTTP-based servers. These are not a single
class/functionality, but a set of network stack layers, implementing
extendable HTTP protocols.
The OpenERP server defines a single instance of a HTTP server, listening at
the standard 8069, 8071 ports (well, it is 2 servers, and ports are
configurable, of course). This "single" server then uses a `MultiHTTPHandler`
to dispatch requests to the appropriate channel protocol, like the XML-RPC,
static HTTP, DAV or other.
"""
import base64
import posixpath
import urllib
import os
import logging
from websrv_lib import *
import openerp.tools as tools
try:
import fcntl
except ImportError:
fcntl = None
try:
from ssl import SSLError
except ImportError:
class SSLError(Exception): pass
_logger = logging.getLogger(__name__)
# TODO delete this for 6.2, it is still needed for 6.1.
class HttpLogHandler:
""" helper class for uniform log handling
Please define self._logger at each class that is derived from this
"""
_logger = None
def log_message(self, format, *args):
self._logger.debug(format % args) # todo: perhaps other level
def log_error(self, format, *args):
self._logger.error(format % args)
def log_exception(self, format, *args):
self._logger.exception(format, *args)
def log_request(self, code='-', size='-'):
self._logger.debug('"%s" %s %s',
self.requestline, str(code), str(size))
class StaticHTTPHandler(HttpLogHandler, FixSendError, HttpOptions, HTTPHandler):
_logger = logging.getLogger(__name__)
_HTTP_OPTIONS = { 'Allow': ['OPTIONS', 'GET', 'HEAD'] }
def __init__(self,request, client_address, server):
HTTPHandler.__init__(self,request,client_address,server)
document_root = tools.config.get('static_http_document_root', False)
assert document_root, "Please specify static_http_document_root in configuration, or disable static-httpd!"
self.__basepath = document_root
def translate_path(self, path):
"""Translate a /-separated PATH to the local filename syntax.
Components that mean special things to the local file system
(e.g. drive or directory names) are ignored. (XXX They should
probably be diagnosed.)
"""
# abandon query parameters
path = path.split('?',1)[0]
path = path.split('#',1)[0]
path = posixpath.normpath(urllib.unquote(path))
words = path.split('/')
words = filter(None, words)
path = self.__basepath
for word in words:
if word in (os.curdir, os.pardir): continue
path = os.path.join(path, word)
return path
def init_static_http():
if not tools.config.get('static_http_enable', False):
return
document_root = tools.config.get('static_http_document_root', False)
assert document_root, "Document root must be specified explicitly to enable static HTTP service (option --static-http-document-root)"
base_path = tools.config.get('static_http_url_prefix', '/')
reg_http_service(base_path, StaticHTTPHandler)
_logger.info("Registered HTTP dir %s for %s", document_root, base_path)
import security
class OpenERPAuthProvider(AuthProvider):
""" Require basic authentication."""
def __init__(self,realm='OpenERP User'):
self.realm = realm
self.auth_creds = {}
self.auth_tries = 0
self.last_auth = None
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:
_logger.debug("Fail auth: %s" % e )
return False
def checkRequest(self,handler,path, db=False):
auth_str = handler.headers.get('Authorization',False)
try:
if not db:
db = handler.get_db_from_path(path)
except Exception:
if path.startswith('/'):
path = path[1:]
psp= path.split('/')
if len(psp)>1:
db = psp[0]
else:
#FIXME!
_logger.info("Wrong path: %s, failing auth" %path)
raise AuthRejectedExc("Authorization failed. Wrong sub-path.")
if self.auth_creds.get(db):
return True
if auth_str and auth_str.startswith('Basic '):
auth_str=auth_str[len('Basic '):]
(user,passwd) = base64.decodestring(auth_str).split(':')
_logger.info("Found user=\"%s\", passwd=\"***\" for db=\"%s\"", user, db)
acd = self.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:
_logger.info("Failing authorization after 5 requests w/o password")
raise AuthRejectedExc("Authorization failed.")
self.auth_tries += 1
raise AuthRequiredExc(atype='Basic', realm=self.realm)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -164,153 +164,6 @@ def wsgi_xmlrpc(environ, start_response):
params, method = xmlrpclib.loads(data)
return xmlrpc_return(start_response, service, method, params, string_faultcode)
def wsgi_webdav(environ, start_response):
pi = environ['PATH_INFO']
if environ['REQUEST_METHOD'] == 'OPTIONS' and pi in ['*','/']:
return return_options(environ, start_response)
elif pi.startswith('/webdav'):
http_dir = websrv_lib.find_http_service(pi)
if http_dir:
path = pi[len(http_dir.path):]
if path.startswith('/'):
environ['PATH_INFO'] = path
else:
environ['PATH_INFO'] = '/' + path
return http_to_wsgi(http_dir)(environ, start_response)
def return_options(environ, start_response):
# Microsoft specific header, see
# http://www.ibm.com/developerworks/rational/library/2089.html
if 'Microsoft' in environ.get('User-Agent', ''):
options = [('MS-Author-Via', 'DAV')]
else:
options = []
options += [('DAV', '1 2'), ('Allow', 'GET HEAD PROPFIND OPTIONS REPORT')]
start_response("200 OK", [('Content-Length', str(0))] + options)
return []
def http_to_wsgi(http_dir):
"""
Turn a BaseHTTPRequestHandler into a WSGI entry point.
Actually the argument is not a bare BaseHTTPRequestHandler but is wrapped
(as a class, so it needs to be instanciated) in a HTTPDir.
This code is adapted from wbsrv_lib.MultiHTTPHandler._handle_one_foreign().
It is a temporary solution: the HTTP sub-handlers (in particular the
document_webdav addon) have to be WSGIfied.
"""
def wsgi_handler(environ, start_response):
headers = {}
for key, value in environ.items():
if key.startswith('HTTP_'):
key = key[5:].replace('_', '-').title()
headers[key] = value
if key == 'CONTENT_LENGTH':
key = key.replace('_', '-').title()
headers[key] = value
if environ.get('Content-Type'):
headers['Content-Type'] = environ['Content-Type']
path = urllib.quote(environ.get('PATH_INFO', ''))
if environ.get('QUERY_STRING'):
path += '?' + environ['QUERY_STRING']
request_version = 'HTTP/1.1' # TODO
request_line = "%s %s %s\n" % (environ['REQUEST_METHOD'], path, request_version)
class Dummy(object):
pass
# Let's pretend we have a server to hand to the handler.
server = Dummy()
server.server_name = environ['SERVER_NAME']
server.server_port = int(environ['SERVER_PORT'])
# Initialize the underlying handler and associated auth. provider.
con = openerp.service.websrv_lib.noconnection(environ['wsgi.input'])
handler = http_dir.instanciate_handler(con, environ['REMOTE_ADDR'], server)
# Populate the handler as if it is called by a regular HTTP server
# and the request is already parsed.
handler.wfile = StringIO.StringIO()
handler.rfile = environ['wsgi.input']
handler.headers = headers
handler.command = environ['REQUEST_METHOD']
handler.path = path
handler.request_version = request_version
handler.close_connection = 1
handler.raw_requestline = request_line
handler.requestline = request_line
# Handle authentication if there is an auth. provider associated to
# the handler.
if hasattr(handler, 'auth_provider'):
try:
handler.auth_provider.checkRequest(handler, path)
except websrv_lib.AuthRequiredExc, ae:
# Darwin 9.x.x webdav clients will report "HTTP/1.0" to us, while they support (and need) the
# authorisation features of HTTP/1.1
if request_version != 'HTTP/1.1' and ('Darwin/9.' not in handler.headers.get('User-Agent', '')):
start_response("403 Forbidden", [])
return []
start_response("401 Authorization required", [
('WWW-Authenticate', '%s realm="%s"' % (ae.atype,ae.realm)),
# ('Connection', 'keep-alive'),
('Content-Type', 'text/html'),
('Content-Length', 4), # len(self.auth_required_msg)
])
return ['Blah'] # self.auth_required_msg
except websrv_lib.AuthRejectedExc,e:
start_response("403 %s" % (e.args[0],), [])
return []
method_name = 'do_' + handler.command
# Support the OPTIONS method even when not provided directly by the
# handler. TODO I would prefer to remove it and fix the handler if
# needed.
if not hasattr(handler, method_name):
if handler.command == 'OPTIONS':
return return_options(environ, start_response)
start_response("501 Unsupported method (%r)" % handler.command, [])
return []
# Finally, call the handler's method.
try:
method = getattr(handler, method_name)
method()
# The DAV handler buffers its output and provides a _flush()
# method.
getattr(handler, '_flush', lambda: None)()
response = parse_http_response(handler.wfile.getvalue())
response_headers = response.getheaders()
body = response.read()
start_response(str(response.status) + ' ' + response.reason, response_headers)
return [body]
except (websrv_lib.AuthRejectedExc, websrv_lib.AuthRequiredExc):
raise
except Exception, e:
start_response("500 Internal error", [])
return []
return wsgi_handler
def parse_http_response(s):
""" Turn a HTTP response string into a httplib.HTTPResponse object."""
class DummySocket(StringIO.StringIO):
"""
This is used to provide a StringIO to httplib.HTTPResponse
which, instead of taking a file object, expects a socket and
uses its makefile() method.
"""
def makefile(self, *args, **kw):
return self
response = httplib.HTTPResponse(DummySocket(s))
response.begin()
return response
# WSGI handlers registered through the register_wsgi_handler() function below.
module_handlers = []
# RPC endpoints registered through the register_rpc_endpoint() function below.
@ -342,7 +195,7 @@ def application_unproxied(environ, start_response):
del threading.current_thread().dbname
# Try all handlers until one returns some result (i.e. not None).
wsgi_handlers = [wsgi_xmlrpc, wsgi_webdav]
wsgi_handlers = [wsgi_xmlrpc]
wsgi_handlers += module_handlers
for handler in wsgi_handlers:
result = handler(environ, start_response)

View File

@ -6,7 +6,8 @@ function waitFor (ready, callback, timeout, timeoutMessageCallback) {
(function waitLoop() {
if(new Date - start > timeout) {
error(timeoutMessageCallback ? timeoutMessageCallback() : "Timeout after "+timeout+" ms");
console.log('error', timeoutMessageCallback ? timeoutMessageCallback() : "Timeout after "+timeout+" ms");
phantom.exit(1);
} else if (ready()) {
callback();
} else {
@ -15,10 +16,6 @@ function waitFor (ready, callback, timeout, timeoutMessageCallback) {
}());
}
function error(message) {
console.log('error', message);
phantom.exit(1);
}
function PhantomTest() {
var self = this;
this.options = JSON.parse(phantom.args[phantom.args.length-1]);
@ -49,10 +46,12 @@ function PhantomTest() {
}));
msg.push('(leaf frame on top)')
}
error(JSON.stringify(msg.join('\n')));
console.log('error', JSON.stringify(msg.join('\n')));
phantom.exit(1);
};
this.page.onAlert = function(message) {
error(message);
console.log('error', message);
phantom.exit(1);
};
this.page.onConsoleMessage = function(message) {
console.log(message);
@ -78,7 +77,8 @@ function PhantomTest() {
if(!found) {
console.log('Injecting', src, 'needed for', need);
if(!self.page.injectJs(src)) {
error("Cannot inject " + src);
console.log('error', "Cannot inject " + src);
phantom.exit(1);
}
}
}
@ -88,8 +88,9 @@ function PhantomTest() {
self.page.evaluate(function () {
var message = ("Timeout\nhref: " + window.location.href
+ "\nreferrer: " + document.referrer
+ "\n\n" + document.body.innerHTML).replace(/[^a-z0-9\s~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, "*");
error(message);
+ "\n\n" + (document.body && document.body.innerHTML)).replace(/[^a-z0-9\s~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, "*");
console.log('error', message);
phantom.exit(1);
});
}, self.timeout);
@ -108,7 +109,8 @@ function PhantomTest() {
var url = self.origin + url_path;
self.page.open(url, function(status) {
if (status !== 'success') {
error("failed to load " + url)
console.log('error', "failed to load " + url);
phantom.exit(1);
} else {
console.log('loaded', url, status);
// process ready
@ -119,7 +121,7 @@ function PhantomTest() {
try {
console.log("page.evaluate eval expr:", ready);
r = !!eval(ready);
} catch(ex) {
} catch(ex) {
}
console.log("page.evaluate eval result:", r);
return r;

View File

@ -152,19 +152,11 @@ class configmanager(object):
parser.add_option_group(group)
# WEB
# TODO move to web addons after MetaOption merge
group = optparse.OptionGroup(parser, "Web interface Configuration")
group.add_option("--db-filter", dest="dbfilter", default='.*',
help="Filter listed database", metavar="REGEXP")
parser.add_option_group(group)
# Static HTTP
group = optparse.OptionGroup(parser, "Static HTTP service")
group.add_option("--static-http-enable", dest="static_http_enable", action="store_true", my_default=False, help="enable static HTTP service for serving plain HTML files")
group.add_option("--static-http-document-root", dest="static_http_document_root", help="specify the directory containing your static HTML files (e.g '/var/www/')")
group.add_option("--static-http-url-prefix", dest="static_http_url_prefix", help="specify the URL root prefix where you want web browsers to access your static HTML files (e.g '/')")
parser.add_option_group(group)
# Testing Group
group = optparse.OptionGroup(parser, "Testing Configuration")
group.add_option("--test-file", dest="test_file", my_default=False,
@ -313,9 +305,10 @@ class configmanager(object):
self.options[option.dest] = option.my_default
self.casts[option.dest] = option
self.parse_config(None, False)
# generate default config
self._parse_config()
def parse_config(self, args=None, complete=True):
def parse_config(self, args=None):
""" Parse the configuration file (if any) and the command-line
arguments.
@ -329,10 +322,12 @@ class configmanager(object):
Typical usage of this method:
openerp.tools.config.parse_config(sys.argv[1:])
:param complete: this is a hack used in __init__(), leave it to True.
"""
self._parse_config(args)
openerp.netsvc.init_logger()
openerp.modules.module.initialize_sys_path()
def _parse_config(self, args=None):
if args is None:
args = []
opt, args = self.parser.parse_args(args)
@ -391,7 +386,6 @@ class configmanager(object):
'db_maxconn', 'import_partial', 'addons_path',
'xmlrpc', 'syslog', 'without_demo', 'timezone',
'xmlrpcs_interface', 'xmlrpcs_port', 'xmlrpcs',
'static_http_enable', 'static_http_document_root', 'static_http_url_prefix',
'secure_cert_file', 'secure_pkey_file', 'dbfilter', 'log_handler', 'log_level', 'log_db'
]
@ -503,8 +497,6 @@ class configmanager(object):
openerp.conf.server_wide_modules = map(lambda m: m.strip(), opt.server_wide_modules.split(','))
else:
openerp.conf.server_wide_modules = ['web','web_kanban']
if complete:
openerp.modules.module.initialize_sys_path()
def _generate_pgpassfile(self):
"""
@ -662,6 +654,9 @@ class configmanager(object):
os.chmod(d, 0700)
return d
def filestore(self, dbname):
return os.path.join(self['data_dir'], 'filestore', dbname)
config = configmanager()

View File

@ -3,7 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010 OpenERP s.a. (<http://openerp.com>).
# Copyright (C) 2010, 2014 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@ -20,11 +20,39 @@
#
##############################################################################
__all__ = ['synchronized']
__all__ = ['synchronized', 'lazy_property']
from functools import wraps
from inspect import getsourcefile
class lazy_property(object):
""" Decorator for a lazy property of an object, i.e., an object attribute
that is determined by the result of a method call evaluated once. To
reevaluate the property, simply delete the attribute on the object, and
get it again.
"""
def __init__(self, fget):
self.fget = fget
self.name = fget.__name__
def __get__(self, obj, cls):
if obj is None:
return self
value = self.fget(obj)
setattr(obj, self.name, value)
return value
@staticmethod
def reset_all(obj):
""" Reset all lazy properties on the instance `obj`. """
cls = type(obj)
obj_dict = obj.__dict__
for name in obj_dict.keys():
if isinstance(getattr(cls, name, None), lazy_property):
obj_dict.pop(name)
def synchronized(lock_attr='_lock'):
def decorator(func):
@wraps(func)

View File

@ -3,7 +3,7 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010-2013 OpenERP s.a. (<http://openerp.com>).
# Copyright (C) 2010-2014 OpenERP s.a. (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@ -83,7 +83,8 @@ def exec_pg_command(name, *args):
raise Exception('Couldn\'t find %s' % name)
args2 = (prog,) + args
return subprocess.call(args2)
with open(os.devnull) as dn:
return subprocess.call(args2, stdout=dn, stderr=subprocess.STDOUT)
def exec_pg_command_pipe(name, *args):
prog = find_pg_tool(name)