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 README
include bin/import_xml.rng
include bin/server.cert
include bin/server.pkey
recursive-include doc * recursive-include doc *
recursive-include man * recursive-include man *
recursive-include bin *xml *xsl *sql *rml *sxw *csv *rng recursive-include bin *xml *xsl *sql *rml *sxw *csv *rng

View File

@ -1,6 +1,6 @@
Metadata-Version: 1.1 Metadata-Version: 1.1
Name: OpenERP Name: OpenERP
Version: 5.0.0-rc1 Version: 5.0.0-rc2
Author: Tiny.be Author: Tiny.be
Author-email: fp at tiny be Author-email: fp at tiny be
Maintainer: 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) package_todo.append(package.name)
ver = release.major_version + '.' + package.data.get('version', '1.0') ver = release.major_version + '.' + package.data.get('version', '1.0')
# update the installed version in database... # update the installed version in database...
cr.execute("update ir_module_module set state='installed', latest_version=%s where id=%s", (ver, mid,)) #cr.execute("update ir_module_module set state='installed', latest_version=%s where id=%s", (ver, mid,))
cr.commit()
# Set new modules and dependencies # Set new modules and dependencies
modobj = pool.get('ir.module.module') modobj = pool.get('ir.module.module')
modobj.write(cr, 1, [mid], {'state':'installed', 'latest_version':ver})
cr.commit()
# Update translations for all installed languages # Update translations for all installed languages
if modobj: if modobj:

View File

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

View File

@ -257,13 +257,14 @@
<!-- register on configuratuion --> <!-- register on configuratuion -->
</data>
<data noupdate="1">
<record id="config_wizard_step_user" model="ir.actions.todo"> <record id="config_wizard_step_user" model="ir.actions.todo">
<field name="name">Create User</field> <field name="name">Create User</field>
<field name="note">Create your users. <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. 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>
<field name="action_id" ref="action_config_user_form"/> <field name="action_id" ref="action_config_user_form"/>
<field name="state">open</field>
<field name="sequence">10</field> <field name="sequence">10</field>
</record> </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. understand. You will be able to switch to the extended view later.
</field> </field>
<field name="action_id" ref="action_config_simple_view_form"/> <field name="action_id" ref="action_config_simple_view_form"/>
<field name="state">open</field>
<field name="sequence">5</field> <field name="sequence">5</field>
</record> </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"?> <?xml version="1.0" encoding="utf-8"?>
<openerp> <openerp>
<data> <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 --> <!-- Values -->
@ -705,8 +745,8 @@
'readonly': [('ttype','!=','one2many'), ('ttype','!=','many2one'), ('ttype','!=','many2many')]}"/> 'readonly': [('ttype','!=','one2many'), ('ttype','!=','many2one'), ('ttype','!=','many2many')]}"/>
<field name="relation_field" attrs="{'required': [('ttype','=','one2many')], <field name="relation_field" attrs="{'required': [('ttype','=','one2many')],
'readonly': [('ttype','!=','one2many')]}"/> 'readonly': [('ttype','!=','one2many')]}"/>
<field name="selection" attrs="{'required': [('ttype','=','selection')], 'readonly': [('ttype','!=','selection')]}"/> <field name="selection" attrs="{'required': [('ttype','in',['selection','reference'])], 'readonly': [('ttype','not in',['selection','reference'])]}"/>
<field name="size" attrs="{'required': [('ttype','=','char')], 'readonly': [('ttype','!=','char')]}"/> <field name="size" attrs="{'required': [('ttype','in',['char','reference'])], 'readonly': [('ttype','not in',['char','reference'])]}"/>
<field name="state"/> <field name="state"/>
<field name="domain" attrs="{'readonly': [('relation','=','')]}"/> <field name="domain" attrs="{'readonly': [('relation','=','')]}"/>
</group> </group>
@ -783,8 +823,8 @@
<field name="relation" select="2" attrs="{'required': [('ttype','in', ['many2one','one2many','many2many'])], <field name="relation" select="2" attrs="{'required': [('ttype','in', ['many2one','one2many','many2many'])],
'readonly': [('ttype','not in', ['many2one','one2many','many2many'])]}"/> 'readonly': [('ttype','not in', ['many2one','one2many','many2many'])]}"/>
<field name="relation_field" attrs="{'required': [('ttype','=','one2many')], 'readonly': [('ttype','!=','one2many')]}"/> <field name="relation_field" attrs="{'required': [('ttype','=','one2many')], 'readonly': [('ttype','!=','one2many')]}"/>
<field name="selection" attrs="{'required': [('ttype','=','selection')], 'readonly': [('ttype','!=','selection')]}"/> <field name="selection" attrs="{'required': [('ttype','in',['selection','reference'])], 'readonly': [('ttype','not in',['selection','reference'])]}"/>
<field name="size" attrs="{'required': [('ttype','=','char')], 'readonly': [('ttype','!=','char')]}"/> <field name="size" attrs="{'required': [('ttype','in',['char','reference'])], 'readonly': [('ttype','not in',['char','reference'])]}"/>
<field name="state"/> <field name="state"/>
<field name="domain" attrs="{'readonly': [('relation','=','')]}"/> <field name="domain" attrs="{'readonly': [('relation','=','')]}"/>
</group> </group>
@ -1148,46 +1188,43 @@
<field name="type">form</field> <field name="type">form</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Server Action"> <form string="Server Action">
<field name="name" select="1"/> <group col="6" colspan="4">
<field name="state" select="1"/> <field name="name" select="1"/>
<field name="model_id" select="1"/> <field name="model_id" select="1"/>
<field name="sequence" select="2"/> <field name="state" select="1"/>
<field name="condition" colspan="4"/> <field name="sequence" select="2"/>
<field name="condition"/>
</group>
<notebook colspan="4"> <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"/> <separator colspan="4" string="Python Code"/>
<field name="code" colspan="4" nolabel="1"/> <field name="code" colspan="4" nolabel="1"/>
</page> </page>
<page string="Trigger" attrs="{'invisible':[('state','!=','trigger')]}"> <page string="Trigger" attrs="{'invisible':[('state','!=','trigger')]}">
<separator colspan="4" string="Trigger Configuration"/> <separator colspan="4" string="Trigger Configuration"/>
<field name="wkf_model_id"/> <field name="wkf_model_id" attrs="{'required':[('state','=','trigger')]}"/>
<field name="trigger_obj_id" select="2" domain="[('model_id','=',model_id)]" on_change="on_trigger_obj_id(trigger_obj_id)"/> <field name="trigger_obj_id" select="2" context="{'key':''}" domain="[('model_id','=',model_id)]" attrs="{'required':[('state','=','trigger')]}"/>
<field name="trigger_name" select="2"/> <field name="trigger_name" select="2" attrs="{'required':[('state','=','trigger')]}"/>
</page> </page>
<page string="Action to Launch" attrs="{'invisible':[('state','!=','client_action')]}">
<page string="Action to Launch" attrs="{'invisible':[('state','!=','client_action')]}"> <separator colspan="4" string="Client Action Configuration"/>
<field name="action_id" select="2" colspan="4"/> <field name="action_id" select="2" attrs="{'required':[('state','=','client_action')]}"/>
</page> </page>
<page string="Email Configuration" attrs="{'invisible':[('state','!=','email')]}"> <page string="Email Configuration" attrs="{'invisible':[('state','!=','email')]}">
<separator colspan="4" string="Email Configuration"/> <separator colspan="4" string="Email Configuration"/>
<field name="email" domain="[('model_id','=',model_id)]"/> <field name="email" domain="[('model_id','=',model_id)]" attrs="{'required':[('state','=','email')]}"/>
<field name="subject" colspan="4"/> <field name="subject" colspan="4" attrs="{'required':[('state','=','email')]}"/>
<field name="message" select="2" colspan="4"/> <field name="message" select="2" colspan="4" attrs="{'required':[('state','=','email')]}"/>
<newline/> <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>
<page string="SMS Configuration" attrs="{'invisible':[('state','!=','sms')]}"> <page string="SMS Configuration" attrs="{'invisible':[('state','!=','sms')]}">
<separator colspan="4" string="SMS Configuration"/> <separator colspan="4" string="SMS Configuration"/>
<field name="mobile" domain="[('model_id','=',model_id)]"/> <field name="mobile" domain="[('model_id','=',model_id)]" attrs="{'required':[('state','=','email')]}"/>
<field name="sms" colspan="4"/> <field name="sms" colspan="4" attrs="{'required':[('state','=','email')]}"/>
<newline/> <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>
<page string="Create / Write" attrs="{'invisible':[('state','!=','object_create'),('state','!=','object_write')]}"> <page string="Create / Write" attrs="{'invisible':[('state','!=','object_create'),('state','!=','object_write')]}">
<separator colspan="4" string="Fields Mapping"/> <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')]}"/> <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')]}"/> <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"/> <label colspan="4" string="If you use a formula type, use a python expression using the variable 'object'." align="0.0"/>
</page> </page>
<page string="Iteration Actions" attrs="{'invisible':[('state','!=','loop')]}"> <page string="Iteration Actions" attrs="{'invisible':[('state','!=','loop')]}">
<separator colspan="4" string="Iteration Action Configuration"/> <separator colspan="4" string="Iteration Action Configuration"/>
<field name="loop_action" domain="[('state','!=','loop')]"/>
<field name="expression" attrs="{'required':[('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>
<page string="Multi Actions" attrs="{'invisible':[('state','!=','other')]}"> <page string="Multi Actions" attrs="{'invisible':[('state','!=','other')]}">
<separator colspan="4" string="Other Actions Configuration"/> <separator colspan="4" string="Other Actions Configuration"/>
<field name="child_ids" nolabel="1" colspan="4"/> <field name="child_ids" nolabel="1" colspan="4"/>
<label colspan="4" string="Only one client action will be execute, last <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"/> clinent action will be consider in case of multiples clients actions" align="0.0"/>
</page> </page>
</notebook> </notebook>
<field name="type" readonly="1"/> <field name="type" readonly="1"/>
</form> </form>
@ -1236,6 +1269,7 @@
<tree string="Server Actions"> <tree string="Server Actions">
<field name="name"/> <field name="name"/>
<field name="state"/> <field name="state"/>
<field name="model_id"/>
<field name="sequence"/> <field name="sequence"/>
</tree> </tree>
</field> </field>
@ -1274,28 +1308,28 @@
</record> </record>
<menuitem action="action_model_grid_security" id="menu_ir_access_grid" parent="menu_security_access"/> <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="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="type">tree</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree editable="bottom" string="Config Wizard Steps"> <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="action_id" select="1"/>
<field name="sequence"/> <field name="sequence"/>
<field name="state"/> <field name="state"/>
<field name="active" select="1"/> <field name="active" select="1"/>
</tree> </tree>
</field> </field>
</record> </record>
<record id="config_wizard_step_view_form" model="ir.ui.view"> <record id="config_wizard_step_view_form" model="ir.ui.view">
<field name="model">ir.actions.todo</field> <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="type">form</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form editable="bottom" string="Config Wizard Steps"> <form editable="bottom" string="Config Wizard Steps">
<field name="name" select="1"/> <field name="name" select="1"/>
<field name="active" select="1"/> <field name="active" select="1"/>
<field name="action_id" select="1"/> <field name="action_id" select="1"/>
<field name="sequence"/> <field name="sequence"/>
<field name="state"/> <field name="state"/>
@ -1308,7 +1342,7 @@
<field name="res_model">ir.actions.todo</field> <field name="res_model">ir.actions.todo</field>
<field name="view_id" ref="ir_actions_todo_tree"/> <field name="view_id" ref="ir_actions_todo_tree"/>
<field name="view_type">form</field> <field name="view_type">form</field>
<field name="domain">[('type','=','configure')]</field> <field name="domain">[('type','=','configure')]</field>
</record> </record>
<menuitem id="next_id_11" name="Configuration Wizards" parent="base.menu_config" sequence="1"/> <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"/> <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 # Actions that are run on the server side
# #
class actions_server(osv.osv): class actions_server(osv.osv):
def _select_signals(self, cr, uid, context={}): 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 "\ 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 " \ " 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: if not rs[0] == None and not rs[1] == None:
res.append(rs) res.append(rs)
return res return res
_name = 'ir.actions.server' _name = 'ir.actions.server'
_table = 'ir_act_server' _table = 'ir_act_server'
_sequence = 'ir_actions_id_seq' _sequence = 'ir_actions_id_seq'
_order = 'sequence' _order = 'sequence'
_columns = { _columns = {
'name': fields.char('Action Name', required=True, size=64), '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), '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"),
'sub_condition' : fields.char('Condition', size=256),
'state': fields.selection([ 'state': fields.selection([
('client_action','Client Action'), ('client_action','Client Action'),
('dummy','Dummy'), ('dummy','Dummy'),
@ -397,18 +396,18 @@ class actions_server(osv.osv):
('object_create','Create Object'), ('object_create','Create Object'),
('object_write','Write Object'), ('object_write','Write Object'),
('other','Multi Actions'), ('other','Multi Actions'),
], 'Action Type', required=True, size=32), ], 'Action Type', required=True, size=32, help="Type of the Action that is to be execute"),
'code':fields.text('Python Code'), 'code':fields.text('Python Code', help="python code to be execute"),
'sequence': fields.integer('Sequence'), '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), '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'), '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), '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'), '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'), '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), '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), '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), '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), '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), 'sms': fields.char('SMS', size=160, translate=True),
'child_ids': fields.many2many('ir.actions.server', 'rel_server_actions', 'server_id', 'action_id', 'Others Actions'), 'child_ids': fields.many2many('ir.actions.server', 'rel_server_actions', 'server_id', 'action_id', 'Others Actions'),
'usage': fields.char('Action Usage', size=32), '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'), '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"), '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"), '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'), '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), '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 = { _defaults = {
'state': lambda *a: 'dummy', 'state': lambda *a: 'dummy',
'condition': lambda *a: 'True', 'condition': lambda *a: 'True',
'sub_condition': lambda *a: 'True',
'type': lambda *a: 'ir.actions.server', 'type': lambda *a: 'ir.actions.server',
'sequence': lambda *a: 5, 'sequence': lambda *a: 5,
'code': lambda *a: """# You can use the following variables '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.execute('CREATE INDEX ir_translation_lts ON ir_translation (lang, type, src)')
cr.commit() cr.commit()
@tools.cache(skiparg=3)
def _get_ids(self, cr, uid, name, tt, lang, ids): def _get_ids(self, cr, uid, name, tt, lang, ids):
translations = {} translations = {}
if ids: if ids:

View File

@ -49,19 +49,45 @@ class ir_values(osv.osv):
value = pickle.dumps(eval(value)) value = pickle.dumps(eval(value))
self.write(cursor, user, id, {name[:-9]: value}, context=ctx) 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 = { _columns = {
'name': fields.char('Name', size=128), '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': fields.text('Value'),
'value_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle, 'value_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle,
method=True, type='text', string='Value'), method=True, type='text', string='Value'),
'object': fields.boolean('Is Object'), 'object': fields.boolean('Is Object'),
'key': fields.char('Type', size=128), 'key': fields.selection([('action','Action'),('default','Default')], 'Type', size=128),
'key2': fields.char('Value', size=256), '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': fields.text('Meta Datas'),
'meta_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle, 'meta_unpickle': fields.function(_value_unpickle, fnct_inv=_value_pickle,
method=True, type='text', string='Meta Datas'), 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'), 'user_id': fields.many2one('res.users', 'User', ondelete='cascade'),
'company_id': fields.many2one('res.company', 'Company') 'company_id': fields.many2one('res.company', 'Company')
} }

View File

@ -459,11 +459,34 @@ class module(osv.osv):
continue continue
for lang in filter_lang: 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): if os.path.exists(f):
logger.notifyChannel("init", netsvc.LOG_INFO, 'module %s: loading translation file for language %s' % (mod.name, lang)) 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) 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() module()
class module_dependency(osv.osv): class module_dependency(osv.osv):

View File

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

View File

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

View File

@ -156,6 +156,7 @@
<rng:element name="notebook"> <rng:element name="notebook">
<rng:optional><rng:attribute name="position"/></rng:optional> <rng:optional><rng:attribute name="position"/></rng:optional>
<rng:optional><rng:attribute name="colspan"/></rng:optional> <rng:optional><rng:attribute name="colspan"/></rng:optional>
<rng:optional><rng:attribute name="tabpos"/></rng:optional>
<rng:oneOrMore> <rng:oneOrMore>
<rng:ref name="page"/> <rng:ref name="page"/>
</rng:oneOrMore> </rng:oneOrMore>
@ -222,6 +223,7 @@
<rng:optional><rng:attribute name="domain"/></rng:optional> <rng:optional><rng:attribute name="domain"/></rng:optional>
<rng:optional><rng:attribute name="invisible"/></rng:optional> <rng:optional><rng:attribute name="invisible"/></rng:optional>
<rng:optional><rng:attribute name="password"/></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="sum"/></rng:optional>
<rng:optional><rng:attribute name="select"/></rng:optional> <rng:optional><rng:attribute name="select"/></rng:optional>
<rng:optional><rng:attribute name="group"/></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="day_length" /></rng:optional>
<rng:optional><rng:attribute name="date_delay" /></rng:optional> <rng:optional><rng:attribute name="date_delay" /></rng:optional>
<rng:optional><rng:attribute name="type" /></rng:optional> <rng:optional><rng:attribute name="type" /></rng:optional>
<rng:optional><rng:attribute name="mode" /></rng:optional>
<rng:oneOrMore> <rng:oneOrMore>
<rng:ref name="field"/> <rng:ref name="field"/>
</rng:oneOrMore> </rng:oneOrMore>
@ -336,6 +339,7 @@
<rng:optional><rng:attribute name="readonly"/></rng:optional> <rng:optional><rng:attribute name="readonly"/></rng:optional>
<rng:optional><rng:attribute name="position"/></rng:optional> <rng:optional><rng:attribute name="position"/></rng:optional>
<rng:optional><rng:attribute name="context"/></rng:optional> <rng:optional><rng:attribute name="context"/></rng:optional>
<rng:optional><rng:attribute name="confirm"/></rng:optional>
<rng:zeroOrMore> <rng:zeroOrMore>
<rng:choice> <rng:choice>
<rng:ref name="form" /> <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_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_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_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 # OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved # 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 # 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 # 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 SocketServer
import socket
import logging import logging
import logging.handlers import logging.handlers
import os import os
import signal
import socket
import sys
import threading
import time
import xmlrpclib
import release
_service = {} _service = {}
_group = {} _group = {}
_res_id = 1 _res_id = 1
_res = {} _res = {}
class ServiceEndPointCall(object): class ServiceEndPointCall(object):
def __init__(self, id, method): def __init__(self, id, method):
self._id = id self._id = id
@ -131,20 +137,10 @@ class LocalService(Service):
Logger().notifyChannel('module', LOG_ERROR, 'This service does not exists: %s' % (str(keyError),) ) Logger().notifyChannel('module', LOG_ERROR, 'This service does not exists: %s' % (str(keyError),) )
raise raise
class ServiceUnavailable(Exception):
pass
def service_exist(name): def service_exist(name):
return (name in _service) and bool(_service[name]) return (name in _service) and bool(_service[name])
LOG_NOTSET = 'notset'
def get_rpc_paths():
return map(lambda s: '/xmlrpc/%s' % s, _service)
LOG_DEBUG_RPC = 'debug_rpc' LOG_DEBUG_RPC = 'debug_rpc'
LOG_DEBUG = 'debug' LOG_DEBUG = 'debug'
LOG_INFO = 'info' LOG_INFO = 'info'
@ -159,7 +155,24 @@ def init_logger():
from tools import config from tools import config
import os 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']: if config['logfile']:
# LogFile Handler
logf = config['logfile'] logf = config['logfile']
try: try:
dirname = os.path.dirname(logf) dirname = os.path.dirname(logf)
@ -170,17 +183,16 @@ def init_logger():
sys.stderr.write("ERROR: couldn't create the logfile directory\n") sys.stderr.write("ERROR: couldn't create the logfile directory\n")
handler = logging.StreamHandler(sys.stdout) handler = logging.StreamHandler(sys.stdout)
else: else:
# Normal Handler on standard output
handler = logging.StreamHandler(sys.stdout) 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 # tell the handler to use this format
handler.setFormatter(formatter) handler.setFormatter(formatter)
# add the handler to the root logger # add the handler to the root logger
logging.getLogger().addHandler(handler) logger.addHandler(handler)
logging.getLogger().setLevel(config['log_level']) logger.setLevel(config['log_level'] or '0')
if (not isinstance(handler, logging.FileHandler)) and os.name != 'nt': if (not isinstance(handler, logging.FileHandler)) and os.name != 'nt':
# change color of level names # change color of level names
@ -206,6 +218,14 @@ def init_logger():
class Logger(object): 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): def notifyChannel(self, name, level, msg):
log = logging.getLogger(name) log = logging.getLogger(name)
@ -213,14 +233,19 @@ class Logger(object):
fct = lambda msg, *args, **kwargs: log.log(logging.DEBUG_RPC, msg, *args, **kwargs) fct = lambda msg, *args, **kwargs: log.log(logging.DEBUG_RPC, msg, *args, **kwargs)
setattr(log, LOG_DEBUG_RPC, fct) setattr(log, LOG_DEBUG_RPC, fct)
extra = {
'uncoloredlevelname': self.uncoloredlevelname(level),
'application' : "%s %s" % (release.description, release.version),
}
level_method = getattr(log, level) level_method = getattr(log, level)
result = str(msg).strip().split('\n') result = str(msg).strip().split('\n')
if len(result)>1: if len(result)>1:
for idx, s in enumerate(result): for idx, s in enumerate(result):
level_method('[%02d]: %s' % (idx+1, s,)) level_method('[%02d]: %s' % (idx+1, s,), extra=extra)
elif result: elif result:
level_method(result[0]) level_method(result[0], extra=extra)
init_logger() init_logger()
@ -248,46 +273,35 @@ class Agent(object):
timer.cancel() timer.cancel()
quit = classmethod(quit) 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 xmlrpc(object):
class RpcGateway(object): class RpcGateway(object):
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
class GenericXMLRPCRequestHandler: 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): def _dispatch(self, method, params):
# print 'TERP-CALL : ',method, params
import traceback import traceback
try: try:
self.log('method', method)
self.log('params', params)
n = self.path.split("/")[-1] n = self.path.split("/")[-1]
s = LocalService(n) s = LocalService(n)
m = getattr(s, method) m = getattr(s, method)
s._service._response = None s._service._response = None
r = m(*params) r = m(*params)
self.log('result', r)
res = s._service._response res = s._service._response
if res != None: if res is not None:
r = res r = res
self.log('res',r)
return r return r
except Exception, e: except Exception, e:
tb_s = reduce(lambda x, y: x+y, traceback.format_exception( self.log('exception', e)
sys.exc_type, sys.exc_value, sys.exc_traceback)) tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
s = str(e) s = str(e)
import tools import tools
if tools.config['debug_mode']: if tools.config['debug_mode']:
@ -296,47 +310,68 @@ class GenericXMLRPCRequestHandler:
pdb.post_mortem(tb) pdb.post_mortem(tb)
raise xmlrpclib.Fault(s, tb_s) 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): 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): class SimpleThreadedXMLRPCServer(SocketServer.ThreadingMixIn, SimpleXMLRPCServer.SimpleXMLRPCServer):
def server_bind(self): def server_bind(self):
try: self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) SimpleXMLRPCServer.SimpleXMLRPCServer.server_bind(self)
SimpleXMLRPCServer.SimpleXMLRPCServer.server_bind(self)
except: class SecureThreadedXMLRPCServer(SimpleThreadedXMLRPCServer):
Logger().notifyChannel('init', LOG_CRITICAL, 'Address already in use') def __init__(self, server_address, HandlerClass, logRequests=1):
sys.exit(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): class HttpDaemon(threading.Thread):
def __init__(self, interface, port, secure=False): def __init__(self, interface, port, secure=False):
threading.Thread.__init__(self) threading.Thread.__init__(self)
self.__port = port self.__port = port
self.__interface = interface self.__interface = interface
self.secure = secure self.secure = bool(secure)
if secure: handler_class = (SimpleXMLRPCRequestHandler, SecureXMLRPCRequestHandler)[self.secure]
from ssl import SecureXMLRPCServer server_class = (SimpleThreadedXMLRPCServer, SecureThreadedXMLRPCServer)[self.secure]
class SecureXMLRPCRequestHandler(GenericXMLRPCRequestHandler, SecureXMLRPCServer.SecureXMLRPCRequestHandler): if self.secure:
SecureXMLRPCServer.SecureXMLRPCRequestHandler.rpc_paths = get_rpc_paths() from OpenSSL.SSL import Error as SSLError
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)
else: else:
self.server = SimpleThreadedXMLRPCServer((interface, port), class SSLError(Exception): pass
SimpleXMLRPCRequestHandler, 0)
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): def attach(self, path, gw):
pass pass
@ -344,16 +379,7 @@ class HttpDaemon(threading.Thread):
def stop(self): def stop(self):
self.running = False self.running = False
if os.name != 'nt': if os.name != 'nt':
if hasattr(socket, 'SHUT_RDWR'): self.server.socket.shutdown( hasattr(socket, 'SHUT_RDWR') and socket.SHUT_RDWR or 2 )
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.close() self.server.socket.close()
def run(self): def run(self):
@ -403,16 +429,17 @@ class TinySocketClientThread(threading.Thread):
return False return False
try: try:
self.log(msg) self.log(msg)
s = LocalService(msg[0]) service = LocalService(msg[0])
m = getattr(s, msg[1]) method = getattr(service, msg[1])
s._service._response = None service._service._response = None
r = m(*msg[2:]) result_from_method = method(*msg[2:])
res = s._service._response res = service._service._response
if res != None: if res != None:
r = res result_from_method = res
self.log(r) self.log(result_from_method)
ts.mysend(r) ts.mysend(result_from_method)
except Exception, e: 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)) tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
import tools import tools
if tools.config['debug_mode']: if tools.config['debug_mode']:

View File

@ -61,6 +61,14 @@ if pwd.getpwuid(os.getuid())[0] == 'root' :
import netsvc import netsvc
logger = netsvc.Logger() 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 # 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') 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 # connect to the database and initialize it with base if needed
#--------------------------------------------------------------- #---------------------------------------------------------------
@ -163,17 +168,16 @@ if tools.config['xmlrpc']:
try: try:
port = int(tools.config["port"]) port = int(tools.config["port"])
except Exception: 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) sys.exit(1)
interface = tools.config["interface"] interface = tools.config["interface"]
secure = tools.config["secure"] secure = tools.config["secure"]
httpd = netsvc.HttpDaemon(interface, port, secure) httpd = netsvc.HttpDaemon(interface, port, secure)
if tools.config["xmlrpc"]: xml_gw = netsvc.xmlrpc.RpcGateway('web-services')
xml_gw = netsvc.xmlrpc.RpcGateway('web-services') httpd.attach("/xmlrpc", xml_gw)
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))
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"]: #if tools.config["soap"]:
@ -220,7 +224,6 @@ if tools.config['netrpc']:
tinySocket.start() tinySocket.start()
if tools.config['xmlrpc']: if tools.config['xmlrpc']:
httpd.start() httpd.start()
#dispatcher.run()
while True: while True:
time.sleep(1) time.sleep(1)

View File

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

View File

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

View File

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

View File

@ -166,7 +166,7 @@ class report_rml(report_int):
res = service.execute(cr.dbname, uid, 'ir.translation', res = service.execute(cr.dbname, uid, 'ir.translation',
'_get_source', self.name2, 'xsl', lang, child.content) '_get_source', self.name2, 'xsl', lang, child.content)
if res: if res:
child.setContent(res) child.setContent(res.encode('utf-8'))
look_down(child.children, lang) look_down(child.children, lang)
child = child.next child = child.next
@ -218,7 +218,7 @@ from report_sxw import report_sxw
def register_all(db): def register_all(db):
opj = os.path.join opj = os.path.join
cr = db.cursor() 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() result = cr.dictfetchall()
cr.close() cr.close()
for r in result: for r in result:

View File

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

View File

@ -20,20 +20,23 @@
# #
############################################################################## ##############################################################################
import base64, os, string import base64
import netsvc
import pooler, security, ir, tools
import logging import logging
import os
import threading, thread import security
import string
import thread
import threading
import time import time
import addons
import sql_db
from tools.translate import _ from tools.translate import _
import addons
import ir
import netsvc
import pooler
import release import release
import sql_db
import tools
logging.basicConfig() logging.basicConfig()
@ -89,8 +92,8 @@ class db(netsvc.Service):
mids = modobj.search(cr, 1, [('state', '=', 'installed')]) mids = modobj.search(cr, 1, [('state', '=', 'installed')])
modobj.update_translations(cr, 1, mids, lang) modobj.update_translations(cr, 1, mids, lang)
cr.execute('UPDATE res_users SET password=%s, active=True WHERE login=%s', ( cr.execute('UPDATE res_users SET password=%s, context_lang=%s, active=True WHERE login=%s', (
user_password, 'admin')) user_password, lang, 'admin'))
cr.execute('SELECT login, password, name ' \ cr.execute('SELECT login, password, name ' \
' FROM res_users ' \ ' FROM res_users ' \
' ORDER BY login') ' ORDER BY login')
@ -459,11 +462,10 @@ class report_spool(netsvc.Service):
self._reports[id] = {'uid': uid, 'result': False, 'state': False, 'exception': None} self._reports[id] = {'uid': uid, 'result': False, 'state': False, 'exception': None}
def go(id, uid, ids, datas, context): def go(id, uid, ids, datas, context):
cr = pooler.get_db(db).cursor()
try: try:
cr = pooler.get_db(db).cursor()
obj = netsvc.LocalService('report.'+object) obj = netsvc.LocalService('report.'+object)
(result, format) = obj.create(cr, uid, ids, datas, context) (result, format) = obj.create(cr, uid, ids, datas, context)
cr.close()
self._reports[id]['result'] = result self._reports[id]['result'] = result
self._reports[id]['format'] = format self._reports[id]['format'] = format
self._reports[id]['state'] = True self._reports[id]['state'] = True
@ -477,6 +479,7 @@ class report_spool(netsvc.Service):
'Exception: %s\n%s' % (str(exception), tb_s)) 'Exception: %s\n%s' % (str(exception), tb_s))
self._reports[id]['exception'] = exception self._reports[id]['exception'] = exception
self._reports[id]['state'] = True self._reports[id]['state'] = True
cr.close()
return True return True
thread.start_new_thread(go, (id, uid, ids, datas, context)) 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._obj = self._cnx.cursor(cursor_factory=psycopg1cursor)
self.autocommit(False) self.autocommit(False)
self.dbname = pool.dbname self.dbname = pool.dbname
from inspect import stack
self.__caller = tuple(stack()[2][1:3])
def __del__(self): def __del__(self):
if hasattr(self, '_obj'): if hasattr(self, '_obj'):
# Oops. 'self' has not been closed explicitly. # 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 # but the database connection is not put back into the connection
# pool, preventing some operation on the database like dropping it. # pool, preventing some operation on the database like dropping it.
# This can also lead to a server overload. # 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() self.close()
@check @check
def execute(self, query, params=None): def execute(self, query, params=None):
if params is None: self.count+=1
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)
if '%d' in query or '%f' in query: if '%d' in query or '%f' in query:
#import traceback
#traceback.print_stack()
log(query, netsvc.LOG_WARNING) log(query, netsvc.LOG_WARNING)
log("SQL queries mustn't containt %d or %f anymore. Use only %s", 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') query = query.replace('%d', '%s').replace('%f', '%s')
if self.sql_log: if self.sql_log:
now = mdt.now() now = mdt.now()
try: try:
res = self._obj.execute(query, p or None) res = self._obj.execute(query, params)
except psycopg2.ProgrammingError, pe: except psycopg2.ProgrammingError, pe:
logger= netsvc.Logger() logger= netsvc.Logger()
logger.notifyChannel('sql_db', netsvc.LOG_ERROR, "Programming error: %s, in query %s" % (pe, query)) 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 self.sql_into_log[res_into.group(1)][1] += mdt.now() - now
return res 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 print_log(self):
def process(type): def process(type):
sqllogs = {'from':self.sql_from_log, 'into':self.sql_into_log} sqllogs = {'from':self.sql_from_log, 'into':self.sql_into_log}
@ -163,6 +150,7 @@ class Cursor(object):
process('from') process('from')
process('into') process('into')
self.count = 0 self.count = 0
self.sql_log = False
@check @check
def close(self): 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 import *
from amount_to_text_en import * from amount_to_text_en import *
from pdf_utils import * from pdf_utils import *
from sql import *
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -28,11 +28,19 @@ import netsvc
import logging import logging
import release import release
def check_ssl():
try:
from OpenSSL import SSL
import socket
return hasattr(socket, 'ssl')
except:
return False
class configmanager(object): class configmanager(object):
def __init__(self, fname=None): def __init__(self, fname=None):
self.options = { self.options = {
'email_from':False, 'email_from':False,
'verbose': False,
'interface': '', # this will bind the server to all interfaces 'interface': '', # this will bind the server to all interfaces
'port': '8069', 'port': '8069',
'netinterface': '', 'netinterface': '',
@ -58,28 +66,29 @@ class configmanager(object):
'import_partial': "", 'import_partial': "",
'pidfile': None, 'pidfile': None,
'logfile': None, 'logfile': None,
'secure': False,
'smtp_server': 'localhost', 'smtp_server': 'localhost',
'smtp_user': False, 'smtp_user': False,
'smtp_port':25, 'smtp_port':25,
'smtp_password': False, 'smtp_password': False,
'stop_after_init': False, # this will stop the server after initialization 'stop_after_init': False, # this will stop the server after initialization
'price_accuracy': 2, 'price_accuracy': 2,
'secure' : False,
'syslog' : False,
'log_level': logging.INFO, 'log_level': logging.INFO,
'assert_exit_level': logging.WARNING, # level above which a failed assert will be raise '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) version = "%s %s" % (release.description, release.version)
parser = optparse.OptionParser(version=version) parser = optparse.OptionParser(version=version)
parser.add_option("-c", "--config", dest="config", help="specify alternate config file") 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("-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("--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("-n", "--interface", dest="interface", help="specify the TCP IP address")
parser.add_option("-p", "--port", dest="port", help="specify the TCP port") 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 # 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("--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('--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("--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') # Logging Group
parser.add_option('--smtp', dest='smtp_server', default='', help='specify the SMTP server for sending email') group = optparse.OptionGroup(parser, "Logging Configuration")
parser.add_option('--smtp-port', dest='smtp_port', default='25', help='specify the SMTP port') group.add_option("--logfile", dest="logfile", help="file where the server log will be stored")
parser.add_option('--smtp-ssl', dest='smtp_ssl', default='', help='specify the SMTP server support SSL or not') group.add_option("--syslog", action="store_true", dest="syslog",
parser.add_option('--smtp-user', dest='smtp_user', default='', help='specify the SMTP username for sending email') default=False, help="Send the log to the syslog server")
parser.add_option('--smtp-password', dest='smtp_password', default='', help='specify the SMTP password for sending email') group.add_option('--log-level', dest='log_level', type='choice', choices=loglevels.keys(),
parser.add_option('--price_accuracy', dest='price_accuracy', default='2', help='specify the price accuracy') 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 = optparse.OptionGroup(parser, "Modules related options")
group.add_option("-g", "--upgrade", action="store_true", dest="upgrade", default=False, help="Upgrade/install/uninstall modules") 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 # the same for the pidfile
if self.options['pidfile'] in ('None', 'False'): if self.options['pidfile'] in ('None', 'False'):
self.options['pidfile'] = False self.options['pidfile'] = False
for arg in ('interface', 'port', 'db_name', 'db_user', 'db_password', 'db_host', keys = ['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'): '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): if getattr(opt, arg):
self.options[arg] = getattr(opt, arg) self.options[arg] = getattr(opt, arg)
for arg in ('language', 'translate_out', 'translate_in', keys = ['language', 'translate_out', 'translate_in', 'upgrade', 'debug_mode',
'upgrade', 'verbose', 'debug_mode', 'stop_after_init', 'without_demo', 'netrpc', 'xmlrpc', 'syslog']
'stop_after_init', 'without_demo', 'netrpc', 'xmlrpc'):
if hasSSL:
keys.append('secure')
for arg in keys:
self.options[arg] = getattr(opt, arg) self.options[arg] = getattr(opt, arg)
if opt.assert_exit_level: if opt.assert_exit_level:
self.options['assert_exit_level'] = loglevels[opt.assert_exit_level] self.options['assert_exit_level'] = loglevels[opt.assert_exit_level]
if opt.log_level: if opt.log_level:
self.options['log_level'] = loglevels[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') rec_id = rec.getAttribute("id").encode('ascii')
self._test_xml_id(rec_id) self._test_xml_id(rec_id)
# if not rec_id and not self.isnoupdate(data_node): if self.isnoupdate(data_node) and self.mode != 'init':
# print "Warning", rec_model
if self.isnoupdate(data_node) and not self.mode in ('init','update'):
# check if the xml record has an id string # check if the xml record has an id string
if rec_id: if rec_id:
id = self.pool.get('ir.model.data')._update_dummy(cr, self.uid, rec_model, self.module, 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 ) 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: if rec_id:
self.idref[rec_id] = int(id) self.idref[rec_id] = int(id)
if config.get('i mport_partial', False): if config.get('import_partial', False):
cr.commit() cr.commit()
return rec_model, id return rec_model, id

View File

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

View File

@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*- # -*- 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 # Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$ # $Id$
# #
@ -26,7 +26,7 @@
import re import re
component_re = re.compile(r'(\d+ | [a-z]+ | \.| -)', re.VERBOSE) 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): def _parse_version_parts(s):
for part in component_re.split(s): for part in component_re.split(s):
@ -82,15 +82,16 @@ def parse_version(s):
return tuple(parts) return tuple(parts)
if __name__ == '__main__': if __name__ == '__main__':
pvs = [] 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'): 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) pv = parse_version(v)
print v, pv print v, pv
pvs.append(pv) pvs.append(pv)
def cmp(a, b): def cmp(a, b):
assert(a < b) print a, b
return b assert(a < b)
return b
reduce(cmp, pvs) reduce(cmp, pvs)

View File

@ -20,8 +20,10 @@
# #
############################################################################## ##############################################################################
def drop_view_if_exists(cr, viewname):
import SecureXMLRPCServer 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: # 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': if result['type'] != 'form':
continue continue
name = "%s,%s" % (encode(obj.wiz_name), state_name) name = "%s,%s" % (encode(obj.wiz_name), state_name)
def_params = { def_params = {
'string': ('wizard_field', lambda s: [encode(s)]), '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)]), 'help': ('help', lambda s: [encode(s)]),
} }
@ -468,9 +468,9 @@ def trans_generate(lang, modules, dbname=None):
d = xml.dom.minidom.parseString(xmlstr) d = xml.dom.minidom.parseString(xmlstr)
for t in parse_func(d.documentElement): for t in parse_func(d.documentElement):
push_translation(module, report_type, name, 0, t) push_translation(module, report_type, name, 0, t)
except IOError: except IOError, xml.dom.expatbuilder.expat.ExpatError:
if fname: 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: for constraint in pool.get(model)._constraints:
msg = constraint[1] msg = constraint[1]

View File

@ -26,14 +26,16 @@
import netsvc import netsvc
def log(cr,ident,act_id,info=''): def log(cr,ident,act_id,info=''):
msg = """ return
res_type: %r # msg = """
res_id: %d #res_type: %r
uid: %d #res_id: %d
act_id: %d #uid: %d
info: %s #act_id: %d
""" % (ident[1], ident[2], ident[0], act_id, info) #info: %s
netsvc.Logger().notifyChannel('wkf_log', netsvc.LOG_DEBUG, msg) #""" % (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)) #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 db_password = False
; Uncomment these for xml-rpc over SSL ; Uncomment these for xml-rpc over SSL
; secure = True ; secure = True
; sslcert = /etc/openerp/server.cert ; secure_cert_file = /etc/openerp/server.cert
; sslkey = /etc/openerp/server.key ; secure_pkey_file = /etc/openerp/server.key
root_path = None root_path = None
soap = False soap = False
translate_modules = ['all'] translate_modules = ['all']

View File

@ -27,9 +27,6 @@
!error "Do not forget to specify the version of OpenERP - /DVERSION=<VERSION>" !error "Do not forget to specify the version of OpenERP - /DVERSION=<VERSION>"
!endif !endif
;--------------------------------
;Include Modern UI
!include "MUI.nsh" !include "MUI.nsh"
;-------------------------------- ;--------------------------------
@ -45,7 +42,7 @@ SetCompress auto
InstallDir "$PROGRAMFILES\OpenERP Server" InstallDir "$PROGRAMFILES\OpenERP Server"
;Get installation folder from registry if available ;Get installation folder from registry if available
InstallDirRegKey HKCU "Software\OpenERP Server" "" InstallDirRegKey HKLM "Software\OpenERP Server" ""
BrandingText "OpenERP Server ${VERSION}" BrandingText "OpenERP Server ${VERSION}"
@ -63,6 +60,12 @@ Var STARTMENU_FOLDER
!define MUI_ABORTWARNING !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 ;Pages
@ -73,14 +76,15 @@ Var STARTMENU_FOLDER
!define MUI_HEADERIMAGE_BITMAP_NOSTRETCH !define MUI_HEADERIMAGE_BITMAP_NOSTRETCH
!define MUI_HEADER_TRANSPARENT_TEXT "" !define MUI_HEADER_TRANSPARENT_TEXT ""
!define MUI_HEADERIMAGE_BITMAP ".\pixmaps\openerp-slogan.bmp" !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_WELCOME
!insertmacro MUI_PAGE_LICENSE "doc\License.rtf" !insertmacro MUI_PAGE_LICENSE "doc\License.rtf"
!insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_DIRECTORY
;Start Menu Folder Page Configuration ;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_KEY "Software\OpenERP Server"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "OpenERP Server" !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "OpenERP Server"
@ -91,7 +95,7 @@ Var STARTMENU_FOLDER
!define MUI_FINISHPAGE_NOAUTOCLOSE !define MUI_FINISHPAGE_NOAUTOCLOSE
!define MUI_FINISHPAGE_RUN !define MUI_FINISHPAGE_RUN
!define MUI_FINISHPAGE_RUN_CHECKED !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_RUN_FUNCTION "LaunchLink"
!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED !define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED
!define MUI_FINISHPAGE_SHOWREADME $INSTDIR\README.txt !define MUI_FINISHPAGE_SHOWREADME $INSTDIR\README.txt
@ -106,6 +110,7 @@ Var STARTMENU_FOLDER
;Languages ;Languages
!insertmacro MUI_LANGUAGE "English" !insertmacro MUI_LANGUAGE "English"
!insertmacro MUI_LANGUAGE "French"
!macro CreateInternetShortcut FILENAME URL !macro CreateInternetShortcut FILENAME URL
WriteINIStr "${FILENAME}.url" "InternetShortcut" "URL" "${URL}" WriteINIStr "${FILENAME}.url" "InternetShortcut" "URL" "${URL}"
@ -114,10 +119,26 @@ Var STARTMENU_FOLDER
;-------------------------------- ;--------------------------------
;Installer Sections ;Installer Sections
Function .onInit 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 ClearErrors
ReadRegStr $0 HKCU "Software\OpenERP Server" "" ReadRegStr $0 HKLM "Software\OpenERP Server" ""
IfErrors DoInstall 0 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 Quit
DoInstall: DoInstall:
FunctionEnd FunctionEnd
@ -137,11 +158,15 @@ Section "OpenERP Server" SecOpenERPServer
File "win32\stop.bat" File "win32\stop.bat"
;Store installation folder ;Store installation folder
WriteRegStr HKCU "Software\OpenERP Server" "" $INSTDIR WriteRegStr HKLM "Software\OpenERP Server" "" $INSTDIR
!ifndef ALLINONE
;Create uninstaller ;Create uninstaller
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\OpenERP Server" "DisplayName" "OpenERP Server ${VERSION}" 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" 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" WriteUninstaller "$INSTDIR\Uninstall.exe"
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application !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\Stop service.lnk" "$INSTDIR\service\stop.bat"
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Edit config.lnk" "notepad.exe" "$INSTDIR\openerp-server.conf" 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" CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\View log.lnk" "notepad.exe" "$INSTDIR\openerp-server.log"
!ifndef ALLINONE
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\uninstall.exe" 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\Forum" "http://www.openerp.com/forum"
!insertmacro CreateInternetShortcut "$SMPROGRAMS\$STARTMENU_FOLDER\Translation" "https://translations.launchpad.net/openobject" !insertmacro CreateInternetShortcut "$SMPROGRAMS\$STARTMENU_FOLDER\Translation" "https://translations.launchpad.net/openobject"
!insertmacro MUI_STARTMENU_WRITE_END !insertmacro MUI_STARTMENU_WRITE_END
@ -164,13 +191,6 @@ SectionEnd
;Descriptions ;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 ;Uninstaller Section
@ -186,7 +206,9 @@ Section "Uninstall"
Delete "$SMPROGRAMS\$MUI_TEMP\Forum.url" Delete "$SMPROGRAMS\$MUI_TEMP\Forum.url"
Delete "$SMPROGRAMS\$MUI_TEMP\Translation.url" Delete "$SMPROGRAMS\$MUI_TEMP\Translation.url"
!ifndef ALLINONE
Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
!endif
Delete "$SMPROGRAMS\$MUI_TEMP\OpenERP Server.lnk" Delete "$SMPROGRAMS\$MUI_TEMP\OpenERP Server.lnk"
Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk"
Delete "$SMPROGRAMS\$MUI_TEMP\Start service.lnk" Delete "$SMPROGRAMS\$MUI_TEMP\Start service.lnk"
@ -208,8 +230,12 @@ Section "Uninstall"
startMenuDeleteLoopDone: startMenuDeleteLoopDone:
!ifndef ALLINONE
DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\OpenERP Server" 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 SectionEnd
@ -217,3 +243,24 @@ Function LaunchLink
nsExec::Exec "net start openerp-service" nsExec::Exec "net start openerp-service"
FunctionEnd 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('..') os.chdir('..')
for (dp,dn,names) in os.walk('doc'): for (dp,dn,names) in os.walk('doc'):
files.append((dp, map(lambda x: opj(dp, x), names))) 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: else:
man_directory = opj('share', 'man') man_directory = opj('share', 'man')
files.append((opj(man_directory, 'man1'), ['man/openerp-server.1'])) 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') 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(): for addon in find_addons():
add_path = addon.replace('.', os.path.sep).replace('openerp-server', 'bin', 1) 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)) 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", "packages": ["lxml", "lxml.builder", "lxml._elementpath", "lxml.etree",
"lxml.objectify", "decimal", "xml", "xml.dom", "xml.xpath", "lxml.objectify", "decimal", "xml", "xml.dom", "xml.xpath",
"encodings","mx.DateTime","wizard","pychart","PIL", "pyparsing", "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"], "excludes" : ["Tkconstants","Tkinter","tcl"],
} }
} }
@ -155,7 +163,6 @@ setup(name = name,
'openerp-server.addons', 'openerp-server.addons',
'openerp-server.ir', 'openerp-server.ir',
'openerp-server.osv', 'openerp-server.osv',
'openerp-server.ssl',
'openerp-server.service', 'openerp-server.service',
'openerp-server.tools', 'openerp-server.tools',
'openerp-server.report', 'openerp-server.report',