From c923e7e802c4869c2ac1f9bd28bcb2c0aa817b75 Mon Sep 17 00:00:00 2001 From: Finn <finnryanit@gmail.com> Date: Thu, 24 Oct 2024 17:17:40 +0100 Subject: [PATCH] Misc fixes. Added Software licenses and Users endpoints. Some need docstrings still --- src/HaloPSA/Halo.py | 308 ++++++++++++++++++++++++++------------------ 1 file changed, 182 insertions(+), 126 deletions(-) diff --git a/src/HaloPSA/Halo.py b/src/HaloPSA/Halo.py index 3ec3756..7e32609 100644 --- a/src/HaloPSA/Halo.py +++ b/src/HaloPSA/Halo.py @@ -1,7 +1,4 @@ # Entirely re-written with classes - -# Apparently this is very, very bad - # Modules to interact with Halo. # Some modules use specifc IDs, will try to clean this up as I go. @@ -9,7 +6,7 @@ import urllib.parse import json import os -from src.HaloPSA.functions import apiCaller +from HaloPSA.functions import apiCaller # CONSTANTS @@ -48,7 +45,6 @@ def createToken(): else: return print('Error') -mainToken = createToken() # Remove this #### Classes @@ -99,7 +95,7 @@ def get(self, """ newVars = locals().copy() - request = apiCaller(HALO_API_URL,'search','Asset',newVars,self.headerJSON) + request = apiCaller(HALO_API_URL,'get','Asset',newVars,self.headerJSON) response = request.getData() return response @@ -207,9 +203,7 @@ def update(self, response = request.getData() self.formattedParams = [] # reset queue return response - - - + class clients: """Client endpoint @@ -576,94 +570,199 @@ def update(): def delete(): pass - - -class Users: - """Users enpdpoint. NOT THE SAME AS CLIENT ENDPOINT! +class softwareLicences: + """Software Licenscs endpoint. """ - def search(): - """ Search users""" - pass + def __init__(self): + token = createToken() + self.token = token + self.headerJSON = { # Header with token + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + token + } + self.url = HALO_API_URL + '/SoftwareLicence' - def get(): - """Get specific user""" - pass + def search(self, + pageinate:bool=False, + page_size:int=50, + page_no:int=1, + order:str =None, + orderdesc:bool=None, + search:str=None, + licence_type:int=None, + tenant_id:int=None, + toplevelid:int=None, + client_id:int=None, + site_id:int=None, + includeinactive:bool=None, + includeactive:bool=None, + count:int=None, + **others): + """Search (Software) Licenses. + + Args: + pageinate (bool, optional): _description_. Defaults to False. + page_size (int, optional): _description_. Defaults to 50. + page_no (int, optional): _description_. Defaults to 1. + order (str, optional): _description_. Defaults to None. + orderdesc (bool, optional): _description_. Defaults to None. + search (str, optional): _description_. Defaults to None. + licence_type (int, optional): _description_. Defaults to None. + tenant_id (int, optional): _description_. Defaults to None. + toplevelid (int, optional): _description_. Defaults to None. + client_id (int, optional): _description_. Defaults to None. + site_id (int, optional): _description_. Defaults to None. + includeinactive (bool, optional): _description_. Defaults to None. + includeactive (bool, optional): _description_. Defaults to None. + count (int, optional): _description_. Defaults to None. + + Returns: + _type_: _description_ + """ + newVars = locals().copy() + + request = apiCaller(HALO_API_URL,'search','SoftwareLicence',newVars,self.headerJSON) + response = request.getData() + return response + - def update(): - """Update specific user""" + def get(self): pass + def update(self, + client_id:int, + type:int, + name:str, + site_id:int=None, + count:int=None, + start_date:str=None, + end_date:str=None, + billing_cycle:str=None, + term_duration:str=None, + autorenew:bool=None, + status:str=None, + is_active:bool=None, + supplier_id:int=None, + manufacturer:str=None, + purchase_price:int=None, + price:int=None, + monthly_cost:int=None, + monthly_price:int=None, + notes:str=None, + **others, + ): + + newVars = locals().copy() + + request = apiCaller(HALO_API_URL,'update','SoftwareLicence',newVars,self.headerJSON) + response = request.getData() + return response + def delete(): - """Delete user""" pass + + +class users: + """Users endpoint. + """ + def __init__(self): + token = createToken() + self.token = token + self.headerJSON = { # Header with token + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + token + } + self.url = HALO_API_URL + '/Users' + + def search(self, + pageinate:bool=False, + page_size:int=50, + page_no:int=1, + order:str =None, + orderdesc:bool=None, + search:str=None, + search_phonenumbers:bool=None, + toplevel_id:int=None, + client_id:int=None, + site_id:int=None, + organisation_id:int=None, + department_id:int=None, + asset_id:int=None, + includeinactive:bool=None, + includeactive:bool=None, + approversonly:bool=None, + excludeagents:bool=None, + count:int=None, + **others + ): + """_summary_ + Args: + paginate (bool, optional): Whether to use Pagination in the response. Defaults to False. + page_size (int, optional): When using Pagination, the size of the page. Defaults to 50. + page_no (int, optional): When using Pagination, the page number to return. Defaults to 1. + order (str, optional): The name of the field to order by. + orderdesc (bool, optional): Whether to order ascending or descending. Defaults to decending sort. + search (str, optional): Query to filter by. + search_phonenumbers (bool, optional): Filter by Users with a phone number like your search. Defaults to None. + toplevel_id (int, optional): Filter by Users belonging to a particular top level. + client_id (int, optional): Filter by Users belonging to a particular customer. + site_id (int, optional): Filter by Users belonging to a particular site. + organisation_id (int, optional): Filter by Users belonging to a particular site. + department_id (int, optional): Filter by Users belonging to a particular department. + asset_id (int, optional): Filter by Users assigned to a particular asset. + includeinactive (bool, optional): Include inactive Users in response. Defaults to False. + includeactive (bool, optional): Include inactive Users in response. Defaults to True. + approversonly (bool, optional): Include only Users that can approve appoval processes response. Defaults to False. + excludeagents (bool, optional): Excluse Users that are linked to active agent accounts. Defaults to False. + count (int, optional): When not using pagination, the number of results to return. + Returns: + dict: Search results + """ + + newVars = locals().copy() + + request = apiCaller(HALO_API_URL,'search','Users',newVars,self.headerJSON) + response = request.getData() + return response + + def get(self, + id:int, + includedetails:bool=None, + includeactivity:bool=None, + includepopups:bool=None, + **others + ): + """ + Get a single user's details. + Supports all Halo parameters, even if not listed. + Requires atleast ID to be provided + Args: + id (int): User ID + includedetails (bool, optional): Whether to include extra details in the response. Defaults to False. + includeactivity (bool, optional): Whether to include User's ticket activity in the response. Defaults to False. + includepopups (bool, optional): Whether to include customer pop ups in the response. Defaults to False. + Returns: + dict: Single users details + """ + + newVars = locals().copy() + request = apiCaller(HALO_API_URL,'get','User',newVars,self.headerJSON) + response = request.getData() + return response + + def update(): + """Update one or more users""" + pass + def delete(): + pass -def userSearch(query): - """ Searches for a user """ - headers = { # Header with token - 'Content-Type': 'application/json', - 'Authorization': 'Bearer ' + mainToken - } - request = requests.get(HALO_API_URL+ '/users?' + urllib.parse.urlencode(query), headers = headers) - if request.status_code != 200: - return 'Failed to get users' - response = json.loads(request.content) - return response - - -def invoiceActivator(ids=None): - """ Set invoices to Active - If no IDs are sent, all invoices will be set to Active """ - headers = { # Header with token - 'Content-Type': 'application/json', - 'Authorization': 'Bearer ' + mainToken - } - query = { - 'type': 54, - } - request = requests.get(HALO_API_URL+ '/Template', headers = headers,params = query) - if request.status_code != 200: - return 'Failed to get Templates' - response = json.loads(request.content) - for invoice in response: - print(invoice['id']) - if invoice == 'more': - invoice = invoice['more'] - if invoice['disabled'] == True: - data = json.dumps([{ - 'disabled': False, - 'end_date': '1901-01-01T00:00:00.000Z', - 'id':invoice['id'] - - }]) - updateAttempt = requests.post(HALO_API_URL+ '/Template', headers = headers,data = data) - if updateAttempt.status_code !=[200,201]: - print('Failed') - else: - print(f'Updated {invoice["id"]}') - return response - - -def manualTokenUpdate(key,id): - """ Manually update tokens for halo integrations. - - Make sure you have the integration type set to bearer token :)""" - headers = { # Header with token - 'Content-Type': 'application/json', - 'Authorization': 'Bearer ' + mainToken - } - payload = json.dumps([{ - "new_client_secret": str(key), - "id": id - }]) - attemptUpdate = requests.post(HALO_API_URL+ '/CustomIntegration', headers = headers, data=payload) - return attemptUpdate -def _formatter(params): +def _formatter(params): # Format user input for API requests formattedData = {} paramsToAdd = params | params['others'] # Copy params and add any additional items @@ -684,46 +783,3 @@ def _formatter(params): if value !=None: formattedData.update({item : value}) return formattedData - - -### OLD SHIT ### - -def productUpdate(updateField,originalText,replacementText): - """ Update a halo product by value. - Requires token, field to search on/update, text to search, text to replace with. - """ - headers = { # Header with token - 'Content-Type': 'application/json', - 'Authorization': 'Bearer ' + mainToken - } - def updateItemByID(ID,originalStr): - payload = json.dumps([{ - updateField: originalStr.replace(originalText,replacementText), - "id": ID - }]) - attemptUpdate = requests.post(HALO_API_URL+ '/item', headers = headers, data=payload) - return attemptUpdate.status_code - - request = requests.get(HALO_API_URL+ '/item', headers = headers) - itemsList = json.loads(request.content)['items'] - for item in itemsList: - if item == 'more': # Shows only 100 by default, this allows it to cycle through the remaining ones - item = item['more'] - if updateField in item: - if originalText in item[updateField]: - print(f'[{item["id"]}] {item["name"]}\n - {item[updateField]}') # Original string - attemptUpdate = updateItemByID(item["id"],item[updateField]) - print(attemptUpdate) # Status of attempted assetUpdate - - -def productDB(): - #TODO create DB for products to allow for easier searching, updating, etc. - sqlQuery = "INSERT OR UPDATE OR IGNORE INTO (tbd) values=()" - sqlData = "" - pass - -### Testing the above tool -# originalText = 'for (contract start date) - (contract end date) - billed monthly' -# newText = 'for contract period $CONTRACTSTARTDATE - $CONTRACTENDDATE (billed monthly)' -# productUpdate(getHaloToken(),'description',originalText,newText) -