diff --git a/mail_drop_target/README.rst b/mail_drop_target/README.rst new file mode 100644 index 000000000..57dd02683 --- /dev/null +++ b/mail_drop_target/README.rst @@ -0,0 +1,114 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +========================== +Drag & drop emails to Odoo +========================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:85f4a6f39edb713ec1bd1513532b8f903b033bf76662c64946375473b5d5c119 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fmail-lightgray.png?logo=github + :target: https://github.com/OCA/mail/tree/19.0/mail_drop_target + :alt: OCA/mail +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/mail-19-0/mail-19-0-mail_drop_target + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/mail&target_branch=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module was written to allow users to drag&drop emails from their +desktop to Odoo. + +It supports as well RFC822 .eml files as Outlook .msg (those only if `an +extra library `__ is +installed) files. + +When the mail is dropped to an odoo record, it will automatically send a +notification of that new message that has been added to all the existing +followers. It is possible to disable this notification. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module, you need to: + +1. save your emails on the desktop / somewhere in the file system +2. drag them to your browser, and drop them on the chatter of the record + you want to attach your email to + +Known issues / Roadmap +====================== + +- most mail clients won't allow you to drag mails directly from the mail + client, you'll need some plugin for that +- for corporate environments, it might be feasible to support imap URLs + and get the mail in question on the server side + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Therp BV + +Contributors +------------ + +- Holger Brunn +- Enric Tobella +- Lois Rilo +- Nguyen Minh Chien + +Other credits +------------- + + + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/mail `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/mail_drop_target/__init__.py b/mail_drop_target/__init__.py new file mode 100644 index 000000000..9484ea350 --- /dev/null +++ b/mail_drop_target/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import controllers +from . import models diff --git a/mail_drop_target/__manifest__.py b/mail_drop_target/__manifest__.py new file mode 100644 index 000000000..6b3be407a --- /dev/null +++ b/mail_drop_target/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +{ + "name": "Drag & drop emails to Odoo", + "version": "19.0.1.0.1", + "author": "Therp BV,Odoo Community Association (OCA)", + "license": "AGPL-3", + "category": "Discuss", + "website": "https://github.com/OCA/mail", + "summary": "Attach emails to Odoo by dragging them from your desktop", + "depends": ["mail"], + "external_dependencies": {"python": ["extract_msg"]}, + "data": ["views/res_config_settings_views.xml"], + "assets": { + "web.assets_backend": [ + "mail_drop_target/static/src/js/file_uploader.esm.js", + ], + }, +} diff --git a/mail_drop_target/controllers/__init__.py b/mail_drop_target/controllers/__init__.py new file mode 100644 index 000000000..636ed8add --- /dev/null +++ b/mail_drop_target/controllers/__init__.py @@ -0,0 +1,3 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import discuss diff --git a/mail_drop_target/controllers/discuss.py b/mail_drop_target/controllers/discuss.py new file mode 100644 index 000000000..9bf47864e --- /dev/null +++ b/mail_drop_target/controllers/discuss.py @@ -0,0 +1,49 @@ +# Copyright Nguyen Minh Chien (chien@trobz.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import http +from odoo.exceptions import AccessError, UserError +from odoo.http import request + +from odoo.addons.mail.controllers import attachment + + +class AttachmentController(attachment.AttachmentController): + @http.route("/mail/attachment/upload", methods=["POST"], type="http", auth="public") + def mail_attachment_upload( + self, ufile, thread_id, thread_model, is_pending=False, **kwargs + ): + if not is_pending or is_pending == "false": + # Add this point, make sure the message related to the uploaded + # file does exist. + resp = self.mail_attachment_upload_email(ufile, thread_id, thread_model) + if resp: + return resp + + return super().mail_attachment_upload( + ufile, thread_id, thread_model, is_pending, **kwargs + ) + + def mail_attachment_upload_email(self, ufile, thread_id, thread_model): + channel_member = request.env["discuss.channel.member"] + if thread_model == "discuss.channel": + channel_member = request.env[ + "discuss.channel.member" + ]._get_as_sudo_from_request_or_raise( + request=request, channel_id=int(thread_id) + ) + try: + mail_resp = channel_member.env["ir.attachment"].read_mail_file_content( + ufile.filename, ufile.read(), int(thread_id), thread_model + ) + ufile.seek(0) + if not mail_resp: + return False + responseData = {"email_upload": 1} + except AccessError: + responseData = { + "error": self.env._("You are not allowed to upload an attachment here.") + } + except UserError as err: + responseData = {"error": str(err)} + return request.make_json_response(responseData) diff --git a/mail_drop_target/i18n/it.po b/mail_drop_target/i18n/it.po new file mode 100644 index 000000000..b629c7912 --- /dev/null +++ b/mail_drop_target/i18n/it.po @@ -0,0 +1,83 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * mail_drop_target +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-02-26 16:34+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: mail_drop_target +#: model:ir.model,name:mail_drop_target.model_ir_attachment +msgid "Attachment" +msgstr "Allegato" + +#. module: mail_drop_target +#: model:ir.model,name:mail_drop_target.model_res_config_settings +msgid "Config Settings" +msgstr "Impostazioni configurazione" + +#. module: mail_drop_target +#: model_terms:ir.ui.view,arch_db:mail_drop_target.res_config_settings_view_form +msgid "Disable Mail Drag&Drop Notification" +msgstr "Disabilita notifica e-mail trascina&rilascia" + +#. module: mail_drop_target +#: model:ir.model.fields,field_description:mail_drop_target.field_res_config_settings__disable_notify_mail_drop_target +msgid "Disable Notification followers on mail dropped to a Thread" +msgstr "Disabilita notifica chi segue per e-mail inserita in una discussione" + +#. module: mail_drop_target +#: model:ir.model,name:mail_drop_target.model_mail_thread +msgid "Email Thread" +msgstr "Discussione e-mail" + +#. module: mail_drop_target +#. odoo-python +#: code:addons/mail_drop_target/models/mail_thread.py:0 +#, python-format +msgid "Install the msg-extractor library to handle .msg files" +msgstr "Installare la libreria msg-extractor per festire i file .msg" + +#. module: mail_drop_target +#. odoo-python +#: code:addons/mail_drop_target/models/mail_thread.py:0 +#, python-format +msgid "This message is already imported." +msgstr "Questo messaggio è già stato importato." + +#. module: mail_drop_target +#: model_terms:ir.ui.view,arch_db:mail_drop_target.res_config_settings_view_form +msgid "" +"When a user drops an email into an existing thread\n" +" the followers of the thread will not be notified." +msgstr "" +"Quando un utente rilascia una e-mail in una discussione esistente\n" +" chi segue la discussione non verrà avvisato." + +#. module: mail_drop_target +#: model:ir.model.fields,help:mail_drop_target.field_res_config_settings__disable_notify_mail_drop_target +msgid "" +"When this setting is set, when a user drops an email into an existing thread" +" the followers of the thread will not be notified. This sets an " +"ir.config.parameter mail_drop_target.disable_notify" +msgstr "" +"Quanto è attiva questa impostazione, quando un utente rilascia una e.mail in " +"una discussione esistente, chi segue la discussione non verrà avvisato. " +"Questo imposta un ir.config.parameter in mail_drop_target.disable_notify" + +#. module: mail_drop_target +#. odoo-python +#: code:addons/mail_drop_target/controllers/discuss.py:0 +#, python-format +msgid "You are not allowed to upload an attachment here." +msgstr "Non si ha l'autorizzazione per caricare qui un allegato." diff --git a/mail_drop_target/i18n/mail_drop_target.pot b/mail_drop_target/i18n/mail_drop_target.pot new file mode 100644 index 000000000..d7eeef933 --- /dev/null +++ b/mail_drop_target/i18n/mail_drop_target.pot @@ -0,0 +1,72 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * mail_drop_target +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: mail_drop_target +#: model:ir.model,name:mail_drop_target.model_ir_attachment +msgid "Attachment" +msgstr "" + +#. module: mail_drop_target +#: model:ir.model,name:mail_drop_target.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: mail_drop_target +#: model_terms:ir.ui.view,arch_db:mail_drop_target.res_config_settings_view_form +msgid "Disable Mail Drag&Drop Notification" +msgstr "" + +#. module: mail_drop_target +#: model:ir.model.fields,field_description:mail_drop_target.field_res_config_settings__disable_notify_mail_drop_target +msgid "Disable Notification followers on mail dropped to a Thread" +msgstr "" + +#. module: mail_drop_target +#: model:ir.model,name:mail_drop_target.model_mail_thread +msgid "Email Thread" +msgstr "" + +#. module: mail_drop_target +#. odoo-python +#: code:addons/mail_drop_target/models/mail_thread.py:0 +msgid "Install the msg-extractor library to handle .msg files" +msgstr "" + +#. module: mail_drop_target +#. odoo-python +#: code:addons/mail_drop_target/models/mail_thread.py:0 +msgid "This message is already imported." +msgstr "" + +#. module: mail_drop_target +#: model_terms:ir.ui.view,arch_db:mail_drop_target.res_config_settings_view_form +msgid "" +"When a user drops an email into an existing thread\n" +" the followers of the thread will not be notified." +msgstr "" + +#. module: mail_drop_target +#: model:ir.model.fields,help:mail_drop_target.field_res_config_settings__disable_notify_mail_drop_target +msgid "" +"When this setting is set, when a user drops an email into an existing thread" +" the followers of the thread will not be notified. This sets an " +"ir.config.parameter mail_drop_target.disable_notify" +msgstr "" + +#. module: mail_drop_target +#. odoo-python +#: code:addons/mail_drop_target/controllers/discuss.py:0 +msgid "You are not allowed to upload an attachment here." +msgstr "" diff --git a/mail_drop_target/models/__init__.py b/mail_drop_target/models/__init__.py new file mode 100644 index 000000000..98fd6d1ef --- /dev/null +++ b/mail_drop_target/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from . import ir_attachment +from . import mail_thread +from . import res_config_settings diff --git a/mail_drop_target/models/ir_attachment.py b/mail_drop_target/models/ir_attachment.py new file mode 100644 index 000000000..9807cb799 --- /dev/null +++ b/mail_drop_target/models/ir_attachment.py @@ -0,0 +1,49 @@ +# Copyright Nguyen Minh Chien (chien@trobz.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +import base64 +import os + +from odoo import api, models + + +class IrAttachment(models.Model): + _inherit = "ir.attachment" + + def _get_email_file_extensions(self): + return ["msg", "eml"] + + def _process_email_file_msg(self, res_obj, raw_content): + if not hasattr(res_obj, "message_process_msg"): + return False + message = base64.b64encode(raw_content) + thread_id = res_obj.message_process_msg( + res_obj._name, message, thread_id=res_obj.id + ) + return thread_id + + @api.model + def _process_email_file_default(self, res_obj, raw_content): + if not hasattr(res_obj, "message_drop"): + return False + message = raw_content + thread_id = res_obj.message_drop(res_obj._name, message, thread_id=res_obj.id) + return thread_id + + def read_mail_file_content(self, file_name, raw_content, res_id, res_model): + file_extensions = self._get_email_file_extensions() + name_lst = os.path.splitext(file_name) + file_extension = name_lst[-1].lower().replace(".", "") + if not file_extension or file_extension not in file_extensions: + return False + + res_obj = self.env[res_model].browse(res_id) + if not res_obj: + return False + + handler = f"_process_email_file_{file_extension}" + if not hasattr(self, handler): + handler = "_process_email_file_default" + + res = getattr(self, handler)(res_obj, raw_content) + return res diff --git a/mail_drop_target/models/mail_thread.py b/mail_drop_target/models/mail_thread.py new file mode 100644 index 000000000..aa7c5a900 --- /dev/null +++ b/mail_drop_target/models/mail_thread.py @@ -0,0 +1,161 @@ +# Copyright 2018 Therp BV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from base64 import b64decode + +import chardet +import lxml.html + +from odoo import api, exceptions, models + +try: + from extract_msg import Message +except ImportError: + Message = None + + +class MailThread(models.AbstractModel): + _inherit = "mail.thread" + + @api.model + def message_drop( + self, + model, + message, + custom_values=None, + save_original=False, + strip_attachments=False, + thread_id=None, + ): + disable_notify_mail_drop_target = ( + self.env["ir.config_parameter"] + .sudo() + .get_param("mail_drop_target.disable_notify", default=False) + ) + self_message_process = self + if disable_notify_mail_drop_target: + self_message_process = self_message_process.with_context( + message_create_from_mail_mail=True + ) + result = self_message_process.message_process( + model, + message, + custom_values=custom_values, + save_original=save_original, + strip_attachments=strip_attachments, + thread_id=thread_id, + ) + if not result: + return self.message_drop_existing( + model, + message, + custom_values=custom_values, + save_original=save_original, + strip_attachments=strip_attachments, + thread_id=thread_id, + ) + return result + + @api.model + def message_drop_existing( + self, + model, + message, + custom_values=None, + save_original=False, + strip_attachments=False, + thread_id=None, + ): + message = self.env._("This message is already imported.") + raise exceptions.UserError(message) + + @api.model + def message_process_msg( + self, + model, + message, + custom_values=None, + save_original=False, + strip_attachments=False, + thread_id=None, + ): + """Convert message to RFC2822 and pass to message_process""" + if not Message: + raise exceptions.UserError( + self.env._("Install the msg-extractor library to handle .msg files") + ) + message_msg = Message(b64decode(message)) + try: + message_id = message_msg.messageId + except AttributeError: + # Using extract_msg < 0.24.4 + message_id = message_msg.message_id + msg_body = message_msg.htmlBody or message_msg.body + if isinstance(msg_body, bytes): + detection = chardet.detect(msg_body) + encoding = detection.get("encoding") + msg_body = msg_body.decode(encoding) + + subtype = ( + lxml.html.fromstring(msg_body).find(".//*") is not None + and "html" + or "plain" + ) + + message_email = self.env["ir.mail_server"].build_email( + message_msg.sender, + message_msg.to.split(","), + message_msg.subject, + # prefer html bodies to text + msg_body, + email_cc=message_msg.cc, + message_id=message_id.strip(), + attachments=[ + (attachment.longFilename, attachment.data, attachment.mimetype) + for attachment in message_msg.attachments + ], + subtype=subtype, + ) + # We need to override message date, as an error rises when processing it + # directly with headers + del message_email["date"] + message_email["date"] = message_msg.date + return self.message_drop( + model, + message_email.as_string(), + custom_values=custom_values, + save_original=save_original, + strip_attachments=strip_attachments, + thread_id=thread_id, + ) + + def _notify_thread_by_email( + self, + message, + recipients_data, + msg_vals=False, + mail_auto_delete=True, # mail.mail + model_description=False, + force_email_company=False, + force_email_lang=False, # rendering + resend_existing=False, + force_send=True, + send_after_commit=True, # email send + subtitles=None, + **kwargs, + ): + if self.env.context.get("message_create_from_mail_mail", False): + return + return super()._notify_thread_by_email( + message, + recipients_data, + msg_vals=msg_vals, + mail_auto_delete=mail_auto_delete, + model_description=model_description, + force_email_company=force_email_company, + force_email_lang=force_email_lang, + resend_existing=resend_existing, + force_send=force_send, + send_after_commit=send_after_commit, + subtitles=subtitles, + **kwargs, + ) diff --git a/mail_drop_target/models/res_config_settings.py b/mail_drop_target/models/res_config_settings.py new file mode 100644 index 000000000..6122fb002 --- /dev/null +++ b/mail_drop_target/models/res_config_settings.py @@ -0,0 +1,17 @@ +# Copyright 2019-20 ForgeFlow S.L. (https://www.forgeflow.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + disable_notify_mail_drop_target = fields.Boolean( + "Disable Notification followers on mail dropped to a Thread", + config_parameter="mail_drop_target.disable_notify", + help="When this setting is set, when a user drops an " + "email into an existing thread the followers of the thread will " + "not be notified. This sets an ir.config.parameter " + "mail_drop_target.disable_notify", + ) diff --git a/mail_drop_target/pyproject.toml b/mail_drop_target/pyproject.toml new file mode 100644 index 000000000..4231d0ccc --- /dev/null +++ b/mail_drop_target/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/mail_drop_target/readme/CONFIGURATION.rst b/mail_drop_target/readme/CONFIGURATION.rst new file mode 100644 index 000000000..79e2eb7b3 --- /dev/null +++ b/mail_drop_target/readme/CONFIGURATION.rst @@ -0,0 +1,3 @@ +To disable the automatic notification to existing followers when you drop an +email to a record, go to *Settings*, activate the developer mode, and then go to +*Settings / General Settings* and set the flag 'Disable Mail Drag&Drop Notification'. diff --git a/mail_drop_target/readme/CONTRIBUTORS.md b/mail_drop_target/readme/CONTRIBUTORS.md new file mode 100644 index 000000000..606ac2b2b --- /dev/null +++ b/mail_drop_target/readme/CONTRIBUTORS.md @@ -0,0 +1,4 @@ +- Holger Brunn \ +- Enric Tobella \ +- Lois Rilo \ +- Nguyen Minh Chien \ diff --git a/mail_drop_target/readme/CREDITS.md b/mail_drop_target/readme/CREDITS.md new file mode 100644 index 000000000..e69de29bb diff --git a/mail_drop_target/readme/DESCRIPTION.md b/mail_drop_target/readme/DESCRIPTION.md new file mode 100644 index 000000000..c871abc30 --- /dev/null +++ b/mail_drop_target/readme/DESCRIPTION.md @@ -0,0 +1,10 @@ +This module was written to allow users to drag&drop emails from their +desktop to Odoo. + +It supports as well RFC822 .eml files as Outlook .msg (those only if [an +extra library](https://github.com/mattgwwalker/msg-extractor) is +installed) files. + +When the mail is dropped to an odoo record, it will automatically send a +notification of that new message that has been added to all the existing +followers. It is possible to disable this notification. diff --git a/mail_drop_target/readme/ROADMAP.md b/mail_drop_target/readme/ROADMAP.md new file mode 100644 index 000000000..49decb662 --- /dev/null +++ b/mail_drop_target/readme/ROADMAP.md @@ -0,0 +1,4 @@ +- most mail clients won't allow you to drag mails directly from the mail + client, you'll need some plugin for that +- for corporate environments, it might be feasible to support imap URLs + and get the mail in question on the server side diff --git a/mail_drop_target/readme/USAGE.md b/mail_drop_target/readme/USAGE.md new file mode 100644 index 000000000..20a9963db --- /dev/null +++ b/mail_drop_target/readme/USAGE.md @@ -0,0 +1,5 @@ +To use this module, you need to: + +1. save your emails on the desktop / somewhere in the file system +2. drag them to your browser, and drop them on the chatter of the + record you want to attach your email to diff --git a/mail_drop_target/static/description/icon.png b/mail_drop_target/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/mail_drop_target/static/description/icon.png differ diff --git a/mail_drop_target/static/description/index.html b/mail_drop_target/static/description/index.html new file mode 100644 index 000000000..d1666bc39 --- /dev/null +++ b/mail_drop_target/static/description/index.html @@ -0,0 +1,463 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Drag & drop emails to Odoo

+ +

Beta License: AGPL-3 OCA/mail Translate me on Weblate Try me on Runboat

+

This module was written to allow users to drag&drop emails from their +desktop to Odoo.

+

It supports as well RFC822 .eml files as Outlook .msg (those only if an +extra library is +installed) files.

+

When the mail is dropped to an odoo record, it will automatically send a +notification of that new message that has been added to all the existing +followers. It is possible to disable this notification.

+

Table of contents

+ +
+

Usage

+

To use this module, you need to:

+
    +
  1. save your emails on the desktop / somewhere in the file system
  2. +
  3. drag them to your browser, and drop them on the chatter of the record +you want to attach your email to
  4. +
+
+
+

Known issues / Roadmap

+
    +
  • most mail clients won’t allow you to drag mails directly from the mail +client, you’ll need some plugin for that
  • +
  • for corporate environments, it might be feasible to support imap URLs +and get the mail in question on the server side
  • +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Therp BV
  • +
+
+
+

Contributors

+ +
+ +
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/mail project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+
+ + diff --git a/mail_drop_target/static/src/js/file_uploader.esm.js b/mail_drop_target/static/src/js/file_uploader.esm.js new file mode 100644 index 000000000..abb33cd60 --- /dev/null +++ b/mail_drop_target/static/src/js/file_uploader.esm.js @@ -0,0 +1,32 @@ +/* @odoo-module */ +import {AttachmentUploadService} from "@mail/core/common/attachment_upload_service"; +import {Chatter} from "@mail/chatter/web_portal/chatter"; +import {patch} from "@web/core/utils/patch"; +import {useService} from "@web/core/utils/hooks"; + +patch(AttachmentUploadService.prototype, { + async _processLoaded(thread, composer, attachmentData, tmpId, def) { + if (attachmentData.email_upload === 1) { + this._fileUploadBus.trigger("REFRESH_CHATTER", thread.id); + } else { + return super._processLoaded(thread, composer, attachmentData, tmpId, def); + } + }, +}); + +patch(Chatter.prototype, { + setup() { + super.setup(...arguments); + + this.attachmentUploadService = useService("mail.attachment_upload"); + + this.attachmentUploadService._fileUploadBus.addEventListener( + "REFRESH_CHATTER", + ({detail: threadId}) => { + if (this.state.thread?.id === threadId) { + this.reloadParentView(); + } + } + ); + }, +}); diff --git a/mail_drop_target/tests/__init__.py b/mail_drop_target/tests/__init__.py new file mode 100644 index 000000000..1dd00d054 --- /dev/null +++ b/mail_drop_target/tests/__init__.py @@ -0,0 +1 @@ +from . import test_mail_drop_target diff --git a/mail_drop_target/tests/sample.eml b/mail_drop_target/tests/sample.eml new file mode 100644 index 000000000..cd2cfa6ef --- /dev/null +++ b/mail_drop_target/tests/sample.eml @@ -0,0 +1,75 @@ +X-MDAV-Result: clean +X-MDAV-Processed: mail3.creublanca.es, Wed, 26 Jun 2019 18:08:19 +0200 +Return-path: +Authentication-Results: mail3.creublanca.es; + auth=pass (login) smtp.auth=etobella@creublanca.es +Received: from WorldClient by creublanca.es with ESMTPA id md50020655392.msg; + Wed, 26 Jun 2019 18:08:19 +0200 +X-Spam-Processed: mail3.creublanca.es, Wed, 26 Jun 2019 18:08:19 +0200 + (not processed: message from trusted or authenticated source) +X-MDArrival-Date: Wed, 26 Jun 2019 18:08:19 +0200 +X-Authenticated-Sender: etobella@creublanca.es +X-Rcpt-To: etobella@creublanca.es +X-MDRcpt-To: etobella@creublanca.es +X-Return-Path: prvs=10800b8cdb=etobella@creublanca.es +X-Envelope-From: etobella@creublanca.es +X-MDaemon-Deliver-To: etobella@creublanca.es +Received: by creublanca.es via MDaemon Webmail with HTTP; + Wed, 26 Jun 2019 18:08:16 +0200 +Date: Wed, 26 Jun 2019 18:08:16 +0200 +From: "Enric Tobella" +To: "Enric Tobella" +Subject: Test +MIME-Version: 1.0 +Content-Type: multipart/alternative; boundary="0626-1608-16-03-PART_BREAK" +Message-ID: +X-Mailer: MDaemon Webmail 19.0.2 + +--0626-1608-16-03-PART_BREAK +Content-Type: text/plain; charset=iso-8859-1 +Content-Transfer-Encoding: 8bit + +TEST + + + + +Tanto este mensaje como los documentos que, en su caso, lleve como anexos, +pueden contener informacin reservada y/o confidencial, destinada exclusivamente +para el uso del destinatario o la persona responsable de entregarlo al mismo, +estando su uso no autorizado prohibido legalmente. +Su contenido no constituye un compromiso para Creu Blanca (la empresa remitente) +salvo ratificacin escrita por ambas partes. En caso de su recepcin por error, +rogamos nos lo comunique por igual va, se abstenga de realizar copias del mensaje +o documentos adjuntos, remitirlo o facilitarlo a un tercero, y proceda en su defecto, +a su eliminacin. + +--0626-1608-16-03-PART_BREAK +Content-Type: text/html; charset=iso-8859-1 +Content-Transfer-Encoding: quoted-printable + + +
TEST
+

+
+
+Tanto este mensaje como los documentos que, en su caso, lleve como anexos, = +
+pueden contener informaci=F3n reservada y/o confidencial, destinada exclusi= +vamente
+para el uso del destinatario o la persona responsable de entregarlo al mism= +o,
+estando su uso no autorizado prohibido legalmente.
+Su contenido no constituye un compromiso para Creu Blanca (la empresa remit= +ente)
+salvo ratificaci=F3n escrita por ambas partes. En caso de su recepci=F3n po= +r error,
+rogamos nos lo comunique por igual v=EDa, se abstenga de realizar copias de= +l mensaje
+o documentos adjuntos, remitirlo o facilitarlo a un tercero, y proceda en s= +u defecto,
+a su eliminaci=F3n.
+ + +--0626-1608-16-03-PART_BREAK-- diff --git a/mail_drop_target/tests/sample.eml:OECustomProperty b/mail_drop_target/tests/sample.eml:OECustomProperty new file mode 100644 index 000000000..86ec7b121 Binary files /dev/null and b/mail_drop_target/tests/sample.eml:OECustomProperty differ diff --git a/mail_drop_target/tests/sample.msg b/mail_drop_target/tests/sample.msg new file mode 100644 index 000000000..0a5ffcd82 Binary files /dev/null and b/mail_drop_target/tests/sample.msg differ diff --git a/mail_drop_target/tests/sample_include_attachment.msg b/mail_drop_target/tests/sample_include_attachment.msg new file mode 100644 index 000000000..9f46bed57 Binary files /dev/null and b/mail_drop_target/tests/sample_include_attachment.msg differ diff --git a/mail_drop_target/tests/test_mail_drop_target.py b/mail_drop_target/tests/test_mail_drop_target.py new file mode 100644 index 000000000..3af803c5a --- /dev/null +++ b/mail_drop_target/tests/test_mail_drop_target.py @@ -0,0 +1,102 @@ +import base64 +from unittest.mock import patch + +from odoo import exceptions, tools +from odoo.tests.common import TransactionCase + + +class TestMailDropTarget(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.partner = cls.env["res.partner"].create({"name": "TEST PARTNER"}) + cls.partner.message_subscribe(partner_ids=cls.partner.ids) + + def test_eml(self): + message = tools.file_open("addons/mail_drop_target/tests/sample.eml").read() + comments = len(self.partner.message_ids) + self.partner.message_process( + self.partner._name, message, thread_id=self.partner.id + ) + self.partner.invalidate_recordset() + self.assertEqual(comments + 1, len(self.partner.message_ids)) + with self.assertRaises(exceptions.UserError): + self.partner.message_drop( + self.partner._name, message, thread_id=self.partner.id + ) + + def test_msg(self): + message = base64.b64encode( + tools.file_open( + "addons/mail_drop_target/tests/sample.msg", mode="rb" + ).read() + ) + comments = len(self.partner.message_ids) + self.partner.message_process_msg( + self.partner._name, message, thread_id=self.partner.id + ) + self.partner.invalidate_recordset() + self.assertEqual(comments + 1, len(self.partner.message_ids)) + msg = self.partner.message_ids.filtered(lambda m: m.subject == "Test") + self.assertIsNotNone(msg.notified_partner_ids) + with self.assertRaises(exceptions.UserError): + self.partner.message_process_msg( + self.partner._name, message, thread_id=self.partner.id + ) + + def test_msg_with_attachment(self): + message = base64.b64encode( + tools.file_open( + "addons/mail_drop_target/tests/sample_include_attachment.msg", mode="rb" + ).read() + ) + comments = len(self.partner.message_ids) + self.partner.message_process_msg( + self.partner._name, message, thread_id=self.partner.id + ) + self.partner.invalidate_recordset() + self.assertEqual(comments + 1, len(self.partner.message_ids)) + msg = self.partner.message_ids.filtered( + lambda m: m.subject == "Test Mail Attachment" + ) + self.assertIsNotNone(msg.notified_partner_ids) + with self.assertRaises(exceptions.UserError): + self.partner.message_process_msg( + self.partner._name, message, thread_id=self.partner.id + ) + + def test_no_msgextract(self): + with ( + self.assertRaises(exceptions.UserError), + patch("odoo.addons.mail_drop_target.models.mail_thread.Message", new=False), + ): + self.test_msg() + + with ( + self.assertRaises(exceptions.UserError), + patch("odoo.addons.mail_drop_target.models.mail_thread.Message", new=False), + ): + self.test_msg_with_attachment() + + def test_msg_no_notification(self): + message = base64.b64encode( + tools.file_open( + "addons/mail_drop_target/tests/sample.msg", mode="rb" + ).read() + ) + settings = self.env["res.config.settings"].create({}) + settings.disable_notify_mail_drop_target = True + settings.execute() + comments = len(self.partner.message_ids) + self.partner.message_process_msg( + self.partner._name, message, thread_id=self.partner.id + ) + self.partner.invalidate_recordset() + self.assertEqual(comments + 1, len(self.partner.message_ids)) + msg = self.partner.message_ids.filtered(lambda m: m.subject == "Test") + self.assertEqual(len(msg.notified_partner_ids), 0) + with self.assertRaises(exceptions.UserError): + self.partner.message_process_msg( + self.partner._name, message, thread_id=self.partner.id + ) diff --git a/mail_drop_target/views/res_config_settings_views.xml b/mail_drop_target/views/res_config_settings_views.xml new file mode 100644 index 000000000..1aa059746 --- /dev/null +++ b/mail_drop_target/views/res_config_settings_views.xml @@ -0,0 +1,27 @@ + + + + res.config.settings.view.form.inherit.mail + res.config.settings + + + +
+
+ +
+
+
+
+
+
+
+
diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..804d6e55a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# generated from manifests external_dependencies +extract_msg