odex30_standard/odex30_base/whatsapp/controller/main.py

99 lines
4.7 KiB
Python

import hashlib
import hmac
import json
import logging
from markupsafe import Markup
from werkzeug.exceptions import Forbidden
from http import HTTPStatus
from odoo import http, _
from odoo.http import request
from odoo.tools import consteq
_logger = logging.getLogger(__name__)
class Webhook(http.Controller):
@http.route('/whatsapp/webhook/', methods=['POST'], type="json", auth="public")
def webhookpost(self):
data = json.loads(request.httprequest.data)
for entry in data['entry']:
account_id = entry['id']
account = request.env['whatsapp.account'].sudo().search(
[('account_uid', '=', account_id)])
if not self._check_signature(account):
raise Forbidden()
for changes in entry.get('changes', []):
value = changes['value']
phone_number_id = value.get('metadata', {}).get('phone_number_id', {})
if not phone_number_id:
phone_number_id = value.get('whatsapp_business_api_data', {}).get('phone_number_id', {})
if phone_number_id:
wa_account_id = request.env['whatsapp.account'].sudo().search([
('phone_uid', '=', phone_number_id), ('account_uid', '=', account_id)])
if wa_account_id:
if changes['field'] == 'messages':
request.env['whatsapp.message']._process_statuses(value)
wa_account_id._process_messages(value)
else:
_logger.warning("There is no phone configured for this whatsapp webhook : %s ", data)
if value.get('message_template_id'):
template = request.env['whatsapp.template'].sudo().with_context(active_test=False).search([('wa_template_uid', '=', value['message_template_id'])])
if template:
if changes['field'] == 'message_template_status_update':
template.write({'status': value['event'].lower()})
if value['event'].lower() == 'rejected':
body = _("Your Template has been rejected.")
description = value.get('other_info', {}).get('description') or value.get('reason')
if description:
body += Markup("<br/>") + _("Reason : %s", description)
template.message_post(body=body)
continue
if changes['field'] == 'message_template_quality_update':
new_quality_score = value['new_quality_score'].lower()
new_quality_score = {'unknown': 'none'}.get(new_quality_score, new_quality_score)
template.write({'quality': new_quality_score})
continue
if changes['field'] == 'template_category_update':
template.write({'template_type': value['new_category'].lower()})
continue
_logger.warning("Unknown Template webhook : %s ", value)
else:
_logger.warning("No Template found for this webhook : %s ", value)
@http.route('/whatsapp/webhook/', methods=['GET'], type="http", auth="public", csrf=False)
def webhookget(self, **kwargs):
token = kwargs.get('hub.verify_token')
mode = kwargs.get('hub.mode')
challenge = kwargs.get('hub.challenge')
if not (token and mode and challenge):
return Forbidden()
wa_account = request.env['whatsapp.account'].sudo().search([('webhook_verify_token', '=', token)])
if mode == 'subscribe' and wa_account:
response = request.make_response(challenge)
response.status_code = HTTPStatus.OK
return response
response = request.make_response({})
response.status_code = HTTPStatus.FORBIDDEN
return response
def _check_signature(self, business_account):
signature = request.httprequest.headers.get('X-Hub-Signature-256')
if not signature or not signature.startswith('sha256=') or len(signature) != 71:
_logger.warning('Invalid signature header %r', signature)
return False
if not business_account.app_secret:
_logger.warning('App-secret is missing, can not check signature')
return False
expected = hmac.new(
business_account.app_secret.encode(),
msg=request.httprequest.data,
digestmod=hashlib.sha256,
).hexdigest()
return consteq(signature[7:], expected)