[MERGE]: Merged with trunk-server.

bzr revid: uco@tinyerp.com-20100617063537-8cv03xltm7fqw6rh
This commit is contained in:
uco (OpenERP)
2010-06-17 12:05:37 +05:30
57 changed files with 827 additions and 409 deletions
+10 -2
View File
@@ -28,6 +28,7 @@ import zipimport
import osv
import tools
import tools.osutil
from tools.safe_eval import safe_eval as eval
import pooler
@@ -663,6 +664,9 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs):
# TODO manage .csv file with noupdate == (kind == 'init')
if ext == '.sql':
process_sql_file(cr, fp)
elif ext == '.csv':
noupdate = (kind == 'init')
tools.convert_csv_import(cr, module_name, file, id_map, mode, noupdate)
elif ext == '.yml':
tools.convert_yaml_import(cr, module_name, file, id_map, mode, noupdate)
else:
@@ -725,8 +729,12 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, **kwargs):
load_demo_xml(cr, m, idref, mode)
load_demo(cr, m, idref, mode)
cr.execute('update ir_module_module set demo=%s where id=%s', (True, mid))
load_test(cr, m, idref, mode)
# launch tests only in demo mode, as most tests will depend
# on demo data. Other tests can be added into the regular
# 'data' section, but should probably not alter the data,
# as there is no rollback.
load_test(cr, m, idref, mode)
package_todo.append(package.name)
+2 -2
View File
@@ -36,7 +36,6 @@
'base_menu.xml',
'res/res_security.xml',
'res/res_config.xml',
'maintenance/maintenance_security.xml',
'data/res.country.state.csv'
],
'update_xml': [
@@ -58,7 +57,7 @@
'res/partner/partner_wizard.xml',
'res/bank_view.xml',
'res/country_view.xml',
'res/res_currency_view.xml',
'res/res_currency_view.xml',
'res/partner/crm_view.xml',
'res/partner/wizard/partner_sms_send_view.xml',
'res/partner/partner_data.xml',
@@ -75,6 +74,7 @@
],
'test': [
'test/base_test.xml',
#'test/base_test.yml'
'test/test_context.xml',
'bug_lp541545.xml',
],
+28 -23
View File
@@ -19,7 +19,7 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Groups">
<field colspan="4" name="name" select="1"/>
<field name="name" select="1"/>
<notebook colspan="4">
<page string="Users">
<field colspan="4" name="users" nolabel="1"/>
@@ -78,18 +78,22 @@
<form string="Users">
<notebook colspan="4">
<page string="Current Activity">
<field name="company_id" widget="selection" readonly="0" context="{'user_preference':True}"/>
<field name="company_id" widget="selection" readonly="0"
context="{'user_id': self, 'user_preference': 1}"/>
<field name="view" readonly="0"/>
<newline/>
<separator colspan="4" string="Preferences"/>
</page>
<page string="Preferences">
<field name="password" password="True" readonly="0"/>
<label colspan="4" string="Please note that you will have to logout and relog if you change your password."/>
<field name="context_lang" completion="1" readonly="0"/>
<field name="context_tz" completion="1" readonly="0" colspan="4"/>
<field name="view" colspan="4" readonly="0" />
<newline/>
<field colspan="4" name="signature" readonly="0"/>
<label string="" colspan="1"/>
<label colspan="3" string="Please note that you will have to logout and relog if you change your password."/>
<field name="context_lang" completion="1" readonly="0"/>
<field name="context_tz" completion="1" readonly="0"/>
<newline/>
<separator string="Signature" colspan="4"/>
<field colspan="4" name="signature" readonly="0" nolabel="1"/>
</page>
</notebook>
</form>
@@ -106,11 +110,12 @@
<field name="active"/>
<field name="login" select="1"/>
<field name="password" password="True"/>
<newline/>
<notebook colspan="4">
<page string="User">
<field name="address_id" select="1"/>
<field name="user_email" widget="email"/>
<field name="company_id" required="1"/>
<field name="company_id" required="1" context="{'user_id': self, 'user_preference': 1}"/>
<field name="action_id" required="True"/>
<field domain="[('usage','=','menu')]" name="menu_id" required="True"/>
<field name="context_lang"/>
@@ -286,22 +291,22 @@
<form position="attributes">
<attribute name="string">Choose Your Interface</attribute>
</form>
<xpath expr="//label[@string='description']"
position="attributes">
<attribute name="string">Choose between the simplified interface and the extended one. We suggest you use the simplified interface. It has less options and fields but is easier to understand. You will be able to switch to the extended interface later.</attribute>
</xpath>
<xpath expr='//separator[@string="title"]' position='attributes'>
<attribute name='string'>Choose Your Interface</attribute>
</xpath>
<xpath expr='//separator[@string="vsep"]' position='attributes'>
<attribute name='string'></attribute>
<attribute name='rowspan'>12</attribute>
</xpath>
<xpath expr="//label[@string='description']"
position="attributes">
<attribute name="string">Choose between the simplified interface and the extended one. We suggest you use the simplified interface. It has less options and fields but is easier to understand. You will be able to switch to the extended interface later.</attribute>
</xpath>
<xpath expr='//separator[@string="title"]' position='attributes'>
<attribute name='string'>Choose Your Interface</attribute>
</xpath>
<xpath expr='//separator[@string="vsep"]' position='attributes'>
<attribute name='string'></attribute>
<attribute name='rowspan'>12</attribute>
</xpath>
<group string="res_config_contents" position="replace">
<group colspan="4">
<field colspan="4" name="view" nolabel="1"/>
</group>
</group>
<group colspan="4">
<field colspan="4" name="view" nolabel="1"/>
</group>
</group>
<xpath expr='//button[@name="action_skip"]' position='replace'/>
<xpath expr='//button[@name="action_next"]' position='attributes'>
<attribute name='string'>Set</attribute>
+4 -4
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-01-04 06:02+0000\n"
"Last-Translator: Kuvaly [LCT] <kuvaly@seznam.cz>\n"
"PO-Revision-Date: 2010-06-06 04:19+0000\n"
"Last-Translator: Vladimír Burian <vladimir.burian@email.cz>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-06-01 03:39+0000\n"
"X-Launchpad-Export-Date: 2010-06-07 03:42+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
@@ -3880,7 +3880,7 @@ msgstr "Kontakty"
#. module: base
#: model:res.country,name:base.fo
msgid "Faroe Islands"
msgstr "Farské ostrovy"
msgstr "Faerské ostrovy"
#. module: base
#: model:ir.actions.wizard,name:base.wizard_upgrade
+12 -13
View File
@@ -8,14 +8,13 @@ msgstr ""
"Project-Id-Version: openobject-server\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-05-31 04:09+0000\n"
"Last-Translator: Sharoon Thomas http://openlabs.co.in "
"<sharoonthomas@teagarden.in>\n"
"PO-Revision-Date: 2010-06-07 04:17+0000\n"
"Last-Translator: OpenERP Administrators <Unknown>\n"
"Language-Team: English (United Kingdom) <en_GB@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-06-01 03:43+0000\n"
"X-Launchpad-Export-Date: 2010-06-08 03:40+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
@@ -493,7 +492,7 @@ msgstr "Model Description"
#. module: base
#: field:workflow.transition,trigger_expr_id:0
msgid "Trigger Expression"
msgstr ""
msgstr "Trigger Expression"
#. module: base
#: model:res.country,name:base.jo
@@ -833,7 +832,7 @@ msgstr "S. Georgia & S. Sandwich Isls."
#. module: base
#: field:ir.actions.url,url:0
msgid "Action URL"
msgstr ""
msgstr "Action URL"
#. module: base
#: selection:ir.ui.menu,icon:0
@@ -1050,7 +1049,7 @@ msgstr "East Timor"
#. module: base
#: view:ir.rule:0
msgid "Simple domain setup"
msgstr ""
msgstr "Simple domain setup"
#. module: base
#: field:res.currency,accuracy:0
@@ -1101,7 +1100,7 @@ msgstr "ir.rule"
#. module: base
#: selection:ir.cron,interval_type:0
msgid "Days"
msgstr ""
msgstr "Days"
#. module: base
#: field:ir.report.custom.fields,width:0
@@ -1436,27 +1435,27 @@ msgstr "STOCK_SELECT_COLOR"
#. module: base
#: selection:ir.ui.menu,icon:0
msgid "STOCK_NO"
msgstr ""
msgstr "STOCK_NO"
#. module: base
#: model:res.country,name:base.st
msgid "Saint Tome (Sao Tome) and Principe"
msgstr ""
msgstr "Saint Tome (Sao Tome) and Principe"
#. module: base
#: selection:res.partner.address,type:0
msgid "Invoice"
msgstr ""
msgstr "Invoice"
#. module: base
#: selection:ir.ui.menu,icon:0
msgid "STOCK_REDO"
msgstr ""
msgstr "STOCK_REDO"
#. module: base
#: model:res.country,name:base.bb
msgid "Barbados"
msgstr ""
msgstr "Barbados"
#. module: base
#: model:res.country,name:base.mg
+5 -5
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-06-01 05:21+0000\n"
"Last-Translator: goranc <goranc@gmail.com>\n"
"PO-Revision-Date: 2010-06-16 04:09+0000\n"
"Last-Translator: Goran Kliska <gkliska@gmail.com>\n"
"Language-Team: openerp-translators\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-06-02 03:32+0000\n"
"X-Launchpad-Export-Date: 2010-06-17 03:32+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
"Language: hr\n"
@@ -1381,7 +1381,7 @@ msgstr "Gruzija"
#. module: base
#: model:res.country,name:base.pl
msgid "Poland"
msgstr ""
msgstr "Poljska"
#. module: base
#: selection:ir.module.module,state:0
@@ -2703,7 +2703,7 @@ msgstr ""
#: help:ir.values,key2:0
msgid ""
"The kind of action or button in the client side that will trigger the action."
msgstr ""
msgstr "Vrsta akcije ili gumba na klijentskoj strani koja će okinuti akciju."
#. module: base
#: selection:ir.ui.menu,icon:0
+2 -2
View File
@@ -8,13 +8,13 @@ msgstr ""
"Project-Id-Version: openobject-server\n"
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-06-01 05:19+0000\n"
"PO-Revision-Date: 2010-06-16 04:11+0000\n"
"Last-Translator: Harry (Open ERP) <hmo@tinyerp.com>\n"
"Language-Team: Japanese <ja@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-06-02 03:32+0000\n"
"X-Launchpad-Export-Date: 2010-06-17 03:32+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
+8 -8
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-03-17 05:16+0000\n"
"Last-Translator: Valentin Caragea <carageav@gmail.com>\n"
"PO-Revision-Date: 2010-06-07 04:16+0000\n"
"Last-Translator: filsys <office@filsystem.ro>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-06-01 03:42+0000\n"
"X-Launchpad-Export-Date: 2010-06-08 03:39+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
@@ -774,12 +774,12 @@ msgstr "Uganda"
#. module: base
#: model:res.country,name:base.ne
msgid "Niger"
msgstr ""
msgstr "Niger"
#. module: base
#: model:res.country,name:base.ba
msgid "Bosnia-Herzegovina"
msgstr ""
msgstr "Bosnia-Herțegovina"
#. module: base
#: field:ir.report.custom.fields,alignment:0
@@ -789,7 +789,7 @@ msgstr "Aliniere"
#. module: base
#: selection:ir.rule,operator:0
msgid ">="
msgstr ""
msgstr ">="
#. module: base
#: view:res.lang:0
@@ -813,12 +813,12 @@ msgstr ""
#: field:ir.module.module,website:0
#: field:res.partner,website:0
msgid "Website"
msgstr ""
msgstr "Website"
#. module: base
#: field:ir.rule.group,rules:0
msgid "Tests"
msgstr ""
msgstr "Teste"
#. module: base
#: view:ir.module.repository:0
+2 -2
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-06-01 05:22+0000\n"
"PO-Revision-Date: 2010-06-16 04:12+0000\n"
"Last-Translator: Anders Wallenquist <anders.wallenquist@vertel.se>\n"
"Language-Team: <>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-06-02 03:32+0000\n"
"X-Launchpad-Export-Date: 2010-06-17 03:32+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
+2 -2
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.0\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-06-01 05:22+0000\n"
"PO-Revision-Date: 2010-06-16 04:09+0000\n"
"Last-Translator: Fabien (Open ERP) <fp@tinyerp.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-06-02 03:32+0000\n"
"X-Launchpad-Export-Date: 2010-06-17 03:32+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
+5 -5
View File
@@ -7,13 +7,13 @@ msgstr ""
"Project-Id-Version: OpenERP Server 5.0.4\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2009-12-18 08:39+0000\n"
"PO-Revision-Date: 2010-06-01 05:19+0000\n"
"Last-Translator: OpenERP Administrators <Unknown>\n"
"PO-Revision-Date: 2010-06-16 04:09+0000\n"
"Last-Translator: Eleanor Chen <chenyueg@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2010-06-02 03:33+0000\n"
"X-Launchpad-Export-Date: 2010-06-17 03:33+0000\n"
"X-Generator: Launchpad (build Unknown)\n"
#. module: base
@@ -3156,7 +3156,7 @@ msgstr "网页"
#. module: base
#: selection:module.lang.install,init,lang:0
msgid "English (CA)"
msgstr "英语(加拿大)"
msgstr "英语(加拿大)"
#. module: base
#: field:res.partner.event,planned_revenue:0
@@ -6656,7 +6656,7 @@ msgstr "职能名称"
#. module: base
#: view:maintenance.contract.wizard:0
msgid "_Cancel"
msgstr "取消(_C)"
msgstr "取消(_C)"
#. module: base
#: model:res.country,name:base.cy
+10 -6
View File
@@ -1244,11 +1244,6 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Record rules">
<separator colspan="4" string="Combination of rules"/>
<label align="0.0" angle="2" colspan="4" string="1. Global rules are combined together with a logical AND operator, and with the result of the following steps"/>
<label align="0.0" angle="2" colspan="4" string="2. Group-specific rules are combined together with a logical AND operator"/>
<label align="0.0" angle="2" colspan="4" string="3. If user belongs to several groups, the results from step 2 are combined with logical OR operator"/>
<label align="0.0" angle="2" colspan="4" string="Example: GLOBAL_RULE_1 AND GLOBAL_RULE_2 AND ( (GROUP_A_RULE_1 AND GROUP_A_RULE_2) OR (GROUP_B_RULE_1 AND GROUP_B_RULE_2) )"/>
<group col="2" colspan="2">
<separator colspan="2" string="General"/>
<field colspan="4" name="name"/>
@@ -1269,7 +1264,16 @@
<group colspan="4" expand="1">
<field name="global" select="1"/>
<field name="groups" select="1" nolabel="1" colspan="4"/>
</group>
</group>
<separator colspan="4" string="Combination of rules"/>
<label align="0.0" colspan="4"
string="1. Global rules are combined together with a logical AND operator, and with the result of the following steps"/>
<label align="0.0" colspan="4"
string="2. Group-specific rules are combined together with a logical AND operator"/>
<label align="0.0" colspan="4"
string="3. If user belongs to several groups, the results from step 2 are combined with logical OR operator"/>
<label align="0.0" colspan="4"
string="Example: GLOBAL_RULE_1 AND GLOBAL_RULE_2 AND ( (GROUP_A_RULE_1 AND GROUP_A_RULE_2) OR (GROUP_B_RULE_1 AND GROUP_B_RULE_2) )"/>
</form>
</field>
</record>
+2 -1
View File
@@ -20,6 +20,7 @@
##############################################################################
from osv import fields,osv
from tools.safe_eval import safe_eval as eval
import tools
import time
from tools.config import config
@@ -564,7 +565,7 @@ class actions_server(osv.osv):
'object':obj,
'obj': obj,
}
exec action.code in localdict
eval(action.code, localdict, "exec")
if 'action' in localdict:
return localdict['action']
else:
+1
View File
@@ -25,6 +25,7 @@ from datetime import datetime
from dateutil.relativedelta import relativedelta
import netsvc
import tools
from tools.safe_eval import safe_eval as eval
import pooler
from osv import fields, osv
+1
View File
@@ -24,6 +24,7 @@ from osv.orm import browse_null
import ir
import report.custom
from tools.translate import _
from tools.safe_eval import safe_eval as eval
import netsvc
class report_custom(osv.osv):
+25 -7
View File
@@ -21,10 +21,14 @@
from osv import fields,osv
import time
from operator import itemgetter
from functools import partial
import tools
from tools.safe_eval import safe_eval as eval
class ir_rule(osv.osv):
_name = 'ir.rule'
_MODES = ['read', 'write', 'create', 'unlink']
def _domain_force_get(self, cr, uid, ids, field_name, arg, context={}):
res = {}
@@ -44,13 +48,7 @@ class ir_rule(osv.osv):
return res
def _check_model_obj(self, cr, uid, ids, context={}):
model_obj = self.pool.get('ir.model')
for rule in self.browse(cr, uid, ids, context):
model = model_obj.browse(cr, uid, rule.model_id.id, context).model
obj = self.pool.get(model)
if isinstance(obj, osv.osv_memory):
return False
return True
return not any(isinstance(self.pool.get(rule.model_id.model), osv.osv_memory) for rule in self.browse(cr, uid, ids, context))
_columns = {
'name': fields.char('Name', size=128, select=1),
@@ -89,6 +87,8 @@ class ir_rule(osv.osv):
@tools.cache()
def _compute_domain(self, cr, uid, model_name, mode="read"):
if mode not in self._MODES:
raise ValueError('Invalid mode: %r' % (mode,))
group_rule = {}
global_rules = []
@@ -114,6 +114,24 @@ class ir_rule(osv.osv):
dom += self.domain_create(cr, uid, value)
return dom
def clear_cache(self, cr, uid):
cr.execute("""SELECT DISTINCT m.model
FROM ir_rule r
JOIN ir_model m
ON r.model_id = m.id
WHERE r.global
OR EXISTS (SELECT 1
FROM rule_group_rel g_rel
JOIN res_groups_users_rel u_rel
ON g_rel.group_id = u_rel.gid
WHERE g_rel.rule_group_id = r.id
AND u_rel.uid = %s)
""", (uid,))
models = map(itemgetter(0), cr.fetchall())
clear = partial(self._compute_domain.clear_cache, cr.dbname, uid)
[clear(model, mode) for model in models for mode in self._MODES]
def domain_get(self, cr, uid, model_name, mode='read', context={}):
dom = self._compute_domain(cr, uid, model_name, mode=mode)
if dom:
+6 -6
View File
@@ -68,15 +68,15 @@ class ir_ui_menu(osv.osv):
self._cache = {}
def search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False):
context=None, count=False):
super_offset = cond(uid == 1, offset, 0)
super_limit = cond(uid == 1, limit, None)
super_count = cond(uid == 1, count, False)
ids = super(ir_ui_menu, self).search(cr, uid, args, super_offset,
super_limit, order,
context=context, count=super_count)
super_limit, order, context=context, count=super_count)
if uid == 1:
return ids
@@ -104,9 +104,9 @@ class ir_ui_menu(osv.osv):
restrict_to_groups = [g.id for g in menu.groups_id]
if not user_groups.intersection(restrict_to_groups):
continue
result.append(menu.id)
self._cache[key] = True
continue
#result.append(menu.id)
#self._cache[key] = True
#continue
if menu.action:
# we check if the user has access to the action of the menu
+2 -1
View File
@@ -22,6 +22,7 @@
from osv import fields,osv
from lxml import etree
from tools import graph
from tools.safe_eval import safe_eval as eval
import tools
import netsvc
import os
@@ -70,7 +71,7 @@ class view(osv.osv):
method=True),
}
_defaults = {
'arch': '<?xml version="1.0"?>\n<tree string="Unknwown">\n\t<field name="name"/>\n</tree>',
'arch': '<?xml version="1.0"?>\n<tree string="My view">\n\t<field name="name"/>\n</tree>',
'priority': 16
}
_order = "priority"
+1 -4
View File
@@ -233,7 +233,7 @@ class ir_values(osv.osv):
pos+=1
try:
datas = self.pool.get(model).read(cr, uid, [id], fields, context)
except except_orm:
except except_orm, e:
return False
datas= datas and datas[0] or None
if not datas:
@@ -260,9 +260,6 @@ class ir_values(osv.osv):
res2.remove(r)
if r[1]=='Menuitem' and not res2:
raise osv.except_osv('Error !','You do not have the permission to perform this operation !!!')
# else:
# #raise osv.except_osv('Error !','You have not permission to perform operation !!!')
# res2.remove(r)
return res2
ir_values()
@@ -2,13 +2,5 @@
<openerp>
<data noupdate="0">
<record model="res.groups" id="group_maintenance_manager">
<field name="name">Maintenance Manager</field>
</record>
<record model="ir.ui.menu" id="menu_maintenance_contract">
<field eval="[(6,0,[ref('group_maintenance_manager')])]" name="groups_id"/>
</record>
</data>
</openerp>
+5 -4
View File
@@ -25,6 +25,7 @@ import re
import urllib
import os
import imp
import logging
import tools
from osv import fields, osv, orm
import zipfile
@@ -445,17 +446,17 @@ class module(osv.osv):
tools.trans_load(cr.dbname, f, lang, verbose=False)
def check(self, cr, uid, ids, context=None):
logger = netsvc.Logger()
logger = logging.getLogger('init')
for mod in self.browse(cr, uid, ids, context=context):
if not mod.description:
logger.notifyChannel("init", netsvc.LOG_WARNING, 'module %s: description is empty !' % (mod.name,))
logger.warn('module %s: description is empty !', mod.name)
if not mod.certificate or not mod.certificate.isdigit():
logger.notifyChannel('init', netsvc.LOG_WARNING, 'module %s: no quality certificate' % (mod.name,))
logger.info('module %s: no quality certificate', mod.name)
else:
val = long(mod.certificate[2:]) % 97 == 29
if not val:
logger.notifyChannel('init', netsvc.LOG_CRITICAL, 'module %s: invalid quality certificate: %s' % (mod.name, mod.certificate))
logger.critical('module %s: invalid quality certificate: %s', mod.name, mod.certificate)
raise osv.except_osv(_('Error'), _('Module %s: Invalid Quality Certificate') % (mod.name,))
+14 -16
View File
@@ -29,13 +29,6 @@
</tree>
</field>
</record>
<record id="action_module_category_tree" model="ir.actions.act_window">
<field name="name">Categories of Modules</field>
<field name="res_model">ir.module.category</field>
<field name="view_type">tree</field>
<field name="domain">[('parent_id','=',False)]</field>
</record>
<menuitem action="action_module_category_tree" id="menu_action_module_category_tree" parent="base.menu_management"/>
<!-- Click on a category -->
@@ -46,17 +39,22 @@
<field name="arch" type="xml">
<search string="Search modules">
<group col='10' colspan='4'>
<filter icon="terp-sale" string="Installed" domain="[('state', 'in', ['installed', 'to upgrade', 'to remove'])]"/>
<filter icon="terp-sale" string="Uninstalled" domain="[('state', 'in', ['uninstalled', 'uninstallable'])]"/>
<filter icon="terp-sale" string="To be upgraded" domain="[('state','in', ['to upgrade', 'to remove', 'to install'])]"/>
<filter icon="terp-check" string="Installed" domain="[('state', 'in', ['installed', 'to upgrade', 'to remove'])]"/>
<filter icon="terp-dialog-close" string="Uninstalled" domain="[('state', 'in', ['uninstalled', 'uninstallable'])]"/>
<filter icon="terp-gtk-jump-to-ltr" string="To be upgraded" domain="[('state','in', ['to upgrade', 'to remove', 'to install'])]"/>
<separator orientation="vertical"/>
<filter icon="terp-sale" string="Certified" domain="[('certificate','&lt;&gt;', False)]"/>
<filter icon="terp-camera_test" string="Certified" domain="[('certificate','&lt;&gt;', False)]"/>
<separator orientation="vertical"/>
<field name="name" select="1"/>
<field name="state" readonly="1" select="1"/>
<field name="name"/>
<field name="category_id"/>
<field name="state"/>
</group>
<group expand="0" string="Group By..." colspan="11" col="11" groups="base.group_extended">
<filter string="Category" icon="terp-personal" domain="[]" context="{'group_by':'category_id'}"/>
<filter string="Author" icon="terp-personal" domain="[]" context="{'group_by':'author'}"/>
<separator orientation="vertical"/>
<filter string="State" icon="terp-stock_effects-object-colorize" domain="[]" context="{'group_by':'state'}"/>
</group>
</search>
</field>
</record>
@@ -160,7 +158,7 @@
<field name="domain"/>
<field name="search_view_id" ref="view_module_filter"/>
</record>
<menuitem action="open_module_tree" id="menu_module_tree" parent="base.menu_management"/>
<menuitem action="open_module_tree" id="menu_module_tree" parent="base.menu_management"/>
</data>
</openerp>
@@ -50,7 +50,8 @@ class wizard_update_module(wizard.interface):
return {'update': update, 'add': add}
def _action_module_open(self, cr, uid, data, context):
return {
res = {
'domain': str([]),
'name': 'Module List',
'view_type': 'form',
@@ -59,8 +60,11 @@ class wizard_update_module(wizard.interface):
'view_id': False,
'type': 'ir.actions.act_window'
}
search_view_id = pooler.get_pool(cr.dbname).get('ir.ui.view').search(cr, uid, [('name','=','ir.module.module.list.select')], context=context)
if search_view_id:
res.update({'search_view_id' : search_view_id[0]})
return res
states = {
'init': {
+30 -6
View File
@@ -63,6 +63,7 @@ class ir_property(osv.osv):
'type' : fields.selection([('char', 'Char'),
('float', 'Float'),
('boolean', 'Boolean'),
('integer', 'Integer'),
('integer_big', 'Integer Big'),
('text', 'Text'),
@@ -84,10 +85,20 @@ class ir_property(osv.osv):
value = values.pop('value', None)
if not value:
return values
type_ = values.get('type', 'many2one')
prop = None
type_ = values.get('type')
if not type_:
if ids:
prop = self.browse(cr, uid, ids[0])
type_ = prop.type
else:
type_ = self._defaults['type']
type2field = {
'char': 'value_text',
'float': 'value_float',
'boolean' : 'value_integer',
'integer': 'value_integer',
'integer_big': 'value_integer',
'text': 'value_text',
@@ -106,9 +117,9 @@ class ir_property(osv.osv):
elif isinstance(value, (int, long)):
field_id = values.get('fields_id')
if not field_id:
if not ids:
if not prop:
raise ValueError()
field_id = self.browse(cr, uid, ids[0]).fields_id
field_id = prop.fields_id
else:
field_id = self.pool.get('ir.model.fields').browse(cr, uid, field_id)
@@ -137,6 +148,8 @@ class ir_property(osv.osv):
return record.value_text
elif record.type == 'float':
return record.value_float
elif record.type == 'boolean':
return bool(record.value_integer)
elif record.type in ('integer', 'integer_big'):
return record.value_integer
elif record.type == 'binary':
@@ -146,6 +159,8 @@ class ir_property(osv.osv):
elif record.type == 'datetime':
return record.value_datetime
elif record.type == 'date':
if not record.value_datetime:
return False
return time.strftime('%Y-%m-%d', time.strptime(record.value_datetime, '%Y-%m-%d %H:%M:%S'))
return False
@@ -158,18 +173,27 @@ class ir_property(osv.osv):
return self.get_by_id(cr, uid, nid, context=context)
return False
def _get_domain_default(self, cr, uid, prop_name, model, context=None):
domain = self._get_domain(cr, uid, prop_name, model, context=context)
if domain is None:
return None
return ['&', ('res_id', '=', False)] + domain
def _get_domain(self, cr, uid, prop_name, model, context=None):
cr.execute('select id from ir_model_fields where name=%s and model=%s', (prop_name, model))
res = cr.fetchone()
if not res:
return None
company = self.pool.get('res.company')
cid = company._company_default_get(cr, uid, model, res[0],
if 'force_company' in context and context['force_company']:
cid = context['force_company']
else:
company = self.pool.get('res.company')
cid = company._company_default_get(cr, uid, model, res[0],
context=context)
domain = ['&', ('fields_id', '=', res[0]),
'|', ('company_id', '=', cid), ('company_id', '=', False)]
'|', ('company_id', '=', cid), ('company_id', '=', False)]
return domain
ir_property()
+1 -1
View File
@@ -30,7 +30,7 @@
<field name="company_id" select="1" groups="base.group_multi_company"/>
<field colspan="4" name="fields_id" select="1"/>
<field colspan="4" name="type"/>
<group colspan="4" attrs="{'invisible' : [('type', 'not in', ('integer', 'integer_big'))]}">
<group colspan="4" attrs="{'invisible' : [('type', 'not in', ('integer', 'integer_big', 'boolean'))]}">
<field colspan="4" name="value_integer" widget="integer"/>
</group>
<group colspan="4" attrs="{'invisible' : [('type', '!=', 'float')]}">
+4 -1
View File
@@ -159,6 +159,9 @@ class res_partner(osv.osv):
default.update({'name': name+ _(' (copy)'), 'events':[]})
return super(res_partner, self).copy(cr, uid, id, default, context)
def do_share(self, cr, uid, ids, *args):
return True
def _check_ean_key(self, cr, uid, ids):
for partner_o in pooler.get_pool(cr.dbname).get('res.partner').read(cr, uid, ids, ['ean13',]):
thisean=partner_o['ean13']
@@ -275,7 +278,7 @@ class res_partner_address(osv.osv):
_description ='Partner Addresses'
_name = 'res.partner.address'
_columns = {
'partner_id': fields.many2one('res.partner', 'Company Name', ondelete='set null', select=True, help="Keep empty for a private address, not related to partner."),
'partner_id': fields.many2one('res.partner', 'Partner Name', ondelete='set null', select=True, help="Keep empty for a private address, not related to partner."),
'type': fields.selection( [ ('default','Default'),('invoice','Invoice'), ('delivery','Delivery'), ('contact','Contact'), ('other','Other') ],'Address Type', help="Used to select automatically the right address according to the context in sales and purchases documents."),
'function': fields.char('Function', size=64),
'title': fields.selection(_contact_title_get, 'Title', size=32),
+20 -27
View File
@@ -5,7 +5,7 @@
<menuitem id="menu_address_book" name="Address Book" parent="menu_base_partner" sequence="2"/>
<menuitem id="menu_base_config" name="Configuration" parent="menu_base_partner" sequence="9"
<menuitem id="menu_base_config" name="Configuration" parent="menu_base_partner" sequence="11"
groups="group_system"/>
<menuitem id="menu_config_address_book" name="Address Book" parent="menu_base_config" sequence="3"
@@ -27,18 +27,18 @@
<field name="arch" type="xml">
<search string="Search Contact">
<group>
<filter string="Customer" name="customer" icon="terp-crm" domain="[('is_customer_add','=','1')]" />
<filter string="Supplier" name="supplier" icon="terp-crm" domain="[('is_supplier_add','=','1')]" />
<filter string="Customer" name="customer" icon="terp-personal" domain="[('is_customer_add','=','1')]" />
<filter string="Supplier" name="supplier" icon="terp-personal" domain="[('is_supplier_add','=','1')]" />
<separator orientation="vertical"/>
<field name="partner_id" />
<field name="name" />
<field name="country_id" />
</group>
<newline/>
<group expand="1" string="Group By...">
<filter string="Partner" icon="terp-crm" domain="[]" context="{'group_by' : 'partner_id'}" />
<filter string="Country" icon="terp-crm" domain="[]" context="{'group_by' : 'country_id'}" />
<filter string="Type" icon="terp-crm" domain="[]" context="{'group_by' : 'type'}" />
<group expand="0" string="Group By...">
<filter string="Partner" icon="terp-personal" domain="[]" context="{'group_by' : 'partner_id'}" />
<filter string="Country" icon="terp-go-home" domain="[]" context="{'group_by' : 'country_id'}" />
<filter string="Type" icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'type'}" />
</group>
</search>
</field>
@@ -259,7 +259,7 @@
<group colspan="1" col="2">
<field name="customer" select="1"/>
<field name="supplier"/>
<field name="employee"/>
<!-- <field name="employee"/>-->
</group>
</group>
<notebook colspan="4">
@@ -317,9 +317,9 @@
<page string="Notes">
<field colspan="4" name="comment" nolabel="1"/>
</page>
<page string="History">
<field colspan="4" name="events" nolabel="1" widget="one2many_list" string="Event Logs"/>
</page>
<!-- <page string="History">-->
<!-- <field colspan="4" name="events" nolabel="1" widget="one2many_list" string="Event Logs"/>-->
<!-- </page>-->
</notebook>
</form>
@@ -333,20 +333,20 @@
<field name="arch" type="xml">
<search string="Search Partner">
<group col='10' colspan='4'>
<filter string="Customers" icon="terp-partner" domain="[('customer','=',1)]" help="Customer Partners"/>
<filter string="Suppliers" icon="terp-partner" domain="[('supplier','=',1)]" help="Supplier Partners"/>
<filter string="Customers" name="customer" icon="terp-personal" domain="[('customer','=',1)]" help="Customer Partners"/>
<filter string="Suppliers" name="supplier" icon="terp-personal" domain="[('supplier','=',1)]" help="Supplier Partners"/>
<separator orientation="vertical"/>
<field name="name" select="1"/>
<field name="address" select="1"/>
<field name="country" select="1"/>
<field name="category_id" select="1"/>
<field name="user_id" select="1">
<filter string="My Partners" icon="terp-partner" domain="[('user_id','=',uid)]"/>
<filter string="My Partners" icon="terp-personal+" domain="[('user_id','=',uid)]"/>
</field>
</group>
<newline />
<group expand="1" string="Group By...">
<filter string="Salesman" icon="terp-crm" domain="[]" context="{'group_by' : 'user_id'}" />
<group expand="0" string="Group By...">
<filter string="Salesman" icon="terp-personal" domain="[]" context="{'group_by' : 'user_id'}" />
</group>
</search>
</field>
@@ -357,7 +357,7 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner</field>
<field name="view_type">form</field>
<field name="context">{"search_default_supplier":supplier}</field>
<field name="context">{"search_default_customer":1}</field>
<field name="search_view_id" ref="view_res_partner_filter"/>
</record>
<record id="action_partner_form_view1" model="ir.actions.act_window.view">
@@ -384,7 +384,7 @@
<field name="res_model">res.partner</field>
<field name="view_type">form</field>
<field name="domain">[('customer','=',1)]</field>
<field name="context">{'default_customer':1}</field>
<field name="context">{'default_customer':1, 'search_default_customer':1}</field>
<field name="filter" eval="True"/>
</record>
@@ -417,15 +417,6 @@
<field name="filter" eval="True"/>
</record>
<record id="action_partner_customer_form_new" model="ir.actions.act_window">
<field name="name">New Partner</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner</field>
<field name="view_type">form</field>
<field name="view_mode">form,tree</field>
<field name="view_id" ref="view_partner_form"/>
</record>
<record id="view_payterm_form" model="ir.ui.view">
<field name="name">res.payterm</field>
<field name="model">res.payterm</field>
@@ -549,6 +540,7 @@
</tree>
</field>
</record>
<!--
<record id="action_partner_category" model="ir.actions.act_window">
<field name="name">Partners by Categories</field>
<field name="type">ir.actions.act_window</field>
@@ -559,6 +551,7 @@
</record>
<menuitem action="action_partner_category" id="menu_partner_category_main" parent="base.menu_address_book" sequence="1"
groups="base.group_extended"/>
-->
<record id="action_partner_by_category" model="ir.actions.act_window">
<field name="name">Partner Categories</field>
+12 -5
View File
@@ -24,6 +24,7 @@ from osv import fields
import os
import tools
from tools.translate import _
from tools.safe_eval import safe_eval as eval
class multi_company_default(osv.osv):
"""
@@ -91,11 +92,18 @@ class res_company(osv.osv):
def search(self, cr, uid, args, offset=0, limit=None, order=None,
context=None, count=False):
user_preference = context and context.get('user_preference', False) or False
if context is None:
context = {}
user_preference = context.get('user_preference', False)
if user_preference:
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
cmp_ids = list(set([user.company_id.id] + [cmp.id for cmp in user.company_ids]))
# TODO: improve this as soon as the client sends the proper
# combination of active_id and active_model we'll be able to
# use active_id here to restrict to the user being modified instead
# of current user.
user_id = context.get('user_id', uid)
user = self.pool.get('res.users').browse(cr, uid, user_id, context=context)
cmp_ids = list(set([user.company_id.id] + [cmp.id for cmp in user.company_ids]))
return cmp_ids
return super(res_company, self).search(cr, uid, args, offset=offset, limit=limit, order=order,
context=context, count=count)
@@ -125,12 +133,12 @@ class res_company(osv.osv):
ids = self._get_company_children(cr, uid, company)
return ids
@tools.cache()
def _get_company_children(self, cr, uid=None, company=None):
if not company:
return []
ids = self.search(cr, uid, [('parent_id','child_of',[company])])
return ids
_get_company_children = tools.cache()(_get_company_children)
def _get_partner_hierarchy(self, cr, uid, company_id, context={}):
if company_id:
@@ -160,7 +168,6 @@ class res_company(osv.osv):
def write(self, cr, *args, **argv):
self.cache_restart(cr)
# Restart the cache on the company_get method
return super(res_company, self).write(cr, *args, **argv)
def _get_euro(self, cr, uid, context={}):
+2
View File
@@ -390,6 +390,8 @@ class res_config_installer(osv.osv_memory):
cr, uid, fields, context, read_access)
for module in self._already_installed(cr, uid, context=context):
if module.name not in fields:
continue
fields[module.name].update(
readonly=True,
help=fields[module.name].get('help', '') +
+1
View File
@@ -22,6 +22,7 @@
from osv import fields, osv
from locale import localeconv
import tools
from tools.safe_eval import safe_eval as eval
class lang(osv.osv):
_name = "res.lang"
+1 -1
View File
@@ -7,7 +7,7 @@
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Logs">
<filter icon="terp-sale" string="My Logs" domain="[('user_id','=',uid)]" name="my"/>
<filter icon="terp-stock_align_left_24" string="My Logs" domain="[('user_id','=',uid)]" name="my"/>
<separator orientation="vertical"/>
<field name="name"/>
<field name="user_id"/>
-4
View File
@@ -6,10 +6,6 @@
<field name="name">Partner Manager</field>
</record>
<record model="ir.ui.menu" id="menu_base_partner">
<field eval="[(6,0,[ref('group_system'), ref('group_partner_manager')])]" name="groups_id"/>
</record>
<record model="ir.ui.menu" id="menu_base_config">
<field eval="[(6,0,[ref('group_system'), ref('group_partner_manager')])]" name="groups_id"/>
</record>
+27 -17
View File
@@ -20,9 +20,9 @@
##############################################################################
from osv import fields,osv
from osv.orm import except_orm, browse_record
from osv.orm import browse_record
import tools
import operator
from functools import partial
import pytz
import pooler
from tools.translate import _
@@ -55,7 +55,6 @@ class groups(osv.osv):
raise osv.except_osv(_('Error'),
_('The name of the group can not start with "-"'))
res = super(groups, self).write(cr, uid, ids, vals, context=context)
# Restart the cache on the company_get method
self.pool.get('ir.model.access').call_cache_clearing_methods(cr)
return res
@@ -233,8 +232,13 @@ class users(osv.osv):
'menu_id': fields.many2one('ir.actions.actions', 'Menu Action'),
'groups_id': fields.many2many('res.groups', 'res_groups_users_rel', 'uid', 'gid', 'Groups'),
'roles_id': fields.many2many('res.roles', 'res_roles_users_rel', 'uid', 'rid', 'Roles'),
# Special behavior for this field: res.company.search() will only return the companies
# available to the current user (should be the user's companies?), when the user_preference
# context is set.
'company_id': fields.many2one('res.company', 'Company', required=True,
help="The company this user is currently working for."),
help="The company this user is currently working for.", context={'user_preference': True}),
'company_ids':fields.many2many('res.company','res_company_users_rel','user_id','cid','Companies'),
'context_lang': fields.selection(_lang_get, 'Language', required=True,
help="Sets the language for the user's user interface, when UI "
@@ -277,7 +281,7 @@ class users(osv.osv):
return all(((this.company_id in this.company_ids) or not this.company_ids) for this in self.browse(cr, uid, ids, context))
_constraints = [
(_check_company, 'The chosen company is not in the allowed companies', ['company_id', 'company_ids']),
(_check_company, 'The chosen company is not in the allowed companies for this user', ['company_id', 'company_ids']),
]
_sql_constraints = [
@@ -327,22 +331,28 @@ class users(osv.osv):
'groups_id': _get_group,
'address_id': False,
}
def company_get(self, cr, uid, uid2, context={}):
return self._get_company(cr, uid, context=context, uid2=uid2)
company_get = tools.cache()(company_get)
def write(self, cr, uid, ids, values, *args, **argv):
if (ids == [uid]):
ok = True
for k in values.keys():
if k not in ('password','signature','action_id', 'context_lang', 'context_tz','company_id'):
ok=False
if ok:
@tools.cache()
def company_get(self, cr, uid, uid2, context=None):
return self._get_company(cr, uid, context=context, uid2=uid2)
def write(self, cr, uid, ids, values, context=None):
if not hasattr(ids, '__iter__'):
ids = [ids]
if ids == [uid]:
for key in values.keys():
if not (key in ('view', 'password','signature','action_id', 'company_id') or key.startswith('context_')):
break
else:
uid = 1
res = super(users, self).write(cr, uid, ids, values, *args, **argv)
res = super(users, self).write(cr, uid, ids, values, context=context)
# clear caches linked to the users
self.company_get.clear_cache(cr.dbname)
# Restart the cache on the company_get method
self.pool.get('ir.model.access').call_cache_clearing_methods(cr)
clear = partial(self.pool.get('ir.rule').clear_cache, cr)
map(clear, ids)
return res
def unlink(self, cr, uid, ids, context=None):
+3 -4
View File
@@ -6,11 +6,11 @@
Users Groups
-->
<record model="res.groups" id="group_system">
<field name="name">Administrator / Configuration</field>
<field name="name">Administration / Configuration</field>
</record>
<record model="res.groups" id="group_erp_manager">
<field name="name">Administrator / Access Rights</field>
<field name="name">Administration / Access Rights</field>
</record>
<record model="res.groups" id="group_user">
@@ -18,7 +18,7 @@
</record>
<record model="res.groups" context="{'noadmin':True}" id="group_multi_company">
<field name="name">Multi Companies</field>
<field name="name">Useability / Multi Companies</field>
</record>
<record model="res.groups" context="{'noadmin':True}" id="group_extended">
@@ -51,7 +51,6 @@
</record>
<record id="base.menu_translation" model="ir.ui.menu">
<!-- FIXME: a "Usability / Translations" group ?? -->
<field eval="[(6,0,[ref('base.group_system')])]" name="groups_id"/>
</record>
+27 -20
View File
@@ -1,10 +1,11 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_ir_attachment_group_system","ir_attachment group_system","model_ir_attachment",,1,1,1,1
"access_ir_attachment_all","ir_attachment all","model_ir_attachment",,1,0,0,0
"access_ir_attachment_group_user","ir_attachment group_user","model_ir_attachment",group_user,1,1,1,1
"access_ir_cron_group_cron","ir_cron group_cron","model_ir_cron","group_system",1,1,1,1
"access_ir_cron_user","ir_cron user","model_ir_cron","group_user",1,0,0,0
"access_ir_default_group_system","ir_default group_system","model_ir_default",,1,1,1,1
"access_ir_exports_group_system","ir_exports group_system","model_ir_exports",,1,1,1,1
"access_ir_exports_line_group_system","ir_exports_line group_system","model_ir_exports_line",,1,1,1,1
"access_ir_exports_group_system","ir_exports group_system","model_ir_exports",base.group_user,1,1,1,1
"access_ir_exports_line_group_system","ir_exports_line group_system","model_ir_exports_line",base.group_user,1,1,1,1
"access_ir_model_group_erp_manager","ir_model group_erp_manager","model_ir_model","group_erp_manager",1,1,1,1
"access_ir_model_access_group_erp_manager","ir_model_access_group_erp_manager","model_ir_model_access","group_erp_manager",1,1,1,1
"access_ir_model_grid_group_erp_manager","ir_model_access_grid_group_erp_manager","model_ir_model_grid","group_erp_manager",1,1,1,1
@@ -24,10 +25,11 @@
"access_ir_report_custom_fields_group_system","ir_report_custom_fields group_system","model_ir_report_custom_fields",,1,0,0,0
"access_ir_rule_group_user","ir_rule group_user","model_ir_rule",,1,0,0,0
"access_ir_rule_group_erp_manager","ir_rule group_erp_manager","model_ir_rule","group_erp_manager",1,1,1,1
"access_ir_sequence_group_user","ir_sequence group_user","model_ir_sequence",,1,1,1,1
"access_ir_sequence_group_user","ir_sequence group_user","model_ir_sequence",,1,0,0,0
"access_ir_sequence_type_group_user","ir_sequence_type group_user","model_ir_sequence_type",,1,0,0,0
"access_ir_translation_group_system","ir_translation group_system","model_ir_translation",,1,1,1,1
"access_ir_ui_menu_group_user","ir_ui_menu group_user","model_ir_ui_menu",,1,0,1,0
"access_ir_translation_all","ir_translation all","model_ir_translation",,1,0,0,0
"access_ir_translation_group_system","ir_translation group_system","model_ir_translation","group_system",1,1,1,1
"access_ir_ui_menu_group_user","ir_ui_menu group_user","model_ir_ui_menu",,1,0,0,0
"access_ir_ui_menu_group_system","ir_ui_menu group_system","model_ir_ui_menu","group_system",1,1,1,1
"access_ir_ui_view_group_user","ir_ui_view group_user","model_ir_ui_view",,1,0,0,0
"access_ir_ui_view_group_system","ir_ui_view group_system","model_ir_ui_view","group_system",1,1,1,1
@@ -41,8 +43,8 @@
"access_wizard_module_lang_export_group_system","wizard_module_lang_export group_system","model_wizard_module_lang_export","group_system",1,1,1,1
"access_res_company_group_erp_manager","res_company group_erp_manager","model_res_company","group_erp_manager",1,1,1,1
"access_res_company_group_user","res_company group_user","model_res_company",,1,0,0,0
"access_res_config_all","res_config all","model_res_config",,1,0,0,0
"access_res_config_users_all","res_config_users all","model_res_config_users",,1,0,0,0
"access_res_config_all","res_config all","model_res_config",group_system,1,1,1,1
"access_res_config_users_all","res_config_users all","model_res_config_users",group_system,1,1,1,1
"access_res_country_group_all","res_country group_user_all","model_res_country",,1,0,0,0
"access_res_country_state_group_all","res_country_state group_user_all","model_res_country_state",,1,0,0,0
"access_res_country_group_user","res_country group_user","model_res_country","group_partner_manager",1,1,1,1
@@ -69,21 +71,23 @@
"access_res_partner_canal_group_partner_manager","res_partner_canal group_partner_manager","model_res_partner_canal","group_partner_manager",1,1,1,1
"access_res_partner_category_group_user","res_partner_category group_user","model_res_partner_category","group_user",1,0,0,0
"access_res_partner_category_group_partner_manager","res_partner_category group_partner_manager","model_res_partner_category","group_partner_manager",1,1,1,1
"access_res_partner_event_group_user","res_partner_event group_user","model_res_partner_event","group_user",1,1,1,1
"access_res_partner_event_group_user","res_partner_event group_user","model_res_partner_event","group_user",1,0,0,0
"access_res_partner_event_group_partner_manager","res_partner_event group_partner_manager","model_res_partner_event","group_partner_manager",1,1,1,1
"access_res_partner_som_group_user","res_partner_som group_user","model_res_partner_som","group_partner_manager",1,1,1,1
"access_res_partner_som_group_partner_manager","res_partner_som group_partner_manager","model_res_partner_som","group_user",1,0,0,0
"access_res_partner_title_group_user","res_partner_title group_user","model_res_partner_title","group_partner_manager",1,1,1,1
"access_res_partner_title_group_partner_manager","res_partner_title group_partner_manager","model_res_partner_title","group_user",1,0,0,0
"access_res_request_group_user","res_request group_user","model_res_request",,1,1,1,1
"access_res_request_history_group_user","res_request_history group_user","model_res_request_history",,1,1,1,1
"access_res_partner_title_group_partner_manager","res_partner_title group_partner_manager","model_res_partner_title",,1,0,0,0
"access_res_request_group_user","res_request group_user","model_res_request",base.group_user,1,1,1,1
"access_res_request_history_group_user","res_request_history group_user","model_res_request_history",base.group_user,1,1,1,1
"access_res_request_group_user_all","res_request group_user all","model_res_request",,1,0,0,0
"access_res_request_history_group_user_all","res_request_history group_user all","model_res_request_history",,1,0,0,0
"access_res_request_link_group_system","res_request_link group_system","model_res_request_link","group_system",1,1,1,1
"access_res_request_link_group_user","res_request_link group_user","model_res_request_link",,1,0,0,0
"access_res_users_all","res_users all","model_res_users",,1,0,0,0
"access_res_users_group_erp_manager","res_users group_erp_manager","model_res_users","group_erp_manager",1,1,1,1
"access_ir_actions_all","ir_actions_all","model_ir_actions_actions",,1,0,0,0
"access_ir_actions_group_system","ir_actions_group_system","model_ir_actions_actions","group_system",1,1,1,1
"access_ir_actions_act_window_all","ir_actions_act_window_all","model_ir_actions_act_window",,1,0,1,0
"access_ir_actions_act_window_all","ir_actions_act_window_all","model_ir_actions_act_window",,1,0,0,0
"access_ir_actions_act_window_system","ir_actions_act_window_system","model_ir_actions_act_window","group_system",1,1,1,1
"access_ir_actions_act_window_close_all","ir_actions_act_window_close_all","model_ir_actions_act_window_close",,1,0,0,0
"access_ir_actions_act_window_close_group_system","ir_actions_act_window_close_group_system","model_ir_actions_act_window_close","group_system",1,1,1,1
@@ -97,7 +101,7 @@
"access_workflow_group_system","workflow_group_system","model_workflow","group_system",1,1,1,1
"access_workflow_activity_all","workflow_activity_all","model_workflow_activity",,1,0,0,0
"access_workflow_activity_group_system","workflow_activity_group_system","model_workflow_activity","group_system",1,1,1,1
"access_workflow_instance_all","workflow_instance_all","model_workflow_instance",,1,1,1,1
"access_workflow_instance_all","workflow_instance_all","model_workflow_instance",,1,0,0,0
"access_workflow_transition_all","workflow_transition_all","model_workflow_transition",,1,0,0,0
"access_workflow_transition_group_system","workflow_transition_group_system","model_workflow_transition","group_system",1,1,1,1
"access_workflow_triggers_all","workflow_triggers_all","model_workflow_triggers",,1,0,0,0
@@ -117,13 +121,16 @@
"access_res_bank_group_system","res_bank_group_system","model_res_bank","group_system",1,1,1,1
"access_res_payterm_group_system","res_payterm_group_system","model_res_payterm","group_system",1,1,1,1
"access_res_roles_group_erpmanager","res_roles_group_erp_manager","model_res_roles","group_erp_manager",1,1,1,1
"access_res_config_view_group_erpmanager","res_config_view_erp_manager","model_res_config_view","group_erp_manager",1,1,1,1
"access_res_config_view_group_erpmanager","res_config_view_erp_manager","model_res_config_view","group_system",1,1,1,1
"access_res_roles_all","res_roles_all","model_res_roles",,1,0,0,0
"access_res_config_view_all","res_config_view_all","model_res_config_view",,1,0,0,0
"access_res_config_view_all","res_config_view_all","model_res_config_view",group_system,1,0,0,0
"access_res_bank_group_partner_manager","res_bank_group_partner_manager","model_res_bank","group_partner_manager",1,1,1,1
"access_res_bank_user","res_bank user","model_res_bank","group_user",1,0,0,0
"access_maintenance_group_user","maintenance_contract group_user","model_maintenance_contract","group_maintenance_manager",1,1,1,1
"access_maintenance_contract_module","maintenance.contract.module","model_maintenance_contract_module","group_maintenance_manager",1,1,1,1
"access_maintenance_contract_wizard","maintenance.contract.wizard","model_maintenance_contract_wizard","group_maintenance_manager",1,1,1,1
"access_multi_company_default user","multi_company_default User","model_multi_company_default","group_user",1,0,0,0
"access_maintenance_group_user","maintenance_contract group_user","model_maintenance_contract","group_system",1,1,1,1
"access_maintenance_contract_module","maintenance.contract.module","model_maintenance_contract_module","group_system",1,1,1,1
"access_maintenance_contract_wizard","maintenance.contract.wizard","model_maintenance_contract_wizard","group_system",1,1,1,1
"access_multi_company_default user","multi_company_default all","model_multi_company_default",,1,0,0,0
"access_multi_company_default manager","multi_company_default Manager","model_multi_company_default","group_erp_manager",1,1,1,1
"access_ir_filter all","ir_filters all","model_ir_filters",,1,0,0,0
"access_ir_filter employee","ir_filters employee","model_ir_filters","group_user",1,1,1,1
"access_res_log all","res_log all","model_res_log",,1,0,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_ir_attachment_group_system access_ir_attachment_all ir_attachment group_system ir_attachment all model_ir_attachment 1 1 0 1 0 1 0
3 access_ir_attachment_group_user ir_attachment group_user model_ir_attachment group_user 1 1 1 1
4 access_ir_cron_group_cron ir_cron group_cron model_ir_cron group_system 1 1 1 1
5 access_ir_cron_user ir_cron user model_ir_cron group_user 1 0 0 0
6 access_ir_default_group_system ir_default group_system model_ir_default 1 1 1 1
7 access_ir_exports_group_system ir_exports group_system model_ir_exports base.group_user 1 1 1 1
8 access_ir_exports_line_group_system ir_exports_line group_system model_ir_exports_line base.group_user 1 1 1 1
9 access_ir_model_group_erp_manager ir_model group_erp_manager model_ir_model group_erp_manager 1 1 1 1
10 access_ir_model_access_group_erp_manager ir_model_access_group_erp_manager model_ir_model_access group_erp_manager 1 1 1 1
11 access_ir_model_grid_group_erp_manager ir_model_access_grid_group_erp_manager model_ir_model_grid group_erp_manager 1 1 1 1
25 access_ir_report_custom_fields_group_system ir_report_custom_fields group_system model_ir_report_custom_fields 1 0 0 0
26 access_ir_rule_group_user ir_rule group_user model_ir_rule 1 0 0 0
27 access_ir_rule_group_erp_manager ir_rule group_erp_manager model_ir_rule group_erp_manager 1 1 1 1
28 access_ir_sequence_group_user ir_sequence group_user model_ir_sequence 1 1 0 1 0 1 0
29 access_ir_sequence_type_group_user ir_sequence_type group_user model_ir_sequence_type 1 0 0 0
30 access_ir_translation_group_system access_ir_translation_all ir_translation group_system ir_translation all model_ir_translation 1 1 0 1 0 1 0
31 access_ir_ui_menu_group_user access_ir_translation_group_system ir_ui_menu group_user ir_translation group_system model_ir_ui_menu model_ir_translation group_system 1 0 1 1 0 1
32 access_ir_ui_menu_group_user ir_ui_menu group_user model_ir_ui_menu 1 0 0 0
33 access_ir_ui_menu_group_system ir_ui_menu group_system model_ir_ui_menu group_system 1 1 1 1
34 access_ir_ui_view_group_user ir_ui_view group_user model_ir_ui_view 1 0 0 0
35 access_ir_ui_view_group_system ir_ui_view group_system model_ir_ui_view group_system 1 1 1 1
43 access_wizard_module_lang_export_group_system wizard_module_lang_export group_system model_wizard_module_lang_export group_system 1 1 1 1
44 access_res_company_group_erp_manager res_company group_erp_manager model_res_company group_erp_manager 1 1 1 1
45 access_res_company_group_user res_company group_user model_res_company 1 0 0 0
46 access_res_config_all res_config all model_res_config group_system 1 0 1 0 1 0 1
47 access_res_config_users_all res_config_users all model_res_config_users group_system 1 0 1 0 1 0 1
48 access_res_country_group_all res_country group_user_all model_res_country 1 0 0 0
49 access_res_country_state_group_all res_country_state group_user_all model_res_country_state 1 0 0 0
50 access_res_country_group_user res_country group_user model_res_country group_partner_manager 1 1 1 1
71 access_res_partner_canal_group_partner_manager res_partner_canal group_partner_manager model_res_partner_canal group_partner_manager 1 1 1 1
72 access_res_partner_category_group_user res_partner_category group_user model_res_partner_category group_user 1 0 0 0
73 access_res_partner_category_group_partner_manager res_partner_category group_partner_manager model_res_partner_category group_partner_manager 1 1 1 1
74 access_res_partner_event_group_user res_partner_event group_user model_res_partner_event group_user 1 1 0 1 0 1 0
75 access_res_partner_event_group_partner_manager res_partner_event group_partner_manager model_res_partner_event group_partner_manager 1 1 1 1
76 access_res_partner_som_group_user res_partner_som group_user model_res_partner_som group_partner_manager 1 1 1 1
77 access_res_partner_som_group_partner_manager res_partner_som group_partner_manager model_res_partner_som group_user 1 0 0 0
78 access_res_partner_title_group_user res_partner_title group_user model_res_partner_title group_partner_manager 1 1 1 1
79 access_res_partner_title_group_partner_manager res_partner_title group_partner_manager model_res_partner_title group_user 1 0 0 0
80 access_res_request_group_user res_request group_user model_res_request base.group_user 1 1 1 1
81 access_res_request_history_group_user res_request_history group_user model_res_request_history base.group_user 1 1 1 1
82 access_res_request_group_user_all res_request group_user all model_res_request 1 0 0 0
83 access_res_request_history_group_user_all res_request_history group_user all model_res_request_history 1 0 0 0
84 access_res_request_link_group_system res_request_link group_system model_res_request_link group_system 1 1 1 1
85 access_res_request_link_group_user res_request_link group_user model_res_request_link 1 0 0 0
86 access_res_users_all res_users all model_res_users 1 0 0 0
87 access_res_users_group_erp_manager res_users group_erp_manager model_res_users group_erp_manager 1 1 1 1
88 access_ir_actions_all ir_actions_all model_ir_actions_actions 1 0 0 0
89 access_ir_actions_group_system ir_actions_group_system model_ir_actions_actions group_system 1 1 1 1
90 access_ir_actions_act_window_all ir_actions_act_window_all model_ir_actions_act_window 1 0 1 0 0
91 access_ir_actions_act_window_system ir_actions_act_window_system model_ir_actions_act_window group_system 1 1 1 1
92 access_ir_actions_act_window_close_all ir_actions_act_window_close_all model_ir_actions_act_window_close 1 0 0 0
93 access_ir_actions_act_window_close_group_system ir_actions_act_window_close_group_system model_ir_actions_act_window_close group_system 1 1 1 1
101 access_workflow_group_system workflow_group_system model_workflow group_system 1 1 1 1
102 access_workflow_activity_all workflow_activity_all model_workflow_activity 1 0 0 0
103 access_workflow_activity_group_system workflow_activity_group_system model_workflow_activity group_system 1 1 1 1
104 access_workflow_instance_all workflow_instance_all model_workflow_instance 1 1 0 1 0 1 0
105 access_workflow_transition_all workflow_transition_all model_workflow_transition 1 0 0 0
106 access_workflow_transition_group_system workflow_transition_group_system model_workflow_transition group_system 1 1 1 1
107 access_workflow_triggers_all workflow_triggers_all model_workflow_triggers 1 0 0 0
121 access_res_bank_group_system res_bank_group_system model_res_bank group_system 1 1 1 1
122 access_res_payterm_group_system res_payterm_group_system model_res_payterm group_system 1 1 1 1
123 access_res_roles_group_erpmanager res_roles_group_erp_manager model_res_roles group_erp_manager 1 1 1 1
124 access_res_config_view_group_erpmanager res_config_view_erp_manager model_res_config_view group_erp_manager group_system 1 1 1 1
125 access_res_roles_all res_roles_all model_res_roles 1 0 0 0
126 access_res_config_view_all res_config_view_all model_res_config_view group_system 1 0 0 0
127 access_res_bank_group_partner_manager res_bank_group_partner_manager model_res_bank group_partner_manager 1 1 1 1
128 access_res_bank_user res_bank user model_res_bank group_user 1 0 0 0
129 access_maintenance_group_user maintenance_contract group_user model_maintenance_contract group_maintenance_manager group_system 1 1 1 1
130 access_maintenance_contract_module maintenance.contract.module model_maintenance_contract_module group_maintenance_manager group_system 1 1 1 1
131 access_maintenance_contract_wizard maintenance.contract.wizard model_maintenance_contract_wizard group_maintenance_manager group_system 1 1 1 1
132 access_multi_company_default user multi_company_default User multi_company_default all model_multi_company_default group_user 1 0 0 0
133 access_multi_company_default manager multi_company_default Manager model_multi_company_default group_erp_manager 1 1 1 1
134 access_ir_filter all ir_filters all model_ir_filters 1 0 0 0
135 access_ir_filter employee ir_filters employee model_ir_filters group_user 1 1 1 1
136 access_res_log all res_log all model_res_log 1 0 1 1
+57
View File
@@ -0,0 +1,57 @@
- |
Safe_Eval Scenario:
In order to check that common dangerous operations are
not allowed by the safe_eval mechanism, attempt to
evaluate some bad expressions, and verify that it triggers
an error.
-
1. Try a few common expressions to verify they work with safe_eval
-
!python {model: ir.model}: |
from tools.safe_eval import safe_eval
expected = (1, {"a": 9 * 2}, (True, False, None))
actual = safe_eval('(1, {"a": 9 * 2}, (True, False, None))')
assert actual == expected, "Simple python expressions are not working with safe_eval"
-
2. Try simple literal definition to verify it works with literal_eval
-
!python {model: ir.model}: |
from tools.safe_eval import literal_eval
expected = (1, {"a": 9}, (True, False, None))
actual = literal_eval('(1, {"a": 9}, (True, False, None))')
assert actual == expected, "Simple python expressions are not working with literal_eval"
-
3. Try arithmetic expression in literal_eval to verify it does not work
-
!python {model: ir.model}: |
from tools.safe_eval import literal_eval
try:
literal_eval('(1, {"a": 2*9}, (True, False, None))')
assert False, "literal_eval should not accept arithmetic expressions"
except ValueError:
pass
-
4. Try forbidden expressions in literal_eval to verify they are not allowed
-
!python {model: ir.model}: |
from tools.safe_eval import literal_eval
try:
literal_eval('{"a": True.__class__}')
assert False, "literal_eval should accept only literals"
except ValueError:
pass
-
5. Try forbidden expressions in safe_eval to verify they are not allowed (open)
-
!python {model: ir.model}: |
from tools.safe_eval import safe_eval
try:
safe_eval('open("/etc/passwd","r")')
assert False, "safe_eval should not allow arbitrary expressions"
except NameError:
pass
except:
# NameError should be raised because open() builtin is not found,
# but other exceptions probably indicate that open() was executed!
assert False, "safe_eval should not allow arbitrary expressions"
+1 -1
View File
@@ -49,7 +49,7 @@ def to_decode(s):
return s
def start_server(root_path, port, netport, addons_path):
os.system('python2.5 %sopenerp-server.py --pidfile=openerp.pid --port=%s --net_port=%s --addons-path=%s' %(root_path, str(port),str(netport),addons_path))
os.system('python2.5 %sopenerp-server.py --pidfile=openerp.pid --no-xmlrpcs --xmlrpc-port=%s --netrpc-port=%s --addons-path=%s' %(root_path, str(port),str(netport),addons_path))
def clean():
if os.path.isfile('openerp.pid'):
ps = open('openerp.pid')
+3
View File
@@ -201,6 +201,9 @@
<rng:optional> <rng:attribute name="target"/> </rng:optional>
<rng:optional> <rng:attribute name="key2"/> </rng:optional>
<rng:optional> <rng:attribute name="groups"/> </rng:optional>
<rng:optional> <rng:attribute name="limit"/> </rng:optional>
<rng:optional> <rng:attribute name="usage"/> </rng:optional>
<rng:optional> <rng:attribute name="auto_refresh"/> </rng:optional>
<rng:empty />
</rng:element>
</rng:define>
+22 -24
View File
@@ -31,6 +31,7 @@
# required
# size
#
from collections import defaultdict
import string
import netsvc
import sys
@@ -245,7 +246,7 @@ class selection(_column):
#
# Values: (0, 0, { fields }) create
# (1, ID, { fields }) modification
# (1, ID, { fields }) update
# (2, ID) remove (delete)
# (3, ID) unlink one (target id or target of relation)
# (4, ID) link
@@ -430,10 +431,10 @@ class one2many(_column):
context.update(self._context)
if not values:
values = {}
res = {}
for id in ids:
res[id] = []
ids2 = obj.pool.get(self._obj).search(cr, user, [(self._fields_id, 'in', ids)], limit=self._limit, context=context)
res = defaultdict(list)
ids2 = obj.pool.get(self._obj).search(cr, user, self._domain + [(self._fields_id, 'in', ids)], limit=self._limit, context=context)
for r in obj.pool.get(self._obj)._read_flat(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'):
res[r[self._fields_id]].append(r['id'])
return res
@@ -479,10 +480,10 @@ class one2many(_column):
#
# Values: (0, 0, { fields }) create
# (1, ID, { fields }) modification
# (2, ID) remove
# (3, ID) unlink
# (4, ID) link
# (1, ID, { fields }) update (write fields to ID)
# (2, ID) remove (calls unlink on ID, that will also delete the relationship because of the ondelete)
# (3, ID) unlink (delete the relationship between the two objects but does not delete ID)
# (4, ID) link (add a relationship)
# (5, ID) unlink all
# (6, ?, ids) set a list of links
#
@@ -491,7 +492,6 @@ class many2many(_column):
_classic_write = False
_prefetch = False
_type = 'many2many'
def __init__(self, obj, rel, id1, id2, string='unknown', limit=None, **args):
_column.__init__(self, string=string, **args)
self._obj = obj
@@ -779,7 +779,7 @@ class related(function):
relation = obj._name
res = {}.fromkeys(ids, False)
objlst = obj.browse(cr, uid, ids, context=context)
objlst = obj.browse(cr, 1, ids, context=context)
for data in objlst:
if not data:
continue
@@ -806,7 +806,7 @@ class related(function):
if self._type=='many2one':
ids = filter(None, res.values())
if ids:
ng = dict(obj.pool.get(self._obj).name_get(cr, uid, ids, context=context))
ng = dict(obj.pool.get(self._obj).name_get(cr, 1, ids, context=context))
for r in res:
if res[r]:
res[r] = (res[r], ng[res[r]])
@@ -874,12 +874,17 @@ class serialized(_column):
class property(function):
def _get_default(self, obj, cr, uid, prop_name, context=None):
from orm import browse_record
prop = obj.pool.get('ir.property')
domain = prop._get_domain(cr, uid, prop_name, obj._name, context)
domain = prop._get_domain_default(cr, uid, prop_name, obj._name, context)
ids = prop.search(cr, uid, domain, order='company_id', context=context)
if not ids:
return False
return prop.get_by_id(cr, uid, ids, context=context)
default_value = prop.get_by_id(cr, uid, ids, context=context)
if isinstance(default_value, browse_record):
return default_value.id
return default_value or False
def _get_by_id(self, obj, cr, uid, prop_name, ids, context=None):
prop = obj.pool.get('ir.property')
@@ -903,7 +908,7 @@ class property(function):
default_val = self._get_default(obj, cr, uid, prop_name, context)
if id_val and id_val != default_val:
if id_val is not default_val:
def_id = self._field_get(cr, uid, obj._name, prop_name)
company = obj.pool.get('res.company')
cid = company._company_default_get(cr, uid, obj._name, def_id,
@@ -924,23 +929,16 @@ class property(function):
def _fnct_read(self, obj, cr, uid, ids, prop_name, obj_dest, context=None):
from orm import browse_record
if context is None:
context = {}
property = obj.pool.get('ir.property')
properties = obj.pool.get('ir.property')
default_val = self._get_default(obj, cr, uid, prop_name, context)
if isinstance(default_val, browse_record):
default_val = default_val.id
else:
default_val = False
nids = self._get_by_id(obj, cr, uid, prop_name, ids, context)
res = {}
for id in ids:
res[id] = default_val
for prop in property.browse(cr, uid, nids):
for prop in properties.browse(cr, uid, nids):
value = prop.get_by_id(context=context)
if isinstance(value, browse_record):
if not value.exists():
+79 -18
View File
@@ -56,7 +56,7 @@ from tools.translate import _
import fields
import tools
from tools.safe_eval import safe_eval as eval
regex_order = re.compile('^(([a-z0-9_]+|"[a-z0-9_]+")( *desc| *asc)?( *, *|))+$', re.I)
@@ -353,8 +353,8 @@ def get_pg_type(f):
f_type = ('int4', 'INTEGER')
else:
f_type = ('varchar', 'VARCHAR(%d)' % f_size)
elif isinstance(f, fields.function) and eval('fields.'+(f._type)) in type_dict:
t = eval('fields.'+(f._type))
elif isinstance(f, fields.function) and eval('fields.'+(f._type),globals()) in type_dict:
t = eval('fields.'+(f._type), globals())
f_type = (type_dict[t], type_dict[t])
elif isinstance(f, fields.function) and f._type == 'float':
if f.digits:
@@ -987,7 +987,7 @@ class orm_template(object):
return (-1, res, 'Line ' + str(counter) +' : ' + msg, '' )
#Raising Uncaught exception
return (-1, res, 'Line ' + str(counter) +' : ' + str(e), '' )
for lang in translate:
context2 = context.copy()
context2['lang'] = lang
@@ -1224,21 +1224,26 @@ class orm_template(object):
attrs = {'views': views}
if node.get('widget') and node.get('widget') == 'selection':
if not check_group(node):
# the field is just invisible. default value must be in the selection
name = node.get('name')
default = self.default_get(cr, user, [name], context=context).get(name)
if default:
attrs['selection'] = relation.name_get(cr, 1, default, context=context)
attrs['selection'] = relation.name_get(cr, 1, [default], context=context)
else:
attrs['selection'] = []
# We can not use the 'string' domain has it is defined according to the record !
else:
# If domain and context are strings, we keep them for client-side, otherwise
# we evaluate them server-side to consider them when generating the list of
# possible values
# TODO: find a way to remove this hack, by allow dynamic domains
dom = []
if column._domain and not isinstance(column._domain, (str, unicode)):
if column._domain and not isinstance(column._domain, basestring):
dom = column._domain
dom += eval(node.get('domain','[]'), {'uid':user, 'time':time})
context.update(eval(node.get('context','{}')))
attrs['selection'] = relation._name_search(cr, user, '', dom, context=context, limit=None, name_get_uid=1)
search_context = dict(context)
if column._context and not isinstance(column._context, basestring):
search_context.update(column._context)
attrs['selection'] = relation._name_search(cr, 1, '', dom, context=search_context, limit=None, name_get_uid=1)
if (node.get('required') and not int(node.get('required'))) or not column.required:
attrs['selection'].append((False,''))
fields[node.get('name')] = attrs
@@ -1951,9 +1956,9 @@ class orm_memory(orm_template):
f = True
for arg in result:
if arg[1] =='=':
val =eval('data[arg[0]]'+'==' +' arg[2]')
val =eval('data[arg[0]]'+'==' +' arg[2]', locals())
elif arg[1] in ['<','>','in','not in','<=','>=','<>']:
val =eval('data[arg[0]]'+arg[1] +' arg[2]')
val =eval('data[arg[0]]'+arg[1] +' arg[2]', locals())
elif arg[1] in ['ilike']:
if str(data[arg[0]]).find(str(arg[2]))!=-1:
val= True
@@ -2103,8 +2108,7 @@ class orm(orm_template):
days = calendar.monthrange(dt.year, dt.month)[1]
d[groupby] = datetime.datetime.strptime(d[groupby][:10],'%Y-%m-%d').strftime('%B %Y')
if not context.get('group_by_no_leaf', False):
d['__domain'] = [(groupby,'>=',alldata[d['id']][groupby] and datetime.datetime.strptime(alldata[d['id']][groupby][:7] + '-01','%Y-%m-%d').strftime('%Y-%m-%d') or False),\
d['__domain'] = [(groupby,'>=',alldata[d['id']][groupby] and datetime.datetime.strptime(alldata[d['id']][groupby][:7] + '-01','%Y-%m-%d').strftime('%Y-%m-%d') or False),\
(groupby,'<=',alldata[d['id']][groupby] and datetime.datetime.strptime(alldata[d['id']][groupby][:7] + '-' + str(days),'%Y-%m-%d').strftime('%Y-%m-%d') or False)] + domain
elif fget[groupby]['type'] == 'many2one':
d[groupby] = d[groupby] and ((type(d[groupby])==type(1)) and d[groupby] or d[groupby][1]) or ''
@@ -2612,6 +2616,7 @@ class orm(orm_template):
fld_def = ((f in self._columns) and self._columns[f]) \
or ((f in self._inherit_fields) and self._inherit_fields[f][2]) \
or False
if isinstance(fld_def, fields.property):
property_obj = self.pool.get('ir.property')
prop_value = property_obj.get(cr, uid, f, self._name, context=context)
@@ -2621,7 +2626,8 @@ class orm(orm_template):
else:
value[f] = prop_value
else:
value[f] = False
if f not in value:
value[f] = False
# get the default values set by the user and override the default
# values defined in the object
@@ -2688,6 +2694,32 @@ class orm(orm_template):
self._inherit_fields = res
self._inherits_reload_src()
def __getattr__(self, name):
"""
Proxies attribute accesses to the `inherits` parent so we can call methods defined on the inherited parent
(though inherits doesn't use Python inheritance).
Handles translating between local ids and remote ids.
Known issue: doesn't work correctly when using python's own super(), don't involve inherit-based inheritance
when you have inherits.
"""
for model, field in self._inherits.iteritems():
proxy = self.pool.get(model)
if hasattr(proxy, name):
attribute = getattr(proxy, name)
if not hasattr(attribute, '__call__'):
return attribute
break
else:
return super(orm, self).__getattr__(name)
def _proxy(cr, uid, ids, *args, **kwargs):
objects = self.browse(cr, uid, ids, kwargs.get('context', None))
lst = [obj[field].id for obj in objects if obj[field]]
return getattr(proxy, name)(cr, uid, lst, *args, **kwargs)
return _proxy
def fields_get(self, cr, user, fields=None, context=None):
"""
Get the description of list of fields
@@ -3068,11 +3100,27 @@ class orm(orm_template):
vals format for relational field type.
+ many2many field : [(6, 0, list of ids)] (example: [(6, 0, [8, 5, 6, 4])])
+ many2many field :
For write operation on a many2many fields a list of tuple is
expected. The folowing tuples are accepted:
(0, 0, { fields }) create
(1, ID, { fields }) update (write fields to ID)
(2, ID) remove (calls unlink on ID, that will also delete the relationship because of the ondelete)
(3, ID) unlink (delete the relationship between the two objects but does not delete ID)
(4, ID) link (add a relationship)
(5, ID) unlink all
(6, 0, list of ids) set a list of links
Example:
[(6, 0, [8, 5, 6, 4])] set the many2many to ids [8, 5, 6, 4]
+ one2many field : [(0, 0, dictionary of values)] (example: [(0, 0, {'field_name':field_value, ...})])
+ many2one field : ID of related record
+ reference field : model name, id (example: 'product.product, 5')
"""
readonly = None
for field in vals.copy():
@@ -3112,9 +3160,10 @@ class orm(orm_template):
ids = [ids]
self._check_concurrency(cr, ids, context)
self.pool.get('ir.model.access').check(cr, user, self._name, 'write', context=context)
result = self._store_get_values(cr, user, ids, vals.keys(), context) or []
# No direct update of parent_left/right
vals.pop('parent_left', None)
vals.pop('parent_right', None)
@@ -3202,7 +3251,6 @@ class orm(orm_template):
if c[0].startswith('default_'):
del rel_context[c[0]]
result = []
for field in upd_todo:
for id in ids:
result += self._columns[field].set(cr, self, id, field, vals[field], user, context=rel_context) or []
@@ -3273,8 +3321,19 @@ class orm(orm_template):
cr.execute('update '+self._table+' set parent_left=parent_left-%s, parent_right=parent_right-%s where parent_left>=%s and parent_left<%s', (pleft-position+distance,pleft-position+distance, pleft+distance, pright+distance))
result += self._store_get_values(cr, user, ids, vals.keys(), context)
result.sort()
done = {}
for order, object, ids, fields in result:
self.pool.get(object)._store_set_values(cr, user, ids, fields, context)
key = (object,tuple(fields))
done.setdefault(key, {})
# avoid to do several times the same computation
todo = []
for id in ids:
if id not in done[key]:
done[key][id] = True
todo.append(id)
self.pool.get(object)._store_set_values(cr, user, todo, fields, context)
wf_service = netsvc.LocalService("workflow")
for id in ids:
@@ -3537,6 +3596,8 @@ class orm(orm_template):
return result2
def _store_set_values(self, cr, uid, ids, fields, context):
if not ids:
return True
field_flag = False
field_dict = {}
if self._log_access:
+1 -1
View File
@@ -132,7 +132,7 @@ class osv_pool(netsvc.Service):
raise except_osv('Access Denied', 'Private methods (such as %s) cannot be called remotely.' % (method,))
res = pool.execute_cr(cr, uid, obj, method, *args, **kw)
if res is None:
self.logger.warning('RPC methods cannot return `None` at the moment!')
self.logger.warning('The method %s of the object %s can not return `None` !', method, obj)
cr.commit()
except Exception:
cr.rollback()
+1
View File
@@ -24,6 +24,7 @@ import time
import netsvc
import tools
from tools.safe_eval import safe_eval as eval
import print_xml
import render
from interface import report_int
+2 -1
View File
@@ -23,6 +23,7 @@ import os,types
from lxml import etree
import netsvc
import tools
from tools.safe_eval import safe_eval
import print_fnc
import copy
from osv.orm import browse_null, browse_record
@@ -111,7 +112,7 @@ class document(object):
#Pinky: Why not this ? eval(expr, browser) ?
# name = browser.name
# data_dict = browser._data[self.get_value(browser, 'id')]
return eval(expr, {}, {'obj': record})
return safe_eval(expr, {}, {'obj': record})
def parse_node(self, node, parent, browser, datas=None):
attrs = self.node_attrs_get(node)
+3 -3
View File
@@ -22,6 +22,7 @@
from report.interface import report_int
import pooler
import tools
from tools.safe_eval import safe_eval as eval
from lxml import etree
from report import render
import locale
@@ -128,8 +129,7 @@ class report_printscreen_list(report_int):
strmax = (pageSize[0]-40) * 2.8346
temp = []
tsum = []
count = len(fields_order)
for i in range(0, count):
for i in range(0, len(fields_order)):
temp.append(0)
tsum.append(0)
ince = -1;
@@ -218,7 +218,7 @@ class report_printscreen_list(report_int):
else:
col.text = '/'
node_line = etree.SubElement(lines, 'row')
for f in range(0, count+1):
for f in range(0, len(fields_order)):
col = etree.SubElement(node_line, 'col', para='group', tree='no')
if tsum[f] != None:
if tsum[f] >= 0.01 :
+2 -1
View File
@@ -34,6 +34,7 @@ import os
from lxml import etree
import base64
from reportlab.platypus.doctemplate import ActionFlowable
from tools.safe_eval import safe_eval as eval
encoding = 'utf-8'
@@ -574,7 +575,7 @@ class _rml_flowable(object):
def _illustration(self, node):
class Illustration(platypus.flowables.Flowable):
def __init__(self, node, localcontext, styles, self2):
self.localcontext = localcontext.copy()
self.localcontext = (localcontext or {}).copy()
self.node = node
self.styles = styles
self.width = utils.unit_get(node.get('width'))
+2 -1
View File
@@ -42,6 +42,7 @@ from lxml import etree
import copy
import locale
import traceback, sys
from tools.safe_eval import safe_eval as eval
_regex = re.compile('\[\[(.+?)\]\]')
@@ -54,7 +55,7 @@ def xml2str(s):
def _child_get(node, self=None, tagname=None):
for n in node:
if self and self.localcontext and n.get('rml_loop'):
oldctx = self.localcontext
oldctx = dict(self.localcontext)
for ctx in eval(n.get('rml_loop'),{}, self.localcontext):
self.localcontext.update(ctx)
+2 -1
View File
@@ -23,6 +23,7 @@ import re
import reportlab
import reportlab.lib.units
from lxml import etree
from tools.safe_eval import safe_eval as eval
_regex = re.compile('\[\[(.+?)\]\]')
@@ -128,4 +129,4 @@ def attr_get(node, attrs, dict={}):
res[key] = unit_get(node.get(key))
return res
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+24 -17
View File
@@ -120,10 +120,6 @@ class BaseHttpDaemon(threading.Thread, netsvc.Server):
self.server = ThreadedHTTPServer((interface, port), handler)
self.server.vdirs = []
self.server.logRequests = True
netsvc.Logger().notifyChannel(
"web-services", netsvc.LOG_INFO,
"starting HTTPS service at %s port %d" %
(interface or '0.0.0.0', port,))
except Exception, e:
netsvc.Logger().notifyChannel(
'httpd', netsvc.LOG_CRITICAL,
@@ -155,6 +151,10 @@ class HttpDaemon(BaseHttpDaemon):
def __init__(self, interface, port):
super(HttpDaemon, self).__init__(interface, port,
handler=MultiHandler2)
netsvc.Logger().notifyChannel(
"web-services", netsvc.LOG_INFO,
"starting HTTP service at %s port %d" %
(interface or '0.0.0.0', port,))
class HttpSDaemon(BaseHttpDaemon):
def __init__(self, interface, port):
@@ -166,19 +166,23 @@ class HttpSDaemon(BaseHttpDaemon):
'httpd-ssl', netsvc.LOG_CRITICAL,
"Can not load the certificate and/or the private key files")
raise
netsvc.Logger().notifyChannel(
"web-services", netsvc.LOG_INFO,
"starting HTTPS service at %s port %d" %
(interface or '0.0.0.0', port,))
httpd = None
httpsd = None
def init_servers():
global httpd, httpsd
if tools.config.get_misc('httpd','enable', True):
httpd = HttpDaemon(tools.config.get_misc('httpd','interface', ''), \
int(tools.config.get_misc('httpd','port', tools.config.get('port',8069))))
if tools.config.get('xmlrpc'):
httpd = HttpDaemon(tools.config.get('xmlrpc_interface', ''),
int(tools.config.get('xmlrpc_port', 8069)))
if tools.config.get_misc('httpsd','enable', False):
httpsd = HttpSDaemon(tools.config.get_misc('httpsd','interface', ''), \
int(tools.config.get_misc('httpsd','port', 8071)))
if tools.config.get('xmlrpcs'):
httpsd = HttpSDaemon(tools.config.get('xmlrpcs_interface', ''),
int(tools.config.get('xmlrpcs_port', 8071)))
def reg_http_service(hts, secure_only = False):
""" Register some handler to httpd.
@@ -226,14 +230,17 @@ class XMLRPCRequestHandler(netsvc.OpenERPDispatcher,FixSendError,SimpleXMLRPCSer
def init_xmlrpc():
if not tools.config.get_misc('xmlrpc','enable', True):
return
reg_http_service(HTTPDir('/xmlrpc/',XMLRPCRequestHandler))
# Example of http file serving:
# reg_http_service(HTTPDir('/test/',HTTPHandler))
netsvc.Logger().notifyChannel("web-services", netsvc.LOG_INFO,
"Registered XML-RPC over HTTP")
if tools.config.get('xmlrpc', False):
# Example of http file serving:
# reg_http_service(HTTPDir('/test/',HTTPHandler))
reg_http_service(HTTPDir('/xmlrpc/', XMLRPCRequestHandler))
netsvc.Logger().notifyChannel("web-services", netsvc.LOG_INFO,
"Registered XML-RPC over HTTP")
if tools.config.get('xmlrpcs', False):
reg_http_service(HTTPDir('/xmlrpc/', XMLRPCRequestHandler, True))
netsvc.Logger().notifyChannel('web-services', netsvc.LOG_INFO,
"Registered XML-RPC over HTTPS")
class OerpAuthProxy(AuthProxy):
""" Require basic authentication..
+27 -18
View File
@@ -23,14 +23,16 @@
"""
import netsvc
import threading
import tools
import os
import logging
import select
import socket
import sys
import threading
import traceback
import netsvc
import tiny_socket
import tools
class TinySocketClientThread(threading.Thread, netsvc.OpenERPDispatcher):
def __init__(self, sock, threads):
@@ -58,27 +60,34 @@ class TinySocketClientThread(threading.Thread, netsvc.OpenERPDispatcher):
self.threads.remove(self)
self.running = False
return False
while self.running:
try:
msg = ts.myreceive()
except:
self.threads.remove(self)
self.running = False
return False
try:
result = self.dispatch(msg[0], msg[1], msg[2:])
ts.mysend(result)
except socket.timeout:
#terminate this channel because other endpoint is gone
break
except netsvc.OpenERPDispatcherException, e:
try:
new_e = Exception(tools.exception_to_unicode(e.exception)) # avoid problems of pickeling
logging.getLogger('web-services').debug("netrpc: rpc-dispatching exception", exc_info=True)
ts.mysend(new_e, exception=True, traceback=e.traceback)
except:
self.running = False
except Exception:
#terminate this channel if we can't properly send back the error
logging.getLogger('web-services').exception("netrpc: cannot deliver exception message to client")
break
except Exception, e:
# this code should not be reachable, therefore we warn
netsvc.Logger().notifyChannel("net-rpc", netsvc.LOG_WARNING, "exception: %s" % str(e))
break
try:
tb = getattr(e, 'traceback', sys.exc_info())
tb_s = "".join(traceback.format_exception(*tb))
logging.getLogger('web-services').debug("netrpc: communication-level exception", exc_info=True)
ts.mysend(e, exception=True, traceback=tb_s)
except Exception, ex:
#terminate this channel if we can't properly send back the error
logging.getLogger('web-services').exception("netrpc: cannot deliver exception message to client")
break
self.threads.remove(self)
self.running = False
@@ -123,7 +132,6 @@ class TinySocketServerThread(threading.Thread,netsvc.Server):
"Netrpc: %d threads" % len(self.threads))
self.socket.close()
except Exception, e:
import logging
logging.getLogger('web-services').warning("Netrpc: closing because of exception %s" % str(e))
self.socket.close()
return False
@@ -152,6 +160,7 @@ netrpcd = None
def init_servers():
global netrpcd
if tools.config.get_misc('netrpcd','enable', True):
netrpcd = TinySocketServerThread(tools.config.get_misc('netrpcd','interface', ''), \
int(tools.config.get_misc('netrpcd','port', tools.config.get('netport', 8070))))
if tools.config.get('netrpc', False):
netrpcd = TinySocketServerThread(
tools.config.get('netrpc_interface', ''),
int(tools.config.get('netrpc_port', 8070)))
+4 -5
View File
@@ -22,12 +22,11 @@
import pooler
import tools
# When rejecting a password, we need to give as little info as possible
# When rejecting a password, hide the traceback
class ExceptionNoTb(Exception):
def __init__(self, msg ):
# self.message = msg # No need in Python 2.6
def __init__(self, msg):
super(ExceptionNoTb, self).__init__(msg)
self.traceback = ('','','')
self.args = (msg, '')
def login(db, login, password):
pool = pooler.get_pool(db)
@@ -38,7 +37,7 @@ def check_super(passwd):
if passwd == tools.config['admin_passwd']:
return True
else:
raise ExceptionNoTb('AccessDenied')
raise ExceptionNoTb('AccessDenied: Invalid super administrator password.')
def check(db, uid, passwd):
pool = pooler.get_pool(db)
+1 -1
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# Copyright P. Christeas <p_christ@hol.gr> 2008,2009
#
# A part of the code comes from the ganeti project: http://www.mail-archive.com/ganeti-devel@googlegroups.com/msg00713.html#
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
+38 -33
View File
@@ -40,10 +40,12 @@ class configmanager(object):
def __init__(self, fname=None):
self.options = {
'email_from':False,
'interface': '', # this will bind the server to all interfaces
'port': 8069,
'netinterface': '',
'netport': 8070,
'xmlrpc_interface': '', # this will bind the server to all interfaces
'xmlrpc_port': 8069,
'netrpc_interface': '',
'netrpc_port': 8070,
'xmlrpcs_interface': '', # this will bind the server to all interfaces
'xmlrpcs_port': 8071,
'db_host': False,
'db_port': False,
'db_name': False,
@@ -53,7 +55,7 @@ class configmanager(object):
'reportgz': False,
'netrpc': True,
'xmlrpc': True,
'soap': False,
'xmlrpcs': True,
'translate_in': None,
'translate_out': None,
'language': None,
@@ -74,7 +76,6 @@ class configmanager(object):
'smtp_password': False,
'stop_after_init': False, # this will stop the server after initialization
'price_accuracy': 2,
'secure' : False,
'syslog' : False,
'log_level': logging.INFO,
'assert_exit_level': logging.ERROR, # level above which a failed assert will be raised
@@ -101,12 +102,30 @@ class configmanager(object):
help="save configuration to ~/.openerp_serverrc")
parser.add_option("--pidfile", dest="pidfile", help="file where the server pid will be stored")
parser.add_option("-n", "--interface", dest="interface", help="specify the TCP IP address")
parser.add_option("-p", "--port", dest="port", help="specify the TCP port", type="int")
parser.add_option("--net_interface", dest="netinterface", help="specify the TCP IP address for netrpc")
parser.add_option("--net_port", dest="netport", help="specify the TCP port for netrpc", type="int")
parser.add_option("--no-netrpc", dest="netrpc", action="store_false", help="disable netrpc")
parser.add_option("--no-xmlrpc", dest="xmlrpc", action="store_false", help="disable xmlrpc")
group = optparse.OptionGroup(parser, "XML-RPC Configuration")
group.add_option("--xmlrpc-interface", dest="xmlrpc_interface", help="specify the TCP IP address for the XML-RPC protocol")
group.add_option("--xmlrpc-port", dest="xmlrpc_port", help="specify the TCP port for the XML-RPC protocol", type="int")
group.add_option("--no-xmlrpc", dest="xmlrpc", action="store_false", help="disable the XML-RPC protocol")
parser.add_option_group(group)
title = "XML-RPC Secure Configuration"
if not self.has_ssl:
title += " (disabled as ssl is unavailable)"
group = optparse.OptionGroup(parser, title)
group.add_option("--xmlrpcs-interface", dest="xmlrpcs_interface", help="specify the TCP IP address for the XML-RPC Secure protocol")
group.add_option("--xmlrpcs-port", dest="xmlrpcs_port", help="specify the TCP port for the XML-RPC Secure protocol", type="int")
group.add_option("--no-xmlrpcs", dest="xmlrpcs", action="store_false", help="disable the XML-RPC Secure protocol")
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)
group = optparse.OptionGroup(parser, "NET-RPC Configuration")
group.add_option("--netrpc-interface", dest="netrpc_interface", help="specify the TCP IP address for the NETRPC protocol")
group.add_option("--netrpc-port", dest="netrpc_port", help="specify the TCP port for the NETRPC protocol", type="int")
group.add_option("--no-netrpc", dest="netrpc", action="store_false", help="disable the NETRPC protocol")
parser.add_option_group(group)
parser.add_option("-i", "--init", dest="init", help="init a module (use \"all\" for all modules)")
parser.add_option("--without-demo", dest="without_demo",
help="load demo data for a module (use \"all\" for all modules)", default=False)
@@ -124,18 +143,6 @@ class configmanager(object):
help="specify the level at which a failed assertion will stop the server. Accepted values: %s" % (self._LOGLEVELS.keys(),))
parser.add_option('--price_accuracy', dest='price_accuracy', default='2', help='deprecated since v6.0, replaced by module decimal_precision')
if self.has_ssl:
group = optparse.OptionGroup(parser, "SSL Configuration")
group.add_option("-S", "--secure", dest="secure",
help="launch server over https instead of http")
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)
# Testing Group
group = optparse.OptionGroup(parser, "Testing Configuration")
group.add_option("--test-disable", action="store_true", dest="test_disable",
@@ -248,15 +255,14 @@ class configmanager(object):
if self.options['pidfile'] in ('None', 'False'):
self.options['pidfile'] = False
keys = ['interface', 'port', 'db_name', 'db_user', 'db_password', 'db_host',
keys = ['xmlrpc_interface', 'xmlrpc_port', 'db_name', 'db_user', 'db_password', 'db_host',
'db_port', 'list_db', 'logfile', 'pidfile', 'smtp_port', 'cache_timeout','smtp_ssl',
'email_from', 'smtp_server', 'smtp_user', 'smtp_password', 'price_accuracy',
'netinterface', 'netport', 'db_maxconn', 'import_partial', 'addons_path',
'netrpc', 'xmlrpc', 'syslog', 'without_demo', 'timezone',]
if self.has_ssl:
keys.extend(['secure_cert_file', 'secure_pkey_file'])
keys.append('secure')
'netrpc_interface', 'netrpc_port', 'db_maxconn', 'import_partial', 'addons_path',
'netrpc', 'xmlrpc', 'syslog', 'without_demo', 'timezone',
'xmlrpcs_interface', 'xmlrpcs_port', 'xmlrpcs',
'secure_cert_file', 'secure_pkey_file'
]
for arg in keys:
if getattr(opt, arg):
@@ -266,8 +272,7 @@ class configmanager(object):
'stop_after_init', 'logrotate', 'without_demo', 'netrpc', 'xmlrpc', 'syslog',
'list_db', 'server_actions_allow_code']
if self.has_ssl and not self.options['secure']:
keys.append('secure')
keys.append('xmlrpcs')
for arg in keys:
if getattr(opt, arg) is not None:
+25 -18
View File
@@ -37,6 +37,12 @@ import pooler
from config import config
from yaml_import import convert_yaml_import
# Import of XML records requires the unsafe eval as well,
# almost everywhere, which is ok because it supposedly comes
# from trusted data, but at least we make it obvious now.
unsafe_eval = eval
from tools.safe_eval import safe_eval as eval
class ConvertError(Exception):
def __init__(self, doc, orig_excpt):
self.d = doc
@@ -62,7 +68,7 @@ def _eval_xml(self,node, pool, cr, uid, idref, context=None):
f_search = node.get("search",'').encode('utf-8')
f_use = node.get("use",'id').encode('ascii')
f_name = node.get("name",'').encode('utf-8')
q = eval(f_search, idref)
q = unsafe_eval(f_search, idref)
ids = pool.get(f_model).search(cr, uid, q)
if f_use != 'id':
ids = map(lambda x: x[f_use], pool.get(f_model).read(cr, uid, ids, [f_use]))
@@ -96,10 +102,10 @@ def _eval_xml(self,node, pool, cr, uid, idref, context=None):
pytz=pytzclass()
idref2['pytz'] = pytz
try:
return eval(a_eval, idref2)
except:
logger = netsvc.Logger()
logger.notifyChannel("init", netsvc.LOG_WARNING, 'could eval(%s) for %s in %s, please get back and fix it!' % (a_eval,node.get('name'),context))
return unsafe_eval(a_eval, idref2)
except Exception, e:
logger = logging.getLogger('init')
logger.warning('couldn\'t eval(%s) for %s in %s, please get back and fix it!' % (a_eval,node.get('name'),context), exc_info=True)
return ""
if t == 'xml':
def _process(s, idref):
@@ -144,7 +150,7 @@ def _eval_xml(self,node, pool, cr, uid, idref, context=None):
a_eval = node.get('eval','')
if a_eval:
idref['ref'] = lambda x: self.id_get(cr, False, x)
args = eval(a_eval, idref)
args = unsafe_eval(a_eval, idref)
for n in node:
return_val = _eval_xml(self,n, pool, cr, uid, idref, context)
if return_val is not None:
@@ -205,13 +211,13 @@ class xml_import(object):
def get_context(self, data_node, node, eval_dict):
data_node_context = (len(data_node) and data_node.get('context','').encode('utf8'))
if data_node_context:
context = eval(data_node_context, eval_dict)
context = unsafe_eval(data_node_context, eval_dict)
else:
context = {}
node_context = node.get("context",'').encode('utf8')
if node_context:
context.update(eval(node_context, eval_dict))
context.update(unsafe_eval(node_context, eval_dict))
return context
@@ -241,7 +247,7 @@ form: module.record_id""" % (xml_id,)
d_id = rec.get("id",'')
ids = []
if d_search:
ids = self.pool.get(d_model).search(cr,self.uid,eval(d_search))
ids = self.pool.get(d_model).search(cr, self.uid, unsafe_eval(d_search))
if d_id:
try:
ids.append(self.id_get(cr, d_model, d_id))
@@ -403,7 +409,8 @@ form: module.record_id""" % (xml_id,)
def ref(str_id):
return self.id_get(cr, None, str_id)
context = eval(context)
context = unsafe_eval(context)
# domain = eval(domain) # XXX need to test this line -> uid, active_id, active_ids, ...
res = {
@@ -623,7 +630,7 @@ form: module.record_id""" % (xml_id,)
if rec_id:
ids = [self.id_get(cr, rec_model, rec_id)]
elif rec_src:
q = eval(rec_src, eval_dict)
q = unsafe_eval(rec_src, eval_dict)
ids = self.pool.get(rec_model).search(cr, uid, q, context=context)
if rec_src_count:
count = int(rec_src_count)
@@ -651,14 +658,14 @@ form: module.record_id""" % (xml_id,)
if key in brrec:
return brrec[key]
return dict.__getitem__(self2, key)
globals = d()
globals['floatEqual'] = self._assert_equals
globals['ref'] = ref
globals['_ref'] = ref
globals_dict = d()
globals_dict['floatEqual'] = self._assert_equals
globals_dict['ref'] = ref
globals_dict['_ref'] = ref
for test in rec.findall('./test'):
f_expr = test.get("expr",'').encode('utf-8')
expected_value = _eval_xml(self, test, self.pool, cr, uid, self.idref, context=context) or True
expression_value = eval(f_expr, globals)
expression_value = unsafe_eval(f_expr, globals_dict)
if expression_value != expected_value: # assertion failed
self.assert_report.record_assertion(False, severity)
msg = 'assertion "%s" failed!\n' \
@@ -682,7 +689,7 @@ form: module.record_id""" % (xml_id,)
rec_id = rec.get("id",'').encode('ascii')
rec_context = rec.get("context", None)
if rec_context:
rec_context = eval(rec_context)
rec_context = unsafe_eval(rec_context)
self._test_xml_id(rec_id)
if self.isnoupdate(data_node) and self.mode != 'init':
# check if the xml record has an id string
@@ -722,7 +729,7 @@ form: module.record_id""" % (xml_id,)
f_val = False
if f_search:
q = eval(f_search, self.idref)
q = unsafe_eval(f_search, self.idref)
field = []
assert f_model, 'Define an attribute model="..." in your .XML file !'
f_obj = self.pool.get(f_model)
+1 -1
View File
@@ -1137,7 +1137,7 @@ icons = map(lambda x: (x,x), ['STOCK_ABOUT', 'STOCK_ADD', 'STOCK_APPLY', 'STOCK_
'terp-face-plain','terp-folder-blue','terp-folder-green','terp-folder-orange','terp-folder-yellow',
'terp-gdu-smart-failing','terp-go-week','terp-gtk-select-all','terp-locked','terp-mail-forward',
'terp-mail-message-new','terp-mail-replied','terp-rating-rated','terp-stage','terp-stock_format-scientific',
'terp-dolar_ok!'
'terp-dolar_ok!','terp-idea','terp-stock_format-default','terp-mail-','terp-mail_delete'
])
def extract_zip_file(zip_file, outdirectory):
+237 -49
View File
@@ -1,66 +1,254 @@
# -*- coding: utf-8 -*-
##############################################################################
# Copyright (C) 2004-2010 OpenERP s.a. (<http://www.openerp.com>).
#
# Copyright P. Christeas <p_christ@hol.gr> 2008,2009
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
###############################################################################
##############################################################################
__export_bis = {}
import sys
"""
safe_eval module - methods intended to provide more restricted alternatives to
evaluate simple and/or untrusted code.
def __init_ebis():
global __export_bis
Methods in this module are typically used as alternatives to eval() to parse
OpenERP domain strings, conditions and expressions, mostly based on locals
condition/math builtins.
"""
_evars = [ 'abs', 'all', 'any', 'basestring' , 'bool',
'chr', 'cmp','complex', 'dict', 'divmod', 'enumerate',
'float', 'frozenset', 'getattr', 'hasattr', 'hash',
'hex', 'id','int', 'iter', 'len', 'list', 'long', 'map', 'max',
'min', 'oct', 'ord','pow', 'range', 'reduce', 'repr',
'reversed', 'round', 'set', 'setattr', 'slice','sorted', 'str',
'sum', 'tuple','type', 'unichr','unicode', 'xrange',
'True','False', 'None', 'NotImplemented', 'Ellipsis', ]
# Module partially ripped from/inspired by several different sources:
# - http://code.activestate.com/recipes/286134/
# - safe_eval in lp:~xrg/openobject-server/optimize-5.0
# - safe_eval in tryton http://hg.tryton.org/hgwebdir.cgi/trytond/rev/bbb5f73319ad
# - python 2.6's ast.literal_eval
if sys.version_info[0:2] >= (2,6):
_evars.extend(['bin', 'format', 'next'])
for v in _evars:
__export_bis[v] = __builtins__[v]
from opcode import HAVE_ARGUMENT, opmap, opname
from types import CodeType
__all__ = ['test_expr', 'literal_eval', 'safe_eval', 'const_eval', 'ext_eval' ]
_CONST_OPCODES = set(opmap[x] for x in [
'POP_TOP', 'ROT_TWO', 'ROT_THREE', 'ROT_FOUR', 'DUP_TOP',
'BUILD_LIST', 'BUILD_MAP', 'BUILD_TUPLE',
'LOAD_CONST', 'RETURN_VALUE', 'STORE_SUBSCR'] if x in opmap)
_EXPR_OPCODES = _CONST_OPCODES.union(set(opmap[x] for x in [
'UNARY_POSITIVE', 'UNARY_NEGATIVE', 'UNARY_NOT',
'UNARY_INVERT', 'BINARY_POWER', 'BINARY_MULTIPLY',
'BINARY_DIVIDE', 'BINARY_FLOOR_DIVIDE', 'BINARY_TRUE_DIVIDE',
'BINARY_MODULO', 'BINARY_ADD', 'BINARY_SUBTRACT', 'BINARY_SUBSCR',
'BINARY_LSHIFT', 'BINARY_RSHIFT', 'BINARY_AND', 'BINARY_XOR',
'BINARY_OR'] if x in opmap))
_SAFE_OPCODES = _EXPR_OPCODES.union(set(opmap[x] for x in [
'STORE_MAP', 'LOAD_NAME', 'CALL_FUNCTION', 'COMPARE_OP', 'LOAD_ATTR',
'STORE_NAME', 'GET_ITER', 'FOR_ITER', 'LIST_APPEND', 'JUMP_ABSOLUTE',
'DELETE_NAME', 'JUMP_IF_TRUE', 'JUMP_IF_FALSE',
] if x in opmap))
__init_ebis()
def _get_opcodes(codeobj):
"""_get_opcodes(codeobj) -> [opcodes]
Extract the actual opcodes as a list from a code object
>>> c = compile("[1 + 2, (1,2)]", "", "eval")
>>> _get_opcodes(c)
[100, 100, 23, 100, 100, 102, 103, 83]
"""
i = 0
opcodes = []
byte_codes = codeobj.co_code
while i < len(byte_codes):
code = ord(byte_codes[i])
opcodes.append(code)
if code >= HAVE_ARGUMENT:
i += 3
else:
i += 1
return opcodes
def test_expr(expr, allowed_codes, mode="eval"):
"""test_expr(expression, allowed_codes[, mode]) -> code_object
Test that the expression contains only the allowed opcodes.
If the expression is valid and contains only allowed codes,
return the compiled code object. Otherwise raise a ValueError.
"""
try:
code_obj = compile(expr, "", mode)
except:
raise ValueError("%s is not a valid expression" % expr)
for code in _get_opcodes(code_obj):
if code not in allowed_codes:
raise ValueError("opcode %s not allowed (%r)" % (opname[code], expr))
return code_obj
def safe_eval(expr,sglobals,slocals = None):
""" A little safer version of eval().
This one, will use fewer builtin functions, so that only
arithmetic and logic expressions can really work """
def const_eval(expr):
"""const_eval(expression) -> value
global __export_bis
Safe Python constant evaluation
if not sglobals.has_key('__builtins__'):
# we copy, because we wouldn't want successive calls to safe_eval
# to be able to alter the builtins.
sglobals['__builtins__'] = __export_bis.copy()
Evaluates a string that contains an expression describing
a Python constant. Strings that are not valid Python expressions
or that contain other code besides the constant raise ValueError.
return eval(expr,sglobals,slocals)
>>> const_eval("10")
10
>>> const_eval("[1,2, (3,4), {'foo':'bar'}]")
[1, 2, (3, 4), {'foo': 'bar'}]
>>> const_eval("1+2")
Traceback (most recent call last):
...
ValueError: opcode BINARY_ADD not allowed
"""
c = test_expr(expr, _CONST_OPCODES)
return eval(c)
#eof
def expr_eval(expr):
"""expr_eval(expression) -> value
Restricted Python expression evaluation
Evaluates a string that contains an expression that only
uses Python constants. This can be used to e.g. evaluate
a numerical expression from an untrusted source.
>>> expr_eval("1+2")
3
>>> expr_eval("[1,2]*2")
[1, 2, 1, 2]
>>> expr_eval("__import__('sys').modules")
Traceback (most recent call last):
...
ValueError: opcode LOAD_NAME not allowed
"""
c = test_expr(expr, _EXPR_OPCODES)
return eval(c)
# Port of Python 2.6's ast.literal_eval for use under Python 2.5
SAFE_CONSTANTS = {'None': None, 'True': True, 'False': False}
try:
# first, try importing directly
from ast import literal_eval
except ImportError:
import _ast as ast
def _convert(node):
if isinstance(node, ast.Str):
return node.s
elif isinstance(node, ast.Num):
return node.n
elif isinstance(node, ast.Tuple):
return tuple(map(_convert, node.elts))
elif isinstance(node, ast.List):
return list(map(_convert, node.elts))
elif isinstance(node, ast.Dict):
return dict((_convert(k), _convert(v)) for k, v
in zip(node.keys, node.values))
elif isinstance(node, ast.Name):
if node.id in SAFE_CONSTANTS:
return SAFE_CONSTANTS[node.id]
raise ValueError('malformed or disallowed expression')
def parse(expr, filename='<unknown>', mode='eval'):
"""parse(source[, filename], mode]] -> code object
Parse an expression into an AST node.
Equivalent to compile(expr, filename, mode, PyCF_ONLY_AST).
"""
return compile(expr, filename, mode, ast.PyCF_ONLY_AST)
def literal_eval(node_or_string):
"""literal_eval(expression) -> value
Safely evaluate an expression node or a string containing a Python
expression. The string or node provided may only consist of the
following Python literal structures: strings, numbers, tuples,
lists, dicts, booleans, and None.
>>> literal_eval('[1,True,"spam"]')
[1, True, 'spam']
>>> literal_eval('1+3')
Traceback (most recent call last):
...
ValueError: malformed or disallowed expression
"""
if isinstance(node_or_string, basestring):
node_or_string = parse(node_or_string)
if isinstance(node_or_string, ast.Expression):
node_or_string = node_or_string.body
return _convert(node_or_string)
def safe_eval(expr, globals_dict=None, locals_dict=None, mode="eval", nocopy=False):
"""safe_eval(expression[, globals[, locals[, mode[, nocopy]]]]) -> result
System-restricted Python expression evaluation
Evaluates a string that contains an expression that mostly
uses Python constants, arithmetic expressions and the
objects directly provided in context.
This can be used to e.g. evaluate
an OpenERP domain expression from an untrusted source.
>>> safe_eval("__import__('sys').modules")
Traceback (most recent call last):
...
ValueError: opcode LOAD_NAME not allowed
"""
if isinstance(expr, CodeType):
raise ValueError("safe_eval does not allow direct evaluation of code objects.")
if '__subclasses__' in expr:
raise ValueError('expression not allowed (__subclasses__)')
if globals_dict is None:
globals_dict = {}
# prevent altering the globals/locals from within the sandbox
# by taking a copy.
if not nocopy:
# isinstance() does not work below, we want *exactly* the dict class
if (globals_dict is not None and type(globals_dict) is not dict) \
or (locals_dict is not None and type(locals_dict) is not dict):
logging.getLogger('safe_eval').warning('Looks like you are trying to pass a dynamic environment,"\
"you should probably pass nocopy=True to safe_eval()')
globals_dict = dict(globals_dict)
if locals_dict is not None:
locals_dict = dict(locals_dict)
globals_dict.update(
__builtins__ = {
'True': True,
'False': False,
'None': None,
'str': str,
'globals': locals,
'locals': locals,
'bool': bool,
'dict': dict,
'list': list,
'tuple': tuple,
}
)
return eval(test_expr(expr,_SAFE_OPCODES, mode=mode), globals_dict, locals_dict)
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+11 -5
View File
@@ -8,9 +8,13 @@ import netsvc
import misc
from config import config
import yaml_tag
import yaml
# YAML import needs both safe and unsafe eval, but let's
# default to /safe/.
unsafe_eval = eval
from tools.safe_eval import safe_eval as eval
logger_channel = 'tests'
class YamlImportException(Exception):
@@ -234,8 +238,9 @@ class YamlInterpreter(object):
record = model.browse(self.cr, self.uid, id, context)
for test in expressions:
try:
success = eval(test, self.eval_context, RecordDictWrapper(record))
success = unsafe_eval(test, self.eval_context, RecordDictWrapper(record))
except Exception, e:
self.logger.debug('Exception during evaluation of !assert block in yaml_file %s.', self.filename, exc_info=True)
raise YamlImportAbortion(e)
if not success:
msg = 'Assertion "%s" FAILED\ntest: %s\n'
@@ -330,7 +335,7 @@ class YamlInterpreter(object):
else:
raise KeyError("Object '%s' does not contain field '%s'" % (model, field_name))
if is_ref(expression):
elements = self.process_ref(expression)
elements = self.process_ref(expression, column)
if column._type in ("many2many", "one2many"):
value = [(6, 0, elements)]
else: # many2one
@@ -367,12 +372,13 @@ class YamlInterpreter(object):
code_context = {'model': model, 'cr': self.cr, 'uid': self.uid, 'log': log, 'context': self.context}
code_context.update({'self': model}) # remove me when no !python block test uses 'self' anymore
try:
code = compile(statements, self.filename, 'exec')
eval(code, {'ref': self.get_id}, code_context)
code_obj = compile(statements, self.filename, 'exec')
unsafe_eval(code_obj, {'ref': self.get_id}, code_context)
except AssertionError, e:
self._log_assert_failure(python.severity, 'AssertionError in Python code %s: %s', python.name, e)
return
except Exception, e:
self.logger.debug('Exception during evaluation of !python block in yaml_file %s.', self.filename, exc_info=True)
raise YamlImportAbortion(e)
else:
self.assert_report.record(True, python.severity)
+2 -1
View File
@@ -23,6 +23,7 @@ import sys
import netsvc
import osv as base
import pooler
from tools.safe_eval import safe_eval as eval
class Env(dict):
def __init__(self, cr, uid, model, ids):
@@ -54,7 +55,7 @@ def _eval_expr(cr, ident, workitem, action):
ret=False
else:
env = Env(cr, uid, model, ids)
ret = eval(line, env)
ret = eval(line, env, nocopy=True)
return ret
def execute_action(cr, ident, workitem, activity):