Browse Source

[ADD] mail_forward

pull/256/head
Jairo Llopis 9 years ago
committed by Pedro M. Baeza
parent
commit
1d68d252b7
  1. 101
      mail_forward/README.rst
  2. 5
      mail_forward/__init__.py
  3. 28
      mail_forward/__openerp__.py
  4. 168
      mail_forward/i18n/es.po
  5. 5
      mail_forward/models/__init__.py
  6. 97
      mail_forward/models/compose_message.py
  7. 14
      mail_forward/models/res_request_link.py
  8. BIN
      mail_forward/static/description/icon.png
  9. 12
      mail_forward/static/src/css/mail_forward.css
  10. 77
      mail_forward/static/src/js/mail_forward.js
  11. 14
      mail_forward/static/src/xml/mail_forward.xml
  12. 5
      mail_forward/tests/__init__.py
  13. 65
      mail_forward/tests/test_compose_message.py
  14. 21
      mail_forward/views/assets.xml
  15. 64
      mail_forward/views/compose_message.xml
  16. 32
      mail_forward/views/res_request_link.xml

101
mail_forward/README.rst

@ -0,0 +1,101 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
===============
Message forward
===============
This module was written to extend the functionality of mails to support
forwarding them to another contact or database object.
* **To another object of the database:** All its followers are notified
according to their settings.
* **To other contacts:** They recieve the forwarded message according to the
usual notification rules of Odoo.
Configuration
=============
When installed, this module allows forwarding to a limited selection of
database models, that will get automatically updated when you install other
modules.
This list can be customized by a user that has *Technical Features* permission.
To do it:
* Go to *Settings > Technical > Database Structure > Referenceable Models*.
* Any model there with *Mail forward target* enabled will appear in the list of
models that can get forwarded messages.
* If you want to *remove* a model from the list, it's usually better to just
*disable* its check box instead of deleting it, because that record might
be used by other modules.
Usage
=====
To use this module, you need to:
* Go to any view that has a message thread.
* Press *Forward* (the button with a curved arrow pointing to the right).
* Modify the subject if you wish.
* If you want to forward the message to an *object*, choose it from the
selector.
* If you want to forward the message to some partner(s), add them in the
selector.
* Modify the message if you want.
* Add attachments if you want.
* If the message contains attachments, you can turn on the *Move attachments*
option, and those will get attached to the new object.
You will need to install the *document* module and have at least *User*
permissions for *Knowledge* to see the effect.
.. info::
Technical note: Internally, forwarded messages are modified copies of
original ones, but attachments are references to the exact originals to
avoid duplicating disk space. Keep that in mind when managing permissions.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/205/8.0
For further information, please visit:
* https://www.odoo.com/forum/help-1
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/social/issues>`_. In
case of trouble, please check there if your issue has already been reported. If
you spotted it first, help us smashing it by providing a detailed and welcomed
feedback `here
<https://github.com/OCA/social/issues/new?body=module:%20mail_forward%0Aversion:%208.0.7.0.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Jairo Llopis <j.llopis@grupoesoc.es>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
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.
To contribute to this module, please visit http://odoo-community.org.

5
mail_forward/__init__.py

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# © 2014-2015 Grupo ESOC <www.grupoesoc.es>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import models

28
mail_forward/__openerp__.py

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# © 2014-2015 Grupo ESOC <www.grupoesoc.es>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
"name": "Message Forward",
"summary": "Add option to forward messages",
"version": "8.0.7.0.0",
"category": "Social Network",
"website": "https://grupoesoc.es",
"author": "Grupo ESOC Ingeniería de Servicios, "
"Odoo Community Association (OCA)",
"license": "AGPL-3",
"application": False,
"installable": True,
"depends": [
"mail",
"web",
],
"data": [
"views/assets.xml",
"views/compose_message.xml",
"views/res_request_link.xml",
],
"qweb": [
"static/src/xml/mail_forward.xml",
],
}

168
mail_forward/i18n/es.po

@ -0,0 +1,168 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mail_forward
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-02 09:15+0000\n"
"PO-Revision-Date: 2015-11-02 10:19+0100\n"
"Last-Translator: Jairo Llopis <j.llopis@grupoesoc.es>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: \n"
"Language: es\n"
"X-Generator: Poedit 1.8.5\n"
#. module: mail_forward
#. openerp-web
#: code:addons/mail_forward/static/src/js/mail_forward.js:25
#, python-format
msgid "(No subject)"
msgstr "(Sin asunto)"
#. module: mail_forward
#: help:res.request.link,mail_forward_target:0
msgid "Allow to forward mails to this model."
msgstr "Permitir reenviar correos a este modelo."
#. module: mail_forward
#: help:mail_forward.compose_message,move_attachments:0
msgid "Attachments will be assigned to the chosen destination object and you will be able to pick them from its 'Attachments' button, but they will not be there for the current object if any. In any case you can always open it from the message itself."
msgstr "Los adjuntos se asignarán al objeto de destino escogido y podrá escogerlos desde el botón 'Adjuntos', pero desaparecerán del objeto en el que estén actualmente (si están en alguno). En cualquier caso, siempre podrá abrirlos desde el propio mensaje."
#. module: mail_forward
#. openerp-web
#: code:addons/mail_forward/static/src/js/mail_forward.js:47
#, python-format
msgid "CC: "
msgstr "CC: "
#. module: mail_forward
#: field:mail_forward.compose_message,create_uid:0
msgid "Created by"
msgstr "Creado por"
#. module: mail_forward
#: field:mail_forward.compose_message,create_date:0
msgid "Created on"
msgstr "Creado el"
#. module: mail_forward
#. openerp-web
#: code:addons/mail_forward/static/src/js/mail_forward.js:38
#, python-format
msgid "Date: "
msgstr "Fecha: "
#. module: mail_forward
#: field:mail_forward.compose_message,destination_object_id:0
msgid "Destination object"
msgstr "Objeto de destino"
#. module: mail_forward
#. openerp-web
#: code:addons/mail_forward/static/src/js/mail_forward.js:16
#, python-format
msgid "FWD"
msgstr "RV"
#. module: mail_forward
#. openerp-web
#: code:addons/mail_forward/static/src/xml/mail_forward.xml:10
#, python-format
msgid "Forward"
msgstr "Reenviar"
#. module: mail_forward
#: model:ir.actions.act_window,name:mail_forward.compose_action
msgid "Forward Email"
msgstr "Reenviar correo electrónico"
#. module: mail_forward
#. openerp-web
#: code:addons/mail_forward/static/src/js/mail_forward.js:36
#, python-format
msgid "Forwarded message"
msgstr "Mensaje reenviado"
#. module: mail_forward
#. openerp-web
#: code:addons/mail_forward/static/src/js/mail_forward.js:37
#, python-format
msgid "From: "
msgstr "De: "
#. module: mail_forward
#: field:mail_forward.compose_message,id:0
msgid "ID"
msgstr "ID"
#. module: mail_forward
#: field:mail_forward.compose_message,write_uid:0
msgid "Last Updated by"
msgstr "Última actualización por"
#. module: mail_forward
#: field:mail_forward.compose_message,write_date:0
msgid "Last Updated on"
msgstr "Última actualización el"
#. module: mail_forward
#: field:res.request.link,mail_forward_target:0
msgid "Mail forward target"
msgstr "Objetivo al reenviar"
#. module: mail_forward
#: field:mail_forward.compose_message,move_attachments:0
msgid "Move attachments"
msgstr "Mover adjuntos"
#. module: mail_forward
#: help:mail_forward.compose_message,destination_object_id:0
msgid "Object where the forwarded message will be attached"
msgstr "Objeto al que se añadirá el mensaje reenviado"
#. module: mail_forward
#: field:mail_forward.compose_message,original_wizard_id:0
msgid "Original message compose wizard"
msgstr "Asistente original de composición de mensajes"
#. module: mail_forward
#. openerp-web
#: code:addons/mail_forward/static/src/js/mail_forward.js:41
#, python-format
msgid "Subject: "
msgstr "Asunto: "
#. module: mail_forward
#. openerp-web
#: code:addons/mail_forward/static/src/js/mail_forward.js:44
#, python-format
msgid "To: "
msgstr "Para: "
#. module: mail_forward
#: view:mail_forward.compose_message:mail_forward.compose_form
msgid ""
"{\n"
" 'invisible': [('destination_object_id', '=', False)]\n"
" }"
msgstr ""
"{\n"
" 'invisible': [('destination_object_id', '=', False)]\n"
" }"
#. module: mail_forward
#: view:mail_forward.compose_message:mail_forward.compose_form
msgid ""
"{\n"
" 'required': [('destination_object_id', '=', False)]\n"
" }"
msgstr ""
"{\n"
" 'required': [('destination_object_id', '=', False)]\n"
" }"

5
mail_forward/models/__init__.py

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# © 2014-2015 Grupo ESOC <www.grupoesoc.es>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import compose_message, res_request_link

97
mail_forward/models/compose_message.py

@ -0,0 +1,97 @@
# -*- coding: utf-8 -*-
# © 2014-2015 Grupo ESOC <www.grupoesoc.es>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import api, fields, models
class MailForwardComposeMessage(models.TransientModel):
"""Allow forwarding a message.
It duplicates the message and optionally attaches it to another object
of the database and sends it to another recipients than the original one.
"""
_name = "mail_forward.compose_message"
_inherits = {"mail.compose.message": "original_wizard_id"}
@api.model
def default_get(self, fields):
"""Fix default values.
Sometimes :meth:`openerp.addons.mail.mail_compose_message
.mail_compose_message.default_get` overwrites the default value
for the ``subject`` field, even when it gets the right default value
from the context.
This method fixes that by getting it from the context if available.
"""
result = self.original_wizard_id.default_get(fields)
if "subject" in result and "default_subject" in self.env.context:
result["subject"] = self.env.context["default_subject"]
return result
@api.model
def _get_model_selection(self):
"""Get allowed models and their names."""
model_objs = self.env["res.request.link"].search(
[("mail_forward_target", "=", True)],
order="name")
return [(m.object, m.name) for m in model_objs]
@api.one
@api.onchange("destination_object_id")
def change_destination_object(self):
"""Update some fields for the new message."""
if self.destination_object_id:
self.model = self.destination_object_id._name
self.res_id = self.destination_object_id.id
model_name = (self.env["ir.model"]
.search([("model", "=", self.model)])
.name)
record_name = self.destination_object_id.name_get()[0][1]
if model_name:
record_name = "%s %s" % (model_name, record_name)
self.record_name = record_name
else:
self.model = self.res_id = self.record_name = False
@api.one
def send_mail(self):
"""Send mail and execute the attachment relocation if needed."""
# Let the original wizard do de hard work
result = self.original_wizard_id.send_mail()
# Relocate attachments if needed
if (self.move_attachments and
self.model and
self.res_id and
self.attachment_ids):
for attachment in self.attachment_ids:
attachment.res_model = self.model
attachment.res_id = self.res_id
return result
destination_object_id = fields.Reference(
_get_model_selection,
"Destination object",
help="Object where the forwarded message will be attached")
move_attachments = fields.Boolean(
"Move attachments",
help="Attachments will be assigned to the chosen destination "
"object and you will be able to pick them from its "
"'Attachments' button, but they will not be there for "
"the current object if any. In any case you can always "
"open it from the message itself.")
original_wizard_id = fields.Many2one(
"mail.compose.message",
"Original message compose wizard",
delegate=True,
ondelete="cascade",
required=True)

14
mail_forward/models/res_request_link.py

@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
# © 2014-2015 Grupo ESOC <www.grupoesoc.es>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from openerp import fields, models
class ResRequestLink(models.Model):
_inherit = "res.request.link"
mail_forward_target = fields.Boolean(
default=True,
index=True,
help="Allow to forward mails to this model.")

BIN
mail_forward/static/description/icon.png

After

Width: 100  |  Height: 100  |  Size: 1.8 KiB

12
mail_forward/static/src/css/mail_forward.css

@ -0,0 +1,12 @@
/* © 2014-2015 Grupo ESOC <www.grupoesoc.es>
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
*/
.openerp .oe_mail .oe_msg .oe_msg_icons .oe_forward:hover a {
color: #1FC0FF;
text-shadow: 0px 1px #184FC5,
0px -1px #184FC5,
-1px 0px #184FC5,
1px 0px #184FC5,
0px 3px 3px rgba(0, 0, 0, 0.1);
}

77
mail_forward/static/src/js/mail_forward.js

@ -0,0 +1,77 @@
/* © 2014-2015 Grupo ESOC <www.grupoesoc.es>
* License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
*/
"use strict";
openerp.mail_forward = function (instance) {
var _t = instance.web._t;
instance.mail.ThreadMessage.include({
bind_events: function () {
this._super.apply(this, arguments);
this.$('.oe_forward').on('click', this.on_message_forward);
},
on_message_forward: function () {
// Generate email subject as possible from record_name and subject
var subject = [_t("FWD")];
if (this.record_name && (this.show_record_name ||
this.parent_id))
{
subject.push(this.record_name);
}
if (this.subject) {
subject.push(this.subject);
} else if (subject.length < 2) {
subject.push(_t("(No subject)"));
}
// Get only ID from the attachments
var attachment_ids = [];
for (var n in this.attachment_ids) {
attachment_ids.push(this.attachment_ids[n].id);
}
// Get necessary fields from the forwarded message
var header = [
"----------" + _t("Forwarded message") + "----------",
_t("From: ") + this.author_id[1],
_t("Date: ") + this.date,
];
if (this.subject) {
header.push(_t("Subject: ") + this.subject);
}
if (this.email_to) {
header.push(_t("To: ") + this.email_to);
}
if (this.email_cc) {
header.push(_t("CC: ") + this.email_cc);
}
header = header.map(_.str.escapeHTML).join("<br/>")
var context = {
default_attachment_ids: attachment_ids,
default_body:
"<p><i>" + header + "</i></p><br/>" +
this.body,
default_model: this.model,
default_res_id: this.res_id,
default_subject: subject.join(": "),
};
if (this.model && this.res_id) {
context.default_destination_object_id =
[this.model, this.res_id].join();
}
// Get the action data and execute it to open the composer wizard
var do_action = this.do_action;
this.rpc("/web/action/load", {
"action_id": "mail_forward.compose_action",
})
.done(function(action) {
action.context = context;
do_action(action);
});
}
});
};

14
mail_forward/static/src/xml/mail_forward.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- © 2014-2015 Grupo ESOC <www.grupoesoc.es>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<template>
<t t-extend="mail.thread.message">
<t t-jquery=".oe_msg_icons .oe_reply" t-operation="before">
<span class="oe_forward">
<a title="Forward" class="oe_e">*</a>
</span>
</t>
</t>
</template>

5
mail_forward/tests/__init__.py

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# © 2014-2015 Grupo ESOC <www.grupoesoc.es>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import test_compose_message

65
mail_forward/tests/test_compose_message.py

@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
# © 2014-2015 Grupo ESOC <www.grupoesoc.es>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from os import path
from openerp.tests.common import TransactionCase
class ForwardMailCase(TransactionCase):
def setUp(self, *args, **kwargs):
super(ForwardMailCase, self).setUp(*args, **kwargs)
self.compose = self.env["mail.compose.message"].create({})
self.fwd = self.env["mail_forward.compose_message"].create({
"original_wizard_id": self.compose.id,
})
self.partner = self.env["res.partner"].create({"name": __file__})
self.attachment = self.env["ir.attachment"].create({
"name": "Testing source",
"datas_fname": path.basename(__file__),
"type": "url",
"url": "file://%s" % __file__,
})
def test_subject(self):
"""Test correct subject is used."""
self.compose.subject = "Bad subject"
good = "Good subject"
defaults = self.fwd.with_context(default_subject=good).default_get(
["subject"])
self.assertEqual(defaults["subject"], good)
def test_change_destination(self):
"""Test what happens when changing the destination."""
model = self.env["ir.model"].search(
[("model", "=", self.partner._name)])
# Set a partner as destination object
self.fwd.destination_object_id = self.partner
self.fwd.change_destination_object()
self.assertEqual(self.fwd.model, self.partner._name)
self.assertEqual(self.fwd.res_id, self.partner.id)
self.assertEqual(self.fwd.record_name,
"%s %s" % (model.name, self.partner.name))
# Remove the destination object
self.fwd.destination_object_id = False
self.fwd.change_destination_object()
self.assertFalse(self.fwd.model)
self.assertFalse(self.fwd.res_id)
self.assertFalse(self.fwd.record_name)
def test_move_attachments(self):
"""Attachments moved correctly."""
self.fwd.attachment_ids |= self.attachment
self.fwd.destination_object_id = self.partner
self.fwd.change_destination_object()
self.fwd.body = "body"
self.fwd.subject = "subject"
self.fwd.move_attachments = True
self.fwd.send_mail()
self.assertEqual(self.attachment.res_model, self.partner._name)
self.assertEqual(self.attachment.res_id, self.partner.id)

21
mail_forward/views/assets.xml

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- © 2014-2015 Grupo ESOC <www.grupoesoc.es>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<openerp>
<data>
<template id="assets_backend"
name="Mail forward assets"
inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<link rel="stylesheet"
href="/mail_forward/static/src/css/mail_forward.css"/>
<script type="text/javascript"
src="/mail_forward/static/src/js/mail_forward.js"/>
</xpath>
</template>
</data>
</openerp>

64
mail_forward/views/compose_message.xml

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- © 2014-2015 Grupo ESOC <www.grupoesoc.es>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<openerp>
<data>
<record id="compose_form" model="ir.ui.view">
<field name="name">Forward Email Form</field>
<field name="model">mail_forward.compose_message</field>
<field name="inherit_id" ref="mail.email_compose_message_wizard_form"/>
<field name="arch" type="xml">
<data>
<!-- It's required to fill either `partner_ids` or
`destination_object_id` -->
<xpath expr="//field[@name='partner_ids']" position="attributes">
<attribute name="attrs">{
'required': [('destination_object_id', '=', False)]
}</attribute>
</xpath>
<xpath expr="//label[@for='partner_ids']" position="before">
<!-- Object where the message will be attached -->
<field
attrs="{
'required': [('partner_ids', '=', [[6, False, []]])]}"
name="destination_object_id"/>
<!-- If the message has attachments, should we move them to the
new object? -->
<field
name="move_attachments"
attrs="{
'invisible': [
'|',
('destination_object_id', '=', False),
('attachment_ids', '=', [[6, False, []]])]}"/>
</xpath>
<!-- If there's no document to follow, hide the message -->
<xpath expr="//span[text()='Followers of the document and']"
position="attributes">
<attribute name="attrs">{
'invisible': [('destination_object_id', '=', False)]
}</attribute>
</xpath>
</data>
</field>
</record>
<record id="compose_action" model="ir.actions.act_window">
<field name="name">Forward Email</field>
<field name="res_model">mail_forward.compose_message</field>
<field name="src_model">mail.message</field>
<field name="type">ir.actions.act_window</field>
<field name="view_id" ref="compose_form"/>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</openerp>

32
mail_forward/views/res_request_link.xml

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- © 2014-2015 Grupo ESOC <www.grupoesoc.es>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -->
<openerp>
<data>
<record id="res_request_link_view_form" model="ir.ui.view">
<field name="name">Add option to forward mails</field>
<field name="model">res.request.link</field>
<field name="inherit_id" ref="base.res_request_link-view"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='priority']" position="after">
<field name="mail_forward_target"/>
</xpath>
</field>
</record>
<record id="res_request_link_view_tree" model="ir.ui.view">
<field name="name">Add option to forward mails</field>
<field name="model">res.request.link</field>
<field name="inherit_id" ref="base.res_request_link_tree-view"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='object']" position="after">
<field name="mail_forward_target"/>
</xpath>
</field>
</record>
</data>
</openerp>
Loading…
Cancel
Save