From 807ed89c08eeca9069beaea9fefe7ea876acd19e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Thu, 2 May 2024 16:27:50 +0200 Subject: [PATCH] [fs2zammad] retry import due to unpredictable 503 --- fs2zammad | 229 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 118 insertions(+), 111 deletions(-) diff --git a/fs2zammad b/fs2zammad index 728c9af..34ab4cb 100755 --- a/fs2zammad +++ b/fs2zammad @@ -110,133 +110,141 @@ def maybe_create_zammad_user(userdata, zammad_session, attr="login", default=Non # id, {"roles": roles.append("Agent")} # ) -def create_zammad_ticket(id, zammad, h2t): - with open(f"tickets/{id}", "rb") as handle: - rt_ticket = pickle.load(handle) +def create_zammad_ticket(id, zammad, h2t, retries=3): + try: + with open(f"tickets/{id}", "rb") as handle: + rt_ticket = pickle.load(handle) - label = "RT-{}".format(rt_ticket["ticket"]["original_id"]) - creator = rt_ticket["ticket"]["Creator"] - with open(f"users/{creator}", "rb") as handle: - rt_creator = pickle.load(handle) + label = "RT-{}".format(rt_ticket["ticket"]["original_id"]) + creator = rt_ticket["ticket"]["Creator"] + with open(f"users/{creator}", "rb") as handle: + rt_creator = pickle.load(handle) - # The RT user object doesn't always contain everything (e.g. disabled users). - if "EmailAddress" in rt_creator: - creator = rt_creator["EmailAddress"] - print(f"Importing {label} ({creator})") + # The RT user object doesn't always contain everything (e.g. disabled users). + if "EmailAddress" in rt_creator: + creator = rt_creator["EmailAddress"] + print(f"Importing {label} ({creator})") - zammad_creator = maybe_create_zammad_user(rt_creator, zammad) + zammad_creator = maybe_create_zammad_user(rt_creator, zammad) - # Make sure that we use what we created in Zammad, independently of what we - # had in RT. - creator = zammad_creator + # Make sure that we use what we created in Zammad, independently of what we + # had in RT. + creator = zammad_creator - zammad_ticket_template = { - "title": rt_ticket["ticket"]["Subject"], - "group": "Users", - "customer": creator, - "note": "RT-import:{}".format(rt_ticket["ticket"]["original_id"]), - "article": { - "subject": rt_ticket["ticket"]["Subject"], - }, - } + zammad_ticket_template = { + "title": rt_ticket["ticket"]["Subject"], + "group": "Users", + "customer": creator, + "note": "RT-import:{}".format(rt_ticket["ticket"]["original_id"]), + "article": { + "subject": rt_ticket["ticket"]["Subject"], + }, + } - # Ticket creation. - merged = False - if rt_ticket["ticket"]["original_id"] != rt_ticket["ticket"]["numerical_id"]: - merged = True - zammad_ticket_template["state_id"] = STATUSMAP["resolved"] - zammad_ticket_template["article"]["body"] = "RT ticket merged into {}".format( - rt_ticket["ticket"]["numerical_id"] - ) - zammad_ticket = get_zammad_session(creator).ticket.create(zammad_ticket_template) - else: - zammad_ticket_template["state_id"] = STATUSMAP[rt_ticket["ticket"]["Status"]] - body = rt_ticket["history"][0]["Content"] or 'RT Import: empty comment.' - zammad_ticket_template["article"]["body"] = body - zammad_ticket = get_zammad_session(creator).ticket.create(zammad_ticket_template) + # Ticket creation. + merged = False + if rt_ticket["ticket"]["original_id"] != rt_ticket["ticket"]["numerical_id"]: + merged = True + zammad_ticket_template["state_id"] = STATUSMAP["resolved"] + zammad_ticket_template["article"]["body"] = "RT ticket merged into {}".format( + rt_ticket["ticket"]["numerical_id"] + ) + zammad_ticket = get_zammad_session(creator).ticket.create(zammad_ticket_template) + else: + zammad_ticket_template["state_id"] = STATUSMAP[rt_ticket["ticket"]["Status"]] + body = rt_ticket["history"][0]["Content"] or 'RT Import: empty comment.' + zammad_ticket_template["article"]["body"] = body + zammad_ticket = get_zammad_session(creator).ticket.create(zammad_ticket_template) - print(f"Created Zammad ticket {zammad_ticket['id']} for {label}") + print(f"Created Zammad ticket {zammad_ticket['id']} for {label}") - if rt_ticket["ticket"]["Owner"] and rt_ticket["ticket"]["Owner"] != "Nobody": - zammad_owner_id = maybe_create_zammad_user(rt_ticket["ticket"]["Owner"], zammad, "id") - zammad.ticket.update( - zammad_ticket["id"], {"owner_id": zammad_owner_id} + if rt_ticket["ticket"]["Owner"] and rt_ticket["ticket"]["Owner"] != "Nobody": + zammad_owner_id = maybe_create_zammad_user(rt_ticket["ticket"]["Owner"], zammad, "id") + zammad.ticket.update( + zammad_ticket["id"], {"owner_id": zammad_owner_id} + ) + + # Ignore comments for merged tickets. + if merged: + return + + # Internal note regarding the RT-Zammad import. + TicketArticle(zammad).create( + { + "ticket_id": zammad_ticket["id"], + "body": COMMENT_TEMPLATE.format(**rt_ticket["ticket"]), + "internal": True, + } ) - # Ignore comments for merged tickets. - if merged: - return - - # Internal note regarding the RT-Zammad import. - TicketArticle(zammad).create( - { - "ticket_id": zammad_ticket["id"], - "body": COMMENT_TEMPLATE.format(**rt_ticket["ticket"]), - "internal": True, - } - ) - - # Comments/notes within the ticket. - for entry in rt_ticket["history"]: - if entry["Type"] not in ("Correspond", "Comment"): - continue - - # Attachments. - files = [] - may_contain_entry_content = None - for a, title in entry["Attachments"]: - with open(f"attachments/{id}/{a}", "rb") as handle: - data = pickle.load(handle) - - if data["Filename"] == "signature.asc": + # Comments/notes within the ticket. + for entry in rt_ticket["history"]: + if entry["Type"] not in ("Correspond", "Comment"): continue - file_template = { - "filename": data["Filename"], - "data": base64.b64encode(data["Content"]).decode("utf-8"), - "mime-type": data["ContentType"], - } + # Attachments. + files = [] + may_contain_entry_content = None + for a, title in entry["Attachments"]: + with open(f"attachments/{id}/{a}", "rb") as handle: + data = pickle.load(handle) - if data["Filename"] == '': - if may_contain_entry_content is None: - may_contain_entry_content = file_template - else: - files.append(file_template) + if data["Filename"] == "signature.asc": + continue + + file_template = { + "filename": data["Filename"], + "data": base64.b64encode(data["Content"]).decode("utf-8"), + "mime-type": data["ContentType"], + } + + if data["Filename"] == '': + if may_contain_entry_content is None: + may_contain_entry_content = file_template + else: + files.append(file_template) - # Comment/note. - entry_creator = entry["Creator"] - with open(f"users/{entry_creator}", "rb") as handle: - rt_entry_creator = pickle.load(handle) + # Comment/note. + entry_creator = entry["Creator"] + with open(f"users/{entry_creator}", "rb") as handle: + rt_entry_creator = pickle.load(handle) - zammad_entry_creator = maybe_create_zammad_user(rt_entry_creator, zammad) - entry_content = entry["Content"] - if entry_content == '' and may_contain_entry_content: - file = may_contain_entry_content - entry_content = base64.b64decode(file["data"]).decode("utf-8") - if file["mime-type"]: - entry_content = h2t.handle(entry_content) + zammad_entry_creator = maybe_create_zammad_user(rt_entry_creator, zammad) + entry_content = entry["Content"] + if entry_content == '' and may_contain_entry_content: + file = may_contain_entry_content + entry_content = base64.b64decode(file["data"]).decode("utf-8") + if file["mime-type"]: + entry_content = h2t.handle(entry_content) - zammad_entry_template = { - "ticket_id": zammad_ticket["id"], - "body": entry_content, - "internal": entry["Type"] == "Comment", - "attachments": files, - } - entry_creator_id = maybe_create_zammad_user(zammad_entry_creator, zammad, "id") + zammad_entry_template = { + "ticket_id": zammad_ticket["id"], + "body": entry_content, + "internal": entry["Type"] == "Comment", + "attachments": files, + } + entry_creator_id = maybe_create_zammad_user(zammad_entry_creator, zammad, "id") - # We temporarly change the ticket's creator to create a new entry - # without giving its author 'Agent' privileges. - restore_creator_to = None - if entry_creator_id != zammad_ticket["customer_id"]: - zammad.ticket.update(zammad_ticket["id"], {"customer_id": entry_creator_id}) - restore_creator_to = zammad_ticket["customer_id"] + # We temporarly change the ticket's creator to create a new entry + # without giving its author 'Agent' privileges. + restore_creator_to = None + if entry_creator_id != zammad_ticket["customer_id"]: + zammad.ticket.update(zammad_ticket["id"], {"customer_id": entry_creator_id}) + restore_creator_to = zammad_ticket["customer_id"] - zammad_ticket_id = zammad_ticket["id"] - print(f"-> Adding a new entry/comment to ticket {zammad_ticket_id} ({zammad_entry_creator})...") - TicketArticle(get_zammad_session(zammad_entry_creator)).create(zammad_entry_template) + zammad_ticket_id = zammad_ticket["id"] + print(f"-> Adding a new entry/comment to ticket {zammad_ticket_id} ({zammad_entry_creator})...") + TicketArticle(get_zammad_session(zammad_entry_creator)).create(zammad_entry_template) - if restore_creator_to != None: - zammad.ticket.update(zammad_ticket["id"], {"customer_id": restore_creator_to}) + if restore_creator_to != None: + zammad.ticket.update(zammad_ticket["id"], {"customer_id": restore_creator_to}) + except KeyboardInterrupt: + print("Received keyboard interrupt. Exiting.") + sys.exit() + except: + print(f"Failed to import RT-#{id} .. ({retries} retries left)") + if retries > 0: + create_zammad_ticket(id, zammad, h2t, retries - 1) ### main logic ### @@ -262,9 +270,8 @@ print(f"Found {len(ticket_ids)} tickets on filesystem.") for id in ticket_ids: try: - create_zammad_ticket(id, zammad, h2t) - except KeyboardInterrupt: - print("Received keyboard interrupt. Exiting.") + create_zammad_ticket(id, zammad, h2t, 3) + except SystemExit: sys.exit() except: print(f"Failed to import RT#{id}")