Merge branch 'master' of openobject-server into mdv-gpl3-fwd

Conflicts:
	bin/netsvc.py
	bin/sql_db.py
	bin/ssl/SecureXMLRPCServer.py (note: fixes are lost now)

bzr revid: p_christ@hol.gr-20081223154608-fs0830k7vyo81m5u
This commit is contained in:
P. Christeas 2008-12-23 17:46:08 +02:00
commit a8229141bc
63 changed files with 48200 additions and 12760 deletions

View File

@ -1,4 +1,7 @@
include README
include bin/import_xml.rng
include bin/server.cert
include bin/server.pkey
recursive-include doc *
recursive-include man *
recursive-include bin *xml *xsl *sql *rml *sxw *csv *rng

View File

@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: OpenERP
Version: 5.0.0-rc1
Version: 5.0.0-rc2
Author: Tiny.be
Author-email: fp at tiny be
Maintainer: Tiny.be

View File

@ -512,11 +512,12 @@ def load_module_graph(cr, graph, status=None, check_access_rules=True, **kwargs)
package_todo.append(package.name)
ver = release.major_version + '.' + package.data.get('version', '1.0')
# update the installed version in database...
cr.execute("update ir_module_module set state='installed', latest_version=%s where id=%s", (ver, mid,))
cr.commit()
#cr.execute("update ir_module_module set state='installed', latest_version=%s where id=%s", (ver, mid,))
# Set new modules and dependencies
modobj = pool.get('ir.module.module')
modobj.write(cr, 1, [mid], {'state':'installed', 'latest_version':ver})
cr.commit()
# Update translations for all installed languages
if modobj:

View File

@ -2877,5 +2877,6 @@
<test expr="currency_id.code == 'eur'.upper()"/>
<test expr="name">Tiny sprl</test>
</assert>
</data>
</openerp>

View File

@ -257,13 +257,14 @@
<!-- register on configuratuion -->
</data>
<data noupdate="1">
<record id="config_wizard_step_user" model="ir.actions.todo">
<field name="name">Create User</field>
<field name="note">Create your users.
You will be able to assign groups to users. Groups define the access rights of each users on the different objects of the system.
</field>
<field name="action_id" ref="action_config_user_form"/>
<field name="state">open</field>
<field name="sequence">10</field>
</record>
@ -275,7 +276,6 @@ the simplified interface, which has less options and fields but is easier to
understand. You will be able to switch to the extended view later.
</field>
<field name="action_id" ref="action_config_simple_view_form"/>
<field name="state">open</field>
<field name="sequence">5</field>
</record>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<!-- Values -->
<record id="values_view_form_action" model="ir.ui.view">
<field name="name">ir.values.form.action</field>
<field name="model">ir.values</field>
<field name="type">form</field>
<field name="priority">20</field>
<field name="arch" type="xml">
<form string="Connect Events to Actions">
<field name="name" select="1" required="1"/>
<newline/>
<group col="2" colspan="2">
<separator string="Action Source" colspan="2"/>
<field name="model_id" on_change="onchange_object_id(model_id)"/>
<field name="model" select="1" required="1"/>
<field name="res_id"/>
<field name="key2" select="2" required="1"/>
</group>
<group col="2" colspan="2">
<separator string="Action To Launch" colspan="2"/>
<field name="action_id" on_change="onchange_action_id(action_id)"/>
<field name="value_unpickle" required="1"/>
<field name="object" readonly="1"/>
</group>
</form>
</field>
</record>
<record id="act_values_form_action" model="ir.actions.act_window">
<field name="name">Connect Actions To Client Events</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.values</field>
<field name="view_type">form</field>
<field name="view_mode">form,tree</field>
<field name="view_id" ref="values_view_form_action"/>
<field name="domain">[('key','=','action')]</field>
<field name="context">{'read':'default','default_object':1}</field>
</record>
<menuitem action="act_values_form_action" id="menu_values_form_action" parent="base.menu_custom_action"/>
<!-- Values -->
@ -705,8 +745,8 @@
'readonly': [('ttype','!=','one2many'), ('ttype','!=','many2one'), ('ttype','!=','many2many')]}"/>
<field name="relation_field" attrs="{'required': [('ttype','=','one2many')],
'readonly': [('ttype','!=','one2many')]}"/>
<field name="selection" attrs="{'required': [('ttype','=','selection')], 'readonly': [('ttype','!=','selection')]}"/>
<field name="size" attrs="{'required': [('ttype','=','char')], 'readonly': [('ttype','!=','char')]}"/>
<field name="selection" attrs="{'required': [('ttype','in',['selection','reference'])], 'readonly': [('ttype','not in',['selection','reference'])]}"/>
<field name="size" attrs="{'required': [('ttype','in',['char','reference'])], 'readonly': [('ttype','not in',['char','reference'])]}"/>
<field name="state"/>
<field name="domain" attrs="{'readonly': [('relation','=','')]}"/>
</group>
@ -783,8 +823,8 @@
<field name="relation" select="2" attrs="{'required': [('ttype','in', ['many2one','one2many','many2many'])],
'readonly': [('ttype','not in', ['many2one','one2many','many2many'])]}"/>
<field name="relation_field" attrs="{'required': [('ttype','=','one2many')], 'readonly': [('ttype','!=','one2many')]}"/>
<field name="selection" attrs="{'required': [('ttype','=','selection')], 'readonly': [('ttype','!=','selection')]}"/>
<field name="size" attrs="{'required': [('ttype','=','char')], 'readonly': [('ttype','!=','char')]}"/>
<field name="selection" attrs="{'required': [('ttype','in',['selection','reference'])], 'readonly': [('ttype','not in',['selection','reference'])]}"/>
<field name="size" attrs="{'required': [('ttype','in',['char','reference'])], 'readonly': [('ttype','not in',['char','reference'])]}"/>
<field name="state"/>
<field name="domain" attrs="{'readonly': [('relation','=','')]}"/>
</group>
@ -1148,46 +1188,43 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Server Action">
<field name="name" select="1"/>
<field name="state" select="1"/>
<field name="model_id" select="1"/>
<field name="sequence" select="2"/>
<field name="condition" colspan="4"/>
<group col="6" colspan="4">
<field name="name" select="1"/>
<field name="model_id" select="1"/>
<field name="state" select="1"/>
<field name="sequence" select="2"/>
<field name="condition"/>
</group>
<notebook colspan="4">
<page string="Python Code" attrs="{'invisible':[('state','!=','code')]}">
<page string="Python Code" attrs="{'invisible':[('state','!=','code')]}">
<separator colspan="4" string="Python Code"/>
<field name="code" colspan="4" nolabel="1"/>
</page>
<page string="Trigger" attrs="{'invisible':[('state','!=','trigger')]}">
<separator colspan="4" string="Trigger Configuration"/>
<field name="wkf_model_id"/>
<field name="trigger_obj_id" select="2" domain="[('model_id','=',model_id)]" on_change="on_trigger_obj_id(trigger_obj_id)"/>
<field name="trigger_name" select="2"/>
<field name="wkf_model_id" attrs="{'required':[('state','=','trigger')]}"/>
<field name="trigger_obj_id" select="2" context="{'key':''}" domain="[('model_id','=',model_id)]" attrs="{'required':[('state','=','trigger')]}"/>
<field name="trigger_name" select="2" attrs="{'required':[('state','=','trigger')]}"/>
</page>
<page string="Action to Launch" attrs="{'invisible':[('state','!=','client_action')]}">
<field name="action_id" select="2" colspan="4"/>
<page string="Action to Launch" attrs="{'invisible':[('state','!=','client_action')]}">
<separator colspan="4" string="Client Action Configuration"/>
<field name="action_id" select="2" attrs="{'required':[('state','=','client_action')]}"/>
</page>
<page string="Email Configuration" attrs="{'invisible':[('state','!=','email')]}">
<separator colspan="4" string="Email Configuration"/>
<field name="email" domain="[('model_id','=',model_id)]"/>
<field name="subject" colspan="4"/>
<field name="message" select="2" colspan="4"/>
<field name="email" domain="[('model_id','=',model_id)]" attrs="{'required':[('state','=','email')]}"/>
<field name="subject" colspan="4" attrs="{'required':[('state','=','email')]}"/>
<field name="message" select="2" colspan="4" attrs="{'required':[('state','=','email')]}"/>
<newline/>
<label colspan="4" string="Access all the fields related to the current object using expression in double brackets, i.e. [[ object.partner_id.name ]]" align="0.0"/>
<label colspan="4" string="Access all the fields related to the current object using expression in double brackets, i.e.[[ object.partner_id.name ]]" align="0.0"/>
</page>
<page string="SMS Configuration" attrs="{'invisible':[('state','!=','sms')]}">
<separator colspan="4" string="SMS Configuration"/>
<field name="mobile" domain="[('model_id','=',model_id)]"/>
<field name="sms" colspan="4"/>
<field name="mobile" domain="[('model_id','=',model_id)]" attrs="{'required':[('state','=','email')]}"/>
<field name="sms" colspan="4" attrs="{'required':[('state','=','email')]}"/>
<newline/>
<label colspan="4" string="Access all the fields related to the current object using expression in double brackets, i.e. [[ object.partner_id.name ]]" align="0.0"/>
</page>
<page string="Create / Write" attrs="{'invisible':[('state','!=','object_create'),('state','!=','object_write')]}">
<separator colspan="4" string="Fields Mapping"/>
<field name="srcmodel_id" select="2" attrs="{'required':[('state','!=','dummy'), ('state','!=','sms'), ('state','!=','code'), ('state','!=','loop'),('state','!=','trigger'), ('state','!=','client_action'), ('state','!=','email'), ('state','!=','sms'), ('state','!=','other')]}"/>
@ -1207,21 +1244,17 @@
<field name="write_id" attrs="{'readonly':[('state','!=','object_write')]}"/>
<label colspan="4" string="If you use a formula type, use a python expression using the variable 'object'." align="0.0"/>
</page>
<page string="Iteration Actions" attrs="{'invisible':[('state','!=','loop')]}">
<separator colspan="4" string="Iteration Action Configuration"/>
<field name="loop_action" domain="[('state','!=','loop')]"/>
<field name="expression" attrs="{'required':[('state','=','loop')]}"/>
<label colspan="4" string="Define the expression that generate a list" align="0.0"/>
<field name="loop_action" domain="[('state','!=','loop')]" attrs="{'required':[('state','=','loop')]}"/>
</page>
<page string="Multi Actions" attrs="{'invisible':[('state','!=','other')]}">
<separator colspan="4" string="Other Actions Configuration"/>
<field name="child_ids" nolabel="1" colspan="4"/>
<label colspan="4" string="Only one client action will be execute, last
clinent action will be consider in case of multiples clients actions" align="0.0"/>
</page>
</notebook>
<field name="type" readonly="1"/>
</form>
@ -1236,6 +1269,7 @@
<tree string="Server Actions">
<field name="name"/>
<field name="state"/>
<field name="model_id"/>
<field name="sequence"/>
</tree>
</field>
@ -1274,28 +1308,28 @@
</record>
<menuitem action="action_model_grid_security" id="menu_ir_access_grid" parent="menu_security_access"/>
<record id="ir_actions_todo_tree" model="ir.ui.view">
<record id="ir_actions_todo_tree" model="ir.ui.view">
<field name="model">ir.actions.todo</field>
<field name="name">Config Wizard Steps</field>
<field name="name">Config Wizard Steps</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree editable="bottom" string="Config Wizard Steps">
<field name="name" select="1"/>
<field name="name" select="1"/>
<field name="action_id" select="1"/>
<field name="sequence"/>
<field name="state"/>
<field name="active" select="1"/>
<field name="active" select="1"/>
</tree>
</field>
</record>
<record id="config_wizard_step_view_form" model="ir.ui.view">
<field name="model">ir.actions.todo</field>
<field name="name">Config Wizard Steps</field>
<field name="name">Config Wizard Steps</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form editable="bottom" string="Config Wizard Steps">
<field name="name" select="1"/>
<field name="active" select="1"/>
<field name="active" select="1"/>
<field name="action_id" select="1"/>
<field name="sequence"/>
<field name="state"/>
@ -1308,7 +1342,7 @@
<field name="res_model">ir.actions.todo</field>
<field name="view_id" ref="ir_actions_todo_tree"/>
<field name="view_type">form</field>
<field name="domain">[('type','=','configure')]</field>
<field name="domain">[('type','=','configure')]</field>
</record>
<menuitem id="next_id_11" name="Configuration Wizards" parent="base.menu_config" sequence="1"/>
<menuitem action="act_ir_actions_todo_form" id="menu_ir_actions_todo_form" parent="next_id_11"/>

View File

@ -365,7 +365,7 @@ server_object_lines()
# Actions that are run on the server side
#
class actions_server(osv.osv):
def _select_signals(self, cr, uid, context={}):
cr.execute("select distinct t.signal as key, t.signal || ' - [ ' || w.osv || ' ] ' as val from wkf w, wkf_activity a, wkf_transition t "\
" where w.id = a.wkf_id " \
@ -377,15 +377,14 @@ class actions_server(osv.osv):
if not rs[0] == None and not rs[1] == None:
res.append(rs)
return res
_name = 'ir.actions.server'
_table = 'ir_act_server'
_sequence = 'ir_actions_id_seq'
_order = 'sequence'
_columns = {
'name': fields.char('Action Name', required=True, size=64),
'condition' : fields.char('Condition', size=256),
'sub_condition' : fields.char('Condition', size=256),
'name': fields.char('Action Name', required=True, size=64, help="Easy to Refer action by name i.e. One Sales Order -> Many Invoice"),
'condition' : fields.char('Condition', size=256, required=True, help="Condition that is to be test before execute action, i.e : object.list_price > object.cost_price"),
'state': fields.selection([
('client_action','Client Action'),
('dummy','Dummy'),
@ -397,18 +396,18 @@ class actions_server(osv.osv):
('object_create','Create Object'),
('object_write','Write Object'),
('other','Multi Actions'),
], 'Action Type', required=True, size=32),
'code':fields.text('Python Code'),
'sequence': fields.integer('Sequence'),
'model_id': fields.many2one('ir.model', 'Object', required=True),
'action_id': fields.many2one('ir.actions.actions', 'Client Action'),
'trigger_name': fields.selection(_select_signals, string='Trigger Name', size=128),
'wkf_model_id': fields.many2one('ir.model', 'Workflow on'),
'trigger_obj_id': fields.many2one('ir.model.fields','Trigger On'),
'email': fields.char('Email Address', size=512),
'subject': fields.char('Subject', size=1024, translate=True),
'message': fields.text('Message', translate=True),
'mobile': fields.char('Mobile No', size=512),
], 'Action Type', required=True, size=32, help="Type of the Action that is to be execute"),
'code':fields.text('Python Code', help="python code to be execute"),
'sequence': fields.integer('Sequence', help="Important when you deal with the multi action, the execution order will be decided based on this, low number higher priority"),
'model_id': fields.many2one('ir.model', 'Object', required=True, help="select the obect on which the action will work (read, write, create)"),
'action_id': fields.many2one('ir.actions.actions', 'Client Action', help="Select the Ation Window, Report, Wizard to be execute"),
'trigger_name': fields.selection(_select_signals, string='Trigger Name', size=128, help="Select the Signal name that is to be "),
'wkf_model_id': fields.many2one('ir.model', 'Workflow on', help="Workflow to be execute on which model"),
'trigger_obj_id': fields.many2one('ir.model.fields','Trigger On', help="select the object from the model on which the workflow will execute"),
'email': fields.char('Email Address', size=512, help="provides the fiels that will refer to the tiny to fetch the email address, i.e. you select the invoice, then `object.invoice_address_id.email` is the field which give the correct address"),
'subject': fields.char('Subject', size=1024, translate=True, help="Specify the subject, you can use the fields from the object. like `Hello [[ object.partner_id.name ]]`"),
'message': fields.text('Message', translate=True, help="Specify the Message, you can use the fields from the object. like `Dear [[ object.partner_id.name ]]`"),
'mobile': fields.char('Mobile No', size=512, help="provides the fiels that will refer to the tiny to fetch the mobile number, i.e. you select the invoice, then `object.invoice_address_id.mobile` is the field which give the correct mobile number"),
'sms': fields.char('SMS', size=160, translate=True),
'child_ids': fields.many2many('ir.actions.server', 'rel_server_actions', 'server_id', 'action_id', 'Others Actions'),
'usage': fields.char('Action Usage', size=32),
@ -417,13 +416,12 @@ class actions_server(osv.osv):
'fields_lines': fields.one2many('ir.server.object.lines', 'server_id', 'Fields Mapping'),
'record_id':fields.many2one('ir.model.fields', 'Create Id', help="Provide the field name from where the record id stores after the create operations, if its empty, you can not track the new record"),
'write_id':fields.char('Write Id', size=256, help="Provide the field name from where the record id refer for the write operation, if its empty it will refer to the active id of the object"),
'loop_action':fields.many2one('ir.actions.server', 'Loop Action'),
'expression':fields.char('Loop Expression', size=512),
'loop_action':fields.many2one('ir.actions.server', 'Loop Action', help="select the action, which will be executes. Loop action will not be avaliable inside loop"),
'expression':fields.char('Loop Expression', size=512, help="enter the field/expression that will return the list, i.e. select the sale order in Object, and we can have loop on sales order line. Expression = `object.order_line`"),
}
_defaults = {
'state': lambda *a: 'dummy',
'condition': lambda *a: 'True',
'sub_condition': lambda *a: 'True',
'type': lambda *a: 'ir.actions.server',
'sequence': lambda *a: 5,
'code': lambda *a: """# You can use the following variables

View File

@ -79,6 +79,7 @@ class ir_translation(osv.osv):
cr.execute('CREATE INDEX ir_translation_lts ON ir_translation (lang, type, src)')
cr.commit()
@tools.cache(skiparg=3)
def _get_ids(self, cr, uid, name, tt, lang, ids):
translations = {}
if ids:

View File

@ -49,19 +49,45 @@ class ir_values(osv.osv):
value = pickle.dumps(eval(value))
self.write(cursor, user, id, {name[:-9]: value}, context=ctx)
def onchange_object_id(self, cr, uid, ids, object_id, context={}):
if not object_id: return {}
act = self.pool.get('ir.model').browse(cr, uid, object_id, context=context)
return {
'value': {'model': act.model}
}
def onchange_action_id(self, cr, uid, ids, action_id, context={}):
if not action_id: return {}
act = self.pool.get('ir.actions.actions').browse(cr, uid, action_id, context=context)
return {
'value': {'value_unpickle': act.type+','+str(act.id)}
}
_columns = {
'name': fields.char('Name', size=128),
'model': fields.char('Object', size=128),
'model_id': fields.many2one('ir.model', 'Object', size=128,
help="This field is not used, it only helps you to select a good model."),
'model': fields.char('Object Name', size=128),
'action_id': fields.many2one('ir.actions.actions', 'Action',
help="This field is not used, it only helps you to select the right action."),
'value': fields.text('Value'),
'value_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle,
method=True, type='text', string='Value'),
'object': fields.boolean('Is Object'),
'key': fields.char('Type', size=128),
'key2': fields.char('Value', size=256),
'key': fields.selection([('action','Action'),('default','Default')], 'Type', size=128),
'key2': fields.selection([
('client_action_multi', 'Wizard in Forms'),
('client_action_relate', 'Relate on Object'),
('client_print_multi', 'Print'),
('tree_but_action', 'Wizard in Tree'),
('tree_but_open', 'Open on Tree'),
('','/')
], string='Event Type', size=256,
help="The kind of action or button in the client side that will trigger the action."),
'meta': fields.text('Meta Datas'),
'meta_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle,
method=True, type='text', string='Meta Datas'),
'res_id': fields.integer('Resource ID'),
'res_id': fields.integer('Object ID', help="Keep 0 if the action must appear on all resources."),
'user_id': fields.many2one('res.users', 'User', ondelete='cascade'),
'company_id': fields.many2one('res.company', 'Company')
}

View File

@ -459,11 +459,34 @@ class module(osv.osv):
continue
for lang in filter_lang:
f = os.path.join(tools.config['addons_path'], mod.name, 'i18n', lang + '.po')
f = os.path.join(addons.get_module_path(mod.name), 'i18n', lang + '.po')
if os.path.exists(f):
logger.notifyChannel("init", netsvc.LOG_INFO, 'module %s: loading translation file for language %s' % (mod.name, lang))
tools.trans_load(cr.dbname, f, lang, verbose=False)
def write(self, cr, uid, ids, vals, context=None):
# Override the write method because we want to show a warning when the description field is empty !
if isinstance( ids, (long, int) ):
ids = [ids]
if 'description' in vals and not vals['description']:
logger = netsvc.Logger()
for mod in self.browse(cr, uid, ids):
logger.notifyChannel("init", netsvc.LOG_WARNING, 'module %s: description is empty !' % (mod.name))
return super(module, self).write(cr, uid, ids, vals, context=context)
def create(self, cr, uid, vals, context=None):
# Override the create method because we want to show a warning when the description field is empty !
module_id = super(module, self).create(cr, uid, vals, context=context)
if 'description' in vals and not vals['description']:
logger = netsvc.Logger()
for mod in self.browse(cr, uid, [module_id]):
logger.notifyChannel("init", netsvc.LOG_WARNING, 'module %s: description is empty !' % (mod.name))
return module_id
module()
class module_dependency(osv.osv):

View File

@ -65,8 +65,7 @@ class wizard_info_get(wizard.interface):
'module_download': '\n'.join(url)}
def _check_upgrade_module(self,cr,uid,data,context):
db, pool = pooler.get_db_and_pool(cr.dbname)
cr = db.cursor()
pool = pooler.get_pool(cr.dbname)
mod_obj = pool.get('ir.module.module')
ids = mod_obj.search(cr, uid, [
('state', 'in', ['to upgrade', 'to remove', 'to install'])])
@ -76,17 +75,16 @@ class wizard_info_get(wizard.interface):
return 'end'
def _upgrade_module(self, cr, uid, data, context):
db, pool = pooler.get_db_and_pool(cr.dbname)
cr = db.cursor()
pool = pooler.get_pool(cr.dbname)
mod_obj = pool.get('ir.module.module')
ids = mod_obj.search(cr, uid, [('state', 'in', ['to upgrade', 'to remove', 'to install'])])
unmet_packages = []
mod_dep_obj = pool.get('ir.module.module.dependency')
for mod in mod_obj.browse(cr, uid, ids):
depends_mod_ids = mod_dep_obj.search(cr, uid, [('module_id', '=', mod.id)])
for dep_mod in mod_dep_obj.browse(cr, uid, depends_mod_ids):
depends_mod_ids = mod_dep_obj.search(cr, uid, [('module_id', '=', mod.id)])
for dep_mod in mod_dep_obj.browse(cr, uid, depends_mod_ids):
if dep_mod.state in ('unknown','uninstalled'):
unmet_packages.append(dep_mod.name)
unmet_packages.append(dep_mod.name)
if len(unmet_packages):
raise wizard.except_wizard('Unmet dependency !', 'Following modules are uninstalled or unknown. \n\n'+'\n'.join(unmet_packages))
mod_obj.download(cr, uid, ids, context=context)
@ -158,8 +156,7 @@ class wizard_info_get_simple(wizard.interface):
'module_download': '\n'.join(url)}
def _check_upgrade_module(self,cr,uid,data,context):
db, pool = pooler.get_db_and_pool(cr.dbname)
cr = db.cursor()
pool = pooler.get_pool(cr.dbname)
mod_obj = pool.get('ir.module.module')
ids = mod_obj.search(cr, uid, [
('state', 'in', ['to upgrade', 'to remove', 'to install'])])
@ -169,8 +166,7 @@ class wizard_info_get_simple(wizard.interface):
return 'end'
def _upgrade_module(self, cr, uid, data, context):
db, pool = pooler.get_db_and_pool(cr.dbname)
cr = db.cursor()
pool = pooler.get_pool(cr.dbname)
mod_obj = pool.get('ir.module.module')
ids = mod_obj.search(cr, uid, [('state', 'in', ['to upgrade', 'to remove', 'to install'])])
unmet_packages = []

View File

@ -1,21 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<rng:grammar xmlns:rng="http://relaxng.org/ns/structure/1.0">
<rng:define name="any">
<rng:element>
<rng:anyName/>
<rng:zeroOrMore>
<rng:choice>
<rng:attribute>
<rng:element>
<rng:anyName/>
</rng:attribute>
<rng:text/>
<rng:ref name="any"/>
</rng:choice>
</rng:zeroOrMore>
<rng:zeroOrMore>
<rng:choice>
<rng:attribute>
<rng:anyName/>
</rng:attribute>
<rng:text/>
<rng:ref name="any"/>
</rng:choice>
</rng:zeroOrMore>
</rng:element>
</rng:define>
<rng:start>
<rng:ref name="any" />
<rng:ref name="any" />
</rng:start>
</rng:grammar>

View File

@ -156,6 +156,7 @@
<rng:element name="notebook">
<rng:optional><rng:attribute name="position"/></rng:optional>
<rng:optional><rng:attribute name="colspan"/></rng:optional>
<rng:optional><rng:attribute name="tabpos"/></rng:optional>
<rng:oneOrMore>
<rng:ref name="page"/>
</rng:oneOrMore>
@ -222,6 +223,7 @@
<rng:optional><rng:attribute name="domain"/></rng:optional>
<rng:optional><rng:attribute name="invisible"/></rng:optional>
<rng:optional><rng:attribute name="password"/></rng:optional>
<rng:optional><rng:attribute name="comparator"/></rng:optional>
<rng:optional><rng:attribute name="sum"/></rng:optional>
<rng:optional><rng:attribute name="select"/></rng:optional>
<rng:optional><rng:attribute name="group"/></rng:optional>
@ -302,6 +304,7 @@
<rng:optional><rng:attribute name="day_length" /></rng:optional>
<rng:optional><rng:attribute name="date_delay" /></rng:optional>
<rng:optional><rng:attribute name="type" /></rng:optional>
<rng:optional><rng:attribute name="mode" /></rng:optional>
<rng:oneOrMore>
<rng:ref name="field"/>
</rng:oneOrMore>
@ -336,6 +339,7 @@
<rng:optional><rng:attribute name="readonly"/></rng:optional>
<rng:optional><rng:attribute name="position"/></rng:optional>
<rng:optional><rng:attribute name="context"/></rng:optional>
<rng:optional><rng:attribute name="confirm"/></rng:optional>
<rng:zeroOrMore>
<rng:choice>
<rng:ref name="form" />

View File

@ -130,3 +130,5 @@
"access_res_bank_group_partner_manager","res_bank_group_partner_manager","model_res_bank","group_partner_manager",1,1,1,1
"access_res_bank_user","res_bank user","model_res_bank","group_user",1,0,0,0
"access_maintenance_group_user","maintenance_contract group_user","model_maintenance_contract","group_maintenance_manager",1,1,1,1
"access_maintenance_contract_module","maintenance.contract.module","model_maintenance_contract_module","group_maintenance_manager",1,1,1,1
"access_maintenance_contract_wizard","maintenance.contract.wizard","model_maintenance_contract_wizard","group_maintenance_manager",1,1,1,1

1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
130 access_res_bank_group_partner_manager res_bank_group_partner_manager model_res_bank group_partner_manager 1 1 1 1
131 access_res_bank_user res_bank user model_res_bank group_user 1 0 0 0
132 access_maintenance_group_user maintenance_contract group_user model_maintenance_contract group_maintenance_manager 1 1 1 1
133 access_maintenance_contract_module maintenance.contract.module model_maintenance_contract_module group_maintenance_manager 1 1 1 1
134 access_maintenance_contract_wizard maintenance.contract.wizard model_maintenance_contract_wizard group_maintenance_manager 1 1 1 1

View File

@ -4,7 +4,10 @@
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
# The refactoring about the OpenSSL support come from Tryton
# Copyright (C) 2007-2008 Cédric Krier.
# Copyright (C) 2007-2008 Bertrand Chenal.
# Copyright (C) 2008 B2CK SPRL.
#
# 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
@ -21,22 +24,25 @@
#
##############################################################################
import time
import threading
import SimpleXMLRPCServer, signal, sys, xmlrpclib
import SimpleXMLRPCServer
import SocketServer
import socket
import logging
import logging.handlers
import os
import signal
import socket
import sys
import threading
import time
import xmlrpclib
import release
_service = {}
_group = {}
_res_id = 1
_res = {}
class ServiceEndPointCall(object):
def __init__(self, id, method):
self._id = id
@ -131,20 +137,10 @@ class LocalService(Service):
Logger().notifyChannel('module', LOG_ERROR, 'This service does not exists: %s' % (str(keyError),) )
raise
class ServiceUnavailable(Exception):
pass
def service_exist(name):
return (name in _service) and bool(_service[name])
def get_rpc_paths():
return map(lambda s: '/xmlrpc/%s' % s, _service)
LOG_NOTSET = 'notset'
LOG_DEBUG_RPC = 'debug_rpc'
LOG_DEBUG = 'debug'
LOG_INFO = 'info'
@ -159,7 +155,24 @@ def init_logger():
from tools import config
import os
logger = logging.getLogger()
if config['syslog']:
# SysLog Handler
if os.name == 'nt':
sysloghandler = logging.handlers.NTEventLogHandler("%s %s" %
(release.description,
release.version))
else:
sysloghandler = logging.handlers.SysLogHandler('/dev/log')
formatter = logging.Formatter('%(application)s:%(uncoloredlevelname)s:%(name)s:%(message)s')
sysloghandler.setFormatter(formatter)
logger.addHandler(sysloghandler)
# create a format for log messages and dates
formatter = logging.Formatter('[%(asctime)s] %(levelname)s:%(name)s:%(message)s', '%a %b %d %Y %H:%M:%S')
if config['logfile']:
# LogFile Handler
logf = config['logfile']
try:
dirname = os.path.dirname(logf)
@ -170,17 +183,16 @@ def init_logger():
sys.stderr.write("ERROR: couldn't create the logfile directory\n")
handler = logging.StreamHandler(sys.stdout)
else:
# Normal Handler on standard output
handler = logging.StreamHandler(sys.stdout)
# create a format for log messages and dates
formatter = logging.Formatter('[%(asctime)s] %(levelname)s:%(name)s:%(message)s', '%a %b %d %H:%M:%S %Y')
# tell the handler to use this format
handler.setFormatter(formatter)
# add the handler to the root logger
logging.getLogger().addHandler(handler)
logging.getLogger().setLevel(config['log_level'])
logger.addHandler(handler)
logger.setLevel(config['log_level'] or '0')
if (not isinstance(handler, logging.FileHandler)) and os.name != 'nt':
# change color of level names
@ -206,6 +218,14 @@ def init_logger():
class Logger(object):
def uncoloredlevelname(self, level):
# The level'names are globals to all loggers, so we must strip-off the
# color formatting for some specific logger (i.e: syslog)
levelname = logging.getLevelName(getattr(logging, level.upper(), 0))
if levelname.startswith("\x1b["):
return levelname[10:-4]
return levelname
def notifyChannel(self, name, level, msg):
log = logging.getLogger(name)
@ -213,14 +233,19 @@ class Logger(object):
fct = lambda msg, *args, **kwargs: log.log(logging.DEBUG_RPC, msg, *args, **kwargs)
setattr(log, LOG_DEBUG_RPC, fct)
extra = {
'uncoloredlevelname': self.uncoloredlevelname(level),
'application' : "%s %s" % (release.description, release.version),
}
level_method = getattr(log, level)
result = str(msg).strip().split('\n')
if len(result)>1:
for idx, s in enumerate(result):
level_method('[%02d]: %s' % (idx+1, s,))
level_method('[%02d]: %s' % (idx+1, s,), extra=extra)
elif result:
level_method(result[0])
level_method(result[0], extra=extra)
init_logger()
@ -248,46 +273,35 @@ class Agent(object):
timer.cancel()
quit = classmethod(quit)
class RpcGateway(object):
def __init__(self, name):
self.name = name
class Dispatcher(object):
def __init__(self):
pass
def monitor(self, signal):
pass
def run(self):
pass
class xmlrpc(object):
class RpcGateway(object):
def __init__(self, name):
self.name = name
class GenericXMLRPCRequestHandler:
def log(self, title, msg):
from pprint import pformat
Logger().notifyChannel('XMLRPC-%s' % title, LOG_DEBUG_RPC, pformat(msg))
def _dispatch(self, method, params):
# print 'TERP-CALL : ',method, params
import traceback
try:
self.log('method', method)
self.log('params', params)
n = self.path.split("/")[-1]
s = LocalService(n)
m = getattr(s, method)
s._service._response = None
r = m(*params)
self.log('result', r)
res = s._service._response
if res != None:
if res is not None:
r = res
self.log('res',r)
return r
except Exception, e:
tb_s = reduce(lambda x, y: x+y, traceback.format_exception(
sys.exc_type, sys.exc_value, sys.exc_traceback))
self.log('exception', e)
tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
s = str(e)
import tools
if tools.config['debug_mode']:
@ -296,47 +310,68 @@ class GenericXMLRPCRequestHandler:
pdb.post_mortem(tb)
raise xmlrpclib.Fault(s, tb_s)
class SSLSocket(object):
def __init__(self, socket):
if not hasattr(socket, 'sock_shutdown'):
from OpenSSL import SSL
import tools
ctx = SSL.Context(SSL.SSLv23_METHOD)
ctx.use_privatekey_file(tools.config['secure_pkey_file'])
ctx.use_certificate_file(tools.config['secure_cert_file'])
self.socket = SSL.Connection(ctx, socket)
else:
self.socket = socket
def shutdown(self, how):
return self.socket.sock_shutdown(how)
def __getattr__(self, name):
return getattr(self.socket, name)
class SimpleXMLRPCRequestHandler(GenericXMLRPCRequestHandler, SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.rpc_paths = get_rpc_paths()
rpc_paths = map(lambda s: '/xmlrpc/%s' % s, _service)
class SecureXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
def setup(self):
self.connection = SSLSocket(self.request)
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
class SimpleThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer):
def server_bind(self):
try:
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
SimpleXMLRPCServer.SimpleXMLRPCServer.server_bind(self)
except:
Logger().notifyChannel('init', LOG_CRITICAL, 'Address already in use')
sys.exit(1)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
SimpleXMLRPCServer.SimpleXMLRPCServer.server_bind(self)
class SecureThreadedXMLRPCServer(SimpleThreadedXMLRPCServer):
def __init__(self, server_address, HandlerClass, logRequests=1):
SimpleThreadedXMLRPCServer.__init__(self, server_address, HandlerClass, logRequests)
self.socket = SSLSocket(socket.socket(self.address_family, self.socket_type))
self.server_bind()
self.server_activate()
class HttpDaemon(threading.Thread):
def __init__(self, interface, port, secure=False):
threading.Thread.__init__(self)
self.__port = port
self.__interface = interface
self.secure = secure
if secure:
from ssl import SecureXMLRPCServer
self.secure = bool(secure)
handler_class = (SimpleXMLRPCRequestHandler, SecureXMLRPCRequestHandler)[self.secure]
server_class = (SimpleThreadedXMLRPCServer, SecureThreadedXMLRPCServer)[self.secure]
class SecureXMLRPCRequestHandler(GenericXMLRPCRequestHandler, SecureXMLRPCServer.SecureXMLRPCRequestHandler):
SecureXMLRPCServer.SecureXMLRPCRequestHandler.rpc_paths = get_rpc_paths()
class SecureThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SecureXMLRPCServer.SecureXMLRPCServer):
def server_bind(self):
try:
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
SecureXMLRPCServer.SecureXMLRPCServer.server_bind(self)
except:
sys.stderr.write("ERROR: address already in use\n")
sys.exit(1)
self.server = SecureThreadedXMLRPCServer((interface, port),
SecureXMLRPCRequestHandler, 0)
if self.secure:
from OpenSSL.SSL import Error as SSLError
else:
self.server = SimpleThreadedXMLRPCServer((interface, port),
SimpleXMLRPCRequestHandler, 0)
class SSLError(Exception): pass
try:
self.server = server_class((interface, port), handler_class, 0)
except SSLError, e:
Logger().notifyChannel('xml-rpc-ssl', LOG_CRITICAL, "Can't load the certificate and/or the private key files")
sys.exit(1)
except Exception, e:
Logger().notifyChannel('xml-rpc', LOG_CRITICAL, "Error occur when strarting the server daemon: %s" % (e,))
sys.exit(1)
def attach(self, path, gw):
pass
@ -344,16 +379,7 @@ class HttpDaemon(threading.Thread):
def stop(self):
self.running = False
if os.name != 'nt':
if hasattr(socket, 'SHUT_RDWR'):
if self.secure:
self.server.socket.sock_shutdown(socket.SHUT_RDWR)
else:
self.server.socket.shutdown(socket.SHUT_RDWR)
else:
if self.secure:
self.server.socket.sock_shutdown(2)
else:
self.server.socket.shutdown(2)
self.server.socket.shutdown( hasattr(socket, 'SHUT_RDWR') and socket.SHUT_RDWR or 2 )
self.server.socket.close()
def run(self):
@ -403,16 +429,17 @@ class TinySocketClientThread(threading.Thread):
return False
try:
self.log(msg)
s = LocalService(msg[0])
m = getattr(s, msg[1])
s._service._response = None
r = m(*msg[2:])
res = s._service._response
service = LocalService(msg[0])
method = getattr(service, msg[1])
service._service._response = None
result_from_method = method(*msg[2:])
res = service._service._response
if res != None:
r = res
self.log(r)
ts.mysend(r)
result_from_method = res
self.log(result_from_method)
ts.mysend(result_from_method)
except Exception, e:
print repr(e)
tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
import tools
if tools.config['debug_mode']:

View File

@ -61,6 +61,14 @@ if pwd.getpwuid(os.getuid())[0] == 'root' :
import netsvc
logger = netsvc.Logger()
def atexit_callback():
logger.notifyChannel('shutdown', netsvc.LOG_INFO, "Shutdown Server!")
#logger.notifyChannel('pan! pan!', netsvc.LOG_INFO, "Killed Server ;-)")
import atexit
atexit.register(atexit_callback)
#-----------------------------------------------------------------------
# import the tools module so that the commandline parameters are parsed
#-----------------------------------------------------------------------
@ -82,9 +90,6 @@ if sys.platform == 'win32':
#----------------------------------------------------------
logger.notifyChannel("objects", netsvc.LOG_INFO, 'initialising distributed objects services')
dispatcher = netsvc.Dispatcher()
dispatcher.monitor(signal.SIGINT)
#---------------------------------------------------------------
# connect to the database and initialize it with base if needed
#---------------------------------------------------------------
@ -163,17 +168,16 @@ if tools.config['xmlrpc']:
try:
port = int(tools.config["port"])
except Exception:
logger.notifyChannel("init", netsvc.LOG_ERROR, "invalid port '%s'!" % (tools.config["port"],))
logger.notifyChannel("init", netsvc.LOG_CRITICAL, "invalid port: %r" % (tools.config["port"],))
sys.exit(1)
interface = tools.config["interface"]
secure = tools.config["secure"]
httpd = netsvc.HttpDaemon(interface, port, secure)
if tools.config["xmlrpc"]:
xml_gw = netsvc.xmlrpc.RpcGateway('web-services')
httpd.attach("/xmlrpc", xml_gw)
logger.notifyChannel("web-services", netsvc.LOG_INFO, "starting XML-RPC%s services, port %s" % ((tools.config['secure'] and ' Secure' or ''), port))
xml_gw = netsvc.xmlrpc.RpcGateway('web-services')
httpd.attach("/xmlrpc", xml_gw)
logger.notifyChannel("web-services", netsvc.LOG_INFO, "starting XML-RPC%s services, port %s" % ((tools.config['secure'] and ' Secure' or ''), port))
#
#if tools.config["soap"]:
@ -220,7 +224,6 @@ if tools.config['netrpc']:
tinySocket.start()
if tools.config['xmlrpc']:
httpd.start()
#dispatcher.run()
while True:
time.sleep(1)

View File

@ -426,7 +426,6 @@ class one2many(_column):
context = {}
if not values:
return
_table = obj.pool.get(self._obj)._table
obj = obj.pool.get(self._obj)
for act in values:

View File

@ -129,7 +129,7 @@ class browse_record(object):
cache.setdefault(table._name, {})
self._data = cache[table._name]
if not id in self._data:
if id not in self._data:
self._data[id] = {'id': id}
self._cache = cache
@ -137,7 +137,7 @@ class browse_record(object):
def __getitem__(self, name):
if name == 'id':
return self._id
if not name in self._data[self._id]:
if name not in self._data[self._id]:
# build the list of fields we will fetch
# fetch the definition of the field which was asked for
@ -166,7 +166,7 @@ class browse_record(object):
# otherwise we fetch only that field
else:
ffields = [(name, col)]
ids = filter(lambda id: not name in self._data[id], self._data.keys())
ids = filter(lambda id: name not in self._data[id], self._data.keys())
# read the data
fffields = map(lambda x: x[0], ffields)
datas = self._table.read(self._cr, self._uid, ids, fffields, context=self._context, load="_classic_write")
@ -311,11 +311,11 @@ class orm_template(object):
_invalids = set()
def _field_create(self, cr, context={}):
cr.execute("SELECT id FROM ir_model WHERE model='%s'" % self._name)
cr.execute("SELECT id FROM ir_model WHERE model=%s", (self._name,))
if not cr.rowcount:
cr.execute('SELECT nextval(%s)', ('ir_model_id_seq',))
model_id = cr.fetchone()[0]
cr.execute("INSERT INTO ir_model (id,model, name, info,state) VALUES (%s, %s, %s, %s,%s)", (model_id, self._name, self._description, self.__doc__, 'base'))
cr.execute("INSERT INTO ir_model (id,model, name, info,state) VALUES (%s, %s, %s, %s, %s)", (model_id, self._name, self._description, self.__doc__, 'base'))
else:
model_id = cr.fetchone()[0]
if 'module' in context:
@ -959,7 +959,6 @@ class orm_template(object):
return None
netsvc.Logger().notifyChannel('orm', netsvc.LOG_DEBUG, type(src))
doc_src = dom.minidom.parseString(encode(src))
doc_dest = dom.minidom.parseString(encode(inherit))
toparse = doc_dest.childNodes
@ -1726,8 +1725,11 @@ class orm(orm_template):
'translate': (field['translate']),
#'select': int(field['select_level'])
}
if field['ttype'] == 'selection':
self._columns[field['name']] = getattr(fields, field['ttype'])(eval(field['selection']), **attrs)
elif field['ttype'] == 'reference':
self._columns[field['name']] = getattr(fields, field['ttype'])(selection=eval(field['selection']), **attrs)
elif field['ttype'] == 'many2one':
self._columns[field['name']] = getattr(fields, field['ttype'])(field['relation'], **attrs)
elif field['ttype'] == 'one2many':

View File

@ -22,7 +22,7 @@
##############################################################################
name = 'openerp-server'
version = '5.0.0_rc1'
version = '5.0.0_rc2'
major_version = '5.0'
description = 'OpenERP Server'
long_desc = '''\

View File

@ -166,7 +166,7 @@ class report_rml(report_int):
res = service.execute(cr.dbname, uid, 'ir.translation',
'_get_source', self.name2, 'xsl', lang, child.content)
if res:
child.setContent(res)
child.setContent(res.encode('utf-8'))
look_down(child.children, lang)
child = child.next
@ -218,7 +218,7 @@ from report_sxw import report_sxw
def register_all(db):
opj = os.path.join
cr = db.cursor()
cr.execute("SELECT * FROM ir_act_report_xml WHERE auto ORDER BY id")
cr.execute("SELECT * FROM ir_act_report_xml WHERE auto=%s ORDER BY id", (True,))
result = cr.dictfetchall()
cr.close()
for r in result:

View File

@ -166,7 +166,7 @@ class report_printscreen_list(report_int):
col.setAttribute('para','yes')
col.setAttribute('tree','no')
if line[f] != None:
txt = new_doc.createTextNode(line[f] or '')
txt = new_doc.createTextNode(str(line[f] or ''))
if temp[count] == 1:
tsum[count] = float(tsum[count]) + float(line[f]);

View File

@ -20,20 +20,23 @@
#
##############################################################################
import base64, os, string
import netsvc
import pooler, security, ir, tools
import base64
import logging
import threading, thread
import os
import security
import string
import thread
import threading
import time
import addons
import sql_db
from tools.translate import _
import addons
import ir
import netsvc
import pooler
import release
import sql_db
import tools
logging.basicConfig()
@ -89,8 +92,8 @@ class db(netsvc.Service):
mids = modobj.search(cr, 1, [('state', '=', 'installed')])
modobj.update_translations(cr, 1, mids, lang)
cr.execute('UPDATE res_users SET password=%s, active=True WHERE login=%s', (
user_password, 'admin'))
cr.execute('UPDATE res_users SET password=%s, context_lang=%s, active=True WHERE login=%s', (
user_password, lang, 'admin'))
cr.execute('SELECT login, password, name ' \
' FROM res_users ' \
' ORDER BY login')
@ -459,11 +462,10 @@ class report_spool(netsvc.Service):
self._reports[id] = {'uid': uid, 'result': False, 'state': False, 'exception': None}
def go(id, uid, ids, datas, context):
cr = pooler.get_db(db).cursor()
try:
cr = pooler.get_db(db).cursor()
obj = netsvc.LocalService('report.'+object)
(result, format) = obj.create(cr, uid, ids, datas, context)
cr.close()
self._reports[id]['result'] = result
self._reports[id]['format'] = format
self._reports[id]['state'] = True
@ -477,6 +479,7 @@ class report_spool(netsvc.Service):
'Exception: %s\n%s' % (str(exception), tb_s))
self._reports[id]['exception'] = exception
self._reports[id]['state'] = True
cr.close()
return True
thread.start_new_thread(go, (id, uid, ids, datas, context))

View File

@ -82,7 +82,10 @@ class Cursor(object):
self._obj = self._cnx.cursor(cursor_factory=psycopg1cursor)
self.autocommit(False)
self.dbname = pool.dbname
from inspect import stack
self.__caller = tuple(stack()[2][1:3])
def __del__(self):
if hasattr(self, '_obj'):
# Oops. 'self' has not been closed explicitly.
@ -90,36 +93,26 @@ class Cursor(object):
# but the database connection is not put back into the connection
# pool, preventing some operation on the database like dropping it.
# This can also lead to a server overload.
log('Cursor not closed explicitly', netsvc.LOG_WARNING)
msg = "Cursor not closed explicitly\n" \
"Cursor was created at %s:%s" % self.__caller
log(msg, netsvc.LOG_WARNING)
self.close()
@check
def execute(self, query, params=None):
if params is None:
params=()
if not isinstance(params, (tuple, list)):
params = (params,)
def base_string(s):
if isinstance(s, unicode):
return s.encode('utf-8')
return s
p=map(base_string, params)
query = base_string(query)
self.count+=1
if '%d' in query or '%f' in query:
#import traceback
#traceback.print_stack()
log(query, netsvc.LOG_WARNING)
log("SQL queries mustn't containt %d or %f anymore. Use only %s", netsvc.LOG_WARNING)
if p:
if params:
query = query.replace('%d', '%s').replace('%f', '%s')
if self.sql_log:
now = mdt.now()
try:
res = self._obj.execute(query, p 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))
@ -140,12 +133,6 @@ class Cursor(object):
self.sql_into_log[res_into.group(1)][1] += mdt.now() - now
return res
def drop_view_if_exists(self, viewname):
self._obj.execute("select count(1) from pg_class where relkind=%s and relname=%s", ('v', viewname,))
if self._obj.fetchone()[0]:
self._obj.execute("DROP view %s" % (viewname,))
self._obj.commit()
def print_log(self):
def process(type):
sqllogs = {'from':self.sql_from_log, 'into':self.sql_into_log}
@ -163,6 +150,7 @@ class Cursor(object):
process('from')
process('into')
self.count = 0
self.sql_log = False
@check
def close(self):

View File

@ -1,176 +0,0 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
#
##############################################################################
"""
SecureXMLRPCServer module using pyOpenSSL 0.5
Extremely kludgey code written 0907.2002
by Michal Wallace ( http://www.sabren.net/ )
This acts as a drop-in replacement for
SimpleXMLRPCServer from the standard python
library.
This code is in the public domain and is
provided AS-IS WITH NO WARRANTY WHATSOEVER.
"""
import SocketServer
import os, socket, sys
import SimpleXMLRPCServer
from OpenSSL import SSL
import tools
import netsvc
logger = netsvc.Logger()
class SSLBugFix:
"""
SSL Connection tends to die on sendall,
so I use send() as a workaround. This is
called by socket._fileobject, which is needed
so SocketServer (and kids) can treat the connection
as a regular file.
"""
def __init__(self, conn):
"""
For some reason, I can't subclass Connection,
so I'm making a proxy, instead.
"""
self.__dict__["conn"] = conn
def __getattr__(self,name):
return getattr(self.__dict__["conn"], name)
def __setattr__(self,name, value):
setattr(self.__dict__["conn"], name, value)
# def sendall(self, data):
# """
# This is the bugfix. Connection.sendall() segfaults
# on socket._fileobject.flush(), so just rewire it
# to use send() instead.
# """
# self.__dict__["conn"].send(data)
def recv(self, bufsize):
""" Another bugfix: SSL's recv() may raise
recoverable exceptions, which simply need us to retry
the call
"""
while True:
try:
return self.__dict__["conn"].recv(bufsize)
except SSL.WantReadError:
pass
except SSL.WantWriteError:
pass
def shutdown(self, how=1):
"""
This isn't part of the bugfix. SimpleXMLRpcServer.doPOST
calls shutdown(1), and Connection.shutdown() doesn't take
an argument. So we just discard it:
"""
self.__dict__["conn"].shutdown()
def accept(self):
"""
This is the other part of the shutdown() workaround.
Since servers create new sockets, we have to infect
them with our magic. :)
"""
c, a = self.__dict__["conn"].accept()
return (SSLBugFix(c), a)
class SecureTCPServer(SocketServer.TCPServer):
"""
Just like TCPServer, but use a socket.
This really ought to let you specify the key and certificate files.
"""
def __init__(self, server_address, RequestHandlerClass):
SocketServer.BaseServer.__init__(self, server_address, RequestHandlerClass)
## Same as normal, but make it secure:
ctx = SSL.Context(SSL.SSLv23_METHOD)
ctx.set_options(SSL.OP_NO_SSLv2)
dir = os.path.join(os.getcwd(), os.path.dirname(sys.argv[0]))
sslkeyname = tools.config.get('sslkey',os.path.join(dir, 'server.pkey'))
sslcertname = tools.config.get('sslcert',os.path.join(dir, 'server.cert'))
try:
ctx.use_privatekey_file (sslkeyname)
ctx.use_certificate_file(sslcertname)
except:
logger.notifyChannel("init", netsvc.LOG_ERROR,"SSL key exception: " + str(sys.exc_info()))
raise Exception, "No ssl keys found in %s, %s" % (sslcertname,sslkeyname)
self.socket = SSLBugFix(SSL.Connection(ctx, socket.socket(self.address_family,
self.socket_type)))
self.server_bind()
self.server_activate()
def handle_error(self, request, client_address):
""" Override the error handler
"""
import traceback
logger.notifyChannel("init", netsvc.LOG_ERROR,"SSL Server error in request from %s:\n%s" %
(client_address,traceback.format_exc()))
class SecureXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
def setup(self):
"""
We need to use socket._fileobject Because SSL.Connection
doesn't have a 'dup'. Not exactly sure WHY this is, but
this is backed up by comments in socket.py and SSL/connection.c
"""
self.connection = self.request # for doPOST
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)
class SecureXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer, SecureTCPServer):
encoding = None
allow_none = False
def __init__(self, addr,
requestHandler=SecureXMLRPCRequestHandler,
logRequests=1):
"""
This is the exact same code as SimpleXMLRPCServer.__init__
except it calls SecureTCPServer.__init__ instead of plain
old TCPServer.__init__
"""
self.funcs = {}
self.logRequests = logRequests
self.instance = None
SecureTCPServer.__init__(self, addr, requestHandler)
def handle_error(self, request, client_address):
""" Override the error handler
"""
import traceback
e_type, e_value, e_traceback = sys.exc_info()
logger.notifyChannel("init", netsvc.LOG_ERROR,"SSL Request handler error in request from %s: %s\n%s" %
(client_address,str(e_type),traceback.format_exc()))
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -1,14 +0,0 @@
-----BEGIN CERTIFICATE-----
MIICNDCCAZ0CAQEwDQYJKoZIhvcNAQEEBQAweTEQMA4GA1UEChMHVGlueUVSUDEM
MAoGA1UECxMDRVJQMRkwFwYJKoZIhvcNAQkBFgpmcEB0aW55LmJlMRAwDgYDVQQH
EwdXYWxoYWluMQswCQYDVQQIEwJCVzELMAkGA1UEBhMCQkUxEDAOBgNVBAMTB1Rp
bnlFUlAwHhcNMDYwNTI0MDgzODUxWhcNMDcwNTI0MDgzODUxWjBMMQswCQYDVQQG
EwJCRTELMAkGA1UECBMCQlcxEDAOBgNVBAoTB1RpbnlFUlAxDDAKBgNVBAsTA0VS
UDEQMA4GA1UEAxMHVGlueUVSUDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
xzIDlU2PrczPsgXtxCskYxuwMPgNCNSCBfWsUZ9nJzlZfRAEXEq4LxaTPIgkzkIF
82bmJLgFz6/CyCFid4mkBLQBj30Opp2Vco39WRncNKHKxbk+/wZpZtQ0bSpvf+F4
MBqCLldYIqsoyenombVCb8X62IUu0ENF1wR22owvyKcCAwEAATANBgkqhkiG9w0B
AQQFAAOBgQB2yUqJ3gbQ8I6rcmaVJlcLDHfC5w1Jr1cUzcJevOPh3wygSZYYoUoe
yeYlzEag/DpPSHyRiJJVOKdiwU0yfmZPhfDNtDiBr47bz8qzIsYq5VeMmSeXrq/f
AA3iI4xE8YFzJHWtiBCqqyUok+j9pVad7iV7+UVIePHZLEkGGWIjDA==
-----END CERTIFICATE-----

View File

@ -1,15 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDHMgOVTY+tzM+yBe3EKyRjG7Aw+A0I1IIF9axRn2cnOVl9EARc
SrgvFpM8iCTOQgXzZuYkuAXPr8LIIWJ3iaQEtAGPfQ6mnZVyjf1ZGdw0ocrFuT7/
Bmlm1DRtKm9/4XgwGoIuV1giqyjJ6eiZtUJvxfrYhS7QQ0XXBHbajC/IpwIDAQAB
AoGAVwAxMHS/3FkoHckZICT3r5HYUosEpmaqo4+5w6yrkSYrP8RPI0A/UdG6XSXZ
bXzIvJakzkTRxPQvTtnF+A/V4rF9hxwB8cGXSywv5eDGmZ91qIsxY7Sv99VqSKNH
dNr9aZHloTvI51e/oramIJ/O3A+TbAS5i+u1DJC2IIFJcAECQQD8iRPTlPIqzjYD
Lg7KYGvwW9TE4ONAhC86kJbzV5o3amlV5duJgnkl/mNlfN1ihA7f3Gx9dfCjfRKp
V1rcjtCBAkEAye2aMw2v1m+MEqcPxyTUzVf5Y8BIXWbk15T43czXec9YclZSOBCX
Dgv4a3Fk+yxQUE0cZUH0U4FJq6mTgpuFJwJASFqZ9KATNlJ4xTZ4BGHV6zrUXkg0
tDJrObNdnID37XKulW7TFLXuMgWNwvEgmO5POLJ13whglubp5tzhapn8gQJAJz9Z
U0b7wFAaB54VAP31ppvMy0iaSB0xqX05CdNAplpYtJB2lpMS6RYGiMuXdwJb8d+q
/ztcg8aDTSw+kYoszQJBAPBrt694VkGT1k9Be6e5wyVDrE05bkHhFxPk/HMeWMDX
sZqHPs9vVaLBqu/uU84FdwRMOV71RG90g6eUEl7HWsg=
-----END RSA PRIVATE KEY-----

View File

@ -27,6 +27,7 @@ from graph import graph
from amount_to_text import *
from amount_to_text_en import *
from pdf_utils import *
from sql import *
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -28,11 +28,19 @@ import netsvc
import logging
import release
def check_ssl():
try:
from OpenSSL import SSL
import socket
return hasattr(socket, 'ssl')
except:
return False
class configmanager(object):
def __init__(self, fname=None):
self.options = {
'email_from':False,
'verbose': False,
'interface': '', # this will bind the server to all interfaces
'port': '8069',
'netinterface': '',
@ -58,28 +66,29 @@ class configmanager(object):
'import_partial': "",
'pidfile': None,
'logfile': None,
'secure': False,
'smtp_server': 'localhost',
'smtp_user': False,
'smtp_port':25,
'smtp_password': False,
'stop_after_init': False, # this will stop the server after initialization
'price_accuracy': 2,
'secure' : False,
'syslog' : False,
'log_level': logging.INFO,
'assert_exit_level': logging.WARNING, # level above which a failed assert will be raise
}
loglevels = dict([(getattr(netsvc, 'LOG_%s' % x), getattr(logging, x)) for x in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'DEBUG_RPC')])
hasSSL = check_ssl()
loglevels = dict([(getattr(netsvc, 'LOG_%s' % x), getattr(logging, x))
for x in ('CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG', 'DEBUG_RPC', 'NOTSET')])
version = "%s %s" % (release.description, release.version)
parser = optparse.OptionParser(version=version)
parser.add_option("-c", "--config", dest="config", help="specify alternate config file")
parser.add_option("-s", "--save", action="store_true", dest="save", default=False, help="save configuration to ~/.openerp_serverrc")
parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="enable debugging")
parser.add_option("--pidfile", dest="pidfile", help="file where the server pid will be stored")
parser.add_option("--logfile", dest="logfile", help="file where the server log will be stored")
parser.add_option("-n", "--interface", dest="interface", help="specify the TCP IP address")
parser.add_option("-p", "--port", dest="port", help="specify the TCP port")
@ -94,17 +103,38 @@ class configmanager(object):
# stops the server from launching after initialization
parser.add_option("--stop-after-init", action="store_true", dest="stop_after_init", default=False, help="stop the server after it initializes")
parser.add_option('--debug', dest='debug_mode', action='store_true', default=False, help='enable debug mode')
parser.add_option('--log-level', dest='log_level', type='choice', choices=loglevels.keys(), help='specify the level of the logging. Accepted values: ' + str(loglevels.keys()))
parser.add_option("--assert-exit-level", dest='assert_exit_level', type="choice", choices=loglevels.keys(), help="specify the level at which a failed assertion will stop the server. Accepted values: " + str(loglevels.keys()))
parser.add_option("-S", "--secure", dest="secure", action="store_true", help="launch server over https instead of http", default=False)
if hasSSL:
group = optparse.OptionGroup(parser, "SSL Configuration")
group.add_option("-S", "--secure", dest="secure", action="store_true", help="launch server over https instead of http", default=False)
group.add_option("--cert-file", dest="secure_cert_file",
default="server.cert",
help="specify the certificate file for the SSL connection")
group.add_option("--pkey-file", dest="secure_pkey_file",
default="server.pkey",
help="specify the private key file for the SSL connection")
parser.add_option_group(group)
parser.add_option('--email-from', dest='email_from', default='', help='specify the SMTP email address for sending email')
parser.add_option('--smtp', dest='smtp_server', default='', help='specify the SMTP server for sending email')
parser.add_option('--smtp-port', dest='smtp_port', default='25', help='specify the SMTP port')
parser.add_option('--smtp-ssl', dest='smtp_ssl', default='', help='specify the SMTP server support SSL or not')
parser.add_option('--smtp-user', dest='smtp_user', default='', help='specify the SMTP username for sending email')
parser.add_option('--smtp-password', dest='smtp_password', default='', help='specify the SMTP password for sending email')
parser.add_option('--price_accuracy', dest='price_accuracy', default='2', help='specify the price accuracy')
# Logging Group
group = optparse.OptionGroup(parser, "Logging Configuration")
group.add_option("--logfile", dest="logfile", help="file where the server log will be stored")
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=loglevels.keys(),
help='specify the level of the logging. Accepted values: ' + str(loglevels.keys()))
parser.add_option_group(group)
# SMTP Group
group = optparse.OptionGroup(parser, "SMTP Configuration")
group.add_option('--email-from', dest='email_from', default='', help='specify the SMTP email address for sending email')
group.add_option('--smtp', dest='smtp_server', default='', help='specify the SMTP server for sending email')
group.add_option('--smtp-port', dest='smtp_port', default='25', help='specify the SMTP port')
if hasSSL:
group.add_option('--smtp-ssl', dest='smtp_ssl', default='', help='specify the SMTP server support SSL or not')
group.add_option('--smtp-user', dest='smtp_user', default='', help='specify the SMTP username for sending email')
group.add_option('--smtp-password', dest='smtp_password', default='', help='specify the SMTP password for sending email')
group.add_option('--price_accuracy', dest='price_accuracy', default='2', help='specify the price accuracy')
parser.add_option_group(group)
group = optparse.OptionGroup(parser, "Modules related options")
group.add_option("-g", "--upgrade", action="store_true", dest="upgrade", default=False, help="Upgrade/install/uninstall modules")
@ -157,19 +187,31 @@ class configmanager(object):
# the same for the pidfile
if self.options['pidfile'] in ('None', 'False'):
self.options['pidfile'] = False
for arg in ('interface', 'port', 'db_name', 'db_user', 'db_password', 'db_host',
'db_port', 'logfile', 'pidfile', 'secure', 'smtp_ssl', 'smtp_port', 'email_from', 'smtp_server', 'smtp_user', 'smtp_password', 'price_accuracy', 'netinterface', 'netport', 'db_maxconn', 'import_partial', 'addons_path'):
keys = ['interface', 'port', 'db_name', 'db_user', 'db_password', 'db_host',
'db_port', 'logfile', 'pidfile', 'smtp_port',
'email_from', 'smtp_server', 'smtp_user', 'smtp_password', 'price_accuracy',
'netinterface', 'netport', 'db_maxconn', 'import_partial', 'addons_path']
if hasSSL:
keys.extend(['smtp_ssl', 'secure_cert_file', 'secure_pkey_file'])
for arg in keys:
if getattr(opt, arg):
self.options[arg] = getattr(opt, arg)
for arg in ('language', 'translate_out', 'translate_in',
'upgrade', 'verbose', 'debug_mode',
'stop_after_init', 'without_demo', 'netrpc', 'xmlrpc'):
keys = ['language', 'translate_out', 'translate_in', 'upgrade', 'debug_mode',
'stop_after_init', 'without_demo', 'netrpc', 'xmlrpc', 'syslog']
if hasSSL:
keys.append('secure')
for arg in keys:
self.options[arg] = getattr(opt, arg)
if opt.assert_exit_level:
self.options['assert_exit_level'] = loglevels[opt.assert_exit_level]
if opt.log_level:
self.options['log_level'] = loglevels[opt.log_level]

View File

@ -669,10 +669,7 @@ form: module.record_id""" % (xml_id,)
rec_id = rec.getAttribute("id").encode('ascii')
self._test_xml_id(rec_id)
# if not rec_id and not self.isnoupdate(data_node):
# print "Warning", rec_model
if self.isnoupdate(data_node) and not self.mode in ('init','update'):
if self.isnoupdate(data_node) and self.mode != 'init':
# check if the xml record has an id string
if rec_id:
id = self.pool.get('ir.model.data')._update_dummy(cr, self.uid, rec_model, self.module, rec_id)
@ -737,7 +734,7 @@ form: module.record_id""" % (xml_id,)
id = self.pool.get('ir.model.data')._update(cr, self.uid, rec_model, self.module, res, rec_id or False, not self.isnoupdate(data_node), noupdate=self.isnoupdate(data_node), mode=self.mode )
if rec_id:
self.idref[rec_id] = int(id)
if config.get('i mport_partial', False):
if config.get('import_partial', False):
cr.commit()
return rec_model, id

View File

@ -542,11 +542,20 @@ class cache(object):
self.timeout = timeout
self.skiparg = skiparg
self.multi = multi
self.lasttime = time.time()
self.cache = {}
def __call__(self, fn):
arg_names = inspect.getargspec(fn)[0][self.skiparg:]
def cached_result(self2, cr=None, *args, **kwargs):
if time.time()-self.timeout > self.lasttime:
self.lasttime = time.time()
t = time.time()-self.timeout
for key in self.cache:
if self.cache[key][1]<t:
del self.cache[key]
if cr is None:
self.cache = {}
return True
@ -563,22 +572,44 @@ class cache(object):
kwargs2[k] = tuple(kwargs2[k])
elif not is_hashable(kwargs2[k]):
kwargs2[k] = repr(kwargs2[k])
if self.multi:
kwargs3 = kwargs2.copy()
notincache = []
result = {}
for id in kwargs3[self.multi]:
kwargs2[self.multi] = [id]
kwargs4 = kwargs2.items()
kwargs4.sort()
# Work out key as a tuple of ('argname', value) pairs
key = (('dbname', cr.dbname),) + tuple(kwargs4)
if key in self.cache:
result[id] = self.cache[key][0]
else:
notincache.append(id)
if notincache:
kwargs2[self.multi] = notincache
result2 = fn(self2, cr, *args[2:self.skip], **kwargs3)
for id in result2:
kwargs2[self.multi] = [id]
kwargs4 = kwargs2.items()
kwargs4.sort()
key = (('dbname', cr.dbname),) + tuple(kwargs4)
self.cache[key] = result2[id]
result.updat(result2)
return result
kwargs2 = kwargs2.items()
kwargs2.sort()
# Work out key as a tuple of ('argname', value) pairs
key = (('dbname', cr.dbname),) + tuple(kwargs2)
# Check cache and return cached value if possible
if key in self.cache:
(value, last_time) = self.cache[key]
mintime = time.time() - self.timeout
if self.timeout <= 0 or mintime <= last_time:
return value
return self.cache[key][0]
# Work out new value, cache it and return it
# FIXME Should copy() this value to avoid futur modifications of the cache ?
# FIXME What about exceptions ?
result = fn(self2, cr, *args, **kwargs)
self.cache[key] = (result, time.time())
@ -598,6 +629,10 @@ def ustr(value):
@return: unicode string
"""
if (value is None) or (value is False):
return value
if not value:
return u''
if isinstance(value, unicode):
return value
@ -612,6 +647,7 @@ def ustr(value):
def get_languages():
languages={
'ar_AR': u'Arabic / الْعَرَبيّة',
'bg_BG': u'Bulgarian / български',
'ca_ES': u'Catalan / Català',
'cs_CZ': u'Czech / Čeština',
@ -631,12 +667,14 @@ def get_languages():
'it_IT': u'Italian / Italiano',
'lt_LT': u'Lithuanian / Lietuvių kalba',
'nl_NL': u'Dutch / Nederlands',
'pl_PL': u'Polish / Język polski',
'pt_BR': u'Portugese (BR) / português (BR)',
'pt_PT': u'Portugese / português',
'ro_RO': u'Romanian / limba română',
'ru_RU': u'Russian / русский язык',
'sl_SL': u'Slovenian / slovenščina',
'sv_SE': u'Swedish / svenska',
'tr_TR': u'Turkish / Türkçe',
'uk_UK': u'Ukrainian / украї́нська мо́ва',
'zh_CN': u'Chinese (CN) / 简体中文' ,
'zh_TW': u'Chinese (TW) / 正體字',
@ -748,7 +786,10 @@ def debug(what):
st = stack()[1]
param = re.split("debug *\((.+)\)", st[4][0].strip())[1].strip()
while param.count(')') > param.count('('): param = param[:param.rfind(')')]
netsvc.Logger().notifyChannel(st[3], netsvc.LOG_DEBUG, "%s = %s" % (param, pformat(what)))
what = pformat(what)
if param != what:
what = "%s = %s" % (param, what)
netsvc.Logger().notifyChannel(st[3], netsvc.LOG_DEBUG, what)
icons = map(lambda x: (x,x), ['STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_BOLD',

View File

@ -1,7 +1,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$
#
@ -26,7 +26,7 @@
import re
component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE)
replace = {'pre':'c', 'preview':'c','-':'final-','rc':'c','dev':'@'}.get
replace = {'pre':'c', 'preview':'c','-':'final-','_':'final-','rc':'c','dev':'@'}.get
def _parse_version_parts(s):
for part in component_re.split(s):
@ -82,15 +82,16 @@ def parse_version(s):
return tuple(parts)
if __name__ == '__main__':
pvs = []
for v in ('0', '4.2', '4.2.3.4', '5.0.0-alpha', '5.0.0-rc1', '5.0.0-rc1.1', '5.0.0'):
pv = parse_version(v)
print v, pv
pvs.append(pv)
pvs = []
for v in ('0', '4.2', '4.2.3.4', '5.0.0-alpha', '5.0.0-rc1', '5.0.0-rc1.1', '5.0.0_rc2', '5.0.0'):
pv = parse_version(v)
print v, pv
pvs.append(pv)
def cmp(a, b):
assert(a < b)
return b
def cmp(a, b):
print a, b
assert(a < b)
return b
reduce(cmp, pvs)
reduce(cmp, pvs)

View File

@ -20,8 +20,10 @@
#
##############################################################################
import SecureXMLRPCServer
def drop_view_if_exists(cr, viewname):
cr.execute("select count(1) from pg_class where relkind=%s and relname=%s", ('v', viewname,))
if cr.fetchone()[0]:
cr.execute("DROP view %s" % (viewname,))
cr.commit()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -386,10 +386,10 @@ def trans_generate(lang, modules, dbname=None):
if result['type'] != 'form':
continue
name = "%s,%s" % (encode(obj.wiz_name), state_name)
def_params = {
'string': ('wizard_field', lambda s: [encode(s)]),
'selection': ('selection', lambda s: [encode(e[1]) for e in s]),
'selection': ('selection', lambda s: [encode(e[1]) for e in (callable(s) and s(None, cr, uid, {}) or s)]),
'help': ('help', lambda s: [encode(s)]),
}
@ -468,9 +468,9 @@ def trans_generate(lang, modules, dbname=None):
d = xml.dom.minidom.parseString(xmlstr)
for t in parse_func(d.documentElement):
push_translation(module, report_type, name, 0, t)
except IOError:
except IOError, xml.dom.expatbuilder.expat.ExpatError:
if fname:
logger.notifyChannel("init", netsvc.LOG_WARNING, "couldn't export translation for report %s %s %s" % (name, report_type, fname))
logger.notifyChannel("init", netsvc.LOG_ERROR, "couldn't export translation for report %s %s %s" % (name, report_type, fname))
for constraint in pool.get(model)._constraints:
msg = constraint[1]

View File

@ -26,14 +26,16 @@
import netsvc
def log(cr,ident,act_id,info=''):
msg = """
res_type: %r
res_id: %d
uid: %d
act_id: %d
info: %s
""" % (ident[1], ident[2], ident[0], act_id, info)
netsvc.Logger().notifyChannel('wkf_log', netsvc.LOG_DEBUG, msg)
return
# msg = """
#res_type: %r
#res_id: %d
#uid: %d
#act_id: %d
#info: %s
#""" % (ident[1], ident[2], ident[0], act_id, info)
#netsvc.Logger().notifyChannel('wkf_log', netsvc.LOG_DEBUG, msg)
#cr.execute('insert into wkf_logs (res_type, res_id, uid, act_id, time, info) values (%s,%s,%s,%s,current_time,%s)', (ident[1],int(ident[2]),int(ident[0]),int(act_id),info))

View File

@ -17,8 +17,8 @@ db_user = tinyerp
db_password = False
; Uncomment these for xml-rpc over SSL
; secure = True
; sslcert = /etc/openerp/server.cert
; sslkey = /etc/openerp/server.key
; secure_cert_file = /etc/openerp/server.cert
; secure_pkey_file = /etc/openerp/server.key
root_path = None
soap = False
translate_modules = ['all']

View File

@ -27,9 +27,6 @@
!error "Do not forget to specify the version of OpenERP - /DVERSION=<VERSION>"
!endif
;--------------------------------
;Include Modern UI
!include "MUI.nsh"
;--------------------------------
@ -45,7 +42,7 @@ SetCompress auto
InstallDir "$PROGRAMFILES\OpenERP Server"
;Get installation folder from registry if available
InstallDirRegKey HKCU "Software\OpenERP Server" ""
InstallDirRegKey HKLM "Software\OpenERP Server" ""
BrandingText "OpenERP Server ${VERSION}"
@ -63,6 +60,12 @@ Var STARTMENU_FOLDER
!define MUI_ABORTWARNING
!define REGKEY "SOFTWARE\$(^Name)"
!define MUI_LANGDLL_REGISTRY_ROOT HKLM
!define MUI_LANGDLL_REGISTRY_KEY ${REGKEY}
!define MUI_LANGDLL_REGISTRY_VALUENAME InstallerLanguage
!insertmacro MUI_RESERVEFILE_LANGDLL
;--------------------------------
;Pages
@ -73,14 +76,15 @@ Var STARTMENU_FOLDER
!define MUI_HEADERIMAGE_BITMAP_NOSTRETCH
!define MUI_HEADER_TRANSPARENT_TEXT ""
!define MUI_HEADERIMAGE_BITMAP ".\pixmaps\openerp-slogan.bmp"
!define MUI_LICENSEPAGE_TEXT_BOTTOM "Usually, a proprietary license provides with the software: limited number of users, limited in time usage, etc. This Open Source license is the opposite: it garantees you the right to use, copy, study, distribute and modify Open ERP for free."
!define MUI_LICENSEPAGE_TEXT_BOTTOM "$(LicenseText)"
!define MUI_LICENSEPAGE_BUTTON "$(LicenseNext)"
!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_LICENSE "doc\License.rtf"
!insertmacro MUI_PAGE_DIRECTORY
;Start Menu Folder Page Configuration
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKCU"
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "HKLM"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "Software\OpenERP Server"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "OpenERP Server"
@ -91,7 +95,7 @@ Var STARTMENU_FOLDER
!define MUI_FINISHPAGE_NOAUTOCLOSE
!define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_CHECKED
!define MUI_FINISHPAGE_RUN_TEXT "Start OpenERP Server"
!define MUI_FINISHPAGE_RUN_TEXT "$(FinishPageText)"
!define MUI_FINISHPAGE_RUN_FUNCTION "LaunchLink"
!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED
!define MUI_FINISHPAGE_SHOWREADME $INSTDIR\README.txt
@ -106,6 +110,7 @@ Var STARTMENU_FOLDER
;Languages
!insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "French"
!macro CreateInternetShortcut FILENAME URL
WriteINIStr "${FILENAME}.url" "InternetShortcut" "URL" "${URL}"
@ -114,10 +119,26 @@ Var STARTMENU_FOLDER
;--------------------------------
;Installer Sections
Function .onInit
!ifndef ALLINONE
;Language selection dialog
Push ""
Push ${LANG_ENGLISH}
Push English
Push ${LANG_FRENCH}
Push French
Push A ; A means auto count languages
; for the auto count to work the first empty push (Push "") must remain
LangDLL::LangDialog "Installer Language" "Please select the language of the installer"
Pop $LANGUAGE
StrCmp $LANGUAGE "cancel" 0 +2
Abort
!endif
ClearErrors
ReadRegStr $0 HKCU "Software\OpenERP Server" ""
ReadRegStr $0 HKLM "Software\OpenERP Server" ""
IfErrors DoInstall 0
MessageBox MB_OK "Can not install the Open ERP Server because a previous installation already exists on this system. Please uninstall your current installation and relaunch this setup wizard."
MessageBox MB_OK "$(CannotInstallServerText)"
Quit
DoInstall:
FunctionEnd
@ -137,11 +158,15 @@ Section "OpenERP Server" SecOpenERPServer
File "win32\stop.bat"
;Store installation folder
WriteRegStr HKCU "Software\OpenERP Server" "" $INSTDIR
WriteRegStr HKLM "Software\OpenERP Server" "" $INSTDIR
!ifndef ALLINONE
;Create uninstaller
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenERP Server" "DisplayName" "OpenERP Server ${VERSION}"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenERP Server" "UninstallString" "$INSTDIR\Uninstall.exe"
!else
WriteRegStr HKLM "Software\OpenERP AllInOne" "UninstallServer" "$INSTDIR\Uninstall.exe"
!endif
WriteUninstaller "$INSTDIR\Uninstall.exe"
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
@ -152,7 +177,9 @@ Section "OpenERP Server" SecOpenERPServer
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Stop service.lnk" "$INSTDIR\service\stop.bat"
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Edit config.lnk" "notepad.exe" "$INSTDIR\openerp-server.conf"
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\View log.lnk" "notepad.exe" "$INSTDIR\openerp-server.log"
!ifndef ALLINONE
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\uninstall.exe"
!endif
!insertmacro CreateInternetShortcut "$SMPROGRAMS\$STARTMENU_FOLDER\Forum" "http://www.openerp.com/forum"
!insertmacro CreateInternetShortcut "$SMPROGRAMS\$STARTMENU_FOLDER\Translation" "https://translations.launchpad.net/openobject"
!insertmacro MUI_STARTMENU_WRITE_END
@ -164,13 +191,6 @@ SectionEnd
;Descriptions
;Language strings
LangString DESC_SecOpenERPServer ${LANG_ENGLISH} "OpenERP Server."
;Assign language strings to sections
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SecOpenERPServer} $(DESC_SecOpenERPServer)
!insertmacro MUI_FUNCTION_DESCRIPTION_END
;--------------------------------
;Uninstaller Section
@ -186,7 +206,9 @@ Section "Uninstall"
Delete "$SMPROGRAMS\$MUI_TEMP\Forum.url"
Delete "$SMPROGRAMS\$MUI_TEMP\Translation.url"
!ifndef ALLINONE
Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
!endif
Delete "$SMPROGRAMS\$MUI_TEMP\OpenERP Server.lnk"
Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
Delete "$SMPROGRAMS\$MUI_TEMP\Start service.lnk"
@ -208,8 +230,12 @@ Section "Uninstall"
startMenuDeleteLoopDone:
!ifndef ALLINONE
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenERP Server"
DeleteRegKey /ifempty HKCU "Software\OpenERP Server"
!else
DeleteRegKey HKLM "Software\OpenERP AllInOne\UninstallServer"
!endif
DeleteRegKey /ifempty HKLM "Software\OpenERP Server"
SectionEnd
@ -217,3 +243,24 @@ Function LaunchLink
nsExec::Exec "net start openerp-service"
FunctionEnd
LangString LicenseText ${LANG_ENGLISH} "Usually, a proprietary license is provided with the software: limited number of users, limited in time usage, etc. This Open Source license is the opposite: it garantees you the right to use, copy, study, distribute and modify Open ERP for free."
LangString LicenseText ${LANG_FRENCH} "Normalement, une licence propriétaire est fournie avec le logiciel: limitation du nombre d'utilisateurs, limitation dans le temps, etc. Cette licence Open Source est l'opposé: Elle vous garantie le droit d'utiliser, de copier, d'étudier, de distribuer et de modifier Open ERP librement."
LangString LicenseNext ${LANG_ENGLISH} "Next >"
LangString LicenseNext ${LANG_FRENCH} "Suivant >"
LangString FinishPageText ${LANG_ENGLISH} "Start OpenERP Server"
LangString FinishPageText ${LANG_FRENCH} "Lancer le serveur OpenERP"
;Language strings
LangString DESC_SecOpenERPServer ${LANG_ENGLISH} "OpenERP Server."
LangString DESC_SecOpenERPServer ${LANG_FRENCH} "Serveur OpenERP."
LangString CannotInstallServerText ${LANG_ENGLISH} "Can not install the Open ERP Server because a previous installation already exists on this system. Please uninstall your current installation and relaunch this setup wizard."
LangString CannotInstallServerText ${LANG_FRENCH} "Ne peut pas installer le serveur Open ERP parce qu'une installation existe déjà  sur ce système. S'il vous plait, désinstallez votre installation actuelle et relancer l'installeur."
;Assign language strings to sections
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SecOpenERPServer} $(DESC_SecOpenERPServer)
!insertmacro MUI_FUNCTION_DESCRIPTION_END

View File

@ -85,6 +85,9 @@ def data_files():
os.chdir('..')
for (dp,dn,names) in os.walk('doc'):
files.append((dp, map(lambda x: opj(dp, x), names)))
files.append(('.', [opj('bin', 'import_xml.rng'),
opj('bin', 'server.pkey'),
opj('bin', 'server.cert')]))
else:
man_directory = opj('share', 'man')
files.append((opj(man_directory, 'man1'), ['man/openerp-server.1']))
@ -97,6 +100,10 @@ def data_files():
openerp_site_packages = opj('lib', 'python%s' % py_short_version, 'site-packages', 'openerp-server')
files.append((openerp_site_packages, [opj('bin', 'import_xml.rng'),
opj('bin', 'server.pkey'),
opj('bin', 'server.cert')]))
for addon in find_addons():
add_path = addon.replace('.', os.path.sep).replace('openerp-server', 'bin', 1)
addon_path = opj('lib', 'python%s' % py_short_version, 'site-packages', add_path.replace('bin', 'openerp-server', 1))
@ -132,7 +139,8 @@ options = {
"packages": ["lxml", "lxml.builder", "lxml._elementpath", "lxml.etree",
"lxml.objectify", "decimal", "xml", "xml.dom", "xml.xpath",
"encodings","mx.DateTime","wizard","pychart","PIL", "pyparsing",
"pydot","asyncore","asynchat", "reportlab", "vobject", "HTMLParser"],
"pydot","asyncore","asynchat", "reportlab", "vobject",
"HTMLParser", "OpenSSL", "select"],
"excludes" : ["Tkconstants","Tkinter","tcl"],
}
}
@ -155,7 +163,6 @@ setup(name = name,
'openerp-server.addons',
'openerp-server.ir',
'openerp-server.osv',
'openerp-server.ssl',
'openerp-server.service',
'openerp-server.tools',
'openerp-server.report',