Exemple #1
0
    def get_api_templates(self, channel):
        if (
            CONFIG_FB_BUSINESS_ID not in channel.config or CONFIG_FB_ACCESS_TOKEN not in channel.config
        ):  # pragma: no cover
            return [], False

        start = timezone.now()
        try:
            # Retrieve the template domain, fallback to the default for channels
            # that have been setup earlier for backwards compatibility
            facebook_template_domain = channel.config.get(CONFIG_FB_TEMPLATE_LIST_DOMAIN, "graph.facebook.com")
            facebook_business_id = channel.config.get(CONFIG_FB_BUSINESS_ID)
            url = TEMPLATE_LIST_URL % (facebook_template_domain, facebook_business_id)
            template_data = []
            while url:
                response = requests.get(
                    url, params=dict(access_token=channel.config[CONFIG_FB_ACCESS_TOKEN], limit=255)
                )
                elapsed = (timezone.now() - start).total_seconds() * 1000
                HTTPLog.create_from_response(
                    HTTPLog.WHATSAPP_TEMPLATES_SYNCED, url, response, channel=channel, request_time=elapsed
                )

                if response.status_code != 200:  # pragma: no cover
                    return [], False

                template_data.extend(response.json()["data"])
                url = response.json().get("paging", {}).get("next", None)
            return template_data, True
        except requests.RequestException as e:
            HTTPLog.create_from_exception(HTTPLog.WHATSAPP_TEMPLATES_SYNCED, url, e, start, channel=channel)
            return [], False
Exemple #2
0
    def get_api_templates(self, channel):
        if Channel.CONFIG_AUTH_TOKEN not in channel.config:  # pragma: no cover
            return [], False

        start = timezone.now()
        try:

            templates_url = "%s/v1/configs/templates" % channel.config.get(
                Channel.CONFIG_BASE_URL, "")

            response = requests.get(templates_url,
                                    headers=self.get_headers(channel))
            elapsed = (timezone.now() - start).total_seconds() * 1000
            HTTPLog.create_from_response(HTTPLog.WHATSAPP_TEMPLATES_SYNCED,
                                         templates_url,
                                         response,
                                         channel=channel,
                                         request_time=elapsed)

            if response.status_code != 200:  # pragma: no cover
                return [], False

            template_data = response.json()["waba_templates"]
            return template_data, True
        except requests.RequestException as e:
            HTTPLog.create_from_exception(HTTPLog.WHATSAPP_TEMPLATES_SYNCED,
                                          templates_url,
                                          e,
                                          start,
                                          channel=channel)
            return [], False
Exemple #3
0
    def get_active_intents_from_api(self, classifier):
        access_token = classifier.config[self.CONFIG_ACCESS_TOKEN]

        start = timezone.now()
        try:
            response = requests.get(
                self.INTENT_URL,
                headers={"Authorization": f"Bearer {access_token}"})
            elapsed = (timezone.now() - start).total_seconds() * 1000

            HTTPLog.create_from_response(HTTPLog.INTENTS_SYNCED,
                                         self.INTENT_URL,
                                         response,
                                         classifier=classifier,
                                         request_time=elapsed)

            response.raise_for_status()
            response_json = response.json()
        except requests.RequestException as e:
            HTTPLog.create_from_exception(HTTPLog.INTENTS_SYNCED,
                                          self.INTENT_URL,
                                          e,
                                          start,
                                          classifier=classifier)
            return []

        intents = []
        for intent in response_json["intents"]:
            intents.append(Intent(name=intent, external_id=intent))

        return intents
Exemple #4
0
    def get_active_intents_from_api(self, classifier):
        """
        Gets the current intents defined by this app, in LUIS that's an attribute of the app version
        """
        app_id = classifier.config[self.CONFIG_APP_ID]
        version = classifier.config[self.CONFIG_VERSION]
        endpoint_url = classifier.config[self.CONFIG_ENDPOINT_URL]
        primary_key = classifier.config[self.CONFIG_PRIMARY_KEY]

        start = timezone.now()
        url = endpoint_url + "/apps/" + app_id + "/versions/" + version + "/intents"
        try:
            response = requests.get(url,
                                    headers={self.AUTH_HEADER: primary_key})
            elapsed = (timezone.now() - start).total_seconds() * 1000

            response.raise_for_status()

            HTTPLog.create_from_response(HTTPLog.INTENTS_SYNCED,
                                         url,
                                         response,
                                         classifier=classifier,
                                         request_time=elapsed)

            response_json = response.json()
        except requests.RequestException as e:
            HTTPLog.create_from_exception(HTTPLog.INTENTS_SYNCED,
                                          url,
                                          e,
                                          start,
                                          classifier=classifier)
            return []

        intents = []
        for intent in response_json:
            intents.append(
                Intent(name=intent["name"], external_id=intent["id"]))

        return intents
Exemple #5
0
    def get_active_intents_from_api(self, classifier):
        """
        Gets the current intents defined by this app. In Wit intents are treated as a special case of an entity. We
        fetch the possible values for that entity.
        """
        access_token = classifier.config[self.CONFIG_ACCESS_TOKEN]

        start = timezone.now()
        try:
            response = requests.get(
                self.INTENT_URL,
                headers={"Authorization": f"Bearer {access_token}"})
            elapsed = (timezone.now() - start).total_seconds() * 1000

            HTTPLog.create_from_response(HTTPLog.INTENTS_SYNCED,
                                         self.INTENT_URL,
                                         response,
                                         classifier=classifier,
                                         request_time=elapsed)

            response.raise_for_status()
            response_json = response.json()
        except requests.RequestException as e:
            HTTPLog.create_from_exception(HTTPLog.INTENTS_SYNCED,
                                          self.INTENT_URL,
                                          e,
                                          start,
                                          classifier=classifier)
            return []

        intents = []
        for intent in response_json["values"]:
            intents.append(
                Intent(name=intent["value"], external_id=intent["value"]))

        return intents
Exemple #6
0
def refresh_whatsapp_templates():
    """
    Runs across all WhatsApp templates that have connected FB accounts and syncs the templates which are active.
    """

    from .type import (
        CONFIG_FB_BUSINESS_ID,
        CONFIG_FB_ACCESS_TOKEN,
        CONFIG_FB_TEMPLATE_LIST_DOMAIN,
        LANGUAGE_MAPPING,
        STATUS_MAPPING,
        TEMPLATE_LIST_URL,
    )

    r = get_redis_connection()
    if r.get("refresh_whatsapp_templates"):  # pragma: no cover
        return

    with r.lock("refresh_whatsapp_templates", 1800):
        # for every whatsapp channel
        for channel in Channel.objects.filter(is_active=True,
                                              channel_type="WA"):
            # move on if we have no FB credentials
            if (CONFIG_FB_BUSINESS_ID not in channel.config
                    or CONFIG_FB_ACCESS_TOKEN
                    not in channel.config):  # pragma: no cover
                continue

            # fetch all our templates
            start = timezone.now()
            try:
                # Retrieve the template domain, fallback to the default for channels
                # that have been setup earlier for backwards compatibility
                facebook_template_domain = channel.config.get(
                    CONFIG_FB_TEMPLATE_LIST_DOMAIN, "graph.facebook.com")
                facebook_business_id = channel.config.get(
                    CONFIG_FB_BUSINESS_ID)
                url = TEMPLATE_LIST_URL % (facebook_template_domain,
                                           facebook_business_id)

                # we should never need to paginate because facebook limits accounts to 255 templates
                response = requests.get(
                    url,
                    params=dict(
                        access_token=channel.config[CONFIG_FB_ACCESS_TOKEN],
                        limit=255))
                elapsed = (timezone.now() - start).total_seconds() * 1000

                HTTPLog.create_from_response(HTTPLog.WHATSAPP_TEMPLATES_SYNCED,
                                             url,
                                             response,
                                             channel=channel,
                                             request_time=elapsed)

                if response.status_code != 200:  # pragma: no cover
                    continue

                # run through all our templates making sure they are present in our DB
                seen = []
                for template in response.json()["data"]:
                    # if this is a status we don't know about
                    if template["status"] not in STATUS_MAPPING:
                        logger.error(
                            f"unknown whatsapp status: {template['status']}")
                        continue

                    status = STATUS_MAPPING[template["status"]]

                    content_parts = []

                    all_supported = True
                    for component in template["components"]:
                        if component["type"] not in [
                                "HEADER", "BODY", "FOOTER"
                        ]:
                            logger.error(
                                f"unknown component type: {component}")
                            continue

                        if component["type"] in [
                                "HEADER", "FOOTER"
                        ] and _calculate_variable_count(component["text"]):
                            logger.error(
                                f"unsupported component type wih variables: {component}"
                            )
                            all_supported = False

                        content_parts.append(component["text"])

                    if not content_parts or not all_supported:
                        continue

                    content = "\n\n".join(content_parts)
                    variable_count = _calculate_variable_count(content)

                    language = LANGUAGE_MAPPING.get(template["language"])

                    # its a (non fatal) error if we see a language we don't know
                    if language is None:
                        status = TemplateTranslation.STATUS_UNSUPPORTED_LANGUAGE
                        language = template["language"]

                    translation = TemplateTranslation.get_or_create(
                        channel=channel,
                        name=template["name"],
                        language=language,
                        content=content,
                        variable_count=variable_count,
                        status=status,
                        external_id=template["id"],
                    )

                    seen.append(translation)

                # trim any translations we didn't see
                TemplateTranslation.trim(channel, seen)

            except RequestException as e:  # pragma: no cover
                HTTPLog.create_from_exception(
                    HTTPLog.WHATSAPP_TEMPLATES_SYNCED,
                    url,
                    e,
                    start,
                    channel=channel)