111 lines
2.8 KiB
Text
111 lines
2.8 KiB
Text
|
#!/usr/bin/env python
|
||
|
|
||
|
import base64
|
||
|
import json
|
||
|
import os
|
||
|
import pickle
|
||
|
import sys
|
||
|
import html2text
|
||
|
import traceback
|
||
|
import time
|
||
|
|
||
|
from zammad_py import ZammadAPI
|
||
|
from zammad_py.api import Resource, TagList, TicketArticle
|
||
|
|
||
|
TEMPLATE = """{
|
||
|
"zammad_url": "",
|
||
|
"zammad_user": "",
|
||
|
"zammad_password": "",
|
||
|
"rt_url": "",
|
||
|
"rt_user": "",
|
||
|
"rt_pass": "",
|
||
|
"rt_start": 1,
|
||
|
"rt_end": 1000,
|
||
|
}
|
||
|
"""
|
||
|
|
||
|
COMMENT_TEMPLATE = """
|
||
|
Ticket imported from Request Tracker (RT-#{numerical_id})
|
||
|
|
||
|
URL: https://support.ungleich.ch/Ticket/Display.html?id={numerical_id}
|
||
|
Created: {Created}
|
||
|
Resolved: {Resolved}
|
||
|
"""
|
||
|
|
||
|
STATUSMAP = {"new": 1, "open": 2, "resolved": 4, "rejected": 4, "deleted": 4}
|
||
|
USERMAP = {}
|
||
|
|
||
|
ZAMMAD_SESSIONS = {}
|
||
|
|
||
|
### helpers ###
|
||
|
|
||
|
def get_zammad_session(impersonated_user=None):
|
||
|
if impersonated_user in ZAMMAD_SESSIONS:
|
||
|
return ZAMMAD_SESSIONS[impersonated_user]
|
||
|
else:
|
||
|
kwargs = {}
|
||
|
if impersonated_user:
|
||
|
kwargs["on_behalf_of"] = impersonated_user
|
||
|
session = ZammadAPI(
|
||
|
url=config["zammad_host"],
|
||
|
username=config["zammad_user"],
|
||
|
password=config["zammad_password"],
|
||
|
**kwargs,
|
||
|
)
|
||
|
ZAMMAD_SESSIONS[impersonated_user or config["zammad_user"]] = session
|
||
|
|
||
|
return session
|
||
|
|
||
|
def remove_duplicates_for(rt_id, zammad, retries=0):
|
||
|
try:
|
||
|
matching_zammad_tickets= zammad.ticket.search(f"title: \"\[RT-{rt_id}\]*\"")
|
||
|
matching_zammad_ids = []
|
||
|
if len(matching_zammad_tickets) >= 2:
|
||
|
print(f"Found duplicates:")
|
||
|
for zt in matching_zammad_tickets:
|
||
|
print(f"{zt["id"]} {zt["title"]}")
|
||
|
matching_zammad_ids.append(zt["id"])
|
||
|
|
||
|
if len(matching_zammad_ids) >= 2:
|
||
|
matching_zammad_ids.sort()
|
||
|
matching_zammad_ids.pop()
|
||
|
for zt_id in matching_zammad_ids:
|
||
|
print(f"Deleting Zammad ticket {zt_id}")
|
||
|
zammad.ticket.destroy(zt_id)
|
||
|
|
||
|
except:
|
||
|
print(f"Failed to process RT-{rt_id} .. ({retries} retries left)")
|
||
|
if retries > 0:
|
||
|
print("Sleeping 5 seconds to give Zammad some air...")
|
||
|
time.sleep(5)
|
||
|
remove_duplicates_for(id, retries - 1)
|
||
|
else:
|
||
|
traceback.print_exc()
|
||
|
raise RuntimeError
|
||
|
|
||
|
### main logic ###
|
||
|
|
||
|
if not os.path.exists("rt2zammad.json"):
|
||
|
print("Missing rt2zammad.json!")
|
||
|
print("Create one based on following template:")
|
||
|
print(TEMPLATE)
|
||
|
sys.exit(1)
|
||
|
|
||
|
with open("rt2zammad.json") as handle:
|
||
|
config = json.load(handle)
|
||
|
|
||
|
h2t = html2text.HTML2Text()
|
||
|
zammad = get_zammad_session()
|
||
|
|
||
|
os.makedirs("tickets", exist_ok=True)
|
||
|
|
||
|
|
||
|
ticket_ids = os.listdir("tickets/")
|
||
|
print(f"Found {len(ticket_ids)} tickets on filesystem.")
|
||
|
ticket_ids = list(map(int, ticket_ids))
|
||
|
ticket_ids.sort()
|
||
|
|
||
|
for id in ticket_ids:
|
||
|
print(f"Processing RT-{id}...")
|
||
|
remove_duplicates_for(id, zammad)
|