From 3f0b7fb35aaffd4fa259f547f12e3480ec65b7f0 Mon Sep 17 00:00:00 2001 From: Ben D Date: Mon, 24 Jan 2022 23:11:21 -0800 Subject: [PATCH] Updated e911_helper.py --- e911_helper.py | 175 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 118 insertions(+), 57 deletions(-) diff --git a/e911_helper.py b/e911_helper.py index bf6e2d8..af57e97 100644 --- a/e911_helper.py +++ b/e911_helper.py @@ -1,10 +1,11 @@ #!/usr/bin/env python3 -# +# # (C) 2020 VOICE1 LLC # import datetime +from dis import dis import requests import json import sys @@ -12,60 +13,55 @@ import os try: from loguru import logger + + logger.add("app.log", rotation="1 month", level="DEBUG") except ImportError: import logging + logger = logging.getLogger(__name__) -# TODO: Set to config file. +class bcolors: + HEADER = "\033[95m" + OKBLUE = "\033[94m" + OKCYAN = "\033[96m" + OKGREEN = "\033[92m" + WARNING = "\033[93m" + FAIL = "\033[91m" + ENDC = "\033[0m" + BOLD = "\033[1m" + UNDERLINE = "\033[4m" + + +# Show and confirm disclaimer +disclaimer_accepted = False + + +def show_disclaimer(): + print( + f""" + {bcolors.BOLD} +WARNING - This script is provided as a DEMO ONLY. It is intended to illistrate how to use the Voice1 APIs. By using this script, you agree to the terms of use and acknowledge that you are responsible for any actions taken. + +Neither VOICE1 nor VOICE1’s resellers, contractors, or associates shall be responsible for providing Services to the extent that the issue is caused by (a) Customer’s misuse, improper use, mis-configuration, alteration, or damage to the Software; (b) Customer’s use of the Software with any hardware or software not supplied or supported by VOICE1; (c) Customer’s failure to install an update to the Software if such update would have resolved the issue; or (d) uses in a manner not in accordance with the Agreement. VOICE1 shall have no responsibility for loss of or damage to Customer’s data or loss of business, regardless of the cause of any such loss or damage. + +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, VOICE1 AND ITS RESELLERS DISCLAIM ALL WARRANTIES AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND TITLE AND NON-INFRINGEMENT, WITH REGARD TO THE SOFTWARE. AND SERVICES. VOICE1 AND RESELLERS DO NOT GUARANTEE THAT THE OPERATION OF THE SOFTWARE OR ANY OTHER CODE WILL BE UNINTERRUPTED OR ERROR-FREE, AND CUSTOMER ACKNOWLEDGE THAT IT IS NOT TECHNICALLY PRACTICABLE FOR US TO DO SO. + +TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL VOICE1 OR ITS RESELLERS BE LIABLE UNDER ANY LEGAL OR EQUITABLE THEORY FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION OR ANY OTHER PECUNIARY LAW) ARISING OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE OR THE SERVICES OR ANY OTHER SUBJECT MATTER RELATING TO THIS AGREEMENT, EVEN IF VOICE1 OR RESELLERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN ANY CASE, VOICE 1'S AND RESELLER'S’ ENTIRE LIABILITY WITH RESPECT TO ANY SUBJECT MATTER RELATING TO THIS AGREEMENT SHALL BE LIMITED TO THE AMOUNT ACTUALLY PAID FOR THE SERVICES + {bcolors.ENDC} + """ + ) + + +# TODO: Set to config file. config_file = "config.json" if os.path.isfile(config_file): with open(config_file) as f: config_data = json.load(f) else: logger.critical(f"Unable to load config.json. Aborting.") - # Generate empty config.json - with open('config.json', 'w') as config: - config.write( -""" -[ - { - "regcode": "", - "company": "", - "username": "", - "password": "", - "provider_username": "", - "provider_password": "", - "911_callrule_id": 0, - "out_call_rule_id": 0, - "redirect_ivr_id": "", - "tenant": { - "tenant1": { - "username": "", - "password": "", - "provider_username": "", - "provider_password": "", - "911_callrule_id": 0, - "out_call_rule_id": 0, - "redirect_ivr_id": "0" - } - } - } -] -""" - ) - logger.info(f"Generated empty config.json file. Besure to populate it with required details before proceeding.") sys.exit() -# Check and update current file to latest version. -def write_file(filename, content): - # put the content into the file - with open(filename, 'wb') as fp: - fp.write(content) - - - -# End update check add_type_list = [ "", @@ -345,23 +341,38 @@ def format_address(address, fmt="human"): """Prettifies address for display.""" if fmt == "human": - address_type = ' '.join(part for part in (address.get('address_type'), address.get('address_type_number')) if part) - address_type = ' '.join(filter(None, (address.get('address_type'), address.get('address_type_number')))) + address_type = " ".join( + part + for part in ( + address.get("address_type"), + address.get("address_type_number"), + ) + if part + ) + address_type = " ".join( + filter( + None, (address.get("address_type"), address.get("address_type_number")) + ) + ) return f"{address['street_number']} {address['street_name']} {address_type} {address['city']}, {address['state']} {address['zip']} {address['country']}" if fmt == "usps": - name = ' '.join(part for part in (address.get('first_name'), address.get('last_name')) if part) + name = " ".join( + part + for part in (address.get("first_name"), address.get("last_name")) + if part + ) return { - 'name': name, - 'company': '', - 'address_1': f"{address['street_number']} {address['street_name']} {address.get('address_type', '')} {address.get('address_type_number', '')}", - 'address_2': '', - 'city': address['city'], - 'state': address['state'], - 'zipcode': address['zip'], - 'zipcode_ext': '', - 'phone': '' + "name": name, + "company": "", + "address_1": f"{address['street_number']} {address['street_name']} {address.get('address_type', '')} {address.get('address_type_number', '')}", + "address_2": "", + "city": address["city"], + "state": address["state"], + "zipcode": address["zip"], + "zipcode_ext": "", + "phone": "", } return address @@ -395,7 +406,9 @@ def add_e911_address(address, extension, auto_correct=True): if auto_correct: n_address = result["errors"][0]["detail"] - logger.warning(f"Submitting updated address change:\n{json.dumps(n_address, indent=4)}") + logger.warning( + f"Submitting updated address change:\n{json.dumps(n_address, indent=4)}" + ) result = add_e911_address(n_address, extension, auto_correct=False) return result @@ -405,7 +418,9 @@ def add_e911_address(address, extension, auto_correct=True): logger.error(f"Error processing request: \n{json.dumps(result, indent=4)}") return result if r.status_code == 201: - logger.info(f"Successfully added E911 Address: {r.status_code} {r.reason} | {r.request.body}.") + logger.info( + f"Successfully added E911 Address: {r.status_code} {r.reason} | {r.request.body}." + ) logger.info(f"Be sure to associate the number with the address.") except Exception as e: logger.critical(f"Exception: {e}") @@ -839,7 +854,7 @@ def menu(): account_name = account["display"] account_id = account["account_id"] if str(extension) == "7001": - x_pos = 736 # TODO: Set to last position / before ranged numbers. + x_pos = 736 # TODO: Set to last position / before ranged numbers. position = input(f"What position to add new record to: [{x_pos}] ") or x_pos if extension == "7001": label = "Available" @@ -1156,8 +1171,54 @@ def menu(): get_e911_info(e911_id) +def prompt_credentials(config): + """Prompt for credentials""" + + print(f"{bcolors.HEADER}DO NOT SHARE YOUR CREDENTIALS WITH ANYONE.{bcolors.ENDC}") + + config["username"] = input("Enter your api.switchvoxuc.com username: ") + config["password"] = input("Enter your api.switchvoxuc.com password: ") + config["provider_username"] = input("Enter your api.nwsip.com username: ") + config["provider_password"] = input("Enter your api.nwsip.com password: ") + + print(f"{bcolors.HEADER}Configure additoinal tenant credentials.{bcolors.ENDC}") + tenant = input("Enter your tenant name or enter for None: ") or None + if tenant is not None: + tenant = tenant.upper() + config["tenant"] = {tenant: {}} + config["tenant"][tenant]["username"] = input( + f"Enter your {bcolors.OKBLUE}{tenant}{bcolors.ENDC} api.switchvoxuc.com username: " + ) + config["tenant"][tenant]["password"] = input( + f"Enter your {bcolors.OKBLUE}{tenant}{bcolors.ENDC} api.switchvoxuc.com password: " + ) + config["tenant"][tenant]["provider_username"] = input( + f"Enter your {bcolors.OKBLUE}{tenant}{bcolors.ENDC} api.nwsip.com username: " + ) + config["tenant"][tenant]["provider_password"] = input( + f"Enter your {bcolors.OKBLUE}{tenant}{bcolors.ENDC} api.nwsip.com password: " + ) + + return config + + if __name__ == "__main__": + try: + config_data = [prompt_credentials(config_data[0])] + show_disclaimer() + disclaimer_accepted = ( + input( + "Do you accept the disclaimer? You must enter 'ACCEPT' in all capitals: " + ) + or disclaimer_accepted + ) + + if disclaimer_accepted != "ACCEPT": + logger.info( + f"The user {config_data[0]['username']} for regcode {config_data[0]['regcode']} did not accept the use and terms your rejections has been logged." + ) + sys.exit(0) set_tenant() while True: menu()