diff --git a/applications/crossbar/doc/conference.md b/applications/crossbar/doc/conference.md index 8190df9edd0..580209162ac 100644 --- a/applications/crossbar/doc/conference.md +++ b/applications/crossbar/doc/conference.md @@ -192,7 +192,27 @@ Dial-able endpoints are Note: Phone numbers will involve some internal legs being generated (loopback legs) to process the number as if it was a call coming in for the desired number. This means billing and limits will be applied just the same as if a user dialed the number from their device. -**Examples** +#### Dial schema + +Schema for conference dial API command + + + +Key | Description | Type | Default | Required | Support Level +--- | ----------- | ---- | ------- | -------- | ------------- +`caller_id_name` | Caller ID Name to use when dialing out to endpoints | `string()` | | `false` | +`caller_id_number` | Caller ID Number to use when dialing out to endpoints | `string()` | | `false` | +`endpoints.[]` | | `string()|[#/definitions/devices](#devices)` | | | +`endpoints` | Endpoints to dial out to and join to the conference | `array()` | | `true` | +`participant_flags.[]` | | `string('mute' | 'deaf' | 'distribute_dtmf' | 'is_moderator' | 'disable_moh' | 'ghost' | 'join_existing' | 'video_mute')` | | `false` | +`participant_flags` | Participant flags applied to each endpoint when it joins the conference | `array(string('mute' | 'deaf' | 'distribute_dtmf' | 'is_moderator' | 'disable_moh' | 'ghost' | 'join_existing' | 'video_mute'))` | | `false` | +`profile_name` | The profile name to use for configuration | `string()` | | `false` | +`target_call_id` | Existing UUID to use as a hint for where to start the conference | `string()` | | `false` | +`timeout` | How long to try to reach the endpoint(s) | `integer()` | | `false` | + + + +#### Example payloads ```json { diff --git a/applications/crossbar/priv/api/swagger.json b/applications/crossbar/priv/api/swagger.json index 198f0ea6781..d45a6fc746f 100644 --- a/applications/crossbar/priv/api/swagger.json +++ b/applications/crossbar/priv/api/swagger.json @@ -11702,6 +11702,9 @@ }, "UUID": { "type": "string" + }, + "Zone": { + "type": "string" } }, "required": [ diff --git a/applications/crossbar/priv/couchdb/schemas/kapi.conference.search_resp.json b/applications/crossbar/priv/couchdb/schemas/kapi.conference.search_resp.json index a5f617b8843..213c753fbdf 100644 --- a/applications/crossbar/priv/couchdb/schemas/kapi.conference.search_resp.json +++ b/applications/crossbar/priv/couchdb/schemas/kapi.conference.search_resp.json @@ -56,6 +56,9 @@ }, "UUID": { "type": "string" + }, + "Zone": { + "type": "string" } }, "required": [ diff --git a/applications/crossbar/src/modules/cb_conferences.erl b/applications/crossbar/src/modules/cb_conferences.erl index ffff76d2028..c5dc3260da2 100644 --- a/applications/crossbar/src/modules/cb_conferences.erl +++ b/applications/crossbar/src/modules/cb_conferences.erl @@ -483,16 +483,16 @@ exec_dial_endpoints(Context, ConferenceId, Data, ToDial) -> ,{<<"Conference-ID">>, ConferenceId} ,{<<"Custom-Application-Vars">>, CAVs} ,{<<"Endpoints">>, ToDial} - ,{<<"Participant-Flags">>, kz_json:get_list_value(<<"participant_flags">>, Data)} - ,{<<"Profile-Name">>, kz_json:get_ne_binary_value(<<"profile_name">>, Data)} ,{<<"Msg-ID">>, cb_context:req_id(Context)} ,{<<"Outbound-Call-ID">>, kz_json:get_ne_binary_value(<<"outbound_call_id">>, Data)} + ,{<<"Participant-Flags">>, kz_json:get_list_value(<<"participant_flags">>, Data)} + ,{<<"Profile-Name">>, kz_json:get_ne_binary_value(<<"profile_name">>, Data)} ,{<<"Target-Call-ID">>, TargetCallId} ,{<<"Timeout">>, Timeout} | kz_api:default_headers(?APP_NAME, ?APP_VERSION) ], - Zone = zone(TargetCallId), + Zone = zone(ConferenceId, TargetCallId), case kz_amqp_worker:call(Command ,fun(P) -> kapi_conference:publish_dial(Zone, P) end ,fun kapi_conference:dial_resp_v/1 @@ -512,10 +512,10 @@ exec_dial_endpoints(Context, ConferenceId, Data, ToDial) -> ]) end. --spec zone(kz_term:api_ne_binary()) -> kz_term:ne_binary(). -zone('undefined') -> - kz_config:zone('binary'); -zone(TargetCallId) -> +-spec zone(kz_term:ne_binary(), kz_term:api_ne_binary()) -> kz_term:ne_binary(). +zone(ConferenceId, 'undefined') -> + discover_conference_zone(ConferenceId); +zone(ConferenceId, TargetCallId) -> Req = [{<<"Call-ID">>, TargetCallId} ,{<<"Fields">>, <<"all">>} ,{<<"Active-Only">>, 'true'} @@ -533,10 +533,22 @@ zone(TargetCallId) -> lager:info("got back channel resp, using target ~s zone ~s", [TargetCallId, Zone]), Zone; _E -> - lager:info("target ~s not found (~p), using local zone: ~p" - ,[TargetCallId, _E, kz_config:zone('binary')] + lager:info("target ~s not found (~p), checking conference id ~s" + ,[TargetCallId, _E, ConferenceId] ), - kz_config:zone('binary') + discover_conference_zone(ConferenceId) + end. + +-spec discover_conference_zone(kz_term:ne_binary()) -> kz_term:ne_binary(). +discover_conference_zone(ConferenceId) -> + case kapps_conference_command:search(ConferenceId, ?APP_NAME, ?APP_VERSION) of + {'error', _E} -> + lager:debug("failed to search for ~s: ~p", [ConferenceId, _E]), + kz_config:zone('binary'); + {'ok', SearchResp} -> + Zone = kz_json:get_ne_binary_value(<<"Zone">>, SearchResp, kz_config:zone('binary')), + lager:debug("found conference ~s in zone ~s", [ConferenceId, Zone]), + Zone end. -record(build_acc, {endpoints = [] :: kz_json:objects() diff --git a/applications/ecallmgr/src/ecallmgr_fs_conferences.erl b/applications/ecallmgr/src/ecallmgr_fs_conferences.erl index 8135a64275c..d99d35dd334 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_conferences.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_conferences.erl @@ -223,6 +223,7 @@ handle_search_conference(JObj, _Props, Name) -> ,{<<"Switch-External-IP">>, ExternalIP} ,{<<"Participant-Count">>, length(Participants)} ,{<<"Participants">>, participants_to_json(Participants)} + ,{<<"Zone">>, kz_config:zone('binary')} | kz_api:default_headers(?APP_NAME, ?APP_VERSION) ], kapi_conference:publish_search_resp(kz_api:server_id(JObj), Resp); @@ -467,7 +468,7 @@ conference_control_node(Node, Props, undefined) -> UUID = kzd_freeswitch:call_id(Props), CtrlNode = kz_nodes:whapp_oldest_node(ecallmgr), ToSet = [{<<"Ecallmgr-Node">>, kz_term:to_binary(CtrlNode)}], - ecallmgr_fs_command:bg_set(Node, UUID, ToSet), + _ = ecallmgr_fs_command:bg_set(Node, UUID, ToSet), CtrlNode; conference_control_node(_Node, _Props, Value) -> Value. diff --git a/core/kazoo_amqp/src/api/kapi_conference.erl b/core/kazoo_amqp/src/api/kapi_conference.erl index 57763b09950..029850aebf9 100644 --- a/core/kazoo_amqp/src/api/kapi_conference.erl +++ b/core/kazoo_amqp/src/api/kapi_conference.erl @@ -119,6 +119,7 @@ ,<<"Switch-Hostname">> ,<<"Switch-URL">> ,<<"UUID">> + ,<<"Zone">> ]). -define(SEARCH_RESP_VALUES, [{<<"Event-Category">>, <<"conference">>} ,{<<"Event-Name">>, <<"search_resp">>} diff --git a/core/kazoo_call/src/kapps_conference_command.erl b/core/kazoo_call/src/kapps_conference_command.erl index ba2edec6d8a..6cb67635e50 100644 --- a/core/kazoo_call/src/kapps_conference_command.erl +++ b/core/kazoo_call/src/kapps_conference_command.erl @@ -8,7 +8,7 @@ -include("kapps_call_command.hrl"). --export([search/1]). +-export([search/1, search/3]). -export([deaf_participant/2]). -export([participant_energy/3]). -export([kick/1, kick/2]). @@ -33,10 +33,18 @@ -spec search(kapps_conference:conference()) -> {'ok', kz_json:object()} | {'error', any()}. + search(Conference) -> AppName = kapps_conference:application_name(Conference), AppVersion = kapps_conference:application_version(Conference), ConferenceId = kapps_conference:id(Conference), + + search(ConferenceId, AppName, AppVersion). + +-spec search(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary()) -> + {'ok', kz_json:object()} | + {'error', any()}. +search(ConferenceId, AppName, AppVersion) -> Req = [{<<"Conference-ID">>, ConferenceId} | kz_api:default_headers(AppName, AppVersion) ], diff --git a/scripts/validate_mkdocs.py b/scripts/validate_mkdocs.py index 1d14e073d9f..0f8cba41032 100755 --- a/scripts/validate_mkdocs.py +++ b/scripts/validate_mkdocs.py @@ -1,7 +1,7 @@ -#!/usr/bin/env python2 -from __future__ import print_function +#!/usr/bin/env python3 import yaml, os.path, sys +from functools import reduce # from https://stackoverflow.com/questions/5574702/how-to-print-to-stderr-in-python def eprint(*args, **kwargs): @@ -25,7 +25,7 @@ def parse_page_string(errors_detected, page): def parse_page(errors_detected, page): "parse a page for existence" if isinstance(page, dict): - return reduce(parse_page_dict, page.items(), errors_detected) + return reduce(parse_page_dict, list(page.items()), errors_detected) elif isinstance(page, list): return reduce(parse_page, page, errors_detected) elif isinstance(page, str): @@ -34,11 +34,11 @@ def parse_page(errors_detected, page): return errors_detected stream = open("doc/mkdocs/mkdocs.yml", 'r') -mkdocs = yaml.load_all(stream) +mkdocs = yaml.safe_load_all(stream) errors_detected = False for doc in mkdocs: - for k,v in doc.items(): + for k,v in list(doc.items()): if "pages" == k: errors_detected = parse_page(False, v)