コード例 #1
0
def slack_dialog(request):  # noqa: C901

    json_payload, slack_settings = validate_slack_request(request)

    # An error occured in validate_slack_response.  So we return a 200
    # and tell Slack to not retry.
    if slack_settings is None:
        response = HttpResponse(status=200)
        response["X-Slack-No-Retry"] = "1"
        return response

    customer = slack_settings.customer

    channel_id = json_payload["channel"]["id"]
    payload_type = json_payload["type"]

    headers = {"Content-Type": "application/json; charset=utf-8"}

    if payload_type == "block_actions":
        # Yes or No button has been clicked

        if json_payload["actions"][0]["text"]["text"] == "No":
            # "No" Button clicked - delete ephemeral message
            delete_ephemeral_message(
                json_payload["container"]["message_ts"],
                json_payload["response_url"],
                headers,
            )

        else:
            # "Yes" button clicked - show dialog

            trigger_id = json_payload["trigger_id"]

            # message_ts is the pointer to the message we care about adding to Savio, NOT the timestamp
            # of the response to the Yes/No ephemeral message that just got POSTed
            message_ts = json_payload["actions"][0]["value"]

            # Get Message so we can display "problem" as a default in the Dialog's problem textarea
            message_url = "https://slack.com/api/channels.history"
            message_json = {
                "oldest": message_ts,
                "count": 1,
                "inclusive": True,
                "channel": channel_id,
            }

            headers = {
                "Content-Type":
                "application/x-www-form-urlencoded;",
                "Authorization":
                "Bearer " + slack_settings.slack_user_access_token,
            }
            response = requests.post(message_url,
                                     data=message_json,
                                     headers=headers)

            if not response.json()["ok"]:
                capture_message(
                    f"Error getting Slack Message: message.json: {response.json()}. slack_settings_id: {slack_settings.id}."
                )
                response = HttpResponse(status=200)
                response["X-Slack-No-Retry"] = "1"
                return response
            else:
                message = response.json()["messages"][0]["text"]

            dialog_json = get_dialog_json(trigger_id,
                                          "show_create_feedback_dialog",
                                          message_ts, message, customer)

            headers = {
                "Content-Type": "application/json; charset=utf-8",
                "Authorization": "Bearer " + slack_settings.slack_bot_token,
            }

            dialog_url = "https://slack.com/api/dialog.open"
            response = requests.post(dialog_url,
                                     data=json.dumps(dialog_json),
                                     headers=headers)

            if not response.json()["ok"]:
                capture_message(
                    f"Error generating Slack dialog: response.json: {response.json()}. message: {message}. message_ts: {message_ts}. slack_settings_id: {slack_settings.id}"
                )
                response = HttpResponse(status=200)
                response["X-Slack-No-Retry"] = "1"
                return response

            delete_ephemeral_message(
                json_payload["container"]["message_ts"],
                json_payload["response_url"],
                headers,
            )

    else:
        # Dialog initiated by message action
        callback_id = json_payload["callback_id"]

        if callback_id == "show_create_feedback_dialog":
            if payload_type == "dialog_submission":

                # Saving a Posted Dialog

                slack_user_name = json_payload["user"]["name"]
                slack_user_id = json_payload["user"]["id"]
                problem = json_payload["submission"]["problem"]
                person = json_payload["submission"]["person"]
                new_person_email = json_payload["submission"][
                    "new_person_email"]
                feedback_from = json_payload["submission"]["feedback_from"]
                feature_request = json_payload["submission"]["feature_request"]
                response_url = json_payload["response_url"]

                # Validate submitted data
                errors = {"errors": []}
                if not problem:
                    errors["errors"].append({
                        "name":
                        "problem",
                        "error":
                        "Can't be blank. Please try again.",
                    })

                if not feedback_from:
                    errors["errors"].append({
                        "name":
                        "feedback_from",
                        "error":
                        "Can't be blank. Please try again.",
                    })

                if not (person or new_person_email):

                    errors["errors"].append({
                        "name":
                        "person",
                        "error":
                        "You need to select an existing or new person.",
                    })
                    errors["errors"].append({
                        "name":
                        "new_person_email",
                        "error":
                        "You need to select an existing or new person.",
                    })

                if len(errors["errors"]) > 0:
                    capture_message(
                        f"Invalid params submitted from Slack. problem: {problem}. person: {person}. feedback_from: {feedback_from}"
                    )
                    return JsonResponse(errors)

                # To post to the Slack channel, we first need to get the permalink of the parent message.
                permalink_url = "https://slack.com/api/chat.getPermalink"
                shared_ts = json_payload["state"]

                # Add Auth header to headers. We don't need it for previous posts to response_url, but we do
                # post web API methods like chat.getPermalink
                headers[
                    "Authorization"] = "Bearer " + slack_settings.slack_bot_token

                permalink_params = {
                    "channel": channel_id,
                    "message_ts": shared_ts
                }
                permalink_response = requests.post(permalink_url,
                                                   params=permalink_params,
                                                   headers=headers).json()

                if not permalink_response["ok"]:

                    params = {
                        "text":
                        "There was an error saving your feedback.  Please try again.",
                    }
                    requests.post(response_url,
                                  data=json.dumps(params),
                                  headers=headers)

                    capture_message(
                        f"Invalid permalink from Slack. channel: {channel_id}. message timestamp: {shared_ts}. "
                    )
                    return HttpResponse(status=406)

                message_permalink = permalink_response["permalink"]

                # Look up User. The user in Slack likely won't have a row in our users table.
                if slack_settings.slack_user_id == slack_user_id:
                    u = slack_settings.user
                else:
                    u = None

                # Are we creating a new person, or using an existing one?  Figure it out.
                if person:
                    use_person_id = person
                else:
                    # handle case where email entered but user exists.
                    try:
                        user = AppUser.objects.get(email=new_person_email,
                                                   customer_id=customer.id)
                    except AppUser.DoesNotExist:
                        user = AppUser.objects.create(email=new_person_email,
                                                      customer_id=customer.id)

                    use_person_id = user.id

                # Save feedback to DB
                feedback = Feedback(
                    customer=customer,
                    source_url=message_permalink,
                    problem=problem,
                    feedback_type=feedback_from,
                    feature_request_id=feature_request,
                    user_id=use_person_id,
                    source_username=slack_user_name,
                    created_by=u,
                )
                feedback.save()

                if u:
                    user_id = u.id
                else:
                    user_id = f"Slack - {slack_user_id}"

                tracking.feedback_created(user_id, customer, feedback,
                                          tracking.EVENT_SOURCE_SLACK)

                # Then, we'll post a reply to the message as part of a thread
                post_message_url = "https://slack.com/api/chat.postMessage"

                now = datetime.datetime.now()
                unix_time = now.timestamp()

                savio_feedback_url = settings.HOST + feedback.get_absolute_url(
                )

                date_string = ("<!date^" + repr(int(unix_time)) +
                               "^{date} at {time}^" + savio_feedback_url +
                               "|" + now.strftime("%b %d %Y at %I:%M %p") +
                               ">")

                company_str = ""
                if feedback.user.company:
                    company_str = f" @ {feedback.user.company.name}"

                fr_string = "None"
                if feedback.feature_request is not None:
                    fr_url = settings.HOST + reverse(
                        "feature-request-feedback-details",
                        kwargs={"pk": feedback.feature_request.id},
                    )
                    fr_string = f"<{fr_url}|{feedback.feature_request.title}>"

                # This Code creates a payload to reply in a thread with the original message as the parent
                reply_json = {
                    "channel":
                    channel_id,
                    "as_user":
                    False,
                    "link_names":
                    True,
                    "mrkdwn":
                    True,
                    "unfurl_links":
                    True,
                    "thread_ts":
                    shared_ts,
                    "blocks": [
                        {
                            "type":
                            "context",
                            "elements": [
                                {
                                    "type":
                                    "mrkdwn",
                                    "text":
                                    f"@{slack_user_name} pushed this customer feedback to Savio on {date_string}:",
                                },
                            ],
                        },
                        {
                            "type": "section",
                            "text": {
                                "type":
                                "mrkdwn",
                                "text":
                                f"*From*\n{feedback.user.get_name_or_email()}{company_str} ({dict(feedback.TYPE_CHOICES)[feedback.feedback_type]})\n\n*Feedback*\n{problem}\n\n*Feature Request*\n{fr_string}",
                            },
                        },
                    ],
                }
                # End Code posts a response to the Slack Channel with the message posted to Savio

                response = requests.post(post_message_url,
                                         data=json.dumps(reply_json),
                                         headers=headers)

            elif payload_type == "message_action":

                # Show a Dialog
                trigger_id = json_payload["trigger_id"]
                message = json_payload["message"]["text"]
                message_ts = json_payload["message_ts"]

                dialog_json = get_dialog_json(trigger_id, callback_id,
                                              message_ts, message, customer)

                headers = {
                    "Content-Type": "application/json; charset=utf-8",
                    "Authorization":
                    "Bearer " + slack_settings.slack_bot_token,
                }

                dialog_url = "https://slack.com/api/dialog.open"
                response = requests.post(dialog_url,
                                         data=json.dumps(dialog_json),
                                         headers=headers)

    return Response(status=status.HTTP_200_OK)