[REV] Revert last commit, breaks tests

bzr revid: odo@openerp.com-20121003153306-e2ugphdyijvq8x6l
This commit is contained in:
Olivier Dony
2012-10-03 17:33:06 +02:00
parent 267f6717c2
commit 3744f5c402
10 changed files with 195 additions and 114 deletions
+116 -68
View File
@@ -134,7 +134,6 @@ class mail_message(osv.Model):
'subtype_id': fields.many2one('mail.message.subtype', 'Subtype'),
'vote_user_ids': fields.many2many('res.users', 'mail_vote', 'message_id', 'user_id', string='Votes',
help='Users that voted for this message'),
'is_private': fields.boolean('Private message'),
}
def _needaction_domain_get(self, cr, uid, context=None):
@@ -222,67 +221,70 @@ class mail_message(osv.Model):
'unread': msg.unread and msg.unread['unread'] or False
}
def _message_read_expandable(self, cr, uid, tree, result, message_loaded, domain, context, parent_id, limit):
"""
create the expandable message for all parent message read
this function is used by message_read
def message_read_tree_get_expandable(self, cr, uid, parent_message, last_message, domain=[], current_level=0, level=0, context=None):
""" . """
base_domain = [('id', '<', last_message['id'])]
if parent_message and current_level < level:
base_domain += [('parent_id', '=', parent_message['id'])]
elif parent_message:
base_domain += [('id', 'child_of', parent_message['id']), ('id', '!=', parent_message['id'])]
if domain:
base_domain += domain
extension = { 'type': 'expandable',
'domain': base_domain,
'thread_level': current_level,
'context': context,
'id': -1,
}
return extension
def message_read_tree_flatten(self, cr, uid, parent_message, messages, domain=[], level=0, current_level=0, context=None, limit=None, add_expandable=True):
""" Given a tree with several roots of following structure :
[ {'id': 1, 'child_ids': [
{'id': 11, 'child_ids': [...] },],
{...} ]
Flatten it to have a maximum number of levels, 0 being flat and
sort messages in a level according to a key of the messages.
Perform the flattening at leafs if above the maximum depth, then get
back in the tree.
:param context: ``sort_key``: key for sorting (id by default)
:param context: ``sort_reverse``: reverser order for sorting (True by default)
"""
def _flatten(msg_dict):
""" from {'id': x, 'child_ids': [{child1}, {child2}]}
get [{'id': x, 'child_ids': []}, {child1}, {child2}]
"""
child_ids = msg_dict.pop('child_ids', [])
msg_dict['child_ids'] = []
return [msg_dict] + child_ids
tree_not = []
# expandable for not show message
for id_msg in tree:
# get all childs
not_loaded_ids = self.search(cr, SUPERUSER_ID, [['parent_id','=',id_msg],['id','not in',message_loaded]], None, limit=1000)
# group childs not read
id_min=None
id_max=None
nb=0
for not_loaded_id in not_loaded_ids:
if not_loaded_id not in tree:
nb+=1
if id_min==None or id_min>not_loaded_id:
id_min=not_loaded_id
if id_max==None or id_max<not_loaded_id:
id_max=not_loaded_id
tree_not.append(not_loaded_id)
else:
if nb>0:
result.append({
'domain': [['id','>=',id_min],['id','<=',id_max],['parent_id','=',id_msg]],
'nb_messages': nb,
'type': 'expandable',
'parent_id': id_msg,
'id': id_min
})
id_min=None
id_max=None
nb=0
if nb>0:
result.append({
'domain': [['id','>=',id_min],['id','<=',id_max],['parent_id','=',id_msg]],
'nb_messages': nb,
'type': 'expandable',
'parent_id': id_msg,
'id': id_min
})
context = context or {}
limit = limit or self._message_read_limit
# Depth-first flattening
for message in messages:
if message.get('type') == 'expandable':
continue
message['child_ids'] = self.message_read_tree_flatten(cr, uid, message, message['child_ids'], domain, level, current_level + 1, context=context, limit=limit)
for child in message['child_ids']:
if child.get('type') == 'expandable':
continue
message['child_nbr'] += child['child_nbr']
# Flatten if above maximum depth
if current_level < level:
return_list = messages
else:
return_list = [flat_message for message in messages for flat_message in _flatten(message)]
# expandable for limit max
ids = self.search(cr, SUPERUSER_ID, domain+[['id','not in',message_loaded+tree+tree_not]], context=context, limit=1)
if len(ids) > 0:
result.append(
{
'domain': domain,
'nb_messages': 0,
'type': 'expandable',
'parent_id': parent_id,
'id': -1
});
result = sorted(result, key=lambda k: k['id'])
return result
# Add expandable
return_list = sorted(return_list, key=itemgetter(context.get('sort_key', 'id')), reverse=context.get('sort_reverse', True))
if return_list and current_level == 0 and add_expandable:
expandable = self.message_read_tree_get_expandable(cr, uid, parent_message, return_list and return_list[-1] or parent_message, domain, current_level, level, context=context)
return_list.append(expandable)
elif return_list and current_level <= level and add_expandable:
expandable = self.message_read_tree_get_expandable(cr, uid, parent_message, return_list and return_list[-1] or parent_message, domain, current_level, level, context=context)
return_list.append(expandable)
return return_list
def message_read(self, cr, uid, ids=False, domain=[], level=0, context=None, parent_id=False, limit=None):
""" Read messages from mail.message, and get back a structured tree
@@ -298,6 +300,7 @@ class mail_message(osv.Model):
further parents
:return list: list of trees of messages
"""
message_loaded = context and context.get('message_loaded') or [0]
# don't read the message display by .js, in context message_loaded list
@@ -338,7 +341,58 @@ class mail_message(osv.Model):
result = sorted(result, key=lambda k: k['id'])
result = self._message_read_expandable(cr, uid, tree, result, message_loaded, domain, context, parent_id, limit)
tree_not = []
# expandable for not show message
for id_msg in tree:
# get all childs
not_loaded_ids = self.search(cr, SUPERUSER_ID, [['parent_id','=',id_msg],['id','not in',message_loaded]], None, limit=1000)
# group childs not read
id_min=None
id_max=None
nb=0
for not_loaded_id in not_loaded_ids:
if not_loaded_id not in tree:
nb+=1
if id_min==None or id_min>not_loaded_id:
id_min=not_loaded_id
if id_max==None or id_max<not_loaded_id:
id_max=not_loaded_id
tree_not.append(not_loaded_id)
else:
if nb>0:
result.append({
'domain': [['id','>=',id_min],['id','<=',id_max],['parent_id','=',id_msg]],
'nb_messages': nb,
'type': 'expandable',
'parent_id': id_msg,
'id': id_min
})
nb=0
if nb>0:
result.append({
'domain': [['id','>=',id_min],['parent_id','=',id_msg]],
'nb_messages': nb,
'type': 'expandable',
'parent_id': id_msg,
'id': id_min
})
# expandable for limit max
ids = self.search(cr, SUPERUSER_ID, domain+[['id','not in',message_loaded+tree+tree_not]], context=context, limit=1)
if len(ids) > 0:
result.append(
{
'domain': domain,
'nb_messages': 0,
'type': 'expandable',
'parent_id': parent_id,
'id': -1
});
result = sorted(result, key=lambda k: k['id'])
return result
@@ -472,9 +526,11 @@ class mail_message(osv.Model):
self.pool.get('ir.attachment').unlink(cr, uid, attachments_to_delete, context=context)
return super(mail_message, self).unlink(cr, uid, ids, context=context)
def _notify_followers(self, cr, uid, newid, message, context=None):
def _notify(self, cr, uid, newid, context=None):
""" Add the related record followers to the destination partner_ids.
Call mail_notification.notify to manage the email sending
"""
message = self.browse(cr, uid, newid, context=context)
partners_to_notify = set([])
# message has no subtype_id: pure log message -> no partners, no one notified
if not message.subtype_id:
@@ -502,14 +558,6 @@ class mail_message(osv.Model):
else:
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(3, message.author_id.id)]}, context=context)
def _notify(self, cr, uid, newid, context=None):
""" Add the related record followers to the destination partner_ids if is not a private message.
Call mail_notification.notify to manage the email sending
"""
message = self.browse(cr, uid, newid, context=context)
if message and (message.is_private!=False and message.is_private!=None):
self._notify_followers(cr, uid, newid, message, context=context)
self.pool.get('mail.notification')._notify(cr, uid, newid, context=context)
def copy(self, cr, uid, id, default=None, context=None):
+2 -9
View File
@@ -87,15 +87,8 @@
<record id="action_mail_inbox_feeds" model="ir.actions.client">
<field name="name">Inbox</field>
<field name="tag">mail.wall</field>
<field name="params" eval="&quot;{'domain': [('is_private','=',True),('notification_ids.partner_id.user_ids', 'in', [uid]),('unread', '=', True)],
'context': {'default_model': 'res.users', 'default_res_id': uid, 'default_is_private':True} }&quot;"/>
</record>
<record id="action_mail_wall_feeds" model="ir.actions.client">
<field name="name">Wall</field>
<field name="tag">mail.wall</field>
<field name="params" eval="&quot;{'domain': [('is_private','=',False),('notification_ids.partner_id.user_ids', 'in', [uid]),('unread', '=', True)],
'context': {'default_model': 'res.users', 'default_res_id': uid, 'default_is_private':False} }&quot;"/>
<field name="params" eval="&quot;{'domain': [('notification_ids.partner_id.user_ids', 'in', [uid]),('unread', '=', True)],
'context': {'default_model': 'res.users', 'default_res_id': uid} }&quot;"/>
</record>
<record id="action_mail_archives_feeds" model="ir.actions.client">
+1 -7
View File
@@ -627,6 +627,7 @@ class mail_thread(osv.AbstractModel):
``(name,content)``, where content is NOT base64 encoded
:return: ID of newly created mail.message
"""
context = context or {}
attachments = attachments or []
assert (not thread_id) or isinstance(thread_id, (int, long)) or \
@@ -678,13 +679,6 @@ class mail_thread(osv.AbstractModel):
'attachment_ids': attachment_ids,
'subtype_id': subtype_id,
})
# 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
# Avoid warnings about non-existing fields
for x in ('from', 'to', 'cc'):
values.pop(x, None)
+2 -8
View File
@@ -18,21 +18,15 @@
<field name="action" ref="action_mail_inbox_feeds"/>
<field name="parent_id" ref="mail_feeds"/>
</record>
<record id="mail_wallfeeds" model="ir.ui.menu">
<field name="name">Wall</field>
<field name="sequence" eval="11"/>
<field name="action" ref="action_mail_wall_feeds"/>
<field name="parent_id" ref="mail_feeds"/>
</record>
<record id="mail_archivesfeeds" model="ir.ui.menu">
<field name="name">Archives</field>
<field name="sequence" eval="12"/>
<field name="sequence" eval="11"/>
<field name="action" ref="action_mail_archives_feeds"/>
<field name="parent_id" ref="mail_feeds"/>
</record>
<record id="mail_sentfeeds" model="ir.ui.menu">
<field name="name">Sent</field>
<field name="sequence" eval="13"/>
<field name="sequence" eval="12"/>
<field name="action" ref="action_mail_sent_feeds"/>
<field name="parent_id" ref="mail_feeds"/>
</record>
+1 -1
View File
@@ -370,7 +370,7 @@
bottom: 0px;
top: auto;
left: auto;
right: 0;
right: 28px;
height: 26px;
width: 26px;
min-width: 22px;
+22 -15
View File
@@ -148,8 +148,8 @@ openerp.mail = function(session) {
// handle attachment button
this.fileupload_id = _.uniqueId('oe_fileupload');
var button_attach = this.$('button.oe_mail_compose_message_attachment');
var rendered = $( session.web.qweb.render('mail.compose_message.add_attachment', {'widget': this}) );
rendered.insertBefore(button_attach);
var rendered = session.web.qweb.render('mail.compose_message.add_attachment', {'widget': this});
$(rendered).insertBefore(button_attach);
// move the button inside div.oe_hidden_input_file
var input_node = this.$('input[name=ufile]');
button_attach.detach().insertAfter(input_node);
@@ -256,10 +256,10 @@ openerp.mail = function(session) {
default_res_id: 0,
default_parent_id: false }, options.context || {});
this.id = options.parameters.id || -1;
this.id = -1;
this.parent_id= options.parameters.parent_id || false;
this.nb_messages = options.parameters.nb_messages || 0;
this.type = 'expandable';
this.type = options.parameters.type || false;
// record options and data
this.parent_thread= parent.messages!= undefined ? parent : options.options.thread._parents[0] ;
@@ -501,6 +501,9 @@ openerp.mail = function(session) {
} else {
self.destroy();
}
for(var i in this.thread.messages){
this.thread.messages[i].animated_destroy({fadeTime:0});
}
},
on_message_delete: function (event) {
@@ -595,8 +598,8 @@ openerp.mail = function(session) {
display_vote: function () {
var self = this;
var vote_element = session.web.qweb.render('mail.thread.message.vote', {'widget': self});
self.$(".placeholder-mail-vote:first").empty();
self.$(".placeholder-mail-vote:first").html(vote_element);
self.$(".placeholder-mail-vote").empty();
self.$(".placeholder-mail-vote").html(vote_element);
},
});
@@ -876,7 +879,7 @@ openerp.mail = function(session) {
fetch_domain = replace_domain ? replace_domain : this.domain;
fetch_context = replace_context ? replace_context : this.context;
fetch_context.message_loaded= [this.id||0].concat( self.options.thread._parents[0].get_child_ids() );
return this.ds_message.call('message_read', [ids, fetch_domain, (this.options.thread.thread_level+1), fetch_context, this.context.default_parent_id || undefined]
).then(this.proxy('switch_new_message'));
},
@@ -942,11 +945,11 @@ openerp.mail = function(session) {
}
}
if(parent_older)
message.insertBefore(parent_older.$el);
else if(parent_newer)
if(parent_newer)
message.insertAfter(parent_newer.$el);
else
else if(parent_older)
message.insertBefore(parent_older.$el);
else
message.prependTo(thread.list_ul);
return message
@@ -1095,7 +1098,6 @@ openerp.mail = function(session) {
this._super.apply(this, arguments);
var searchview_ready = this.load_searchview({}, false);
var thread_displayed = this.message_render();
this.options.domain = this.options.domain.concat(this.search_results['domain']);
return (searchview_ready && thread_displayed);
},
@@ -1135,14 +1137,19 @@ openerp.mail = function(session) {
/** Clean and display the threads */
message_render: function (search) {
var domain = this.options.domain.concat(this.search_results['domain']);
var domain = _.extend(this.options.domain, search&&search.domain? search.domain : {});
var context = _.extend(this.options.context, search&&search.context ? search.context : {});
this.thread = new mail.Thread(this, {
'domain' : this.options.domain.concat(this.search_results['domain']),
'context' : _.extend(this.options.context, search&&search.search_results['context'] ? search.search_results['context'] : {}),
'domain' : domain,
'context' : context,
'options': {
'thread' :{
'thread_level': this.options.thread_level,
'use_composer': true,
'show_header_compose': 1,
'show_header_compose': 1,
},
'message': {
'show_reply': this.options.thread_level > 0,
+3 -2
View File
@@ -149,6 +149,7 @@ openerp_mail_followers = function(session, mail) {
var self = this;
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 + ')' : '') );
console.log(records);
for(var i=0; i<records.length&&i<5; i++) {
var record=records[i];
record.avatar_url = mail.ChatterUtils.get_image(self.session, 'res.partner', 'image_small', record.id);
@@ -199,7 +200,7 @@ openerp_mail_followers = function(session, mail) {
$(record).attr('checked','checked');
});
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_){
return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], undefined, undefined, context]).pipe(function(value_){
self.read_value(value_);
if(!self.$('.oe_recthread_subtypes').is(":visible"))
self.display_subtypes(true);
@@ -211,7 +212,7 @@ openerp_mail_followers = function(session, mail) {
$(record).attr('checked',false);
});
var context = new session.web.CompoundContext(this.build_context(), {});
return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], [this.session.uid], context]).pipe(this.proxy('read_value'));
return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], undefined, context]).pipe(this.proxy('read_value'));
},
do_update_subscription: function () {
+5 -4
View File
@@ -104,14 +104,15 @@
</div>
<!-- default layout -->
<li t-name="mail.thread.message" t-attf-class="oe_mail oe_mail_thread_msg #{widget.unread?'oe_mail_unread':'oe_mail_read'}">
<li t-name="mail.thread.message" t-attf-class="oe_mail oe_mail_thread_msg #{widget.unread?'oe_mail_unread':'oe_mail_read'}" t-attf-data-msg_id="{widget.id}">
<div t-attf-class="oe_mail_msg_#{widget.type} oe_semantic_html_override">
<!-- message actions (read/unread, reply, delete...) -->
<ul class="oe_header">
<li class="placeholder-mail-vote"><t t-call="mail.thread.message.vote"/></li>
<li t-if="!widget.options.thread.display_on_flat and widget.unread" title="Read"><a class="oe_read oe_e">W</a></li>
<li t-if="!widget.options.thread.display_on_flat and !widget.unread" title="Set back to unread"><a class="oe_unread oe_e">h</a></li>
<li title="Quick reply"><a class="oe_reply oe_e">)</a></li>
<li t-if="!widget.options.message.show_reply_by_email" title="Reply"><a class="oe_reply oe_e">)</a></li>
<li t-if="widget.options.message.show_reply_by_email"><a class="oe_reply_by_email oe_e" title="Reply by mail">)</a></li>
<t t-if="(widget.options.message.show_reply || widget.options.message.show_reply_by_email || (widget.is_author and widget.options.message.show_dd_delete) || widget.type == 'email')">
<li>
<span class="oe_dropdown_toggle">
@@ -123,7 +124,7 @@
<a href="#" class="oe_mail_msg_hide_type" t-attf-data-subtype='{widget.subtype}'>Hide '<t t-esc="widget.subtype"/>' for this document</a>
</li> -->
<li t-if="widget.options.message.show_reply" title="Reply"><a class="oe_reply oe_full_reply">Full reply</a></li>
<li t-if="widget.options.message.show_reply_by_email"><a class="oe_reply_by_email oe_full_reply" title="Reply by mail">Full reply by mail</a></li>
<li t-if="widget.options.message.show_reply_by_email"><a class="oe_reply_by_email oe_full_reply" title="Reply by mail">Full reply</a></li>
<li t-if="widget.type == 'email'"><a class="oe_mail_msg_details" t-attf-href="#model=mail.message&amp;id=#{widget.id}" >Details</a></li>
</ul>
</span>
@@ -170,7 +171,7 @@
</li>
<!-- expandable message layout -->
<li t-name="mail.thread.expandable" class="oe_mail oe_mail_thread_msg oe_mail_unread">
<li t-name="mail.thread.expandable" t-attf-class="oe_mail oe_mail_thread_msg oe_mail_unread" t-attf-data-thread_id="{widget.id}">
<div t-attf-class="oe_mail_msg_#{widget.type} oe_semantic_html_override">
<div class="oe_mail_msg_content oe_mail_msg_more_message">
<a class="oe_mail_fetch_more">Load more messages <span t-if="widget.nb_messages>0">(<t t-raw="widget.nb_messages"/> messages not display)</span>...</a>
+42
View File
@@ -550,6 +550,48 @@ class test_mail(TestMailMockups):
# _compare_structures(struct1[x]['child_ids'], struct2[x]['child_ids'], n + 1)
# # print '%send compare' % ('\t' * n)
# # ----------------------------------------
# # CASE1: Flattening test
# # ----------------------------------------
# # Create dummy message structure
# import copy
# tree = [{'id': 2, 'child_nbr': 1, 'child_ids': [
# {'id': 6, 'child_nbr': 1, 'child_ids': [
# {'id': 8, 'child_nbr': 0, 'child_ids': []},
# ]},
# ]},
# {'id': 1, 'child_nbr': 3, 'child_ids':[
# {'id': 7, 'child_nbr': 1, 'child_ids': [
# {'id': 9, 'child_nbr': 0, 'child_ids': []},
# ]},
# {'id': 4, 'child_nbr': 2, 'child_ids': [
# {'id': 10, 'child_nbr': 0, 'child_ids': []},
# {'id': 5, 'child_nbr': 0, 'child_ids': []},
# ]},
# {'id': 3, 'child_nbr': 0, 'child_ids': []},
# ]},
# ]
# # Test: completely flat
# new_tree = self.mail_message.message_read_tree_flatten(cr, uid, None, copy.deepcopy(tree), [('type', 'in', 'borderlands')], 0, limit=15, add_expandable=False)
# _compare_structures(new_tree, new_tree)
# self.assertEqual(len(new_tree), 10, 'message_read_tree_flatten wrong in flat')
# # Test: 1 thread level
# tree_test = [{'id': 2, 'child_ids': [
# {'id': 8, 'child_ids': []}, {'id': 6, 'child_ids': []},
# ]},
# {'id': 1, 'child_ids': [
# {'id': 10, 'child_ids': []}, {'id': 9, 'child_ids': []},
# {'id': 7, 'child_ids': []}, {'id': 5, 'child_ids': []},
# {'id': 4, 'child_ids': []}, {'id': 3, 'child_ids': []},
# ]},
# ]
# new_tree = self.mail_message.message_read_tree_flatten(cr, uid, None, copy.deepcopy(tree), [('type', 'in', 'borderlands')], 1, limit=15, add_expandable=False)
# _compare_structures(new_tree, tree_test)
# # Test: 2 thread levels
# new_tree = self.mail_message.message_read_tree_flatten(cr, uid, None, copy.deepcopy(tree), [('type', 'in', 'borderlands')], 2, limit=15, add_expandable=False)
# _compare_structures(new_tree, tree)
# # ----------------------------------------
# # CASE2: message_read test
# # ----------------------------------------
@@ -219,6 +219,7 @@ class mail_compose_message(osv.TransientModel):
email(s), rendering any template patterns on the fly if needed. """
if context is None:
context = {}
print '**', context
active_ids = context.get('active_ids')
for wizard in self.browse(cr, uid, ids, context=context):