Thibault Delavallée (OpenERP) has proposed merging 
lp:~openerp-dev/openobject-addons/trunk-mail-clean-rule-tde into 
lp:openobject-addons.

Requested reviews:
  OpenERP Core Team (openerp)

For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-addons/trunk-mail-clean-rule-tde/+merge/129680
-- 
https://code.launchpad.net/~openerp-dev/openobject-addons/trunk-mail-clean-rule-tde/+merge/129680
Your team OpenERP R&D Team is subscribed to branch 
lp:~openerp-dev/openobject-addons/trunk-mail-clean-rule-tde.
=== modified file 'mail/mail_group.py'
--- mail/mail_group.py	2012-10-01 18:27:22 +0000
+++ mail/mail_group.py	2012-10-15 14:20:29 +0000
@@ -30,7 +30,7 @@
         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'}
 

=== modified file 'mail/mail_thread.py'
--- mail/mail_thread.py	2012-10-10 11:20:18 +0000
+++ mail/mail_thread.py	2012-10-15 14:20:29 +0000
@@ -57,10 +57,16 @@
         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 @@
             res[thread.id]['message_summary'] = "<span%s><span class='oe_e'>9</span> %d</span> <span><span class='oe_e'>+</span> %d</span>" % (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 @@
             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 @@
             (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 @@
             }
             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 @@
 
         # 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)
-
-    #------------------------------------------------------
-    # Followers API
-    #------------------------------------------------------
+        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):
-        # 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,
+        # 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)
-
-        attachment_ids=[]
+        # Chatter: attachments linked to the document (not done JS-side), load the message
         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)
+            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:
-                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
+                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):
-        """ 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 @@
             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)

=== modified file 'mail/res_partner.py'
--- mail/res_partner.py	2012-10-01 18:27:22 +0000
+++ mail/res_partner.py	2012-10-15 14:20:29 +0000
@@ -25,7 +25,7 @@
     """ 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([

=== modified file 'mail/static/src/css/mail.css'
--- mail/static/src/css/mail.css	2012-10-10 11:17:51 +0000
+++ mail/static/src/css/mail.css	2012-10-15 14:20:29 +0000
@@ -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;
 }
 

=== modified file 'mail/static/src/js/mail.js'
--- mail/static/src/js/mail.js	2012-10-15 13:33:34 +0000
+++ mail/static/src/js/mail.js	2012-10-15 14:20:29 +0000
@@ -387,7 +387,7 @@
                         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'));

=== modified file 'mail/static/src/js/mail_followers.js'
--- mail/static/src/js/mail_followers.js	2012-10-10 18:16:11 +0000
+++ mail/static/src/js/mail_followers.js	2012-10-15 14:20:29 +0000
@@ -26,7 +26,6 @@
             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 @@
         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 @@
             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 @@
                 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 @@
             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 @@
             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

=== modified file 'mail/static/src/xml/mail_followers.xml'
--- mail/static/src/xml/mail_followers.xml	2012-10-10 18:16:11 +0000
+++ mail/static/src/xml/mail_followers.xml	2012-10-15 14:20:29 +0000
@@ -7,7 +7,7 @@
         -->
     <div t-name="mail.followers" class="oe_mail_recthread_aside oe_semantic_html_override">
         <div class="oe_mail_recthread_actions">
-            <div class="oe_mouse_subtypes">
+            <div class="oe_mail_subtypes">
                 <button type="button" class="oe_follower oe_notfollow">
                     <span class="oe_follow">Follow</span>
                     <span class="oe_unfollow">Unfollow</span>
@@ -18,11 +18,9 @@
                 <ul class="oe_subtypes"></ul>
             </div>
         </div>
-        <div class="oe_grey">
-            <t t-if="widget.options.comment">
-                <h5><t t-raw="widget.options.comment"/></h5>
-            </t>
-        </div>
+        <t t-if="widget.options.comment">
+            <h5 class="oe_grey"><t t-raw="widget.options.comment"/></h5>
+        </t>
         <div class="oe_mail_recthread_followers">
             <button type="button" class="oe_invite"><span>Invite</span></button>
             <t t-if="widget.options.title">

=== modified file 'mail/tests/test_mail_access_rights.py'
--- mail/tests/test_mail_access_rights.py	2012-09-27 16:15:58 +0000
+++ mail/tests/test_mail_access_rights.py	2012-10-15 14:20:29 +0000
@@ -102,53 +102,53 @@
         """ 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
-
-    #     # 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')
-
-    #     # 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)
+    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
+        # ----------------------------------------
+        # 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)
+
+        # ----------------------------------------
+        # 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)

_______________________________________________
Mailing list: https://launchpad.net/~openerp-dev-gtk
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~openerp-dev-gtk
More help   : https://help.launchpad.net/ListHelp

Reply via email to