odoo-addon-mail-gateway 16.0.1.0.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of odoo-addon-mail-gateway might be problematic. Click here for more details.

Files changed (73) hide show
  1. odoo/addons/mail_gateway/README.rst +100 -0
  2. odoo/addons/mail_gateway/__init__.py +6 -0
  3. odoo/addons/mail_gateway/__manifest__.py +38 -0
  4. odoo/addons/mail_gateway/controllers/__init__.py +2 -0
  5. odoo/addons/mail_gateway/controllers/discuss.py +11 -0
  6. odoo/addons/mail_gateway/controllers/gateway.py +81 -0
  7. odoo/addons/mail_gateway/hooks.py +12 -0
  8. odoo/addons/mail_gateway/i18n/mail_gateway.pot +533 -0
  9. odoo/addons/mail_gateway/models/__init__.py +10 -0
  10. odoo/addons/mail_gateway/models/ir_websocket.py +21 -0
  11. odoo/addons/mail_gateway/models/mail_channel.py +79 -0
  12. odoo/addons/mail_gateway/models/mail_gateway.py +149 -0
  13. odoo/addons/mail_gateway/models/mail_gateway_abstract.py +82 -0
  14. odoo/addons/mail_gateway/models/mail_guest.py +18 -0
  15. odoo/addons/mail_gateway/models/mail_message.py +123 -0
  16. odoo/addons/mail_gateway/models/mail_notification.py +43 -0
  17. odoo/addons/mail_gateway/models/mail_thread.py +85 -0
  18. odoo/addons/mail_gateway/models/res_partner.py +89 -0
  19. odoo/addons/mail_gateway/models/res_users.py +16 -0
  20. odoo/addons/mail_gateway/readme/CONFIGURATION.rst +4 -0
  21. odoo/addons/mail_gateway/readme/CONTRIBUTORS.rst +2 -0
  22. odoo/addons/mail_gateway/readme/CREDITS.rst +1 -0
  23. odoo/addons/mail_gateway/readme/DESCRIPTION.rst +5 -0
  24. odoo/addons/mail_gateway/readme/USAGE.rst +9 -0
  25. odoo/addons/mail_gateway/security/ir.model.access.csv +9 -0
  26. odoo/addons/mail_gateway/security/security.xml +61 -0
  27. odoo/addons/mail_gateway/static/description/icon.png +0 -0
  28. odoo/addons/mail_gateway/static/description/index.html +441 -0
  29. odoo/addons/mail_gateway/static/src/components/chatter/chatter.xml +40 -0
  30. odoo/addons/mail_gateway/static/src/components/composer/composer.xml +24 -0
  31. odoo/addons/mail_gateway/static/src/components/discuss_sidebar/discuss_sidebar.xml +17 -0
  32. odoo/addons/mail_gateway/static/src/components/gateway_follower/gateway_follower.esm.js +31 -0
  33. odoo/addons/mail_gateway/static/src/components/gateway_follower/gateway_follower.scss +12 -0
  34. odoo/addons/mail_gateway/static/src/components/gateway_follower/gateway_follower.xml +30 -0
  35. odoo/addons/mail_gateway/static/src/components/message/message.xml +22 -0
  36. odoo/addons/mail_gateway/static/src/components/message_notification_popover_content/message_notification_popover_content.xml +15 -0
  37. odoo/addons/mail_gateway/static/src/models/channel.esm.js +33 -0
  38. odoo/addons/mail_gateway/static/src/models/channel_member_view.esm.js +39 -0
  39. odoo/addons/mail_gateway/static/src/models/chatter.esm.js +41 -0
  40. odoo/addons/mail_gateway/static/src/models/composer.esm.js +32 -0
  41. odoo/addons/mail_gateway/static/src/models/composer_gateway_follower.esm.js +32 -0
  42. odoo/addons/mail_gateway/static/src/models/composer_view.esm.js +56 -0
  43. odoo/addons/mail_gateway/static/src/models/discuss.esm.js +51 -0
  44. odoo/addons/mail_gateway/static/src/models/discuss_sidebar_category.esm.js +128 -0
  45. odoo/addons/mail_gateway/static/src/models/discuss_sidebar_category_item.esm.js +51 -0
  46. odoo/addons/mail_gateway/static/src/models/gateway.esm.js +16 -0
  47. odoo/addons/mail_gateway/static/src/models/gateway_channel.esm.js +14 -0
  48. odoo/addons/mail_gateway/static/src/models/gateway_channel_view.esm.js +15 -0
  49. odoo/addons/mail_gateway/static/src/models/guest.esm.js +10 -0
  50. odoo/addons/mail_gateway/static/src/models/message.esm.js +76 -0
  51. odoo/addons/mail_gateway/static/src/models/message_action.esm.js +45 -0
  52. odoo/addons/mail_gateway/static/src/models/message_action_list.esm.js +37 -0
  53. odoo/addons/mail_gateway/static/src/models/message_action_view.esm.js +91 -0
  54. odoo/addons/mail_gateway/static/src/models/message_view.esm.js +13 -0
  55. odoo/addons/mail_gateway/static/src/models/messaging_initializer.esm.js +24 -0
  56. odoo/addons/mail_gateway/static/src/models/notification.esm.js +20 -0
  57. odoo/addons/mail_gateway/static/src/models/partner.esm.js +11 -0
  58. odoo/addons/mail_gateway/static/src/models/thread.esm.js +77 -0
  59. odoo/addons/mail_gateway/tests/__init__.py +0 -0
  60. odoo/addons/mail_gateway/tests/common.py +21 -0
  61. odoo/addons/mail_gateway/views/mail_gateway.xml +93 -0
  62. odoo/addons/mail_gateway/views/res_partner_gateway_channel.xml +59 -0
  63. odoo/addons/mail_gateway/wizards/__init__.py +3 -0
  64. odoo/addons/mail_gateway/wizards/mail_guest_manage.py +58 -0
  65. odoo/addons/mail_gateway/wizards/mail_guest_manage.xml +37 -0
  66. odoo/addons/mail_gateway/wizards/mail_message_gateway_link.py +42 -0
  67. odoo/addons/mail_gateway/wizards/mail_message_gateway_link.xml +28 -0
  68. odoo/addons/mail_gateway/wizards/mail_message_gateway_send.py +20 -0
  69. odoo/addons/mail_gateway/wizards/mail_message_gateway_send.xml +39 -0
  70. odoo_addon_mail_gateway-16.0.1.0.0.2.dist-info/METADATA +118 -0
  71. odoo_addon_mail_gateway-16.0.1.0.0.2.dist-info/RECORD +73 -0
  72. odoo_addon_mail_gateway-16.0.1.0.0.2.dist-info/WHEEL +5 -0
  73. odoo_addon_mail_gateway-16.0.1.0.0.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,149 @@
1
+ # Copyright 2024 Dixmit
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3
+ from odoo import Command, api, fields, models, tools
4
+
5
+
6
+ class MailGateway(models.Model):
7
+ _name = "mail.gateway"
8
+ _description = "Mail Gateway"
9
+
10
+ name = fields.Char(required=True)
11
+ token = fields.Char(required=True, help="Key used for integration purposes")
12
+ gateway_type = fields.Selection([], required=True)
13
+ webhook_key = fields.Char(help="Key used on the connection URL")
14
+ webhook_secret = fields.Char(
15
+ help="""Key used to ensure that the connection is secure and
16
+ comes from the desired source"""
17
+ )
18
+ integrated_webhook_state = fields.Selection(
19
+ [("pending", "Pending"), ("integrated", "Integrated")], readonly=True
20
+ )
21
+ can_set_webhook = fields.Boolean(compute="_compute_webhook_checks")
22
+ webhook_url = fields.Char(compute="_compute_webhook_url")
23
+ has_new_channel_security = fields.Boolean(
24
+ help="When checked, channels are not created automatically. Usable on Telegram"
25
+ )
26
+ webhook_user_id = fields.Many2one(
27
+ "res.users",
28
+ default=lambda self: self.env.user.id,
29
+ help="User that will create the messages",
30
+ )
31
+ member_ids = fields.Many2many(
32
+ "res.users", default=lambda self: [Command.link(self.env.user.id)]
33
+ )
34
+ company_id = fields.Many2one(
35
+ "res.company", default=lambda self: self.env.company.id
36
+ )
37
+
38
+ _sql_constraints = [
39
+ ("mail_gateway_token", "unique(token)", "Token must be unique"),
40
+ (
41
+ "mail_gateway_webhook_key",
42
+ "unique(webhook_key)",
43
+ "Webhook Key must be unique",
44
+ ),
45
+ ]
46
+
47
+ @api.depends("webhook_key")
48
+ def _compute_webhook_url(self):
49
+ for record in self:
50
+ record.webhook_url = record._get_webhook_url()
51
+
52
+ def _get_channel_id(self, chat_token):
53
+ return (
54
+ self.env["mail.channel"]
55
+ .search(
56
+ [
57
+ ("gateway_channel_token", "=", str(chat_token)),
58
+ ("gateway_id", "=", self.id),
59
+ ],
60
+ limit=1,
61
+ )
62
+ .id
63
+ )
64
+
65
+ def _get_webhook_url(self):
66
+ return "%s/gateway/%s/%s/update" % (
67
+ self.webhook_url
68
+ or self.env["ir.config_parameter"].get_param("web.base.url"),
69
+ self.gateway_type,
70
+ self.webhook_key,
71
+ )
72
+
73
+ def _can_set_webhook(self):
74
+ return self.webhook_key and self.webhook_user_id
75
+
76
+ @api.depends("gateway_type")
77
+ def _compute_webhook_checks(self):
78
+ for record in self:
79
+ record.can_set_webhook = record._can_set_webhook()
80
+
81
+ def set_webhook(self):
82
+ self.ensure_one()
83
+ if self.can_set_webhook:
84
+ self.env["mail.gateway.%s" % self.gateway_type]._set_webhook(self)
85
+
86
+ def remove_webhook(self):
87
+ self.ensure_one()
88
+ self.env["mail.gateway.%s" % self.gateway_type]._remove_webhook(self)
89
+
90
+ def update_webhook(self):
91
+ self.ensure_one()
92
+ self.remove_webhook()
93
+ self.set_webhook()
94
+
95
+ def write(self, vals):
96
+ res = super(MailGateway, self).write(vals)
97
+ if (
98
+ "webhook_key" in vals
99
+ or "integrated_webhook_state" in vals
100
+ or "webhook_secret" in vals
101
+ or "webhook_user_id" in vals
102
+ ):
103
+ self.clear_caches()
104
+ return res
105
+
106
+ @api.model_create_multi
107
+ def create(self, mvals):
108
+ res = super(MailGateway, self).create(mvals)
109
+ self.clear_caches()
110
+ return res
111
+
112
+ @api.model
113
+ @tools.ormcache()
114
+ def _get_gateway_map(self, state="integrated", gateway_type=False):
115
+ result = {}
116
+ for record in self.search(
117
+ [
118
+ ("integrated_webhook_state", "=", state),
119
+ ("gateway_type", "=", gateway_type),
120
+ ]
121
+ ):
122
+ result[record.webhook_key] = record._get_gateway_data()
123
+ return result
124
+
125
+ def _get_gateway_data(self):
126
+ return {
127
+ "id": self.id,
128
+ "webhook_secret": self.webhook_secret,
129
+ "webhook_user_id": self.webhook_user_id.id,
130
+ }
131
+
132
+ @api.model
133
+ def _get_gateway(self, key, state="integrated", gateway_type=False):
134
+ # We are using cache in order to avoid an exploit
135
+ if not key:
136
+ return False
137
+ return self._get_gateway_map(state=state, gateway_type=gateway_type).get(
138
+ key, False
139
+ )
140
+
141
+ def gateway_info(self):
142
+ return [record._gateway_info() for record in self]
143
+
144
+ def _gateway_info(self):
145
+ return {
146
+ "id": self.id,
147
+ "name": self.name,
148
+ "type": self.gateway_type,
149
+ }
@@ -0,0 +1,82 @@
1
+ # Copyright 2024 Dixmit
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3
+ from odoo import Command, models
4
+
5
+
6
+ class MailGatewayAbstract(models.AbstractModel):
7
+ _name = "mail.gateway.abstract"
8
+ _description = "Gateway abstract for functions"
9
+
10
+ def _verify_update(self, bot_data, kwargs):
11
+ return True
12
+
13
+ def _receive_update(self, gateway, kwargs):
14
+ pass
15
+
16
+ def _post_process_message(self, message, channel):
17
+ self.env["mail.notification"].search(
18
+ [("gateway_channel_id", "=", channel.id), ("is_read", "=", False)]
19
+ )._set_read_gateway()
20
+
21
+ def _post_process_reply(self, related_message):
22
+ pass
23
+
24
+ def _update_content_after_hook(self, channel, message):
25
+ pass
26
+
27
+ def _set_webhook(self, gateway):
28
+ gateway.integrated_webhook_state = "integrated"
29
+
30
+ def _remove_webhook(self, gateway):
31
+ gateway.integrated_webhook_state = False
32
+
33
+ def _get_channel(self, gateway, token, update, force_create=False):
34
+ chat_id = gateway._get_channel_id(token)
35
+ if chat_id:
36
+ return gateway.env["mail.channel"].browse(chat_id)
37
+ if not force_create and gateway.has_new_channel_security:
38
+ return False
39
+ channel = gateway.env["mail.channel"].create(
40
+ self._get_channel_vals(gateway, token, update)
41
+ )
42
+ channel._broadcast(channel.channel_member_ids.mapped("partner_id").ids)
43
+ return channel
44
+
45
+ def _get_author(self, gateway, update):
46
+ return False
47
+
48
+ def _get_channel_vals(self, gateway, token, update):
49
+ author = self._get_author(gateway, update)
50
+ members = [
51
+ Command.create({"partner_id": partner.id, "is_pinned": True})
52
+ for partner in gateway.member_ids.partner_id
53
+ ]
54
+ if author:
55
+ members.append(
56
+ Command.create(
57
+ {
58
+ "partner_id": author._name == "res.partner" and author.id,
59
+ "guest_id": author._name == "mail.guest" and author.id,
60
+ }
61
+ )
62
+ )
63
+ return {
64
+ "gateway_channel_token": token,
65
+ "gateway_id": gateway.id,
66
+ "channel_type": "gateway",
67
+ "channel_member_ids": members,
68
+ "company_id": gateway.company_id.id,
69
+ }
70
+
71
+ def _send(
72
+ self,
73
+ gateway,
74
+ record,
75
+ auto_commit=False,
76
+ raise_exception=False,
77
+ parse_mode=False,
78
+ ):
79
+ raise NotImplementedError()
80
+
81
+ def _get_message_body(self, record):
82
+ return record.mail_message_id.body
@@ -0,0 +1,18 @@
1
+ # Copyright 2024 Dixmit
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3
+
4
+ from odoo import fields, models
5
+
6
+
7
+ class MailGuest(models.Model):
8
+ _inherit = "mail.guest"
9
+
10
+ gateway_id = fields.Many2one("mail.gateway")
11
+ gateway_token = fields.Char()
12
+
13
+ def _guest_format(self, fields=None):
14
+ result = super()._guest_format(fields=fields)
15
+ if not fields or "gateway_id" in fields:
16
+ for guest in result:
17
+ result[guest]["gateway"] = {"id": guest.gateway_id.id}
18
+ return result
@@ -0,0 +1,123 @@
1
+ # Copyright 2024 Dixmit
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3
+
4
+
5
+ from odoo import api, fields, models
6
+
7
+
8
+ class MailMessage(models.Model):
9
+
10
+ _inherit = "mail.message"
11
+
12
+ gateway_type = fields.Selection(
13
+ selection=lambda r: r.env["mail.gateway"]._fields["gateway_type"].selection
14
+ )
15
+ gateway_notification_ids = fields.One2many(
16
+ "mail.notification",
17
+ inverse_name="mail_message_id",
18
+ domain=[("notification_type", "=", "gateway")],
19
+ )
20
+ gateway_channel_ids = fields.Many2many(
21
+ "res.partner.gateway.channel", compute="_compute_gateway_channel_ids"
22
+ )
23
+ gateway_channel_data = fields.Json(compute="_compute_gateway_channel_ids")
24
+ gateway_message_ids = fields.One2many(
25
+ "mail.message",
26
+ inverse_name="gateway_message_id",
27
+ string="Child gateway messages",
28
+ )
29
+ gateway_message_id = fields.Many2one(
30
+ "mail.message", string="Original gateway message"
31
+ )
32
+ gateway_thread_data = fields.Json(compute="_compute_gateway_thread_data")
33
+
34
+ @api.depends("gateway_message_id")
35
+ def _compute_gateway_thread_data(self):
36
+ for record in self:
37
+ gateway_thread_data = {}
38
+ if record.gateway_message_id:
39
+ gateway_thread_data.update(
40
+ {
41
+ "name": record.gateway_message_id.record_name,
42
+ "id": record.gateway_message_id.res_id,
43
+ "model": record.gateway_message_id.model,
44
+ }
45
+ )
46
+ record.gateway_thread_data = gateway_thread_data
47
+
48
+ @api.depends("notification_ids", "gateway_message_ids")
49
+ def _compute_gateway_channel_ids(self):
50
+ for record in self:
51
+ if self.env.user.has_group("mail_gateway.gateway_user"):
52
+ channels = record.notification_ids.res_partner_id.gateway_channel_ids.filtered(
53
+ lambda r: (r.gateway_token, r.gateway_id.id)
54
+ not in [
55
+ (
56
+ notification.gateway_channel_id.gateway_channel_token,
57
+ notification.gateway_channel_id.gateway_id.id,
58
+ )
59
+ for notification in record.gateway_message_ids.gateway_notification_ids
60
+ ]
61
+ )
62
+ else:
63
+ channels = self.env["res.partner.gateway.channel"]
64
+ record.gateway_channel_ids = channels
65
+ record.gateway_channel_data = {
66
+ "channels": channels.ids,
67
+ "partners": channels.partner_id.ids,
68
+ }
69
+
70
+ @api.depends("gateway_notification_ids")
71
+ def _compute_gateway_channel_id(self):
72
+ for rec in self:
73
+ if rec.gateway_notification_ids:
74
+ rec.gateway_channel_id = rec.gateway_notification_ids[
75
+ 0
76
+ ].gateway_channel_id
77
+
78
+ def _get_message_format_fields(self):
79
+ result = super()._get_message_format_fields()
80
+ result.append("gateway_type")
81
+ result.append("gateway_channel_data")
82
+ result.append("gateway_thread_data")
83
+ return result
84
+
85
+ def _send_to_gateway_thread(self, gateway_channel_id):
86
+ chat_id = gateway_channel_id.gateway_id._get_channel_id(
87
+ gateway_channel_id.gateway_token
88
+ )
89
+ channel = self.env["mail.channel"].browse(chat_id)
90
+ channel.message_post(**self._get_gateway_thread_message_vals())
91
+ if not self.gateway_type:
92
+ self.gateway_type = gateway_channel_id.gateway_id.gateway_type
93
+ self.env["mail.notification"].create(
94
+ {
95
+ "notification_status": "sent",
96
+ "mail_message_id": self.id,
97
+ "gateway_channel_id": channel.id,
98
+ "notification_type": "gateway",
99
+ "gateway_type": gateway_channel_id.gateway_id.gateway_type,
100
+ }
101
+ )
102
+ self.env["bus.bus"]._sendone(
103
+ self.env.user.partner_id,
104
+ "mail.message/insert",
105
+ {
106
+ "id": self.id,
107
+ "gateway_type": self.gateway_type,
108
+ "notifications": self.sudo()
109
+ .notification_ids._filtered_for_web_client()
110
+ ._notification_format(),
111
+ },
112
+ )
113
+ return {}
114
+
115
+ def _get_gateway_thread_message_vals(self):
116
+ return {
117
+ "body": self.body,
118
+ "attachment_ids": self.attachment_ids.ids,
119
+ "subtype_id": self.subtype_id.id,
120
+ "author_id": self.env.user.partner_id.id,
121
+ "gateway_message_id": self.id,
122
+ "message_type": "comment",
123
+ }
@@ -0,0 +1,43 @@
1
+ # Copyright 2024 Dixmit
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3
+
4
+ from odoo import fields, models
5
+
6
+
7
+ class MailNotification(models.Model):
8
+ _inherit = "mail.notification"
9
+
10
+ gateway_channel_id = fields.Many2one("mail.channel")
11
+ notification_type = fields.Selection(
12
+ selection_add=[("gateway", "Gateway")], ondelete={"gateway": "cascade"}
13
+ )
14
+ gateway_message_id = fields.Char(readonly=True)
15
+ gateway_failure_reason = fields.Text(
16
+ readonly=1,
17
+ help="Failure reason. This is usually the exception thrown by the"
18
+ " email server, stored to ease the debugging of mailing issues.",
19
+ )
20
+ gateway_type = fields.Selection(
21
+ selection=lambda r: r.env["mail.gateway"]._fields["gateway_type"].selection
22
+ )
23
+
24
+ def _set_read_gateway(self):
25
+ self.sudo().write({"is_read": True, "read_date": fields.Datetime.now()})
26
+
27
+ def _notification_format(self):
28
+ result = super()._notification_format()
29
+ for record, formatted_value in zip(self, result):
30
+ formatted_value["gateway_type"] = record.gateway_type
31
+ formatted_value["channel_name"] = record.gateway_channel_id.name
32
+ return result
33
+
34
+ def send_gateway(self, auto_commit=False, raise_exception=False, parse_mode="HTML"):
35
+ for record in self:
36
+ gateway = record.gateway_channel_id.gateway_id
37
+ self.env["mail.gateway.%s" % gateway.gateway_type]._send(
38
+ gateway,
39
+ record,
40
+ auto_commit=auto_commit,
41
+ raise_exception=raise_exception,
42
+ parse_mode=parse_mode,
43
+ )
@@ -0,0 +1,85 @@
1
+ # Copyright 2024 Dixmit
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3
+ from odoo import models
4
+
5
+
6
+ class MailThread(models.AbstractModel):
7
+ _inherit = "mail.thread"
8
+
9
+ def _notify_thread_by_email(self, message, recipients_data, **kwargs):
10
+ partners_data = [r for r in recipients_data if r["notif"] == "gateway"]
11
+ if partners_data:
12
+ self._notify_thread_by_gateway(message, partners_data, **kwargs)
13
+ return super()._notify_thread_by_email(message, recipients_data, **kwargs)
14
+
15
+ def _notify_thread_by_gateway(self, message, partners_data, **kwargs):
16
+ for partner_data in partners_data:
17
+ if partner_data["notif"] != "gateway" or not partner_data.get(
18
+ "gateway_channel_id"
19
+ ):
20
+ continue
21
+ message._send_to_gateway_thread(
22
+ self.env["res.partner.gateway.channel"].browse(
23
+ partner_data.get("gateway_channel_id")
24
+ )
25
+ )
26
+
27
+ def _notify_get_recipients(self, message, msg_vals, **kwargs):
28
+ if "gateway_notifications" in kwargs:
29
+ result = []
30
+ for notification in kwargs["gateway_notifications"]:
31
+ if not notification.get("channel_type"):
32
+ continue
33
+ partner = self.env["res.partner"].browse(notification["partner_id"])
34
+ user = partner.user_ids
35
+ follower_data = {
36
+ "active": partner.active,
37
+ "id": partner.id,
38
+ "is_follower": True,
39
+ "lang": partner.lang,
40
+ "groups": set(user.groups_id.ids),
41
+ "notif": notification.get("channel_type"),
42
+ "share": partner.partner_share,
43
+ "uid": user[:1].id,
44
+ "ushare": user and any(user.mapped("share")),
45
+ "gateway_channel_id": notification.get("gateway_channel_id"),
46
+ }
47
+ if follower_data["ushare"]: # any type of share user
48
+ follower_data["type"] = "portal"
49
+ elif follower_data[
50
+ "share"
51
+ ]: # no user, is share -> customer (partner only)
52
+ follower_data["type"] = "customer"
53
+ else: # has a user not share -> internal user
54
+ follower_data["type"] = "user"
55
+ result.append(follower_data)
56
+ return result
57
+ return super()._notify_get_recipients(message, msg_vals, **kwargs)
58
+
59
+ def _check_can_update_message_content(self, messages):
60
+ # We can delete the messages comming from a gateway on not channels
61
+ if self._name != "mail.channel":
62
+ new_messages = messages.filtered(lambda r: not r.gateway_message_ids)
63
+ else:
64
+ new_messages = messages
65
+ return super()._check_can_update_message_content(new_messages)
66
+
67
+ def _message_update_content(
68
+ self, message, body, attachment_ids=None, strict=True, **kwargs
69
+ ):
70
+ result = super()._message_update_content(
71
+ message, body, attachment_ids=attachment_ids, strict=strict, **kwargs
72
+ )
73
+ if body == "":
74
+ # Unlink the message
75
+ for gateway_message in message.gateway_message_ids:
76
+ gateway_message.gateway_message_id = False
77
+ self.env["bus.bus"]._sendone(
78
+ self.env.user.partner_id,
79
+ "mail.message/insert",
80
+ {
81
+ "id": gateway_message.id,
82
+ "gateway_thread_data": gateway_message.sudo().gateway_thread_data,
83
+ },
84
+ )
85
+ return result
@@ -0,0 +1,89 @@
1
+ # Copyright 2024 Dixmit
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3
+
4
+ from odoo import fields, models
5
+
6
+
7
+ class ResPartner(models.Model):
8
+ """Update of res.partner class to take into account the gateway."""
9
+
10
+ _inherit = "res.partner"
11
+
12
+ gateway_channel_ids = fields.One2many(
13
+ "res.partner.gateway.channel", inverse_name="partner_id"
14
+ )
15
+
16
+ def mail_partner_format(self, fields=None):
17
+ """Override to add gateway info."""
18
+ partners_format = super().mail_partner_format(fields=fields)
19
+ if not fields:
20
+ fields = {"gateway_channel_ids": True}
21
+ for partner in self:
22
+ if "gateway_channel_ids" in fields:
23
+ partners_format.get(partner).update(
24
+ {
25
+ "gateway_channels": partner.gateway_channel_ids.mail_format(),
26
+ }
27
+ )
28
+ return partners_format
29
+
30
+ def _get_channels_as_member(self):
31
+ channels = super()._get_channels_as_member()
32
+ if self.env.user.has_group("mail_gateway.gateway_user"):
33
+ channels |= self.env["mail.channel"].search(
34
+ [
35
+ ("channel_type", "=", "gateway"),
36
+ (
37
+ "channel_member_ids",
38
+ "in",
39
+ self.env["mail.channel.member"]
40
+ .sudo()
41
+ ._search(
42
+ [
43
+ ("partner_id", "=", self.id),
44
+ ("is_pinned", "=", True),
45
+ ]
46
+ ),
47
+ ),
48
+ ]
49
+ )
50
+ return channels
51
+
52
+
53
+ class ResPartnerGatewayChannel(models.Model):
54
+ _name = "res.partner.gateway.channel"
55
+ _description = "Technical data used to get the gateway author"
56
+
57
+ name = fields.Char(related="gateway_id.name")
58
+ partner_id = fields.Many2one(
59
+ "res.partner", required=True, readonly=True, ondelete="cascade"
60
+ )
61
+ gateway_id = fields.Many2one(
62
+ "mail.gateway", required=True, readonly=True, ondelete="cascade"
63
+ )
64
+ gateway_token = fields.Char(readonly=True)
65
+ company_id = fields.Many2one(
66
+ "res.company", related="gateway_id.company_id", store=True
67
+ )
68
+
69
+ _sql_constraints = [
70
+ (
71
+ "unique_partner_gateway",
72
+ "UNIQUE(partner_id, gateway_id)",
73
+ "Partner can only have one configuration for each gateway.",
74
+ ),
75
+ ]
76
+
77
+ def mail_format(self):
78
+ return [r._mail_format() for r in self]
79
+
80
+ def _mail_format(self):
81
+ return {
82
+ "id": self.id,
83
+ "name": self.name,
84
+ "gateway": {
85
+ "id": self.gateway_id.id,
86
+ "name": self.gateway_id.name,
87
+ "type": self.gateway_id.gateway_type,
88
+ },
89
+ }
@@ -0,0 +1,16 @@
1
+ # Copyright 2024 Dixmit
2
+ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3
+
4
+ from odoo import fields, models
5
+
6
+
7
+ class ResUsers(models.Model):
8
+
9
+ _inherit = "res.users"
10
+
11
+ gateway_ids = fields.Many2many("mail.gateway")
12
+
13
+ def _init_messaging(self):
14
+ result = super()._init_messaging()
15
+ result["gateways"] = self.gateway_ids.gateway_info()
16
+ return result
@@ -0,0 +1,4 @@
1
+ - Access in development mode
2
+ - Go to `Settings / Technical / Email / Gateway`
3
+ - Create a gateway. Follow the instruction of the specific tab in order to integrate it.
4
+ - Start receiving notifications
@@ -0,0 +1,2 @@
1
+ * Enric Tobella
2
+ * Olga Marco
@@ -0,0 +1 @@
1
+ This work has been funded by AEOdoo (Asociación Española de Odoo - https://www.aeodoo.org)
@@ -0,0 +1,5 @@
1
+ This module will allow you to integrate an external chat system in your Odoo system.
2
+ It requires extra modules with the specific configuration of each chat system, like `mail_gateway_telegram` or `mail_gateway_whatsapp`.
3
+
4
+ This way, a group of users can respond customers or any other set
5
+ of partners within Odoo, but the messages will be sent through the external chat system.
@@ -0,0 +1,9 @@
1
+ When external messages are received, they will be directly sent to the discuss menu.
2
+ Answering to these messages will send the answer to the external contact.
3
+ We can assign this messages to any record using the message actions.
4
+ Also, we can assign the sender to a partner using the followers menu and selecting the partner.
5
+
6
+ On a standard record associated to a partner with external chat, we can send messages to the external contact directly selecting the methods of the partner.
7
+ To use this, we just need to use the
8
+
9
+ It is recomended to enable chatter notification to all users that will receive messages from gateways.
@@ -0,0 +1,9 @@
1
+ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
2
+ access_res_partner_gateway_channel_portal,res.partner.gateway.channel.portal,model_res_partner_gateway_channel,base.group_portal,1,0,0,0
3
+ access_res_partner_gateway_channel_user,res.partner.gateway.channel,model_res_partner_gateway_channel,base.group_user,1,0,0,0
4
+ manage_res_partner_gateway_channel_user,res.partner.gateway.channel,model_res_partner_gateway_channel,gateway_user,1,1,1,1
5
+ access_mail_message_gateway_send_user,mail.message.gateway.send,model_mail_message_gateway_send,base.group_user,1,1,1,0
6
+ access_mail_gateway_all,mail.telegram.bot.all,model_mail_gateway,,1,0,0,0
7
+ access_mail_guest_manage,mail.telegram.bot.all,model_mail_guest_manage,base.group_user,1,1,1,1
8
+ access_mail_message_gateway_link,mail.message.link.all,model_mail_message_gateway_link,base.group_user,1,1,1,1
9
+ access_mail_gateway_system,mail_gateway,model_mail_gateway,base.group_system,1,1,1,1