Почему мои макросы ZenDesk обновляются, но никаких изменений на самом деле не происходит?

Я пытался массово редактировать подпись моих личных макросов в ZenDesk, и единственный способ сделать это - через API. Поэтому я написал этот быстрый скрипт на Python, чтобы попытаться это сделать:

import sys
import time
import logging
import requests
import re

start_time = time.time()

# Set up logging
logger = logging.getLogger()
log_handler = logging.StreamHandler(sys.stdout)
log_handler.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s - %(funcName)s - line %(lineno)d"))
log_handler.setLevel(logging.DEBUG)
logger.addHandler(log_handler)
logger.setLevel(logging.DEBUG)

def doTheGet(url, user, pwd):
        response = requests.get(url, auth=(user + "/token", pwd))

        if response.status_code != 200:
                logger.error("Status: %s (%s) Problem with the request. Exiting. %f seconds elapsed" % (response.status_code, response.reason, time.time() - start_time))
                exit()

        data = response.json()
        return data

def doThePut(url, updated_data, user, pwd):
        response = requests.put(url, json="{'macro': {'actions': %r}}" % updated_data, headers={"Content-Type": "application/json"}, auth=(user + "/token", pwd))

        if response.status_code != 200:
                logger.error("Status: %s (%s) Problem with the request. Exiting. %f seconds elapsed" % (response.status_code, response.reason, time.time() - start_time))
                exit()

        data = response.json()
        return data

def getMacros():
        macros = {}

        data = doTheGet("https://mydomain.zendesk.com/api/v2/macros.json", "me@mydomain.com", "111tokenZZZ")

        def getMacros(macro_list, page, page_count):
                if not page:
                        for macro in macro_list:
                                if macro["restriction"] and macro["active"]:
                                        if macro["restriction"]["type"] == "User":
                                                macros[macro["id"]] = macro["actions"]
                else:
                        for macro in macro_list:
                                if macro["restriction"] and macro["active"]:
                                        if macro["restriction"]["type"] == "User":
                                                macros[macro["id"]] = macro["actions"]

                        page_count += 1
                        new_data = doTheGet(page, "me@mydomain.com", "111tokenZZZ")
                        new_macs = new_data["macros"]
                        new_next_page = new_data["next_page"]
                        getMacros(new_macs, new_next_page, page_count)


        macs = data["macros"]
        current_page = 1
        next_page = data["next_page"]
        getMacros(macs, next_page, current_page)
        return macros

def updateMacros():
        macros = getMacros()

        regular = "RegEx to match signature to be replaced$" #since some macros already have the updated signature

        for macro in macros:
                for action in macros[macro]:
                        if action["field"] == "comment_value":
                                if re.search(regular, action["value"][1]):
                                        ind = action["value"][1].rfind("\n")
                                        action["value"][1] = action["value"][1][:ind] + "\nNew signature"

        return macros

macs = updateMacros()

for mac in macs:
        doThePut("https://mydomain.zendesk.com/api/v2/macros/%d.json" % (mac), macs[mac], "me@mydomain.com", "111tokenZZZ")

Теперь все работает, как ожидалось, и я не получаю ошибок. Когда я захожу к своим макросам в ZenDesk и сортирую их по последнему обновлению, я вижу, что скрипт что-то сделал, так как они отображаются как последние обновленные сегодня. Тем не менее, ничего не меняется на них. Я убедился, что данные, которые я отправляю, отредактированы (updateMacros делает свою работу). Я удостоверился, что запросы посылают ответ OK. Поэтому я отправляю обновленные данные, получаю ответ 200, но отправленный ответ показывает мне макросы, какими они были раньше, с нулевыми изменениями.

Единственное, что мне кажется неправильным - это формат данных, которые я посылаю, или что-то в этом роде. Но даже тогда я ожидаю, что ответ не будет 200, тогда...

Что мне здесь не хватает?

1 ответ

Решение

Похоже, вы дважды кодируете данные JSON в вашем запросе PUT:

response = requests.put(url, json="{'macro': {'actions': %r}}" % updated_data, headers={"Content-Type": "application/json"}, auth=(user + "/token", pwd))

Параметр json ожидает объект, который затем покорно кодируется как JSON и отправляется как тело запроса; это просто удобство; реализация просто,

    if not data and json is not None:
        # urllib3 requires a bytes-like body. Python 2's json.dumps
        # provides this natively, but Python 3 gives a Unicode string.
        content_type = 'application/json'
        body = complexjson.dumps(json)
        if not isinstance(body, bytes):
            body = body.encode('utf-8')

(источник: https://github.com/kennethreitz/requests/blob/master/requests/models.py)

Поскольку значение всегда передается через json.dumps(), если вы передадите строку, представляющую уже закодированный JSON, она сама будет закодирована:

"{\'macro\': {\'actions\': [{\'field\': \'comment_value\', \'value\': [\'channel:all\', \'Spiffy New Sig that will Never Be Saved\']}]}}"

ZenDesk, получив JSON, которого он не ожидает, обновляет updated_at поле и... больше ничего не делает. Вы можете проверить это, передав пустую строку - тот же результат.

Обратите внимание, что вы также полагаетесь на форматирование repr Python для заполнения вашего JSON; это тоже плохая идея. Вместо этого давайте просто восстановим наш макро-объект и разрешим запросам его кодировать:

response = requests.put(url, json={'macro': {'actions': updated_data}}, headers={"Content-Type": "application/json"}, auth=(user + "/token", pwd))

Это должно делать то, что вы ожидаете.

Другие вопросы по тегам