From 06b42d042bcdbfd74030b0905ca4b52af6829677 Mon Sep 17 00:00:00 2001 From: kjg Date: Fri, 2 Aug 2024 15:18:40 +0900 Subject: [PATCH 1/9] [rt2zammad] update range and except duplicated ticket --- fs2zammad | 9 ++++++++- zammad-duplicates-cleanup | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/fs2zammad b/fs2zammad index 3f65a7a..e5669bd 100755 --- a/fs2zammad +++ b/fs2zammad @@ -169,7 +169,6 @@ def create_zammad_ticket(id, zammad, h2t, retries=3): zammad_ticket = zammad.ticket.create(zammad_ticket_template) 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( @@ -281,6 +280,9 @@ if not os.path.exists("rt2zammad.json"): with open("rt2zammad.json") as handle: config = json.load(handle) +rt_start = config["rt_start"] +rt_end = config["rt_end"] + h2t = html2text.HTML2Text() zammad = get_zammad_session() @@ -294,9 +296,14 @@ ticket_ids = os.listdir("tickets/") print(f"Found {len(ticket_ids)} tickets on filesystem.") ticket_ids = list(map(int, ticket_ids)) ticket_ids.sort() +ticket_ids = list(map(int, ticket_ids[rt_start:rt_end])) for id in ticket_ids: try: + matching_zammad_tickets= zammad.ticket.search(f"title: \"\[RT-{id}\]*\"") + if len(matching_zammad_tickets) >= 1: + print(f"Found duplicates: {id}") + continue zammad_ticket_id = create_zammad_ticket(id, zammad, h2t, 5) dumpfile = f"processed/{id}" with open(dumpfile, "w") as handle: diff --git a/zammad-duplicates-cleanup b/zammad-duplicates-cleanup index 89d0888..6da9cd4 100755 --- a/zammad-duplicates-cleanup +++ b/zammad-duplicates-cleanup @@ -59,11 +59,13 @@ def get_zammad_session(impersonated_user=None): def remove_duplicates_for(rt_id, zammad, retries=0): try: matching_zammad_tickets= zammad.ticket.search(f"title: \"\[RT-{rt_id}\]*\"") + #matching_zammad_tickets= zammad.ticket.search('number:16014') + print(matching_zammad_tickets[0]) 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"]}") + #print(f"{zt["rt_id"]} {zt["title"]}") matching_zammad_ids.append(zt["id"]) if len(matching_zammad_ids) >= 2: From e9d28bde1ff1347809885ddd6eded5d358447594 Mon Sep 17 00:00:00 2001 From: kjg Date: Fri, 2 Aug 2024 16:21:04 +0900 Subject: [PATCH 2/9] [rt2zammad] update range] --- fs2zammad | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/fs2zammad b/fs2zammad index e5669bd..5a90119 100755 --- a/fs2zammad +++ b/fs2zammad @@ -280,8 +280,17 @@ if not os.path.exists("rt2zammad.json"): with open("rt2zammad.json") as handle: config = json.load(handle) -rt_start = config["rt_start"] -rt_end = config["rt_end"] +#import_start = config["rt_start"] +#import_end = config["rt_end"] + +if len(sys.argv) != 3: + print(len(sys.argv)) + print("It needs ticket range to import ex. start, end") + sys.exit() +else: + import_start = int(sys.argv[1]) + import_end = int(sys.argv[2]) + print(f"start : {import_start} end : {import_end}") h2t = html2text.HTML2Text() zammad = get_zammad_session() @@ -296,7 +305,7 @@ ticket_ids = os.listdir("tickets/") print(f"Found {len(ticket_ids)} tickets on filesystem.") ticket_ids = list(map(int, ticket_ids)) ticket_ids.sort() -ticket_ids = list(map(int, ticket_ids[rt_start:rt_end])) +ticket_ids = list(map(int, ticket_ids[import_start-1:import_end])) for id in ticket_ids: try: From 44b0a81e45748886226726296bc3f0c65f9df79d Mon Sep 17 00:00:00 2001 From: kjg Date: Fri, 2 Aug 2024 16:27:51 +0900 Subject: [PATCH 3/9] [rt2zammad] update range of rt2fs --- rt2fs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/rt2fs b/rt2fs index 2fb28f7..164bb4c 100755 --- a/rt2fs +++ b/rt2fs @@ -50,7 +50,17 @@ os.makedirs("users", exist_ok=True) os.makedirs("tickets", exist_ok=True) os.makedirs("attachments", exist_ok=True) -ticket_ids = range(config["rt_start"], config["rt_end"]) +#ticket_ids = range(config["rt_start"], config["rt_end"]) +if len(sys.argv) != 3: + print(len(sys.argv)) + print("It needs ticket range to import ex. start, end") + sys.exit() +else: + export_start = int(sys.argv[1]) + export_end = int(sys.argv[2]) + print(f"start : {export_start} end : {export_end}") + ticket_ids = range(export_start, export_end) + def dump(id, retries=3): print(f"Dumping RT#{id}") From ce79a522b11e217fecf0ad8d70aeea5b5577f37f Mon Sep 17 00:00:00 2001 From: kjg Date: Fri, 2 Aug 2024 16:50:00 +0900 Subject: [PATCH 4/9] [rt2zammad] update range of rt2fs --- rt2fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rt2fs b/rt2fs index 164bb4c..edd09bf 100755 --- a/rt2fs +++ b/rt2fs @@ -59,7 +59,7 @@ else: export_start = int(sys.argv[1]) export_end = int(sys.argv[2]) print(f"start : {export_start} end : {export_end}") - ticket_ids = range(export_start, export_end) + ticket_ids = range(export_start, export_end + 1) def dump(id, retries=3): From 2d3526918e59b3bf90a6ff2c1ffe19dc0b3d43b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Mon, 5 Aug 2024 11:08:41 +0200 Subject: [PATCH 5/9] [fs2zammad] remove previously (half) imported zammad ticket --- fs2zammad | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/fs2zammad b/fs2zammad index 3f65a7a..8b590c7 100755 --- a/fs2zammad +++ b/fs2zammad @@ -113,6 +113,25 @@ def maybe_create_zammad_user(userdata, zammad_session, attr="login", default=Non return USERMAP[lowercase_email].get(attr, default) +def remove_existing_zammad_tickets_for(rt_id, zammad, retries=3): + try: + matching_zammad_tickets= zammad.ticket.search(f"title: \"[RT-{rt_id}]*\"") + if len(matching_zammad_tickets) >= 1: + print(f"Found existing ticket:") + for zt in matching_zammad_tickets: + print(f"{zt["id"]} {zt["title"]}") + print(f"Deleting Zammad ticket {zt["id"]}") + zammad.ticket.destroy(zt["id"]) + except: + print(f"Failed to cleanup duplicates for RT-{rt_id} .. ({retries} retries left)") + if retries > 0: + print("Sleeping 5 seconds to give Zammad some air...") + time.sleep(5) + remove_existing_zammad_tickets_for(rt_id, zammad, retries - 1) + else: + traceback.print_exc() + raise RuntimeError + # 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") @@ -297,6 +316,7 @@ ticket_ids.sort() for id in ticket_ids: try: + remove_existing_zammad_tickets_for(id, zammad, 5) zammad_ticket_id = create_zammad_ticket(id, zammad, h2t, 5) dumpfile = f"processed/{id}" with open(dumpfile, "w") as handle: From 230d8703ff937ee6ceca8538f51f96f9e8c164e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Mon, 5 Aug 2024 11:15:52 +0200 Subject: [PATCH 6/9] [fs2zammad] allow arbitrary source directory as CLI arg --- fs2zammad | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/fs2zammad b/fs2zammad index 8b590c7..dc08171 100755 --- a/fs2zammad +++ b/fs2zammad @@ -303,14 +303,21 @@ with open("rt2zammad.json") as handle: h2t = html2text.HTML2Text() zammad = get_zammad_session() +source_directory = "tickets/" +if len(sys.argv) >= 2: + source_directory = sys.argv[1] +if not os.path.isdir(source_directory): + print(f"Could not find source directory {source_directory}. Exiting.") + sys.exit(1) + os.makedirs("users", exist_ok=True) os.makedirs("tickets", exist_ok=True) os.makedirs("attachments", exist_ok=True) os.makedirs("failed", exist_ok=True) os.makedirs("processed", exist_ok=True) -ticket_ids = os.listdir("tickets/") -print(f"Found {len(ticket_ids)} tickets on filesystem.") +ticket_ids = os.listdir(source_directory) +print(f"Found {len(ticket_ids)} tickets on filesystem (source directory: {source_directory})") ticket_ids = list(map(int, ticket_ids)) ticket_ids.sort() From 13ab913c7b0f07c9f95b7897e378e0598783e7a3 Mon Sep 17 00:00:00 2001 From: kjg Date: Wed, 7 Aug 2024 14:21:05 +0900 Subject: [PATCH 7/9] [rt2zammad] update range --- zammad-duplicates-cleanup | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/zammad-duplicates-cleanup b/zammad-duplicates-cleanup index 6da9cd4..d34ed5f 100755 --- a/zammad-duplicates-cleanup +++ b/zammad-duplicates-cleanup @@ -60,7 +60,7 @@ def remove_duplicates_for(rt_id, zammad, retries=0): try: matching_zammad_tickets= zammad.ticket.search(f"title: \"\[RT-{rt_id}\]*\"") #matching_zammad_tickets= zammad.ticket.search('number:16014') - print(matching_zammad_tickets[0]) + #print(matching_zammad_tickets[0]) matching_zammad_ids = [] if len(matching_zammad_tickets) >= 2: print(f"Found duplicates:") @@ -96,6 +96,15 @@ if not os.path.exists("rt2zammad.json"): with open("rt2zammad.json") as handle: config = json.load(handle) +if len(sys.argv) != 3: + print(len(sys.argv)) + print("It needs ticket range to import ex. start, end") + sys.exit() +else: + import_start = int(sys.argv[1]) + import_end = int(sys.argv[2]) + print(f"start : {import_start} end : {import_end}") + h2t = html2text.HTML2Text() zammad = get_zammad_session() @@ -106,6 +115,7 @@ ticket_ids = os.listdir("tickets/") print(f"Found {len(ticket_ids)} tickets on filesystem.") ticket_ids = list(map(int, ticket_ids)) ticket_ids.sort() +ticket_ids = list(map(int, ticket_ids[import_start-1:import_end])) for id in ticket_ids: print(f"Processing RT-{id}...") From b5a6453acc973fd923f953496c826f3836ea55e2 Mon Sep 17 00:00:00 2001 From: kjg Date: Fri, 4 Oct 2024 21:43:21 +0900 Subject: [PATCH 8/9] [rt2migration] update fs2zammad for owner --- fs2zammad | 40 +++++++++++++-- zammad-remove-ticket | 115 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 151 insertions(+), 4 deletions(-) create mode 100755 zammad-remove-ticket diff --git a/fs2zammad b/fs2zammad index 5a90119..442df8c 100755 --- a/fs2zammad +++ b/fs2zammad @@ -58,19 +58,26 @@ def get_zammad_session(impersonated_user=None): def maybe_create_zammad_user(userdata, zammad_session, attr="login", default=None): # Map disabled users (in RT) to mock user in Zammad. + #print("*userdata",userdata) #debug + #print("*USERMAP", USERMAP) #debug if type(userdata) is str and userdata.lower() in USERMAP: email = userdata + #print("*1") #debug elif type(userdata) is str or "EmailAddress" not in userdata: userdata = { 'EmailAddress': 'technik@ungleich.ch', 'RealName': 'Disabled RT' } email = userdata["EmailAddress"] + #print("*2") #debug elif "EmailAddress" in userdata: email = userdata["EmailAddress"] + #print("*3") #debuig else: raise ValueError("Invalid userdata") + #print("*default",default) #debug + #print("*email",email) #debug # We manually filter out invalid addresses. if email == "*@*.com": userdata = { @@ -81,6 +88,7 @@ def maybe_create_zammad_user(userdata, zammad_session, attr="login", default=Non lowercase_email = email.lower() + #print("*lowercase_email",lowercase_email) #debug if lowercase_email not in USERMAP: kwargs = {"email": email} @@ -107,7 +115,8 @@ def maybe_create_zammad_user(userdata, zammad_session, attr="login", default=Non USERMAP[lowercase_email] = user else: print(f"Could not create/fetch user {lowercase_email}") - + + #print("*lastdefault",default) #debug if default is None: return USERMAP[lowercase_email][attr] @@ -170,7 +179,13 @@ def create_zammad_ticket(id, zammad, h2t, retries=3): 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") + #print("*rt_ticket",rt_ticket) #debug + get_owner = rt_ticket["ticket"]["Owner"] + with open(f"users/{get_owner}", "rb") as handle: + get_owner_data = pickle.load(handle) + #print("*get_owner_data",get_owner_data) #debug + zammad_owner_id = maybe_create_zammad_user(get_owner_data, zammad, "id") + #print("*zammad_owner_id",zammad_owner_id) #debug zammad.ticket.update( zammad_ticket["id"], {"owner_id": zammad_owner_id} ) @@ -220,7 +235,9 @@ def create_zammad_ticket(id, zammad, h2t, retries=3): with open(f"users/{entry_creator}", "rb") as handle: rt_entry_creator = pickle.load(handle) + #print("*rt_entry_creator",rt_entry_creator) #debug zammad_entry_creator = maybe_create_zammad_user(rt_entry_creator, zammad) + #print("*zammad_entry_creator",zammad_entry_creator) # debug entry_content = entry["Content"] if entry_content == '' and may_contain_entry_content: file = may_contain_entry_content @@ -236,20 +253,29 @@ def create_zammad_ticket(id, zammad, h2t, retries=3): "internal": entry["Type"] == "Comment", "attachments": files, } - entry_creator_id = maybe_create_zammad_user(zammad_entry_creator, zammad, "id") + entry_creator_id = maybe_create_zammad_user(rt_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"]: + #print("*t1_1 restore_creator_to",restore_creator_to) #debug + #print("*t1_2 entry_creator_id",entry_creator_id) #debug + #print("*t1_3 customer_id",zammad_ticket["customer_id"]) #debug 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})...") + #print("*t2_1",restore_creator_to) #debug + #print("*t2_2",entry_creator_id) #debug + #print("*t2_3",zammad_entry_creator) #debug + #print("*t2_4",zammad_entry_template) #debug TicketArticle(get_zammad_session(zammad_entry_creator)).create(zammad_entry_template) if restore_creator_to != None: + #print("*t3_1",restore_creator_to) #debug + #print("*t3_2",entry_creator_id) #debug zammad.ticket.update(zammad_ticket["id"], {"customer_id": restore_creator_to}) # Returns the new Zammad ticket ID. @@ -295,6 +321,10 @@ else: h2t = html2text.HTML2Text() zammad = get_zammad_session() +#this_page = zammad.user.all() +#for user in this_page: +# print(user) + os.makedirs("users", exist_ok=True) os.makedirs("tickets", exist_ok=True) os.makedirs("attachments", exist_ok=True) @@ -309,7 +339,9 @@ ticket_ids = list(map(int, ticket_ids[import_start-1:import_end])) for id in ticket_ids: try: - matching_zammad_tickets= zammad.ticket.search(f"title: \"\[RT-{id}\]*\"") + print(id) + matching_zammad_tickets = zammad.ticket.search(f"title: \"\[RT-{id}\]*\"") + print(len(matching_zammad_tickets)) if len(matching_zammad_tickets) >= 1: print(f"Found duplicates: {id}") continue diff --git a/zammad-remove-ticket b/zammad-remove-ticket new file mode 100755 index 0000000..4d2f1bc --- /dev/null +++ b/zammad-remove-ticket @@ -0,0 +1,115 @@ +#!/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, +} +""" + + +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_tickets_for(rt_id, zammad, retries=0): + try: + matching_zammad_tickets= zammad.ticket.search(f"title: \"\[RT-{rt_id}\]*\"") + #matching_zammad_tickets= zammad.ticket.search('number:16014') + #print(matching_zammad_tickets[0]) + matching_zammad_ids = [] + if len(matching_zammad_tickets) >= 1: + print(f"Found ticket:") + for zt in matching_zammad_tickets: + #print(f"{zt["rt_id"]} {zt["title"]}") + matching_zammad_ids.append(zt["id"]) + + if len(matching_zammad_ids) >= 1: + 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_tickets_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) + +if len(sys.argv) != 3: + print(len(sys.argv)) + print("It needs ticket range to import ex. start, end") + sys.exit() +else: + import_start = int(sys.argv[1]) + import_end = int(sys.argv[2]) + print(f"start : {import_start} end : {import_end}") + +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() +ticket_ids = list(map(int, ticket_ids[import_start-1:import_end])) + +for id in ticket_ids: + print(f"Processing RT-{id}...") + remove_tickets_for(id, zammad) From ed45622c0458bfc484bc20a3cd3b9a631ec555a1 Mon Sep 17 00:00:00 2001 From: kjg Date: Mon, 21 Oct 2024 14:34:58 +0000 Subject: [PATCH 9/9] [rt2zammad] update fs2zammad for Task#12785 --- fs2zammad | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs2zammad b/fs2zammad index 442df8c..e31ea2a 100755 --- a/fs2zammad +++ b/fs2zammad @@ -104,15 +104,21 @@ def maybe_create_zammad_user(userdata, zammad_session, attr="login", default=Non first = "" kwargs["lastname"] = last kwargs["firstname"] = first + #print("*kwargs",kwargs) #debug try: + #print("*try") #debug user = zammad_session.user.create(kwargs) USERMAP[lowercase_email] = user + #print("*try USERMAP") #debug except: # The use probably exist already... - result = list(zammad.user.search(lowercase_email)) + #print("*ecept") + result = list(zammad.user.search(f'"{lowercase_email}"')) + #print("*ecept result",result) #debug if len(result) >= 1: user = next(u for u in result if u['email'] == lowercase_email) USERMAP[lowercase_email] = user + #print("*except USERMAP",USERMAP) #debug else: print(f"Could not create/fetch user {lowercase_email}")