From 62e88a16e4b46945551a6fb0db057ef9c6416e9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 18 Oct 2013 16:49:24 +0200 Subject: [PATCH 1/6] [FIX] mail: mail_mail: fixed url embedded in notification emails. When having emails not linked to a notification (mail.notification = False) the link is generated without any clue about the source record. However we can try to use model and res_id defined on the mail_mail record to correctly format a link. Added support of model and res_id in message_redirect_action. This method now can redirect based on a message_id, or based on model / res_id. bzr revid: tde@openerp.com-20131018144924-j4f22hen3lsua7cb --- addons/mail/mail_mail.py | 6 +- addons/mail/mail_thread.py | 40 +++++---- addons/mail/tests/test_mail_features.py | 106 ++++++++++++++++++++---- 3 files changed, 116 insertions(+), 36 deletions(-) diff --git a/addons/mail/mail_mail.py b/addons/mail/mail_mail.py index 91799b0ac63..8e99655dddb 100644 --- a/addons/mail/mail_mail.py +++ b/addons/mail/mail_mail.py @@ -157,9 +157,9 @@ class mail_mail(osv.Model): 'action': 'mail.action_mail_redirect', } if mail.notification: - fragment.update({ - 'message_id': mail.mail_message_id.id, - }) + fragment['message_id'] = mail.mail_message_id.id + elif mail.model and mail.res_id: + fragment.update(model=mail.model, res_id=mail.res_id) url = urljoin(base_url, "?%s#%s" % (urlencode(query), urlencode(fragment))) return _("""Access your messages and documents in OpenERP""") % url else: diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index b902f733207..9692b94f159 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -566,29 +566,37 @@ class mail_thread(osv.AbstractModel): self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context) act_model, act_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, *self._get_inbox_action_xml_id(cr, uid, context=context)) action = self.pool.get(act_model).read(cr, uid, act_id, []) + params = context.get('params') + msg_id = model = res_id = None - # if msg_id specified: try to redirect to the document or fallback on the Inbox - msg_id = context.get('params', {}).get('message_id') - if not msg_id: + if params: + msg_id = params.get('message_id') + model = params.get('model') + res_id = params.get('res_id') + if not msg_id and not (model and res_id): return action - msg = self.pool.get('mail.message').browse(cr, uid, msg_id, context=context) - if msg.model and msg.res_id: - action.update({ - 'context': { - 'search_default_model': msg.model, - 'search_default_res_id': msg.res_id, - } - }) - if self.pool.get(msg.model).check_access_rights(cr, uid, 'read', raise_exception=False): + if msg_id and not (model and res_id): + msg = self.pool.get('mail.message').browse(cr, uid, msg_id, context=context) + model, res_id = msg.model, msg.res_id + + # if model + res_id found: try to redirect to the document or fallback on the Inbox + if model and res_id: + model_obj = self.pool.get(model) + if model_obj.check_access_rights(cr, uid, 'read', raise_exception=False): try: - model_obj = self.pool.get(msg.model) - model_obj.check_access_rule(cr, uid, [msg.res_id], 'read', context=context) + model_obj.check_access_rule(cr, uid, [res_id], 'read', context=context) if not hasattr(model_obj, '_get_formview_action'): - action = self.pool.get('mail.thread')._get_formview_action(cr, uid, msg.res_id, model=msg.model, context=context) + action = self.pool.get('mail.thread')._get_formview_action(cr, uid, res_id, model=model, context=context) else: - action = model_obj._get_formview_action(cr, uid, msg.res_id, context=context) + action = model_obj._get_formview_action(cr, uid, res_id, context=context) except (osv.except_osv, orm.except_orm): pass + action.update({ + 'context': { + 'search_default_model': model, + 'search_default_res_id': res_id, + } + }) return action #------------------------------------------------------ diff --git a/addons/mail/tests/test_mail_features.py b/addons/mail/tests/test_mail_features.py index 0688bf02606..62c76db5a40 100644 --- a/addons/mail/tests/test_mail_features.py +++ b/addons/mail/tests/test_mail_features.py @@ -231,6 +231,8 @@ class test_mail(TestMail): def test_11_notification_url(self): """ Tests designed to test the URL added in notification emails. """ cr, uid, group_pigs = self.cr, self.uid, self.group_pigs + # Test URL formatting + base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url') # Partner data partner_raoul = self.res_partner.browse(cr, uid, self.partner_raoul_id) @@ -243,19 +245,59 @@ class test_mail(TestMail): # Test: link for nobody -> None url = mail_mail._get_partner_access_link(self.mail_mail, cr, uid, mail) self.assertEqual(url, None, - 'notification email: mails not send to a specific partner should not have any URL') + 'notification email: mails not send to a specific partner should not have any URL') # Test: link for partner -> None url = mail_mail._get_partner_access_link(self.mail_mail, cr, uid, mail, partner=partner_bert) self.assertEqual(url, None, - 'notification email: mails send to a not-user partner should not have any URL') + 'notification email: mails send to a not-user partner should not have any URL') # Test: link for user -> signin url = mail_mail._get_partner_access_link(self.mail_mail, cr, uid, mail, partner=partner_raoul) + self.assertIn(base_url, url, + 'notification email: link should contain web.base.url') + self.assertIn('db=%s' % cr.dbname, url, + 'notification email: link should contain database name') self.assertIn('action=mail.action_mail_redirect', url, - 'notification email: link should contain the redirect action') + 'notification email: link should contain the redirect action') self.assertIn('login=%s' % partner_raoul.user_ids[0].login, url, - 'notification email: link should contain the user login') + 'notification email: link should contain the user login') + + # Test: link for user -> with model and res_id + mail_mail_id = self.mail_mail.create(cr, uid, {'model': 'mail.group', 'res_id': group_pigs.id}) + mail = self.mail_mail.browse(cr, uid, mail_mail_id) + url = mail_mail._get_partner_access_link(self.mail_mail, cr, uid, mail, partner=partner_raoul) + self.assertIn(base_url, url, + 'notification email: link should contain web.base.url') + self.assertIn('db=%s' % cr.dbname, url, + 'notification email: link should contain database name') + self.assertIn('action=mail.action_mail_redirect', url, + 'notification email: link should contain the redirect action') + self.assertIn('login=%s' % partner_raoul.user_ids[0].login, url, + 'notification email: link should contain the user login') + self.assertIn('model=mail.group', url, + 'notification email: link should contain the model when having not notification email on a record') + self.assertIn('res_id=%s' % group_pigs.id, url, + 'notification email: link should contain the res_id when having not notification email on a record') + + # Test: link for user -> with model and res_id + mail_mail_id = self.mail_mail.create(cr, uid, {'notification': True, 'model': 'mail.group', 'res_id': group_pigs.id}) + mail = self.mail_mail.browse(cr, uid, mail_mail_id) + url = mail_mail._get_partner_access_link(self.mail_mail, cr, uid, mail, partner=partner_raoul) + self.assertIn(base_url, url, + 'notification email: link should contain web.base.url') + self.assertIn('db=%s' % cr.dbname, url, + 'notification email: link should contain database name') + self.assertIn('action=mail.action_mail_redirect', url, + 'notification email: link should contain the redirect action') + self.assertIn('login=%s' % partner_raoul.user_ids[0].login, url, + 'notification email: link should contain the user login') + self.assertIn('message_id=%s' % mail.mail_message_id.id, url, + 'notification email: link based on message should contain the mail_message id') + self.assertNotIn('model', url, + 'notification email: link based on message should not contain model') + self.assertNotIn('res_id', url, + 'notification email: link based on message should not contain res_id') @mute_logger('openerp.addons.mail.mail_thread', 'openerp.osv.orm') def test_12_inbox_redirection(self): @@ -267,24 +309,54 @@ class test_mail(TestMail): # No specific parameters -> should redirect to Inbox action = mail_thread.message_redirect_action(self.mail_thread, cr, self.user_raoul_id, {'params': {}}) - self.assertEqual(action.get('type'), 'ir.actions.client', - 'URL redirection: action without parameters should redirect to client action Inbox') - self.assertEqual(action.get('id'), act_id, - 'URL redirection: action without parameters should redirect to client action Inbox') + self.assertEqual( + action.get('type'), 'ir.actions.client', + 'URL redirection: action without parameters should redirect to client action Inbox' + ) + self.assertEqual( + action.get('id'), act_id, + 'URL redirection: action without parameters should redirect to client action Inbox' + ) - # Bert has read access to Pigs -> should redirect to form view of Pigs + # Raoul has read access to Pigs -> should redirect to form view of Pigs action = mail_thread.message_redirect_action(self.mail_thread, cr, self.user_raoul_id, {'params': {'message_id': msg_id}}) - self.assertEqual(action.get('type'), 'ir.actions.act_window', - 'URL redirection: action with message_id for read-accredited user should redirect to Pigs') - self.assertEqual(action.get('res_id'), group_pigs.id, - 'URL redirection: action with message_id for read-accredited user should redirect to Pigs') + self.assertEqual( + action.get('type'), 'ir.actions.act_window', + 'URL redirection: action with message_id for read-accredited user should redirect to Pigs' + ) + self.assertEqual( + action.get('res_id'), group_pigs.id, + 'URL redirection: action with message_id for read-accredited user should redirect to Pigs' + ) + action = mail_thread.message_redirect_action(self.mail_thread, cr, self.user_raoul_id, {'params': {'model': 'mail.group', 'res_id': group_pigs.id}}) + self.assertEqual( + action.get('type'), 'ir.actions.act_window', + 'URL redirection: action with message_id for read-accredited user should redirect to Pigs' + ) + self.assertEqual( + action.get('res_id'), group_pigs.id, + 'URL redirection: action with message_id for read-accredited user should redirect to Pigs' + ) # Bert has no read access to Pigs -> should redirect to Inbox action = mail_thread.message_redirect_action(self.mail_thread, cr, self.user_bert_id, {'params': {'message_id': msg_id}}) - self.assertEqual(action.get('type'), 'ir.actions.client', - 'URL redirection: action without parameters should redirect to client action Inbox') - self.assertEqual(action.get('id'), act_id, - 'URL redirection: action without parameters should redirect to client action Inbox') + self.assertEqual( + action.get('type'), 'ir.actions.client', + 'URL redirection: action without parameters should redirect to client action Inbox' + ) + self.assertEqual( + action.get('id'), act_id, + 'URL redirection: action without parameters should redirect to client action Inbox' + ) + action = mail_thread.message_redirect_action(self.mail_thread, cr, self.user_bert_id, {'params': {'model': 'mail.group', 'res_id': group_pigs.id}}) + self.assertEqual( + action.get('type'), 'ir.actions.client', + 'URL redirection: action without parameters should redirect to client action Inbox' + ) + self.assertEqual( + action.get('id'), act_id, + 'URL redirection: action without parameters should redirect to client action Inbox' + ) def test_20_message_post(self): """ Tests designed for message_post. """ From 6752a298ec7df4265b0b092c8e1d7781478b6a5b Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 21 Oct 2013 16:36:41 +0200 Subject: [PATCH 2/6] [IMP] ir.translation: `module` field is useful for admin/debugging bzr revid: odo@openerp.com-20131021143641-eflzertf2r7hap44 --- openerp/addons/base/ir/ir_translation_view.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/openerp/addons/base/ir/ir_translation_view.xml b/openerp/addons/base/ir/ir_translation_view.xml index 64a02576091..f3f9c4d0fac 100644 --- a/openerp/addons/base/ir/ir_translation_view.xml +++ b/openerp/addons/base/ir/ir_translation_view.xml @@ -34,6 +34,7 @@ + From fadd46c5cbe8de3a79644b5ddcd1ee0acb966807 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Mon, 21 Oct 2013 17:51:20 +0200 Subject: [PATCH 3/6] hr_holidays: force refuse.@flow_stop to False to correctly update existing databases bzr revid: odo@openerp.com-20131021155120-vn63of44ya0od9e2 --- addons/hr_holidays/hr_holidays_workflow.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/hr_holidays/hr_holidays_workflow.xml b/addons/hr_holidays/hr_holidays_workflow.xml index b563dbf68d4..c539ff6de41 100644 --- a/addons/hr_holidays/hr_holidays_workflow.xml +++ b/addons/hr_holidays/hr_holidays_workflow.xml @@ -55,6 +55,7 @@ refuse + function holidays_refuse() From d97bd2bce2bd9b5c338541ac43268eacb04fbd9e Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 22 Oct 2013 12:41:45 +0200 Subject: [PATCH 4/6] [FIX] web: avoid useless redirection when in mono db mode bzr revid: chs@openerp.com-20131022104145-janmthq1r6sibm2e --- addons/web/controllers/main.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 2d585fe2466..9584c53ca5b 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -529,12 +529,14 @@ class Home(http.Controller): def index(self, s_action=None, db=None, debug=False, **kw): debug = debug != False - lst = http.db_list(True) + try: + lst = http.db_list() + except openerp.exceptions.AccessDenied: + lst = [] + if db not in lst: db = None guessed_db = http.db_monodb(request.httprequest) - if guessed_db is None and len(lst) > 0: - guessed_db = lst[0] def redirect(db): query = dict(urlparse.parse_qsl(request.httprequest.query_string, keep_blank_values=True)) @@ -542,8 +544,11 @@ class Home(http.Controller): redirect = request.httprequest.path + '?' + urllib.urlencode(query) return redirect_with_hash(redirect) - if db is None and guessed_db is not None: - return redirect(guessed_db) + if guessed_db is None and db is None and lst: + return redirect(lst[0]) + + if guessed_db is None and lst: + guessed_db = lst[0] if db is not None and db != guessed_db: request.session.logout() From 91fdcc63a73f882d58316a55631012a17e10f6ca Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 22 Oct 2013 15:10:49 +0200 Subject: [PATCH 5/6] [FIX] board: correct /board/add_to_dashboard to use new @route decorator and request object bzr revid: chs@openerp.com-20131022131049-lb6mva47y0i3kpvq --- addons/board/controllers.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/addons/board/controllers.py b/addons/board/controllers.py index 3bdebe1ef26..93634627352 100644 --- a/addons/board/controllers.py +++ b/addons/board/controllers.py @@ -1,24 +1,22 @@ # -*- coding: utf-8 -*- from xml.etree import ElementTree -import openerp from openerp.addons.web.controllers.main import load_actions_from_ir_values +from openerp.addons.web.http import Controller, route, request -class Board(openerp.addons.web.http.Controller): - _cp_path = '/board' - - @openerp.addons.web.http.jsonrequest - def add_to_dashboard(self, req, menu_id, action_id, context_to_save, domain, view_mode, name=''): +class Board(Controller): + @route('/board/add_to_dashboard', type='json', auth='user') + def add_to_dashboard(self, menu_id, action_id, context_to_save, domain, view_mode, name=''): # FIXME move this method to board.board model - dashboard_action = load_actions_from_ir_values( - req, 'action', 'tree_but_open', [('ir.ui.menu', menu_id)], False) + dashboard_action = load_actions_from_ir_values('action', 'tree_but_open', + [('ir.ui.menu', menu_id)], False) if dashboard_action: action = dashboard_action[0][2] if action['res_model'] == 'board.board' and action['views'][0][1] == 'form': # Maybe should check the content instead of model board.board ? view_id = action['views'][0][0] - board = req.session.model(action['res_model']).fields_view_get(view_id, 'form') + board = request.session.model(action['res_model']).fields_view_get(view_id, 'form') if board and 'arch' in board: xml = ElementTree.fromstring(board['arch']) column = xml.find('./board/column') @@ -32,10 +30,10 @@ class Board(openerp.addons.web.http.Controller): }) column.insert(0, new_action) arch = ElementTree.tostring(xml, 'utf-8') - return req.session.model('ir.ui.view.custom').create({ - 'user_id': req.session._uid, + return request.session.model('ir.ui.view.custom').create({ + 'user_id': request.session.uid, 'ref_id': view_id, 'arch': arch - }, req.context) + }, request.context) return False From c58f13c8e91f193201dba08b63c19c16617870d6 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Tue, 22 Oct 2013 19:10:10 +0200 Subject: [PATCH 6/6] [FIX] im: do not search users before start polling. This avoid a race condition for im.user creation bzr revid: chs@openerp.com-20131022171010-ilfvqced6q8qta3h --- addons/im/static/src/js/im.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/addons/im/static/src/js/im.js b/addons/im/static/src/js/im.js index 6fbf452f974..f4b74adebf6 100644 --- a/addons/im/static/src/js/im.js +++ b/addons/im/static/src/js/im.js @@ -62,16 +62,12 @@ this.user_search_dm = new instance.web.DropMisordered(); }, start: function() { + var self = this; this.$el.css("right", -this.$el.outerWidth()); $(window).scroll(_.bind(this.calc_box, this)); $(window).resize(_.bind(this.calc_box, this)); this.calc_box(); - this.on("change:current_search", this, this.search_changed); - this.search_changed(); - - var self = this; - return this.c_manager.start_polling().then(function() { self.c_manager.on("new_conversation", self, function(conv) { conv.$el.droppable({ @@ -80,6 +76,7 @@ } }); }); + self.search_changed(); }); }, calc_box: function() { @@ -174,4 +171,4 @@ openerp.webclient.to_kitten(); }; -})(); \ No newline at end of file +})();