Upload files to "/"
This commit is contained in:
commit
698bfde83c
246
ticket_transfer.py
Normal file
246
ticket_transfer.py
Normal file
@ -0,0 +1,246 @@
|
||||
#!/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 = []
|
||||
transArray = []
|
||||
groupIdDefs_source = []
|
||||
groupIdDefs_dest = []
|
||||
contactIdDefs = []
|
||||
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}')
|
||||
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} || Target Domain: {GREEN}{destDom}{RESET}')
|
||||
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(3)
|
||||
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...◓')
|
||||
contactIdDefs = makeCall(sourceDom + '/api/v2/contacts', '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)
|
||||
clear(1)
|
||||
print(f'Gathering list of tickets from source...{GREEN}COMPLETE{RESET}')
|
||||
|
||||
## Transferring tickets to Destination
|
||||
print(f'*This may take a while*')
|
||||
print(f'Transferring tickets to destination account...◐')
|
||||
for i, ticket in enumerate(ticketArray):
|
||||
attachments = {}
|
||||
anim = ['◓', '◑', '◒', '◐']
|
||||
ticketData = makeCall(sourceDom + f'/api/v2/tickets/{ticket["id"]}?include=conversations,requester', 'get', sourceKey)
|
||||
for x, attachment in enumerate(ticket['attachments']):
|
||||
if attachment['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"],
|
||||
}
|
||||
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']:
|
||||
for contact in contactIdDefs:
|
||||
if contact['id'] == convo['user_id']:
|
||||
username = contact['name']
|
||||
break
|
||||
if convo['private'] == 'true':
|
||||
convos += f'Private Note from {username}:<br>{convo["body"]}<br>---------------------------<br><br>'
|
||||
elif convo['private'] == 'false' and convo['incoming'] == 'true':
|
||||
convos += f'Incoming Reply from {username}:<br>{convo["body"]}<br>---------------------------<br><br>'
|
||||
elif convo['private'] == 'false' and convo['incoming'] == 'false':
|
||||
convos += f'Outgoing Reply from {username}:<br>{convo["body"]}<br>---------------------------<br><br>'
|
||||
makeCall(destDom + f'/api/v2/tickets/{ticket['id']}/notes', 'post', destKey,{'body': convos})
|
||||
|
||||
clear(1)
|
||||
print(f'Transferring tickets to destination account...{anim[i % len(anim)]}')
|
||||
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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user