def test_html_email_clean(self): # Test1: reply through gmail: quote in blockquote, signature --\nAdministrator new_html = html_email_clean(GMAIL_REPLY1_SAN) self.assertNotIn('blockquote', new_html, 'html_email_cleaner did not remove a blockquote') self.assertNotIn('I contact you about our meeting', new_html, 'html_email_cleaner wrongly removed the quoted content') self.assertNotIn('Administrator', new_html, 'html_email_cleaner did not erase the signature') self.assertIn('Ok for me', new_html, 'html_email_cleaner erased too much content') # Test2: reply through Tunderbird 16.0.2 new_html = html_email_clean(THUNDERBIRD_16_REPLY1_SAN) self.assertNotIn('blockquote', new_html, 'html_email_cleaner did not remove a blockquote') self.assertNotIn('I contact you about our meeting', new_html, 'html_email_cleaner wrongly removed the quoted content') self.assertNotIn('Administrator', new_html, 'html_email_cleaner did not erase the signature') self.assertNotIn('Grosbedonn', new_html, 'html_email_cleaner did not erase the signature') self.assertIn('Ok for me', new_html, 'html_email_cleaner erased too much content') # Test3: text email new_html = html_email_clean(TEXT_MAIL1) self.assertIn('I contact you about our meeting', new_html, 'html_email_cleaner wrongly removed the quoted content') self.assertNotIn('Administrator', new_html, 'html_email_cleaner did not erase the signature') # Test4: more complex text email new_html = html_email_clean(TEXT_TPL) self.assertNotIn('quote', new_html, 'html_email_cleaner did not remove correctly plaintext quotes') # Test5: False boolean for text must return empty string new_html = html_email_clean(False) self.assertEqual(new_html, False, 'html_email_cleaner did change a False in an other value.')
def test_70_read_more_and_shorten(self): expand_options = { 'oe_expand_container_class': 'span_class', 'oe_expand_container_content': 'Herbert Einstein', 'oe_expand_separator_node': 'br_lapin', 'oe_expand_a_class': 'a_class', 'oe_expand_a_content': 'read mee', } new_html = html_email_clean(test_mail_examples.OERP_WEBSITE_HTML_1, remove=True, shorten=True, max_length=100, expand_options=expand_options) for ext in test_mail_examples.OERP_WEBSITE_HTML_1_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.OERP_WEBSITE_HTML_1_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase overlimit content') for ext in ['<span class="span_class">Herbert Einstein<br_lapin></br_lapin><a href="#" class="a_class">read mee</a></span>']: self.assertIn(ext, new_html, 'html_email_cleaner wrongly take into account specific expand options') new_html = html_email_clean(test_mail_examples.OERP_WEBSITE_HTML_2, remove=True, shorten=True, max_length=200, expand_options=expand_options, protect_sections=False) for ext in test_mail_examples.OERP_WEBSITE_HTML_2_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.OERP_WEBSITE_HTML_2_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase overlimit content') for ext in ['<span class="span_class">Herbert Einstein<br_lapin></br_lapin><a href="#" class="a_class">read mee</a></span>']: self.assertIn(ext, new_html, 'html_email_cleaner wrongly take into account specific expand options') new_html = html_email_clean(test_mail_examples.OERP_WEBSITE_HTML_2, remove=True, shorten=True, max_length=200, expand_options=expand_options, protect_sections=True) for ext in test_mail_examples.OERP_WEBSITE_HTML_2_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.OERP_WEBSITE_HTML_2_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase overlimit content') for ext in [ '<span class="span_class">Herbert Einstein<br_lapin></br_lapin><a href="#" class="a_class">read mee</a></span>', 'tasks using the gantt chart and control deadlines']: self.assertIn(ext, new_html, 'html_email_cleaner wrongly take into account specific expand options')
def test_90_misc(self): # False boolean for text must return empty string new_html = html_email_clean(False) self.assertEqual(new_html, False, 'html_email_cleaner did change a False in an other value.') # Message with xml and doctype tags don't crash new_html = html_email_clean(u'<?xml version="1.0" encoding="iso-8859-1"?>\n<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\n "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n <head>\n <title>404 - Not Found</title>\n </head>\n <body>\n <h1>404 - Not Found</h1>\n </body>\n</html>\n') self.assertNotIn('encoding', new_html, 'html_email_cleaner did not remove correctly encoding attributes')
def test_20_email_html(self): new_html = html_email_clean(test_mail_examples.HTML_1, remove=True) for ext in test_mail_examples.HTML_1_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.HTML_1_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase signature / quoted content') new_html = html_email_clean(test_mail_examples.HTML_2, remove=True) for ext in test_mail_examples.HTML_2_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.HTML_2_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase signature / quoted content')
def test_70_read_more(self): new_html = html_email_clean(test_mail_examples.BUG1, remove=True, shorten=True, max_length=100) for ext in test_mail_examples.BUG_1_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed valid content') for ext in test_mail_examples.BUG_1_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not removed invalid content') new_html = html_email_clean(test_mail_examples.BUG2, remove=True, shorten=True, max_length=250) for ext in test_mail_examples.BUG_2_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed valid content') for ext in test_mail_examples.BUG_2_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not removed invalid content')
def test_05_shorten(self): # TEST: shorten length test_str = """<div> <span> </span> <p>Hello, <span>Raoul</span> <bold>You</bold> are pretty</p> <span>Really</span> </div> """ # shorten at 'H' of Hello -> should shorten after Hello, html = html_email_clean(test_str, shorten=True, max_length=1, remove=True) self.assertIn("Hello,", html, "html_email_cleaner: shorten error or too short") self.assertNotIn("Raoul", html, "html_email_cleaner: shorten error or too long") self.assertIn("read more", html, "html_email_cleaner: shorten error about read more inclusion") # shorten at 'are' -> should shorten after are html = html_email_clean(test_str, shorten=True, max_length=17, remove=True) self.assertIn("Hello,", html, "html_email_cleaner: shorten error or too short") self.assertIn("Raoul", html, "html_email_cleaner: shorten error or too short") self.assertIn("are", html, "html_email_cleaner: shorten error or too short") self.assertNotIn("pretty", html, "html_email_cleaner: shorten error or too long") self.assertNotIn("Really", html, "html_email_cleaner: shorten error or too long") self.assertIn("read more", html, "html_email_cleaner: shorten error about read more inclusion") # TEST: shorten in quote test_str = """<div> Blahble bluih blouh <blockquote>This is a quote <span>And this is quite a long quote, after all.</span> </blockquote> </div>""" # shorten in the quote html = html_email_clean(test_str, shorten=True, max_length=25, remove=True) self.assertIn("Blahble", html, "html_email_cleaner: shorten error or too short") self.assertIn("bluih", html, "html_email_cleaner: shorten error or too short") self.assertIn("blouh", html, "html_email_cleaner: shorten error or too short") self.assertNotIn("quote", html, "html_email_cleaner: shorten error or too long") self.assertIn("read more", html, "html_email_cleaner: shorten error about read more inclusion") # shorten in second word html = html_email_clean(test_str, shorten=True, max_length=9, remove=True) self.assertIn("Blahble", html, "html_email_cleaner: shorten error or too short") self.assertIn("bluih", html, "html_email_cleaner: shorten error or too short") self.assertNotIn("blouh", html, "html_email_cleaner: shorten error or too short") self.assertNotIn("quote", html, "html_email_cleaner: shorten error or too long") self.assertIn("read more", html, "html_email_cleaner: shorten error about read more inclusion") # shorten waaay too large html = html_email_clean(test_str, shorten=True, max_length=900, remove=True) self.assertIn("Blahble", html, "html_email_cleaner: shorten error or too short") self.assertIn("bluih", html, "html_email_cleaner: shorten error or too short") self.assertIn("blouh", html, "html_email_cleaner: shorten error or too short") self.assertNotIn("quote", html, "html_email_cleaner: shorten error or too long")
def test_05_shorten(self): # TEST: shorten length test_str = '''<div> <span> </span> <p>Hello, <span>Raoul</span> <bold>You</bold> are pretty</p> <span>Really</span> </div> ''' # shorten at 'H' of Hello -> should shorten after Hello, html = html_email_clean(test_str, shorten=True, max_length=1, remove=True) self.assertIn('Hello,', html, 'html_email_cleaner: shorten error or too short') self.assertNotIn('Raoul', html, 'html_email_cleaner: shorten error or too long') self.assertIn('read more', html, 'html_email_cleaner: shorten error about read more inclusion') # shorten at 'are' -> should shorten after are html = html_email_clean(test_str, shorten=True, max_length=17, remove=True) self.assertIn('Hello,', html, 'html_email_cleaner: shorten error or too short') self.assertIn('Raoul', html, 'html_email_cleaner: shorten error or too short') self.assertIn('are', html, 'html_email_cleaner: shorten error or too short') self.assertNotIn('pretty', html, 'html_email_cleaner: shorten error or too long') self.assertNotIn('Really', html, 'html_email_cleaner: shorten error or too long') self.assertIn('read more', html, 'html_email_cleaner: shorten error about read more inclusion') # TEST: shorten in quote test_str = '''<div> Blahble bluih blouh <blockquote>This is a quote <span>And this is quite a long quote, after all.</span> </blockquote> </div>''' # shorten in the quote html = html_email_clean(test_str, shorten=True, max_length=25, remove=True) self.assertIn('Blahble', html, 'html_email_cleaner: shorten error or too short') self.assertIn('bluih', html, 'html_email_cleaner: shorten error or too short') self.assertIn('blouh', html, 'html_email_cleaner: shorten error or too short') self.assertNotIn('quote', html, 'html_email_cleaner: shorten error or too long') self.assertIn('read more', html, 'html_email_cleaner: shorten error about read more inclusion') # shorten in second word html = html_email_clean(test_str, shorten=True, max_length=9, remove=True) self.assertIn('Blahble', html, 'html_email_cleaner: shorten error or too short') self.assertIn('bluih', html, 'html_email_cleaner: shorten error or too short') self.assertNotIn('blouh', html, 'html_email_cleaner: shorten error or too short') self.assertNotIn('quote', html, 'html_email_cleaner: shorten error or too long') self.assertIn('read more', html, 'html_email_cleaner: shorten error about read more inclusion') # shorten waaay too large html = html_email_clean(test_str, shorten=True, max_length=900, remove=True) self.assertIn('Blahble', html, 'html_email_cleaner: shorten error or too short') self.assertIn('bluih', html, 'html_email_cleaner: shorten error or too short') self.assertIn('blouh', html, 'html_email_cleaner: shorten error or too short') self.assertNotIn('quote', html, 'html_email_cleaner: shorten error or too long')
def test_10_email_text(self): """ html_email_clean test for text-based emails """ new_html = html_email_clean(test_mail_examples.TEXT_1, remove=True) for ext in test_mail_examples.TEXT_1_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.TEXT_1_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase signature / quoted content') new_html = html_email_clean(test_mail_examples.TEXT_2, remove=True) for ext in test_mail_examples.TEXT_2_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.TEXT_2_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase signature / quoted content')
def test_00_basic_text(self): """ html_email_clean test for signatures """ test_data = [ ( """This is Sparta!\n--\nAdministrator\n+9988776655""", ['This is Sparta!'], ['Administrator', '9988776655'] ), ( """<p>--\nAdministrator</p>""", [], ['--', 'Administrator'] ), ( """<p>This is Sparta!\n---\nAdministrator</p>""", ['This is Sparta!'], ['---', 'Administrator'] ), ( """<p>--<br>Administrator</p>""", [], [] ), ( """<p>This is Sparta!<br/>--<br>Administrator</p>""", ['This is Sparta!'], [] ), ( """This is Sparta!\n>Ah bon ?\nCertes\n> Chouette !\nClair""", ['This is Sparta!', 'Certes', 'Clair'], ['Ah bon', 'Chouette'] ) ] for test, in_lst, out_lst in test_data: new_html = html_email_clean(test, remove=True) for text in in_lst: self.assertIn(text, new_html, 'html_email_cleaner wrongly removed content') for text in out_lst: self.assertNotIn(text, new_html, 'html_email_cleaner did not remove unwanted content')
def test_30_email_msoffice(self): new_html = html_email_clean(test_mail_examples.MSOFFICE_1, remove=True) for ext in test_mail_examples.MSOFFICE_1_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.MSOFFICE_1_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase signature / quoted content') new_html = html_email_clean(test_mail_examples.MSOFFICE_2, remove=True) for ext in test_mail_examples.MSOFFICE_2_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.MSOFFICE_2_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase signature / quoted content') new_html = html_email_clean(test_mail_examples.MSOFFICE_3, remove=True) for ext in test_mail_examples.MSOFFICE_3_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.MSOFFICE_3_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase signature / quoted content')
def test_html_email_clean(self): # Test1: reply through gmail: quote in blockquote, signature --\nAdministrator new_html = html_email_clean(GMAIL_REPLY1_SAN) self.assertNotIn('blockquote', new_html, 'html_email_cleaner did not remove a blockquote') self.assertNotIn('I contact you about our meeting', new_html, 'html_email_cleaner wrongly removed the quoted content') self.assertNotIn('Administrator', new_html, 'html_email_cleaner did not erase the signature') self.assertIn('Ok for me', new_html, 'html_email_cleaner erased too much content') # Test2: reply through Tunderbird 16.0.2 new_html = html_email_clean(THUNDERBIRD_16_REPLY1_SAN) self.assertNotIn('blockquote', new_html, 'html_email_cleaner did not remove a blockquote') self.assertNotIn('I contact you about our meeting', new_html, 'html_email_cleaner wrongly removed the quoted content') self.assertNotIn('Administrator', new_html, 'html_email_cleaner did not erase the signature') self.assertNotIn('Grosbedonn', new_html, 'html_email_cleaner did not erase the signature') self.assertIn('Ok for me', new_html, 'html_email_cleaner erased too much content') # Test3: text email new_html = html_email_clean(TEXT_MAIL1) self.assertIn('I contact you about our meeting', new_html, 'html_email_cleaner wrongly removed the quoted content') self.assertNotIn('Administrator', new_html, 'html_email_cleaner did not erase the signature') # Test4: more complex text email new_html = html_email_clean(TEXT_TPL) self.assertNotIn('quote', new_html, 'html_email_cleaner did not remove correctly plaintext quotes') # Test5: False boolean for text must return empty string new_html = html_email_clean(False) self.assertEqual(new_html, False, 'html_email_cleaner did change a False in an other value.') # Test6: Message with xml and doctype tags don't crash new_html = html_email_clean(u'<?xml version="1.0" encoding="iso-8859-1"?>\n<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"\n "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">\n <head>\n <title>404 - Not Found</title>\n </head>\n <body>\n <h1>404 - Not Found</h1>\n </body>\n</html>\n') self.assertNotIn('encoding', new_html, 'html_email_cleaner did not remove correctly encoding attributes')
def _message_read_dict(self, cr, uid, message, parent_id=False, context=None): """ Return a dict representation of the message. This representation is used in the JS client code, to display the messages. Partners and attachments related stuff will be done in post-processing in batch. :param dict message: mail.message browse record """ # private message: no model, no res_id is_private = False if not message.model or not message.res_id: is_private = True # votes and favorites: res.users ids, no prefetching should be done vote_nb = len(message.vote_user_ids) has_voted = uid in [user.id for user in message.vote_user_ids] try: if parent_id: max_length = 300 else: max_length = 100 body_short = html_email_clean(message.body, remove=False, shorten=True, max_length=max_length) except Exception: body_short = "<p><b>Encoding Error : </b><br/>Unable to convert this message (id: %s).</p>" % message.id _logger.exception(Exception) return { "id": message.id, "type": message.type, "subtype": message.subtype_id.name if message.subtype_id else False, "body": message.body, "body_short": body_short, "model": message.model, "res_id": message.res_id, "record_name": message.record_name, "subject": message.subject, "date": message.date, "to_read": message.to_read, "parent_id": parent_id, "is_private": is_private, "author_id": False, "author_avatar": message.author_avatar, "is_author": False, "partner_ids": [], "vote_nb": vote_nb, "has_voted": has_voted, "is_favorite": message.starred, "attachment_ids": [], }
def _message_read_dict(self, cr, uid, message, parent_id=False, \ context=None): """ Return a dict representation of the message. This representation is used in the JS client code, to display the messages. Partners and attachments related stuff will be done in post-processing in batch. :param dict message: mail.message browse record """ # private message: no model, no res_id is_private = False if not message.model or not message.res_id: is_private = True # votes and favorites: res.users ids, no prefetching should be done vote_nb = len(message.vote_user_ids) has_voted = uid in [user.id for user in message.vote_user_ids] try: body_html = html_email_clean(message.body) except Exception: body_html = '<p><b>Encoding Error : </b><br/>Unable to convert\ this message (id: %s).</p>' % message.id _logger.exception(Exception) return {'id': message.id, 'type': message.type, 'subtype': message.subtype_id.name if \ message.subtype_id else False, 'body': body_html, 'model': message.model, 'res_id': message.res_id, 'record_name': message.record_name, 'subject': message.subject, 'date': message.date, 'to_read': message.to_read, 'parent_id': parent_id, 'is_private': is_private, 'author_id': False, 'is_author': False, 'partner_ids': [], 'vote_nb': vote_nb, 'has_voted': has_voted, 'is_favorite': message.starred, 'attachment_ids': [], 'email_from':message.email_from or '', 'email_to': message.email_to or '', 'email_cc': message.email_cc or '', }
def get_shortened_content(self, cr, uid, ids, name, arg, context=None): res = {} for page in self.browse(cr, uid, ids, context=context): try: body_short = tools.html_email_clean( page.content, remove=True, shorten=True, max_length=self._shorten_max_char, expand_options={ 'oe_expand_container_tag': 'div', 'oe_expand_container_class': 'oe_mail_expand text-center', 'oe_expand_container_content': '', 'oe_expand_a_href': '/blogpost/%d' % page.id, 'oe_expand_a_class': 'oe_mail_expand btn btn-info', 'oe_expand_separator_node': 'br', }, protect_sections=True, ) except Exception: body_short = False res[page.id] = body_short return res
def test_00_basic_text(self): """ html_email_clean test for signatures """ test_data = [ ( """This is Sparta!\n--\nAdministrator\n+9988776655""", ["This is Sparta!"], ["Administrator", "9988776655"], ), ("""<p>--\nAdministrator</p>""", [], ["--", "Administrator"]), ("""<p>This is Sparta!\n---\nAdministrator</p>""", ["This is Sparta!"], ["---", "Administrator"]), ("""<p>--<br>Administrator</p>""", [], []), ("""<p>This is Sparta!<br/>--<br>Administrator</p>""", ["This is Sparta!"], []), ( """This is Sparta!\n>Ah bon ?\nCertes\n> Chouette !\nClair""", ["This is Sparta!", "Certes", "Clair"], ["Ah bon", "Chouette"], ), ] for test, in_lst, out_lst in test_data: new_html = html_email_clean(test, remove=True) for text in in_lst: self.assertIn(text, new_html, "html_email_cleaner wrongly removed content") for text in out_lst: self.assertNotIn(text, new_html, "html_email_cleaner did not remove unwanted content")
def _message_read_dict_postprocess(self, messages, message_tree): """ Post-processing on values given by message_read. This method will handle partners in batch to avoid doing numerous queries. :param list messages: list of message, as get_dict result :param dict message_tree: {[msg.id]: msg browse record} """ # 1. Aggregate partners (author_id and partner_ids), attachments and tracking values partners = self.env['res.partner'] attachments = self.env['ir.attachment'] trackings = self.env['mail.tracking.value'] for key, message in message_tree.iteritems(): if message.author_id: partners |= message.author_id if message.subtype_id and message.partner_ids: # take notified people of message with a subtype partners |= message.partner_ids elif not message.subtype_id and message.partner_ids: # take specified people of message without a subtype (log) partners |= message.partner_ids if message.attachment_ids: attachments |= message.attachment_ids if message.tracking_value_ids: trackings |= message.tracking_value_ids # Read partners as SUPERUSER -> display the names like classic m2o even if no access partners_names = partners.sudo().name_get() partner_tree = dict((partner[0], partner) for partner in partners_names) # 2. Attachments as SUPERUSER, because could receive msg and attachments for doc uid cannot see attachments_data = attachments.sudo().read(['id', 'datas_fname', 'name', 'mimetype']) attachments_tree = dict((attachment['id'], { 'id': attachment['id'], 'filename': attachment['datas_fname'], 'name': attachment['name'], 'mimetype': attachment['mimetype'], }) for attachment in attachments_data) # 3. Tracking values tracking_tree = dict((tracking.id, { 'id': tracking.id, 'changed_field': tracking.field_desc, 'old_value': tracking.get_old_display_value()[0], 'new_value': tracking.get_new_display_value()[0], }) for tracking in trackings) # 4. Update message dictionaries for message_dict in messages: message_id = message_dict.get('id') message = message_tree[message_id] if message.author_id: author = partner_tree[message.author_id.id] else: author = (0, message.email_from) partner_ids = [] if message.subtype_id: partner_ids = [partner_tree[partner.id] for partner in message.partner_ids if partner.id in partner_tree] else: partner_ids = [partner_tree[partner.id] for partner in message.partner_ids if partner.id in partner_tree] attachment_ids = [] for attachment in message.attachment_ids: if attachment.id in attachments_tree: attachment_ids.append(attachments_tree[attachment.id]) tracking_value_ids = [] for tracking_value in message.tracking_value_ids: if tracking_value.id in tracking_tree: tracking_value_ids.append(tracking_tree[tracking_value.id]) message_dict.update({ 'author_id': author, 'partner_ids': partner_ids, 'attachment_ids': attachment_ids, 'tracking_value_ids': tracking_value_ids, }) body_short = tools.html_email_clean(message_dict['body'], shorten=True, remove=True) message_dict['body_short'] = body_short != message_dict['body'] and body_short or False return True
def _message_read_dict_postprocess(self, messages, message_tree): """ Post-processing on values given by message_read. This method will handle partners in batch to avoid doing numerous queries. :param list messages: list of message, as get_dict result :param dict message_tree: {[msg.id]: msg browse record} """ # 1. Aggregate partners (author_id and partner_ids), attachments and tracking values partners = self.env['res.partner'] attachments = self.env['ir.attachment'] message_ids = message_tree.keys() for key, message in message_tree.iteritems(): if message.author_id: partners |= message.author_id if message.subtype_id and message.partner_ids: # take notified people of message with a subtype partners |= message.partner_ids elif not message.subtype_id and message.partner_ids: # take specified people of message without a subtype (log) partners |= message.partner_ids if message.attachment_ids: attachments |= message.attachment_ids # Read partners as SUPERUSER -> display the names like classic m2o even if no access partners_names = partners.sudo().name_get() partner_tree = dict((partner[0], partner) for partner in partners_names) # 2. Attachments as SUPERUSER, because could receive msg and attachments for doc uid cannot see attachments_data = attachments.sudo().read(['id', 'datas_fname', 'name', 'mimetype']) attachments_tree = dict((attachment['id'], { 'id': attachment['id'], 'filename': attachment['datas_fname'], 'name': attachment['name'], 'mimetype': attachment['mimetype'], }) for attachment in attachments_data) # 3. Tracking values tracking_values = self.env['mail.tracking.value'].sudo().search([('mail_message_id', 'in', message_ids)]) message_to_tracking = dict() tracking_tree = dict.fromkeys(tracking_values.ids, False) for tracking in tracking_values: message_to_tracking.setdefault(tracking.mail_message_id.id, list()).append(tracking.id) tracking_tree[tracking.id] = { 'id': tracking.id, 'changed_field': tracking.field_desc, 'old_value': tracking.get_old_display_value()[0], 'new_value': tracking.get_new_display_value()[0], 'field_type': tracking.field_type, } # 4. Update message dictionaries for message_dict in messages: message_id = message_dict.get('id') message = message_tree[message_id] if message.author_id: author = partner_tree[message.author_id.id] else: author = (0, message.email_from) partner_ids = [] if message.subtype_id: partner_ids = [partner_tree[partner.id] for partner in message.partner_ids if partner.id in partner_tree] else: partner_ids = [partner_tree[partner.id] for partner in message.partner_ids if partner.id in partner_tree] attachment_ids = [] for attachment in message.attachment_ids: if attachment.id in attachments_tree: attachment_ids.append(attachments_tree[attachment.id]) tracking_value_ids = [] for tracking_value_id in message_to_tracking.get(message_id, list()): if tracking_value_id in tracking_tree: tracking_value_ids.append(tracking_tree[tracking_value_id]) message_dict.update({ 'author_id': author, 'partner_ids': partner_ids, 'attachment_ids': attachment_ids, 'tracking_value_ids': tracking_value_ids, }) body_short = tools.html_email_clean(message_dict['body'], shorten=True, remove=True) message_dict['body'] = tools.html_email_clean(message_dict['body'], shorten=False, remove=False) message_dict['body_short'] = body_short != message_dict['body'] and body_short or False return True
def test_05_shorten(self): # TEST: shorten length test_str = '''<div> <span> </span> <p>Hello, <span>Raoul</span> <bold>You</bold> are pretty</p> <span>Really</span> </div> ''' # shorten at 'H' of Hello -> should shorten after Hello, html = html_email_clean(test_str, shorten=True, max_length=1, remove=True) self.assertIn('Hello,', html, 'html_email_cleaner: shorten error or too short') self.assertNotIn('Raoul', html, 'html_email_cleaner: shorten error or too long') self.assertIn( 'read more', html, 'html_email_cleaner: shorten error about read more inclusion') # shorten at 'are' -> should shorten after are html = html_email_clean(test_str, shorten=True, max_length=17, remove=True) self.assertIn('Hello,', html, 'html_email_cleaner: shorten error or too short') self.assertIn('Raoul', html, 'html_email_cleaner: shorten error or too short') self.assertIn('are', html, 'html_email_cleaner: shorten error or too short') self.assertNotIn('pretty', html, 'html_email_cleaner: shorten error or too long') self.assertNotIn('Really', html, 'html_email_cleaner: shorten error or too long') self.assertIn( 'read more', html, 'html_email_cleaner: shorten error about read more inclusion') # TEST: shorten in quote test_str = '''<div> Blahble bluih blouh <blockquote>This is a quote <span>And this is quite a long quote, after all.</span> </blockquote> </div>''' # shorten in the quote html = html_email_clean(test_str, shorten=True, max_length=25, remove=True) self.assertIn('Blahble', html, 'html_email_cleaner: shorten error or too short') self.assertIn('bluih', html, 'html_email_cleaner: shorten error or too short') self.assertIn('blouh', html, 'html_email_cleaner: shorten error or too short') self.assertNotIn('quote', html, 'html_email_cleaner: shorten error or too long') self.assertIn( 'read more', html, 'html_email_cleaner: shorten error about read more inclusion') # shorten in second word html = html_email_clean(test_str, shorten=True, max_length=9, remove=True) self.assertIn('Blahble', html, 'html_email_cleaner: shorten error or too short') self.assertIn('bluih', html, 'html_email_cleaner: shorten error or too short') self.assertNotIn('blouh', html, 'html_email_cleaner: shorten error or too short') self.assertNotIn('quote', html, 'html_email_cleaner: shorten error or too long') self.assertIn( 'read more', html, 'html_email_cleaner: shorten error about read more inclusion') # shorten waaay too large html = html_email_clean(test_str, shorten=True, max_length=900, remove=True) self.assertIn('Blahble', html, 'html_email_cleaner: shorten error or too short') self.assertIn('bluih', html, 'html_email_cleaner: shorten error or too short') self.assertIn('blouh', html, 'html_email_cleaner: shorten error or too short') self.assertNotIn('quote', html, 'html_email_cleaner: shorten error or too long')
def test_60_email_thunderbird(self): new_html = html_email_clean(test_mail_examples.THUNDERBIRD_1, remove=True) for ext in test_mail_examples.THUNDERBIRD_1_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.THUNDERBIRD_1_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase signature / quoted content')
def test_70_read_more_and_shorten(self): expand_options = { 'oe_expand_container_class': 'span_class', 'oe_expand_container_content': 'Herbert Einstein', 'oe_expand_separator_node': 'br_lapin', 'oe_expand_a_class': 'a_class', 'oe_expand_a_content': 'read mee', } new_html = html_email_clean(test_mail_examples.OERP_WEBSITE_HTML_1, remove=True, shorten=True, max_length=100, expand_options=expand_options) for ext in test_mail_examples.OERP_WEBSITE_HTML_1_IN: self.assertIn( ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.OERP_WEBSITE_HTML_1_OUT: self.assertNotIn( ext, new_html, 'html_email_cleaner did not erase overlimit content') for ext in [ '<span class="span_class">Herbert Einstein<br_lapin></br_lapin><a href="#" class="a_class">read mee</a></span>' ]: self.assertIn( ext, new_html, 'html_email_cleaner wrongly take into account specific expand options' ) new_html = html_email_clean(test_mail_examples.OERP_WEBSITE_HTML_2, remove=True, shorten=True, max_length=200, expand_options=expand_options, protect_sections=False) for ext in test_mail_examples.OERP_WEBSITE_HTML_2_IN: self.assertIn( ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.OERP_WEBSITE_HTML_2_OUT: self.assertNotIn( ext, new_html, 'html_email_cleaner did not erase overlimit content') for ext in [ '<span class="span_class">Herbert Einstein<br_lapin></br_lapin><a href="#" class="a_class">read mee</a></span>' ]: self.assertIn( ext, new_html, 'html_email_cleaner wrongly take into account specific expand options' ) new_html = html_email_clean(test_mail_examples.OERP_WEBSITE_HTML_2, remove=True, shorten=True, max_length=200, expand_options=expand_options, protect_sections=True) for ext in test_mail_examples.OERP_WEBSITE_HTML_2_IN: self.assertIn( ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.OERP_WEBSITE_HTML_2_OUT: self.assertNotIn( ext, new_html, 'html_email_cleaner did not erase overlimit content') for ext in [ '<span class="span_class">Herbert Einstein<br_lapin></br_lapin><a href="#" class="a_class">read mee</a></span>', 'tasks using the gantt chart and control deadlines' ]: self.assertIn( ext, new_html, 'html_email_cleaner wrongly take into account specific expand options' )
def test_50_email_gmail(self): new_html = html_email_clean(test_mail_examples.GMAIL_1, remove=True) for ext in test_mail_examples.GMAIL_1_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed not quoted content') for ext in test_mail_examples.GMAIL_1_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not erase signature / quoted content')
def test_50_email_gmail(self): new_html = html_email_clean(test_mail_examples.GMAIL_1, remove=True) for ext in test_mail_examples.GMAIL_1_IN: self.assertIn(ext, new_html, "html_email_cleaner wrongly removed not quoted content") for ext in test_mail_examples.GMAIL_1_OUT: self.assertNotIn(ext, new_html, "html_email_cleaner did not erase signature / quoted content")
def test_80_remove_classes(self): new_html = html_email_clean(test_mail_examples.REMOVE_CLASS, remove=True) for ext in test_mail_examples.REMOVE_CLASS_IN: self.assertIn(ext, new_html, 'html_email_cleaner wrongly removed classes') for ext in test_mail_examples.REMOVE_CLASS_OUT: self.assertNotIn(ext, new_html, 'html_email_cleaner did not removed correctly unwanted classes')