From 5451ff85f9b61b8290b6bff3edcbd694c943fce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 13 Sep 2012 13:39:31 +0200 Subject: [PATCH 01/44] [FIX] mail_mail: added security rules for mail.mail, to allow users to send emails. This fixes notably the crash when Demo User tries to send a quotation by email. bzr revid: tde@openerp.com-20120913113931-x31vkhihikfdn4bc --- addons/mail/security/ir.model.access.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv index 1979e2fec05..c89c60756bd 100644 --- a/addons/mail/security/ir.model.access.csv +++ b/addons/mail/security/ir.model.access.csv @@ -1,6 +1,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_mail_message_all,mail.message.all,model_mail_message,,1,0,0,0 access_mail_message_group_user,mail.message.group.user,model_mail_message,base.group_user,1,1,1,1 +access_mail_mail_all,mail.mail.all,model_mail_mail,,1,1,1,1 access_mail_thread,mail.thread,model_mail_thread,base.group_user,1,1,1,0 access_mail_followers_all,mail.followers.all,model_mail_followers,,1,1,1,1 access_mail_notification_all,mail.notification.all,model_mail_notification,,1,1,1,1 From 827bc4ec989cf53e3e774efd92527a0c8d4f5a23 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Thu, 13 Sep 2012 17:30:27 +0200 Subject: [PATCH 02/44] [IMP] portal: better ids for csv access rights bzr revid: abo@openerp.com-20120913153027-64cq2njzbagdlr3h --- addons/portal/security/ir.model.access.csv | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/addons/portal/security/ir.model.access.csv b/addons/portal/security/ir.model.access.csv index 56b3ae5f269..ea472cece38 100644 --- a/addons/portal/security/ir.model.access.csv +++ b/addons/portal/security/ir.model.access.csv @@ -1,12 +1,12 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_all,access.portal.all,model_res_portal,,1,0,0,0 -access_widget_all,access.portal.widget.all,model_res_portal_widget,,1,0,0,0 -access_manager,access.portal.manager,model_res_portal,group_portal_manager,1,1,1,1 -access_widget_manager,access.portal.widget.manager,model_res_portal_widget,group_portal_manager,1,1,1,1 -access_mail_message,mail.message,mail.model_mail_message,group_portal_member,1,0,1,1 -access_mail_message_all,mail.message.all,mail.model_mail_message,group_portal_member,1,0,0,0 -access_mail_thread,mail.thread,mail.model_mail_thread,group_portal_member,1,0,0,0 -access_mail_followers,mail.followers,mail.model_mail_followers,group_portal_member,1,0,1,1 -access_mail_notification,mail.notification,mail.model_mail_notification,group_portal_member,1,0,1,0 -access_mail_group,mail.group,mail.model_mail_group,group_portal_member,1,0,0,0 -access_mail_alias,mail.alias,mail.model_mail_alias,group_portal_member,1,0,0,0 +access_portal_all,access.portal.all,model_res_portal,,1,0,0,0 +access_widget_portal_all,access.portal.widget.all,model_res_portal_widget,,1,0,0,0 +access_manager_portal,access.portal.manager,model_res_portal,group_portal_manager,1,1,1,1 +access_widget_manager_portal,access.portal.widget.manager,model_res_portal_widget,group_portal_manager,1,1,1,1 +access_mail_message_portal,mail.message,mail.model_mail_message,group_portal_member,1,0,1,1 +access_mail_message_portal_all,mail.message.all,mail.model_mail_message,group_portal_member,1,0,0,0 +access_mail_thread_portal,mail.thread,mail.model_mail_thread,group_portal_member,1,0,0,0 +access_mail_followers_portal,mail.followers,mail.model_mail_followers,group_portal_member,1,0,1,1 +access_mail_notification_portal,mail.notification,mail.model_mail_notification,group_portal_member,1,0,1,0 +access_mail_group_portal,mail.group,mail.model_mail_group,group_portal_member,1,0,0,0 +access_mail_alias_portal,mail.alias,mail.model_mail_alias,group_portal_member,1,0,0,0 From e66cd01467ddb209cb9cdb6c60c72e97f0ae191b Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Thu, 13 Sep 2012 17:58:10 +0200 Subject: [PATCH 03/44] [IMP] portal: first batch of ir rules bzr revid: abo@openerp.com-20120913155810-3grgq7xht1h981m5 --- addons/portal_claim/security/portal_security.xml | 2 +- addons/portal_event/security/portal_security.xml | 2 +- addons/portal_project/security/portal_security.xml | 2 +- .../security/portal_security.xml | 2 +- addons/portal_sale/security/portal_security.xml | 12 ++++++------ addons/project_issue/project_issue_demo.xml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/addons/portal_claim/security/portal_security.xml b/addons/portal_claim/security/portal_security.xml index e902bd043ad..6013bc1d42f 100644 --- a/addons/portal_claim/security/portal_security.xml +++ b/addons/portal_claim/security/portal_security.xml @@ -5,7 +5,7 @@ Portal Personal Claims - [('partner_id','child_of',user.partner_id.id)] + [('message_follower_ids','in',user.partner_id.id)] diff --git a/addons/portal_event/security/portal_security.xml b/addons/portal_event/security/portal_security.xml index 6a3ed0ac786..d8c7f54099f 100644 --- a/addons/portal_event/security/portal_security.xml +++ b/addons/portal_event/security/portal_security.xml @@ -12,7 +12,7 @@ Portal Personal Registrations - [('partner_id','child_of',user.partner_id.id)] + [('message_follower_ids','in',user.partner_id.id)] diff --git a/addons/portal_project/security/portal_security.xml b/addons/portal_project/security/portal_security.xml index b995c79bbbc..d70b576fe4c 100644 --- a/addons/portal_project/security/portal_security.xml +++ b/addons/portal_project/security/portal_security.xml @@ -5,7 +5,7 @@ Portal Personal Task - [('partner_id','child_of',user.partner_id.id)] + [('message_follower_ids','in',user.partner_id.id)] diff --git a/addons/portal_project_issue/security/portal_security.xml b/addons/portal_project_issue/security/portal_security.xml index 4ef8da5e4b6..3ba6f773a57 100644 --- a/addons/portal_project_issue/security/portal_security.xml +++ b/addons/portal_project_issue/security/portal_security.xml @@ -5,7 +5,7 @@ Portal Personal Issues - [('partner_id','child_of',user.partner_id.id)] + [('message_follower_ids','in',user.partner_id.id)] diff --git a/addons/portal_sale/security/portal_security.xml b/addons/portal_sale/security/portal_security.xml index f69fd283db6..db82dc7b599 100644 --- a/addons/portal_sale/security/portal_security.xml +++ b/addons/portal_sale/security/portal_security.xml @@ -6,42 +6,42 @@ Portal Personal Quotations/Sales Orders - [('partner_id','child_of',user.partner_id.id)] + [('message_follower_ids','in',user.partner_id.id)] Portal Personal Delivery Orders - [('partner_id','child_of',[user.partner_id.id])] + [('message_follower_ids','in',user.partner_id.id)] Portal Personal Delivery Orders Out - [('partner_id','child_of',[user.partner_id.id])] + [('message_follower_ids','in',user.partner_id.id)] Portal Personal Account Invoices - [('partner_id','child_of',user.partner_id.id)] + [('message_follower_ids','in',user.partner_id.id)] Portal Personal Payments - [('partner_id','child_of',user.partner_id.id)] + [('message_follower_ids','in',user.partner_id.id)] Portal Personal Contacts - [('id','child_of',user.partner_id.id)] + [('message_follower_ids','in',user.partner_id.id)] diff --git a/addons/project_issue/project_issue_demo.xml b/addons/project_issue/project_issue_demo.xml index 0a4eee3067b..9759d15dabb 100644 --- a/addons/project_issue/project_issue_demo.xml +++ b/addons/project_issue/project_issue_demo.xml @@ -31,7 +31,7 @@ - + 3 From f6ed42db867fdad6da59a5b348b603793a59803b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 13 Sep 2012 19:05:00 +0200 Subject: [PATCH 04/44] [WIP] [FIX] mail: fixing access rights + related tests. WIP, already fixed mail.group and mail.alias, not readable by anonymous not-employee users. bzr revid: tde@openerp.com-20120913170500-um93rzw0nq6njl39 --- addons/mail/mail_message.py | 49 ++++++++++++---- addons/mail/security/ir.model.access.csv | 2 + addons/mail/tests/test_mail.py | 73 ++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 11 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 44ce76b94b0..cec3b89d9b6 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -24,6 +24,7 @@ import openerp import tools from email.header import decode_header +from openerp import SUPERUSER_ID from operator import itemgetter from osv import osv, fields from tools.translate import _ @@ -138,7 +139,8 @@ class mail_message(osv.Model): return [] def _get_default_author(self, cr, uid, context=None): - return self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id + # remove context to avoid possible hack in browse with superadmin using context keys that could trigger a specific behavior + return self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=None).partner_id.id _defaults = { 'type': 'email', @@ -274,15 +276,40 @@ class mail_message(osv.Model): if isinstance(ids, (int, long)): ids = [ids] - # check messages for which you have a notification - partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id - not_obj = self.pool.get('mail.notification') - not_ids = not_obj.search(cr, uid, [ - ('partner_id', '=', partner_id), - ('message_id', 'in', ids), - ], context=context) - notified_ids = [notification.message_id.id for notification in not_obj.browse(cr, uid, not_ids, context=context) - if notification.message_id.id in ids] + # Rights + # - read: if + # - notification exist (I receive pushed message) OR + # - author_id = pid (I am the author) OR + # - I can read the related document + # - create: if + # - I can write on the related document OR + # - I am in the document message_follower_ids + # - write: if + # - I can write on the related document + # - unlink: if + # - I can write on the related document + # + + if operation != 'read': + notified_ids = [] + author_ids = [] + else: + # read: check for notifications + partner_id = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=None).partner_id.id + not_obj = self.pool.get('mail.notification') + not_ids = not_obj.search(cr, uid, [ + ('partner_id', '=', partner_id), + ('message_id', 'in', ids), + ], context=context) + notified_ids = [notification.message_id.id for notification in not_obj.browse(cr, uid, not_ids, context=context)] + + # read: check messages you are author + author_ids = self.search(cr, uid, [('author_id', '=', partner_id), ('id', 'in', ids)], context=context) + + # if operation != 'create': + # follower_ids = [] + # else: + # write: check I am in the document followers # check messages linked to an existing document model_record_ids = {} @@ -300,7 +327,7 @@ class mail_message(osv.Model): model_obj.check_access_rule(cr, uid, mids, operation, context=context) # fall back on classic operation for other ids - other_ids = set(ids).difference(set(notified_ids), set(document_ids)) + other_ids = set(ids).difference(set(notified_ids), set(document_ids), set(author_ids)) super(mail_message, self).check_access_rule(cr, uid, other_ids, operation, context=None) def create(self, cr, uid, values, context=None): diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv index c89c60756bd..e4f6faf735d 100644 --- a/addons/mail/security/ir.model.access.csv +++ b/addons/mail/security/ir.model.access.csv @@ -5,6 +5,8 @@ access_mail_mail_all,mail.mail.all,model_mail_mail,,1,1,1,1 access_mail_thread,mail.thread,model_mail_thread,base.group_user,1,1,1,0 access_mail_followers_all,mail.followers.all,model_mail_followers,,1,1,1,1 access_mail_notification_all,mail.notification.all,model_mail_notification,,1,1,1,1 +access_mail_group_all,mail.group.all,model_mail_group,,1,0,0,0 access_mail_group,mail.group,model_mail_group,base.group_user,1,1,1,1 +access_mail_alias_all,mail.alias.all,model_mail_alias,,1,0,0,0 access_mail_alias_user,mail.alias,model_mail_alias,base.group_user,1,1,1,0 access_mail_alias_system,mail.alias,model_mail_alias,base.group_system,1,1,1,1 diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py index 1fab5dd1732..01646b6ad43 100644 --- a/addons/mail/tests/test_mail.py +++ b/addons/mail/tests/test_mail.py @@ -23,6 +23,7 @@ import tools from openerp.tests import common from openerp.tools.html_sanitize import html_sanitize +from osv.orm import except_orm MAIL_TEMPLATE = """Return-Path: To: {to} @@ -276,6 +277,78 @@ class test_mail(TestMailMockups): follower_ids = [follower.id for follower in group_pigs.message_follower_ids] self.assertEqual(follower_ids, [user_admin.partner_id.id], 'Admin must be the only Pigs fan') + def test_15_access_rights(self): + cr, uid = self.cr, self.uid + self.res_groups = self.registry('res.groups') + + self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message') + + # Find Employee group + group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user') + group_employee_id = group_employee_ref and group_employee_ref[1] or False + group_employee = self.res_groups.browse(cr, uid, group_employee_id) + + self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'}) + + user_bert_id = self.res_users.create(cr, uid, {'name': 'Bert Tartopoils', 'login': 'bert', 'groups_id': [(6, 0, [])]}) + user_raoul_id = self.res_users.create(cr, uid, {'name': 'Raoul Grosbedon', 'login': 'raoul', 'groups_id': [(6, 0, [group_employee_id])]}) + + user_bert = self.res_users.browse(cr, uid, user_bert_id) + user_raoul = self.res_users.browse(cr, uid, user_raoul_id) + + print '-----' + for group in user_bert.groups_id: + print group.name + print '-----' + for group in user_raoul.groups_id: + print group.name + + # Summary + # group_pigs: groups (Employee) + # group_jobs: public + + # ---------------------------------------- + # CASE1: Bert, without groups + # ---------------------------------------- + + # Do: Bert creates a group, should crash because perm_create only for employees + self.assertRaises(except_orm, + self.mail_group.create, + cr, user_bert_id, {'name': 'Bert\'s Group'}) + # Do: Bert reads Jobs basic fields, ok because public = read access on the group + self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['name', 'description']) + # Do: Bert reads Jobs messages, ok because read access on the group = read access on its messages + jobs_message_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_ids'])['message_ids'] + self.mail_message.read(cr, user_bert_id, jobs_message_ids) + # Do: Bert reads Jobs followers, ko because partner are accessible to employees or partner manager + jobs_followers_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_follower_ids'])['message_follower_ids'] + self.assertRaises(except_orm, + self.res_partner.read, + cr, user_bert_id, jobs_followers_ids) + # Do: Bert comments Jobs, ko because not write access on the group and not in the followers + self.assertRaises(except_orm, + self.mail_group.message_post, + cr, user_bert_id, self.group_jobs_id, body='I love Pigs') + + # Do: Bert reads Pigs, should crash because mail.group security=groups only for employee group + self.assertRaises(except_orm, + self.mail_group.read, + cr, user_bert_id, self.group_pigs_id) + + # Do: add Bert to jobs followers + self.mail_group.message_subscribe(cr, uid, [self.group_pigs_id], [user_bert.partner_id.id]) + # Do: Bert comments Jobs, ok because he is in the followers + self.mail_group.message_post(cr, user_bert_id, self.group_jobs_id, body='I love Pigs') + + # ---------------------------------------- + # CASE1: Raoul, employee + # ---------------------------------------- + + # Do: Bert read Jobs, ok because public + self.mail_group.read(cr, user_raoul_id, self.group_pigs_id) + # Do: Bert read Jobs, ok because public + self.mail_group.read(cr, user_raoul_id, self.group_jobs_id) + def test_20_message_post(self): """ Tests designed for message_post. """ cr, uid = self.cr, self.uid From 9a9a56fa490a8f05991f0182a73daee14048d773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 14 Sep 2012 13:51:07 +0200 Subject: [PATCH 05/44] [WIP] [FIX] mail: fixing access rights: second turn of update. bzr revid: tde@openerp.com-20120914115107-mtgu8soy3ck5xgir --- addons/mail/mail_followers.py | 3 +- addons/mail/mail_mail.py | 8 +- addons/mail/mail_message.py | 126 +++++++++++++++-------- addons/mail/security/ir.model.access.csv | 14 +-- 4 files changed, 94 insertions(+), 57 deletions(-) diff --git a/addons/mail/mail_followers.py b/addons/mail/mail_followers.py index b8f6c21ecf5..23417850f2a 100644 --- a/addons/mail/mail_followers.py +++ b/addons/mail/mail_followers.py @@ -19,6 +19,7 @@ # ############################################################################## +from openerp import SUPERUSER_ID from osv import osv from osv import fields import tools @@ -91,7 +92,7 @@ class mail_notification(osv.Model): :param browse_record message: mail.message to notify """ notify_pids = [] - for partner in self.pool.get('res.partner').browse(cr, uid, partner_ids, context=context): + for partner in self.pool.get('res.partner').browse(cr, SUPERUSER_ID, partner_ids, context=context): # Do not send an email to the writer if partner.user_ids and partner.user_ids[0].id == uid: continue diff --git a/addons/mail/mail_mail.py b/addons/mail/mail_mail.py index 6bbfa9bc30e..e9a569a8192 100644 --- a/addons/mail/mail_mail.py +++ b/addons/mail/mail_mail.py @@ -19,13 +19,12 @@ # ############################################################################## -# import ast import base64 import logging import tools -from osv import osv -from osv import fields +from openerp import SUPERUSER_ID +from osv import osv, fields from tools.translate import _ _logger = logging.getLogger(__name__) @@ -134,7 +133,8 @@ class mail_mail(osv.Model): :return: True """ if mail.auto_delete: - mail.unlink() + # done with SUPERUSER_ID to avoid giving large unlink access rights + self.unlink(cr, SUPERUSER_ID, [mail.id], context=context) return True def send_get_mail_subject(self, cr, uid, mail, force=False, partner=None, context=None): diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index cec3b89d9b6..39145d3534b 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -27,6 +27,7 @@ from email.header import decode_header from openerp import SUPERUSER_ID from operator import itemgetter from osv import osv, fields +from osv.orm import except_orm from tools.translate import _ _logger = logging.getLogger(__name__) @@ -269,65 +270,100 @@ class mail_message(osv.Model): cr.execute("""CREATE INDEX mail_message_model_res_id_idx ON mail_message (model, res_id)""") def check_access_rule(self, cr, uid, ids, operation, context=None): - """ mail.message access rule check - - message received (a notification exists) -> ok - - check rules of related document if exists - - fallback on normal mail.message check """ + """ Access rules of mail.message: + - read: if + - notification exist (I receive pushed message) OR + - author_id = pid (I am the author) OR + - I can read the related document if res_model, res_id + - Otherwise: raise + - create: if + - I am in the document message_follower_ids OR + - I can write on the related document if res_model, res_id + - Otherwise: raise + - write: if + - I can write on the related document if res_model, res_id + - Otherwise: raise + - unlink: if + - I can write on the related document if res_model, res_id + - Otherwise: raise + """ + if uid == SUPERUSER_ID: + return if isinstance(ids, (int, long)): ids = [ids] + print 'check-access-rule', uid, ids, operation, context - # Rights - # - read: if - # - notification exist (I receive pushed message) OR - # - author_id = pid (I am the author) OR - # - I can read the related document - # - create: if - # - I can write on the related document OR - # - I am in the document message_follower_ids - # - write: if - # - I can write on the related document - # - unlink: if - # - I can write on the related document - # + # Read mail_message.ids to have their values + model_record_ids = {} + message_values = dict.fromkeys(ids) + cr.execute('SELECT DISTINCT id, model, res_id, author_id FROM mail_message WHERE id = ANY (%s)', (ids,)) + for id, rmod, rid, author_id in cr.fetchall(): + message_values[id] = {'res_model': rmod, 'res_id': rid, 'author_id': author_id} + model_record_ids.setdefault(rmod, set()).add(rid) - if operation != 'read': - notified_ids = [] - author_ids = [] - else: - # read: check for notifications - partner_id = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=None).partner_id.id + partner_id = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=None).partner_id.id + + # R: Check for received notifications -> could become an ir.rule + if operation == 'read': not_obj = self.pool.get('mail.notification') - not_ids = not_obj.search(cr, uid, [ + not_ids = not_obj.search(cr, SUPERUSER_ID, [ ('partner_id', '=', partner_id), ('message_id', 'in', ids), ], context=context) - notified_ids = [notification.message_id.id for notification in not_obj.browse(cr, uid, not_ids, context=context)] + notified_ids = [notification.message_id.id for notification in not_obj.browse(cr, SUPERUSER_ID, not_ids, context=context)] + else: + notified_ids = [] + # R: Check messages you are author -> could become an ir.rule + if operation == 'read': + author_ids = [mid for mid, message in message_values.iteritems() + if message.get('author_id') and message.get('author_id') == partner_id] + else: + author_ids = [] - # read: check messages you are author - author_ids = self.search(cr, uid, [('author_id', '=', partner_id), ('id', 'in', ids)], context=context) + # C: Check message_follower_ids + if operation == 'create': + doc_follower_ids = [] + for model, mids in model_record_ids.items(): + fol_obj = self.pool.get('mail.followers') + fol_ids = fol_obj.search(cr, SUPERUSER_ID, [ + ('res_model', '=', model), + ('res_id', 'in', list(mids)), + ('partner_id', '=', partner_id), + ], context=context) + fol_mids = [follower.res_id for follower in fol_obj.browse(cr, SUPERUSER_ID, fol_ids, context=context)] + doc_follower_ids += [mid for mid, message in message_values.iteritems() + if message.get('res_model') == model and message.get('res_id') in fol_mids] + else: + doc_follower_ids = [] - # if operation != 'create': - # follower_ids = [] - # else: - # write: check I am in the document followers - - # check messages linked to an existing document + # fall back on classic operation for other ids model_record_ids = {} - document_ids = [] - cr.execute('SELECT DISTINCT id, model, res_id FROM mail_message WHERE id = ANY (%s)', (ids,)) - for id, rmod, rid in cr.fetchall(): - if not (rmod and rid): - continue - document_ids.append(id) - model_record_ids.setdefault(rmod, set()).add(rid) + other_ids = set(ids).difference(set(notified_ids), set(author_ids), set(doc_follower_ids)) + for id in other_ids: + model_record_ids.setdefault(message_values[id]['res_model'], set()).add(message_values[id]['res_id']) + + # CRUD: Access rights related to the document + document_related_ids = [] for model, mids in model_record_ids.items(): model_obj = self.pool.get(model) mids = model_obj.exists(cr, uid, mids) - model_obj.check_access_rights(cr, uid, operation) - model_obj.check_access_rule(cr, uid, mids, operation, context=context) + if operation in ['create', 'write', 'unlink']: + model_obj.check_access_rights(cr, uid, 'write') + model_obj.check_access_rule(cr, uid, mids, 'write', context=context) + else: + model_obj.check_access_rights(cr, uid, operation) + model_obj.check_access_rule(cr, uid, mids, operation, context=context) + document_related_ids += [mid for mid, message in message_values.iteritems() + if message.get('res_model') == model and message.get('res_id') in mids] # fall back on classic operation for other ids - other_ids = set(ids).difference(set(notified_ids), set(document_ids), set(author_ids)) + other_ids = set(ids).difference(set(notified_ids), set(author_ids), set(doc_follower_ids), set(document_related_ids)) + + if other_ids: + raise except_orm(_('Access Denied'), + _('The requested operation cannot be completed due to security restrictions. Please contact your system administrator.\n\n(Document type: %s, Operation: %s)') % \ + (self._description, operation)) + super(mail_message, self).check_access_rule(cr, uid, other_ids, operation, context=None) def create(self, cr, uid, values, context=None): @@ -360,11 +396,11 @@ class mail_message(osv.Model): partners_to_notify |= set(partner.id for partner in message.partner_ids) # add all followers and set add them in partner_ids if message.model and message.res_id: - record = self.pool.get(message.model).browse(cr, uid, message.res_id, context=context) + record = self.pool.get(message.model).browse(cr, SUPERUSER_ID, message.res_id, context=context) extra_notified = set(partner.id for partner in record.message_follower_ids) missing_notified = extra_notified - partners_to_notify if missing_notified: - message.write({'partner_ids': [(4, p_id) for p_id in missing_notified]}) + self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(4, p_id) for p_id in missing_notified]}, context=context) partners_to_notify |= extra_notified self.pool.get('mail.notification').notify(cr, uid, list(partners_to_notify), newid, context=context) diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv index e4f6faf735d..5f7dff49222 100644 --- a/addons/mail/security/ir.model.access.csv +++ b/addons/mail/security/ir.model.access.csv @@ -1,12 +1,12 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_mail_message_all,mail.message.all,model_mail_message,,1,0,0,0 +access_mail_message_all,mail.message.all,model_mail_message,,1,0,1,0 access_mail_message_group_user,mail.message.group.user,model_mail_message,base.group_user,1,1,1,1 -access_mail_mail_all,mail.mail.all,model_mail_mail,,1,1,1,1 -access_mail_thread,mail.thread,model_mail_thread,base.group_user,1,1,1,0 -access_mail_followers_all,mail.followers.all,model_mail_followers,,1,1,1,1 -access_mail_notification_all,mail.notification.all,model_mail_notification,,1,1,1,1 +access_mail_mail_all,mail.mail.all,model_mail_mail,,0,0,1,0 +access_mail_mail_system,mail.mail.system,model_mail_mail,base.group_system,1,1,1,1 +access_mail_followers_all,mail.followers.all,model_mail_followers,,0,0,0,0 +access_mail_notification_all,mail.notification.all,model_mail_notification,,0,0,0,0 access_mail_group_all,mail.group.all,model_mail_group,,1,0,0,0 -access_mail_group,mail.group,model_mail_group,base.group_user,1,1,1,1 +access_mail_group_user,mail.group.user,model_mail_group,base.group_user,1,1,1,1 access_mail_alias_all,mail.alias.all,model_mail_alias,,1,0,0,0 access_mail_alias_user,mail.alias,model_mail_alias,base.group_user,1,1,1,0 -access_mail_alias_system,mail.alias,model_mail_alias,base.group_system,1,1,1,1 +access_mail_alias_system,mail.alias.system,model_mail_alias,base.group_system,1,1,1,1 From 48993e868eb7f88e9af87fb185e961cbe06b375b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 14 Sep 2012 13:58:15 +0200 Subject: [PATCH 06/44] [REF] mail: tests: moved access rights test into a dedicated file. bzr revid: tde@openerp.com-20120914115815-ge6vy4zjxz1fnxfl --- addons/mail/tests/__init__.py | 5 +- addons/mail/tests/test_mail.py | 73 --------------- addons/mail/tests/test_mail_access_rights.py | 98 ++++++++++++++++++++ 3 files changed, 101 insertions(+), 75 deletions(-) create mode 100644 addons/mail/tests/test_mail_access_rights.py diff --git a/addons/mail/tests/__init__.py b/addons/mail/tests/__init__.py index d63c5634cc3..2d48fa233c4 100644 --- a/addons/mail/tests/__init__.py +++ b/addons/mail/tests/__init__.py @@ -18,10 +18,11 @@ # along with this program. If not, see . # ############################################################################## -from . import test_mail +from . import test_mail, test_mail_access_rights checks = [ test_mail, + test_mail_access_rights, ] -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/mail/tests/test_mail.py b/addons/mail/tests/test_mail.py index 01646b6ad43..1fab5dd1732 100644 --- a/addons/mail/tests/test_mail.py +++ b/addons/mail/tests/test_mail.py @@ -23,7 +23,6 @@ import tools from openerp.tests import common from openerp.tools.html_sanitize import html_sanitize -from osv.orm import except_orm MAIL_TEMPLATE = """Return-Path: To: {to} @@ -277,78 +276,6 @@ class test_mail(TestMailMockups): follower_ids = [follower.id for follower in group_pigs.message_follower_ids] self.assertEqual(follower_ids, [user_admin.partner_id.id], 'Admin must be the only Pigs fan') - def test_15_access_rights(self): - cr, uid = self.cr, self.uid - self.res_groups = self.registry('res.groups') - - self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message') - - # Find Employee group - group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user') - group_employee_id = group_employee_ref and group_employee_ref[1] or False - group_employee = self.res_groups.browse(cr, uid, group_employee_id) - - self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'}) - - user_bert_id = self.res_users.create(cr, uid, {'name': 'Bert Tartopoils', 'login': 'bert', 'groups_id': [(6, 0, [])]}) - user_raoul_id = self.res_users.create(cr, uid, {'name': 'Raoul Grosbedon', 'login': 'raoul', 'groups_id': [(6, 0, [group_employee_id])]}) - - user_bert = self.res_users.browse(cr, uid, user_bert_id) - user_raoul = self.res_users.browse(cr, uid, user_raoul_id) - - print '-----' - for group in user_bert.groups_id: - print group.name - print '-----' - for group in user_raoul.groups_id: - print group.name - - # Summary - # group_pigs: groups (Employee) - # group_jobs: public - - # ---------------------------------------- - # CASE1: Bert, without groups - # ---------------------------------------- - - # Do: Bert creates a group, should crash because perm_create only for employees - self.assertRaises(except_orm, - self.mail_group.create, - cr, user_bert_id, {'name': 'Bert\'s Group'}) - # Do: Bert reads Jobs basic fields, ok because public = read access on the group - self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['name', 'description']) - # Do: Bert reads Jobs messages, ok because read access on the group = read access on its messages - jobs_message_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_ids'])['message_ids'] - self.mail_message.read(cr, user_bert_id, jobs_message_ids) - # Do: Bert reads Jobs followers, ko because partner are accessible to employees or partner manager - jobs_followers_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_follower_ids'])['message_follower_ids'] - self.assertRaises(except_orm, - self.res_partner.read, - cr, user_bert_id, jobs_followers_ids) - # Do: Bert comments Jobs, ko because not write access on the group and not in the followers - self.assertRaises(except_orm, - self.mail_group.message_post, - cr, user_bert_id, self.group_jobs_id, body='I love Pigs') - - # Do: Bert reads Pigs, should crash because mail.group security=groups only for employee group - self.assertRaises(except_orm, - self.mail_group.read, - cr, user_bert_id, self.group_pigs_id) - - # Do: add Bert to jobs followers - self.mail_group.message_subscribe(cr, uid, [self.group_pigs_id], [user_bert.partner_id.id]) - # Do: Bert comments Jobs, ok because he is in the followers - self.mail_group.message_post(cr, user_bert_id, self.group_jobs_id, body='I love Pigs') - - # ---------------------------------------- - # CASE1: Raoul, employee - # ---------------------------------------- - - # Do: Bert read Jobs, ok because public - self.mail_group.read(cr, user_raoul_id, self.group_pigs_id) - # Do: Bert read Jobs, ok because public - self.mail_group.read(cr, user_raoul_id, self.group_jobs_id) - def test_20_message_post(self): """ Tests designed for message_post. """ cr, uid = self.cr, self.uid diff --git a/addons/mail/tests/test_mail_access_rights.py b/addons/mail/tests/test_mail_access_rights.py new file mode 100644 index 00000000000..0a7284098bd --- /dev/null +++ b/addons/mail/tests/test_mail_access_rights.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Business Applications +# Copyright (c) 2012-TODAY OpenERP S.A. +# +# 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. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from openerp.addons.mail.tests import test_mail +from osv.orm import except_orm + + +class test_mail_access_rights(test_mail.TestMailMockups): + + def setUp(self): + super(test_mail_access_rights, self).setUp() + self.mail_group = self.registry('mail.group') + self.mail_message = self.registry('mail.message') + self.res_users = self.registry('res.users') + self.res_partner = self.registry('res.partner') + + # create a 'pigs' group that will be used through the various tests + self.group_pigs_id = self.mail_group.create(self.cr, self.uid, + {'name': 'Pigs', 'description': 'Fans of Pigs, unite !'}) + + def test_00_access_rights(self): + cr, uid = self.cr, self.uid + self.res_groups = self.registry('res.groups') + # Prepare groups: Pigs (employee), Jobs (public) + self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message') + self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'}) + + # Find Employee group + group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user') + group_employee_id = group_employee_ref and group_employee_ref[1] or False + group_employee = self.res_groups.browse(cr, uid, group_employee_id) + + # Create Bert (without groups) and Raoul( employee) + user_bert_id = self.res_users.create(cr, uid, {'name': 'Bert Tartopoils', 'login': 'bert', 'groups_id': [(6, 0, [])]}) + user_raoul_id = self.res_users.create(cr, uid, {'name': 'Raoul Grosbedon', 'login': 'raoul', 'groups_id': [(6, 0, [group_employee_id])]}) + user_bert = self.res_users.browse(cr, uid, user_bert_id) + user_raoul = self.res_users.browse(cr, uid, user_raoul_id) + + # ---------------------------------------- + # CASE1: Bert, without groups + # ---------------------------------------- + print 'Bert CASE1' + # Do: Bert creates a group, should crash because perm_create only for employees + self.assertRaises(except_orm, + self.mail_group.create, + cr, user_bert_id, {'name': 'Bert\'s Group'}) + # Do: Bert reads Jobs basic fields, ok because public = read access on the group + self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['name', 'description']) + # Do: Bert reads Jobs messages, ok because read access on the group = read access on its messages + jobs_message_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_ids'])['message_ids'] + self.mail_message.read(cr, user_bert_id, jobs_message_ids) + # Do: Bert reads Jobs followers, ko because partner are accessible to employees or partner manager + jobs_followers_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_follower_ids'])['message_follower_ids'] + self.assertRaises(except_orm, + self.res_partner.read, + cr, user_bert_id, jobs_followers_ids) + # Do: Bert comments Jobs, ko because no write access on the group and not in the followers + self.assertRaises(except_orm, + self.mail_group.message_post, + cr, user_bert_id, self.group_jobs_id, body='I love Pigs') + # Do: add Bert to jobs followers + self.mail_group.message_subscribe(cr, uid, [self.group_jobs_id], [user_bert.partner_id.id]) + # Do: Bert comments Jobs, ok because he is now in the followers + self.mail_group.message_post(cr, user_bert_id, self.group_jobs_id, body='I love Pigs') + # Do: Bert browse Pigs, ok (no direct browse of partners) + self.mail_group.browse(cr, user_bert_id, self.group_jobs_id) + + # Do: Bert reads Pigs, should crash because mail.group security=groups only for employee group + self.assertRaises(except_orm, + self.mail_group.read, + cr, user_bert_id, self.group_pigs_id) + + # ---------------------------------------- + # CASE1: Raoul, employee + # ---------------------------------------- + print 'Raoul CASE1' + # Do: Bert read Jobs, ok because public + self.mail_group.read(cr, user_raoul_id, self.group_pigs_id) + # Do: Bert read Jobs, ok because public + self.mail_group.read(cr, user_raoul_id, self.group_jobs_id) From 2c60cc4d4c1a171eb52887bbb9c316c06a78c437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 14 Sep 2012 13:58:53 +0200 Subject: [PATCH 07/44] [FIX] mail: in message_get_data, notification search for unread messages is done as SUPERUSER, because we need this info but do not want to give access to notications. bzr revid: tde@openerp.com-20120914115853-xsquf25kz4hhzlyf --- addons/mail/mail_thread.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index d798007275f..7af3331d943 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -30,6 +30,7 @@ import xmlrpclib from email.message import Message from mail_message import decode +from openerp import SUPERUSER_ID from osv import osv, fields from tools.safe_eval import safe_eval as eval @@ -120,14 +121,15 @@ class mail_thread(osv.AbstractModel): res = dict((id, dict(message_unread=False, message_summary='')) for id in ids) user = self.pool.get('res.users').browse(cr, uid, uid, context=context) + # search for unread messages, by reading directly mail.notification, as SUPERUSER notif_obj = self.pool.get('mail.notification') - notif_ids = notif_obj.search(cr, uid, [ + notif_ids = notif_obj.search(cr, SUPERUSER_ID, [ ('partner_id.user_ids', 'in', [uid]), ('message_id.res_id', 'in', ids), ('message_id.model', '=', self._name), ('read', '=', False) ], context=context) - for notif in notif_obj.browse(cr, uid, notif_ids, context=context): + for notif in notif_obj.browse(cr, SUPERUSER_ID, notif_ids, context=context): res[notif.message_id.res_id]['message_unread'] = True for thread in self.browse(cr, uid, ids, context=context): From 85fe3bca8efda814c0c7c876aaec1c62ecd52f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 14 Sep 2012 14:20:24 +0200 Subject: [PATCH 08/44] [FIX] mail_group_menu: user->partner_id fetch done as SUPERUSER, because even anonymous people will have to perform a search for menu entries (public groups). bzr revid: tde@openerp.com-20120914122024-1rk8t8ooj33v0aaa --- addons/mail/mail_group_menu.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/addons/mail/mail_group_menu.py b/addons/mail/mail_group_menu.py index 25b85bb7b22..090d1cd00fb 100644 --- a/addons/mail/mail_group_menu.py +++ b/addons/mail/mail_group_menu.py @@ -19,9 +19,10 @@ # ############################################################################## +from openerp import SUPERUSER_ID from osv import osv from osv import fields -from tools.translate import _ + class ir_ui_menu(osv.osv): """ Override of ir.ui.menu class. When adding mail_thread module, each @@ -38,13 +39,14 @@ class ir_ui_menu(osv.osv): def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False): """ Override to take off menu entries (mail.group) the user is not - following. """ + following. Access are done using SUPERUSER_ID to avoid access + rights issues for an internal back-end algorithm. """ ids = super(ir_ui_menu, self).search(cr, uid, args, offset=0, limit=None, order=order, context=context, count=False) - partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id + partner_id = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context).partner_id.id follower_obj = self.pool.get('mail.followers') for menu in self.browse(cr, uid, ids, context=context): if menu.mail_group_id: - sub_ids = follower_obj.search(cr, uid, [ + sub_ids = follower_obj.search(cr, SUPERUSER_ID, [ ('partner_id', '=', partner_id), ('res_model', '=', 'mail.group'), ('res_id', '=', menu.mail_group_id.id) ], context=context) From 2909c507af21c380b56eab2895417653cb24530a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 14 Sep 2012 14:21:39 +0200 Subject: [PATCH 09/44] [FIX] mail_message: message_read evaluates the message domain as SUPERUSER (because even anonymous people will have a wall, and therefore evaluate notifications.partner_id.users_ids). bzr revid: tde@openerp.com-20120914122139-dv1xlinpgvd4dw7g --- addons/mail/mail_message.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 39145d3534b..35703e790f5 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -222,7 +222,7 @@ class mail_message(osv.Model): limit = limit or self._message_read_limit context = context or {} if not ids: - ids = self.search(cr, uid, domain, context=context, limit=limit) + ids = self.search(cr, SUPERUSER_ID, domain, context=context, limit=limit) messages = self.browse(cr, uid, ids, context=context) result = [] From 994441ae4a2af6d55248d431682ce64cd943e2a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 14 Sep 2012 15:52:45 +0200 Subject: [PATCH 10/44] [FIX] mail_thread: copy do not copy messages and followers. bzr revid: tde@openerp.com-20120914135245-roldmjl5x8tqlood --- addons/mail/mail_thread.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 7af3331d943..88f7246a1ff 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -121,7 +121,7 @@ class mail_thread(osv.AbstractModel): res = dict((id, dict(message_unread=False, message_summary='')) for id in ids) user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - # search for unread messages, by reading directly mail.notification, as SUPERUSER + # search for unread messages, by reading directly mail.notification, as SUPERUSER notif_obj = self.pool.get('mail.notification') notif_ids = notif_obj.search(cr, SUPERUSER_ID, [ ('partner_id.user_ids', 'in', [uid]), @@ -198,6 +198,13 @@ class mail_thread(osv.AbstractModel): fol_obj.unlink(cr, uid, fol_ids, context=context) return super(mail_thread, self).unlink(cr, uid, ids, context=context) + def copy(self, cr, uid, id, default=None, context=None): + default = default or {} + default['message_ids'] = [] + default['message_comment_ids'] = [] + default['message_follower_ids'] = [] + return super(mail_thread, self).copy(cr, uid, id, default=default, context=context) + #------------------------------------------------------ # mail.message wrappers and tools #------------------------------------------------------ From 40215cd64afe59339e43bc901d0e3086373ec727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 14 Sep 2012 16:18:49 +0200 Subject: [PATCH 11/44] [REM] mail: removed unnecessary group and category for mail_manager. bzr revid: tde@openerp.com-20120914141849-i10vo6zjhclvgpu9 --- addons/mail/security/mail_security.xml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/addons/mail/security/mail_security.xml b/addons/mail/security/mail_security.xml index a12314e6f25..632b43754f8 100644 --- a/addons/mail/security/mail_security.xml +++ b/addons/mail/security/mail_security.xml @@ -2,20 +2,6 @@ - - - Social and Sharing Tools - - 26 - - - - - Mail manager - - - - Mail.group: access only public and joined groups From fa5d90e46aee2b66a9e2ab936ed36cdf7bbbcdf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 14 Sep 2012 16:19:22 +0200 Subject: [PATCH 12/44] [IMP] mail: security: added all access for system group on mail.notification and mail.followers. bzr revid: tde@openerp.com-20120914141922-it1c4df7k72y8vsq --- addons/mail/security/ir.model.access.csv | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv index 5f7dff49222..b5b46acfcfa 100644 --- a/addons/mail/security/ir.model.access.csv +++ b/addons/mail/security/ir.model.access.csv @@ -4,7 +4,9 @@ access_mail_message_group_user,mail.message.group.user,model_mail_message,base.g access_mail_mail_all,mail.mail.all,model_mail_mail,,0,0,1,0 access_mail_mail_system,mail.mail.system,model_mail_mail,base.group_system,1,1,1,1 access_mail_followers_all,mail.followers.all,model_mail_followers,,0,0,0,0 +access_mail_followers_system,mail.followers.system,model_mail_followers,base.group_system,1,1,1,1 access_mail_notification_all,mail.notification.all,model_mail_notification,,0,0,0,0 +access_mail_notification_aystem,mail.notification.system,model_mail_notification,base.group_system,1,1,1,1 access_mail_group_all,mail.group.all,model_mail_group,,1,0,0,0 access_mail_group_user,mail.group.user,model_mail_group,base.group_user,1,1,1,1 access_mail_alias_all,mail.alias.all,model_mail_alias,,1,0,0,0 From 708d76885721959a13715173be3c12407a1aa99e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 14 Sep 2012 16:19:55 +0200 Subject: [PATCH 13/44] [FIX] auth_signup: fixed duplicate xml_id, causing troubles when installing portal. bzr revid: tde@openerp.com-20120914141955-h1lvs2g5thz9urlo --- addons/auth_signup/auth_signup_data.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/auth_signup/auth_signup_data.xml b/addons/auth_signup/auth_signup_data.xml index 4a6bf9ae4b9..2ad868362b5 100644 --- a/addons/auth_signup/auth_signup_data.xml +++ b/addons/auth_signup/auth_signup_data.xml @@ -13,7 +13,7 @@ - + auth_signup.template_user_id From f641508fe31bd359075992262c48ef80700a6c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 14 Sep 2012 18:16:33 +0200 Subject: [PATCH 14/44] [FIX] mail_message: fixed check_access_rule and misc acces issues. bzr revid: tde@openerp.com-20120914161633-bpg65bl6i0wxu8k2 --- addons/mail/mail_message.py | 53 +++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 35703e790f5..ffaabf7c8f7 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -71,7 +71,7 @@ class mail_message(osv.Model): def _get_unread(self, cr, uid, ids, name, arg, context=None): """ Compute if the message is unread by the current user. """ res = dict((id, {'unread': False}) for id in ids) - partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id + partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] notif_obj = self.pool.get('mail.notification') notif_ids = notif_obj.search(cr, uid, [ ('partner_id', 'in', [partner_id]), @@ -156,10 +156,11 @@ class mail_message(osv.Model): def _message_dict_get(self, cr, uid, msg, context=None): """ Return a dict representation of the message browse record. """ - attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, uid, [x.id for x in msg.attachment_ids], context=context)] - author_id = self.pool.get('res.partner').name_get(cr, uid, [msg.author_id.id], context=context)[0] - author_user_id = self.pool.get('res.users').name_get(cr, uid, [msg.author_id.user_ids[0].id], context=context)[0] - partner_ids = self.pool.get('res.partner').name_get(cr, uid, [x.id for x in msg.partner_ids], context=context) + # TDE TEMP: use SUPERUSER_ID + attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, SUPERUSER_ID, [x.id for x in msg.attachment_ids], context=context)] + author_id = self.pool.get('res.partner').name_get(cr, SUPERUSER_ID, [msg.author_id.id], context=context)[0] + author_user_id = self.pool.get('res.users').name_get(cr, SUPERUSER_ID, [msg.author_id.user_ids[0].id], context=context)[0] + partner_ids = self.pool.get('res.partner').name_get(cr, SUPERUSER_ID, [x.id for x in msg.partner_ids], context=context) return { 'id': msg.id, 'type': msg.type, @@ -291,7 +292,7 @@ class mail_message(osv.Model): return if isinstance(ids, (int, long)): ids = [ids] - print 'check-access-rule', uid, ids, operation, context + partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=None)['partner_id'][0] # Read mail_message.ids to have their values model_record_ids = {} @@ -299,11 +300,10 @@ class mail_message(osv.Model): cr.execute('SELECT DISTINCT id, model, res_id, author_id FROM mail_message WHERE id = ANY (%s)', (ids,)) for id, rmod, rid, author_id in cr.fetchall(): message_values[id] = {'res_model': rmod, 'res_id': rid, 'author_id': author_id} - model_record_ids.setdefault(rmod, set()).add(rid) + if rmod: + model_record_ids.setdefault(rmod, set()).add(rid) - partner_id = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=None).partner_id.id - - # R: Check for received notifications -> could become an ir.rule + # Read: Check for received notifications -> could become an ir.rule, but not till we do not have a many2one variable field if operation == 'read': not_obj = self.pool.get('mail.notification') not_ids = not_obj.search(cr, SUPERUSER_ID, [ @@ -313,14 +313,14 @@ class mail_message(osv.Model): notified_ids = [notification.message_id.id for notification in not_obj.browse(cr, SUPERUSER_ID, not_ids, context=context)] else: notified_ids = [] - # R: Check messages you are author -> could become an ir.rule + # Read: Check messages you are author -> could become an ir.rule, but not till we do not have a many2one variable field if operation == 'read': author_ids = [mid for mid, message in message_values.iteritems() if message.get('author_id') and message.get('author_id') == partner_id] else: author_ids = [] - # C: Check message_follower_ids + # Create: Check message_follower_ids if operation == 'create': doc_follower_ids = [] for model, mids in model_record_ids.items(): @@ -332,15 +332,16 @@ class mail_message(osv.Model): ], context=context) fol_mids = [follower.res_id for follower in fol_obj.browse(cr, SUPERUSER_ID, fol_ids, context=context)] doc_follower_ids += [mid for mid, message in message_values.iteritems() - if message.get('res_model') == model and message.get('res_id') in fol_mids] + if message.get('res_model') == model and message.get('res_id') in fol_mids] else: doc_follower_ids = [] - # fall back on classic operation for other ids + # Calculate remaining ids, and related model/res_ids model_record_ids = {} other_ids = set(ids).difference(set(notified_ids), set(author_ids), set(doc_follower_ids)) for id in other_ids: - model_record_ids.setdefault(message_values[id]['res_model'], set()).add(message_values[id]['res_id']) + if message_values[id]['res_model']: + model_record_ids.setdefault(message_values[id]['res_model'], set()).add(message_values[id]['res_id']) # CRUD: Access rights related to the document document_related_ids = [] @@ -356,15 +357,13 @@ class mail_message(osv.Model): document_related_ids += [mid for mid, message in message_values.iteritems() if message.get('res_model') == model and message.get('res_id') in mids] - # fall back on classic operation for other ids + # Calculate remaining ids: if not void, raise an error other_ids = set(ids).difference(set(notified_ids), set(author_ids), set(doc_follower_ids), set(document_related_ids)) - - if other_ids: - raise except_orm(_('Access Denied'), - _('The requested operation cannot be completed due to security restrictions. Please contact your system administrator.\n\n(Document type: %s, Operation: %s)') % \ - (self._description, operation)) - - super(mail_message, self).check_access_rule(cr, uid, other_ids, operation, context=None) + if not other_ids: + return + raise except_orm(_('Access Denied'), + _('The requested operation cannot be completed due to security restrictions. Please contact your system administrator.\n\n(Document type: %s, Operation: %s)') % \ + (self._description, operation)) def create(self, cr, uid, values, context=None): if not values.get('message_id') and values.get('res_id') and values.get('model'): @@ -373,6 +372,14 @@ class mail_message(osv.Model): self.notify(cr, uid, newid, context=context) return newid + def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'): + """ Override to explicitely call check_access_rule, that is not called + by the ORM. It instead directly fetches ir.rules and apply them. """ + res = super(mail_message, self).read(cr, uid, ids, fields=fields, context=context, load=load) + # print '-->', res + self.check_access_rule(cr, uid, ids, 'read', context=context) + return res + def unlink(self, cr, uid, ids, context=None): # cascade-delete attachments that are directly attached to the message (should only happen # for mail.messages that act as parent for a standalone mail.mail record). From 55ec1211c040f250bd2af4d6ea7209a3b5a32ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 14 Sep 2012 18:16:57 +0200 Subject: [PATCH 15/44] [FIX] mail: security: added read access on notifications. bzr revid: tde@openerp.com-20120914161657-bst7gz4d3er1i2rl --- addons/mail/security/ir.model.access.csv | 2 +- addons/mail/security/mail_security.xml | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv index b5b46acfcfa..cc6a934956f 100644 --- a/addons/mail/security/ir.model.access.csv +++ b/addons/mail/security/ir.model.access.csv @@ -5,7 +5,7 @@ access_mail_mail_all,mail.mail.all,model_mail_mail,,0,0,1,0 access_mail_mail_system,mail.mail.system,model_mail_mail,base.group_system,1,1,1,1 access_mail_followers_all,mail.followers.all,model_mail_followers,,0,0,0,0 access_mail_followers_system,mail.followers.system,model_mail_followers,base.group_system,1,1,1,1 -access_mail_notification_all,mail.notification.all,model_mail_notification,,0,0,0,0 +access_mail_notification_all,mail.notification.all,model_mail_notification,,1,0,0,0 access_mail_notification_aystem,mail.notification.system,model_mail_notification,base.group_system,1,1,1,1 access_mail_group_all,mail.group.all,model_mail_group,,1,0,0,0 access_mail_group_user,mail.group.user,model_mail_group,base.group_user,1,1,1,1 diff --git a/addons/mail/security/mail_security.xml b/addons/mail/security/mail_security.xml index 632b43754f8..7da03664b82 100644 --- a/addons/mail/security/mail_security.xml +++ b/addons/mail/security/mail_security.xml @@ -10,5 +10,15 @@ ['|', '|', ('public', '=', 'public'), ('message_follower_ids', 'in', [user.id]), '&', ('public','=','groups'), ('group_public_id','in', [x.id for x in user.groups_id])] + + + From ee84313321b12d38a46a0f89c5519ec63442fd5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 14 Sep 2012 18:17:37 +0200 Subject: [PATCH 16/44] [IMP] mail: improved test about access rights. Still WIP. bzr revid: tde@openerp.com-20120914161737-3tpf6g0clzfq1fur --- addons/mail/tests/test_mail_access_rights.py | 94 ++++++++++++++++---- 1 file changed, 75 insertions(+), 19 deletions(-) diff --git a/addons/mail/tests/test_mail_access_rights.py b/addons/mail/tests/test_mail_access_rights.py index 0a7284098bd..31e99b53930 100644 --- a/addons/mail/tests/test_mail_access_rights.py +++ b/addons/mail/tests/test_mail_access_rights.py @@ -27,44 +27,103 @@ class test_mail_access_rights(test_mail.TestMailMockups): def setUp(self): super(test_mail_access_rights, self).setUp() + cr, uid = self.cr, self.uid self.mail_group = self.registry('mail.group') self.mail_message = self.registry('mail.message') + self.mail_notification = self.registry('mail.notification') self.res_users = self.registry('res.users') + self.res_groups = self.registry('res.groups') self.res_partner = self.registry('res.partner') # create a 'pigs' group that will be used through the various tests self.group_pigs_id = self.mail_group.create(self.cr, self.uid, {'name': 'Pigs', 'description': 'Fans of Pigs, unite !'}) - def test_00_access_rights(self): + # Find Employee group + group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user') + self.group_employee_id = group_employee_ref and group_employee_ref[1] or False + + # Create Bert (without groups) and Raoul( employee) + self.user_bert_id = self.res_users.create(cr, uid, {'name': 'Bert Tartopoils', 'login': 'bert', 'groups_id': [(6, 0, [])]}) + self.user_raoul_id = self.res_users.create(cr, uid, {'name': 'Raoul Grosbedon', 'login': 'raoul', 'groups_id': [(6, 0, [self.group_employee_id])]}) + self.user_bert = self.res_users.browse(cr, uid, self.user_bert_id) + self.partner_bert_id = self.user_bert.partner_id.id + self.user_raoul = self.res_users.browse(cr, uid, self.user_raoul_id) + self.partner_raoul_id = self.user_raoul.partner_id.id + + def test_00_mail_message_read_access_rights(self): + """ Test basic mail_message read access rights. """ cr, uid = self.cr, self.uid - self.res_groups = self.registry('res.groups') + partner_bert_id, partner_raoul_id = self.partner_bert_id, self.partner_raoul_id + user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id + # Prepare groups: Pigs (employee), Jobs (public) self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message') self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'}) - # Find Employee group - group_employee_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'group_user') - group_employee_id = group_employee_ref and group_employee_ref[1] or False - group_employee = self.res_groups.browse(cr, uid, group_employee_id) + # ---------------------------------------- + # CASE1: Bert, basic mail.message read access + # ---------------------------------------- - # Create Bert (without groups) and Raoul( employee) - user_bert_id = self.res_users.create(cr, uid, {'name': 'Bert Tartopoils', 'login': 'bert', 'groups_id': [(6, 0, [])]}) - user_raoul_id = self.res_users.create(cr, uid, {'name': 'Raoul Grosbedon', 'login': 'raoul', 'groups_id': [(6, 0, [group_employee_id])]}) - user_bert = self.res_users.browse(cr, uid, user_bert_id) - user_raoul = self.res_users.browse(cr, uid, user_raoul_id) + # Do: create a new mail.message + message_id = self.mail_message.create(cr, uid, {'body': 'My Body'}) + # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc + self.assertRaises(except_orm, self.mail_message.read, + cr, user_bert_id, message_id) + # Do: message is pushed to Bert + notif_id = self.mail_notification.create(cr, uid, {'message_id': message_id, 'partner_id': partner_bert_id}) + # Test: Bert reads the message, ok because notification pushed + self.mail_message.read(cr, user_bert_id, message_id) + # Do: remove notification + self.mail_notification.unlink(cr, uid, notif_id) + # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc + self.assertRaises(except_orm, self.mail_message.read, + cr, self.user_bert_id, message_id) + # Do: Bert is now the author + self.mail_message.write(cr, uid, [message_id], {'author_id': partner_bert_id}) + # Test: Bert reads the message, ok because Bert is the author + self.mail_message.read(cr, user_bert_id, message_id) + # Do: Bert is not the author anymore + self.mail_message.write(cr, uid, [message_id], {'author_id': partner_raoul_id}) + # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc + self.assertRaises(except_orm, self.mail_message.read, + cr, user_bert_id, message_id) + # Do: message is attached to a document Bert can read, Jobs + self.mail_message.write(cr, uid, [message_id], {'model': 'mail.group', 'res_id': self.group_jobs_id}) + # Test: Bert reads the message, ok because linked to a doc he is allowed to read + self.mail_message.read(cr, user_bert_id, message_id) + # Do: message is attached to a document Bert cannot read, Pigs + self.mail_message.write(cr, uid, [message_id], {'model': 'mail.group', 'res_id': self.group_pigs_id}) + # Test: Bert reads the message, crash because not notification/not in doc followers/not read on doc + self.assertRaises(except_orm, self.mail_message.read, + cr, user_bert_id, message_id) + + def test_05_mail_message_search_access_rights(self): + """ Test mail_message search override about access rights. """ + self.assertTrue(1 == 0, 'Test not implemented') + + def test_10_mail_flow_access_rights(self): + """ Test a Chatter-looks alike flow. """ + cr, uid = self.cr, self.uid + partner_bert_id, partner_raoul_id = self.partner_bert_id, self.partner_raoul_id + user_bert_id, user_raoul_id = self.user_bert_id, self.user_raoul_id + + # Prepare groups: Pigs (employee), Jobs (public) + self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message') + self.group_jobs_id = self.mail_group.create(cr, uid, {'name': 'Jobs', 'public': 'public'}) # ---------------------------------------- # CASE1: Bert, without groups # ---------------------------------------- - print 'Bert CASE1' # Do: Bert creates a group, should crash because perm_create only for employees self.assertRaises(except_orm, self.mail_group.create, cr, user_bert_id, {'name': 'Bert\'s Group'}) # Do: Bert reads Jobs basic fields, ok because public = read access on the group self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['name', 'description']) - # Do: Bert reads Jobs messages, ok because read access on the group = read access on its messages + # Do: Bert browse Pigs, ok (no direct browse of partners) + self.mail_group.browse(cr, user_bert_id, self.group_jobs_id) + # Do: Bert reads Jobs messages, ok because read access on the group => read access on its messages jobs_message_ids = self.mail_group.read(cr, user_bert_id, self.group_jobs_id, ['message_ids'])['message_ids'] self.mail_message.read(cr, user_bert_id, jobs_message_ids) # Do: Bert reads Jobs followers, ko because partner are accessible to employees or partner manager @@ -77,11 +136,9 @@ class test_mail_access_rights(test_mail.TestMailMockups): self.mail_group.message_post, cr, user_bert_id, self.group_jobs_id, body='I love Pigs') # Do: add Bert to jobs followers - self.mail_group.message_subscribe(cr, uid, [self.group_jobs_id], [user_bert.partner_id.id]) + self.mail_group.message_subscribe(cr, uid, [self.group_jobs_id], [partner_bert_id]) # Do: Bert comments Jobs, ok because he is now in the followers self.mail_group.message_post(cr, user_bert_id, self.group_jobs_id, body='I love Pigs') - # Do: Bert browse Pigs, ok (no direct browse of partners) - self.mail_group.browse(cr, user_bert_id, self.group_jobs_id) # Do: Bert reads Pigs, should crash because mail.group security=groups only for employee group self.assertRaises(except_orm, @@ -91,8 +148,7 @@ class test_mail_access_rights(test_mail.TestMailMockups): # ---------------------------------------- # CASE1: Raoul, employee # ---------------------------------------- - print 'Raoul CASE1' - # Do: Bert read Jobs, ok because public + # Do: Bert read Pigs, ok because public self.mail_group.read(cr, user_raoul_id, self.group_pigs_id) - # Do: Bert read Jobs, ok because public + # Do: Bert read Jobs, ok because group_public_id = employee self.mail_group.read(cr, user_raoul_id, self.group_jobs_id) From 3f63690a5a57120199e853d1b0dc83a0f12d5bc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 17 Sep 2012 11:51:10 +0200 Subject: [PATCH 17/44] [FIX] mail_message: in a search of function field on mail.message, replaced a browse by a read, to avoid access rights issues (user.partner_id). bzr revid: tde@openerp.com-20120917095110-w5lxoykyrk3aa3yf --- addons/mail/mail_message.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index ffaabf7c8f7..d2bafcac826 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -89,7 +89,7 @@ class mail_message(osv.Model): read_cond = '(read = false or read is null)' else: read_cond = 'read = true' - partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id + partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] cr.execute("SELECT message_id FROM mail_notification "\ "WHERE partner_id = %%s AND %s" % read_cond, (partner_id,)) @@ -157,10 +157,14 @@ class mail_message(osv.Model): def _message_dict_get(self, cr, uid, msg, context=None): """ Return a dict representation of the message browse record. """ # TDE TEMP: use SUPERUSER_ID - attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, SUPERUSER_ID, [x.id for x in msg.attachment_ids], context=context)] - author_id = self.pool.get('res.partner').name_get(cr, SUPERUSER_ID, [msg.author_id.id], context=context)[0] - author_user_id = self.pool.get('res.users').name_get(cr, SUPERUSER_ID, [msg.author_id.user_ids[0].id], context=context)[0] - partner_ids = self.pool.get('res.partner').name_get(cr, SUPERUSER_ID, [x.id for x in msg.partner_ids], context=context) + # attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, SUPERUSER_ID, [x.id for x in msg.attachment_ids], context=context)] + attachment_ids = [] + # author_id = self.pool.get('res.partner').name_get(cr, SUPERUSER_ID, [msg.author_id.id], context=context)[0] + author_id = False + # author_user_id = self.pool.get('res.users').name_get(cr, SUPERUSER_ID, [msg.author_id.user_ids[0].id], context=context)[0] + author_user_id = False + # partner_ids = self.pool.get('res.partner').name_get(cr, SUPERUSER_ID, [x.id for x in msg.partner_ids], context=context) + partner_ids = [] return { 'id': msg.id, 'type': msg.type, From 418b35c33b0ae33aedc14ca9b48ef8629ec02677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 17 Sep 2012 11:52:03 +0200 Subject: [PATCH 18/44] [FIX] Porta: fixed access rights (removed duplicate of basic access rights, added read rights on res_partner, to see the topbar avatar and group followers). Set news and jobs group as public. bzr revid: tde@openerp.com-20120917095203-3v6q49qk9sxe0b4o --- addons/portal/portal_data.xml | 2 ++ addons/portal/security/ir.model.access.csv | 4 +--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/portal/portal_data.xml b/addons/portal/portal_data.xml index eb06ca656d6..8014519895d 100644 --- a/addons/portal/portal_data.xml +++ b/addons/portal/portal_data.xml @@ -13,6 +13,7 @@ Company's news + @@ -25,6 +26,7 @@ Company's jobs + diff --git a/addons/portal/security/ir.model.access.csv b/addons/portal/security/ir.model.access.csv index 56b3ae5f269..e8ed29dc3cb 100644 --- a/addons/portal/security/ir.model.access.csv +++ b/addons/portal/security/ir.model.access.csv @@ -4,9 +4,7 @@ access_widget_all,access.portal.widget.all,model_res_portal_widget,,1,0,0,0 access_manager,access.portal.manager,model_res_portal,group_portal_manager,1,1,1,1 access_widget_manager,access.portal.widget.manager,model_res_portal_widget,group_portal_manager,1,1,1,1 access_mail_message,mail.message,mail.model_mail_message,group_portal_member,1,0,1,1 -access_mail_message_all,mail.message.all,mail.model_mail_message,group_portal_member,1,0,0,0 access_mail_thread,mail.thread,mail.model_mail_thread,group_portal_member,1,0,0,0 access_mail_followers,mail.followers,mail.model_mail_followers,group_portal_member,1,0,1,1 access_mail_notification,mail.notification,mail.model_mail_notification,group_portal_member,1,0,1,0 -access_mail_group,mail.group,mail.model_mail_group,group_portal_member,1,0,0,0 -access_mail_alias,mail.alias,mail.model_mail_alias,group_portal_member,1,0,0,0 +access_res_partner_portal,res.partner.portal,base.model_res_partner,group_portal_member,1,0,0,0 From 809bf8336ab5f48c131599b2c738f3679b5e292b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 17 Sep 2012 12:07:06 +0200 Subject: [PATCH 19/44] [FIX] Portal: fixed the fix, because public should not be in an eval. bzr revid: tde@openerp.com-20120917100706-lbl7lrkqb6i77w7r --- addons/portal/portal_data.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/portal/portal_data.xml b/addons/portal/portal_data.xml index 8014519895d..aadc7fc5db4 100644 --- a/addons/portal/portal_data.xml +++ b/addons/portal/portal_data.xml @@ -13,7 +13,7 @@ Company's news - + public @@ -26,7 +26,7 @@ Company's jobs - + public From d3e328d3cc4df6066d05bdbb2b79eeb824916c63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 17 Sep 2012 15:48:32 +0200 Subject: [PATCH 20/44] [FIX] Portal: fixed demo portal user, linked to asustek, overriding default values, makign some tests crash. Demo portal user should have its own partner. bzr revid: tde@openerp.com-20120917134832-9t5w8ax3gw3v2y8e --- addons/portal/portal_demo.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/addons/portal/portal_demo.xml b/addons/portal/portal_demo.xml index 1ace02f3d7d..3fedc721bbd 100644 --- a/addons/portal/portal_demo.xml +++ b/addons/portal/portal_demo.xml @@ -9,7 +9,9 @@ portal - + + + demo@portal.wrong.address From 198fd2b12cd6a9e0079752ce2f4f366f9b8e3e26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 17 Sep 2012 15:48:49 +0200 Subject: [PATCH 21/44] [IMP] Portal: removed access on res.partner. bzr revid: tde@openerp.com-20120917134849-ehbv3oq0lhmm19jh --- addons/portal/security/ir.model.access.csv | 1 - 1 file changed, 1 deletion(-) diff --git a/addons/portal/security/ir.model.access.csv b/addons/portal/security/ir.model.access.csv index e8ed29dc3cb..0a5027ad812 100644 --- a/addons/portal/security/ir.model.access.csv +++ b/addons/portal/security/ir.model.access.csv @@ -7,4 +7,3 @@ access_mail_message,mail.message,mail.model_mail_message,group_portal_member,1,0 access_mail_thread,mail.thread,mail.model_mail_thread,group_portal_member,1,0,0,0 access_mail_followers,mail.followers,mail.model_mail_followers,group_portal_member,1,0,1,1 access_mail_notification,mail.notification,mail.model_mail_notification,group_portal_member,1,0,1,0 -access_res_partner_portal,res.partner.portal,base.model_res_partner,group_portal_member,1,0,0,0 From 7f309d2df0dc14ff12e68a286750f399c00f530d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 17 Sep 2012 17:01:29 +0200 Subject: [PATCH 22/44] [FIX] Mail: fixed mail_followers widget, now taking into account crash when reading message_follower_ids, to disply only the number of followers, when the user does not have read access on the partners (ex: portal members). bzr revid: tde@openerp.com-20120917150129-7ahagbvopo2iqoe5 --- addons/mail/mail_group_view.xml | 1 + addons/mail/mail_thread.py | 10 +++++----- addons/mail/static/src/js/mail_followers.js | 19 ++++++++++++++++++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/addons/mail/mail_group_view.xml b/addons/mail/mail_group_view.xml index 31beba80ecc..bac7c22ee09 100644 --- a/addons/mail/mail_group_view.xml +++ b/addons/mail/mail_group_view.xml @@ -81,6 +81,7 @@
+ diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 6b4db7bc7d1..ea6f795bc61 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -119,7 +119,7 @@ class mail_thread(osv.AbstractModel): def _get_message_data(self, cr, uid, ids, name, args, context=None): res = dict((id, dict(message_unread=False, message_summary='')) for id in ids) - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) + partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] # search for unread messages, by reading directly mail.notification, as SUPERUSER notif_obj = self.pool.get('mail.notification') @@ -132,10 +132,10 @@ class mail_thread(osv.AbstractModel): for notif in notif_obj.browse(cr, SUPERUSER_ID, notif_ids, context=context): res[notif.message_id.res_id]['message_unread'] = True - for thread in self.browse(cr, uid, ids, context=context): - cls = res[thread.id]['message_unread'] and ' class="oe_kanban_mail_new"' or '' - res[thread.id]['message_summary'] = "9 %d + %d" % (cls, len(thread.message_comment_ids), len(thread.message_follower_ids)) - res[thread.id]['message_is_follower'] = user.partner_id.id in [follower.id for follower in thread.message_follower_ids] + for thread in self.read(cr, uid, ids, ['message_follower_ids', 'message_comment_ids', 'message_ids'], context=context): + cls = res[thread['id']]['message_unread'] and ' class="oe_kanban_mail_new"' or '' + res[thread['id']]['message_summary'] = "9 %d + %d" % (cls, len(thread['message_comment_ids']), len(thread['message_follower_ids'])) + res[thread['id']]['message_is_follower'] = partner_id in thread['message_follower_ids'] return res def _search_unread(self, cr, uid, obj=None, name=None, domain=None, context=None): diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index cf33bd64640..c3c59428920 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -88,7 +88,24 @@ openerp_mail_followers = function(session, mail) { }, fetch_followers: function (value_) { - return this.ds_follow.call('read', [value_, ['name', 'user_ids']]).pipe(this.proxy('display_followers')); + this.value = value_; + this.message_is_follower = this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value() || undefined; + return this.ds_follow.call('read', [value_, ['name', 'user_ids']]).pipe(this.proxy('display_followers'), this.proxy('display_generic')); + }, + + + /* Display generic info about follower, for people not having access to res_partner */ + display_generic: function (error, event) { + event.preventDefault(); + var node_user_list = this.$el.find('ul.oe_mail_followers_display').empty(); + this.$el.find('div.oe_mail_recthread_followers h4').html(this.options.title + ' (' + this.value.length + ')'); + if (this.message_is_follower) { + this.$el.find('button.oe_mail_button_follow').hide(); + this.$el.find('button.oe_mail_button_unfollow').show(); } + else { + this.$el.find('button.oe_mail_button_follow').show(); + this.$el.find('button.oe_mail_button_unfollow').hide(); } + return $.when(); }, /** Display the followers, evaluate is_follower directly */ From 0fea3331ae827d9a26cde8359fe77ff048e77b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 17 Sep 2012 17:01:57 +0200 Subject: [PATCH 23/44] [TEST] Portal: added some basic tests about access rights. bzr revid: tde@openerp.com-20120917150157-hyhfrfo249aovfs3 --- addons/portal/tests/test_portal.py | 40 +++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/addons/portal/tests/test_portal.py b/addons/portal/tests/test_portal.py index 2c301228859..abbcab58dac 100644 --- a/addons/portal/tests/test_portal.py +++ b/addons/portal/tests/test_portal.py @@ -21,15 +21,18 @@ from openerp.addons.mail.tests import test_mail from openerp.tools import append_content_to_html +from osv.orm import except_orm class test_portal(test_mail.TestMailMockups): def setUp(self): super(test_portal, self).setUp() + cr, uid = self.cr, self.uid self.ir_model = self.registry('ir.model') self.mail_group = self.registry('mail.group') self.mail_mail = self.registry('mail.mail') + self.mail_message = self.registry('mail.message') self.res_users = self.registry('res.users') self.res_partner = self.registry('res.partner') @@ -37,7 +40,42 @@ class test_portal(test_mail.TestMailMockups): self.group_pigs_id = self.mail_group.create(self.cr, self.uid, {'name': 'Pigs', 'description': 'Fans of Pigs, unite !'}) - def test_00_mail_invite(self): + # Find Portal group + group_portal_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'portal', 'group_portal_member') + self.group_portal_id = group_portal_ref and group_portal_ref[1] or False + + # Create Chell (portal user) + self.user_chell_id = self.res_users.create(cr, uid, {'name': 'Chell Gladys', 'login': 'chell', 'groups_id': [(6, 0, [self.group_portal_id])]}) + self.user_chell = self.res_users.browse(cr, uid, self.user_chell_id) + self.partner_chell_id = self.user_chell.partner_id.id + + def test_00_access_rights(self): + """ Test basic mail_message and mail_group access rights for portal users. """ + cr, uid = self.cr, self.uid + partner_chell_id = self.partner_chell_id + user_chell_id = self.user_chell_id + + # Prepare group: Pigs (portal) + self.mail_group.message_post(cr, uid, self.group_pigs_id, body='Message') + self.mail_group.write(cr, uid, [self.group_pigs_id], {'name': 'Jobs', 'public': 'groups', 'group_public_id': self.group_portal_id}) + + # ---------------------------------------- + # CASE1: Chell will use the Chatter + # ---------------------------------------- + + # Do: Chell reads Pigs messages, ok because restricted to portal group + message_ids = self.mail_group.read(cr, user_chell_id, self.group_pigs_id, ['message_ids'])['message_ids'] + self.mail_message.read(cr, user_chell_id, message_ids) + # Do: Chell posts a message on Pigs, crash because can not write on group or is not in the followers + self.assertRaises(except_orm, + self.mail_group.message_post, + cr, user_chell_id, self.group_pigs_id, body='Message') + # Do: Chell is added to Pigs followers + self.mail_group.message_subscribe(cr, uid, [self.group_pigs_id], [partner_chell_id]) + # Test: Chell posts a message on Pigs, ok because in the followers + self.mail_group.message_post(cr, user_chell_id, self.group_pigs_id, body='Message') + + def test_50_mail_invite(self): cr, uid = self.cr, self.uid user_admin = self.res_users.browse(cr, uid, uid) self.mail_invite = self.registry('mail.wizard.invite') From abf16c58c637ddfd57823b3a3faddb8dc4b632c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 17 Sep 2012 17:35:33 +0200 Subject: [PATCH 24/44] [IMP] Addons: added invisible field for message_is_follower; note: reidented view; account_voucher: reidented one view. bzr revid: tde@openerp.com-20120917153533-u102ds3eo1xr1mnt --- addons/account/account_invoice_view.xml | 2 + .../account_voucher/account_voucher_view.xml | 145 ++++----- .../voucher_payment_receipt_view.xml | 2 + .../voucher_sales_purchase_view.xml | 2 + addons/analytic/analytic_view.xml | 1 + addons/base_calendar/crm_meeting_view.xml | 1 + addons/crm/crm_lead_view.xml | 2 + addons/crm/crm_phonecall_view.xml | 1 + addons/crm_claim/crm_claim_view.xml | 1 + addons/crm_helpdesk/crm_helpdesk_view.xml | 1 + addons/event/event_view.xml | 2 + addons/hr_expense/hr_expense_view.xml | 1 + addons/hr_holidays/hr_holidays_view.xml | 2 + addons/hr_recruitment/hr_recruitment_view.xml | 1 + addons/idea/idea_view.xml | 1 + addons/mail/res_partner_view.xml | 1 + addons/mrp/mrp_view.xml | 6 +- addons/mrp_operations/mrp_operations_view.xml | 1 + addons/mrp_repair/mrp_repair_view.xml | 1 + addons/note/note_view.xml | 283 +++++++++--------- addons/procurement/procurement_view.xml | 1 + addons/product/product_view.xml | 1 + addons/project/project_view.xml | 2 + addons/project_issue/project_issue_view.xml | 1 + addons/purchase/purchase_view.xml | 1 + .../purchase_requisition_view.xml | 5 +- addons/sale/sale_view.xml | 1 + addons/stock/stock_view.xml | 2 + 28 files changed, 253 insertions(+), 218 deletions(-) diff --git a/addons/account/account_invoice_view.xml b/addons/account/account_invoice_view.xml index 1c4d83106ca..7a58b359008 100644 --- a/addons/account/account_invoice_view.xml +++ b/addons/account/account_invoice_view.xml @@ -278,6 +278,7 @@
+
@@ -437,6 +438,7 @@
+
diff --git a/addons/account_voucher/account_voucher_view.xml b/addons/account_voucher/account_voucher_view.xml index 07647d02fe3..bf8c7a9e3cb 100644 --- a/addons/account_voucher/account_voucher_view.xml +++ b/addons/account_voucher/account_voucher_view.xml @@ -39,80 +39,81 @@ account.voucher
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
From 33f60023e85949ac8e6076830e14711e2d553c4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 18 Sep 2012 12:14:23 +0200 Subject: [PATCH 31/44] [FIX] mail: replaced a superuser_id by a classic read with uid on partner in mail_group and mail_thread; fixed access rigths definition in portal that are not necessary. bzr revid: tde@openerp.com-20120918101423-pizn2tyrwta5o93n --- addons/mail/mail_group_menu.py | 2 +- addons/mail/mail_thread.py | 2 +- addons/portal/security/ir.model.access.csv | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/addons/mail/mail_group_menu.py b/addons/mail/mail_group_menu.py index 090d1cd00fb..707ece6a180 100644 --- a/addons/mail/mail_group_menu.py +++ b/addons/mail/mail_group_menu.py @@ -42,7 +42,7 @@ class ir_ui_menu(osv.osv): following. Access are done using SUPERUSER_ID to avoid access rights issues for an internal back-end algorithm. """ ids = super(ir_ui_menu, self).search(cr, uid, args, offset=0, limit=None, order=order, context=context, count=False) - partner_id = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context).partner_id.id + partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] follower_obj = self.pool.get('mail.followers') for menu in self.browse(cr, uid, ids, context=context): if menu.mail_group_id: diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 7e6803a22f2..c671dd55ec4 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -139,7 +139,7 @@ class mail_thread(osv.AbstractModel): return res def _search_unread(self, cr, uid, obj=None, name=None, domain=None, context=None): - partner_id = self.pool.get('res.users').browse(cr, uid, uid, context=context).partner_id.id + partner_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] res = {} notif_obj = self.pool.get('mail.notification') notif_ids = notif_obj.search(cr, uid, [ diff --git a/addons/portal/security/ir.model.access.csv b/addons/portal/security/ir.model.access.csv index 0a5027ad812..c3ff27bdfdf 100644 --- a/addons/portal/security/ir.model.access.csv +++ b/addons/portal/security/ir.model.access.csv @@ -4,6 +4,3 @@ access_widget_all,access.portal.widget.all,model_res_portal_widget,,1,0,0,0 access_manager,access.portal.manager,model_res_portal,group_portal_manager,1,1,1,1 access_widget_manager,access.portal.widget.manager,model_res_portal_widget,group_portal_manager,1,1,1,1 access_mail_message,mail.message,mail.model_mail_message,group_portal_member,1,0,1,1 -access_mail_thread,mail.thread,mail.model_mail_thread,group_portal_member,1,0,0,0 -access_mail_followers,mail.followers,mail.model_mail_followers,group_portal_member,1,0,1,1 -access_mail_notification,mail.notification,mail.model_mail_notification,group_portal_member,1,0,1,0 From df5b4656179c89d5e1a0b7671193d976d1cd90ea Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Tue, 18 Sep 2012 15:10:23 +0200 Subject: [PATCH 32/44] [FIX] typo in comment bzr revid: abo@openerp.com-20120918131023-stpvmvyg0df3hgv1 --- addons/portal_crm/wizard/contact.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/addons/portal_crm/wizard/contact.py b/addons/portal_crm/wizard/contact.py index 036993e1720..755b422f8ea 100644 --- a/addons/portal_crm/wizard/contact.py +++ b/addons/portal_crm/wizard/contact.py @@ -61,11 +61,11 @@ class crm_contact_us(osv.TransientModel): def create(self, cr, uid, values, context=None): """ - Since they potentially sensitive, we don't want any user to be able to - read datas generated through this module. That's why we'll write those - information in the crm.lead table and leave blank entries in the - portal_crm.crm_contact_us table. This is why the create() method is - overwritten. + Since they are potentially sensitive, we don't want any user to be able + to read datas generated through this module. That's why we'll write + those information directly in the crm.lead table and leave blank + entries in the portal_crm.crm_contact_us table. + This is why the create() method is overwritten. """ crm_lead = self.pool.get('crm.lead') From bbae9cdc00af41f890b4bac9e7b19c96b235313d Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Tue, 18 Sep 2012 16:17:24 +0200 Subject: [PATCH 33/44] [FIX] read user login and email with a read() instead of a browse() this way, we prevent the auto-loading of all the user's fields which crashes the contact form while accessed by a portal user bzr revid: abo@openerp.com-20120918141724-fjhpu0m46ndgtble --- addons/portal_crm/wizard/contact.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/portal_crm/wizard/contact.py b/addons/portal_crm/wizard/contact.py index 755b422f8ea..37e6a0ca6d1 100644 --- a/addons/portal_crm/wizard/contact.py +++ b/addons/portal_crm/wizard/contact.py @@ -47,10 +47,10 @@ class crm_contact_us(osv.TransientModel): @return current user's email if the user isn't "anonymous", None otherwise """ - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) + user = self.pool.get('res.users').read(cr, uid, uid, ['login', 'email'], context) - if (user.login != 'anonymous'): - return user.email + if (user['login'] != 'anonymous'): + return user['email'] else: return None From a8798fc9c05c8801207adea22e92d051293d17ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 18 Sep 2012 16:23:18 +0200 Subject: [PATCH 34/44] [IMP] mail.followers widget: invite is now a link after 'Followers' h4 title. Removed the button. The behavior is the same as before. bzr revid: tde@openerp.com-20120918142318-glwj47jx7xyvj26d --- addons/mail/static/src/css/mail.css | 10 +++++++++- addons/mail/static/src/js/mail_followers.js | 6 +++--- addons/mail/static/src/xml/mail_followers.xml | 3 +-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 48a178732b0..a26beb237d1 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -124,6 +124,14 @@ } +/* ------------------------------------------------------------ */ +/* Followers +/* ------------------------------------------------------------ */ + +.openerp div.oe_mail_recthread_aside h4 { + display: inline-block; +} + /* ------------------------------------------------------------ */ /* Thread /* ------------------------------------------------------------ */ @@ -226,7 +234,7 @@ clear: both; } -.openerp .oe_mail_msg_content a { +.openerp .oe_chatter a { cursor: pointer; } diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index b321ca42027..4b3d6b13abb 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -53,7 +53,7 @@ openerp_mail_followers = function(session, mail) { .mouseover(function () { $(this).html('Unfollow').removeClass('oe_mail_button_mouseout').addClass('oe_mail_button_mouseover'); }) .mouseleave(function () { $(this).html('Following').removeClass('oe_mail_button_mouseover').addClass('oe_mail_button_mouseout'); }); this.$el.on('click', 'button.oe_mail_button_follow', function () { self.do_follow(); }); - this.$el.on('click', 'button.oe_mail_button_invite', function(event) { + this.$el.on('click', 'a.oe_mail_invite', function(event) { action = { type: 'ir.actions.act_window', res_model: 'mail.wizard.invite', @@ -126,9 +126,9 @@ openerp_mail_followers = function(session, mail) { display_buttons: function () { this.$('button.oe_mail_button_follow').hide(); this.$('button.oe_mail_button_unfollow').hide(); - this.$('button.oe_mail_button_invite').hide(); + this.$('span.oe_mail_invite_wrapper').hide(); if (! this.view.is_action_enabled('edit')) return; - this.$('button.oe_mail_button_invite').show(); + this.$('span.oe_mail_invite_wrapper').show(); if (this.message_is_follower) { this.$('button.oe_mail_button_unfollow').show(); } else if (this.message_is_follower == false) { this.$('button.oe_mail_button_follow').show(); } }, diff --git a/addons/mail/static/src/xml/mail_followers.xml b/addons/mail/static/src/xml/mail_followers.xml index 8e4c4b3991f..dbcfe794166 100644 --- a/addons/mail/static/src/xml/mail_followers.xml +++ b/addons/mail/static/src/xml/mail_followers.xml @@ -9,11 +9,10 @@
-
From 470c0fa818c44d617063eafc6d83819c889dde3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 19 Sep 2012 12:13:39 +0200 Subject: [PATCH 35/44] [IMP] mail_mesage: fixed message_dict_get (getting values is now inside try/except, not having access rigths on some details of the mail.message should not crash, just hide the data); My Feeds -> My Posts; mis cleaning in mail.js, xml and css. bzr revid: tde@openerp.com-20120919101339-d1k16lxk5e4gwxxg --- addons/mail/mail_message.py | 41 ++++++++++++++++++----------- addons/mail/mail_message_view.xml | 2 +- addons/mail/static/src/css/mail.css | 24 ----------------- addons/mail/static/src/js/mail.js | 11 ++------ addons/mail/static/src/xml/mail.xml | 4 +-- 5 files changed, 30 insertions(+), 52 deletions(-) diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 94f2d1f83e2..7d9c7b3085f 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -26,8 +26,7 @@ import tools from email.header import decode_header from openerp import SUPERUSER_ID from operator import itemgetter -from osv import osv, fields -from osv.orm import except_orm +from osv import osv, orm, fields from tools.translate import _ _logger = logging.getLogger(__name__) @@ -64,7 +63,7 @@ class mail_message(osv.Model): continue try: result[message.id] = self._shorten_name(self.pool.get(message.model).name_get(cr, uid, [message.res_id], context=context)[0][1]) - except openerp.exceptions.AccessDenied, e: + except (orm.except_orm, osv.except_osv): pass return result @@ -175,22 +174,31 @@ class mail_message(osv.Model): #------------------------------------------------------ def _message_dict_get(self, cr, uid, msg, context=None): - """ Return a dict representation of the message browse record. """ + """ Return a dict representation of the message browse record. A read + is performed to because of access rights issues (reading many2one + fields allow to have the foreign record name without having + to check external access rights). + """ has_voted = False vote_ids = self.pool.get('res.users').name_get(cr, SUPERUSER_ID, [user.id for user in msg.vote_user_ids], context=context) for vote in vote_ids: if vote[0] == uid: has_voted = True break - # TDE TEMP: use SUPERUSER_ID - # attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, SUPERUSER_ID, [x.id for x in msg.attachment_ids], context=context)] - attachment_ids = [] - # author_id = self.pool.get('res.partner').name_get(cr, SUPERUSER_ID, [msg.author_id.id], context=context)[0] - author_id = False - # author_user_id = self.pool.get('res.users').name_get(cr, SUPERUSER_ID, [msg.author_id.user_ids[0].id], context=context)[0] - author_user_id = False - # partner_ids = self.pool.get('res.partner').name_get(cr, SUPERUSER_ID, [x.id for x in msg.partner_ids], context=context) - partner_ids = [] + try: + attachment_ids = [{'id': attach[0], 'name': attach[1]} for attach in self.pool.get('ir.attachment').name_get(cr, uid, [x.id for x in msg.attachment_ids], context=context)] + except (orm.except_orm, osv.except_osv): + attachment_ids = [] + try: + author_id = self.pool.get('res.partner').name_get(cr, uid, [msg.author_id.id], context=context)[0] + is_author = uid in msg.author_id.user_ids + except (orm.except_orm, osv.except_osv): + author_id = False + is_author = False + try: + partner_ids = self.pool.get('res.partner').name_get(cr, uid, [x.id for x in msg.partner_ids], context=context) + except (orm.except_orm, osv.except_osv): + partner_ids = [] return { 'id': msg.id, 'type': msg.type, @@ -202,7 +210,7 @@ class mail_message(osv.Model): 'subject': msg.subject, 'date': msg.date, 'author_id': author_id, - 'author_user_id': author_user_id, + 'is_author': is_author, 'partner_ids': partner_ids, 'child_ids': [], 'vote_user_ids': vote_ids, @@ -393,7 +401,7 @@ class mail_message(osv.Model): other_ids = set(ids).difference(set(notified_ids), set(author_ids), set(doc_follower_ids), set(document_related_ids)) if not other_ids: return - raise except_orm(_('Access Denied'), + raise orm.except_orm(_('Access Denied'), _('The requested operation cannot be completed due to security restrictions. Please contact your system administrator.\n\n(Document type: %s, Operation: %s)') % \ (self._description, operation)) @@ -408,7 +416,6 @@ class mail_message(osv.Model): """ Override to explicitely call check_access_rule, that is not called by the ORM. It instead directly fetches ir.rules and apply them. """ res = super(mail_message, self).read(cr, uid, ids, fields=fields, context=context, load=load) - # print '-->', res self.check_access_rule(cr, uid, ids, 'read', context=context) return res @@ -441,6 +448,8 @@ class mail_message(osv.Model): if missing_notified: self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(4, p_id) for p_id in missing_notified]}, context=context) partners_to_notify |= extra_notified + # # remove uid from partners + self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(3, uid)]}, context=context) self.pool.get('mail.notification').notify(cr, uid, list(partners_to_notify), newid, context=context) def copy(self, cr, uid, id, default=None, context=None): diff --git a/addons/mail/mail_message_view.xml b/addons/mail/mail_message_view.xml index 914937a34f3..814702f6db4 100644 --- a/addons/mail/mail_message_view.xml +++ b/addons/mail/mail_message_view.xml @@ -95,7 +95,7 @@ - My Feeds + My Posts mail.wall diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index badbc09788a..166555500dd 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -268,30 +268,6 @@ display: none; } -/*--------------------------------------------------------------*/ -/* mail.vote -/*--------------------------------------------------------------*/ - -.openerp .oe_mail_msg_content button.oe_mail_msg_vote { - height:21px; - width: 30px; - padding: 1px; - background: #8A89BA; - margin-top: -4px; -} - -.openerp .oe_mail_msg_content button.oe_mail_msg_vote_true { - background:#DC5F59; -} - -.openerp .oe_mail_msg_content button.oe_mail_msg_vote span { - color: white; -} - -.openerp .oe_mail_msg_content span.oe_mail_vote_count{ - color: #807FB4; -} - /* ------------------------------------------------------------ */ /* mail.compose.message form view & OpenERP hacks diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 41d5ca87c28..d1d813476d2 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -56,11 +56,6 @@ openerp.mail = function(session) { return session.origin + '/web/binary/saveas?session_id=' + session.session_id + '&model=ir.attachment&field=datas&filename_field=datas_fname&id=' + attachment['id']; }, - /** Check if the current user is the message author */ - is_author: function (widget, message_user_id) { - return (widget.session && widget.session.uid != 0 && widget.session.uid == message_user_id); - }, - /** Replaces some expressions * - :name - shortcut to an image */ @@ -301,6 +296,7 @@ openerp.mail = function(session) { // TDE TODO: check for deferred, not sure it is correct this._super.apply(this, arguments); this.bind_events(); + this.display_user_avatar(); // fetch and display message, using message_ids if set var display_done = $.when(this.message_fetch(true, [], {})).then(this.proxy('do_customize_display')); // add message composition form view @@ -313,7 +309,6 @@ openerp.mail = function(session) { /** Customize the display * - show_header_compose: show the composition form in the header */ do_customize_display: function() { - this.display_user_avatar(); if (this.options.show_header_compose) { this.$el.find('div.oe_mail_thread_action').eq(0).show(); } @@ -489,8 +484,7 @@ openerp.mail = function(session) { * - record.date: formatting according to the user timezone * - record.timerelative: relative time givein by timeago lib * - record.avatar: image url - * - record.attachment_ids[].url: url of each attachment - * - record.is_author: is the current user the author of the record */ + * - record.attachment_ids[].url: url of each attachment */ display_record: function (record) { // formatting and additional fields record.date = session.web.format_value(record.date, {type:"datetime"}); @@ -504,7 +498,6 @@ openerp.mail = function(session) { var attach = record.attachment_ids[l]; attach['url'] = mail.ChatterUtils.get_attachment_url(this.session, attach); } - record.is_author = mail.ChatterUtils.is_author(this, record.author_user_id[0]); // add to internal storage this.records[record.id] = record; // render, add the expand feature diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index e3586e723e4..c54bd4dbb2d 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -140,7 +140,7 @@
  • -
  • +
  • Reply
  • @@ -185,7 +185,7 @@ votes - From bc9decbe45f57c0c61d3a3c8a6758e6b3b744bfc Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Wed, 19 Sep 2012 13:12:04 +0200 Subject: [PATCH 36/44] [IMP] make sure that the user email exist bzr revid: abo@openerp.com-20120919111204-n461eriy40nirvgz --- addons/portal_crm/wizard/contact.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/portal_crm/wizard/contact.py b/addons/portal_crm/wizard/contact.py index 37e6a0ca6d1..4deb17876e9 100644 --- a/addons/portal_crm/wizard/contact.py +++ b/addons/portal_crm/wizard/contact.py @@ -49,7 +49,7 @@ class crm_contact_us(osv.TransientModel): """ user = self.pool.get('res.users').read(cr, uid, uid, ['login', 'email'], context) - if (user['login'] != 'anonymous'): + if (user['login'] != 'anonymous' and user['email']): return user['email'] else: return None From 6d7c30af8592da558ef8157842849f4a41f72ea1 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Wed, 19 Sep 2012 16:51:10 +0200 Subject: [PATCH 37/44] [IMP] indentation bzr revid: abo@openerp.com-20120919145110-81ucvhpf9jcf867y --- addons/portal_crm/wizard/contact.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/addons/portal_crm/wizard/contact.py b/addons/portal_crm/wizard/contact.py index 4deb17876e9..1ddc70178f5 100644 --- a/addons/portal_crm/wizard/contact.py +++ b/addons/portal_crm/wizard/contact.py @@ -88,11 +88,12 @@ class crm_contact_us(osv.TransientModel): def submit(self, cr, uid, ids, context=None): """ When the form is submitted, redirect the user to a "Thanks" message """ - return {'type': 'ir.actions.act_window', - 'view_mode': 'form', - 'view_type': 'form', - 'res_model': self._name, - 'res_id': ids[0], - 'view_id': self.pool.get('ir.model.data').get_object_reference(cr, uid, 'portal_crm', 'wizard_contact_form_view_thanks')[1], - 'target': 'inline' - } + return { + 'type': 'ir.actions.act_window', + 'view_mode': 'form', + 'view_type': 'form', + 'res_model': self._name, + 'res_id': ids[0], + 'view_id': self.pool.get('ir.model.data').get_object_reference(cr, uid, 'portal_crm', 'wizard_contact_form_view_thanks')[1], + 'target': 'inline', + } From cae00c851a209296c0b8861cd9fa7ad79e3750ba Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Wed, 19 Sep 2012 16:55:57 +0200 Subject: [PATCH 38/44] [IMP] needaction handling for crm_contact_us model don't display the needactions anymore next to the 'contact' portal menuitem bzr revid: abo@openerp.com-20120919145557-p6285mrhw82cv2l6 --- addons/portal_crm/wizard/contact.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/addons/portal_crm/wizard/contact.py b/addons/portal_crm/wizard/contact.py index 1ddc70178f5..3a08e1bce9a 100644 --- a/addons/portal_crm/wizard/contact.py +++ b/addons/portal_crm/wizard/contact.py @@ -97,3 +97,11 @@ class crm_contact_us(osv.TransientModel): 'view_id': self.pool.get('ir.model.data').get_object_reference(cr, uid, 'portal_crm', 'wizard_contact_form_view_thanks')[1], 'target': 'inline', } + + def _needaction_domain_get(self, cr, uid, context=None): + """ + This model doesn't need the needactions mechanism inherited from + crm_lead, so simply override the method to return an empty domain + and, therefore, 0 needactions. + """ + return False From 52b33a8044819fc7975be2f9acda6e8d8ef25e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 20 Sep 2012 09:39:50 +0200 Subject: [PATCH 39/44] [FIX] Followers widget: fixed is_follower bug. bzr revid: tde@openerp.com-20120920073950-wyrf8pads5j6hgqh --- addons/mail/static/src/js/mail_followers.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index 4b3d6b13abb..64fb2974d78 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -72,24 +72,24 @@ openerp_mail_followers = function(session, mail) { read_value: function() { var self = this; - return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).pipe(function (results) { - return results[0].message_follower_ids; - }).pipe(this.proxy('set_value')); + return this.ds_model.read_ids([this.view.datarecord.id], ['message_is_follower', 'message_follower_ids']).then(function (results) { + self.set_value(results[0].message_follower_ids, results[0].message_is_follower); + }); }, - set_value: function(value_) { + set_value: function(value_, message_is_follower) { this.reinit(); if (! this.view.datarecord.id || session.web.BufferedDataSet.virtual_id_regex.test(this.view.datarecord.id)) { this.$('div.oe_mail_recthread_aside').hide(); return; } - return this.fetch_followers(value_ || this.get_value()); + return this.fetch_followers(value_ || this.get_value(), message_is_follower); }, - fetch_followers: function (value_) { + fetch_followers: function (value_, message_is_follower) { this.value = value_; - this.message_is_follower = this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value(); + this.message_is_follower = message_is_follower || (this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value()); return this.ds_follow.call('read', [value_, ['name', 'user_ids']]).pipe(this.proxy('display_followers'), this.proxy('display_generic')); }, From f5c64f0b1554b683de1a3c4bd42b4ac8640794c2 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Thu, 20 Sep 2012 14:38:45 +0200 Subject: [PATCH 40/44] [IMP] pre-fill portal's contact form fields e-mail and phone, when it's possible bzr revid: abo@openerp.com-20120920123845-4gjv90n4tn20t3dq --- addons/portal_crm/wizard/contact.py | 34 +++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/addons/portal_crm/wizard/contact.py b/addons/portal_crm/wizard/contact.py index 3a08e1bce9a..516bb30b471 100644 --- a/addons/portal_crm/wizard/contact.py +++ b/addons/portal_crm/wizard/contact.py @@ -40,6 +40,20 @@ class crm_contact_us(osv.TransientModel): r = self.pool.get('res.company').search(cr, uid, [], context=context) return r + def _get_current_user_name(self, cr, uid, context=None): + """ + If the user is logged in (i.e. not anonymous), get the user's name to + pre-fill the partner_name field. + + @return current user's name if the user isn't "anonymous", None otherwise + """ + user = self.pool.get('res.users').read(cr, uid, uid, ['login'], context) + + if (user['login'] != 'anonymous'): + return self.pool.get('res.users').name_get(cr, uid, uid, context)[0][1] + else: + return None + def _get_current_user_email(self, cr, uid, context=None): """ If the user is logged in (i.e. not anonymous), get the user's email to @@ -54,9 +68,25 @@ class crm_contact_us(osv.TransientModel): else: return None + def _get_current_user_phone(self, cr, uid, context=None): + """ + If the user is logged in (i.e. not anonymous), get the user's phone to + pre-fill the phone field. + + @return current user's phone if the user isn't "anonymous", None otherwise + """ + user = self.pool.get('res.users').read(cr, uid, uid, ['login', 'phone'], context) + + if (user['login'] != 'anonymous' and user['phone']): + return user['phone'] + else: + return None + _defaults = { - 'email_from' : _get_current_user_email, - 'company_ids' : _get_companies, + 'partner_name': _get_current_user_name, + 'email_from': _get_current_user_email, + 'phone': _get_current_user_phone, + 'company_ids': _get_companies, } def create(self, cr, uid, values, context=None): From 01cda53501ef8993f9306fe93663258024c22ea1 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Thu, 20 Sep 2012 16:56:58 +0200 Subject: [PATCH 41/44] [IMP] indentation bzr revid: abo@openerp.com-20120920145658-oigqs5ctd3qoiq7u --- addons/event/event_view.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/addons/event/event_view.xml b/addons/event/event_view.xml index dda7bd805e4..a92487e4c73 100644 --- a/addons/event/event_view.xml +++ b/addons/event/event_view.xml @@ -248,12 +248,12 @@
    -
    -
    - - -
    -
    +
    +
    + + +
    +

    @@ -273,10 +273,10 @@

    - - + + From 457533c80812de214b6472123b7413d4d23db260 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Thu, 20 Sep 2012 16:57:08 +0200 Subject: [PATCH 42/44] [IMP] methods names bzr revid: abo@openerp.com-20120920145708-zsuechbcj2uxcys3 --- addons/portal_crm/wizard/contact.py | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/addons/portal_crm/wizard/contact.py b/addons/portal_crm/wizard/contact.py index 516bb30b471..b671ced2275 100644 --- a/addons/portal_crm/wizard/contact.py +++ b/addons/portal_crm/wizard/contact.py @@ -40,10 +40,11 @@ class crm_contact_us(osv.TransientModel): r = self.pool.get('res.company').search(cr, uid, [], context=context) return r - def _get_current_user_name(self, cr, uid, context=None): + def _get_user_name(self, cr, uid, context=None): """ If the user is logged in (i.e. not anonymous), get the user's name to pre-fill the partner_name field. + Same goes for the other _get_user_attr methods. @return current user's name if the user isn't "anonymous", None otherwise """ @@ -54,13 +55,7 @@ class crm_contact_us(osv.TransientModel): else: return None - def _get_current_user_email(self, cr, uid, context=None): - """ - If the user is logged in (i.e. not anonymous), get the user's email to - pre-fill the email_from field. - - @return current user's email if the user isn't "anonymous", None otherwise - """ + def _get_user_email(self, cr, uid, context=None): user = self.pool.get('res.users').read(cr, uid, uid, ['login', 'email'], context) if (user['login'] != 'anonymous' and user['email']): @@ -68,13 +63,7 @@ class crm_contact_us(osv.TransientModel): else: return None - def _get_current_user_phone(self, cr, uid, context=None): - """ - If the user is logged in (i.e. not anonymous), get the user's phone to - pre-fill the phone field. - - @return current user's phone if the user isn't "anonymous", None otherwise - """ + def _get_user_phone(self, cr, uid, context=None): user = self.pool.get('res.users').read(cr, uid, uid, ['login', 'phone'], context) if (user['login'] != 'anonymous' and user['phone']): @@ -83,9 +72,9 @@ class crm_contact_us(osv.TransientModel): return None _defaults = { - 'partner_name': _get_current_user_name, - 'email_from': _get_current_user_email, - 'phone': _get_current_user_phone, + 'partner_name': _get_user_name, + 'email_from': _get_user_email, + 'phone': _get_user_phone, 'company_ids': _get_companies, } From 0c6258855d84ef1a0618a408cd3f8d27ff5a6d3e Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Thu, 20 Sep 2012 17:50:06 +0200 Subject: [PATCH 43/44] [FIX] event registrations record rules now a portal user has full control over his own event registrations bzr revid: abo@openerp.com-20120920155006-ullbntw8jju4xnh4 --- addons/portal_event/security/ir.model.access.csv | 2 +- addons/portal_event/security/portal_security.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/portal_event/security/ir.model.access.csv b/addons/portal_event/security/ir.model.access.csv index 7418b08bb4b..fc652f4bcd1 100644 --- a/addons/portal_event/security/ir.model.access.csv +++ b/addons/portal_event/security/ir.model.access.csv @@ -1,3 +1,3 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_event,event,event.model_event_event,portal.group_portal,1,0,0,0 -access_registration,registration,event.model_event_registration,portal.group_portal,1,0,0,0 +access_registration,registration,event.model_event_registration,portal.group_portal,1,1,1,1 diff --git a/addons/portal_event/security/portal_security.xml b/addons/portal_event/security/portal_security.xml index d84979ff9ca..8f17808345b 100644 --- a/addons/portal_event/security/portal_security.xml +++ b/addons/portal_event/security/portal_security.xml @@ -12,7 +12,7 @@ Portal Personal Registrations - [('message_follower_ids','in',user.partner_id.id)] + [('user_id','=',user.id)] From 9f8cdcca14614e9f1c860da8b08ec390184b0459 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Fri, 28 Sep 2012 16:30:17 +0200 Subject: [PATCH 44/44] [FIX] test setUp bzr revid: abo@openerp.com-20120928143017-orijtb9jwsel6za2 --- addons/portal/tests/test_portal.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/portal/tests/test_portal.py b/addons/portal/tests/test_portal.py index a8e06f16516..653a05d40aa 100644 --- a/addons/portal/tests/test_portal.py +++ b/addons/portal/tests/test_portal.py @@ -41,7 +41,7 @@ class test_portal(test_mail.TestMailMockups): {'name': 'Pigs', 'description': 'Fans of Pigs, unite !'}) # Find Portal group - group_portal_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'portal', 'group_portal_member') + group_portal_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'portal', 'group_portal') self.group_portal_id = group_portal_ref and group_portal_ref[1] or False # Create Chell (portal user)