diff --git a/bin/addons/base/__terp__.py b/bin/addons/base/__terp__.py index ae83f7ea164..d90d56a3a72 100644 --- a/bin/addons/base/__terp__.py +++ b/bin/addons/base/__terp__.py @@ -38,7 +38,7 @@ "init_xml" : [ "base_data.xml", "base_menu.xml", - "base_security.xml", + "security/base_security.xml", "res/res_security.xml", ], "demo_xml" : [ @@ -66,8 +66,8 @@ "res/partner/crm_view.xml", "res/partner/partner_data.xml", "res/ir_property_view.xml", - "base_security.xml", - "ir.model.access.csv", + "security/base_security.xml", + "security/ir.model.access.csv", ], "active": True, "installable": True, diff --git a/bin/addons/base/ir/ir_ui_menu.py b/bin/addons/base/ir/ir_ui_menu.py index a76b8ec1e76..555a5b4b7a1 100644 --- a/bin/addons/base/ir/ir_ui_menu.py +++ b/bin/addons/base/ir/ir_ui_menu.py @@ -66,16 +66,25 @@ class ir_ui_menu(osv.osv): context=context) if uid==1: return ids - user_groups = self.pool.get('res.users').read(cr, uid, [uid])[0]['groups_id'] + user_groups = set(self.pool.get('res.users').read(cr, uid, uid)['groups_id']) result = [] for menu in self.browse(cr, uid, ids): - if not len(menu.groups_id): - result.append(menu.id) + restrict_to_groups = menu.groups_id + if not restrict_to_groups: + if menu.action: + # if the menu itself has no restrictions, we get the groups of + # the action of the menu + try: + m, oid = menu.action.split(',', 1) + data = self.pool.get(m).read(cr, uid, int(oid), context=context) + if data and 'groups_id' in data: + restrict_to_groups = data['groups_id'] + except: + pass + + if restrict_to_groups and not user_groups.intersection(restrict_to_groups): continue - for g in menu.groups_id: - if g.id in user_groups: - result.append(menu.id) - break + result.append(menu.id) return result def _get_full_name(self, cr, uid, ids, name, args, context): @@ -122,8 +131,7 @@ class ir_ui_menu(osv.osv): ('key2', '=', 'tree_but_open'), ('res_id', 'in', ids)], context=context) values_action = {} - for value in values_obj.browse(cursor, user, value_ids, - context=context): + for value in values_obj.browse(cursor, user, value_ids, context=context): values_action[value.res_id] = value.value for menu_id in ids: res[menu_id] = values_action.get(menu_id, False) diff --git a/bin/addons/base/module/module.py b/bin/addons/base/module/module.py index fa8ce19fd57..ca25c010ccc 100644 --- a/bin/addons/base/module/module.py +++ b/bin/addons/base/module/module.py @@ -268,7 +268,7 @@ class module(osv.osv): raise orm.except_orm(_('Error'), _('You try to remove a module that is installed or will be installed')) return super(module, self).unlink(cr, uid, ids, context=context) - + def state_update(self, cr, uid, ids, newstate, states_to_update, context={}, level=50): if level<1: raise orm.except_orm(_('Error'), _('Recursion error in modules dependencies !')) @@ -471,14 +471,14 @@ class module(osv.osv): match = re.search('-([a-zA-Z0-9\._-]+)(\.zip)', mod.url, re.I) version = '0' if match: - version = match.group(1) + version = match.group(1) if vercmp(mod.installed_version or '0', version) >= 0: continue res.append(mod.url) if not download: continue zipfile = urllib.urlopen(mod.url).read() - fname = addons.get_module_path(mod.name+'.zip') + fname = addons.get_module_path(mod.name+'.zip') try: fp = file(fname, 'wb') fp.write(zipfile) @@ -528,12 +528,12 @@ class module(osv.osv): self.write(cr, uid, [id], {'category_id': p_id}) def action_install(self,cr,uid,ids,context=None): - self.write(cr , uid, ids ,{'state' : 'to install'}) + self.write(cr , uid, ids ,{'state' : 'to install'}) self.download(cr, uid, ids, context=context) for id in ids: cr.execute("select m.id as id from ir_module_module_dependency d inner join ir_module_module m on (m.name=d.name) where d.module_id=%d and m.state='uninstalled'",(id,)) dep_ids = map(lambda x:x[0],cr.fetchall()) - if len(dep_ids): + if len(dep_ids): self.action_install(cr,uid,dep_ids,context=context) def update_translations(self, cr, uid, ids, filter_lang=None): @@ -550,7 +550,7 @@ class module(osv.osv): for mod in self.browse(cr, uid, ids): if mod.state != 'installed': continue - + for lang in filter_lang: f = os.path.join(tools.config['addons_path'], mod.name, 'i18n', lang + '.po') if os.path.exists(f): @@ -680,6 +680,18 @@ class module_configuration(osv.osv_memory): 'type': item.action_id.type, 'target':item.action_id.target, } + user_action=self.pool.get('res.users').browse(cr,uid,uid) + act_obj=self.pool.get(user_action.menu_id.type) + action_ids=act_obj.search(cr,uid,[('name','=',user_action.menu_id.name)]) + action_open=act_obj.browse(cr,uid,action_ids)[0] + if context.get('menu',False): + return{ + 'view_type': action_open.view_type, + 'view_id':action_open.view_id and [action_open.view_id.id] or False, + 'res_model': action_open.res_model, + 'type': action_open.type, + 'domain':action_open.domain + } return {'type':'ir.actions.act_window_close' } module_configuration() diff --git a/bin/addons/base/res/res_user.py b/bin/addons/base/res/res_user.py index d168a69de38..35b008806e1 100644 --- a/bin/addons/base/res/res_user.py +++ b/bin/addons/base/res/res_user.py @@ -118,12 +118,18 @@ class users(osv.osv): 'context_tz': fields.selection(_tz_get, 'Timezone', size=64) } def read(self,cr, uid, ids, fields=None, context=None, load='_classic_read'): + def override_password(o): + if 'password' in o: + o['password'] = '********' + return o + result = super(users, self).read(cr, uid, ids, fields, context, load) canwrite = self.pool.get('ir.model.access').check(cr, uid, 'res.users', 'write', raise_exception=False) if not canwrite: - for r in result: - if 'password' in r: - r['password'] = '********' + if isinstance(ids, (int, float)): + result = override_password(result) + else: + result = map(override_password, result) return result _sql_constraints = [ diff --git a/bin/addons/base/base_security.xml b/bin/addons/base/security/base_security.xml similarity index 88% rename from bin/addons/base/base_security.xml rename to bin/addons/base/security/base_security.xml index d109ae05e9c..c72f31418f3 100644 --- a/bin/addons/base/base_security.xml +++ b/bin/addons/base/security/base_security.xml @@ -41,6 +41,9 @@ + + + diff --git a/bin/addons/base/ir.model.access.csv b/bin/addons/base/security/ir.model.access.csv similarity index 100% rename from bin/addons/base/ir.model.access.csv rename to bin/addons/base/security/ir.model.access.csv diff --git a/bin/osv/fields.py b/bin/osv/fields.py index 825420b1ec6..daee0e4e40a 100644 --- a/bin/osv/fields.py +++ b/bin/osv/fields.py @@ -223,7 +223,7 @@ class binary(_column): val = v[name] break res.setdefault(i, val) - if context.get('get_binary_size', True): + if context.get('bin_size', False): res[i] = tools.human_size(val) return res @@ -620,7 +620,7 @@ class function(_column): else: res = self._fnct(cr, obj._table, ids, name, self._arg, context) - if self._type == 'binary' and context.get('get_binary_size', True): + if self._type == 'binary' and context.get('bin_size', False): # convert the data returned by the function with the size of that data... res = dict(map(lambda (x, y): (x, tools.human_size(len(y))), res.items())) return res @@ -648,8 +648,8 @@ class related(function): # return True - def _fnct_write(self,obj,cr, uid, ids, field_name, args, context=None): - raise 'Not Implemented Yet' +# def _fnct_write(self,obj,cr, uid, ids,values, field_name, args, context=None): +# raise 'Not Implemented Yet' def _fnct_read(self,obj,cr, uid, ids, field_name, args, context=None): if not ids: return {} @@ -678,7 +678,7 @@ class related(function): def __init__(self,*arg,**args): print arg self.arg = arg - super(related, self).__init__(self._fnct_read, arg, fnct_inv=self._fnct_write, fnct_inv_arg=arg,method=True, fnct_search=self._fnct_search,**args) + super(related, self).__init__(self._fnct_read, arg, fnct_inv_arg=arg,method=True, fnct_search=self._fnct_search,**args) # TODO: call field_get on the object, not in the DB def _field_get(self, cr, uid, obj, model_name, prop): diff --git a/bin/osv/orm.py b/bin/osv/orm.py index 00e2f30b35f..0fb4fdfcbf2 100644 --- a/bin/osv/orm.py +++ b/bin/osv/orm.py @@ -647,7 +647,7 @@ class orm_template(object): if not fun(self, cr, uid, ids): translated_msg = trans._get_source(cr, uid, self._name, 'constraint', lng, source=msg) or msg error_msgs.append( - _("Error occur when validation the fields %s: %s") % (','.join(fields), translated_msg) + _("Error occured while validating the field(s) %s: %s") % (','.join(fields), translated_msg) ) if error_msgs: cr.rollback() @@ -775,23 +775,15 @@ class orm_template(object): if result: node.setAttribute('string', result.decode('utf-8')) if node.nodeType == node.ELEMENT_NODE and node.hasAttribute('groups'): - groups = None - group_str = node.getAttribute('groups') - if ',' in group_str: - groups = group_str.split(',') + if node.getAttribute('groups'): + groups = node.getAttribute('groups').split(',') readonly = False access_pool = self.pool.get('ir.model.access') for group in groups: - readonly = readonly and access_pool.check_groups(cr, user, group) - - if readonly: - parent = node.parentNode - parent.removeChild(node) - - else: - if not self.pool.get('ir.model.access').check_groups(cr, user, group_str): - parent = node.parentNode - parent.removeChild(node) + readonly = readonly or access_pool.check_groups(cr, user, group) + if not readonly: + node.setAttribute('invisible', '1') + node.removeAttribute('groups') if node.nodeType == node.ELEMENT_NODE: # translate view @@ -837,7 +829,6 @@ class orm_template(object): button.setAttribute('readonly', '0') arch = node.toxml(encoding="utf-8").replace('\t', '') - fields = self.fields_get(cr, user, fields_def.keys(), context) for field in fields_def: fields[field].update(fields_def[field]) @@ -1122,12 +1113,14 @@ class orm_memory(orm_template): fields_to_read = self._columns.keys() result = [] if self.datas: + if isinstance(ids, (int, long)): + ids = [ids] for id in ids: r = {'id': id} for f in fields_to_read: if id in self.datas: r[f] = self.datas[id].get(f, False) - if r[f] and isinstance(self._columns[f], fields.binary) and context.get('get_binary_size', True): + if r[f] and isinstance(self._columns[f], fields.binary) and context.get('bin_size', False): r[f] = len(r[f]) result.append(r) if id in self.datas: @@ -1137,6 +1130,8 @@ class orm_memory(orm_template): res2 = self._columns[f].get_memory(cr, self, ids, f, user, context=context, values=result) for record in result: record[f] = res2[record['id']] + if isinstance(ids, (int, long)): + return result[0] return result def write(self, cr, user, ids, vals, context=None): @@ -1721,7 +1716,7 @@ class orm(orm_template): def convert_field(f): if f in ('create_date', 'write_date'): return "date_trunc('second', %s) as %s" % (f, f) - if isinstance(self._columns[f], fields.binary) and context.get('get_binary_size', True): + if isinstance(self._columns[f], fields.binary) and context.get('bin_size', False): return "length(%s) as %s" % (f,f) return '"%s"' % (f,) #fields_pre2 = map(lambda x: (x in ('create_date', 'write_date')) and ('date_trunc(\'second\', '+x+') as '+x) or '"'+x+'"', fields_pre) diff --git a/bin/report/interface.py b/bin/report/interface.py index fafc52367b6..95e6ec31946 100644 --- a/bin/report/interface.py +++ b/bin/report/interface.py @@ -64,6 +64,7 @@ class report_int(netsvc.Service): self.name = name self.id = 0 self.name2 = '.'.join(name.split('.')[1:]) + self.title = None self.joinGroup('report') self.exportMethod(self.create) @@ -101,10 +102,10 @@ class report_rml(report_int): ir_actions_report_xml_obj = pool.get('ir.actions.report.xml') report_xml_ids = ir_actions_report_xml_obj.search(cr, uid, [('report_name', '=', self.name[7:])], context=context) - ftitle = ir_actions_report_xml_obj.browse(cr,uid,report_xml_ids)[0].name + self.title = ir_actions_report_xml_obj.browse(cr,uid,report_xml_ids)[0].name report_type = datas.get('report_type', 'pdf') create_doc = self.generators[report_type] - pdf = create_doc(rml,title=ftitle) + pdf = create_doc(rml, title=self.title) return (pdf, report_type) def create_xml(self, cr, uid, ids, datas, context=None): @@ -196,7 +197,7 @@ class report_rml(report_int): result.freeDoc() return xml - def create_pdf(self, xml, logo=None,title=None): + def create_pdf(self, xml, logo=None, title=None): if logo: self.bin_datas['logo'] = logo else: @@ -206,15 +207,15 @@ class report_rml(report_int): obj.render() return obj.get() - def create_html(self, xml, logo=None,title=None): + def create_html(self, xml, logo=None, title=None): obj = render.rml2html(xml, self.bin_datas) obj.render() return obj.get() - def create_raw(self, xml, logo=None,title=None): + def create_raw(self, xml, logo=None, title=None): return xml - def create_sxw(self, path, logo=None,title=None): + def create_sxw(self, path, logo=None, title=None): return path from report_sxw import report_sxw diff --git a/bin/report/printscreen/ps_form.py b/bin/report/printscreen/ps_form.py index 6e8b2de602f..1e7757e3f17 100644 --- a/bin/report/printscreen/ps_form.py +++ b/bin/report/printscreen/ps_form.py @@ -39,7 +39,7 @@ import libxml2 import libxslt import time, os -ftitle="" + class report_printscreen_list(report_int): def __init__(self, name): report_int.__init__(self, name) @@ -63,7 +63,6 @@ class report_printscreen_list(report_int): return self._parse_node(dom) def create(self, cr, uid, ids, datas, context=None): - global ftitle if not context: context={} datas['ids'] = ids @@ -71,10 +70,10 @@ class report_printscreen_list(report_int): model_id = pool.get('ir.model').search(cr, uid, [('model','=',model._name)]) if model_id: model_desc = pool.get('ir.model').browse(cr, uid, model_id, context).name - ftitle=model_desc + self.title = model_desc else: model_desc = model._description - ftitle=model_desc + self.title = model_desc model = pool.get(datas['model']) result = model.fields_view_get(cr, uid, view_type='tree', context=context) @@ -158,8 +157,7 @@ class report_printscreen_list(report_int): doc = libxml2.parseDoc(new_doc.toxml()) rml_obj = style.applyStylesheet(doc, None) rml = style.saveResultToString(rml_obj) - global ftitle - self.obj = render.rml(rml,ftitle) + self.obj = render.rml(rml, self.title) self.obj.render() return True report_printscreen_list('report.printscreen.form') diff --git a/bin/report/printscreen/ps_list.py b/bin/report/printscreen/ps_list.py index 4717fe03437..29242a3119e 100644 --- a/bin/report/printscreen/ps_list.py +++ b/bin/report/printscreen/ps_list.py @@ -39,7 +39,7 @@ import libxml2 import libxslt import time, os -ftitle="" + class report_printscreen_list(report_int): def __init__(self, name): report_int.__init__(self, name) @@ -63,7 +63,6 @@ class report_printscreen_list(report_int): return self._parse_node(dom) def create(self, cr, uid, ids, datas, context=None): - global ftitle if not context: context={} pool = pooler.get_pool(cr.dbname) @@ -71,10 +70,10 @@ class report_printscreen_list(report_int): model_id = pool.get('ir.model').search(cr, uid, [('model','=',model._name)]) if model_id: model_desc = pool.get('ir.model').browse(cr, uid, model_id[0], context).name - ftitle=model_desc + self.title = model_desc else: model_desc = model._description - ftitle=model_desc + self.title = model_desc datas['ids'] = ids model = pooler.get_pool(cr.dbname).get(datas['model']) @@ -202,8 +201,7 @@ class report_printscreen_list(report_int): doc = libxml2.parseDoc(new_doc.toxml()) rml_obj = style.applyStylesheet(doc, None) rml = style.saveResultToString(rml_obj) - global ftitle - self.obj = render.rml(rml,title=ftitle) + self.obj = render.rml(rml, title=self.title) self.obj.render() return True report_printscreen_list('report.printscreen.list') diff --git a/bin/report/render/rml2pdf/trml2pdf.py b/bin/report/render/rml2pdf/trml2pdf.py index aeee1220d08..e0cc3cc8220 100644 --- a/bin/report/render/rml2pdf/trml2pdf.py +++ b/bin/report/render/rml2pdf/trml2pdf.py @@ -60,7 +60,7 @@ from reportlab import platypus import utils import color import os -ftitle="" + # # Change this to UTF-8 if you plan tu use Reportlab's UTF-8 support # @@ -180,11 +180,12 @@ class _rml_styles(object): return style class _rml_doc(object): - def __init__(self, data, images={}, path='.'): + def __init__(self, data, images={}, path='.', title=None): self.dom = xml.dom.minidom.parseString(data) self.filename = self.dom.documentElement.getAttribute('filename') self.images = images self.path = path + self.title = title def docinit(self, els): from reportlab.lib.fonts import addMapping @@ -229,28 +230,28 @@ class _rml_doc(object): el = self.dom.documentElement.getElementsByTagName('template') if len(el): - pt_obj = _rml_template(out, el[0], self, images=self.images, path=self.path) + pt_obj = _rml_template(out, el[0], self, images=self.images, path=self.path, title=self.title) pt_obj.render(self.dom.documentElement.getElementsByTagName('story')) else: self.canvas = canvas.Canvas(out) pd = self.dom.documentElement.getElementsByTagName('pageDrawing')[0] - pd_obj = _rml_canvas(self.canvas, None, self, self.images, path=self.path) + pd_obj = _rml_canvas(self.canvas, None, self, self.images, path=self.path, title=self.title) pd_obj.render(pd) self.canvas.showPage() self.canvas.save() class _rml_canvas(object): - def __init__(self, canvas, doc_tmpl=None, doc=None, images={}, path='.'): + def __init__(self, canvas, doc_tmpl=None, doc=None, images={}, path='.', title=None): self.canvas = canvas self.styles = doc.styles self.doc_tmpl = doc_tmpl self.doc = doc self.images = images self.path = path - global ftitle - if ftitle: - self.canvas.setTitle(ftitle) + self.title = title + if self.title: + self.canvas.setTitle(self.title) def _textual(self, node, x=0, y=0): rc = '' @@ -324,7 +325,7 @@ class _rml_canvas(object): self.canvas.circle(x_cen=utils.unit_get(node.getAttribute('x')), y_cen=utils.unit_get(node.getAttribute('y')), r=utils.unit_get(node.getAttribute('radius')), **utils.attr_get(node, [], {'fill':'bool','stroke':'bool'})) def _place(self, node): - flows = _rml_flowable(self.doc, images=self.images, path=self.path).render(node) + flows = _rml_flowable(self.doc, images=self.images, path=self.path, title=self.title).render(node) infos = utils.attr_get(node, ['x','y','width','height']) infos['y']+=infos['height'] @@ -450,25 +451,27 @@ class _rml_canvas(object): break class _rml_draw(object): - def __init__(self, node, styles, images={}, path='.'): + def __init__(self, node, styles, images={}, path='.', title=None): self.node = node self.styles = styles self.canvas = None self.images = images self.path = path + self.canvas_title = title def render(self, canvas, doc): canvas.saveState() - cnv = _rml_canvas(canvas, doc, self.styles, images=self.images, path=self.path) + cnv = _rml_canvas(canvas, doc, self.styles, images=self.images, path=self.path, title=self.canvas_title) cnv.render(self.node) canvas.restoreState() class _rml_flowable(object): - def __init__(self, doc, images={}, path='.'): + def __init__(self, doc, images={}, path='.', title=None): self.doc = doc self.styles = doc.styles self.images = images self.path = path + self.title = title def _textual(self, node): rc = '' @@ -569,7 +572,7 @@ class _rml_flowable(object): return (self.width, self.height) def draw(self): canvas = self.canv - drw = _rml_draw(self.node, self.styles, images=self.self2.images, path=self.self2.path) + drw = _rml_draw(self.node, self.styles, images=self.self2.images, path=self.self2.path, title=self.self2.title) drw.render(self.canv, None) return Illustration(node, self.styles, self) @@ -741,9 +744,10 @@ class TinyDocTemplate(platypus.BaseDocTemplate): self.canv._pageNumber = 0 class _rml_template(object): - def __init__(self, out, node, doc, images={}, path='.'): + def __init__(self, out, node, doc, images={}, path='.', title=None): self.images= images self.path = path + self.title = title if not node.hasAttribute('pageSize'): pageSize = (utils.unit_get('21cm'), utils.unit_get('29.7cm')) else: @@ -764,7 +768,7 @@ class _rml_template(object): frames.append( frame ) gr = pt.getElementsByTagName('pageGraphics') if len(gr): - drw = _rml_draw(gr[0], self.doc, images=images, path=self.path) + drw = _rml_draw(gr[0], self.doc, images=images, path=self.path, title=self.title) self.page_templates.append( platypus.PageTemplate(frames=frames, onPage=drw.render, **utils.attr_get(pt, [], {'id':'str'}) )) else: self.page_templates.append( platypus.PageTemplate(frames=frames, **utils.attr_get(pt, [], {'id':'str'}) )) @@ -772,7 +776,7 @@ class _rml_template(object): def render(self, node_stories): fis = [] - r = _rml_flowable(self.doc,images=self.images, path=self.path) + r = _rml_flowable(self.doc,images=self.images, path=self.path, title=self.title) for node_story in node_stories: fis += r.render(node_story) if node_story==node_stories[-1]: @@ -784,9 +788,7 @@ class _rml_template(object): self.doc_tmpl.build(fis) def parseString(data, fout=None, images={}, path='.',title=None): - r = _rml_doc(data, images, path) - global ftitle - ftitle=title + r = _rml_doc(data, images, path, title=title) if fout: fp = file(fout,'wb') r.render(fp) diff --git a/bin/report/report_sxw.py b/bin/report/report_sxw.py index 5b9a78c630a..a5f7ee8d7ef 100644 --- a/bin/report/report_sxw.py +++ b/bin/report/report_sxw.py @@ -566,7 +566,6 @@ class report_sxw(report_rml): if not context: context={} context = context.copy() - context['get_binary_size'] = False pool = pooler.get_pool(cr.dbname) ir_actions_report_xml_obj = pool.get('ir.actions.report.xml') diff --git a/bin/tools/misc.py b/bin/tools/misc.py index 0034a1e0bce..f29f1731ddb 100644 --- a/bin/tools/misc.py +++ b/bin/tools/misc.py @@ -327,7 +327,7 @@ def reverse_enumerate(l): #---------------------------------------------------------- # Emails #---------------------------------------------------------- -def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=None, on_error=False, reply_to=False, tinycrm=False): +def email_send(email_from, email_to, subject, body, email_cc=None, email_bcc=None, on_error=False, reply_to=False, tinycrm=False, ssl=False, debug=False): """Send an email.""" if not email_cc: email_cc=[]