[MERGE] trunk

bzr revid: fp@tinyerp.com-20121011142308-vdynmuonffi31yug
This commit is contained in:
Fabien Pinckaers 2012-10-11 16:23:08 +02:00
commit cd014978dc
17 changed files with 947 additions and 833 deletions

View File

@ -21,7 +21,7 @@ class res_users(osv.Model):
}
_sql_constraints = [
('uniq_users_oauth_provider_oauht_uid', 'unique(auth_provider_id, auth_uid)', 'OAuth UID must be unique per provider'),
('uniq_users_oauth_provider_oauth_uid', 'unique(oauth_provider_id, oauth_uid)', 'OAuth UID must be unique per provider'),
]
def auth_oauth_rpc(self, cr, uid, endpoint, access_token, context=None):

View File

@ -155,30 +155,6 @@ class document_file(osv.osv):
res['value'].update({'name': datas_fname})
return res
def _check_duplication(self, cr, uid, vals, ids=[], op='create'):
name = vals.get('name', False)
parent_id = vals.get('parent_id', False)
res_model = vals.get('res_model', False)
res_id = vals.get('res_id', 0)
if op == 'write':
for file in self.browse(cr, uid, ids): # FIXME fields_only
if not name:
name = file.name
if not parent_id:
parent_id = file.parent_id and file.parent_id.id or False
if not res_model:
res_model = file.res_model and file.res_model or False
if not res_id:
res_id = file.res_id and file.res_id or 0
res = self.search(cr, uid, [('id', '<>', file.id), ('name', '=', name), ('parent_id', '=', parent_id), ('res_model', '=', res_model), ('res_id', '=', res_id)])
if len(res):
return False
if op == 'create':
res = self.search(cr, uid, [('name', '=', name), ('parent_id', '=', parent_id), ('res_id', '=', res_id), ('res_model', '=', res_model)])
if len(res):
return False
return True
def check(self, cr, uid, ids, mode, context=None, values=None):
"""Check access wrt. res_model, relax the rule of ir.attachment parent
@ -225,8 +201,6 @@ class document_file(osv.osv):
res = self.search(cr, uid, [('id', 'in', ids)])
if not len(res):
return False
if not self._check_duplication(cr, uid, vals, ids, 'write'):
raise osv.except_osv(_('ValidateError'), _('File name must be unique!'))
# if nodes call this write(), they must skip the code below
from_node = context and context.get('__from_node', False)
@ -292,22 +266,8 @@ class document_file(osv.osv):
else:
if vals.get('file_size'):
del vals['file_size']
result = self._check_duplication(cr, uid, vals)
if not result:
domain = [
('res_id', '=', vals['res_id']),
('res_model', '=', vals['res_model']),
('datas_fname', '=', vals['datas_fname']),
]
attach_ids = self.search(cr, uid, domain, context=context)
super(document_file, self).write(cr, uid, attach_ids,
{'datas' : vals['datas']},
context=context)
result = attach_ids[0]
else:
#raise osv.except_osv(_('ValidateError'), _('File name must be unique!'))
result = super(document_file, self).create(cr, uid, vals, context)
return result
return super(document_file, self).create(cr, uid, vals, context)
def __get_partner_id(self, cr, uid, res_model, res_id, context=None):
""" A helper to retrieve the associated partner from any res_model+id

View File

@ -4,14 +4,8 @@ import textwrap
import simplejson
import werkzeug.wrappers
try:
# embedded
import openerp.addons.web.common.http as openerpweb
import openerp.addons.web.controllers.main as webmain
except ImportError:
# standalone
import web.common.http as openerpweb
import web.controllers.main as webmain
import openerp.addons.web.http as openerpweb
import openerp.addons.web.controllers.main as webmain
class EDI(openerpweb.Controller):
# http://hostname:8069/edi/view?db=XXXX&token=XXXXXXXXXXX

View File

@ -39,7 +39,7 @@
attrs="{'invisible':[('use_template','=',False)]}"
on_change="onchange_template_id(use_template, template_id, composition_mode, model, res_id, context)"/>
</xpath>
<xpath expr="//button[@class='oe_mail_compose_message_attachment']" position="before">
<xpath expr="//button[@name='dummy']" position="before">
<button icon="/email_template/static/src/img/email_template.png"
type="object" name="toggle_template" string=""
help="Use a message template"

View File

@ -134,6 +134,7 @@ 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):
@ -150,6 +151,7 @@ class mail_message(osv.Model):
'date': lambda *a: fields.datetime.now(),
'author_id': lambda self, cr, uid, ctx={}: self._get_default_author(cr, uid, ctx),
'body': '',
'is_private': True,
}
#------------------------------------------------------
@ -220,127 +222,12 @@ class mail_message(osv.Model):
'unread': msg.unread and msg.unread['unread'] or False
}
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 _message_read_expandable(self, cr, uid, tree, result, message_loaded, domain, context, parent_id, limit):
"""
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
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)]
# 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
of messages to be displayed as discussion threads. If IDs is set,
fetch these records. Otherwise use the domain to fetch messages.
After having fetch messages, their parents will be added to obtain
well formed threads.
:param domain: optional domain for searching ids
:param level: level of threads to display, 0 being flat
:param limit: number of messages to fetch
:param parent_id: if parent_id reached, stop searching for
further parents
:return list: list of trees of messages
create the expandable message for all parent message read
this function is used by message_read
"""
message_loaded = context and context.get('message_loaded') or [0]
# don't read the message display by .js, in context message_loaded list
if context and context.get('message_loaded'):
domain += [ ['id','not in',message_loaded] ];
limit = limit or self._message_read_limit
context = context or {}
tree = []
result = []
record = None
# select ids
if ids:
for msg in self.browse(cr, uid, ids, context=context):
result.append(self._message_dict_get(cr, uid, msg, context=context))
return result
# key: ID, value: record
ids = self.search(cr, SUPERUSER_ID, domain, context=context, limit=limit)
for msg in self.browse(cr, uid, ids, context=context):
# if not in record and not in message_loded list
if msg.id not in tree and msg.id not in message_loaded :
record = self._message_dict_get(cr, uid, msg, context=context)
tree.append(msg.id)
result.append(record)
while msg.parent_id and msg.parent_id.id != parent_id:
parent_id = msg.parent_id.id
if msg.parent_id.id not in tree:
msg = msg.parent_id
tree.append(msg.id)
# if not in record and not in message_loded list
if msg.id not in message_loaded :
record = self._message_dict_get(cr, uid, msg, context=context)
result.append(record)
result = sorted(result, key=lambda k: k['id'])
tree_not = []
# expandable for not show message
for id_msg in tree:
@ -367,10 +254,12 @@ class mail_message(osv.Model):
'parent_id': id_msg,
'id': id_min
})
id_min=None
id_max=None
nb=0
if nb>0:
result.append({
'domain': [['id','>=',id_min],['parent_id','=',id_msg]],
'domain': [['id','>=',id_min],['id','<=',id_max],['parent_id','=',id_msg]],
'nb_messages': nb,
'type': 'expandable',
'parent_id': id_msg,
@ -395,6 +284,73 @@ class mail_message(osv.Model):
return result
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
of messages to be displayed as discussion threads. If IDs is set,
fetch these records. Otherwise use the domain to fetch messages.
After having fetch messages, their parents will be added to obtain
well formed threads.
:param domain: optional domain for searching ids
:param limit: number of messages to fetch
:param parent_id: if parent_id reached, stop searching for
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
if context and context.get('message_loaded'):
domain += [ ['id','not in',message_loaded] ];
limit = limit or self._message_read_limit
context = context or {}
tree = []
result = []
record = None
# select ids
if ids and ids!=[None]:
for msg in self.browse(cr, uid, ids, context=context):
result.append(self._message_dict_get(cr, uid, msg, context=context))
return result
# key: ID, value: record
ids = self.search(cr, SUPERUSER_ID, domain, context=context, limit=limit)
for msg in self.browse(cr, uid, ids, context=context):
# if not in record and not in message_loded list
if msg.id not in tree and msg.id not in message_loaded :
record = self._message_dict_get(cr, uid, msg, context=context)
tree.append(msg.id)
result.append(record)
while msg.parent_id and msg.parent_id.id != parent_id:
parent_id = msg.parent_id.id
if msg.parent_id.id not in tree:
msg = msg.parent_id
tree.append(msg.id)
# if not in record and not in message_loded list
if msg.id not in message_loaded :
record = self._message_dict_get(cr, uid, msg, context=context)
result.append(record)
result = sorted(result, key=lambda k: k['id'])
result = self._message_read_expandable(cr, uid, tree, result, message_loaded, domain, context, parent_id, limit)
return result
def user_free_attachment(self, cr, uid, context=None):
attachment_list = []
attachment = self.pool.get('ir.attachment')
attachment_ids = attachment.search(cr, uid, [('res_model','=',''),('create_uid','=',uid)])
if len(attachment_ids):
attachment_list = [{'id': attach.id, 'name': attach.name, 'date': attach.create_date} for attach in attachment.browse(cr, uid, attachment_ids, context=context)]
return attachment_list
#------------------------------------------------------
# Email api
#------------------------------------------------------
@ -525,11 +481,9 @@ 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(self, cr, uid, newid, context=None):
def _notify_followers(self, cr, uid, newid, message, 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:
@ -550,6 +504,14 @@ class mail_message(osv.Model):
self.write(cr, SUPERUSER_ID, [newid], {'partner_ids': [(4, p_id) for p_id in missing_notified]}, context=context)
partners_to_notify |= extra_notified
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)
# add myself if I wrote on my wall,
# unless remove myself author
if ((message.model=="res.partner" and message.res_id==message.author_id.id)):

View File

@ -88,21 +88,21 @@
<field name="name">Inbox</field>
<field name="tag">mail.wall</field>
<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;"/>
'context': {'default_model': 'res.partner'} }&quot;"/>
</record>
<record id="action_mail_archives_feeds" model="ir.actions.client">
<field name="name">Archives</field>
<field name="tag">mail.wall</field>
<field name="params" eval="&quot;{'domain': [('notification_ids.partner_id.user_ids', 'in', [uid]),('unread', '=', False)],
'context': {'default_model': 'res.users', 'default_res_id': uid} }&quot;"/>
'context': {'default_model': 'res.partner'} }&quot;"/>
</record>
<record id="action_mail_sent_feeds" model="ir.actions.client">
<field name="name">Sent</field>
<field name="tag">mail.wall</field>
<field name="params" eval="&quot;{'domain': [('author_id.user_ids', 'in', [uid])],
'context': {'default_model': 'res.users', 'default_res_id': uid} }&quot;"/>
'context': {'default_model': 'res.partner'} }&quot;"/>
</record>
</data>
</openerp>

View File

@ -623,11 +623,10 @@ class mail_thread(osv.AbstractModel):
:param str subject: optional subject
:param str type: mail_message.type
:param int parent_id: optional ID of parent message in this thread
:param tuple(str,str) attachments: list of attachment tuples in the form
:param tuple(str,str) attachments or list id: list of attachment tuples in the form
``(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 \
@ -635,7 +634,7 @@ class mail_thread(osv.AbstractModel):
if isinstance(thread_id, (list, tuple)):
thread_id = thread_id and thread_id[0]
attachment_ids = []
attachment_ids=[]
for name, content in attachments:
if isinstance(content, unicode):
content = content.encode('utf-8')
@ -679,6 +678,13 @@ 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)
@ -691,10 +697,23 @@ class mail_thread(osv.AbstractModel):
def message_post_api(self, cr, uid, thread_id, body='', subject=False, type='notification',
subtype=None, parent_id=False, attachments=None, context=None, **kwargs):
added_message_id = self.message_post(cr, uid, thread_id=thread_id, body=body, subject=subject, type=type,
subtype=subtype, parent_id=parent_id, attachments=attachments, context=context)
added_message = self.pool.get('mail.message').message_read(cr, uid, [added_message_id])
# 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):

View File

@ -20,13 +20,13 @@
</record>
<record id="mail_archivesfeeds" model="ir.ui.menu">
<field name="name">Archives</field>
<field name="sequence" eval="11"/>
<field name="sequence" eval="12"/>
<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="12"/>
<field name="sequence" eval="13"/>
<field name="action" ref="action_mail_sent_feeds"/>
<field name="parent_id" ref="mail_feeds"/>
</record>

View File

@ -82,9 +82,13 @@
overflow: auto;
}
.openerp .oe_mail_record_wall {
margin: auto;
width: 560px;
}
.openerp .oe_mail_record_wall > .oe_mail_wall_threads {
float: left;
width: 560px;
}
.openerp div.oe_mail_recthread_aside {
@ -145,6 +149,10 @@
z-index: 5;
}
.openerp .oe_mouse_subtypes .oe_recthread_subtypes {
background: #fff;
padding: 2px;
border: 1px solid #aaaaaa;
border-top: 0px;
position: absolute;
z-index: 2;
}
@ -160,7 +168,6 @@
/* ------------------------------------------------------------ */
.openerp div.oe_mail_thread_action {
display: none;
white-space: normal;
padding: 8px;
z-index:5;
@ -173,16 +180,6 @@
clear: both;
}
/* default textarea (oe_mail_compose_textarea), and body textarea for compose form view */
.openerp .oe_mail_msg_content textarea.oe_mail_compose_textarea,
.openerp .oe_mail_msg_content div.oe_mail_compose_message_body textarea {
width: 474px;
height: 60px;
padding: 4px;
font-size: 12px;
border: 1px solid #cccccc;
}
/* default textarea (oe_mail_compose_textarea), and body textarea for compose form view */
.openerp .oe_mail_msg_content textarea.oe_mail_compose_textarea:focus,
.openerp .oe_mail_msg_content div.oe_mail_compose_message_body textarea:focus {
@ -206,6 +203,10 @@
margin-left: 66px;
}
.openerp li.oe_mail_thread_msg {
width: 560px;
}
.openerp div.oe_thread_placeholder li.oe_mail_thread_msg:last-child {
margin-bottom: 8px;
}
@ -223,13 +224,18 @@
.openerp li.oe_mail_thread_msg.oe_mail_read,
.openerp li.oe_mail_thread_msg.oe_mail_read div {
background-color: #F0F0F0;
border-left: #F0F0F0;
}
.openerp li.oe_mail_thread_msg.oe_mail_read li.oe_mail_thread_msg.oe_mail_unread,
.openerp li.oe_mail_thread_msg.oe_mail_read li.oe_mail_thread_msg.oe_mail_unread div {
background-color: #F6F6F6;
}
.openerp li.oe_mail_thread_msg.oe_mail_unread>div>ul>li.oe_unread,
.openerp li.oe_mail_thread_msg.oe_mail_read>div>ul>li.oe_read {
display: none;
}
.openerp li.oe_mail_thread_msg > div:after {
content: "";
display: block;
@ -247,7 +253,7 @@
.openerp .oe_mail_msg_email {
padding: 8px;
background: white;
border-top: 1px solid #ebebeb;
position: relative;
}
.openerp .oe_mail_msg_notification:after,
@ -259,7 +265,7 @@
}
.openerp div.oe_mail_msg_content {
float: right;
float: left;
position: relative;
width: 486px;
}
@ -309,76 +315,6 @@
display: none;
}
/* ------------------------------------------------------------ */
/* mail.compose.message form view & OpenERP hacks
/* ------------------------------------------------------------ */
/* form_view: delete white background */
.openerp .oe_mail_msg_content div.oe_formview {
background-color: transparent;
}
.openerp .oe_mail_msg_content div.oe_form_nosheet {
margin: 0px;
}
.openerp .oe_mail_msg_content table.oe_form_group {
margin: 0px;
}
.openerp .oe_mail_msg_content table.oe_form_field,
.openerp .oe_mail_msg_content div.oe_form_field {
padding: 0px;
}
.openerp .oe_mail_msg_content td.oe_form_group_cell {
vertical-align: bottom;
}
/* subject: change width */
.openerp .oe_mail_msg_content .oe_form .oe_form_field input {
width: 472px;
}
/* body_html: cleditor */
.openerp .oe_mail_msg_content div.cleditorMain {
border: 1px solid #cccccc;
}
/* destination_partner_ids */
.openerp .oe_mail_msg_content div.text-core {
height: 22px !important;
width: 472px;
}
/* buttons */
.openerp .oe_mail_msg_content .oe_mail_compose_message_icons button.oe_form_button {
padding: 1px;
}
/* attachment button: override of openerp values */
.openerp .oe_mail_msg_content .oe_mail_compose_message_icons div.oe_hidden_input_file {
display: inline-block;
width: 24px;
height: 24px;
margin: 2px;
}
.openerp .oe_mail_msg_content .oe_mail_compose_message_icons div.oe_hidden_input_file button {
margin: 0px;
}
.openerp .oe_mail_msg_content .oe_mail_compose_message_icons input.oe_form_binary_file {
bottom: 0px;
top: auto;
left: auto;
right: 28px;
height: 26px;
width: 26px;
min-width: 22px;
font-size: 0px;
margin: 0px;
padding: 0px;
}
/* ------------------------------------------------------------ */
/* Messages layout
/* ------------------------------------------------------------ */
@ -413,39 +349,27 @@
}
/* Dropdown menu */
/*.openerp .oe_mail_msg_content .oe_dropdown_toggle {
position: absolute;
top: 0px;
right: 3px;
}*/
.openerp .oe_mail .oe_semantic_html_override {
.openerp .oe_mail ul.oe_mail_thread_display ul.oe_mail_thread_display {
position: relative;
border-left: 1px #DDD dashed;
}
.openerp .oe_mail ul.oe_header {
position: absolute;
right: 3px;
top: -6px;
display: none;
z-index: 10;
height: 18px;
}
.openerp .oe_mail ul.oe_header a {
text-decoration: none;
}
.openerp .oe_mail .oe_semantic_html_override:hover > ul.oe_header {
display: block;
}
.openerp .oe_mail ul.oe_header>li {
display: inline-block;
}
.openerp .oe_mail_msg_content .oe_dropdown_arrow:after {
border-top: 4px solid #404040;
height: 20px;
text-align: right;
}
/* Message footer */
@ -465,16 +389,36 @@
/* Attachments list */
.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments {
display: none;
width: 100%;
border-top: 1px solid #CCC;
margin: .5em 0 0 0;
padding: .5em 0;
list-style-position: inside;
}
.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments.oe_hidden {
display: none;
}
.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments li {
float: none;
height: 20px;
line-height: 20px;
margin: 0;
padding: 0;
list-style-type: square;
}
.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments .oe_upload_in_process {
float: right;
width: 200px;
height: 16px;
}
.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments .oe_upload_in_process div {
float: left;
width: 38px;
height: 16px;
margin-right: 2px;
background: #66FF66;
}
.openerp .oe_mail_msg_content ul.oe_mail_msg_attachments .oe_upload_in_process span {
color: #aaaaaa;
position: absolute;
}

View File

@ -1,12 +1,166 @@
/* ------------------------------ */
/* Compose Message Wizard Form */
/* Compose Message */
/* ------------------------------ */
.openerp .oe_mail_compose_message_icons {
text-align: right;
.openerp .oe_mail_msg_content .oe_mail_compose_message_footer {
height: 24px;
}
.openerp .oe_mail_compose_message_icons img {
width: 20px;
height: 20px;
.openerp .oe_mail_msg_content .oe_mail_compose_message_footer button.oe_mail_compose_message_button_send {
float: left;
}
.openerp .oe_mail .oe_mail_compose_textarea
{
display: none;
}
.openerp .oe_mail .oe_mail_compose_textarea .oe_mail_post_header,
.openerp .oe_mail .oe_mail_compose_textarea .oe_mail_post_footer,
{
position: relative;
}
.openerp .oe_mail .oe_mail_compose_textarea a.oe_cancel {
position: absolute;
right: -8px;
top: -8px;
}
.openerp .oe_mail .oe_mail_compose_textarea a.oe_cancel:first-of-type {
display:none;
}
.openerp .oe_mail .oe_mail_compose_textarea button.oe_full {
float: right;
position: relative;
right: -10px;
}
/* ------------------------------------------------------------ */
/* mail.compose.message : list_recipients
/* ------------------------------------------------------------ */
.openerp .oe_mail .oe_mail_list_recipients {
display: inline;
}
.openerp .oe_mail .oe_mail_list_recipients .oe_all_follower {
color: blue;
}
.openerp .oe_mail .oe_mail_list_recipients .oe_partner_follower a {
color: red;
}
.openerp .oe_mail .oe_mail_list_recipients .oe_hidden,
.openerp .oe_mail .oe_mail_list_recipients .oe_more_hidden {
display: none;
}
/* ------------------------------------------------------------ */
/* mail.compose.message : attachment
/* ------------------------------------------------------------ */
.openerp .oe_mail .oe_attachment_file {
display: inline-block;
}
.openerp .oe_mail .oe_attachment_file .oe_add {
float: left;
width: 24px;
height: 24px;
position: relative;
z-index: 10;
left: +2px;
top: +7px;
overflow: hidden;
}
/* attachment button: override of openerp values */
.openerp .oe_mail .oe_attachment_file .oe_add button,
.openerp .oe_mail .oe_attachment_file .oe_add input.oe_insert_file {
position: absolute;
bottom: +0px;
left: +0px;
height: 24px;
width: 24px;
margin: 0px;
padding: 0px;
}
.openerp .oe_mail .oe_attachment_file .oe_add input.oe_insert_file {
z-index:2;
width: 300px;
left: -100px;
background: transparent;
border: 0;
color: transparent;
}
.openerp .oe_mail .oe_attachment_file .oe_add button span {
position: relative;
bottom: +4px;
font-size: 30px;
}
.openerp .oe_mail .oe_mail_msg_attachments input {
visibility: hidden;
}
.openerp .oe_mail .oe_mail_compose_attachment_list {
clear: both;
}
/* ------------------------------------------------------------ */
/* mail.compose.message
/* ------------------------------------------------------------ */
/* default textarea (oe_mail_compose_textarea), and body textarea for compose form view */
.openerp .oe_mail.oe_semantic_html_override .oe_mail_compose_textarea textarea.field_text,
.openerp .oe_mail div.oe_mail_compose_message_body textarea.field_text {
width: 100%;
min-height: 120px;
height: auto;
padding: 4px;
font-size: 12px;
border: 1px solid #cccccc;
}
/* not top textarea */
.openerp .oe_mail.oe_semantic_html_override .oe_semantic_html_override .oe_mail_compose_textarea textarea.field_text {
height: 60px;
}
/* form_view: delete white background */
.openerp .oe_mail_msg_content div.oe_formview {
background-color: transparent;
}
.openerp .oe_mail_msg_content div.oe_form_nosheet {
margin: 0px;
}
.openerp .oe_mail_msg_content table.oe_form_group {
margin: 0px;
}
.openerp .oe_mail_msg_content table.oe_form_field,
.openerp .oe_mail_msg_content div.oe_form_field {
padding: 0px;
}
.openerp .oe_mail_msg_content td.oe_form_group_cell {
vertical-align: bottom;
}
/* subject: change width */
.openerp .oe_mail_msg_content .oe_form .oe_form_field input[type='text'] {
width: 472px;
}
/* body_html: cleditor */
.openerp .oe_mail_msg_content div.cleditorMain {
border: 1px solid #cccccc;
}
/* destination_partner_ids */
.openerp .oe_mail_msg_content div.text-core {
height: 22px !important;
width: 472px;
}

File diff suppressed because it is too large Load Diff

View File

@ -40,6 +40,7 @@ openerp_mail_followers = function(session, mail) {
this._check_visibility();
this.reinit();
this.bind_events();
this.display_subtypes();
},
_check_visibility: function() {
@ -53,31 +54,15 @@ openerp_mail_followers = function(session, mail) {
bind_events: function() {
var self = this;
this.$('div.oe_mouse_subtypes')
.on('mouseover', function () {
$(this).removeClass('oe_mouseout').addClass('oe_mouseover');
self.display_subtypes();
})
.on('mouseleave', function () {
$(this).removeClass('oe_mouseover').addClass('oe_mouseout');
self.display_subtypes();
});
this.$('button.oe_follower')
.on('click', function () {
if($(this).hasClass('oe_notfollow'))
self.do_follow();
else
self.do_unfollow();
})
.on('mouseover', function () {
$(this).removeClass('oe_mouseout').addClass('oe_mouseover');
})
.on('mouseleave', function () {
$(this).removeClass('oe_mouseover').addClass('oe_mouseout');
});
this.$el.on('click', 'ul.oe_subtypes input', function () { self.do_update_subscription(); })
this.$el.on('click', 'ul.oe_subtypes input', self.do_update_subscription );
this.$el.on('click', 'button.oe_invite', function(event) {
action = {
@ -173,7 +158,8 @@ openerp_mail_followers = function(session, mail) {
set_subtypes:function(data){
var self = this;
var records = data[this.view.datarecord.id].message_subtype_data;
var records = (data[this.view.datarecord.id] || data[null]).message_subtype_data;
_(records).each(function (record, record_name) {
record.name = record_name;
record.followed = record.followed || undefined;
@ -194,16 +180,10 @@ openerp_mail_followers = function(session, mail) {
},
do_follow: function () {
var self =this;
_(this.$('.oe_msg_subtype_check')).each(function(record){
$(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], undefined, undefined, context]).pipe(function(value_){
self.read_value(value_);
if(!self.$('.oe_recthread_subtypes').is(":visible"))
self.display_subtypes(true);
});
this.do_update_subscription();
},
do_unfollow: function () {
@ -211,23 +191,28 @@ 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], undefined, context]).pipe(this.proxy('read_value'));
return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], [this.session.uid], context]).pipe(this.proxy('read_value'));
},
do_update_subscription: function () {
var context = new session.web.CompoundContext(this.build_context(), {});
do_update_subscription: function (event) {
var self = this;
var checklist = new Array();
_(this.$('.oe_msg_subtype_check')).each(function(record){
_(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
return this.ds_model.call('message_subscribe_users',[[self.view.datarecord.id], undefined, checklist, context]).pipe(this.proxy('read_value'));
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);
});
}
},
});

View File

@ -1,11 +1,118 @@
<?xml version="1.0" encoding="UTF-8"?>
<template>
<!--
mail.compose_message template
This template holds the composition form to write a note or send
an e-mail. It contains by default a textarea, that will be replaced
by another composition form in the main wall composition form, or
for main thread composition form in document form view.
-->
<t t-name="mail.compose_message">
<div class="oe_mail_compose_textarea">
<img class="oe_mail_icon oe_mail_frame oe_left" alt="User img"/>
<div class="oe_mail_msg_content">
<!-- contains the composition form -->
<!-- default content: old basic textarea -->
<div class="oe_mail_post_header">
<t t-call="mail.thread.list_recipients"/>
<a class="oe_cancel oe_e">X</a>
</div>
<textarea class="field_text" placeholder="Add your comment here..."/>
<div class="oe_mail_post_footer">
<div class="oe_mail_compose_attachment_list"/>
<button class="oe_full">Full mail message</button>
<button class="oe_post">Post message</button>
<t t-call="mail.compose_message.add_attachment"/>
</div>
</div>
<div class="oe_clear"/>
</div>
</t>
<!--
mail.compose_message.add_attachment template
Small template to be inserted in the composition for add attachments
-->
<t t-name="mail.compose_message.add_attachment">
<div class="oe_attachment_file">
<div class="oe_add">
<!-- uploader of file -->
<button><span class="oe_e">p</span></button>
<t t-call="HiddenInputFile">
<t t-set="fileupload_id" t-value="widget.fileupload_id"/>
<t t-set="fileupload_action">/web/binary/upload_attachment</t>
<input type="hidden" name="model" value=""/>
<input type="hidden" name="id" value="0"/>
<input type="hidden" name="session_id" t-att-value="widget.session.session_id"/>
</t>
</div>
</div>
</t>
<!--
mail.thread.message.attachments template
Template used to display attachments in a mail.message
-->
<t t-name="mail.thread.message.attachments">
<ul t-attf-class="oe_mail_msg_attachments #{widget.attachment_ids[0] and widget.options.thread.show_attachment_link?'':'oe_hidden'}">
<t t-foreach="widget.attachment_ids" t-as="attachment">
<li>
<span t-if="(attachment.upload or attachment.percent_loaded&lt;100)" t-attf-title="{(attachment.name || attachment.filename) + (attachment.date?' \n('+attachment.date+')':'' )}" t-attf-name="{attachment.name || attachment.filename}">
<div class="oe_upload_in_process">
<span>...wait upload...</span>
<div t-attf-style="{attachment.percent_loaded&gt;0?'':'display:none;'}"/>
<div t-attf-style="{attachment.percent_loaded&gt;20?'':'display:none;'}"/>
<div t-attf-style="{attachment.percent_loaded&gt;40?'':'display:none;'}"/>
<div t-attf-style="{attachment.percent_loaded&gt;60?'':'display:none;'}"/>
<div t-attf-style="{attachment.percent_loaded&gt;80?'':'display:none;'}"/>
</div>
<t t-raw="attachment.name || attachment.filename"/>
</span>
<a t-if="(!attachment.upload or attachment.percent_loaded&gt;=100)" t-att-href="attachment.url" t-attf-title="{(attachment.name || attachment.filename) + (attachment.date?' \n('+attachment.date+')':'' )}">
<t t-raw="attachment.name || attachment.filename"/>
</a>
<t t-if="widget.options.thread.show_attachment_delete and (!attachment.upload or attachment.percent_loaded&gt;=100)">
<a class="oe_right oe_mail_attachment_delete" title="Delete this attachmentt" t-attf-data-id="{attachment.id}">x</a>
</t>
</li>
</t>
</ul>
</t>
<t t-name="mail.thread.message.private">
<div>
<span class="oe_placeholder_checkbox_private"/>
<span class="oe_send_private">This email is private.</span>
<span class="oe_send_public">I wrote for contacts and all my followers.</span>
</div>
</t>
<!--
template to the recipients list
-->
<t t-name="mail.thread.list_recipients">
<div class="oe_mail_list_recipients">
Post to:
<span t-if="!widget.is_private" class="oe_all_follower">All Followers</span>
<t t-if="!widget.is_private and widget.partner_ids.length"> and </t>
<t t-set="inc" t-value="0"/>
<t t-if="widget.partner_ids.length" t-foreach="widget.partner_ids" t-as="partner"><span t-attf-class="oe_partner_follower #{inc>=3?'oe_hidden':''}"><t t-if="inc" t-raw="', '"/><a t-attf-href="#model=res.partner&amp;id=#{partner[0]}"><t t-raw="partner[1]"/></a></span><t t-set="inc" t-value="inc+1"/>
</t>
<t t-if="widget.partner_ids.length>=3">
<span class="oe_more">, <a><t t-raw="widget.partner_ids.length-3"/> others...</a></span>
<a class="oe_more_hidden">&lt;&lt;&lt;</a>
</t>
</div>
</t>
<!--
wall main template
Template used to display the communication history in the wall.
-->
<div t-name="mail.wall" class="oe_view_manager oe_mail_wall oe_view_manager_current">
<div t-name="mail.wall" class="oe_view_manager oe_mail_wall oe_view_manag
er_current">
<table class="oe_view_manager_header">
<colgroup>
<col width="33%"/>
@ -25,21 +132,30 @@
</td>
<td><div class="oe_view_manager_view_search" t-opentag="true"/></td>
</tr>
<tr class="oe_header_row">
<td colspan="2">
<button type="button" class="oe_write_full oe_highlight">
Compose a new message
</button>
<button type="button" class="oe_write_onwall" help="Your followers can read this message">
Write to your followers
</button>
</td>
</tr>
</tbody>
</table>
<ul class="oe_mail_wall_threads">
<!-- contains threads -->
</ul>
<!-- placeholder for the wall threads -->
<div class="oe_mail_wall_threads"/>
<div class="oe_mail_wall_aside">
<!-- contains currently nothing -->
</div>
</div>
<!--
wall_thread_container template for the wall
Each discussion thread is contained inside this template
display message on the wall when there are no message
-->
<li t-name="mail.wall_thread_container" class="oe_mail_wall_thread">
<li t-name="mail.wall_no_message" class="oe_wall_no_message">
You have no messages
</li>
<!--
@ -54,39 +170,6 @@
</ul>
</div>
<!--
mail.compose_message template
This template holds the composition form to write a note or send
an e-mail. It contains by default a textarea, that will be replaced
by another composition form in the main wall composition form, or
for main thread composition form in document form view.
-->
<t t-name="mail.compose_message">
<div class="oe_mail_compose_textarea">
<img class="oe_mail_icon oe_mail_frame oe_left" alt="User img"/>
<div class="oe_mail_msg_content">
<!-- contains the composition form -->
<!-- default content: old basic textarea -->
<textarea placeholder="Add your comment here..."/>
</div>
<div class="oe_clear"/>
</div>
</t>
<!--
mail.compose_message.add_attachment template
Small template to be inserted in the composition form to add attachments
-->
<t t-name="mail.compose_message.add_attachment">
<t t-call="HiddenInputFile">
<t t-set="fileupload_id" t-value="widget.fileupload_id"/>
<t t-set="fileupload_action">/web/binary/upload_attachment</t>
<input type="hidden" name="model" t-att-value="widget.form_view.model"/>
<input type="hidden" name="id" t-att-value="widget.form_view.datarecord.id || 0"/>
<input type="hidden" name="session_id" t-att-value="widget.session.session_id"/>
</t>
</t>
<!--
thread template
This template holds a thread of comments. It begins with an actions
@ -96,7 +179,6 @@
<div t-name="mail.thread" class="oe_mail oe_mail_thread oe_semantic_html_override">
<div class="oe_mail_thread_action">
<!-- contains the composition box (form + image) -->
<t t-call="mail.compose_message"/>
</div>
<ul class="oe_mail_thread_display">
<!-- contains the threads -->
@ -104,16 +186,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'}" t-attf-data-msg_id="{widget.id}">
<li t-name="mail.thread.message" t-attf-class="oe_mail oe_mail_thread_msg #{widget.unread?'oe_mail_unread':'oe_mail_read'}">
<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 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 t-if="!widget.options.thread.display_on_flat" title="Read" class="oe_read"><a class="oe_read oe_e">W</a></li>
<li t-if="!widget.options.thread.display_on_flat" title="Set back to unread" class="oe_unread"><a class="oe_unread oe_e">h</a></li>
<li title="Quick reply"><a class="oe_reply oe_e">)</a></li>
<t t-if="(widget.is_author and widget.options.message.show_dd_delete) or widget.type == 'email'">
<li>
<span class="oe_dropdown_toggle">
<a class="oe_e" title="More options">í</a>
@ -123,8 +204,6 @@
<li t-if="display['show_hide']">
<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</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>
@ -145,7 +224,6 @@
<ul class="oe_mail_msg_footer">
<li t-if="widget.author_id"><a t-attf-href="#model=res.partner&amp;id=#{widget.author_id[0]}"><t t-raw="widget.author_id[1]"/></a></li>
<li><span t-att-title="widget.date"><t t-raw="widget.timerelative"/></span></li>
<li t-if="widget.attachment_ids.length > 0">
<a class="oe_mail_msg_view_attachments">
<t t-if="widget.attachment_ids.length == 1">1 Attachment</t>
@ -155,7 +233,7 @@
</ul>
<div class="oe_clear"/>
<div class="oe_mail_msg_body">
<t t-if="widget.options.message.show_record_name and widget.record_name and (!widget.subject) and widget.options.thread._parents.length&lt;=widget.options.thread.thread_level and widget.model!='res.partner'">
<t t-if="widget.options.message.show_record_name and widget.record_name and (!widget.subject) and !widget.options.thread.thread_level and !widget.options.thread.display_on_flat and widget.model!='res.partner'">
<a class="oe_mail_action_model" t-attf-href="#model=#{widget.model}&amp;id=#{widget.res_id}"><t t-raw="widget.record_name"/></a>
</t>
<t t-raw="widget.body"/>
@ -171,7 +249,7 @@
</li>
<!-- expandable message layout -->
<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}">
<li t-name="mail.thread.expandable" class="oe_mail oe_mail_thread_msg oe_mail_unread">
<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>
@ -179,23 +257,6 @@
</div>
</li>
<!--
mail.thread.message.attachments template
Template used to display attachments in a mail.message
-->
<t t-name="mail.thread.message.attachments">
<ul class="oe_mail_msg_attachments">
<t t-foreach="record.attachment_ids" t-as="attachment">
<li>
<a t-att-href="attachment.url"><t t-raw="attachment.name || attachment.filename"/></a>
<t t-if="record.show_attachment_delete">
<a class="oe_right oe_mail_attachment_delete" title="Delete this attachmentt" t-attf-data-id="{attachment.id}">x</a>
</t>
</li>
</t>
</ul>
</t>
<!-- mail.thread.message.vote
Template used to display Like/Unlike in a mail.message
-->
@ -215,7 +276,7 @@
<button t-attf-class="oe_mail_msg_vote oe_tag">
<span>
<t t-if="!widget.has_voted">Agree</t>
<t t-if="widget.has_voted">Unagree</t>
<t t-if="widget.has_voted">Undo</t>
</span>
</button>
</span>

View File

@ -13,9 +13,9 @@
<span class="oe_unfollow">Unfollow</span>
<span class="oe_following">Following</span>
</button>
<div class="oe_recthread_subtypes">
<ul class="oe_subtypes"></ul>
</div>
</div>
<div class="oe_recthread_subtypes">
<ul class="oe_subtypes"></ul>
</div>
</div>
<div class="oe_grey">

View File

@ -529,109 +529,6 @@ class test_mail(TestMailMockups):
self.assertEqual(message2.subject, _subject, 'mail.message subject incorrect')
self.assertEqual(message2.body, group_bird.description, 'mail.message body incorrect')
# FP Note: to be reviewed to be more generic, not depending on the algorythm of
# message_read
#def test_30_message_read(self):
# """ Tests designed for message_read. """
# # TDE NOTE: this test is not finished, as the message_read method is not fully specified.
# # It will be updated as soon as we have fixed specs !
# cr, uid = self.cr, self.uid
# group_pigs = self.mail_group.browse(cr, uid, self.group_pigs_id)
# def _compare_structures(struct1, struct2, n=0):
# # print '%scompare structure' % ('\t' * n)
# # self.assertEqual(len(struct1), len(struct2), 'message_read structure number of childs incorrect')
# for x in range(len(struct1)):
# if struct1[x].get('type') == 'expandable':
# continue
# # print '%s' % ('\t' * n), struct1[x]['id'], struct1[x]['child_nbr'], struct2[x]['id'], struct2[x].get('child_nbr', 'XX'), struct1[x].get('subject') or ''
# self.assertEqual(struct1[x]['id'], struct2[x]['id'], 'message_read failure %s' % struct1[x].get('subject'))
# _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
# # ----------------------------------------
# # 1. Add a few messages to pigs group
# msgid1 = group_pigs.message_post(body='1', subject='1', parent_id=False)
# msgid2 = group_pigs.message_post(body='2', subject='1-1', parent_id=msgid1)
# msgid3 = group_pigs.message_post(body='3', subject='1-2', parent_id=msgid1)
# msgid4 = group_pigs.message_post(body='4', subject='2', parent_id=False)
# msgid5 = group_pigs.message_post(body='5', subject='1-1-1', parent_id=msgid2)
# msgid6 = group_pigs.message_post(body='6', subject='2-1', parent_id=msgid4)
# # Test: read all messages flat
# tree_test = [{'id': msgid6, 'child_ids': []}, {'id': msgid5, 'child_ids': []},
# {'id': msgid4, 'child_ids': []}, {'id': msgid3, 'child_ids': []},
# {'id': msgid2, 'child_ids': []}, {'id': msgid1, 'child_ids': []}]
# tree = self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], level=0, limit=15)
# _compare_structures(tree, tree_test)
# # Test: read with 1 level of thread
# tree_test = [{'id': msgid4, 'child_ids': [{'id': msgid6, 'child_ids': []}, ]},
# {'id': msgid1, 'child_ids': [
# {'id': msgid5, 'child_ids': []}, {'id': msgid3, 'child_ids': []},
# {'id': msgid2, 'child_ids': []},
# ]},
# ]
# tree = self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], level=1, limit=15)
# _compare_structures(tree, tree_test)
# # Test: read with 2 levels of thread
# tree_test = [{'id': msgid4, 'child_ids': [{'id': msgid6, 'child_ids': []}, ]},
# {'id': msgid1, 'child_ids': [
# {'id': msgid3, 'child_ids': []},
# {'id': msgid2, 'child_ids': [{'id': msgid5, 'child_ids': []}, ]},
# ]},
# ]
# tree = self.mail_message.message_read(cr, uid, ids=False, domain=[('model', '=', 'mail.group'), ('res_id', '=', self.group_pigs_id)], level=2, limit=15)
# _compare_structures(tree, tree_test)
# # 2. Test expandables
# # TDE FIXME: add those tests when expandables are specified and implemented
def test_40_needaction(self):
""" Tests for mail.message needaction. """
cr, uid = self.cr, self.uid

View File

@ -223,7 +223,6 @@ 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):

View File

@ -16,13 +16,11 @@
<field name="partner_ids" widget="many2many_tags" placeholder="Add contacts to notify..."
context="{'force_email':True}"
on_change="onchange_partner_ids(partner_ids)"/>
<field name="is_private" help="If this message is not private, this message will send to all your followers or all followers of the parented message."/>
</group>
<notebook>
<page string="Body">
<field name="body_text" nolabel="1"
attrs="{'invisible':[('content_subtype', '=', 'html')]}"/>
<field name="body" nolabel="1"
attrs="{'invisible':[('content_subtype', '=', 'plain')]}"/>
<field name="body" nolabel="1"/>
</page>
<page string="Attachments">
<field name="attachment_ids" colspan="4" nolabel="1"/>
@ -32,10 +30,10 @@
<button string="Send" name="send_mail" type="object" class="oe_highlight" />
or
<button string="Cancel" class="oe_link" special="cancel" />
<div class="oe_right">
<!--div class="oe_right">
<button string="" name="toggle_content_subtype" type="object" icon="/mail/static/src/img/formatting.png"
help="Toggle advanced formatting mode"/>
</div>
</div-->
</footer>
</form>
</field>
@ -68,6 +66,7 @@
context="{'force_email':True}"
on_change="onchange_partner_ids(partner_ids)"
class="oe_mail_compose_message_partner_ids"/>
<!--field name="is_private" help="If this message is not private, this message will send to all your followers or all followers of the parented message."/-->
<field name="attachment_ids" colspan="2" nolabel="1" widget="many2many_tags"
placeholder="Add attachments..." invisible="1"
class="oe_mail_compose_message_attachment_ids"/>