Почему мои макросы 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))
Это должно делать то, что вы ожидаете.