diff --git a/ticket_transfer.py b/ticket_transfer.py index ba7b352..743c8bc 100644 --- a/ticket_transfer.py +++ b/ticket_transfer.py @@ -13,6 +13,8 @@ import base64 import urllib.parse from datetime import datetime from dateutil.relativedelta import relativedelta +import itertools +import threading ################################### # Function Definitions @@ -59,6 +61,22 @@ def makeCall (target, verb, key, payload= None, files= None): except Exception as error: print(f'{RED}Error:{RESET}\n{error}') raise + if verb.lower() == 'put': + try: + response = requests.put(target, auth=(key, 'X'), json= payload) + if response.status_code != 429: + response.raise_for_status() + responseData = response.json() + if (checkRate(response)): + return makeCall(target, verb, key, payload) + return responseData + except requests.exceptions.HTTPError as http_error: + print(f'{RED}HTTP Error:{RESET}\n{http_error}') + print(f'Reponse Content: {response.content}') + raise + except Exception as error: + print(f'{RED}Error:{RESET}\n{error}') + raise # Clears out the specified number of console lines def clear(number): @@ -111,6 +129,26 @@ def buildTicketArray(domain, groupId, key): currentDate -= relativedelta(months=1) return retArray +def spinner(): + anim = itertools.cycle(['◑', '◒', '◐', '◓']) + while not stopSpin.is_set(): + sys.stdout.write(f'\r{message}{next(anim)}\n') + sys.stdout.flush() + time.sleep(0.1) + clear(1) + +def start_spinner(msg): + global stopSpin, message + stopSpin.clear() + message = msg + spinner_thread = threading.Thread(target=spinner) + spinner_thread.start() + return spinner_thread + +def stop_spinner(spinner_thread): + stopSpin.set() + spinner_thread.join() + ################################### # Globals Variables ################################### @@ -126,6 +164,8 @@ RED = '\033[31m' GREEN = '\033[32m' YELLOW = '\033[33m' RESET = '\033[0m' +stopSpin = threading.Event() +spinnerThread = threading.Thread(target=spinner) ################################### # Main Loop @@ -187,37 +227,27 @@ else: ## Building Definition Arrays -print(f'Obtaining account information...◐') +spinner_thread = start_spinner('Obtaining account information...') groupIdDefs_source = makeCall(sourceDom + '/api/v2/groups', 'get', sourceKey) -clear(1) -print(f'Obtaining account information...◓') groupIdDefs_dest = makeCall(destDom + '/api/v2/groups', 'get', destKey) -clear(1) -print(f'Obtaining account information...◑') -for i, group in enumerate(groupIdDefs_source): - anim = ['◒','◐', '◓', '◑'] +for group in groupIdDefs_source: if group["name"] == targetGroup: targetGroupId = group["id"] break - clear(1) - print(f'Obtaining account information...{anim[i % len(anim)]}') -clear(1) +stop_spinner(spinner_thread) print(f'Obtaining account information...{GREEN}COMPLETE{RESET}') ## Building Ticket Array from Source -print(f'Gathering list of tickets from source...') -#ticketArray = makeCall(sourceDom + '/api/v2/search/tickets?query=' + urllib.parse.urlencode(f'"group_id:\'{targetGroupId}\'"'), 'get', sourceKey) -#ticketArray = makeCall(f'{sourceDom}/api/v2/search/tickets?query="group_id:{targetGroupId}"', 'get', sourceKey) +spinner_thread = start_spinner('Gathering list of tickets from source...') ticketArray = buildTicketArray(sourceDom, targetGroupId, sourceKey) -clear(1) +stop_spinner(spinner_thread) print(f'Gathering list of tickets from source...{GREEN}COMPLETE{RESET}') ## Transferring tickets to Destination print(f'{YELLOW}*This may take a while*{RESET}') -print(f'Transferring tickets to destination account...◐') -for i, ticket in enumerate(ticketArray): +spinner_thread = start_spinner(f'Transferring tickets to destination account...') +for ticket in ticketArray: attachments = {} - anim = ['◓', '◑', '◒', '◐'] ticketData = makeCall(sourceDom + f'/api/v2/tickets/{ticket["id"]}?include=conversations,requester', 'get', sourceKey) if 'attachments' in ticketData: for attachment in ticketData['attachments']: @@ -238,7 +268,7 @@ for i, ticket in enumerate(ticketArray): 'source': ticketData["source"], } newTicket = makeCall(destDom + '/api/v2/tickets', 'post', destKey, payload, attachments if attachments else None) - + ticket['new_ticket'] = newTicket['id'] ## Gaterhing conversation history from ticketData, and then updating the ticket to include them in a private note if len(ticketData['conversations']) > 0: convos = ''' @@ -260,12 +290,19 @@ for i, ticket in enumerate(ticketArray): elif convo['private'] == False and convo['incoming'] == False: convos += f'Outgoing Reply from {username}:
{convo["body"]}
---------------------------
' makeCall(destDom + f'/api/v2/tickets/{newTicket["id"]}/notes', 'post', destKey,{'body': convos}) - - clear(1) - print(f'Transferring tickets to destination account...{anim[i % len(anim)]}') - i += 1 -clear(2) +stop_spinner(spinner_thread) +clear(1) print(f'Transferring tickets to destination account...{GREEN}COMPLETE{RESET}') +spinner_thread = start_spinner('Closing transferred tickets on source account...') +for ticket in ticketArray: + noteBody = f''' + Ticket has been transferred to {destDom}/a/tickets/{ticket['new_ticket']}
+ Ticket ID: {ticket['new_ticket']}
+ ''' + makeCall(sourceDom + f'/api/v2/tickets/{ticket["id"]}/notes', 'post', sourceKey, {'body': noteBody}) + makeCall(sourceDom + f'/api/v2/tickets/{ticket["id"]}', 'put', sourceKey, {'status': 5}) +stop_spinner(spinner_thread) +print(f'Closing transferred tickets on source account...{GREEN}COMPLETE{RESET}') print(f'{GREEN}*TICKET TRANSFER COMPLETED SUCCESSFULLY*{RESET}') for i in range(5, 0, -1): print(f'Exiting in {i} seconds...')