From ddb869f1804da7ad549dc9565653c861ab77ba0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20van=20der=20Essen?= Date: Fri, 5 Oct 2012 16:06:16 +0200 Subject: [PATCH 01/33] [FIX] fixing css errors as reported by firefox bzr revid: fva@openerp.com-20121005140616-w5tulvk6v6hesjmn --- addons/point_of_sale/static/src/css/pos.css | 2 +- addons/process/static/src/css/process.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/point_of_sale/static/src/css/pos.css b/addons/point_of_sale/static/src/css/pos.css index cbb625c02d7..81c6a1e1a6e 100644 --- a/addons/point_of_sale/static/src/css/pos.css +++ b/addons/point_of_sale/static/src/css/pos.css @@ -897,7 +897,7 @@ width: 100%; height: 100%; margin: 0; - margin-right: 18px + margin-right: 18px; font-family: "Inconsolata"; color: #6c6c6c; text-shadow: 0px 3px 3px rgba(0,0,0, 0.2); diff --git a/addons/process/static/src/css/process.css b/addons/process/static/src/css/process.css index 7442db9bc4a..5f438622653 100644 --- a/addons/process/static/src/css/process.css +++ b/addons/process/static/src/css/process.css @@ -44,7 +44,7 @@ a.cta-a strong { background-color:#FFF; } .process_canvas svg{ - height:500px;!important; + height:500px; padding:15px; } .oe_process { From d09f14df7e26dbd70d63600305b5a9231e4749fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 15 Oct 2012 13:12:24 +0200 Subject: [PATCH 02/33] [REV] Reverted commenting mail tests... seems weird to comment tests. bzr revid: tde@openerp.com-20121015111224-7vzt4zthbzs96bb2 --- addons/mail/tests/test_mail_access_rights.py | 92 ++++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/addons/mail/tests/test_mail_access_rights.py b/addons/mail/tests/test_mail_access_rights.py index 4d40c66fc81..104d7f28ffe 100644 --- a/addons/mail/tests/test_mail_access_rights.py +++ b/addons/mail/tests/test_mail_access_rights.py @@ -102,53 +102,53 @@ class test_mail_access_rights(test_mail.TestMailMockups): """ Test mail_message search override about access rights. """ self.assertTrue(1 == 1, 'Test not implemented, do not replace by return True') - # 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 + 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'}) + # 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 - # # ---------------------------------------- - # # 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 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 - # 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], [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') + # ---------------------------------------- + # 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 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 + 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], [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 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: 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 - # # ---------------------------------------- - # # 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 group_public_id = employee - # self.mail_group.read(cr, user_raoul_id, self.group_jobs_id) + # ---------------------------------------- + # CASE1: Raoul, employee + # ---------------------------------------- + # 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 group_public_id = employee + self.mail_group.read(cr, user_raoul_id, self.group_jobs_id) From d7a38755166bba022ec8a913e9dd733cb8776a5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 15 Oct 2012 14:03:31 +0200 Subject: [PATCH 03/33] [CLEAN] [FIX] mail_followers widget: small cleanup of code, fixed wrong display of follower button when having more than one follower. bzr revid: tde@openerp.com-20121015120331-uiv40j3d9fxqhopt --- addons/mail/static/src/css/mail.css | 8 ++-- addons/mail/static/src/js/mail_followers.js | 40 +++++++++---------- addons/mail/static/src/xml/mail_followers.xml | 10 ++--- 3 files changed, 26 insertions(+), 32 deletions(-) diff --git a/addons/mail/static/src/css/mail.css b/addons/mail/static/src/css/mail.css index 1592d79e18d..0f1f90d04fb 100644 --- a/addons/mail/static/src/css/mail.css +++ b/addons/mail/static/src/css/mail.css @@ -143,12 +143,12 @@ /* subtypes /* ------------------------------------------------------------ */ -.openerp .oe_mouse_subtypes { +.openerp .oe_mail_subtypes { display:inline-block; position: relative; z-index: 5; } -.openerp .oe_mouse_subtypes .oe_recthread_subtypes { +.openerp .oe_mail_subtypes .oe_recthread_subtypes { background: #fff; padding: 2px; border: 1px solid #aaaaaa; @@ -156,10 +156,10 @@ position: absolute; z-index: 2; } -.openerp .oe_mouse_subtypes.oe_mouseout .oe_recthread_subtypes { +.openerp .oe_mail_subtypes.oe_mouseout .oe_recthread_subtypes { display: none; } -.openerp .oe_mouse_subtypes.oe_mouseover .oe_recthread_subtypes { +.openerp .oe_mail_subtypes.oe_mouseover .oe_recthread_subtypes { display: block; } diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index 236e3081136..0dd3aef5571 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -26,7 +26,6 @@ openerp_mail_followers = function(session, mail) { this._super.apply(this, arguments); this.options.image = this.node.attrs.image || 'image_small'; this.options.title = this.node.attrs.title || 'Followers'; - this.options.context = this.node.attrs.context; this.options.comment = this.node.attrs.help || false; this.ds_model = new session.web.DataSetSearch(this, this.view.model); this.sub_model = new session.web.DataSetSearch(this,'mail.message.subtype'); @@ -55,16 +54,14 @@ openerp_mail_followers = function(session, mail) { bind_events: function() { var self = this; this.$('button.oe_follower') - .on('click', function () { + .on('click', function (event) { if($(this).hasClass('oe_notfollow')) self.do_follow(); else self.do_unfollow(); }); - - this.$el.on('click', 'ul.oe_subtypes input', self.do_update_subscription ); - - this.$el.on('click', 'button.oe_invite', function(event) { + this.$('ul.oe_subtypes input').on('click', self.do_update_subscription); + this.$('button.oe_invite').on('click', function (event) { action = { type: 'ir.actions.act_window', res_model: 'mail.wizard.invite', @@ -93,23 +90,13 @@ openerp_mail_followers = function(session, mail) { return this.fetch_followers(value_ || this.get_value()); }, - set_is_follower: function(value_) { - for(var i in value_){ - if(value_[i]['user_ids'][0]==this.session.uid) - this.message_is_follower=true; - this.display_buttons(); - return true; - } - this.message_is_follower=false; - this.display_buttons(); - return false; - }, - fetch_followers: function (value_) { this.value = value_ || {}; this.message_is_follower = (this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value()); if(value_) - return this.ds_follow.call('read', [this.value, ['name', 'user_ids']]).pipe(this.proxy('display_followers'), this.proxy('display_generic')); + return this.ds_follow.call('read', [this.value, ['name', 'user_ids']]) + .pipe(this.proxy('display_followers'), this.proxy('display_generic')) + .pipe(this.proxy('display_buttons')); }, /* Display generic info about follower, for people not having access to res_partner */ @@ -125,8 +112,6 @@ openerp_mail_followers = function(session, mail) { content += ' (' + this.value.length + ')' } this.$('div.oe_mail_recthread_followers h4').html(content); - this.display_buttons(); - return $.when(); }, /** Display the followers, evaluate is_follower directly */ @@ -142,6 +127,17 @@ openerp_mail_followers = function(session, mail) { self.set_is_follower(records); }, + /** Computes whether the current user is in the followers */ + set_is_follower: function(value_) { + this.message_is_follower = false; + for(var i in value_) { + if (value_[i]['user_ids'][0] == this.session.uid) { + this.message_is_follower = true; + return true; + } + } + }, + display_buttons: function () { if (this.message_is_follower) { this.$('button.oe_follower').removeClass('oe_notfollow').addClass('oe_following'); @@ -149,7 +145,7 @@ openerp_mail_followers = function(session, mail) { else { this.$('button.oe_follower').removeClass('oe_following').addClass('oe_notfollow'); } - + if (this.view.is_action_enabled('edit')) this.$('span.oe_mail_invite_wrapper').hide(); else diff --git a/addons/mail/static/src/xml/mail_followers.xml b/addons/mail/static/src/xml/mail_followers.xml index f78c91c6305..87b49579100 100644 --- a/addons/mail/static/src/xml/mail_followers.xml +++ b/addons/mail/static/src/xml/mail_followers.xml @@ -7,7 +7,7 @@ -->
-
+
-
- -
-
-
+ +
+
From ad54dfbbf6d73e5e5509ccaa11e15762858fc1bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 15 Oct 2012 15:23:13 +0200 Subject: [PATCH 04/33] [FIX] [CLEAN] mail_thrad: fixed subtypes (not comment by default, but Chatter explicitely set the new message as a comment); some code cleaning. bzr revid: tde@openerp.com-20121015132313-zmip3v7sv4y90lzr --- addons/mail/mail_group.py | 2 +- addons/mail/mail_thread.py | 106 +++++++++++++++--------------- addons/mail/res_partner.py | 2 +- addons/mail/static/src/js/mail.js | 2 +- 4 files changed, 56 insertions(+), 56 deletions(-) diff --git a/addons/mail/mail_group.py b/addons/mail/mail_group.py index 3febe34be51..644718fdfb9 100644 --- a/addons/mail/mail_group.py +++ b/addons/mail/mail_group.py @@ -30,7 +30,7 @@ class mail_group(osv.Model): group. The group mechanics are based on the followers. """ _description = 'Discussion group' _name = 'mail.group' - _mail_autothread = False + _mail_flat_thread = False _inherit = ['mail.thread'] _inherits = {'mail.alias': 'alias_id', 'ir.ui.menu': 'menu_id'} diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index e5b93ac4000..6388ad76457 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -57,10 +57,16 @@ class mail_thread(osv.AbstractModel): to override at least the ``message_new`` and ``message_update`` methods (calling ``super``) to add model-specific behavior at creation and update of a thread when processing incoming emails. + + Options: + - _mail_flat_thread: if set to True, all messages without parent_id + are automatically attached to the first message posted on the + ressource. If set to False, the display of Chatter is done using + threads, and no parent_id is automatically set. ''' _name = 'mail.thread' _description = 'Email Thread' - _mail_autothread = True + _mail_flat_thread = True def _get_message_data(self, cr, uid, ids, name, args, context=None): """ Computes: @@ -84,7 +90,7 @@ class mail_thread(osv.AbstractModel): res[thread.id]['message_summary'] = "9 %d + %d" % (cls, len(thread.message_comment_ids), len(thread.message_follower_ids)) return res - + def _get_subscription_data(self, cr, uid, ids, name, args, context=None): """ Computes: - message_is_follower: is uid in the document followers @@ -113,7 +119,7 @@ class mail_thread(osv.AbstractModel): for subtype in fol.subtype_ids: thread_subtype_dict[subtype.name]['followed'] = True res[fol.res_id]['message_subtype_data'] = thread_subtype_dict - + return res def _search_unread(self, cr, uid, obj=None, name=None, domain=None, context=None): @@ -633,8 +639,10 @@ class mail_thread(osv.AbstractModel): (isinstance(thread_id, (list, tuple)) and len(thread_id) == 1), "Invalid thread_id" if isinstance(thread_id, (list, tuple)): thread_id = thread_id and thread_id[0] + mail_message = self.pool.get('mail.message') + model = context.get('thread_model', self._name) if thread_id else False - attachment_ids=[] + attachment_ids = [] for name, content in attachments: if isinstance(content, unicode): content = content.encode('utf-8') @@ -648,24 +656,20 @@ class mail_thread(osv.AbstractModel): } attachment_ids.append((0, 0, data_attach)) - # get subtype - if not subtype: - subtype = 'mail.mt_comment' - s = subtype.split('.') - if len(s)==1: - s = ('mail', s[0]) - ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, s[0], s[1]) - subtype_id = ref and ref[1] or False - - model = context.get('thread_model', self._name) if thread_id else False - messages = self.pool.get('mail.message') - - #auto link messages for same id and object - if self._mail_autothread and thread_id: - message_ids = messages.search(cr, uid, ['&',('res_id', '=', thread_id),('model','=',model)], context=context) - if len(message_ids): - parent_id = min(message_ids) + # fetch subtype + if subtype: + s_data = subtype.split('.') + if len(s_data) == 1: + s_data = ('mail', s_data[0]) + ref = self.pool.get('ir.model.data').get_object_reference(cr, uid, s_data[0], s_data[1]) + subtype_id = ref and ref[1] or False + else: + subtype_id = False + # _mail_flat_thread: automatically set free messages to the first posted message + if self._mail_flat_thread and not parent_id and thread_id: + message_ids = mail_message.search(cr, uid, ['&', ('res_id', '=', thread_id), ('model', '=', model)], context=context, order="id ASC", limit=1) + parent_id = message_ids and message_ids[0] or False values = kwargs values.update({ @@ -681,51 +685,47 @@ class mail_thread(osv.AbstractModel): # if the parent is private, the message must be private if parent_id: - msg = messages.browse(cr, uid, parent_id, context=context) - if msg.is_private: - values["is_private"] = msg.is_private + parent_message = mail_message.browse(cr, uid, parent_id, context=context) + if parent_message.is_private: + values["is_private"] = parent_message.is_private # Avoid warnings about non-existing fields for x in ('from', 'to', 'cc'): values.pop(x, None) - return messages.create(cr, uid, values, context=context) + return mail_message.create(cr, uid, values, context=context) + + def message_post_api(self, cr, uid, thread_id, body='', subject=False, type='notification', + subtype=None, parent_id=False, attachments=None, context=None, **kwargs): + # when writing on res.partner, without specific thread_id -> redirect to the user's partner + if self._name == 'res.partner' and not thread_id: + thread_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=type, + subtype=subtype, parent_id=parent_id, context=context) + # Chatter: attachments linked to the document (not done JS-side), load the message + if attachments: + ir_attachment = self.pool.get('ir.attachment') + mail_message = self.pool.get('mail.message') + attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [('res_model', '=', False), ('res_id', '=', False), ('user_id', '=', uid), ('id', 'in', attachments)], context=context) + if attachment_ids: + ir_attachment.write(cr, SUPERUSER_ID, attachment_ids, {'res_model': self._name, 'res_id': thread_id}, context=context) + mail_message.write(cr, SUPERUSER_ID, [new_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]}) + new_message = self.pool.get('mail.message').message_read(cr, uid, [new_message_id]) + return new_message #------------------------------------------------------ # Followers API #------------------------------------------------------ - def message_post_api(self, cr, uid, thread_id, body='', subject=False, type='notification', - subtype=None, parent_id=False, attachments=None, context=None, **kwargs): - # if the user write on his wall - if self._name=='res.partner' and not thread_id: - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - thread_id = user.partner_id.id - - added_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=type, - subtype=subtype, parent_id=parent_id, context=context) - - attachment_ids=[] - if attachments: - ir_attachment = self.pool.get('ir.attachment') - attachment_ids = ir_attachment.search(cr, 1, [('res_model', '=', ""), ('res_id', '=', ""), ('user_id', '=', uid), ('id', 'in', attachments)], context=context) - if attachment_ids: - self.pool.get('ir.attachment').write(cr, 1, attachment_ids, { 'res_model': self._name, 'res_id': thread_id }, context=context) - self.pool.get('mail.message').write(cr, 1, [added_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]} ) - - added_message = self.pool.get('mail.message').message_read(cr, uid, [added_message_id]) - return added_message - def get_message_subtypes(self, cr, uid, ids, context=None): - """ message_subtype_data: data about document subtypes: which are - available, which are followed if any """ + """ Wrapper to get subtypes. """ return self._get_subscription_data(cr, uid, ids, None, None, context=context) def message_subscribe_users(self, cr, uid, ids, user_ids=None, subtype_ids=None, context=None): """ Wrapper on message_subscribe, using users. If user_ids is not provided, subscribe uid instead. """ - if not user_ids: - return False + if user_ids is None: + user_ids = [uid] partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)] return self.message_subscribe(cr, uid, ids, partner_ids, subtype_ids=subtype_ids, context=context) @@ -738,14 +738,14 @@ class mail_thread(osv.AbstractModel): subtype_ids = subtype_obj.search(cr, uid, [('default', '=', True), '|', ('res_model', '=', self._name), ('res_model', '=', False)], context=context) # update the subscriptions fol_obj = self.pool.get('mail.followers') - fol_ids = fol_obj.search(cr, 1, [('res_model', '=', self._name), ('res_id', 'in', ids), ('partner_id', 'in', partner_ids)], context=context) - fol_obj.write(cr, 1, fol_ids, {'subtype_ids': [(6, 0, subtype_ids)]}, context=context) + fol_ids = fol_obj.search(cr, SUPERUSER_ID, [('res_model', '=', self._name), ('res_id', 'in', ids), ('partner_id', 'in', partner_ids)], context=context) + fol_obj.write(cr, SUPERUSER_ID, fol_ids, {'subtype_ids': [(6, 0, subtype_ids)]}, context=context) return True def message_unsubscribe_users(self, cr, uid, ids, user_ids=None, context=None): """ Wrapper on message_subscribe, using users. If user_ids is not provided, unsubscribe uid instead. """ - if not user_ids: + if user_ids is None: user_ids = [uid] partner_ids = [user.partner_id.id for user in self.pool.get('res.users').browse(cr, uid, user_ids, context=context)] return self.message_unsubscribe(cr, uid, ids, partner_ids, context=context) diff --git a/addons/mail/res_partner.py b/addons/mail/res_partner.py index 363ea74d16c..6b13fe6ad20 100644 --- a/addons/mail/res_partner.py +++ b/addons/mail/res_partner.py @@ -25,7 +25,7 @@ class res_partner_mail(osv.Model): """ Update partner to add a field about notification preferences """ _name = "res.partner" _inherit = ['res.partner', 'mail.thread'] - _mail_autothread = False + _mail_flat_thread = False _columns = { 'notification_email_send': fields.selection([ diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 15a81be4c54..7aa8a11f62a 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -387,7 +387,7 @@ openerp.mail = function(session) { mail.ChatterUtils.get_text2html(body), false, 'comment', - false, + 'mail.mt_comment',, this.context.default_parent_id, attachments] ).then(this.parent_thread.proxy('switch_new_message')); From 55700ac6616b2fdc77caed5d0953df0a48fba4c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 15 Oct 2012 15:34:38 +0200 Subject: [PATCH 05/33] [CLEAN] get_message_subtypes -> message_get_subscription_data bzr revid: tde@openerp.com-20121015133438-oqbe24v80y0ayimn --- addons/mail/mail_thread.py | 12 +++++++++--- addons/mail/static/src/js/mail_followers.js | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 6388ad76457..cfc2992ecde 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -36,6 +36,7 @@ from tools.safe_eval import safe_eval as eval _logger = logging.getLogger(__name__) + def decode_header(message, header, separator=' '): return separator.join(map(decode, message.get_all(header, []))) @@ -404,7 +405,8 @@ class mail_thread(osv.AbstractModel): overrides the automatic detection based on the message headers. """ - if context is None: context = {} + if context is None: + context = {} # extract message bytes - we are forced to pass the message as binary because # we don't know its encoding until we parse its headers and hence can't @@ -420,7 +422,8 @@ class mail_thread(osv.AbstractModel): thread_id, custom_values, context=context) msg = self.message_parse(cr, uid, msg_txt, save_original=save_original, context=context) - if strip_attachments: msg.pop('attachments', None) + if strip_attachments: + msg.pop('attachments', None) thread_id = False for model, thread_id, custom_values, user_id in routes: if self._name != model: @@ -700,8 +703,10 @@ class mail_thread(osv.AbstractModel): # when writing on res.partner, without specific thread_id -> redirect to the user's partner if self._name == 'res.partner' and not thread_id: thread_id = self.pool.get('res.users').read(cr, uid, uid, ['partner_id'], context=context)['partner_id'][0] + new_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=type, subtype=subtype, parent_id=parent_id, context=context) + # Chatter: attachments linked to the document (not done JS-side), load the message if attachments: ir_attachment = self.pool.get('ir.attachment') @@ -711,13 +716,14 @@ class mail_thread(osv.AbstractModel): ir_attachment.write(cr, SUPERUSER_ID, attachment_ids, {'res_model': self._name, 'res_id': thread_id}, context=context) mail_message.write(cr, SUPERUSER_ID, [new_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]}) new_message = self.pool.get('mail.message').message_read(cr, uid, [new_message_id]) + return new_message #------------------------------------------------------ # Followers API #------------------------------------------------------ - def get_message_subtypes(self, cr, uid, ids, context=None): + def message_get_subscription_data(self, cr, uid, ids, context=None): """ Wrapper to get subtypes. """ return self._get_subscription_data(cr, uid, ids, None, None, context=context) diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index 0dd3aef5571..eff3f904b71 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -171,7 +171,7 @@ openerp_mail_followers = function(session, mail) { if(subtype_list_ul.is(":empty")) { var context = new session.web.CompoundContext(this.build_context(), {}); - this.ds_model.call('get_message_subtypes',[[self.view.datarecord.id], context]).pipe(this.proxy('set_subtypes')); + this.ds_model.call('message_get_subscription_data',[[self.view.datarecord.id], context]).pipe(this.proxy('set_subtypes')); } }, From 4525b411e91b7fed75ba3809355e65c965765d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 15 Oct 2012 17:11:27 +0200 Subject: [PATCH 06/33] [IMP] mail.followers: users can now read their own subscriptions. bzr revid: tde@openerp.com-20121015151127-5abtwg8uraj0du0u --- addons/mail/security/ir.model.access.csv | 2 +- addons/mail/security/mail_security.xml | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/addons/mail/security/ir.model.access.csv b/addons/mail/security/ir.model.access.csv index b68a9ab7443..c609667c26e 100644 --- a/addons/mail/security/ir.model.access.csv +++ b/addons/mail/security/ir.model.access.csv @@ -3,7 +3,7 @@ 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,,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_all,mail.followers.all,model_mail_followers,,1,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,,1,0,0,0 access_mail_notification_aystem,mail.notification.system,model_mail_notification,base.group_system,1,1,1,1 diff --git a/addons/mail/security/mail_security.xml b/addons/mail/security/mail_security.xml index be3bb667628..c8d37f333c7 100644 --- a/addons/mail/security/mail_security.xml +++ b/addons/mail/security/mail_security.xml @@ -3,13 +3,22 @@ - + Mail.group: access only public and joined groups ['|', '|', ('public', '=', 'public'), ('message_follower_ids', 'in', [user.partner_id.id]), '&', ('public','=','groups'), ('group_public_id','in', [g.id for g in user.groups_id])] + + mail.followers: read its own entries + + + [('partner_id', '=', user.partner_id.id)] + + + + + + + + + + - + /> - + @@ -30,68 +34,11 @@
-
-
- - - - - Compose Email mail.compose.message From cb3463780add5c7798fa2e6765a3a06bd94c9c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 17 Oct 2012 11:28:07 +0200 Subject: [PATCH 13/33] [FIX] Chatter widget: fixed model sent to the compose wizard. bzr revid: tde@openerp.com-20121017092807-7uvax8ren3iqz1n9 --- addons/mail/static/src/js/mail.js | 35 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 1f6aa1976c6..026b7b47240 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -300,22 +300,23 @@ openerp.mail = function(session) { /* to avoid having unsorted file on the server. we will show the users files of the first message post + TDE note: unnecessary call to server I think */ - set_free_attachments: function(){ - var self=this; - this.parent_thread.ds_message.call('user_free_attachment').then(function(attachments){ - this.attachment_ids=[]; - for(var i in attachments){ - self.attachment_ids[i]={ - 'id': attachments[i].id, - 'name': attachments[i].name, - 'filename': attachments[i].filename, - 'url': mail.ChatterUtils.get_attachment_url(self.session, attachments[i]) - }; - } - self.display_attachments(); - }); - }, + // set_free_attachments: function(){ + // var self=this; + // this.parent_thread.ds_message.call('user_free_attachment').then(function(attachments){ + // this.attachment_ids=[]; + // for(var i in attachments){ + // self.attachment_ids[i]={ + // 'id': attachments[i].id, + // 'name': attachments[i].name, + // 'filename': attachments[i].filename, + // 'url': mail.ChatterUtils.get_attachment_url(self.session, attachments[i]) + // }; + // } + // self.display_attachments(); + // }); + // }, bind_events: function() { var self = this; @@ -341,7 +342,7 @@ openerp.mail = function(session) { views: [[false, 'form']], target: 'new', context: { - 'default_res_model': this.context.default_res_model, + 'default_model': this.context.default_model, 'default_res_id': this.context.default_res_id, 'default_content_subtype': 'html', 'default_is_private': true, @@ -867,7 +868,7 @@ openerp.mail = function(session) { return display_done && compose_done; }, - instantiate_ComposeMessage: function(){ + instantiate_ComposeMessage: function() { // add message composition form view this.ComposeMessage = new mail.ThreadComposeMessage(this,{ 'context': this.context, From ae1985702b243a9c6879402bab0cef22796be964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 17 Oct 2012 11:29:38 +0200 Subject: [PATCH 14/33] [REM] email_template: removed overrided chatter form view; updated legacy wizard form view. bzr revid: tde@openerp.com-20121017092938-8ulu2h3ml9on4iu9 --- .../wizard/mail_compose_message.py | 3 +- .../wizard/mail_compose_message_view.xml | 34 ++++--------------- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/addons/email_template/wizard/mail_compose_message.py b/addons/email_template/wizard/mail_compose_message.py index c0cb7fc92e5..fe6f85da544 100644 --- a/addons/email_template/wizard/mail_compose_message.py +++ b/addons/email_template/wizard/mail_compose_message.py @@ -24,7 +24,8 @@ import tools from osv import osv from osv import fields -class mail_compose_message(osv.osv_memory): + +class mail_compose_message(osv.TransientModel): _inherit = 'mail.compose.message' def _get_templates(self, cr, uid, context=None): diff --git a/addons/email_template/wizard/mail_compose_message_view.xml b/addons/email_template/wizard/mail_compose_message_view.xml index 655f5b9d0c2..c2fe7dc6157 100644 --- a/addons/email_template/wizard/mail_compose_message_view.xml +++ b/addons/email_template/wizard/mail_compose_message_view.xml @@ -8,38 +8,16 @@ - - - -
- - File Format Options… -
-

- - - -

+
+ + + +
@@ -54,7 +56,7 @@ simpler especially when the file has many columns.

- +

Frequently Asked Questions

From 1c7859c67a70c50b5ae42306d3bbb78c897e95b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 18 Oct 2012 11:13:27 +0200 Subject: [PATCH 27/33] [IMP] [FIX] mail_followers widget: fixed buggy button; fixed subtypes displayed only if the current user is following the document; various code cleaning. bzr revid: tde@openerp.com-20121018091327-bt7dyi7pn9w11lsa --- addons/mail/static/src/js/mail_followers.js | 124 +++++++++++--------- 1 file changed, 68 insertions(+), 56 deletions(-) diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js index ab28198fdbd..ab45d27eef6 100644 --- a/addons/mail/static/src/js/mail_followers.js +++ b/addons/mail/static/src/js/mail_followers.js @@ -27,10 +27,10 @@ openerp_mail_followers = function(session, mail) { this.options.image = this.node.attrs.image || 'image_small'; this.options.title = this.node.attrs.title || 'Followers'; this.options.comment = this.node.attrs.help || false; + this.options.displayed_nb = this.node.attrs.displayed_nb || 10; this.ds_model = new session.web.DataSetSearch(this, this.view.model); - this.sub_model = new session.web.DataSetSearch(this,'mail.message.subtype'); this.ds_follow = new session.web.DataSetSearch(this, this.field.relation); - this.follower_model = new session.web.DataSetSearch(this,'mail.followers'); + this.ds_users = new session.web.DataSetSearch(this, 'res.users'); }, start: function() { @@ -39,7 +39,6 @@ openerp_mail_followers = function(session, mail) { this._check_visibility(); this.reinit(); this.bind_events(); - this.display_subtypes(); }, _check_visibility: function() { @@ -53,14 +52,17 @@ openerp_mail_followers = function(session, mail) { bind_events: function() { var self = this; - this.$('button.oe_follower').on('click', function (event) { + // event: click on '(Un)Follow' button, that toggles the follow for uid + this.$('.oe_follower').on('click', function (event) { if($(this).hasClass('oe_notfollow')) self.do_follow(); else self.do_unfollow(); }); - this.$('ul.oe_subtypes input').on('click', self.do_update_subscription); - this.$('button.oe_invite').on('click', function (event) { + // event: click on a subtype, that (un)subscribe for this subtype + this.$el.on('click', 'ul.oe_subtypes input', self.do_update_subscription); + // event: click on 'invite' button, that opens the invite wizard + this.$('.oe_invite').on('click', function (event) { action = { type: 'ir.actions.act_window', res_model: 'mail.wizard.invite', @@ -81,38 +83,55 @@ openerp_mail_followers = function(session, mail) { }); }, - read_value: function() { + read_value: function () { var self = this; return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).pipe(function (results) { self.set_value(results[0].message_follower_ids); }); }, - render_value: function() { + set_value: function (value_) { + this._super(value_); + // TDE FIXME: render_value is never called... ask to niv + this.render_value(); + }, + + render_value: function () { this.reinit(); return this.fetch_followers(this.get("value")); }, fetch_followers: function (value_) { this.value = value_ || {}; - if (value_) - return this.ds_follow.call('read', [this.value, ['name', 'user_ids']]) - .pipe(this.proxy('display_followers'), this.proxy('display_generic')) - .pipe(this.proxy('display_buttons')); + return this.ds_follow.call('read', [this.value, ['name', 'user_ids']]) + .pipe(this.proxy('display_followers'), this.proxy('fetch_generic')) + .pipe(this.proxy('display_buttons')) + .pipe(this.proxy('fetch_subtypes')); + }, + + /** Read on res.partner failed: fall back on a generic case + - fetch current user partner_id (call because no other smart solution currently) FIXME + - then display a generic message about followers */ + fetch_generic: function (error, event) { + var self = this; + event.preventDefault(); + return this.ds_users.call('read', [this.session.uid, ['partner_id']]).pipe(function (results) { + var pid = results['partner_id'][0]; + self.message_is_follower = (_.indexOf(self.get('value'), pid) != -1); + }).pipe(self.proxy('display_generic')); }, /* Display generic info about follower, for people not having access to res_partner */ - display_generic: function (error, event) { - event.preventDefault(); - this.message_is_follower = false; + display_generic: function () { + var self = this; var node_user_list = this.$('ul.oe_mail_followers_display').empty(); // format content: Followers (You and 0 other) // Followers (3) var content = this.options.title; if (this.message_is_follower) { - content += ' (You and ' + (this.value.length-1) + ' other)'; + content += ' (You and ' + (this.get('value').length-1) + ' other)'; } else { - content += ' (' + this.value.length + ')' + content += ' (' + this.get('value').length + ')' } this.$('div.oe_mail_recthread_followers h4').html(content); }, @@ -121,23 +140,24 @@ openerp_mail_followers = function(session, mail) { display_followers: function (records) { var self = this; this.message_is_follower = this.set_is_follower(records); + // clean and display title var node_user_list = this.$('ul.oe_mail_followers_display').empty(); - this.$('div.oe_mail_recthread_followers h4').html(this.options.title + (records.length>=5 ? ' (' + records.length + ')' : '') ); - for(var i=0; iAnd ' + (records.length - truncated.length) + ' more.').appendTo(node_user_list); } }, /** Computes whether the current user is in the followers */ - set_is_follower: function(records) { - for(var i in records) { - if (records[i]['user_ids'][0] == this.session.uid) { - return true; - } - } - return false; + set_is_follower: function (records) { + var user_ids = _.pluck(_.pluck(records, 'user_ids'), 0); + return _.indexOf(user_ids, this.session.uid) != -1; }, display_buttons: function () { @@ -154,8 +174,18 @@ openerp_mail_followers = function(session, mail) { this.$('span.oe_mail_invite_wrapper').show(); }, - set_subtypes:function(data){ + /** Fetch subtypes, only if current user is follower */ + fetch_subtypes: function () { + var subtype_list_ul = this.$('.oe_subtypes').empty(); + if (! this.message_is_follower) return; + var context = new session.web.CompoundContext(this.build_context(), {}); + this.ds_model.call('message_get_subscription_data', [[this.view.datarecord.id], context]).pipe(this.proxy('display_subtypes')); + }, + + /** Display subtypes: {'name': default, followed} */ + display_subtypes:function (data) { var self = this; + var subtype_list_ul = this.$('.oe_subtypes'); var records = (data[this.view.datarecord.id] || data[null]).message_subtype_data; _(records).each(function (record, record_name) { @@ -165,27 +195,15 @@ openerp_mail_followers = function(session, mail) { }); }, - /** Display subtypes: {'name': default, followed} */ - display_subtypes: function (visible) { - var self = this; - var recthread_subtypes = self.$('.oe_recthread_subtypes'); - subtype_list_ul = self.$('ul.oe_subtypes'); - - if(subtype_list_ul.is(":empty")) { - var context = new session.web.CompoundContext(this.build_context(), {}); - this.ds_model.call('message_get_subscription_data',[[self.view.datarecord.id], context]).pipe(this.proxy('set_subtypes')); - } - }, - do_follow: function () { - _(this.$('.oe_msg_subtype_check')).each(function(record){ - $(record).attr('checked','checked'); + _(this.$('.oe_msg_subtype_check')).each(function (record) { + $(record).attr('checked', 'checked'); }); this.do_update_subscription(); }, do_unfollow: function () { - _(this.$('.oe_msg_subtype_check')).each(function(record){ + _(this.$('.oe_msg_subtype_check')).each(function (record) { $(record).attr('checked',false); }); var context = new session.web.CompoundContext(this.build_context(), {}); @@ -196,21 +214,15 @@ openerp_mail_followers = function(session, mail) { var self = this; var checklist = new Array(); - _(this.$('.oe_mail_recthread_actions input[type="checkbox"]')).each(function(record){ - if($(record).is(':checked')) { - checklist.push(parseInt($(record).data('id')))} + _(this.$('.oe_mail_recthread_actions input[type="checkbox"]')).each(function (record) { + if ($(record).is(':checked')) { + checklist.push(parseInt($(record).data('id'))) + } }); - if(!checklist.length) - return this.do_unfollow(); - else{ - var context = new session.web.CompoundContext(this.build_context(), {}); - return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], undefined, context]).pipe(function(value_){ - self.read_value(value_); - self.display_subtypes(true); - }); - } + var context = new session.web.CompoundContext(this.build_context(), {}); + return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], this.message_is_follower ? checklist:undefined, context]) + .pipe(this.proxy('read_value')); }, - }); }; From 51db8844bde14cb10dc0ddf76be592fa29338267 Mon Sep 17 00:00:00 2001 From: Stephane Wirtel Date: Thu, 18 Oct 2012 11:20:13 +0200 Subject: [PATCH 28/33] [IMP] mail: use the web.base.url parameter bzr revid: stw@openerp.com-20121018092013-6xo2hs9hizu0ro33 --- addons/mail/update.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/addons/mail/update.py b/addons/mail/update.py index 0e10ee0a7f1..9e35391bf52 100644 --- a/addons/mail/update.py +++ b/addons/mail/update.py @@ -41,6 +41,8 @@ def get_sys_logs(cr, uid): nbr_share_users = pool.get("res.users").search(cr, uid, [("share", "=", True)], count=True) nbr_active_share_users = pool.get("res.users").search(cr, uid, [("share", "=", True), ("date", ">=", limit_date_str)], count=True) user = pool.get("res.users").browse(cr, uid, uid) + + web_base_url = safe_eval(self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', 'False')) msg = { "dbuuid": dbuuid, "nbr_users": nbr_users, @@ -51,6 +53,7 @@ def get_sys_logs(cr, uid): "db_create_date": db_create_date, "version": release.version, "language": user.lang, + "web_base_url": web_base_url, } msg.update(pool.get("res.company").read(cr,uid,[1],["name","email","phone"])[0]) From 1737a3161b5c98eb6977d2e9b0ee90c50b4a355b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 18 Oct 2012 11:34:53 +0200 Subject: [PATCH 29/33] [REVIEW] Cleaning before merging. bzr revid: tde@openerp.com-20121018093453-trijh79z0j7oha6f --- .../wizard/mail_compose_message_view.xml | 1 - addons/mail/mail_message.py | 14 +++++++------- addons/mail/mail_thread.py | 4 ++-- addons/mail/security/mail_security.xml | 2 -- addons/mail/static/src/js/mail_followers.js | 2 +- 5 files changed, 10 insertions(+), 13 deletions(-) diff --git a/addons/email_template/wizard/mail_compose_message_view.xml b/addons/email_template/wizard/mail_compose_message_view.xml index c2fe7dc6157..a33135ca098 100644 --- a/addons/email_template/wizard/mail_compose_message_view.xml +++ b/addons/email_template/wizard/mail_compose_message_view.xml @@ -17,7 +17,6 @@ -