copied from internal repo
This commit is contained in:
0
lib/__init__.py
Normal file
0
lib/__init__.py
Normal file
292
lib/create_sip_trunk.py
Normal file
292
lib/create_sip_trunk.py
Normal file
@@ -0,0 +1,292 @@
|
||||
import argparse
|
||||
import configparser
|
||||
import os
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
from itertools import product
|
||||
|
||||
from conpeek_setup import util
|
||||
from conpeek_setup.api import operator_api
|
||||
|
||||
|
||||
def unpack_regex(regex):
|
||||
# Helper function to expand ranges and lists within square brackets, e.g., [2-5] or [234]
|
||||
def expand_square_brackets(pattern):
|
||||
expanded = []
|
||||
content = pattern[1:-1] # Remove the square brackets
|
||||
if '-' in content:
|
||||
# Handle ranges like [2-5]
|
||||
start, end = content.split('-')
|
||||
expanded = [str(i) for i in range(int(start), int(end) + 1)]
|
||||
elif pattern == '\\d':
|
||||
return [str(i) for i in range(10)]
|
||||
else:
|
||||
# Handle specific digits like [234]
|
||||
expanded = list(content)
|
||||
return expanded
|
||||
|
||||
# Split the regex into parts of digits and square bracket patterns
|
||||
# This regex splits on digits and square brackets with their content
|
||||
parts = re.findall(r'\[\d+-\d+\]|\[\d+\]|\d+|\\d', regex)
|
||||
|
||||
# Process parts to generate all possible values
|
||||
expanded_parts = []
|
||||
|
||||
for part in parts:
|
||||
if part.startswith('[') and part.endswith(']'):
|
||||
# Handle square brackets
|
||||
expanded_parts.append(expand_square_brackets(part))
|
||||
elif part == '\d':
|
||||
expanded_parts.append(expand_square_brackets(part))
|
||||
|
||||
else:
|
||||
# Handle digits
|
||||
expanded_parts.append([part])
|
||||
|
||||
for combination in product(*expanded_parts):
|
||||
print(''.join(combination))
|
||||
|
||||
# Generate all combinations of expanded parts
|
||||
possible_values = [''.join(combination) for combination in product(*expanded_parts)]
|
||||
|
||||
print(possible_values)
|
||||
|
||||
return possible_values
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="")
|
||||
parser.add_argument("--config", type=str, required=True, help="Path to the config file")
|
||||
parser.add_argument("--user", type=str, required=True, help="Operator login")
|
||||
parser.add_argument("--password", type=str, required=True, help="Operator password")
|
||||
parser.add_argument("--output-path", type=str, required=False, help="Path to the output")
|
||||
|
||||
args = parser.parse_args()
|
||||
config = configparser.ConfigParser()
|
||||
|
||||
config_directory = args.config
|
||||
if not os.path.abspath(config_directory):
|
||||
config_directory = os.path.join(pathlib.Path(__file__).parent.resolve(), config_directory)
|
||||
config.read(config_directory)
|
||||
if args.output_path:
|
||||
util.Settings.output_directory = args.output_path
|
||||
|
||||
output_directory = os.path.join(util.get_output_path(), "freeswitch")
|
||||
template_freeswitch_directory = os.path.join(util.get_templates_path(), "freeswitch/conf")
|
||||
|
||||
app_domain = config["new_machine_network"]["app_installation_domain"]
|
||||
api = operator_api.OperatorAPI(app_domain)
|
||||
api.login(args.user, args.password)
|
||||
|
||||
tenant = None
|
||||
tenants = api.get_tenants()
|
||||
for o_tenant in tenants:
|
||||
tenant = o_tenant
|
||||
break
|
||||
|
||||
if not tenant:
|
||||
util.print_red("Tenant not exists. First you need to create tenant and the run this script.")
|
||||
sys.exit()
|
||||
|
||||
# sip trunks
|
||||
for section in config:
|
||||
if not section.startswith("sip_trunk_"):
|
||||
continue
|
||||
|
||||
operator = "default"
|
||||
if config.has_option(section, "operator") and config[section]["operator"]:
|
||||
if config[section]["operator"] not in util.Constants.sip_trunk_operators:
|
||||
util.print_red(f'Operator does not exists {config[section]["operator"]}. Using default sip trunk!')
|
||||
else:
|
||||
operator = config[section]["operator"]
|
||||
|
||||
siptrunk_number = section[10:]
|
||||
proxy = config[section]["proxy"]
|
||||
|
||||
SIP_TRUNK_NUMBER = str(int(siptrunk_number) + 1)
|
||||
SIP_TRUNK_INTERNAL_PORT = 5100 + int(siptrunk_number)
|
||||
SIP_TRUNK_NAME = f"ic{siptrunk_number}"
|
||||
SIP_TRUNK_NAME_WITH_PORT = f"{SIP_TRUNK_NAME}_{SIP_TRUNK_INTERNAL_PORT}"
|
||||
SIP_PROFILE_NAME = f"gw1_external_{siptrunk_number}_{SIP_TRUNK_INTERNAL_PORT}"
|
||||
|
||||
template_freeswitch_directory_operator = os.path.join(util.get_templates_path(), f"freeswitch/{operator}")
|
||||
|
||||
sip_profile_template_path = os.path.join(template_freeswitch_directory_operator, "sip_profiles/gw_external.xml")
|
||||
if not os.path.exists(sip_profile_template_path):
|
||||
sip_profile_template_path = os.path.join(template_freeswitch_directory, "sip_profiles/gw_external.xml")
|
||||
|
||||
sip_profile_output_path = os.path.join(output_directory, f"conf/sip_profiles/{SIP_PROFILE_NAME}.xml")
|
||||
if os.path.exists(sip_profile_output_path):
|
||||
util.print_red(f"SIP profile {sip_profile_output_path} exists.")
|
||||
continue
|
||||
else:
|
||||
util.copy_file(sip_profile_template_path, sip_profile_output_path)
|
||||
|
||||
SIP_TRUNK_USERNAME = ""
|
||||
if config.has_option(section, "username"):
|
||||
SIP_TRUNK_USERNAME = config[section]["username"]
|
||||
|
||||
SIP_TRUNK_PASSWORD = ""
|
||||
if config.has_option(section, "password"):
|
||||
SIP_TRUNK_PASSWORD = config[section]["password"]
|
||||
|
||||
sip_profile_replacements = {
|
||||
'SIP_PROFILE_NAME': SIP_PROFILE_NAME,
|
||||
'SIP_TRUNK_NAME_WITH_PORT': SIP_TRUNK_NAME_WITH_PORT,
|
||||
'SIP_TRUNK_PROXY': proxy,
|
||||
'SIP_TRUNK_INTERNAL_PORT': str(SIP_TRUNK_INTERNAL_PORT),
|
||||
'SIP_TRUNK_USERNAME': SIP_TRUNK_USERNAME,
|
||||
'SIP_TRUNK_PASSWORD': SIP_TRUNK_PASSWORD,
|
||||
'EXTERNAL_IP': config["new_machine_network"]["external_ip"],
|
||||
'INTERNAL_IP': config["new_machine_network"]["internal_ip"],
|
||||
}
|
||||
|
||||
for name in sip_profile_replacements.keys():
|
||||
util.basic_on_location_sed(sip_profile_output_path, name, sip_profile_replacements[name])
|
||||
|
||||
operator_gateways = api.get_operator_gateways()
|
||||
operator_gateway = None
|
||||
for o_gateway in operator_gateways:
|
||||
if o_gateway["name"] == SIP_TRUNK_NAME:
|
||||
operator_gateway = o_gateway
|
||||
break
|
||||
|
||||
tenant_telco_networks = api.get_tenant_telco_networks(tenant["id"])
|
||||
tenant_has_telco_network_exists = False
|
||||
for tenant_has_telco_network in tenant_telco_networks:
|
||||
if tenant_has_telco_network["gateway_external_sip_port"] == SIP_TRUNK_INTERNAL_PORT:
|
||||
tenant_has_telco_network_exists = True
|
||||
break
|
||||
|
||||
if not tenant_has_telco_network_exists:
|
||||
api.create_tenant_telco_network(tenant["id"], {
|
||||
"8021q_vlan_id": 0,
|
||||
"gateway_external_sip_port": SIP_TRUNK_INTERNAL_PORT,
|
||||
"telco_network_id": 1
|
||||
})
|
||||
|
||||
if not operator_gateway:
|
||||
util.print_black_light(f"Creating operator gateway {SIP_TRUNK_NAME}")
|
||||
operator_gateway = api.create_operator_gateway({
|
||||
"name": SIP_TRUNK_NAME,
|
||||
"validate_e164": True,
|
||||
"presentation_preservation_policy": "DISABLED",
|
||||
"telco_network_id": 1,
|
||||
"username": SIP_TRUNK_USERNAME,
|
||||
"password": SIP_TRUNK_PASSWORD
|
||||
})
|
||||
|
||||
if not operator_gateway:
|
||||
util.print_red(f"Cant insert to operator_gateway {SIP_TRUNK_NAME}.")
|
||||
continue
|
||||
|
||||
normalization_to_create = [{
|
||||
"direction": "outbound",
|
||||
"peer": "caller",
|
||||
"pattern": '^48([0-9]{9})$',
|
||||
"replacement": '\\1',
|
||||
"priority": 10
|
||||
}, {
|
||||
"direction": "inbound",
|
||||
"peer": "callee",
|
||||
"pattern": '^([0-9]{9})$',
|
||||
"replacement": '48\\1',
|
||||
"priority": 10
|
||||
}, {
|
||||
"direction": "inbound",
|
||||
"peer": "caller",
|
||||
"pattern": '^([0-9]{9})$',
|
||||
"replacement": '48\\1',
|
||||
"priority": 10
|
||||
}, {
|
||||
"direction": "inbound",
|
||||
"peer": "caller",
|
||||
"pattern": '^\\+([0-9]*)$',
|
||||
"replacement": '\\1',
|
||||
"priority": 10
|
||||
}, {
|
||||
"direction": "inbound",
|
||||
"peer": "caller",
|
||||
"pattern": '^00([0-9]*)$',
|
||||
"replacement": '\\1',
|
||||
"priority": 10
|
||||
}, {
|
||||
"direction": "outbound",
|
||||
"peer": "callee",
|
||||
"pattern": '^([0-9]*)$',
|
||||
"replacement": '+\\1',
|
||||
"priority": 10
|
||||
}]
|
||||
|
||||
for normalization in normalization_to_create:
|
||||
api.create_operator_gateway_normalization(operator_gateway["id"], normalization)
|
||||
|
||||
ddi = config[section]["ddi"]
|
||||
ddi = ddi.replace(",", ";")
|
||||
ddi_patterns = ddi.split(";")
|
||||
for ddi_pattern in ddi_patterns:
|
||||
if ddi_pattern.startswith("^") and ddi_pattern.endswith("$"):
|
||||
api.create_operator_routing({
|
||||
"priority": 100,
|
||||
"src_number_to_charge": ddi_pattern,
|
||||
"src_presentation_number": ".*",
|
||||
"dst": ".*",
|
||||
"operator_gateway_id": operator_gateway["id"]
|
||||
})
|
||||
|
||||
ddi_list = unpack_regex(ddi_pattern)
|
||||
if len(ddi_list) > 1000:
|
||||
util.print_red("There cannot be more than 1000 numbers -- invalid regexp pattern")
|
||||
sys.exit()
|
||||
|
||||
for ddi_number in ddi_list:
|
||||
api.create_ddi(tenant["id"], {
|
||||
"e164number": ddi_number,
|
||||
"fax_enabled": 1,
|
||||
"voice_enabled": 1,
|
||||
"sms_enabled": 0,
|
||||
"operator_gateway_id": operator_gateway["id"]
|
||||
})
|
||||
|
||||
elif "-" in ddi_pattern:
|
||||
from_number = int(ddi_pattern.split("-")[0])
|
||||
to_number = int(ddi_pattern.split("-")[1])
|
||||
|
||||
numbers = set(range(from_number, to_number + 1))
|
||||
if len(numbers) > 1000:
|
||||
util.print_red("There cannot be more than 1000 numbers")
|
||||
sys.exit()
|
||||
|
||||
for number in numbers:
|
||||
api.create_operator_routing({
|
||||
"priority": 100,
|
||||
"src_number_to_charge": f"^{number}$",
|
||||
"src_presentation_number": ".*",
|
||||
"dst": ".*",
|
||||
"operator_gateway_id": operator_gateway["id"]
|
||||
})
|
||||
|
||||
api.create_ddi(tenant["id"], {
|
||||
"e164number": number,
|
||||
"fax_enabled": 1,
|
||||
"voice_enabled": 1,
|
||||
"sms_enabled": 0,
|
||||
"operator_gateway_id": operator_gateway["id"]
|
||||
})
|
||||
else:
|
||||
api.create_operator_routing({
|
||||
"priority": 100,
|
||||
"src_number_to_charge": f"^{ddi_pattern}$",
|
||||
"src_presentation_number": ".*",
|
||||
"dst": ".*",
|
||||
"operator_gateway_id": operator_gateway["id"]
|
||||
})
|
||||
|
||||
api.create_ddi(tenant["id"], {
|
||||
"e164number": ddi_pattern,
|
||||
"fax_enabled": 1,
|
||||
"voice_enabled": 1,
|
||||
"sms_enabled": 0,
|
||||
"operator_gateway_id": operator_gateway["id"]
|
||||
})
|
||||
228
lib/create_tenant.py
Normal file
228
lib/create_tenant.py
Normal file
@@ -0,0 +1,228 @@
|
||||
import argparse
|
||||
import configparser
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
import pytz
|
||||
|
||||
from conpeek_setup import util
|
||||
from conpeek_setup.api import operator_api
|
||||
from conpeek_setup.api.tenant_api import TenantAPI
|
||||
|
||||
|
||||
def validate_config(config):
|
||||
sections_to_validate = [
|
||||
"tenant"
|
||||
]
|
||||
|
||||
for section in sections_to_validate:
|
||||
if not config.has_section(section):
|
||||
util.print_red(f"No {section} section in config")
|
||||
raise Exception(f"No {section} section in config")
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="")
|
||||
parser.add_argument("--config", type=str, required=True, help="Path to the config file")
|
||||
parser.add_argument("--user", type=str, required=True, help="Operator login")
|
||||
parser.add_argument("--password", type=str, required=True, help="Operator password")
|
||||
|
||||
args = parser.parse_args()
|
||||
config = configparser.ConfigParser()
|
||||
|
||||
config_directory = args.config
|
||||
if not os.path.abspath(config_directory):
|
||||
config_directory = os.path.join(pathlib.Path(__file__).parent.resolve(), config_directory)
|
||||
|
||||
config.read(config_directory)
|
||||
|
||||
validate_config(config)
|
||||
|
||||
app_domain = config["new_machine_network"]["app_installation_domain"]
|
||||
|
||||
api = operator_api.OperatorAPI(app_domain)
|
||||
util.print_black_light(f"Wait for start TenantLoginAPI")
|
||||
api.wait_for_start(f"{api.api_tenant_login_url}/tenant/check_connection")
|
||||
util.print_green(f"TenantLoginAPI Started")
|
||||
api.login(args.user, args.password)
|
||||
util.print_black_light(f"Wait for start OperatorAPI")
|
||||
api.wait_for_start()
|
||||
util.print_green(f"OperatorAPI Started")
|
||||
|
||||
tenant = None
|
||||
tenants = api.get_tenants()
|
||||
for o_tenant in tenants:
|
||||
tenant = o_tenant
|
||||
break
|
||||
|
||||
if not tenant:
|
||||
# Create Tenant if not exists
|
||||
print("Creating tenant...")
|
||||
tenant = api.create_tenant({
|
||||
"name": config["tenant"]["domain"],
|
||||
"domain": config["tenant"]["domain"],
|
||||
"time_zone": "Europe/Warsaw",
|
||||
"language": "pl",
|
||||
"active": 1,
|
||||
"estimated_number_of_users": 100,
|
||||
"allow_to_exceed_concurrent_packages": 0,
|
||||
"create_recording_checksum_file": 1,
|
||||
"video_recording_enabled": 0,
|
||||
"simultaneous_calls_limit": 100,
|
||||
"anonymous_sessions": 1,
|
||||
"access_network_id": 1,
|
||||
"plugin_enabled_domain_id": 1,
|
||||
"telco_network_id": 1
|
||||
})
|
||||
|
||||
util.print_black_light(f"Created tenant ({tenant['id']}) {tenant['name']}.")
|
||||
else:
|
||||
util.print_yellow(f"Tenant {config['tenant']['domain']} exists, id={tenant['id']}.")
|
||||
|
||||
license_packages = api.get_license_packages(tenant_id=tenant["id"])
|
||||
packages_count = {
|
||||
"Super Admin": 3,
|
||||
}
|
||||
|
||||
license_package_agreements = api.get_package_agreements(tenant_id=tenant["id"])
|
||||
for license_package in license_package_agreements:
|
||||
if license_package["operator_license_package_name"] in packages_count:
|
||||
if license_package["commercial_license_package_amount"] >= packages_count[license_package["operator_license_package_name"]]:
|
||||
util.print_black_light(f'Licenses {license_package["operator_license_package_name"]} exists.')
|
||||
del packages_count[license_package["operator_license_package_name"]]
|
||||
|
||||
super_admin_package_id = None
|
||||
package_activation_item_list = []
|
||||
for package_license in license_packages:
|
||||
if package_license["name"] == "Super Admin":
|
||||
super_admin_package_id = package_license["id"]
|
||||
if package_license["name"] in packages_count:
|
||||
package_activation_item_list.append({
|
||||
"license_package_amount": packages_count[package_license["name"]],
|
||||
"license_package_type": "COMMERCIAL",
|
||||
"concurrent_usage_limit": 0,
|
||||
"operator_license_package_id": package_license["id"]
|
||||
})
|
||||
|
||||
local_tz = pytz.timezone(tenant["time_zone"])
|
||||
local_now = datetime.now(local_tz)
|
||||
local_start_of_day = local_tz.localize(datetime(local_now.year, local_now.month, local_now.day, 0, 0, 0))
|
||||
utc_start_of_day = local_start_of_day.astimezone(pytz.utc)
|
||||
|
||||
if package_activation_item_list:
|
||||
api.create_package_activation_request(tenant_id=tenant["id"], params={
|
||||
"activate_date": utc_start_of_day.strftime("%Y-%m-%d %H:%M:%S"),
|
||||
"note": "Auto generated",
|
||||
"package_activation_item_list": package_activation_item_list
|
||||
})
|
||||
|
||||
# Create super administrators
|
||||
util.print_black_light("Creating super administrators...")
|
||||
super_admin_users_to_create = [
|
||||
{
|
||||
"username": "super1",
|
||||
"extension": "1001"
|
||||
},
|
||||
{
|
||||
"username": "super2",
|
||||
"extension": "1002"
|
||||
},
|
||||
{
|
||||
"username": "super3",
|
||||
"extension": "1003"
|
||||
}
|
||||
]
|
||||
|
||||
super_admin_users_to_create_list = []
|
||||
for user in super_admin_users_to_create:
|
||||
super_admin_users_to_create_list.append(user["username"])
|
||||
|
||||
users_in_tenant = []
|
||||
super_tenant_user_id = None
|
||||
tenant_api = None
|
||||
user_mapping = {}
|
||||
|
||||
users = api.get_users(tenant_id=tenant["id"])
|
||||
for user in users:
|
||||
if not super_tenant_user_id:
|
||||
super_tenant_user_id = user["id"]
|
||||
|
||||
user_mapping[user["username"]] = user["id"]
|
||||
if not tenant_api:
|
||||
login_data = api.login_as_user(tenant_id=tenant["id"], tenant_user_id=super_tenant_user_id)
|
||||
tenant_api = TenantAPI(app_domain)
|
||||
tenant_api.initialize_user_login(login_data)
|
||||
util.print_black_light(f"Wait for start TenantAPI")
|
||||
tenant_api.wait_for_start()
|
||||
util.print_green(f"TenantAPI Started")
|
||||
users_in_tenant.append(user["username"])
|
||||
|
||||
if super_admin_package_id:
|
||||
for user in super_admin_users_to_create:
|
||||
|
||||
if user["username"] in users_in_tenant:
|
||||
util.print_black_light(f'User {user["username"]} exists.')
|
||||
continue
|
||||
d_user = api.create_user(tenant_id=tenant["id"], params={
|
||||
"active": 1,
|
||||
"username": user["username"],
|
||||
"password": args.password,
|
||||
"main_license_package_id": super_admin_package_id,
|
||||
"language": "pl",
|
||||
"change_avatar_allowed": 1,
|
||||
"change_on_leave_allowed": 1,
|
||||
"on_leave": 0,
|
||||
"system_role": [],
|
||||
"tenant_role": []
|
||||
})
|
||||
|
||||
user_mapping[user["username"]] = d_user["id"]
|
||||
|
||||
if not super_tenant_user_id:
|
||||
super_tenant_user_id = d_user["id"]
|
||||
|
||||
if not tenant_api:
|
||||
login_data = api.login_as_user(tenant_id=tenant["id"], tenant_user_id=super_tenant_user_id)
|
||||
tenant_api = TenantAPI(app_domain)
|
||||
tenant_api.initialize_user_login(login_data)
|
||||
util.print_black_light(f"Wait for start TenantAPI")
|
||||
tenant_api.wait_for_start()
|
||||
util.print_green(f"TenantAPI Started")
|
||||
|
||||
tenant_api.update_feature_tenant_user_call(d_user["id"], {
|
||||
"call_enabled": 1,
|
||||
"extension": user["extension"],
|
||||
"click_to_dial_auto_answer": 1
|
||||
})
|
||||
|
||||
tenant_api.update_feature_tenant_user_consultant(d_user["id"], {
|
||||
"work_state": "ONLINE"
|
||||
})
|
||||
|
||||
tenant_api.update_feature_tenant_user_consultant(d_user["id"], {
|
||||
"audio_enabled": 1,
|
||||
"file_enabled": 1,
|
||||
"chat_enabled": 1
|
||||
})
|
||||
|
||||
tenant_api.update_feature_tenant_user_hotdesk(d_user["id"], {
|
||||
"hotdesk_enabled": 1,
|
||||
"hotdesk_identifier": user["extension"],
|
||||
"hotdesk_pin": user["extension"],
|
||||
})
|
||||
|
||||
tenant_api.create_web_link({
|
||||
"name": "Web",
|
||||
"tenant_user_id": d_user["id"],
|
||||
"audio": 1,
|
||||
"chat": 1,
|
||||
"video": 1,
|
||||
"call_timeout": 30,
|
||||
"priority": 100,
|
||||
"state": "ON",
|
||||
"user_device_type": "WEBAPP"
|
||||
})
|
||||
|
||||
if not tenant_api:
|
||||
sys.exit()
|
||||
Reference in New Issue
Block a user