diff options
| author | Christophe Simonis <chs@odoo.com> | 2019-04-12 13:37:44 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2019-04-12 13:37:44 +0200 |
| commit | 0a09a4d8a819ef06db47e798f0465e500004e4c1 (patch) | |
| tree | b9d66d60a1e9b5ff6030be62fff89df410b744ee /addons/mail | |
| parent | db97bb7f1136dc3ebde9924b79364a698a63765d (diff) | |
| parent | 120359bf0c98191051ac19ae2e5fde53ca7d2ae5 (diff) | |
[MERGE] forward port branch saas-12.3 up to 120359bf0c9
Diffstat (limited to 'addons/mail')
| -rw-r--r-- | addons/mail/models/ir_attachment.py | 7 | ||||
| -rw-r--r-- | addons/mail/models/mail_mail.py | 18 | ||||
| -rw-r--r-- | addons/mail/models/mail_message.py | 4 | ||||
| -rw-r--r-- | addons/mail/models/mail_thread.py | 2 | ||||
| -rw-r--r-- | addons/mail/static/src/js/chatter.js | 4 | ||||
| -rw-r--r-- | addons/mail/static/src/js/document_viewer.js | 5 | ||||
| -rw-r--r-- | addons/mail/static/src/scss/chatter.scss | 21 | ||||
| -rw-r--r-- | addons/mail/static/src/scss/composer.scss | 3 | ||||
| -rw-r--r-- | addons/mail/static/src/xml/thread.xml | 20 | ||||
| -rw-r--r-- | addons/mail/static/tests/document_viewer_tests.js | 19 |
10 files changed, 72 insertions, 31 deletions
diff --git a/addons/mail/models/ir_attachment.py b/addons/mail/models/ir_attachment.py index 31e59d680c9..7273145096d 100644 --- a/addons/mail/models/ir_attachment.py +++ b/addons/mail/models/ir_attachment.py @@ -13,9 +13,9 @@ class IrAttachment(models.Model): """ super(IrAttachment, self)._post_add_create() for record in self: - record.register_as_main_attachment() + record.register_as_main_attachment(force=False) - def register_as_main_attachment(self): + def register_as_main_attachment(self, force=True): """ Registers this attachment as the main one of the model it is attached to. """ @@ -24,4 +24,5 @@ class IrAttachment(models.Model): # message_main_attachment_id field can be empty, that's why we compare to False; # we are just checking that it exists on the model before writing it if related_record and hasattr(related_record, 'message_main_attachment_id'): - related_record.message_main_attachment_id = self + if force or not related_record.message_main_attachment_id: + related_record.message_main_attachment_id = self diff --git a/addons/mail/models/mail_mail.py b/addons/mail/models/mail_mail.py index 7aff20cf59e..a2ba820656f 100644 --- a/addons/mail/models/mail_mail.py +++ b/addons/mail/models/mail_mail.py @@ -5,6 +5,7 @@ import base64 import datetime import logging import psycopg2 +import smtplib import threading import re @@ -162,14 +163,14 @@ class MailMail(models.Model): failed = self.env['mail.notification'] if failure_type: failed = notifications.filtered(lambda notif: notif.res_partner_id not in success_pids) - failed.write({ + failed.sudo().write({ 'email_status': 'exception', 'failure_type': failure_type, 'failure_reason': failure_reason, }) messages = notifications.mapped('mail_message_id').filtered(lambda m: m.res_id and m.model) messages._notify_failure_update() # notify user that we have a failure - (notifications - failed).write({ + (notifications - failed).sudo().write({ 'email_status': 'sent', }) if not failure_type or failure_type == 'RECIPIENT': # if we have another error, we want to keep the mail. @@ -338,7 +339,7 @@ class MailMail(models.Model): ]) if notifs: notif_msg = _('Error without exception. Probably due do concurrent access update of notification records. Please see with an administrator.') - notifs.write({ + notifs.sudo().write({ 'email_status': 'exception', 'failure_type': 'UNKNOWN', 'failure_reason': notif_msg, @@ -394,11 +395,12 @@ class MailMail(models.Model): mail.id, mail.message_id) # mail status will stay on ongoing since transaction will be rollback raise - except psycopg2.Error: - # If an error with the database occurs, chances are that the cursor is unusable. - # This will lead to an `psycopg2.InternalError` being raised when trying to write - # `state`, shadowing the original exception and forbid a retry on concurrent - # update. Let's bubble it. + except (psycopg2.Error, smtplib.SMTPServerDisconnected): + # If an error with the database or SMTP session occurs, chances are that the cursor + # or SMTP session are unusable, causing further errors when trying to save the state. + _logger.exception( + 'Exception while processing mail with ID %r and Msg-Id %r.', + mail.id, mail.message_id) raise except Exception as e: failure_reason = tools.ustr(e) diff --git a/addons/mail/models/mail_message.py b/addons/mail/models/mail_message.py index e228f7c4062..e2ebb16c69e 100644 --- a/addons/mail/models/mail_message.py +++ b/addons/mail/models/mail_message.py @@ -154,8 +154,8 @@ class Message(models.Model): @api.multi def _search_has_error(self, operator, operand): if operator == '=' and operand: - return ['&', ('notification_ids.email_status', 'in', ('bounce', 'exception')), ('author_id', '=', self.env.user.partner_id.id)] - return ['!', '&', ('notification_ids.email_status', 'in', ('bounce', 'exception')), ('author_id', '=', self.env.user.partner_id.id)] # this wont work and will be equivalent to "not in" beacause of orm restrictions. Dont use "has_error = False" + return [('notification_ids.email_status', 'in', ('bounce', 'exception'))] + return ['!', ('notification_ids.email_status', 'in', ('bounce', 'exception'))] # this wont work and will be equivalent to "not in" beacause of orm restrictions. Dont use "has_error = False" @api.depends('starred_partner_ids') def _get_starred(self): diff --git a/addons/mail/models/mail_thread.py b/addons/mail/models/mail_thread.py index 127b7f7d609..81f1dc0510b 100644 --- a/addons/mail/models/mail_thread.py +++ b/addons/mail/models/mail_thread.py @@ -237,7 +237,7 @@ class MailThread(models.AbstractModel): @api.model def _search_message_has_error(self, operator, operand): - return [('message_ids.has_error', operator, operand)] + return ['&', ('message_ids.has_error', operator, operand), ('message_ids.author_id', '=', self.env.user.partner_id.id)] @api.multi def _compute_message_attachment_count(self): diff --git a/addons/mail/static/src/js/chatter.js b/addons/mail/static/src/js/chatter.js index bc5d18a4150..968242ffe6a 100644 --- a/addons/mail/static/src/js/chatter.js +++ b/addons/mail/static/src/js/chatter.js @@ -81,6 +81,7 @@ var Chatter = Widget.extend({ var nodeOptions = fieldsInfo[mailFields.mail_thread].options || {}; this.hasLogButton = options.display_log_button || nodeOptions.display_log_button; this.postRefresh = nodeOptions.post_refresh || 'never'; + this.reloadOnUploadAttachment = this.postRefresh === 'always'; } }, /** @@ -577,6 +578,9 @@ var Chatter = Widget.extend({ * @private */ _onReloadAttachmentBox: function () { + if (this.reloadOnUploadAttachment) { + this.trigger_up('reload'); + } this._reloadAttachmentBox(); }, /** diff --git a/addons/mail/static/src/js/document_viewer.js b/addons/mail/static/src/js/document_viewer.js index fc084b48204..be7dfeb9115 100644 --- a/addons/mail/static/src/js/document_viewer.js +++ b/addons/mail/static/src/js/document_viewer.js @@ -44,11 +44,10 @@ var DocumentViewer = Widget.extend({ this._super.apply(this, arguments); this.attachment = _.filter(attachments, function (attachment) { var match = attachment.type === 'url' ? attachment.url.match("(youtu|.png|.jpg|.gif)") : attachment.mimetype.match("(image|video|application/pdf|text)"); - if (match) { - attachment.type = match[1]; + attachment.fileType = match[1]; if (match[1].match("(.png|.jpg|.gif)")) { - attachment.type = 'image'; + attachment.fileType = 'image'; } if (match[1] === 'youtu') { var youtube_array = attachment.url.split('/'); diff --git a/addons/mail/static/src/scss/chatter.scss b/addons/mail/static/src/scss/chatter.scss index b670e5b92d0..5b503966706 100644 --- a/addons/mail/static/src/scss/chatter.scss +++ b/addons/mail/static/src/scss/chatter.scss @@ -21,11 +21,11 @@ position: relative; float: right; flex: 1 1 auto; + height: $o-statusbar-height; .o_chatter_button_attachment { - height: $o-statusbar-height - 2px; + height: $o-statusbar-height; float: right; - padding: 0px; margin-right: 25px; .fa-paperclip, .o_chatter_attachment_button_count { @@ -33,15 +33,20 @@ } } .o_followers { - height: $o-statusbar-height + 1; + height: $o-statusbar-height; border-bottom: 1px solid transparent; flex: 0 1 auto; } } > .btn { - height: $o-statusbar-height + 1; + height: $o-statusbar-height; border: 1px solid transparent; } + .btn { + @extend .text-nowrap; + padding-right: $btn-padding-x; + padding-left: $btn-padding-x; + } } @@ -60,3 +65,11 @@ } } } + +@include media-breakpoint-down(sm) { + .o_chatter .o_chatter_topbar > .o_topbar_right_area { + .o_chatter_button_attachment { + margin-right: initial; + } + } +} diff --git a/addons/mail/static/src/scss/composer.scss b/addons/mail/static/src/scss/composer.scss index e7f7eb98d3b..75c62bbeae0 100644 --- a/addons/mail/static/src/scss/composer.scss +++ b/addons/mail/static/src/scss/composer.scss @@ -142,6 +142,9 @@ &:not(.o_chat_inline_composer) { flex-flow: row wrap; + .o_composer_container { + max-width: 100%; + } .o_composer_container, .o_composer_button_send { flex: 1 0 100%; } diff --git a/addons/mail/static/src/xml/thread.xml b/addons/mail/static/src/xml/thread.xml index 9f490bba0b5..2a5fd7ee30b 100644 --- a/addons/mail/static/src/xml/thread.xml +++ b/addons/mail/static/src/xml/thread.xml @@ -38,9 +38,9 @@ <t t-set="model" t-value="widget.modelName"/> <div class="o_viewer-header"> <span class="o_image_caption"> - <i class="fa fa-picture-o mr8" t-if="widget.activeAttachment.type == 'image'" role="img" aria-label="Image" title="Image"/> - <i class="fa fa-file-text mr8" t-if="widget.activeAttachment.type == 'application/pdf'" role="img" aria-label="PDF file" title="PDF file"/> - <i class="fa fa-video-camera mr8" t-if="widget.activeAttachment.type == 'video'" role="img" aria-label="Video" title="Video"/> + <i class="fa fa-picture-o mr8" t-if="widget.activeAttachment.fileType == 'image'" role="img" aria-label="Image" title="Image"/> + <i class="fa fa-file-text mr8" t-if="widget.activeAttachment.fileType == 'application/pdf'" role="img" aria-label="PDF file" title="PDF file"/> + <i class="fa fa-video-camera mr8" t-if="widget.activeAttachment.fileType == 'video'" role="img" aria-label="Video" title="Video"/> <t t-esc="widget.activeAttachment.name"/> <a role="button" href="#" class="o_download_btn ml8 small" data-toggle="tooltip" data-placement="right" title="Download"><i class="fa fa-fw fa-download" role="img" aria-label="Download"/></a> </span> @@ -48,19 +48,19 @@ </div> <div class="o_viewer_img_wrapper"> <div class="o_viewer_zoomer"> - <div t-if="widget.activeAttachment.type == 'image'" class="o_loading_img text-center"> + <div t-if="widget.activeAttachment.fileType == 'image'" class="o_loading_img text-center"> <i class="fa fa-circle-o-notch fa-spin text-gray-light fa-3x fa-fw" role="img" aria-label="Loading" title="Loading"/> </div> - <img t-if="widget.activeAttachment.type === 'image'" class="o_viewer_img" t-attf-src="/web/image/#{widget.activeAttachment.id}?unique=1&signature=#{widget.activeAttachment.checksum}&model=#{model}" alt="Viewer"/> - <iframe t-if="widget.activeAttachment.type == 'application/pdf'" class="mt32 o_viewer_pdf" t-attf-src="/web/static/lib/pdfjs/web/viewer.html?file=/web/content/#{widget.activeAttachment.id}?model%3D#{model}" /> - <iframe t-if="(widget.activeAttachment.type || '').indexOf('text') !== -1" class="mt32 o_viewer_text" t-attf-src="/web/content/#{widget.activeAttachment.id}?model%3D#{model}" /> - <iframe t-if="widget.activeAttachment.type == 'youtu'" class="mt32 o_viewer_text" allow="autoplay; encrypted-media" width="560" height="315" t-attf-src="https://www.youtube.com/embed/#{widget.activeAttachment.youtube}"/> - <video t-if="widget.activeAttachment.type == 'video'" class="o_viewer_video" controls="controls"> + <img t-if="widget.activeAttachment.fileType === 'image'" class="o_viewer_img" t-attf-src="/web/image/#{widget.activeAttachment.id}?unique=1&signature=#{widget.activeAttachment.checksum}&model=#{model}" alt="Viewer"/> + <iframe t-if="widget.activeAttachment.fileType == 'application/pdf'" class="mt32 o_viewer_pdf" t-attf-src="/web/static/lib/pdfjs/web/viewer.html?file=/web/content/#{widget.activeAttachment.id}?model%3D#{model}" /> + <iframe t-if="(widget.activeAttachment.fileType || '').indexOf('text') !== -1" class="mt32 o_viewer_text" t-attf-src="/web/content/#{widget.activeAttachment.id}?model%3D#{model}" /> + <iframe t-if="widget.activeAttachment.fileType == 'youtu'" class="mt32 o_viewer_text" allow="autoplay; encrypted-media" width="560" height="315" t-attf-src="https://www.youtube.com/embed/#{widget.activeAttachment.youtube}"/> + <video t-if="widget.activeAttachment.fileType == 'video'" class="o_viewer_video" controls="controls"> <source t-attf-src="/web/image/#{widget.activeAttachment.id}?model=#{model}" t-att-data-type="widget.activeAttachment.mimetype"/> </video> </div> </div> - <div t-if="widget.activeAttachment.type == 'image'" class="o_viewer_toolbar btn-toolbar" role="toolbar"> + <div t-if="widget.activeAttachment.fileType == 'image'" class="o_viewer_toolbar btn-toolbar" role="toolbar"> <div class="btn-group ml0" role="group"> <a role="button" href="#" class="o_viewer_toolbar_btn btn o_zoom_in" data-toggle="tooltip" title="Zoom In"><i class="fa fa-fw fa-plus" role="img" aria-label="Zoom In"/></a> <a role="button" href="#" class="o_viewer_toolbar_btn btn o_zoom_reset disabled" data-toggle="tooltip" title="Reset Zoom"><i class="fa fa-fw fa-search" role="img" aria-label="Reset Zoom"/></a> diff --git a/addons/mail/static/tests/document_viewer_tests.js b/addons/mail/static/tests/document_viewer_tests.js index 5d3dcf7069f..b5748ab72ee 100644 --- a/addons/mail/static/tests/document_viewer_tests.js +++ b/addons/mail/static/tests/document_viewer_tests.js @@ -207,5 +207,24 @@ QUnit.module('DocumentViewer', { assert.ok(viewer.isDestroyed(), 'viewer should be destroyed'); }); + + QUnit.test('fileType and integrity test', async function (assert) { + assert.expect(3); + + var viewer = await createViewer({ + attachmentID: 2, + attachments: this.attachments, + }); + + assert.strictEqual(this.attachments[1].type, 'url', + "the type should be url"); + assert.strictEqual(this.attachments[1].fileType, 'youtu', + "there should be a fileType 'youtu'"); + assert.strictEqual(this.attachments[1].youtube, 'FYqW0Gdwbzk', + "there should be a youtube token"); + + viewer.destroy(); + }); + }); }); |
