HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux spn-python 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64
User: arjun (1000)
PHP: 8.1.2-1ubuntu2.20
Disabled: NONE
Upload Files
File: //home/arjun/projects/buyercall_forms/buyercall/buyercall/blueprints/api2/doc/endpoints/webhooks.py
import logging
import time

from flask import (
    Blueprint,
    make_response,
    request,
    jsonify)
from datetime import datetime
from flask import Blueprint, jsonify, make_response
from buyercall.lib.util_rest import rest_partnership_account, rest_partnership, requires_auth, rest_is_partnership_account, rest_is_partnership
from flask_restx import Resource
from buyercall.blueprints.api2.doc import serializers
from buyercall.blueprints.api2.restplus import api
from buyercall.blueprints.partnership.models import Partnership, PartnershipAccount
from buyercall.blueprints.webhooks.models import Webhook
from sqlalchemy import func, or_, and_, extract

log = logging.getLogger(__name__)
ns = api.namespace('Webhooks', description='Operations related to webhooks.', path='/accounts')


@ns.route('/webhooks')
@api.doc(responses={200: 'OK',
                    400: 'Error performing operation.',
                    401: 'Unauthorized request.'})
class ApiWebhooksCollection(Resource):
    @requires_auth
    def get(self):
        """
        Retrieve all the webhook call-back urls for a specific partnership.
        <p>
        The Webhook API GET endpoint should be used to retrieve the webhook call-back urls for a specific partnership.
        Webhook call-back urls are not defined at a partnership account level, but rather at a partnership level. The
        call-back information returned by the webhook url will contain partnership account specific information.
        </p>
        <br />
        <p>
        There are no required parameters.  A response will
        be returned, similar to the example below, based
        on a successful request:
        <br />
        <br />
        </p>
         <pre class="code-background" style="color: white">
       {
      "created_on": "2019-07-16 00:30:00",
      "deactivated_on": "",
      "id": 6,
      "is_deactivated": false,
      "updated_on": "2019-07-16 01:06:55",
      "webhook_url": "http://buyercall.pythonanywhere.com/local_wehook"
        }
     </pre>
        """
        if rest_is_partnership and rest_partnership is not None:
            webhook = Webhook.query\
                .filter(and_(Webhook.partnership_id == rest_partnership.id, Webhook.is_deactivated == False))\
                .first()

            if webhook is not None:
                result_deactivated_on = ''

                if webhook.is_deactivated:
                    if webhook.deactivated_on is not None:
                        result_deactivated_on = webhook.deactivated_on.strftime('%Y-%m-%d %H:%M:%S')

                return jsonify(
                    id=webhook.id,
                    webhook_url=webhook.webhook_url,
                    security_token=webhook.security_token,
                    is_deactivated=webhook.is_deactivated,
                    deactivated_on=result_deactivated_on,
                    created_on=webhook.date_created,
                    updated_on=webhook.date_updated
                )
            else:
                api.abort(code=404, message="Error retrieving webhook. No webhook found.")
        else:
            api.abort(code=401)


    @api.expect(serializers.webhook_add, validate=True)
    @api.response(200, 'Webhook successfully created.')
    @requires_auth
    def post(self):
        """
        Creates a webhook for a partnership account.

        <p>
        The Webhook API POST endpoint should be used to to receive a call-back response whenever a phone call occurs or
        a text message is sent or received. For example, when a phone call is started the webhook call-back url will be called
        sending the specific call start data as body response. A webhook url will be triggered based on specific event
        types. Call or text message data responses will be sent via a webhook POST request based on the following event
        types:
        </p>
        <br />
        <p><b>operational_start_call</b> - Receive call data when a new inbound or outbound operational phone number call
        starts.</p>
        <p><b>operational_agent_call</b> - Receive call data when an agent answers an operational phone number call.</p>
        <p><b>operational_end_call</b> - Receive call data when an operational phone number call ends.</p>
        <p><b>mobile_start_call</b> - Receive call data when a new inbound or outbound mobile phone number call starts.</p>
        <p><b>mobile_end_call</b> - Receive call data when a mobile phone number call ends.</p>
        <p><b>operational_send_message</b> - Receive data when a operational phone number text message is sent.</p>
        <p><b>operational_receive_message</b> - Receive data when a operational phone number text message is received.</p>
        <p><b>mobile_send_message</b> - Receive data when a mobile phone number text message is sent.</p>
        <p><b>mobile_receive_message</b> - Receive data when a mobile phone number text message is received.</p>
        <br />
        <p>
        A webhook call-back url is defined at a partnership level. Therefore, only one webhook call-back url is required for
        all partnership accounts. The call-back response data will not only include the call or message data, but also
        contain a the partnership account id as well as the event type.
        </p>
        <br />
        <p>
        You require a valid webhook url to
        make a successful request. A response will
        be returned, similar to the example below, based
        on a successful request. Please note a phone call response will look different to a message response.
        <br />
        <br />
        </p>
        <p>
        Text Message Response:
        </p>
        <br />
         <pre class="code-background" style="color: white">
        {
        "status": "received",
        "direction": u'inbound',
        "phone_number_id": 204,
        "event_type": "mobile_receive_message",
        "delivery_description": None,
        "body_text": "Mooi man",
        "id": 275,
        "delivery_code": None,
        "delivery_type": None,
        "created_on": "2019-07-16 17:37:53",
        "agent_id': 3,
        "updated_on": "2019-07-16 17:37:53",
        "from_": "+17739699892",
        "type': "phone",
        "partnership_account_id": 1,
        "to": "+18722217507",
        "media_url": ""
        }
        </pre>
        <br />
        <p>
        Phone Call Response:
        </p>
        <br />
         <pre class="code-background" style="color: white">
        {
        "status": "ringing",
        "call_type": "outbound",
        "widget_guid": None,
        "progress_status": "new lead",
        "call_source": "Phone number for app user CoCoButter",
        "phonenumber_id": 204,
        "caller_id": "CHICAGO, IL",
        "id": 750,
        "created_on": "2019-07-16 19:09:23",
        "phonenumber": "+17739699892",
        "agent_id": None,
        "starttime": "2019-07-16 19:09:23",
        "my_phone": "+18722217507",
        "duration": None,
        "updated_on": "2019-07-16 19:09:23",
        "recording_url": "",
        "endtime": None,
        "type": "phone",
        "partnership_account_id": 1,
        "call_count": 0,
        "event_type": "mobile_start_call"
        }
        </pre>
        """
        if rest_is_partnership and rest_partnership is not None:
            received = request.json
            result_webhook_url = received['webhook_url']
            result_token = ''

            if 'security_token' in received:
                result_token = received['security_token']

            result = Webhook.create(result_webhook_url, result_token, rest_partnership.id, False)

            if result > 0:
                return True, 204
            elif result == -2:
                return api.abort(code=400, message="Error creating webhook. Webhook for partnership already exists.")
            else:
                return api.abort(code=404, message="Error creating webhook.")
        else:
            api.abort(code=401)


@ns.route('/webhooks/<int:whid>')
@api.doc(responses={200: 'OK',
                    400: 'Error performing operation.',
                    401: 'Unauthorized request.'},
         params={'whid': 'The webhook ID.'})
class ApiWebhooksSpecific(Resource):
    @api.expect(serializers.webhook_edit, validate=True)
    @api.response(200, 'Webhook successfully updated.')
    @requires_auth
    def put(self, whid):
        """
        Updates a webhook of a partnership account.

        <p>The Webhook API PUT endpoint can be used to update a webhook call-back url for a specific partnership.</p>
        <br />
        <p>
        You require a valid partnership webhook id to
        make a successful request. A response code will be returned
        on a successful request.
        </p>
        """
        if rest_is_partnership and rest_partnership is not None:

            webhook = Webhook.query\
                .filter(and_(Webhook.partnership_id == rest_partnership.id, Webhook.id == whid))\
                .first()

            if webhook is not None:
                received = request.json
                result_webhook_url = None
                result_token = None

                if 'webhook_url' in received:
                    result_webhook_url = received['webhook_url']

                if 'security_token' in received:
                    result_token = received['security_token']

                result = Webhook.update(whid, rest_partnership.id, result_webhook_url, result_token)

                if result:
                    return True, 204
                else:
                    return api.abort(code=404, message="Error updating webhook.")
            else:
                api.abort(code=404, message="Error updating webhook. Webhook not found.")
        else:
            api.abort(code=401)


    @api.response(200, 'Webhook successfully deleted.')
    @requires_auth
    def delete(self, whid):
        """
        Removes a webhook of a partnership account.

        <p>The Webhook API DELETE endpoint can be used to deactive a webhook call-back url for a specific partnership.</p>
        <br />
        <p>
        You require a valid partnership webhook id to
        make a successful request. A response code will be returned
        on a successful request.
        </p>
        """
        if rest_is_partnership and rest_partnership is not None:

            webhook = Webhook.query\
                .filter(and_(Webhook.partnership_id == rest_partnership.id, Webhook.id == whid))\
                .first()

            if webhook is not None:
                result = Webhook.deactivate(whid, rest_partnership.id)

                if result:
                    return True, 204
                else:
                    return api.abort(code=400, message="Error deleting webhook.")
            else:
                api.abort(code=404, message="Error deleting webhook. Webhook not found.")
        else:
            api.abort(code=401)