diff --git a/mail_gateway_whatsapp/README.rst b/mail_gateway_whatsapp/README.rst new file mode 100644 index 000000000..d79d0756d --- /dev/null +++ b/mail_gateway_whatsapp/README.rst @@ -0,0 +1 @@ +TO DO diff --git a/mail_gateway_whatsapp/__init__.py b/mail_gateway_whatsapp/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/mail_gateway_whatsapp/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/mail_gateway_whatsapp/__manifest__.py b/mail_gateway_whatsapp/__manifest__.py new file mode 100644 index 000000000..055960077 --- /dev/null +++ b/mail_gateway_whatsapp/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright 2022 Creu Blanca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Mail Whatsapp Broker", + "summary": """ + Set a broker for whatsapp""", + "version": "13.0.1.0.0", + "license": "AGPL-3", + "author": "Creu Blanca, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/social", + "depends": ["mail_broker"], + "data": ["views/mail_broker.xml"], + "external_dependencies": {}, +} diff --git a/mail_gateway_whatsapp/models/__init__.py b/mail_gateway_whatsapp/models/__init__.py new file mode 100644 index 000000000..cf04d46c0 --- /dev/null +++ b/mail_gateway_whatsapp/models/__init__.py @@ -0,0 +1,3 @@ +from . import mail_broker_channel +from . import mail_message_broker +from . import mail_broker diff --git a/mail_gateway_whatsapp/models/mail_broker.py b/mail_gateway_whatsapp/models/mail_broker.py new file mode 100644 index 000000000..c73f29e8b --- /dev/null +++ b/mail_gateway_whatsapp/models/mail_broker.py @@ -0,0 +1,54 @@ +# Copyright 2022 Creu Blanca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging + +from odoo import fields, models +from odoo.http import request + +_logger = logging + + +class MailBroker(models.Model): + _inherit = "mail.broker" + + whatsapp_security_key = fields.Char() + broker_type = fields.Selection(selection_add=[("whatsapp", "WhatsApp")]) + whatsapp_from_phone = fields.Char() + + def _set_webhook(self): + super(MailBroker, self)._set_webhook() + + def _remove_webhook(self): + super(MailBroker, self)._remove_webhook() + + def _get_channel_vals(self, token, update): + result = super(MailBroker, self)._get_channel_vals(token, update) + if self.broker_type == "whatsapp" and not result.get("name"): + for contact in update["contacts"]: + if contact["wa_id"] == token: + result["name"] = contact["profile"]["name"] + continue + return result + + def _receive_update_whatsapp(self, update): + chat = {} + if update: + for entry in update["entry"]: + for change in entry["changes"]: + if change["field"] != "messages": + continue + for message in change["value"].get("messages", []): + chat = self._get_channel( + message["from"], change["value"], force_create=True + ) + if not chat: + return + return chat.whatsapp_update(update) + + def _verify_bot(self, **kwargs): + self.ensure_one() + if self.broker_type != "whatsapp": + return super()._verify_bot() + response = request.make_response(kwargs.get("hub").get("challenge")) + response.status_code = 200 + return response diff --git a/mail_gateway_whatsapp/models/mail_broker_channel.py b/mail_gateway_whatsapp/models/mail_broker_channel.py new file mode 100644 index 000000000..fd31b58aa --- /dev/null +++ b/mail_gateway_whatsapp/models/mail_broker_channel.py @@ -0,0 +1,78 @@ +# Copyright 2022 Creu Blanca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import base64 +import mimetypes +from datetime import datetime + +import requests + +from odoo import models + + +class MailBrokerChannel(models.Model): + _inherit = "mail.broker.channel" + + def whatsapp_update(self, updates): + self.ensure_one() + body = "" + attachments = [] + for entry in updates["entry"]: + for change in entry["changes"]: + if change["field"] != "messages": + continue + for message in change["value"]["messages"]: + if message.get("text"): + body = message.get("text").get("body") + for key in ["image", "audio", "video"]: + if message.get(key): + image_id = message.get(key).get("id") + image_info_request = requests.get( + "https://graph.facebook.com/v13.0/%s" % image_id, + headers={ + "Authorization": "Bearer %s" % self.broker_id.token, + }, + ) + image_info_request.raise_for_status() + image_info = image_info_request.json() + image_request = requests.get( + image_info["url"], + headers={ + "Authorization": "Bearer %s" % self.broker_id.token, + }, + ) + image_request.raise_for_status() + attachments.append( + ( + "{}{}".format( + image_id, + mimetypes.guess_extension( + image_info["mime_type"] + ), + ), + base64.b64encode(image_request.content).decode( + "utf-8" + ), + image_info["mime_type"], + ) + ) + if message.get("location"): + body += ( + 'Location' + % ( + message["location"]["latitude"], + message["location"]["longitude"], + ) + ) + if message.get("contacts"): + pass + if len(body) > 0 or attachments: + self.message_post_broker( + body=body, + broker_type="whatsapp", + date=datetime.fromtimestamp(int(message["timestamp"])), + message_id=message.get("id"), + subtype="mt_comment", + attachments=attachments, + ) diff --git a/mail_gateway_whatsapp/models/mail_message_broker.py b/mail_gateway_whatsapp/models/mail_message_broker.py new file mode 100644 index 000000000..eeb132826 --- /dev/null +++ b/mail_gateway_whatsapp/models/mail_message_broker.py @@ -0,0 +1,78 @@ +# Copyright 2022 Creu Blanca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging +import traceback +from io import StringIO + +import requests + +from odoo import _, models +from odoo.tools import html2plaintext + +from odoo.addons.base.models.ir_mail_server import MailDeliveryException + +_logger = logging.getLogger(__name__) + + +class MailMessageBroker(models.Model): + _inherit = "mail.message.broker" + + def _send_whatsapp_payload(self, body=False, media_id=False): + if body: + return { + "messaging_product": "whatsapp", + "recipient_type": "individual", + "to": self.channel_id.token, + "type": "text", + "text": {"preview_url": False, "body": html2plaintext(body)}, + } + if media_id: + return { + "messaging_product": "whatsapp", + "recipient_type": "individual", + "to": self.channel_id.token, + "type": "image", + "image": {"id": media_id}, + } + + def _send_whatsapp( + self, auto_commit=False, raise_exception=False, parse_mode=False + ): + message = False + try: + # TODO: Now only works for text. improve it... + if self.body: + response = requests.post( + "https://graph.facebook.com/v13.0/%s/messages" + % self.channel_id.broker_id.whatsapp_from_phone, + headers={ + "Authorization": "Bearer %s" % self.channel_id.broker_id.token, + }, + json=self._send_whatsapp_payload(body=self.body), + ) + response.raise_for_status() + message = response.json() + except Exception as exc: + buff = StringIO() + traceback.print_exc(file=buff) + _logger.error(buff.getvalue()) + if raise_exception: + raise MailDeliveryException( + _("Unable to send the whatsapp message"), exc + ) + else: + _logger.warning( + "Issue sending message with id {}: {}".format(self.id, exc) + ) + self.write({"state": "exception", "failure_reason": exc}) + if message: + self.write( + { + "state": "sent", + "message_id": message["messages"][0]["id"], + "failure_reason": False, + } + ) + if auto_commit is True: + # pylint: disable=invalid-commit + self._cr.commit() diff --git a/mail_gateway_whatsapp/readme/CONFIGURE.rst b/mail_gateway_whatsapp/readme/CONFIGURE.rst new file mode 100644 index 000000000..f23168d69 --- /dev/null +++ b/mail_gateway_whatsapp/readme/CONFIGURE.rst @@ -0,0 +1,29 @@ +First steps +~~~~~~~~~~~ + +You need to create a WhatsApp Business Account (WABA), a Meta App and define a phone number. +You can follow this `steps `_. + +If you create a test Business Account, passwords will change every 24 hours. + +In order to make the webhook accessible, the system must be public. + +Configure the broker +~~~~~~~~~~~~~~~~~~~~ + +Once you have created the Meta App, you need to add the broker and webhook. +In order to make it you must follow this steps: + +* Access `Settings > Emails > Mail Broker` +* Create a Broker of type `WhatsApp` + + * Use the Meta App authentication key as `Token` field + * Use the Meta App Phone Number ID as `Whatsapp from Phone` field + * Write your own `Webhook key` and `Whatsapp Security Key` + * Press the `Integrate Webhook Key`. In this case, it will not integrate it, we need to make it manually + * Copy the webhook URL + +* Access `Facebook Apps website `_ +* Access your App then `Whatsapp > Configuration` +* Create your webhook using your URL and put the Whatsapp Security Key as validation Key +* Administer the Webhook and activate the messages webhook diff --git a/mail_gateway_whatsapp/readme/CONTRIBUTORS.rst b/mail_gateway_whatsapp/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..cd3b2e447 --- /dev/null +++ b/mail_gateway_whatsapp/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Olga Marco +* Enric Tobella diff --git a/mail_gateway_whatsapp/readme/DESCRIPTION.rst b/mail_gateway_whatsapp/readme/DESCRIPTION.rst new file mode 100644 index 000000000..b8b23c141 --- /dev/null +++ b/mail_gateway_whatsapp/readme/DESCRIPTION.rst @@ -0,0 +1,4 @@ +This module allows to respond whatsapp chats. + +This way, a group of users can respond customers or any other set +of partners in an integrated way. diff --git a/mail_gateway_whatsapp/readme/USAGE.rst b/mail_gateway_whatsapp/readme/USAGE.rst new file mode 100644 index 000000000..fa884cb73 --- /dev/null +++ b/mail_gateway_whatsapp/readme/USAGE.rst @@ -0,0 +1,3 @@ +1. Access `Broker` +2. Wait until someone starts a conversation. +3. Now you will be able to respond and receive messages to this person. diff --git a/mail_gateway_whatsapp/static/description/icon.png b/mail_gateway_whatsapp/static/description/icon.png new file mode 100644 index 000000000..dea8a38ec Binary files /dev/null and b/mail_gateway_whatsapp/static/description/icon.png differ diff --git a/mail_gateway_whatsapp/static/description/icon.svg b/mail_gateway_whatsapp/static/description/icon.svg new file mode 100644 index 000000000..fe2e6d4f1 --- /dev/null +++ b/mail_gateway_whatsapp/static/description/icon.svg @@ -0,0 +1,160 @@ + + + + + + image/svg+xml + + icon + + + + + + + + + + + + + + + + + icon + + + + + + + + + + diff --git a/mail_gateway_whatsapp/static/description/index.html b/mail_gateway_whatsapp/static/description/index.html new file mode 100644 index 000000000..745179b53 --- /dev/null +++ b/mail_gateway_whatsapp/static/description/index.html @@ -0,0 +1,452 @@ + + + + + + +Mail Telegram Broker + + + +
+

Mail Telegram Broker

+ + +

Beta License: AGPL-3 tegin/cb-addons

+

This module allows to respond telegram chats as a telegram bot.

+

This way, a group of users can respond customers or any other set +of partners in an integrated way.

+

It is not intended to be integrated on default chatter as users don’t need +to review again when one has responded.

+

Table of contents

+ +
+

Configuration

+
+

Create the bot

+
    +
  1. Create a Bot on telegram https://core.telegram.org/bots
  2. +
  3. Create a broker following the examples on +https://github.com/tegin/telegram-broker with the TOKEN provided
  4. +
+
+
+

Configure Odoo

+
    +
  1. Access on debug mode
  2. +
  3. Access Settings > Technical Settings > Email > Telegram Bot.
  4. +
  5. Create a bot and assign the token. Mark it as Show on App
  6. +
+
+
+
+

Usage

+
    +
  1. Access Telegram
  2. +
  3. Wait until someone starts a conversation with your bot.
  4. +
  5. Now you will be able to respond and receive messages to this person.
  6. +
+
+
+

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 smashing it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Creu Blanca
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is part of the tegin/cb-addons project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/mail_gateway_whatsapp/views/mail_broker.xml b/mail_gateway_whatsapp/views/mail_broker.xml new file mode 100644 index 000000000..8fc6d9275 --- /dev/null +++ b/mail_gateway_whatsapp/views/mail_broker.xml @@ -0,0 +1,22 @@ + + + + + mail.broker.form (in mail_broker_telegram) + mail.broker + + + + + + + + +