Compare commits

..

2 commits

2 changed files with 83 additions and 39 deletions

View file

@ -5,6 +5,7 @@ import json
import os import os
import pickle import pickle
import sys import sys
import html2text
from zammad_py import ZammadAPI from zammad_py import ZammadAPI
from zammad_py.api import Resource, TagList, TicketArticle from zammad_py.api import Resource, TagList, TicketArticle
@ -55,15 +56,20 @@ def get_zammad_session(impersonated_user=None):
def maybe_create_zammad_user(userdata, zammad_session, attr="login", default=None): def maybe_create_zammad_user(userdata, zammad_session, attr="login", default=None):
# Map disabled users (in RT) to mock user in Zammad. # Map disabled users (in RT) to mock user in Zammad.
if type(userdata) is str or "EmailAddress" not in userdata: if type(userdata) is str and userdata.lower() in USERMAP:
email = userdata
elif type(userdata) is str or "EmailAddress" not in userdata:
userdata = { userdata = {
'EmailAddress': 'technik@ungleich.ch', 'EmailAddress': 'technik@ungleich.ch',
'RealName': 'Disabled RT' 'RealName': 'Disabled RT'
} }
email = userdata["EmailAddress"]
elif "EmailAddress" in userdata:
email = userdata["EmailAddress"]
else:
raise ValueError("Invalid userdata")
email = userdata["EmailAddress"]
lowercase_email = email.lower() lowercase_email = email.lower()
if lowercase_email not in USERMAP: if lowercase_email not in USERMAP:
kwargs = {"email": email} kwargs = {"email": email}
kwargs.update(config["userdata"]) kwargs.update(config["userdata"])
@ -95,6 +101,15 @@ def maybe_create_zammad_user(userdata, zammad_session, attr="login", default=Non
return USERMAP[lowercase_email].get(attr, default) return USERMAP[lowercase_email].get(attr, default)
# def ensure_user_is_zammad_agent(user, zammad_session):
# print(f"Promoting user {user} to Agent")
# id = maybe_create_zammad_user(user, zammad_session, "id")
# roles = maybe_create_zammad_user(user, zammad_session, "roles")
# if "Agent" not in roles:
# zammad_session.user.update(
# id, {"roles": roles.append("Agent")}
# )
### main logic ### ### main logic ###
if not os.path.exists("rt2zammad.json"): if not os.path.exists("rt2zammad.json"):
@ -106,6 +121,7 @@ if not os.path.exists("rt2zammad.json"):
with open("rt2zammad.json") as handle: with open("rt2zammad.json") as handle:
config = json.load(handle) config = json.load(handle)
h2t = html2text.HTML2Text()
zammad = get_zammad_session() zammad = get_zammad_session()
os.makedirs("users", exist_ok=True) os.makedirs("users", exist_ok=True)
@ -188,33 +204,56 @@ for id in ticket_ids:
# Attachments. # Attachments.
files = [] files = []
may_contain_entry_content = None
for a, title in entry["Attachments"]: for a, title in entry["Attachments"]:
with open(f"attachments/{id}/{a}", "rb") as handle: with open(f"attachments/{id}/{a}", "rb") as handle:
data = pickle.load(handle) data = pickle.load(handle)
if data["Filename"] in ("", "signature.asc"): if data["Filename"] == "signature.asc":
continue continue
files.append(
{ file_template = {
"filename": data["Filename"], "filename": data["Filename"],
"data": base64.b64encode(data["Content"]).decode("utf-8"), "data": base64.b64encode(data["Content"]).decode("utf-8"),
"mime-type": data["ContentType"], "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. # Comment/note.
entry_creator = entry["Creator"] entry_creator = entry["Creator"]
with open(f"users/{entry_creator}", "rb") as handle: with open(f"users/{entry_creator}", "rb") as handle:
rt_entry_creator = pickle.load(handle) rt_entry_creator = pickle.load(handle)
zammad_creator = maybe_create_zammad_user(rt_entry_creator, zammad) 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 = { zammad_entry_template = {
"ticket_id": zammad_ticket["id"], "ticket_id": zammad_ticket["id"],
"body": entry["Content"], "body": entry_content,
"internal": entry["Type"] == "Comment", "internal": entry["Type"] == "Comment",
"attachments": files, "attachments": files,
} }
try: entry_creator_id = maybe_create_zammad_user(zammad_entry_creator, zammad, "id")
TicketArticle(get_zammad_session(zammad_creator)).create(zammad_entry_template)
except: # We temporarly change the ticket's creator to create a new entry
print(f"FIXME: Failed to add comment to ticket RT#{id}/Zammad#{zammad_ticket["id"]}: user permission issue?") # without giving its author 'Agent' privileges.
restore_creator_to = None
if entry_creator_id != zammad_ticket["customer_id"]:
zammad_ticket = zammad.ticket.update(zammad_ticket["id"], {"customer_id": entry_creator_id})
restore_creator_to = zammad_ticket["customer_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})

57
rt2fs
View file

@ -52,34 +52,39 @@ os.makedirs("attachments", exist_ok=True)
ticket_ids = range(config["rt_start"], config["rt_end"]) ticket_ids = range(config["rt_start"], config["rt_end"])
def dump(id): def dump(id, retries=3):
print(f"Dumping RT#{id}") print(f"Dumping RT#{id}")
ticket_dumpfile = f"tickets/{id}" try:
if not os.path.exists(ticket_dumpfile): ticket_dumpfile = f"tickets/{id}"
ticket = rt.get_ticket(id) if not os.path.exists(ticket_dumpfile):
if ticket is None: ticket = rt.get_ticket(id)
print("Got 'None' while fetching ticket") if ticket is None:
os.exit(1) print("Got 'None' while fetching ticket")
ticket["original_id"] = str(id) os.exit(1)
if ticket["Queue"] != 'spam': ticket["original_id"] = str(id)
maybe_dump_user(rt, ticket["Creator"]) if ticket["Queue"] != 'spam':
maybe_dump_user(rt, ticket["Owner"]) maybe_dump_user(rt, ticket["Creator"])
maybe_dump_user(rt, ticket["Owner"])
if ticket["original_id"] != ticket["numerical_id"]: if ticket["original_id"] != ticket["numerical_id"]:
# Merged ticket # Merged ticket
history = [] history = []
else: else:
history = rt.get_history(id) history = rt.get_history(id)
for item in history: for item in history:
for a, title in item["Attachments"]: for a, title in item["Attachments"]:
attachment = rt.get_attachment(id, a) attachment = rt.get_attachment(id, a)
os.makedirs(f"attachments/{id}", exist_ok=True) os.makedirs(f"attachments/{id}", exist_ok=True)
with open(f"attachments/{id}/{a}", "wb") as handle: with open(f"attachments/{id}/{a}", "wb") as handle:
pickle.dump(attachment, handle) pickle.dump(attachment, handle)
maybe_dump_user(rt, item["Creator"]) maybe_dump_user(rt, item["Creator"])
data = {"ticket": ticket, "history": history} data = {"ticket": ticket, "history": history}
with open(ticket_dumpfile, "wb") as handle: with open(ticket_dumpfile, "wb") as handle:
pickle.dump(data, handle) pickle.dump(data, handle)
except:
print(f"Failed to dump RT#{id}.. ({retries} retries left)")
if retries > 0:
dump(id, retries - 1)
worker_count = 4 worker_count = 4
with Pool(worker_count) as p: with Pool(worker_count) as p: