Ticket_Transfer/ticket_transfer.py

246 lines
9.6 KiB
Python

#!/usr/bin/env python3
###################################
# Library Inclusions
###################################
import requests
import json
import os
import time
import sys
import base64
import urllib.parse
import mimetypes
###################################
# Function Definitions
###################################
# Makes API call to target using either GET or POST and returns the JSON response
## request.post() usage (url, headers = headers, data= payload, files= files) or (url, headers= headers, json= payload)
def makeCall (target, verb, key, payload= None, files= None):
if verb.lower() == 'get':
try:
response = requests.get(target, auth=(key, 'X'))
if response.status_code != 429:
response.raise_for_status()
responseData = response.json()
if (checkRate(response)):
return makeCall(target, verb, key)
return responseData
except requests.exceptions.HTTPError as http_error:
print(f'{RED}HTTP Error:{RESET}\n{http_error}')
raise
except Exception as error:
print(f'{RED}Error:{RESET}\n{error}')
raise
elif verb.lower() == 'post':
try:
if files == None:
response = requests.post(target, auth=(key, 'X'), json= payload)
else:
response = requests.post(target, data= payload, auth=(key, 'X'), files= files)
if response.status_code != 429:
response.raise_for_status()
responseData = response.json()
if (checkRate(response)):
if files == None:
return makeCall(target, verb, key, payload)
else:
return makeCall(target, verb, key, payload, files)
return responseData
except requests.exceptions.HTTPError as http_error:
print(f'{RED}HTTP Error:{RESET}\n{http_error}')
raise
except Exception as error:
print(f'{RED}Error:{RESET}\n{error}')
raise
# Clears out the specified number of console lines
def clear(number):
for num in range(number):
sys.stdout.write('\x1b[1A')
sys.stdout.write('\x1b[2K')
def checkRate(response):
if 'Retry-After' in response.headers:
timer = int(response.headers.get('Retry-After')) + 5
while timer > 0:
print(f'{YELLOW}*RATE LIMITED*{RESET}...Pausing for {timer} seconds')
time.sleep(1)
timer -= 1
clear(1)
return True
else:
return False
###################################
# Globals Variables
###################################
ticketArray = []
groupIdDefs_source = []
sourceDom = ''
destDom = ''
sourceKey = ''
destKey = ''
targetGroup = ''
targetGroupId = ''
RED = '\033[31m'
GREEN = '\033[32m'
YELLOW = '\033[33m'
RESET = '\033[0m'
###################################
# Main Loop
###################################
if os.name == 'nt':
os.system('cls')
else:
os.system('clear')
print(' ______ ___ __ __ ')
print(' / ____/________ _____ ___ / | / / ____ / /_ ')
print(' / / / ___/ __ `/ __ `__ \______/ /| |______/ / / __ \/ __/ ')
print('/ /___/ / / /_/ / / / / / /_____/ ___ /_____/ /___/ /_/ / /_ ')
print('\____/_/_ \__,_/_/ /_/ /_/ /_/__|_| /_____/\____/\__/___ ')
print(' /_ __(_)____/ /_____ / /_ /_ __/________ _____ _____/ __/__ _____')
print(' / / / / ___/ //_/ _ \/ __/ / / / ___/ __ `/ __ \/ ___/ /_/ _ \/ ___/')
print(' / / / / /__/ ,< / __/ /_ / / / / / /_/ / / / (__ ) __/ __/ / ')
print('/_/ /_/\___/_/|_|\___/\__/ /_/ /_/ \__,_/_/ /_/____/_/ \___/_/ \n')
print('=========================================================================')
## Getting transfer settings from user
sourceDom = input('Please enter the source domain:\n(ex. "https://your_domain.freshdesk.com")\n> ')
if sourceDom == '':
print(f'{RED}Invalid Domain Provided{RESET}')
sys.exit(1)
else:
clear(3)
sourceDom = "".join(sourceDom.split())
print(f'SETTINGS:\nSource Domain: {GREEN}{sourceDom}{RESET}\n=========================================================================')
sourceKey = input('Please provide the API Key for the source account:\n(Hint: You can find this from your profile settings menu in Freshdesk)\n> ')
if sourceKey == '':
print(f'{RED}Invalid Key Provided{RESET}')
sys.exit(1)
else:
clear(3)
sourceKey = "".join(sourceKey.split())
destDom = input('Please enter the destination domain:\n> ')
if destDom == '':
print(f'{RED}Invalid Domain Provided{RESET}')
sys.exit(1)
else:
clear(4)
destDom = "".join(destDom.split())
print(f'Source Domain: {GREEN}{sourceDom}{RESET}\nDestination Domain: {GREEN}{destDom}{RESET}\n=========================================================================')
destKey = input('Please provide the API key for the destination account:\n> ')
if destKey == '':
print(f'{RED}Invalid Key Provided{RESET}')
sys.exit(1)
else:
clear(2)
destKey = "".join(destKey.split())
targetGroup = input('What is the name of the Freshdesk group you want to transfer from?\n> ')
if targetGroup == '':
print(f'{RED}Invalid Group Name Provided{RESET}')
sys.exit(1)
else:
clear(3)
print(f'Group: {GREEN}{targetGroup}{RESET}')
print(f'=========================================================================')
## Building Definition Arrays
print(f'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 = ['','', '', '']
if group["name"] == targetGroup:
targetGroupId = group["id"]
break
clear(1)
print(f'Obtaining account information...{anim[i % len(anim)]}')
clear(1)
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)
clear(1)
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['results']):
attachments = {}
anim = ['', '', '', '']
ticketData = makeCall(sourceDom + f'/api/v2/tickets/{ticket["id"]}?include=conversations,requester', 'get', sourceKey)
if 'attachments' in ticket:
for x, attachment in enumerate(ticket['attachments']):
if attachment.get('attachment_url'):
fileRes = requests.get(attachment.attachment_url)
if fileRes.status_code == 200:
attachments[x] = (attachment['name'], fileRes.content)
else:
print(f'{RED}File Error:{RESET}\nFailed to download {attachment["name"]}')
payload = {
'name': ticketData["requester"]["name"],
'email': ticketData["requester"]["email"],
'phone': ticketData["requester"]["phone"],
'subject': ticketData["subject"],
'status': ticketData["status"],
'priority': ticketData["priority"],
'description': ticketData["description"],
'source': ticketData["source"],
}
newTicket = makeCall(destDom + '/api/v2/tickets', 'post', destKey, payload, files=attachments if attachments else None)
## Gaterhing conversation history from ticketData, and then updating the ticket to include them in a private note
if len(ticketData['conversations']) > 0:
convos = '''
=====================<br>
Conversation History<br>
=====================<br>
'''
for convo in ticketData['conversations']:
if convo['incoming'] == False:
agent = (makeCall(sourceDom + f'/api/v2/agents/{convo["user_id"]}', 'get', sourceKey))
username = agent["contact"]["name"]
if convo['incoming'] == True:
user = (makeCall(sourceDom + f'/api/v2/contacts/{convo["user_id"]}', 'get', sourceKey))
username = user["name"]
if convo['private'] == True:
convos += f'<b>Private Note from {username}:</b><br>{convo["body"]}<br>---------------------------<br>'
elif convo['private'] == False and convo['incoming'] == True:
convos += f'<b>Incoming Reply from {username}:</b><br>{convo["body"]}<br>---------------------------<br>'
elif convo['private'] == False and convo['incoming'] == False:
convos += f'<b>Outgoing Reply from {username}:</b><br>{convo["body"]}<br>---------------------------<br>'
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)
print(f'Transferring tickets to destination 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...')
time.sleep(1)
clear(1)
sys.exit(0)