diff --git a/Makefile b/Makefile index 193fcb8691c..0fcb8ad6edd 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ FMT = $(ROOT)/make/erlang-formatter-master/fmt.sh KAZOODIRS = core/Makefile applications/Makefile -.PHONY: $(KAZOODIRS) deps core apps xref xref_release dialyze dialyze-it dialyze-apps dialyze-core dialyze-kazoo clean clean-test clean-release build-release build-ci-release tar-release release read-release-cookie elvis install ci diff fmt bump-copyright apis validate-swagger coverage-report fs-headers +.PHONY: $(KAZOODIRS) deps core apps xref xref_release dialyze dialyze-it dialyze-apps dialyze-core dialyze-kazoo clean clean-test clean-release build-release build-ci-release tar-release release read-release-cookie elvis install ci diff fmt bump-copyright apis validate-swagger coverage-report fs-headers docs all: compile rel/dev-vm.args @@ -120,7 +120,7 @@ read-release-cookie: DIALYZER ?= dialyzer PLT ?= .kazoo.plt -OTP_APPS ?= erts kernel stdlib crypto public_key ssl asn1 inets +OTP_APPS ?= erts kernel stdlib crypto public_key ssl asn1 inets xmerl $(PLT): DEPS_SRCS ?= $(shell find $(ROOT)/deps -name src ) # $(PLT): CORE_EBINS ?= $(shell find $(ROOT)/core -name ebin) $(PLT): @@ -189,10 +189,14 @@ apis: @ERL_LIBS=deps/:core/:applications/ $(ROOT)/scripts/generate-schemas.escript @$(ROOT)/scripts/format-json.sh applications/crossbar/priv/couchdb/schemas/*.json @ERL_LIBS=deps/:core/:applications/ $(ROOT)/scripts/generate-api-endpoints.escript + @$(ROOT)/scripts/generate-doc-schemas.sh applications/crossbar/doc/ref/*.md @$(ROOT)/scripts/format-json.sh applications/crossbar/priv/api/swagger.json @$(ROOT)/scripts/format-json.sh applications/crossbar/priv/api/*.json @ERL_LIBS=deps/:core/:applications/ $(ROOT)/scripts/generate-fs-headers-hrl.escript +docs: + $(ROOT)/scripts/validate_mkdocs.py + fs-headers: @ERL_LIBS=deps/:core/:applications/ $(ROOT)/scripts/generate-fs-headers-hrl.escript diff --git a/applications/acdc/src/acdc.hrl b/applications/acdc/src/acdc.hrl index b35a7cf7f42..3568956367a 100644 --- a/applications/acdc/src/acdc.hrl +++ b/applications/acdc/src/acdc.hrl @@ -36,6 +36,10 @@ -type deliveries() :: [gen_listener:basic_deliver()]. +-type fsm_state_name() :: 'wait' | 'sync' | 'ready' | 'ringing' | + 'ringing_callback' | 'awaiting_callback' | + 'answered' | 'wrapup' | 'paused' | 'outbound'. + %% Check for cleanup every 5 minutes -define(CLEANUP_PERIOD, kapps_config:get_integer(?CONFIG_CAT, <<"cleanup_period_ms">>, 360000)). diff --git a/applications/acdc/src/acdc_agent_fsm.erl b/applications/acdc/src/acdc_agent_fsm.erl index 2412ad9afc1..ab89f2b243c 100644 --- a/applications/acdc/src/acdc_agent_fsm.erl +++ b/applications/acdc/src/acdc_agent_fsm.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Tracks the agent's state, responds to messages from the corresponding %%% acdc_agent gen_listener process. @@ -23,6 +23,8 @@ ,sync_req/2, sync_resp/2 ,pause/2 ,resume/1 + + ,add_acdc_queue/2, rm_acdc_queue/2 ,update_presence/3 ,agent_logout/1 ,refresh/2 @@ -275,6 +277,26 @@ pause(FSM, Timeout) -> resume(FSM) -> gen_fsm:send_all_state_event(FSM, {'resume'}). +%%-------------------------------------------------------------------- +%% @doc +%% Request the agent listener bind to queue and conditionally send an +%% availability update depending on agent state +%% @end +%%-------------------------------------------------------------------- +-spec add_acdc_queue(server_ref(), ne_binary()) -> 'ok'. +add_acdc_queue(FSM, QueueId) -> + gen_fsm:send_all_state_event(FSM, {'add_acdc_queue', QueueId}). + +%%-------------------------------------------------------------------- +%% @doc +%% Request the agent listener unbind from queue and send an +%% unavailability update +%% @end +%%-------------------------------------------------------------------- +-spec rm_acdc_queue(server_ref(), ne_binary()) -> 'ok'. +rm_acdc_queue(FSM, QueueId) -> + gen_fsm:send_all_state_event(FSM, {'rm_acdc_queue', QueueId}). + %%-------------------------------------------------------------------- %% @doc %% @end @@ -1340,6 +1362,12 @@ handle_event({'pause', _}=Event, StateName, #state{agent_state_updates=Queue}=St lager:debug("recv pause during ~p, delaying", [StateName]), NewQueue = [Event | Queue], {'next_state', StateName, State#state{agent_state_updates=NewQueue}}; +handle_event({'add_acdc_queue', QueueId}, StateName, #state{agent_listener=AgentListener}=State) -> + acdc_agent_listener:add_acdc_queue(AgentListener, QueueId, StateName), + {'next_state', StateName, State}; +handle_event({'rm_acdc_queue', QueueId}, StateName, #state{agent_listener=AgentListener}=State) -> + acdc_agent_listener:rm_acdc_queue(AgentListener, QueueId), + {'next_state', StateName, State}; handle_event({'update_presence', PresenceId, PresenceState}, 'ready', State) -> handle_presence_update(PresenceId, PresenceState, State), {'next_state', 'ready', State}; @@ -1347,7 +1375,7 @@ handle_event({'update_presence', _, _}=Event, StateName, #state{agent_state_upda NewQueue = [Event | Queue], {'next_state', StateName, State#state{agent_state_updates=NewQueue}}; handle_event({'refresh', AgentJObj}, StateName, #state{agent_listener=AgentListener}=State) -> - acdc_agent_listener:refresh_config(AgentListener, kz_json:get_value(<<"queues">>, AgentJObj)), + acdc_agent_listener:refresh_config(AgentListener, kz_json:get_value(<<"queues">>, AgentJObj), StateName), {'next_state', StateName, State}; handle_event('load_endpoints', StateName, #state{agent_listener='undefined'}=State) -> lager:debug("agent proc not ready, not loading endpoints yet"), @@ -1919,6 +1947,7 @@ apply_state_updates_fold({_, StateName, #state{account_id=AccountId acdc_agent_stats:agent_ready(AccountId, AgentId); 'wrapup' -> acdc_agent_stats:agent_wrapup(AccountId, AgentId, time_left(WRef)); 'paused' -> + acdc_agent_listener:send_agent_busy(AgentListener), acdc_agent_stats:agent_paused(AccountId, AgentId, time_left(PRef)) end, Acc; diff --git a/applications/acdc/src/acdc_agent_handler.erl b/applications/acdc/src/acdc_agent_handler.erl index 853005925e5..850642fff00 100644 --- a/applications/acdc/src/acdc_agent_handler.erl +++ b/applications/acdc/src/acdc_agent_handler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Handlers for various call events, acdc events, etc %%% @end @@ -70,7 +70,7 @@ maybe_agent_queue_change(AccountId, AgentId, <<"login_queue">>, QueueId, JObj) - lager:debug("queue login for agent ~s into ~s", [AgentId, QueueId]), case maybe_start_agent(AccountId, AgentId, JObj) of 'fail' -> lager:error("could not start agent process for ~s", [AgentId]); - Sup -> acdc_agent_listener:add_acdc_queue(acdc_agent_sup:listener(Sup), QueueId) + Sup -> acdc_agent_fsm:add_acdc_queue(acdc_agent_sup:fsm(Sup), QueueId) end; maybe_agent_queue_change(AccountId, AgentId, <<"logout_queue">>, QueueId, JObj) -> lager:debug("queue logout for agent ~s into ~s", [AgentId, QueueId]), @@ -78,7 +78,7 @@ maybe_agent_queue_change(AccountId, AgentId, <<"logout_queue">>, QueueId, JObj) 'undefined' -> lager:debug("agent process for ~s already stopped"); Sup -> maybe_update_presence(Sup, JObj), - acdc_agent_listener:rm_acdc_queue(acdc_agent_sup:listener(Sup), QueueId) + acdc_agent_fsm:rm_acdc_queue(acdc_agent_sup:fsm(Sup), QueueId) end. -spec maybe_start_agent(ne_binary(), ne_binary(), kz_json:object()) -> pid() | 'fail'. diff --git a/applications/acdc/src/acdc_agent_listener.erl b/applications/acdc/src/acdc_agent_listener.erl index 4728a770089..264e5c3a48a 100644 --- a/applications/acdc/src/acdc_agent_listener.erl +++ b/applications/acdc/src/acdc_agent_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -26,11 +26,12 @@ ,originate_uuid/3 ,outbound_call/2 ,send_agent_available/1 + ,send_agent_busy/1 ,send_sync_req/1 ,send_sync_resp/3, send_sync_resp/4 - ,config/1, refresh_config/2 + ,config/1, refresh_config/3 ,send_status_resume/1 - ,add_acdc_queue/2 + ,add_acdc_queue/3 ,rm_acdc_queue/2 ,call_status_req/1, call_status_req/2 ,stop/1 @@ -262,6 +263,10 @@ outbound_call(Srv, CallId) -> send_agent_available(Srv) -> gen_listener:cast(Srv, 'send_agent_available'). +-spec send_agent_busy(pid()) -> 'ok'. +send_agent_busy(Srv) -> + gen_listener:cast(Srv, 'send_agent_busy'). + -spec send_sync_req(pid()) -> 'ok'. send_sync_req(Srv) -> gen_listener:cast(Srv, {'send_sync_req'}). @@ -274,9 +279,10 @@ send_sync_resp(Srv, Status, ReqJObj, Options) -> -spec config(pid()) -> config(). config(Srv) -> gen_listener:call(Srv, 'config'). --spec refresh_config(pid(), api_ne_binaries()) -> 'ok'. -refresh_config(_, 'undefined') -> 'ok'; -refresh_config(Srv, Qs) -> gen_listener:cast(Srv, {'refresh_config', Qs}). +-spec refresh_config(pid(), api_ne_binaries(), fsm_state_name()) -> 'ok'. +refresh_config(_, 'undefined', _) -> 'ok'; +refresh_config(Srv, Qs, StateName) -> + gen_listener:cast(Srv, {'refresh_config', Qs, StateName}). -spec agent_info(pid(), kz_json:path()) -> kz_json:api_json_term(). agent_info(Srv, Field) -> gen_listener:call(Srv, {'agent_info', Field}). @@ -285,9 +291,9 @@ agent_info(Srv, Field) -> gen_listener:call(Srv, {'agent_info', Field}). send_status_resume(Srv) -> gen_listener:cast(Srv, {'send_status_update', 'resume'}). --spec add_acdc_queue(pid(), ne_binary()) -> 'ok'. -add_acdc_queue(Srv, Q) -> - gen_listener:cast(Srv, {'add_acdc_queue', Q}). +-spec add_acdc_queue(pid(), ne_binary(), fsm_state_name()) -> 'ok'. +add_acdc_queue(Srv, Q, StateName) -> + gen_listener:cast(Srv, {'add_acdc_queue', Q, StateName}). -spec rm_acdc_queue(pid(), ne_binary()) -> 'ok'. rm_acdc_queue(Srv, Q) -> @@ -433,11 +439,11 @@ handle_call(_Request, _From, #state{}=State) -> %% @end %%-------------------------------------------------------------------- -spec handle_cast(any(), state()) -> handle_cast_ret_state(state()). -handle_cast({'refresh_config', Qs}, #state{agent_queues=Queues}=State) -> +handle_cast({'refresh_config', Qs, StateName}, #state{agent_queues=Queues}=State) -> {Add, Rm} = acdc_agent_util:changed(Queues, Qs), Self = self(), - _ = [gen_listener:cast(Self, {'add_acdc_queue', A}) || A <- Add], + _ = [gen_listener:cast(Self, {'add_acdc_queue', A, StateName}) || A <- Add], _ = [gen_listener:cast(Self, {'rm_acdc_queue', R}) || R <- Rm], {'noreply', State}; handle_cast({'stop_agent', Req}, #state{supervisor=Supervisor}=State) -> @@ -455,16 +461,16 @@ handle_cast({'fsm_started', FSMPid}, State) -> handle_cast({'gen_listener', {'created_queue', Q}}, State) -> {'noreply', State#state{my_q=Q}, 'hibernate'}; -handle_cast({'add_acdc_queue', Q}, #state{agent_queues=Qs - ,acct_id=AcctId - ,agent_id=AgentId - }=State) when is_binary(Q) -> +handle_cast({'add_acdc_queue', Q, StateName}, #state{agent_queues=Qs + ,acct_id=AcctId + ,agent_id=AgentId + }=State) when is_binary(Q) -> case lists:member(Q, Qs) of 'true' -> lager:debug("queue ~s already added", [Q]), {'noreply', State}; 'false' -> - add_queue_binding(AcctId, AgentId, Q), + add_queue_binding(AcctId, AgentId, Q, StateName), {'noreply', State#state{agent_queues=[Q|Qs]}} end; @@ -494,7 +500,7 @@ handle_cast('bind_to_member_reqs', #state{agent_queues=Qs ,acct_id=AcctId ,agent_id=AgentId }=State) -> - _ = [add_queue_binding(AcctId, AgentId, Q) || Q <- Qs], + _ = [add_queue_binding(AcctId, AgentId, Q, 'ready') || Q <- Qs], {'noreply', State}; handle_cast({'rebind_events', OldCallId, NewCallId}, State) -> @@ -667,6 +673,7 @@ handle_cast({'member_connect_accepted'}, #state{msg_queue_id=AmqpQueue ,call=Call ,acct_id=AcctId ,agent_id=AgentId + ,agent_queues=Qs ,my_id=MyId ,record_calls=ShouldRecord ,recording_url=RecordingUrl @@ -675,12 +682,14 @@ handle_cast({'member_connect_accepted'}, #state{msg_queue_id=AmqpQueue maybe_start_recording(Call, ShouldRecord, RecordingUrl), send_member_connect_accepted(AmqpQueue, call_id(Call), AcctId, AgentId, MyId), + [send_agent_busy(AcctId, AgentId, QueueId) || QueueId <- Qs], {'noreply', State}; handle_cast({'member_connect_accepted', ACallId}, #state{msg_queue_id=AmqpQueue ,call=Call ,acct_id=AcctId ,agent_id=AgentId + ,agent_queues=Qs ,my_id=MyId ,record_calls=ShouldRecord ,recording_url=RecordingUrl @@ -694,6 +703,7 @@ handle_cast({'member_connect_accepted', ACallId}, #state{msg_queue_id=AmqpQueue lager:debug("new agent call ids: ~p", [ACallIds1]), send_member_connect_accepted(AmqpQueue, call_id(Call), AcctId, AgentId, MyId), + [send_agent_busy(AcctId, AgentId, QueueId) || QueueId <- Qs], {'noreply', State#state{agent_call_ids=ACallIds1}, 'hibernate'}; handle_cast({'member_connect_resp', ReqJObj}, #state{agent_id=AgentId @@ -763,9 +773,13 @@ handle_cast({'originate_uuid', UUID, CtlQ}, #state{agent_call_ids=ACallIds}=Stat lager:debug("updating ~s with ~s in ~p", [UUID, CtlQ, ACallIds]), {'noreply', State#state{agent_call_ids=[{UUID, CtlQ} | props:delete(UUID, ACallIds)]}}; -handle_cast({'outbound_call', CallId}, State) -> +handle_cast({'outbound_call', CallId}, #state{agent_id=AgentId + ,acct_id=AcctId + ,agent_queues=Qs + }=State) -> _ = kz_util:put_callid(CallId), acdc_util:bind_to_call_events(CallId), + [send_agent_busy(AcctId, AgentId, QueueId) || QueueId <- Qs], lager:debug("bound to agent's outbound call ~s", [CallId]), {'noreply', State#state{call=kapps_call:set_call_id(CallId, kapps_call:new())}, 'hibernate'}; @@ -777,6 +791,13 @@ handle_cast('send_agent_available', #state{agent_id=AgentId [send_agent_available(AcctId, AgentId, QueueId) || QueueId <- Qs], {'noreply', State}; +handle_cast('send_agent_busy', #state{agent_id=AgentId + ,acct_id=AcctId + ,agent_queues=Qs + }=State) -> + [send_agent_busy(AcctId, AgentId, QueueId) || QueueId <- Qs], + {'noreply', State}; + handle_cast({'send_sync_req'}, #state{my_id=MyId ,my_q=MyQ ,acct_id=AcctId @@ -1127,8 +1148,9 @@ outbound_call_id(CallId, AgentId) when is_binary(CallId) -> outbound_call_id(Call, AgentId) -> outbound_call_id(kapps_call:call_id(Call), AgentId). --spec add_queue_binding(ne_binary(), ne_binary(), ne_binary()) -> 'ok'. -add_queue_binding(AcctId, AgentId, QueueId) -> +-spec add_queue_binding(ne_binary(), ne_binary(), ne_binary(), fsm_state_name()) -> + 'ok'. +add_queue_binding(AcctId, AgentId, QueueId, StateName) -> lager:debug("adding queue binding for ~s", [QueueId]), gen_listener:add_binding(self() ,'acdc_queue' @@ -1136,7 +1158,7 @@ add_queue_binding(AcctId, AgentId, QueueId) -> ,{'queue_id', QueueId} ,{'account_id', AcctId} ]), - send_agent_available(AcctId, AgentId, QueueId). + send_availability_update(AcctId, AgentId, QueueId, StateName). -spec rm_queue_binding(ne_binary(), ne_binary(), ne_binary()) -> 'ok'. rm_queue_binding(AcctId, AgentId, QueueId) -> @@ -1149,6 +1171,13 @@ rm_queue_binding(AcctId, AgentId, QueueId) -> ]), send_agent_unavailable(AcctId, AgentId, QueueId). +-spec send_availability_update(ne_binary(), ne_binary(), ne_binary(), fsm_state_name()) -> + 'ok'. +send_availability_update(AcctId, AgentId, QueueId, 'ready') -> + send_agent_available(AcctId, AgentId, QueueId); +send_availability_update(AcctId, AgentId, QueueId, _) -> + send_agent_busy(AcctId, AgentId, QueueId). + -spec send_agent_available(ne_binary(), ne_binary(), ne_binary()) -> 'ok'. send_agent_available(AcctId, AgentId, QueueId) -> Prop = [{<<"Account-ID">>, AcctId} @@ -1159,6 +1188,16 @@ send_agent_available(AcctId, AgentId, QueueId) -> ], kapi_acdc_queue:publish_agent_change(Prop). +-spec send_agent_busy(ne_binary(), ne_binary(), ne_binary()) -> 'ok'. +send_agent_busy(AcctId, AgentId, QueueId) -> + Prop = [{<<"Account-ID">>, AcctId} + ,{<<"Agent-ID">>, AgentId} + ,{<<"Queue-ID">>, QueueId} + ,{<<"Change">>, <<"busy">>} + | kz_api:default_headers(?APP_NAME, ?APP_VERSION) + ], + kapi_acdc_queue:publish_agent_change(Prop). + -spec send_agent_unavailable(ne_binary(), ne_binary(), ne_binary()) -> 'ok'. send_agent_unavailable(AcctId, AgentId, QueueId) -> Prop = [{<<"Account-ID">>, AcctId} diff --git a/applications/acdc/src/acdc_agent_maintenance.erl b/applications/acdc/src/acdc_agent_maintenance.erl index 21b18945013..a4c71e132aa 100644 --- a/applications/acdc/src/acdc_agent_maintenance.erl +++ b/applications/acdc/src/acdc_agent_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_agent_manager.erl b/applications/acdc/src/acdc_agent_manager.erl index 55ced795846..403c11d4d94 100644 --- a/applications/acdc/src/acdc_agent_manager.erl +++ b/applications/acdc/src/acdc_agent_manager.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Manages agent processes: %%% starting when an agent logs in diff --git a/applications/acdc/src/acdc_agent_stats.erl b/applications/acdc/src/acdc_agent_stats.erl index 2f9bd6608d4..86a8e8491f8 100644 --- a/applications/acdc/src/acdc_agent_stats.erl +++ b/applications/acdc/src/acdc_agent_stats.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% Collector of stats for agents %%% @end diff --git a/applications/acdc/src/acdc_agent_sup.erl b/applications/acdc/src/acdc_agent_sup.erl index 8605140d897..856b746f64a 100644 --- a/applications/acdc/src/acdc_agent_sup.erl +++ b/applications/acdc/src/acdc_agent_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_agent_util.erl b/applications/acdc/src/acdc_agent_util.erl index 961226d359a..e8883d65eea 100644 --- a/applications/acdc/src/acdc_agent_util.erl +++ b/applications/acdc/src/acdc_agent_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_agents_sup.erl b/applications/acdc/src/acdc_agents_sup.erl index c82866d5b0b..9d4b5e58190 100644 --- a/applications/acdc/src/acdc_agents_sup.erl +++ b/applications/acdc/src/acdc_agents_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_app.erl b/applications/acdc/src/acdc_app.erl index 8e862fadd4a..ca63963aa0f 100644 --- a/applications/acdc/src/acdc_app.erl +++ b/applications/acdc/src/acdc_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_eavesdrop.erl b/applications/acdc/src/acdc_eavesdrop.erl index 5b5398d491d..c687431e78e 100644 --- a/applications/acdc/src/acdc_eavesdrop.erl +++ b/applications/acdc/src/acdc_eavesdrop.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @author James Aimonetti <> %%% @doc %%% diff --git a/applications/acdc/src/acdc_handlers.erl b/applications/acdc/src/acdc_handlers.erl index 1c591ca34a4..2330812ccd8 100644 --- a/applications/acdc/src/acdc_handlers.erl +++ b/applications/acdc/src/acdc_handlers.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_init.erl b/applications/acdc/src/acdc_init.erl index c290ae18ecc..64254ce3615 100644 --- a/applications/acdc/src/acdc_init.erl +++ b/applications/acdc/src/acdc_init.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Iterate over each account, find configured queues and configured %%% agents, and start the attendant processes diff --git a/applications/acdc/src/acdc_listener.erl b/applications/acdc/src/acdc_listener.erl index 39df0ee43f7..75927c381fc 100644 --- a/applications/acdc/src/acdc_listener.erl +++ b/applications/acdc/src/acdc_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_maintenance.erl b/applications/acdc/src/acdc_maintenance.erl index 06a464b7b80..bcbfdcd3678 100644 --- a/applications/acdc/src/acdc_maintenance.erl +++ b/applications/acdc/src/acdc_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Helpers for cli commands %%% @end diff --git a/applications/acdc/src/acdc_queue_fsm.erl b/applications/acdc/src/acdc_queue_fsm.erl index a20c7fdfb9a..adc9fd3c315 100644 --- a/applications/acdc/src/acdc_queue_fsm.erl +++ b/applications/acdc/src/acdc_queue_fsm.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Controls how a queue process progresses a member_call %%% @end @@ -242,9 +242,6 @@ init([MgrPid, ListenerPid, QueueJObj]) -> -spec ready(any(), any(), state()) -> handle_sync_event_ret(state()). ready({'member_call', CallJObj, Delivery}, #state{queue_proc=QueueSrv ,manager_proc=MgrSrv - ,connection_timeout=ConnTimeout - ,connection_timer_ref=ConnRef - ,cdr_url=Url }=State) -> Call = kapps_call:from_json(kz_json:get_value(<<"Call">>, CallJObj)), CallId = kapps_call:call_id(Call), @@ -252,20 +249,7 @@ ready({'member_call', CallJObj, Delivery}, #state{queue_proc=QueueSrv case acdc_queue_manager:should_ignore_member_call(MgrSrv, Call, CallJObj) of 'false' -> - lager:debug("member call received: ~s", [CallId]), - - webseq:note(?WSD_ID, self(), 'right', [CallId, <<": member call">>]), - webseq:evt(?WSD_ID, CallId, self(), <<"member call received">>), - - acdc_queue_listener:member_connect_req(QueueSrv, CallJObj, Delivery, Url), - - maybe_stop_timer(ConnRef), % stop the old one, maybe - - {'next_state', 'connect_req', State#state{collect_ref=start_collect_timer() - ,member_call=Call - ,member_call_start=kz_util:current_tstamp() - ,connection_timer_ref=start_connection_timer(ConnTimeout) - }}; + maybe_delay_connect_req(Call, CallJObj, Delivery, State); 'true' -> lager:debug("queue mgr said to ignore this call: ~s", [CallId]), acdc_queue_listener:ignore_member_call(QueueSrv, Call, Delivery), @@ -808,6 +792,45 @@ elapsed(Ref) when is_reference(Ref) -> end; elapsed(Time) -> kz_util:elapsed_s(Time). +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% If some agents are busy, the manager will tell us to delay our +%% connect reqs +%% +%% @end +%%-------------------------------------------------------------------- +-spec maybe_delay_connect_req(kapps_call:call(), kz_json:object(), gen_listener:basic_deliver(), state()) -> + {'next_state', 'ready' | 'connect_req', state()}. +maybe_delay_connect_req(Call, CallJObj, Delivery, #state{queue_proc=QueueSrv + ,manager_proc=MgrSrv + ,connection_timeout=ConnTimeout + ,connection_timer_ref=ConnRef + ,cdr_url=Url + }=State) -> + CallId = kapps_call:call_id(Call), + case acdc_queue_manager:up_next(MgrSrv, CallId) of + 'true' -> + lager:debug("member call received: ~s", [CallId]), + + webseq:note(?WSD_ID, self(), 'right', [CallId, <<": member call">>]), + webseq:evt(?WSD_ID, CallId, self(), <<"member call received">>), + + acdc_queue_listener:member_connect_req(QueueSrv, CallJObj, Delivery, Url), + + maybe_stop_timer(ConnRef), % stop the old one, maybe + + {'next_state', 'connect_req', State#state{collect_ref=start_collect_timer() + ,member_call=Call + ,member_call_start=kz_util:current_tstamp() + ,connection_timer_ref=start_connection_timer(ConnTimeout) + }}; + 'false' -> + lager:debug("connect_req delayed (not up next)"), + gen_fsm:send_event_after(1000, {'member_call', CallJObj, Delivery}), + {'next_state', 'ready', State} + end. + %%-------------------------------------------------------------------- %% @private %% @doc @@ -825,10 +848,7 @@ maybe_connect_re_req(MgrSrv, ListenerSrv, #state{account_id=AccountId }=State) -> case acdc_queue_manager:are_agents_available(MgrSrv) of 'true' -> - lager:debug("done waiting, no agents responded, let's ask again"), - webseq:note(?WSD_ID, self(), 'right', <<"no agents responded, trying again">>), - acdc_queue_listener:member_connect_re_req(ListenerSrv), - {'next_state', 'connect_req', State#state{collect_ref=start_collect_timer()}}; + maybe_delay_connect_re_req(MgrSrv, ListenerSrv, State); 'false' -> lager:debug("all agents have left the queue, failing call"), webseq:note(?WSD_ID, self(), 'right', <<"all agents have left the queue, failing call">>), @@ -837,6 +857,22 @@ maybe_connect_re_req(MgrSrv, ListenerSrv, #state{account_id=AccountId {'next_state', 'ready', clear_member_call(State), 'hibernate'} end. +-spec maybe_delay_connect_re_req(pid(), pid(), state()) -> + {'next_state', 'connect_req', state()}. +maybe_delay_connect_re_req(MgrSrv, ListenerSrv, #state{member_call=Call}=State) -> + CallId = kapps_call:call_id(Call), + case acdc_queue_manager:up_next(MgrSrv, CallId) of + 'true' -> + lager:debug("done waiting, no agents responded, let's ask again"), + webseq:note(?WSD_ID, self(), 'right', <<"no agents responded, trying again">>), + acdc_queue_listener:member_connect_re_req(ListenerSrv), + {'next_state', 'connect_req', State#state{collect_ref=start_collect_timer()}}; + 'false' -> + lager:debug("connect_re_req delayed (not up next)"), + gen_fsm:send_event_after(1000, {'timeout', 'undefined', ?COLLECT_RESP_MESSAGE}), + {'next_state', 'connect_req', State#state{collect_ref='undefined'}} + end. + -spec accept_is_for_call(kz_json:object(), kapps_call:call()) -> boolean(). accept_is_for_call(AcceptJObj, Call) -> kz_json:get_value(<<"Call-ID">>, AcceptJObj) =:= kapps_call:call_id(Call). diff --git a/applications/acdc/src/acdc_queue_handler.erl b/applications/acdc/src/acdc_queue_handler.erl index 388615a0381..8dd77c8f74b 100644 --- a/applications/acdc/src/acdc_queue_handler.erl +++ b/applications/acdc/src/acdc_queue_handler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_queue_listener.erl b/applications/acdc/src/acdc_queue_listener.erl index db452fcfbfb..e1336a2c496 100644 --- a/applications/acdc/src/acdc_queue_listener.erl +++ b/applications/acdc/src/acdc_queue_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% The queue process manages two queues diff --git a/applications/acdc/src/acdc_queue_manager.erl b/applications/acdc/src/acdc_queue_manager.erl index 3b9c84fcbd0..0286b404f70 100644 --- a/applications/acdc/src/acdc_queue_manager.erl +++ b/applications/acdc/src/acdc_queue_manager.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Manages queue processes: %%% starting when a queue is created @@ -25,6 +25,7 @@ ,are_agents_available/1 ,handle_config_change/2 ,should_ignore_member_call/3, should_ignore_member_call/4 + ,up_next/2 ,config/1 ,status/1 ,current_agents/1 @@ -44,6 +45,12 @@ ,code_change/3 ]). +-ifdef(TEST). +-export([ss_size/2 + ,update_strategy_with_agent/5 + ]). +-endif. + -include("acdc.hrl"). -include("acdc_queue_manager.hrl"). @@ -211,6 +218,8 @@ handle_agent_change(JObj, Prop) -> gen_listener:cast(Server, {'agent_available', JObj}); <<"ringing">> -> gen_listener:cast(Server, {'agent_ringing', JObj}); + <<"busy">> -> + gen_listener:cast(Server, {'agent_busy', JObj}); <<"unavailable">> -> gen_listener:cast(Server, {'agent_unavailable', JObj}) end. @@ -239,6 +248,10 @@ should_ignore_member_call(Srv, Call, AccountId, QueueId) -> K = make_ignore_key(AccountId, QueueId, kapps_call:call_id(Call)), gen_listener:call(Srv, {'should_ignore_member_call', K}). +-spec up_next(pid(), ne_binary()) -> boolean(). +up_next(Srv, CallId) -> + gen_listener:call(Srv, {'up_next', CallId}). + -spec config(pid()) -> {ne_binary(), ne_binary()}. config(Srv) -> gen_listener:call(Srv, 'config'). @@ -334,26 +347,27 @@ handle_call({'should_ignore_member_call', {AccountId, QueueId, CallId}=K}, _, #s {'reply', 'true', State#state{ignored_member_calls=dict:erase(K, Dict)}} end; +handle_call({'up_next', CallId}, _, #state{strategy_state=SS + ,current_member_calls=CurrentCalls + }=State) -> + Available = ss_size(SS, 'free'), + Reply = up_next_fold(lists:reverse(CurrentCalls), CallId, Available), + {'reply', Reply, State}; + handle_call('config', _, #state{account_id=AccountId ,queue_id=QueueId }=State) -> {'reply', {AccountId, QueueId}, State}; -handle_call('status', _, #state{known_agents=As}=State) -> - Known = [A || {A, N} <- dict:to_list(As), N > 0], +handle_call('status', _, #state{strategy_state=#strategy_state{details=Details}}=State) -> + Known = [A || {A, {N, _}} <- dict:to_list(Details), N > 0], {'reply', Known, State}; handle_call('strategy', _, #state{strategy=Strategy}=State) -> {'reply', Strategy, State, 'hibernate'}; -handle_call('agents_available', _, #state{strategy_state='undefined'}=State) -> - {'reply', 0, State}; -handle_call('agents_available', _, #state{strategy_state=[]}=State) -> - {'reply', 0, State}; -handle_call('agents_available', _, #state{strategy_state=[_|_]}=State) -> - {'reply', 1, State}; handle_call('agents_available', _, #state{strategy_state=SS}=State) -> - {'reply', queue:len(SS), State}; + {'reply', ss_size(SS, 'logged_in'), State}; handle_call('enter_when_empty', _, #state{enter_when_empty=EnterWhenEmpty}=State) -> {'reply', EnterWhenEmpty, State}; @@ -361,21 +375,21 @@ handle_call('enter_when_empty', _, #state{enter_when_empty=EnterWhenEmpty}=State handle_call('next_winner', _, #state{strategy='mi'}=State) -> {'reply', 'undefined', State}; handle_call('next_winner', _, #state{strategy='rr' - ,strategy_state=SS + ,strategy_state=#strategy_state{agents=Agents}=SS }=State) -> - case queue:out(SS) of - {{'value', Winner}, SS1} -> - {'reply', Winner, State#state{strategy_state=queue:in(Winner, SS1)}, 'hibernate'}; + case queue:out(Agents) of + {{'value', Winner}, Agents1} -> + {'reply', Winner, State#state{strategy_state=SS#strategy_state{agents=queue:in(Winner, Agents1)}}, 'hibernate'}; {'empty', _} -> {'reply', 'undefined', State} end; handle_call('current_agents', _, #state{strategy='rr' - ,strategy_state=Q + ,strategy_state=#strategy_state{agents=Q} }=State) -> {'reply', queue:to_list(Q), State}; handle_call('current_agents', _, #state{strategy='mi' - ,strategy_state=L + ,strategy_state=#strategy_state{agents=L} }=State) -> {'reply', L, State}; @@ -427,6 +441,9 @@ handle_cast({'start_workers'}, #state{account_id=AccountId ,'include_docs' ]) of + {'ok', []} -> + lager:debug("no agents yet, but create a worker anyway"), + acdc_queue_workers_sup:new_worker(WorkersSup, AccountId, QueueId); {'ok', Agents} -> _ = [start_agent_and_worker(WorkersSup, AccountId, QueueId ,kz_json:get_value(<<"doc">>, A) @@ -453,13 +470,12 @@ handle_cast({'start_worker', N}, #state{account_id=AccountId handle_cast({'agent_available', AgentId}, #state{strategy=Strategy ,strategy_state=StrategyState - ,known_agents=As + ,supervisor=QueueSup }=State) when is_binary(AgentId) -> lager:info("adding agent ~s to strategy ~s", [AgentId, Strategy]), - {StrategyState1, As1} = update_strategy_with_agent(Strategy, StrategyState, As, AgentId, 'add'), - {'noreply', State#state{strategy_state=StrategyState1 - ,known_agents=As1 - } + StrategyState1 = update_strategy_with_agent(Strategy, StrategyState, AgentId, 'add', 'undefined'), + maybe_start_queue_workers(QueueSup, ss_size(StrategyState1, 'logged_in')), + {'noreply', State#state{strategy_state=StrategyState1} ,'hibernate'}; handle_cast({'agent_available', JObj}, State) -> handle_cast({'agent_available', kz_json:get_value(<<"Agent-ID">>, JObj)}, State); @@ -474,20 +490,24 @@ handle_cast({'agent_ringing', AgentId}, #state{strategy=Strategy handle_cast({'agent_ringing', JObj}, State) -> handle_cast({'agent_ringing', kz_json:get_value(<<"Agent-ID">>, JObj)}, State); +handle_cast({'agent_busy', AgentId}, #state{strategy=Strategy + ,strategy_state=StrategyState + }=State) when is_binary(AgentId) -> + lager:info("agent ~s busy, maybe updating strategy ~s", [AgentId, Strategy]), + + StrategyState1 = update_strategy_with_agent(Strategy, StrategyState, AgentId, 'remove', 'busy'), + {'noreply', State#state{strategy_state=StrategyState1} + ,'hibernate'}; +handle_cast({'agent_busy', JObj}, State) -> + handle_cast({'agent_busy', kz_json:get_value(<<"Agent-ID">>, JObj)}, State); + handle_cast({'agent_unavailable', AgentId}, #state{strategy=Strategy ,strategy_state=StrategyState - ,known_agents=As - ,supervisor=QueueSup }=State) when is_binary(AgentId) -> lager:info("agent ~s unavailable, maybe updating strategy ~s", [AgentId, Strategy]), - {StrategyState1, As1} = update_strategy_with_agent(Strategy, StrategyState, As, AgentId, 'remove'), - - maybe_start_queue_workers(QueueSup, dict:size(As1)), - - {'noreply', State#state{strategy_state=StrategyState1 - ,known_agents=As1 - } + StrategyState1 = update_strategy_with_agent(Strategy, StrategyState, AgentId, 'remove', 'undefined'), + {'noreply', State#state{strategy_state=StrategyState1} ,'hibernate'}; handle_cast({'agent_unavailable', JObj}, State) -> handle_cast({'agent_unavailable', kz_json:get_value(<<"Agent-ID">>, JObj)}, State); @@ -507,7 +527,7 @@ handle_cast({'reject_member_call', Call, JObj}, #state{account_id=AccountId handle_cast({'sync_with_agent', A}, #state{account_id=AccountId}=State) -> case acdc_agent_util:most_recent_status(AccountId, A) of - {'ok', <<"logout">>} -> gen_listener:cast(self(), {'agent_unavailable', A}); + {'ok', <<"logged_out">>} -> gen_listener:cast(self(), {'agent_unavailable', A}); _ -> gen_listener:cast(self(), {'agent_available', A}) end, {'noreply', State}; @@ -699,55 +719,97 @@ pick_winner(_Mgr, CRs, 'mi', _) -> {[MostIdle|Same], Other}. --spec update_strategy_with_agent(queue_strategy(), queue_strategy_state(), dict:dict(), ne_binary(), 'add' | 'remove') -> - {queue_strategy_state(), dict:dict()}. -update_strategy_with_agent('rr', 'undefined', As, AgentId, 'add') -> - {queue:in(AgentId, queue:new()), dict:update_counter(AgentId, 1, As)}; -update_strategy_with_agent('rr', AgentQueue, As, AgentId, 'add') -> +-spec update_strategy_with_agent(queue_strategy(), strategy_state(), ne_binary(), 'add' | 'remove', 'busy' | 'undefined') -> + strategy_state(). +update_strategy_with_agent('rr', #strategy_state{agents=AgentQueue}=SS, AgentId, 'add', Busy) -> case queue:member(AgentId, AgentQueue) of - 'true' -> {AgentQueue, dict:update_counter(AgentId, 1, As)}; - 'false' -> {queue:in(AgentId, AgentQueue), dict:update_counter(AgentId, 1, As)} + 'true' -> set_busy(AgentId, Busy, SS); + 'false' -> set_busy(AgentId, Busy, add_agent('rr', AgentId, SS)) end; -update_strategy_with_agent('rr', AgentQueue, As, AgentId, 'remove') -> +update_strategy_with_agent('rr', SS, AgentId, 'remove', 'busy') -> + set_busy(AgentId, 'busy', SS); +update_strategy_with_agent('rr', #strategy_state{agents=AgentQueue}=SS, AgentId, 'remove', Busy) -> case queue:member(AgentId, AgentQueue) of - 'false' -> {AgentQueue, As}; - 'true' -> - case catch dict:fetch(AgentId, As) of - N when is_integer(N), N > 1 -> {AgentQueue, dict:update_counter(AgentId, -1, As)}; - _ -> {queue:from_list( - [A || A <- queue:to_list(AgentQueue), - A =/= AgentId - ]) - ,dict:erase(AgentId, As) - } - end + 'false' -> set_busy(AgentId, Busy, SS); + 'true' -> set_busy(AgentId, Busy, remove_agent('rr', AgentId, SS)) end; -update_strategy_with_agent('mi', AgentL, As, AgentId, 'add') -> +update_strategy_with_agent('mi', #strategy_state{agents=AgentL}=SS, AgentId, 'add', Busy) -> case lists:member(AgentId, AgentL) of - 'true' -> {AgentL, As}; - 'false' -> {[AgentId | AgentL], dict:update_counter(AgentId, 1, As)} + 'true' -> set_busy(AgentId, Busy, SS); + 'false' -> set_busy(AgentId, Busy, add_agent('mi', AgentId, SS)) end; -update_strategy_with_agent('mi', AgentL, As, AgentId, 'remove') -> +update_strategy_with_agent('mi', SS, AgentId, 'remove', 'busy') -> + set_busy(AgentId, 'busy', SS); +update_strategy_with_agent('mi', #strategy_state{agents=AgentL}=SS, AgentId, 'remove', Busy) -> case lists:member(AgentId, AgentL) of - 'false' -> {AgentL, As}; - 'true' -> - case catch dict:fetch(AgentId, As) of - N when is_integer(N), N > 1 -> - {AgentL, dict:update_counter(AgentId, -1, As)}; - _ -> - {[A || A <- AgentL, A =/= AgentId], dict:erase(AgentId, As)} - end + 'false' -> set_busy(AgentId, Busy, SS); + 'true' -> set_busy(AgentId, Busy, remove_agent('mi', AgentId, SS)) + end. + +-spec add_agent(queue_strategy(), ne_binary(), strategy_state()) -> strategy_state(). +add_agent('rr', AgentId, #strategy_state{agents=AgentQueue + ,details=Details + }=SS) -> + SS#strategy_state{agents=queue:in(AgentId, AgentQueue) + ,details=incr_agent(AgentId, Details) + }; +add_agent('mi', AgentId, #strategy_state{agents=AgentL + ,details=Details + }=SS) -> + SS#strategy_state{agents=[AgentId | AgentL] + ,details=incr_agent(AgentId, Details) + }. + +-spec remove_agent(queue_strategy(), ne_binary(), strategy_state()) -> strategy_state(). +remove_agent('rr', AgentId, #strategy_state{agents=AgentQueue + ,details=Details + }=SS) -> + case dict:find(AgentId, Details) of + {'ok', {Count, _}} when Count > 1 -> + SS#strategy_state{details=decr_agent(AgentId, Details)}; + _ -> + SS#strategy_state{agents=queue:filter(fun(AgentId1) when AgentId =:= AgentId1 -> 'false'; + (_) -> 'true' end + ,AgentQueue + ) + ,details=decr_agent(AgentId, Details) + } end; -update_strategy_with_agent('mi', _, As, _, _) -> - {'undefined', As}. +remove_agent('mi', AgentId, #strategy_state{agents=AgentL + ,details=Details + }=SS) -> + case dict:find(AgentId, Details) of + {'ok', {Count, _}} when Count > 1 -> + SS#strategy_state{details=decr_agent(AgentId, Details)}; + _ -> + SS#strategy_state{agents=[A || A <- AgentL, A =/= AgentId] + ,details=decr_agent(AgentId, Details) + } + end. + +-spec incr_agent(ne_binary(), dict:dict(ne_binary(), ss_details())) -> + dict:dict(ne_binary(), ss_details()). +incr_agent(AgentId, Details) -> + dict:update(AgentId, fun({Count, Busy}) -> {Count + 1, Busy} end, {1, 'undefined'}, Details). + +-spec decr_agent(ne_binary(), dict:dict(ne_binary(), ss_details())) -> + dict:dict(ne_binary(), ss_details()). +decr_agent(AgentId, Details) -> + dict:update(AgentId, fun({Count, Busy}) when Count > 1 -> {Count - 1, Busy}; + ({_, Busy}) -> {0, Busy} end + ,{0, 'undefined'}, Details). + +-spec set_busy(ne_binary(), 'busy' | 'undefined', strategy_state()) -> strategy_state(). +set_busy(AgentId, Busy, #strategy_state{details=Details}=SS) -> + SS#strategy_state{details=dict:update(AgentId, fun({Count, _}) -> {Count, Busy} end, {0, Busy}, Details)}. maybe_update_strategy('mi', StrategyState, _AgentId) -> StrategyState; -maybe_update_strategy('rr', StrategyState, AgentId) -> - case queue:out(StrategyState) of - {{'value', AgentId}, StrategyState1} -> +maybe_update_strategy('rr', #strategy_state{agents=AgentQueue}=SS, AgentId) -> + case queue:out(AgentQueue) of + {{'value', AgentId}, AgentQueue1} -> lager:debug("agent ~s was front of queue, moving", [AgentId]), - queue:in(AgentId, StrategyState1); - _ -> StrategyState + SS#strategy_state{agents=queue:in(AgentId, AgentQueue1)}; + _ -> SS end. %% If A's idle time is greater, it should come before B @@ -783,48 +845,93 @@ get_strategy(<<"most_idle">>) -> 'mi'; get_strategy(_) -> 'rr'. -spec create_strategy_state(queue_strategy() - ,queue_strategy_state() | 'undefined' + ,strategy_state() ,ne_binary(), ne_binary() - ) -> queue_strategy_state(). + ) -> strategy_state(). create_strategy_state(Strategy, AcctDb, QueueId) -> - create_strategy_state(Strategy, 'undefined', AcctDb, QueueId). + create_strategy_state(Strategy, #strategy_state{}, AcctDb, QueueId). -create_strategy_state('rr', 'undefined', AcctDb, QueueId) -> - create_strategy_state('rr', queue:new(), AcctDb, QueueId); -create_strategy_state('rr', AgentQ, AcctDb, QueueId) -> +create_strategy_state('rr', #strategy_state{agents='undefined'}=SS, AcctDb, QueueId) -> + create_strategy_state('rr', SS#strategy_state{agents=queue:new()}, AcctDb, QueueId); +create_strategy_state('rr', #strategy_state{agents=AgentQ}=SS, AcctDb, QueueId) -> case kz_datamgr:get_results(AcctDb, <<"queues/agents_listing">>, [{'key', QueueId}]) of - {'ok', []} -> lager:debug("no agents around"), AgentQ; + {'ok', []} -> lager:debug("no agents around"), SS; {'ok', JObjs} -> Q = queue:from_list([Id || JObj <- JObjs, not queue:member((Id = kz_doc:id(JObj)), AgentQ) ]), - queue:join(AgentQ, Q); - {'error', _E} -> lager:debug("error creating strategy rr: ~p", [_E]), AgentQ + Details = lists:foldl(fun(JObj, Acc) -> + dict:store(kz_doc:id(JObj), {1, 'undefined'}, Acc) + end, dict:new(), JObjs), + SS#strategy_state{agents=queue:join(AgentQ, Q) + ,details=Details + }; + {'error', _E} -> lager:debug("error creating strategy rr: ~p", [_E]), SS end; -create_strategy_state('mi', 'undefined', AcctDb, QueueId) -> - create_strategy_state('mi', [], AcctDb, QueueId); -create_strategy_state('mi', AgentL, AcctDb, QueueId) -> +create_strategy_state('mi', #strategy_state{agents='undefined'}=SS, AcctDb, QueueId) -> + create_strategy_state('mi', SS#strategy_state{agents=[]}, AcctDb, QueueId); +create_strategy_state('mi', #strategy_state{agents=AgentL}=SS, AcctDb, QueueId) -> case kz_datamgr:get_results(AcctDb, <<"queues/agents_listing">>, [{key, QueueId}]) of - {'ok', []} -> lager:debug("no agents around"), AgentL; + {'ok', []} -> lager:debug("no agents around"), SS; {'ok', JObjs} -> - lists:foldl(fun(JObj, Acc) -> - Id = kz_doc:id(JObj), - case lists:member(Id, Acc) of - 'true' -> Acc; - 'false' -> [Id | Acc] - end - end, AgentL, JObjs); - {'error', _E} -> lager:debug("error creating strategy mi: ~p", [_E]), AgentL + AgentL1 = lists:foldl(fun(JObj, Acc) -> + Id = kz_doc:id(JObj), + case lists:member(Id, Acc) of + 'true' -> Acc; + 'false' -> [Id | Acc] + end + end, AgentL, JObjs), + Details = lists:foldl(fun(JObj, Acc) -> + dict:store(kz_doc:id(JObj), {1, 'undefined'}, Acc) + end, dict:new(), JObjs), + SS#strategy_state{agents=AgentL1 + ,details=Details + }; + {'error', _E} -> lager:debug("error creating strategy mi: ~p", [_E]), SS end. -update_strategy_state(Srv, 'rr', StrategyState) -> - L = queue:to_list(StrategyState), +update_strategy_state(Srv, 'rr', #strategy_state{agents=AgentQueue}) -> + L = queue:to_list(AgentQueue), update_strategy_state(Srv, L); -update_strategy_state(Srv, 'mi', StrategyState) -> - update_strategy_state(Srv, StrategyState). +update_strategy_state(Srv, 'mi', #strategy_state{agents=AgentL}) -> + update_strategy_state(Srv, AgentL). update_strategy_state(Srv, L) -> [gen_listener:cast(Srv, {'sync_with_agent', A}) || A <- L]. +-spec ss_size(strategy_state(), 'free' | 'logged_in') -> integer(). +ss_size(#strategy_state{agents=Agents}, 'logged_in') -> + case queue:is_queue(Agents) of + 'true' -> queue:len(Agents); + 'false' -> length(Agents) + end; +ss_size(#strategy_state{agents=Agents + ,details=Details + }, 'free') when is_list(Agents) -> + lists:foldl(fun(AgentId, Count) -> + case dict:find(AgentId, Details) of + {'ok', {ProcCount, 'undefined'}} when ProcCount > 0 -> Count + 1; + _ -> Count + end + end, 0, Agents); +ss_size(#strategy_state{agents=Agents}=SS, 'free') -> + ss_size(SS#strategy_state{agents=queue:to_list(Agents)}, 'free'). + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Returns true if CallId is within the first Max elements of Calls +%% +%% @end +%%-------------------------------------------------------------------- +-spec up_next_fold([kapps_call:call()], ne_binary(), integer()) -> boolean(). +up_next_fold(Calls, _, Max) when Max >= length(Calls) -> 'true'; +up_next_fold(_, _, 0) -> 'false'; +up_next_fold([Call|Calls], CallId, Max) -> + case kapps_call:call_id(Call) of + CallId -> 'true'; + _ -> up_next_fold(Calls, CallId, Max-1) + end. + maybe_start_queue_workers(QueueSup, AgentCount) -> WSup = acdc_queue_sup:workers_sup(QueueSup), case acdc_queue_workers_sup:worker_count(WSup) of diff --git a/applications/acdc/src/acdc_queue_manager.hrl b/applications/acdc/src/acdc_queue_manager.hrl index 35d3c7080e6..2b53d2bf2e1 100644 --- a/applications/acdc/src/acdc_queue_manager.hrl +++ b/applications/acdc/src/acdc_queue_manager.hrl @@ -9,7 +9,7 @@ ,queue_id :: api_binary() ,supervisor :: pid() ,strategy = 'rr' :: queue_strategy() % round-robin | most-idle - ,strategy_state :: queue_strategy_state() % based on the strategy + ,strategy_state :: strategy_state() % based on the strategy ,known_agents = dict:new() :: dict:dict() % how many agent processes are available {AgentId, Count} ,enter_when_empty = 'true' :: boolean() % allow caller into queue if no agents are logged in ,moh :: api_binary() @@ -18,6 +18,12 @@ -type mgr_state() :: #state{}. -type queue_strategy_state() :: queue:queue() | ne_binaries(). +-type ss_details() :: {non_neg_integer(), 'busy' | 'undefined'}. +-record(strategy_state, {agents :: queue_strategy_state() + %% details include # of agent processes and availability + ,details = dict:new() :: dict:dict(ne_binary(), ss_details()) + }). +-type strategy_state() :: #strategy_state{}. -define(ACDC_QUEUE_MANAGER_HRL, 'true'). -endif. diff --git a/applications/acdc/src/acdc_queue_shared.erl b/applications/acdc/src/acdc_queue_shared.erl index 3abec0f25c7..3c6f718901b 100644 --- a/applications/acdc/src/acdc_queue_shared.erl +++ b/applications/acdc/src/acdc_queue_shared.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_queue_sup.erl b/applications/acdc/src/acdc_queue_sup.erl index 20edad7bf35..517909233fe 100644 --- a/applications/acdc/src/acdc_queue_sup.erl +++ b/applications/acdc/src/acdc_queue_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_queue_thief.erl b/applications/acdc/src/acdc_queue_thief.erl index f3cc34b9e2b..3bc33b59a63 100644 --- a/applications/acdc/src/acdc_queue_thief.erl +++ b/applications/acdc/src/acdc_queue_thief.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Caller calls in and gets the first available call from the queue %%% @end diff --git a/applications/acdc/src/acdc_queue_worker_sup.erl b/applications/acdc/src/acdc_queue_worker_sup.erl index bd42388c203..c4c5654fde0 100644 --- a/applications/acdc/src/acdc_queue_worker_sup.erl +++ b/applications/acdc/src/acdc_queue_worker_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_queue_workers_sup.erl b/applications/acdc/src/acdc_queue_workers_sup.erl index b65ee266651..d280201d4fe 100644 --- a/applications/acdc/src/acdc_queue_workers_sup.erl +++ b/applications/acdc/src/acdc_queue_workers_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_queues_sup.erl b/applications/acdc/src/acdc_queues_sup.erl index 8b04945c07f..2abc91e3e30 100644 --- a/applications/acdc/src/acdc_queues_sup.erl +++ b/applications/acdc/src/acdc_queues_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_recordings_sup.erl b/applications/acdc/src/acdc_recordings_sup.erl index 2cb344ad903..46262df4af0 100644 --- a/applications/acdc/src/acdc_recordings_sup.erl +++ b/applications/acdc/src/acdc_recordings_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_stats.erl b/applications/acdc/src/acdc_stats.erl index b4f4e684209..9a7de7be782 100644 --- a/applications/acdc/src/acdc_stats.erl +++ b/applications/acdc/src/acdc_stats.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Collector of stats %%% @end diff --git a/applications/acdc/src/acdc_stats_etsmgr.erl b/applications/acdc/src/acdc_stats_etsmgr.erl index 7b1edb895c7..77e5f65974f 100644 --- a/applications/acdc/src/acdc_stats_etsmgr.erl +++ b/applications/acdc/src/acdc_stats_etsmgr.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Manage the ETS table lookup for token server to account/client IP %%% @end diff --git a/applications/acdc/src/acdc_stats_sup.erl b/applications/acdc/src/acdc_stats_sup.erl index 05ad2135467..5d6a5688357 100644 --- a/applications/acdc/src/acdc_stats_sup.erl +++ b/applications/acdc/src/acdc_stats_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Manage the bucket servers %%% @end diff --git a/applications/acdc/src/acdc_stats_util.erl b/applications/acdc/src/acdc_stats_util.erl index 677fa1e8ab9..ee996e40720 100644 --- a/applications/acdc/src/acdc_stats_util.erl +++ b/applications/acdc/src/acdc_stats_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Stat util functions %%% @end diff --git a/applications/acdc/src/acdc_sup.erl b/applications/acdc/src/acdc_sup.erl index 075590a847f..50496a28a4b 100644 --- a/applications/acdc/src/acdc_sup.erl +++ b/applications/acdc/src/acdc_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/acdc/src/acdc_util.erl b/applications/acdc/src/acdc_util.erl index 665c7e78bc1..f1454094cb6 100644 --- a/applications/acdc/src/acdc_util.erl +++ b/applications/acdc/src/acdc_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/acdc/src/kapi_acdc_agent.erl b/applications/acdc/src/kapi_acdc_agent.erl index cbb74cac1a1..b5d1eb93a00 100644 --- a/applications/acdc/src/kapi_acdc_agent.erl +++ b/applications/acdc/src/kapi_acdc_agent.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% Bindings and JSON APIs for dealing with agents, as part of ACDc diff --git a/applications/acdc/src/kapi_acdc_queue.erl b/applications/acdc/src/kapi_acdc_queue.erl index bacb6f0229f..f4ce5bd0eeb 100644 --- a/applications/acdc/src/kapi_acdc_queue.erl +++ b/applications/acdc/src/kapi_acdc_queue.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end @@ -31,6 +31,7 @@ -export([agent_change_available/0 ,agent_change_ringing/0 + ,agent_change_busy/0 ,agent_change_unavailable/0 ]). @@ -502,17 +503,21 @@ agent_change_routing_key(AcctId, QueueId) -> -define(AGENT_CHANGE_AVAILABLE, <<"available">>). -define(AGENT_CHANGE_RINGING, <<"ringing">>). +-define(AGENT_CHANGE_BUSY, <<"busy">>). -define(AGENT_CHANGE_UNAVAILABLE, <<"unavailable">>). -define(AGENT_CHANGES, [?AGENT_CHANGE_AVAILABLE ,?AGENT_CHANGE_RINGING + ,?AGENT_CHANGE_BUSY ,?AGENT_CHANGE_UNAVAILABLE ]). -spec agent_change_available() -> ne_binary(). -spec agent_change_ringing() -> ne_binary(). +-spec agent_change_busy() -> ne_binary(). -spec agent_change_unavailable() -> ne_binary(). agent_change_available() -> ?AGENT_CHANGE_AVAILABLE. agent_change_ringing() -> ?AGENT_CHANGE_RINGING. +agent_change_busy() -> ?AGENT_CHANGE_BUSY. agent_change_unavailable() -> ?AGENT_CHANGE_UNAVAILABLE. -define(AGENT_CHANGE_HEADERS, [<<"Account-ID">>, <<"Agent-ID">>, <<"Queue-ID">>, <<"Change">>]). diff --git a/applications/acdc/src/kapi_acdc_stats.erl b/applications/acdc/src/kapi_acdc_stats.erl index 9350649aa67..aca3f407ba7 100644 --- a/applications/acdc/src/kapi_acdc_stats.erl +++ b/applications/acdc/src/kapi_acdc_stats.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/acdc/test/acdc_agent_fsm_test.erl b/applications/acdc/test/acdc_agent_fsm_test.erl index 2ec752800ba..da11359f11f 100644 --- a/applications/acdc/test/acdc_agent_fsm_test.erl +++ b/applications/acdc/test/acdc_agent_fsm_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% @end %%% @contributors diff --git a/applications/acdc/test/acdc_queue_manager_test.erl b/applications/acdc/test/acdc_queue_manager_test.erl new file mode 100644 index 00000000000..471fc3174ca --- /dev/null +++ b/applications/acdc/test/acdc_queue_manager_test.erl @@ -0,0 +1,31 @@ +%%%------------------------------------------------------------------- +%%% @copyright (C) 2016, Voxter Communications Inc. +%%% @doc +%%% @end +%%% @contributors +%%% Daniel Finke +%%%------------------------------------------------------------------- +-module(acdc_queue_manager_test). + +-include_lib("eunit/include/eunit.hrl"). + +-include("../src/acdc.hrl"). +-include("../src/acdc_queue_manager.hrl"). + +-define(AGENT_ID, <<"agent_id">>). + +%%% ===== +%%% TESTS +%%% ===== + +ss_size_empty_test_() -> + SS = #strategy_state{agents=[]}, + [?_assertEqual(0, acdc_queue_manager:ss_size(SS, 'free')) + ,?_assertEqual(0, acdc_queue_manager:ss_size(SS, 'logged_in'))]. + +ss_size_one_busy_test_() -> + SS = #strategy_state{agents=[]}, + SS1 = acdc_queue_manager:update_strategy_with_agent('mi', SS, ?AGENT_ID, 'add', 'undefined'), + SS2 = acdc_queue_manager:update_strategy_with_agent('mi', SS1, ?AGENT_ID, 'remove', 'busy'), + [?_assertEqual(0, acdc_queue_manager:ss_size(SS2, 'free')) + ,?_assertEqual(1, acdc_queue_manager:ss_size(SS2, 'logged_in'))]. diff --git a/applications/ananke/doc/README.md b/applications/ananke/doc/README.md index b33b9bcccbf..0f0e1ba1a24 100644 --- a/applications/ananke/doc/README.md +++ b/applications/ananke/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Ananke -Title: Ananke -Language: en-US -*/ # Ananke *Callback features* diff --git a/applications/ananke/src/ananke_app.erl b/applications/ananke/src/ananke_app.erl index 08002c335ec..76f4ecaaa1c 100644 --- a/applications/ananke/src/ananke_app.erl +++ b/applications/ananke/src/ananke_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/ananke/src/ananke_listener.erl b/applications/ananke/src/ananke_listener.erl index 1a870bde606..a3234b5cad0 100644 --- a/applications/ananke/src/ananke_listener.erl +++ b/applications/ananke/src/ananke_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/ananke/src/ananke_sup.erl b/applications/ananke/src/ananke_sup.erl index 97149f693dd..3086aaabc26 100644 --- a/applications/ananke/src/ananke_sup.erl +++ b/applications/ananke/src/ananke_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/ananke/src/ananke_tasks_sup.erl b/applications/ananke/src/ananke_tasks_sup.erl index 172f10bfdf8..338a1bd26fb 100644 --- a/applications/ananke/src/ananke_tasks_sup.erl +++ b/applications/ananke/src/ananke_tasks_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016 2600Hz +%%% @copyright (C) 2017 2600Hz %%% @doc %%% %%% @end diff --git a/applications/ananke/src/tasks/ananke_callback_worker.erl b/applications/ananke/src/tasks/ananke_callback_worker.erl index bec3543558f..be2c65af879 100644 --- a/applications/ananke/src/tasks/ananke_callback_worker.erl +++ b/applications/ananke/src/tasks/ananke_callback_worker.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/ananke/src/tasks/ananke_vm_callback.erl b/applications/ananke/src/tasks/ananke_vm_callback.erl index fb40952b3fd..5ed04185fa2 100644 --- a/applications/ananke/src/tasks/ananke_vm_callback.erl +++ b/applications/ananke/src/tasks/ananke_vm_callback.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz +%%% @copyright (C) 2015-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/blackhole/doc/README.md b/applications/blackhole/doc/README.md index f6dd8e5ebc6..59e60f4bc3a 100644 --- a/applications/blackhole/doc/README.md +++ b/applications/blackhole/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Blackhole -Title: Blackhole -Language: en-US -*/ # Blackhole *Realtime HTTP Websocket Events* diff --git a/applications/blackhole/doc/bindings.md b/applications/blackhole/doc/bindings.md index c107ef0a8ff..878b718b74c 100644 --- a/applications/blackhole/doc/bindings.md +++ b/applications/blackhole/doc/bindings.md @@ -1,8 +1,3 @@ -/* -Section: Blackhole -Title: Blackhole Bindings -Language: en-US -*/ # Blackhole *Realtime HTTP Websocket Events* diff --git a/applications/blackhole/doc/haproxy.md b/applications/blackhole/doc/haproxy.md index e2e4b8be69e..6c721227737 100644 --- a/applications/blackhole/doc/haproxy.md +++ b/applications/blackhole/doc/haproxy.md @@ -1,8 +1,3 @@ -/* -Section: Blackhole -Title: Haproxy -Language: en-US -*/ # Blackhole diff --git a/applications/blackhole/doc/troubleshooting.md b/applications/blackhole/doc/troubleshooting.md index e3fb17d213c..8b137891791 100644 --- a/applications/blackhole/doc/troubleshooting.md +++ b/applications/blackhole/doc/troubleshooting.md @@ -1,6 +1 @@ -/* -Section: Blackhole -Title: Troubleshooting -Language: en-US -*/ diff --git a/applications/blackhole/src/bh_context.erl b/applications/blackhole/src/bh_context.erl index 3b73ed85126..87066e5f8b1 100644 --- a/applications/blackhole/src/bh_context.erl +++ b/applications/blackhole/src/bh_context.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Helpers for manipulating the #bh_context{} record %%% @end diff --git a/applications/blackhole/src/bh_events.erl b/applications/blackhole/src/bh_events.erl index ef2ec9d98c1..caacbdc4eed 100644 --- a/applications/blackhole/src/bh_events.erl +++ b/applications/blackhole/src/bh_events.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz Inc +%%% @copyright (C) 2012-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/blackhole_app.erl b/applications/blackhole/src/blackhole_app.erl index 3af7030701d..2a20c028608 100644 --- a/applications/blackhole/src/blackhole_app.erl +++ b/applications/blackhole/src/blackhole_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/blackhole_bindings.erl b/applications/blackhole/src/blackhole_bindings.erl index 176ed8f6439..28499d318b4 100644 --- a/applications/blackhole/src/blackhole_bindings.erl +++ b/applications/blackhole/src/blackhole_bindings.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Store routing keys/pid bindings. When a binding is fired, %%% pass the payload to the pid for evaluation, accumulating @@ -194,7 +194,7 @@ modules_loaded() -> -spec is_bh_module(ne_binary() | atom()) -> boolean(). is_bh_module(<<"bh_", _/binary>>) -> 'true'; -is_bh_module(<<"blackhole_", _binary>>) -> 'true'; +is_bh_module(<<"blackhole_", _/binary>>) -> 'true'; is_bh_module(<<_/binary>>) -> 'false'; is_bh_module(Mod) -> is_bh_module(kz_util:to_binary(Mod)). diff --git a/applications/blackhole/src/blackhole_config.erl b/applications/blackhole/src/blackhole_config.erl index b3200ad1f5b..4a2be79c017 100644 --- a/applications/blackhole/src/blackhole_config.erl +++ b/applications/blackhole/src/blackhole_config.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/blackhole_data_emitter.erl b/applications/blackhole/src/blackhole_data_emitter.erl index 555d54a63a2..ffd68ae1313 100644 --- a/applications/blackhole/src/blackhole_data_emitter.erl +++ b/applications/blackhole/src/blackhole_data_emitter.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/blackhole_listener.erl b/applications/blackhole/src/blackhole_listener.erl index 2b33875d3d6..b5914a2948a 100644 --- a/applications/blackhole/src/blackhole_listener.erl +++ b/applications/blackhole/src/blackhole_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/blackhole_maintenance.erl b/applications/blackhole/src/blackhole_maintenance.erl index 5112449040e..6444b52edeb 100644 --- a/applications/blackhole/src/blackhole_maintenance.erl +++ b/applications/blackhole/src/blackhole_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/blackhole_socket_callback.erl b/applications/blackhole/src/blackhole_socket_callback.erl index c16641e744b..4e7784d6aa0 100644 --- a/applications/blackhole/src/blackhole_socket_callback.erl +++ b/applications/blackhole/src/blackhole_socket_callback.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz Inc +%%% @copyright (C) 2010-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/blackhole_socket_handler.erl b/applications/blackhole/src/blackhole_socket_handler.erl index f45e397b765..46af1e00df4 100644 --- a/applications/blackhole/src/blackhole_socket_handler.erl +++ b/applications/blackhole/src/blackhole_socket_handler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/blackhole_sup.erl b/applications/blackhole/src/blackhole_sup.erl index 03fb0218c56..77c0f4c7842 100644 --- a/applications/blackhole/src/blackhole_sup.erl +++ b/applications/blackhole/src/blackhole_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz Inc +%%% @copyright (C) 2012-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/blackhole_tracking.erl b/applications/blackhole/src/blackhole_tracking.erl index 1f7477ccd71..00f9b3732de 100644 --- a/applications/blackhole/src/blackhole_tracking.erl +++ b/applications/blackhole/src/blackhole_tracking.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz inc +%%% @copyright (C) 2017, 2600Hz inc %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/blackhole_util.erl b/applications/blackhole/src/blackhole_util.erl index 99a6cf698ad..0b31b6de2a6 100644 --- a/applications/blackhole/src/blackhole_util.erl +++ b/applications/blackhole/src/blackhole_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz Inc +%%% @copyright (C) 2012-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/modules/bh_authz_subscribe.erl b/applications/blackhole/src/modules/bh_authz_subscribe.erl index 078e214a4fd..26493415cdc 100644 --- a/applications/blackhole/src/modules/bh_authz_subscribe.erl +++ b/applications/blackhole/src/modules/bh_authz_subscribe.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Subscribe authz module %%% diff --git a/applications/blackhole/src/modules/bh_call.erl b/applications/blackhole/src/modules/bh_call.erl index a2ec3ef96ef..4fad33197e6 100644 --- a/applications/blackhole/src/modules/bh_call.erl +++ b/applications/blackhole/src/modules/bh_call.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz Inc +%%% @copyright (C) 2012-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/modules/bh_conference.erl b/applications/blackhole/src/modules/bh_conference.erl index e9c87699488..72fff2b8b9c 100644 --- a/applications/blackhole/src/modules/bh_conference.erl +++ b/applications/blackhole/src/modules/bh_conference.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz Inc +%%% @copyright (C) 2012-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/modules/bh_fax.erl b/applications/blackhole/src/modules/bh_fax.erl index 0b201d66872..cca2726816a 100644 --- a/applications/blackhole/src/modules/bh_fax.erl +++ b/applications/blackhole/src/modules/bh_fax.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz Inc +%%% @copyright (C) 2012-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/modules/bh_object.erl b/applications/blackhole/src/modules/bh_object.erl index 4f731ee54f6..a3d7f97ad13 100644 --- a/applications/blackhole/src/modules/bh_object.erl +++ b/applications/blackhole/src/modules/bh_object.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz Inc +%%% @copyright (C) 2012-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/modules/bh_skel.erl b/applications/blackhole/src/modules/bh_skel.erl index c0dff432cd5..86d932e5b59 100644 --- a/applications/blackhole/src/modules/bh_skel.erl +++ b/applications/blackhole/src/modules/bh_skel.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz Inc +%%% @copyright (C) 2012-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/blackhole/src/modules/bh_token_auth.erl b/applications/blackhole/src/modules/bh_token_auth.erl index 0bcc3ef4598..adfd2456480 100644 --- a/applications/blackhole/src/modules/bh_token_auth.erl +++ b/applications/blackhole/src/modules/bh_token_auth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Token auth module %%% diff --git a/applications/call_inspector/doc/README.md b/applications/call_inspector/doc/README.md index 7262ed3f060..0c1f2cf9a60 100644 --- a/applications/call_inspector/doc/README.md +++ b/applications/call_inspector/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Call Inspector -Title: Call Inspector -Language: en-US -*/ # Call Inspector diff --git a/applications/call_inspector/src/analyzers/ci_analysis.erl b/applications/call_inspector/src/analyzers/ci_analysis.erl index 9ec36eaa0af..e7cd12d185c 100644 --- a/applications/call_inspector/src/analyzers/ci_analysis.erl +++ b/applications/call_inspector/src/analyzers/ci_analysis.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/analyzers/ci_analyzers.erl b/applications/call_inspector/src/analyzers/ci_analyzers.erl index 152ba0071db..49454812f6e 100644 --- a/applications/call_inspector/src/analyzers/ci_analyzers.erl +++ b/applications/call_inspector/src/analyzers/ci_analyzers.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/analyzers/ci_analyzers_sup.erl b/applications/call_inspector/src/analyzers/ci_analyzers_sup.erl index ff3c9b0c909..5af6cfe70aa 100644 --- a/applications/call_inspector/src/analyzers/ci_analyzers_sup.erl +++ b/applications/call_inspector/src/analyzers/ci_analyzers_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/call_inspector_app.erl b/applications/call_inspector/src/call_inspector_app.erl index dfd859961b7..e82f6c60a98 100644 --- a/applications/call_inspector/src/call_inspector_app.erl +++ b/applications/call_inspector/src/call_inspector_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/call_inspector_maintenance.erl b/applications/call_inspector/src/call_inspector_maintenance.erl index 0b348bc60e7..9feecd96832 100644 --- a/applications/call_inspector/src/call_inspector_maintenance.erl +++ b/applications/call_inspector/src/call_inspector_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/call_inspector_sup.erl b/applications/call_inspector/src/call_inspector_sup.erl index 9439331c426..ccba858bdf6 100644 --- a/applications/call_inspector/src/call_inspector_sup.erl +++ b/applications/call_inspector/src/call_inspector_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/ci_datastore.erl b/applications/call_inspector/src/ci_datastore.erl index 45c33454994..568ca582a2b 100644 --- a/applications/call_inspector/src/ci_datastore.erl +++ b/applications/call_inspector/src/ci_datastore.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/ci_filter_req.erl b/applications/call_inspector/src/ci_filter_req.erl index ac127ac73ab..11fdb5d7332 100644 --- a/applications/call_inspector/src/ci_filter_req.erl +++ b/applications/call_inspector/src/ci_filter_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/ci_listener.erl b/applications/call_inspector/src/ci_listener.erl index 4429f912994..0cbceb61da6 100644 --- a/applications/call_inspector/src/ci_listener.erl +++ b/applications/call_inspector/src/ci_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/ci_lookup_req.erl b/applications/call_inspector/src/ci_lookup_req.erl index 27748919c5d..7cb7bcabb2c 100644 --- a/applications/call_inspector/src/ci_lookup_req.erl +++ b/applications/call_inspector/src/ci_lookup_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/kapi_inspector.erl b/applications/call_inspector/src/kapi_inspector.erl index 9dd822e4cd6..55413eb1dc3 100644 --- a/applications/call_inspector/src/kapi_inspector.erl +++ b/applications/call_inspector/src/kapi_inspector.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/parsers/ci_chunk.erl b/applications/call_inspector/src/parsers/ci_chunk.erl index 8de8b6c1677..b0cc01cb770 100644 --- a/applications/call_inspector/src/parsers/ci_chunk.erl +++ b/applications/call_inspector/src/parsers/ci_chunk.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/parsers/ci_parser_freeswitch.erl b/applications/call_inspector/src/parsers/ci_parser_freeswitch.erl index 62388af128a..c3f01c0289c 100644 --- a/applications/call_inspector/src/parsers/ci_parser_freeswitch.erl +++ b/applications/call_inspector/src/parsers/ci_parser_freeswitch.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (c) 2010-2016, 2600Hz +%%% @copyright (c) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/parsers/ci_parser_hep.erl b/applications/call_inspector/src/parsers/ci_parser_hep.erl index b22680b7e69..a63ba055b0f 100644 --- a/applications/call_inspector/src/parsers/ci_parser_hep.erl +++ b/applications/call_inspector/src/parsers/ci_parser_hep.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (c) 2010-2016, 2600Hz +%%% @copyright (c) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/parsers/ci_parser_kamailio.erl b/applications/call_inspector/src/parsers/ci_parser_kamailio.erl index ff79c608614..4c9516f9193 100644 --- a/applications/call_inspector/src/parsers/ci_parser_kamailio.erl +++ b/applications/call_inspector/src/parsers/ci_parser_kamailio.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (c) 2010-2016, 2600Hz +%%% @copyright (c) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/parsers/ci_parsers_sup.erl b/applications/call_inspector/src/parsers/ci_parsers_sup.erl index 9d357e3d145..6076e67b0d4 100644 --- a/applications/call_inspector/src/parsers/ci_parsers_sup.erl +++ b/applications/call_inspector/src/parsers/ci_parsers_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/call_inspector/src/parsers/ci_parsers_util.erl b/applications/call_inspector/src/parsers/ci_parsers_util.erl index 7094fb88199..c3a433d8f4d 100644 --- a/applications/call_inspector/src/parsers/ci_parsers_util.erl +++ b/applications/call_inspector/src/parsers/ci_parsers_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (c) 2010-2016, 2600Hz +%%% @copyright (c) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/callflow/doc/README.md b/applications/callflow/doc/README.md index 27f9f72feaf..d0e7e3fd1b0 100644 --- a/applications/callflow/doc/README.md +++ b/applications/callflow/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Callflow -Title: Callflow -Language: en-US -*/ # Callflow *PBX Functionality* Please press 1 to continue diff --git a/applications/callflow/doc/conference.md b/applications/callflow/doc/conference.md index 779b066187b..c539a6f05e5 100644 --- a/applications/callflow/doc/conference.md +++ b/applications/callflow/doc/conference.md @@ -1,9 +1,3 @@ -/* -Section: Callflows -Title: Conference -Language: en-US -Version: 3.22 -*/ The Conference callflow element allows one to override parts of a Conference document. diff --git a/applications/callflow/doc/fax_detect.md b/applications/callflow/doc/fax_detect.md index 67b5377a48a..705bfe4531c 100644 --- a/applications/callflow/doc/fax_detect.md +++ b/applications/callflow/doc/fax_detect.md @@ -1,8 +1,3 @@ -/* -Section: Callflow -Title: Fax Detect -Language: en-US -*/ # Fax Detect diff --git a/applications/callflow/doc/language.md b/applications/callflow/doc/language.md index 66d6f2a1a6b..35e6da0b324 100644 --- a/applications/callflow/doc/language.md +++ b/applications/callflow/doc/language.md @@ -1,13 +1,3 @@ -/* -Section: Callflows - -Title: Language - -Language: en-US - -Sponsors: CloudPBX - -*/ Prompts and other content take optional language settings to know which to fetch. Use this callflow action to set the language for the call. diff --git a/applications/callflow/doc/lookupcidname.md b/applications/callflow/doc/lookupcidname.md index dae7efc5b07..3e8ca6eac73 100644 --- a/applications/callflow/doc/lookupcidname.md +++ b/applications/callflow/doc/lookupcidname.md @@ -1,9 +1,3 @@ -/* -Section: Callflows -Title: Look up CID name -Language: en-US -Version: 3.20 -*/ This module looks up the Caller ID Name by matching numbers/patters with the provided lists. diff --git a/applications/callflow/doc/preflow.md b/applications/callflow/doc/preflow.md index 7a405ef3930..ab4a73fcc2c 100644 --- a/applications/callflow/doc/preflow.md +++ b/applications/callflow/doc/preflow.md @@ -1,8 +1,3 @@ -/* -Section: Callflow -Title: Preflow -Language: en-US -*/ # Preflow diff --git a/applications/callflow/doc/prepend_cid.md b/applications/callflow/doc/prepend_cid.md index c66f87fc71a..10c9812f797 100644 --- a/applications/callflow/doc/prepend_cid.md +++ b/applications/callflow/doc/prepend_cid.md @@ -1,7 +1,7 @@ # Prepend CID -The 'cf_prepend_cid' module can be used to prepend static values to the Caller ID Name and Number for a call in callflows. +The `cf_prepend_cid` module can be used to prepend static values to the Caller ID Name and Number for a call in callflows. ## Configuration Values diff --git a/applications/callflow/doc/record_call.md b/applications/callflow/doc/record_call.md index a4e866feda9..f20dd588dd9 100644 --- a/applications/callflow/doc/record_call.md +++ b/applications/callflow/doc/record_call.md @@ -1,9 +1,3 @@ -/* -Section: Callflows -Title: Record Call -Language: en-US -Version: 3.20 -*/ The `record_call` callflow enables you to record the audio of the call. diff --git a/applications/callflow/doc/ring_group.md b/applications/callflow/doc/ring_group.md index 65374c62736..b907a6c9d86 100644 --- a/applications/callflow/doc/ring_group.md +++ b/applications/callflow/doc/ring_group.md @@ -1,9 +1,3 @@ -/* -Section: Callflows -Title: Ring Group -Language: en-US -Version: 3.20 -*/ Ring group callflow element allows calling multiple endpoints with given strategy and timeout. diff --git a/applications/callflow/doc/temporal_route.md b/applications/callflow/doc/temporal_route.md index ee8e97c3977..5e327397150 100644 --- a/applications/callflow/doc/temporal_route.md +++ b/applications/callflow/doc/temporal_route.md @@ -1,8 +1,3 @@ -/* -Section: Callflow -Title: Temporal Route -Language: en-US -*/ # Rule Set diff --git a/applications/callflow/src/callflow_app.erl b/applications/callflow/src/callflow_app.erl index 7c46d3e9a75..a0ead417879 100644 --- a/applications/callflow/src/callflow_app.erl +++ b/applications/callflow/src/callflow_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/callflow/src/callflow_maintenance.erl b/applications/callflow/src/callflow_maintenance.erl index 5ec53c3b8d1..2f477aee745 100644 --- a/applications/callflow/src/callflow_maintenance.erl +++ b/applications/callflow/src/callflow_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016 2600Hz INC +%%% @copyright (C) 2011-2017 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/callflow_sup.erl b/applications/callflow/src/callflow_sup.erl index e22c0cfefb8..f421f53e5c2 100644 --- a/applications/callflow/src/callflow_sup.erl +++ b/applications/callflow/src/callflow_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/callflow/src/cf_event_handler_sup.erl b/applications/callflow/src/cf_event_handler_sup.erl index 4c242ad36ba..ed3bfa8789d 100644 --- a/applications/callflow/src/cf_event_handler_sup.erl +++ b/applications/callflow/src/cf_event_handler_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/callflow/src/cf_exe.erl b/applications/callflow/src/cf_exe.erl index aa6db0a2614..335bd962be2 100644 --- a/applications/callflow/src/cf_exe.erl +++ b/applications/callflow/src/cf_exe.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% @end %%% @contributors diff --git a/applications/callflow/src/cf_exe_sup.erl b/applications/callflow/src/cf_exe_sup.erl index 027869c0e24..4a316f24535 100644 --- a/applications/callflow/src/cf_exe_sup.erl +++ b/applications/callflow/src/cf_exe_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/callflow/src/cf_flow.erl b/applications/callflow/src/cf_flow.erl index d5b76ad5281..1033966db33 100644 --- a/applications/callflow/src/cf_flow.erl +++ b/applications/callflow/src/cf_flow.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/callflow/src/cf_listener.erl b/applications/callflow/src/cf_listener.erl index b7509e65526..8393cdc75da 100644 --- a/applications/callflow/src/cf_listener.erl +++ b/applications/callflow/src/cf_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Listener for route requests that can be fulfilled by callflows %%% @end diff --git a/applications/callflow/src/cf_route_req.erl b/applications/callflow/src/cf_route_req.erl index b63b9e675ba..763e3a4ece2 100644 --- a/applications/callflow/src/cf_route_req.erl +++ b/applications/callflow/src/cf_route_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% handler for route requests, responds if callflows match %%% @end diff --git a/applications/callflow/src/cf_route_resume.erl b/applications/callflow/src/cf_route_resume.erl index 708fb60f895..eae6139fb37 100644 --- a/applications/callflow/src/cf_route_resume.erl +++ b/applications/callflow/src/cf_route_resume.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Starts a cf_exe and processes the "flow" sans DB %%% @end diff --git a/applications/callflow/src/cf_route_win.erl b/applications/callflow/src/cf_route_win.erl index bd3166719b2..eb05fa5c5cb 100644 --- a/applications/callflow/src/cf_route_win.erl +++ b/applications/callflow/src/cf_route_win.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% handler for route wins, bootstraps callflow execution %%% @end diff --git a/applications/callflow/src/cf_shared_listener.erl b/applications/callflow/src/cf_shared_listener.erl index e98c99ebd30..410e0bace30 100644 --- a/applications/callflow/src/cf_shared_listener.erl +++ b/applications/callflow/src/cf_shared_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Listener for route requests that can be fulfilled by callflows %%% @end diff --git a/applications/callflow/src/cf_singular_call_hooks.erl b/applications/callflow/src/cf_singular_call_hooks.erl index 6239c29c6d2..58da9b5553b 100644 --- a/applications/callflow/src/cf_singular_call_hooks.erl +++ b/applications/callflow/src/cf_singular_call_hooks.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% A singular call is as an entire conversation as dialed by the caller, %%% and it may comprise of multiple "legs" or "calls". diff --git a/applications/callflow/src/cf_singular_call_hooks_listener.erl b/applications/callflow/src/cf_singular_call_hooks_listener.erl index 700b4d12316..e805edf0b7f 100644 --- a/applications/callflow/src/cf_singular_call_hooks_listener.erl +++ b/applications/callflow/src/cf_singular_call_hooks_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% This listener handles call CHANNEL_DESTROY events. %%% It is started by cf_singular_call_hooks and will diff --git a/applications/callflow/src/cf_task.erl b/applications/callflow/src/cf_task.erl index 0ca714afe43..2fcb310e585 100644 --- a/applications/callflow/src/cf_task.erl +++ b/applications/callflow/src/cf_task.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% @end %%% @contributors diff --git a/applications/callflow/src/cf_util.erl b/applications/callflow/src/cf_util.erl index 804d858ee18..40e08ec4b84 100644 --- a/applications/callflow/src/cf_util.erl +++ b/applications/callflow/src/cf_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_acdc_agent.erl b/applications/callflow/src/module/cf_acdc_agent.erl index eeacc5d7070..02678bcb640 100644 --- a/applications/callflow/src/module/cf_acdc_agent.erl +++ b/applications/callflow/src/module/cf_acdc_agent.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Handles changing an agent's status %%% diff --git a/applications/callflow/src/module/cf_acdc_member.erl b/applications/callflow/src/module/cf_acdc_member.erl index 4f8295e6248..41d1a5a84e8 100644 --- a/applications/callflow/src/module/cf_acdc_member.erl +++ b/applications/callflow/src/module/cf_acdc_member.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% Data: { diff --git a/applications/callflow/src/module/cf_acdc_queue.erl b/applications/callflow/src/module/cf_acdc_queue.erl index 662fb0cbf03..e5e188731f8 100644 --- a/applications/callflow/src/module/cf_acdc_queue.erl +++ b/applications/callflow/src/module/cf_acdc_queue.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Handles changing an agent's status %%% diff --git a/applications/callflow/src/module/cf_after_bridge.erl b/applications/callflow/src/module/cf_after_bridge.erl index d48355efb5c..5bcd6d96c54 100644 --- a/applications/callflow/src/module/cf_after_bridge.erl +++ b/applications/callflow/src/module/cf_after_bridge.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% set [park|transfer|hangup]_after_bridge variable %%% diff --git a/applications/callflow/src/module/cf_branch_bnumber.erl b/applications/callflow/src/module/cf_branch_bnumber.erl index a2d5e6bdbdb..d95b58bb50a 100644 --- a/applications/callflow/src/module/cf_branch_bnumber.erl +++ b/applications/callflow/src/module/cf_branch_bnumber.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_branch_variable.erl b/applications/callflow/src/module/cf_branch_variable.erl index 4b599340a31..246f1bc5f06 100644 --- a/applications/callflow/src/module/cf_branch_variable.erl +++ b/applications/callflow/src/module/cf_branch_variable.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% %%% Try branch to variable's value diff --git a/applications/callflow/src/module/cf_call_forward.erl b/applications/callflow/src/module/cf_call_forward.erl index 499c50af4a0..46498d8dd5e 100644 --- a/applications/callflow/src/module/cf_call_forward.erl +++ b/applications/callflow/src/module/cf_call_forward.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% "data":{ %%% "action":"activate" | "deactivate" | "update" | "toggle" | "menu" diff --git a/applications/callflow/src/module/cf_call_waiting.erl b/applications/callflow/src/module/cf_call_waiting.erl index 20ed213f11c..6a59fba87b0 100644 --- a/applications/callflow/src/module/cf_call_waiting.erl +++ b/applications/callflow/src/module/cf_call_waiting.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% "data": { diff --git a/applications/callflow/src/module/cf_callflow.erl b/applications/callflow/src/module/cf_callflow.erl index d2ac1873d42..74bc9b4754d 100644 --- a/applications/callflow/src/module/cf_callflow.erl +++ b/applications/callflow/src/module/cf_callflow.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz Inc +%%% @copyright (C) 2011-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_camping_feature.erl b/applications/callflow/src/module/cf_camping_feature.erl index 93fa1c8076a..82377ea7b3d 100644 --- a/applications/callflow/src/module/cf_camping_feature.erl +++ b/applications/callflow/src/module/cf_camping_feature.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% Sends request to start the call to recepient when he's available %%% diff --git a/applications/callflow/src/module/cf_check_cid.erl b/applications/callflow/src/module/cf_check_cid.erl index 3a3afb176bf..568e10ca2f0 100644 --- a/applications/callflow/src/module/cf_check_cid.erl +++ b/applications/callflow/src/module/cf_check_cid.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Handles inspection of incoming caller id and branching to a child %%% callflow node accordingly. diff --git a/applications/callflow/src/module/cf_cidlistmatch.erl b/applications/callflow/src/module/cf_cidlistmatch.erl index 1f44d20906c..e8b8f5eff80 100644 --- a/applications/callflow/src/module/cf_cidlistmatch.erl +++ b/applications/callflow/src/module/cf_cidlistmatch.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Handles inspection of incoming caller id and branching to a child %%% callflow node accordingly. diff --git a/applications/callflow/src/module/cf_collect_dtmf.erl b/applications/callflow/src/module/cf_collect_dtmf.erl index 3e8e6519f10..fc2eb27f13f 100644 --- a/applications/callflow/src/module/cf_collect_dtmf.erl +++ b/applications/callflow/src/module/cf_collect_dtmf.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Collect DTMF into an optional key for later retrieval %%% "data":{ diff --git a/applications/callflow/src/module/cf_conference.erl b/applications/callflow/src/module/cf_conference.erl index de6a2283bbf..d690df19d66 100644 --- a/applications/callflow/src/module/cf_conference.erl +++ b/applications/callflow/src/module/cf_conference.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_dead_air.erl b/applications/callflow/src/module/cf_dead_air.erl index 1030cb1113e..d46f7e6081f 100644 --- a/applications/callflow/src/module/cf_dead_air.erl +++ b/applications/callflow/src/module/cf_dead_air.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% Answers to the call and switches media off diff --git a/applications/callflow/src/module/cf_device.erl b/applications/callflow/src/module/cf_device.erl index 1bf00dd2210..8da49e0ebdd 100644 --- a/applications/callflow/src/module/cf_device.erl +++ b/applications/callflow/src/module/cf_device.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_directory.erl b/applications/callflow/src/module/cf_directory.erl index 8afda39c61f..e3e1b2685d6 100644 --- a/applications/callflow/src/module/cf_directory.erl +++ b/applications/callflow/src/module/cf_directory.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% The basic flow of a directory call: %%% 1) Prompt: Please enter the first few letters of the person's diff --git a/applications/callflow/src/module/cf_disa.erl b/applications/callflow/src/module/cf_disa.erl index 0bb2049d689..1af1d2aa1e2 100644 --- a/applications/callflow/src/module/cf_disa.erl +++ b/applications/callflow/src/module/cf_disa.erl @@ -1,5 +1,5 @@ %%%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% "data":{ %%% "pin":"1234" @@ -136,7 +136,10 @@ collect_destination_number(Call, Data, Interdigit) -> try_collect_destination_number(Call, Interdigit, MaxDigits, Timeout) -> case kapps_call_command:collect_digits(MaxDigits, Timeout, Interdigit, Call) of {'ok', <<>>} -> try_collect_destination_number(Call, Interdigit, MaxDigits, Timeout); - {'ok', Digits} -> knm_converters:normalize(Digits) + {'ok', Digits} -> knm_converters:normalize(Digits); + {'error', _E} -> + lager:info("caller hungup while collecting destination number"), + cf_exe:stop(Call) end. %%-------------------------------------------------------------------- diff --git a/applications/callflow/src/module/cf_do_not_disturb.erl b/applications/callflow/src/module/cf_do_not_disturb.erl index 2cf5830cc37..e459deadc93 100644 --- a/applications/callflow/src/module/cf_do_not_disturb.erl +++ b/applications/callflow/src/module/cf_do_not_disturb.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_dynamic_cid.erl b/applications/callflow/src/module/cf_dynamic_cid.erl index 2e19d5ca002..ac209cab896 100644 --- a/applications/callflow/src/module/cf_dynamic_cid.erl +++ b/applications/callflow/src/module/cf_dynamic_cid.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% "data":{ %%% "action": "manual" | "list" @@ -24,35 +24,30 @@ -define(MOD_CONFIG_CAT, <<(?CF_CONFIG_CAT)/binary, ".dynamic_cid">>). --define(CONFIG_BIN(Key, Default) - ,kapps_config:get_binary(?MOD_CONFIG_CAT, Key, Default) - ). --define(CONFIG_INT(Key, Default) - ,kapps_config:get_integer(?MOD_CONFIG_CAT, Key, Default) - ). - -record(prompts ,{accept_tone = - ?CONFIG_BIN(<<"accept_prompt">>, <<"tone_stream://%(250,50,440)">>) + kapps_config:get_binary(?MOD_CONFIG_CAT, <<"accept_prompt">>, <<"tone_stream://%(250,50,440)">>) ,reject_tone = kz_media_util:get_prompt( - ?CONFIG_BIN(<<"reject_prompt">>, <<"dynamic-cid-invalid_using_default">>) + kapps_config:get_binary(?MOD_CONFIG_CAT, <<"reject_prompt">>, <<"dynamic-cid-invalid_using_default">>) ) ,default_prompt = kz_media_util:get_prompt( - ?CONFIG_BIN(<<"default_prompt">>, <<"dynamic-cid-enter_cid">>) + kapps_config:get_binary(?MOD_CONFIG_CAT, <<"default_prompt">>, <<"dynamic-cid-enter_cid">>) ) }). -type prompts() :: #prompts{}. -record(dynamic_cid ,{prompts = #prompts{} :: prompts() - ,max_digits = ?CONFIG_INT(<<"max_digits">>, 10) :: integer() - ,min_digits = ?CONFIG_INT(<<"min_digits">>, 10) :: integer() - ,whitelist = ?CONFIG_BIN(<<"whitelist_regex">>, <<"\\d+">>) :: ne_binary() + ,default_max_digits = kapps_config:get_integer(?MOD_CONFIG_CAT, <<"max_digits">>, 10) :: integer() + ,default_min_digits = kapps_config:get_integer(?MOD_CONFIG_CAT, <<"min_digits">>, 10) :: integer() + ,default_whitelist = kapps_config:get_binary(?MOD_CONFIG_CAT, <<"whitelist_regex">>, <<"\\d+">>) :: ne_binary() } ). +-type cid() :: {ne_binary(), ne_binary()}. + %%-------------------------------------------------------------------- %% @public %% @doc @@ -72,6 +67,9 @@ handle(Data, Call, <<"list">>, ?NE_BINARY = _CaptureGroup) -> handle(Data, Call, <<"lists">>, ?NE_BINARY = _CaptureGroup) -> lager:info("using account's lists/entries view to get new cid info"), handle_lists(Data, Call); +handle(Data, Call, <<"static">>, CaptureGroup) -> + lager:info("user chose a static caller id for this call"), + handle_static(Data, Call, CaptureGroup); handle(Data, Call, _Manual, ?NE_BINARY = CaptureGroup) -> lager:info("user must manually enter on keypad the caller id for this call"), handle_manual(Data, Call, CaptureGroup); @@ -89,46 +87,27 @@ handle(Data, Call, _Manual, CaptureGroup) -> handle_manual(Data, Call, CaptureGroup) -> CID = collect_cid_number(Data, Call), update_call(Call, CID, CaptureGroup), + kapps_call_command:flush_dtmf(Call), cf_exe:continue(Call). %%-------------------------------------------------------------------- %% @private -%% @doc Update caller id number. If call -%% has a capture group, strip the non capture group digits from -%% request, to and callee_number +%% @doc +%% Handle static mode of dynamic cid %% @end %%-------------------------------------------------------------------- --spec update_call(kapps_call:call(), api_binary(), api_binary()) -> 'ok'. -update_call(Call, CIDNumber, DestNumber) -> - Updates = [{fun kapps_call:kvs_store/3, 'dynamic_cid', CIDNumber} - ,{fun kapps_call:set_caller_id_number/2, CIDNumber} - ], - {'ok', C1} = cf_exe:get_call(Call), - lager:info("setting the caller id number to ~s (from ~s)", [CIDNumber, kapps_call:caller_id_number(Call)]), - maybe_strip_features_code(kapps_call:exec(Updates, C1), DestNumber). - --spec maybe_strip_features_code(kapps_call:call(), api_binary()) -> kapps_call:call(). -maybe_strip_features_code(Call, 'undefined') -> - cf_exe:set_call(Call); -maybe_strip_features_code(Call, DestNumber) -> - Norm = knm_converters:normalize(DestNumber), - Request = list_to_binary([Norm, "@", kapps_call:request_realm(Call)]), - To = list_to_binary([Norm, "@", kapps_call:to_realm(Call)]), - - lager:info("sending the call onto real destination of: ~s", [Norm]), - - Updates = [{fun kapps_call:set_request/2, Request} - ,{fun kapps_call:set_to/2, To} - ,{fun kapps_call:set_callee_id_number/2, Norm} - ], - cf_exe:set_call(kapps_call:exec(Updates, Call)). +-spec handle_static(kz_json:object(), kapps_call:call(), api_binary()) -> 'ok'. +handle_static(Data, Call, CaptureGroup) -> + {CIDName, CIDNumber} = get_static_cid_entry(Data, Call), + update_call(Call, CIDNumber, CIDName, CaptureGroup), + cf_exe:continue(Call). %%-------------------------------------------------------------------- %% @private %% @doc Read CID info from a list of CID defined in database %% @end %%-------------------------------------------------------------------- --type cid_entry() :: {binary(), binary(), binary()} | {'error', kz_data:data_error()}. +-type list_cid_entry() :: {ne_binary(), ne_binary(), ne_binary()} | {'error', kz_data:data_error()}. -spec handle_list(kz_json:object(), kapps_call:call()) -> 'ok'. handle_list(Data, Call) -> @@ -138,12 +117,7 @@ handle_list(Data, Call) -> handle_lists(Data, Call) -> maybe_proceed_with_call(get_lists_entry(Data, Call), Data, Call). --spec maybe_proceed_with_call(cid_entry(), kz_json:object(), kapps_call:call()) -> 'ok'. -maybe_proceed_with_call({<<>>, <<>>, _}, _, Call) -> - lager:debug("empty cid entry, hanging up"), - _ = kapps_call_command:answer(Call), - _ = kapps_call_command:prompt(<<"menu-invalid_entry">>, Call), - kapps_call_command:queued_hangup(Call); +-spec maybe_proceed_with_call(list_cid_entry(), kz_json:object(), kapps_call:call()) -> 'ok'. maybe_proceed_with_call({NewCallerIdName, NewCallerIdNumber, Dest}, Data, Call) -> proceed_with_call(NewCallerIdName, NewCallerIdNumber, Dest, Data, Call); maybe_proceed_with_call(_, _, Call) -> @@ -153,30 +127,79 @@ maybe_proceed_with_call(_, _, Call) -> -spec proceed_with_call(ne_binary(), ne_binary(), binary(), kz_json:object(), kapps_call:call()) -> 'ok'. proceed_with_call(NewCallerIdName, NewCallerIdNumber, Dest, Data, Call) -> - lager:info("caller id number is about to be changed from: ~p to: ~p ", [kapps_call:caller_id_number(Call), NewCallerIdNumber]), - Updates = [{fun kapps_call:kvs_store/3, 'dynamic_cid', NewCallerIdNumber} - ,{fun kapps_call:set_caller_id_number/2, NewCallerIdNumber} - ,{fun kapps_call:set_caller_id_name/2, NewCallerIdName} - ], - cf_exe:set_call(kapps_call:exec(Updates, Call)), + update_call(Call, NewCallerIdNumber, NewCallerIdName, Dest), Number = knm_converters:normalize(Dest), - lager:info("send the call onto real destination of: ~s", [Number]), maybe_route_to_callflow(Data, Call, Number). +%%-------------------------------------------------------------------- +%% @private +%% @doc Update caller id number. If call +%% has a capture group, strip the non capture group digits from +%% request, to and callee_number +%% @end +%%-------------------------------------------------------------------- +-spec update_call(kapps_call:call(), ne_binary(), api_binary()) -> 'ok'. +update_call(Call, CIDNumber, CaptureGroup) -> + Updates = [{fun kapps_call:kvs_store/3, 'dynamic_cid', CIDNumber} + ,{fun kapps_call:set_caller_id_number/2, CIDNumber} + ], + {'ok', C1} = cf_exe:get_call(Call), + lager:info("setting the caller id number to ~s (from ~s)" + ,[CIDNumber, kapps_call:caller_id_number(Call)] + ), + maybe_strip_features_code(kapps_call:exec(Updates, C1), CaptureGroup). + +%%-------------------------------------------------------------------- +%% @private +%% @doc Same as update_call/3, but also sets caller id name +%% @end +%%-------------------------------------------------------------------- +-spec update_call(kapps_call:call(), ne_binary(), ne_binary(), api_binary()) -> 'ok'. +update_call(Call, CIDNumber, CIDName, CaptureGroup) -> + Updates = [{fun kapps_call:kvs_store/3, 'dynamic_cid', CIDNumber} + ,{fun kapps_call:set_caller_id_number/2, CIDNumber} + ,{fun kapps_call:set_caller_id_name/2, CIDName} + ], + {'ok', C1} = cf_exe:get_call(Call), + lager:info("setting the cid to <~s> ~s (from <~s> ~s)" + ,[CIDName + ,CIDNumber + ,kapps_call:caller_id_name(Call) + ,kapps_call:caller_id_number(Call) + ] + ), + maybe_strip_features_code(kapps_call:exec(Updates, C1), CaptureGroup). + +%%-------------------------------------------------------------------- +%% @private +%% @doc If CaptureGroup exists correct request, to and callee_id_number +%% @end +%%-------------------------------------------------------------------- +-spec maybe_strip_features_code(kapps_call:call(), api_binary()) -> kapps_call:call(). +maybe_strip_features_code(Call, 'undefined') -> + cf_exe:set_call(Call); +maybe_strip_features_code(Call, CaptureGroup) -> + Norm = knm_converters:normalize(CaptureGroup), + Request = list_to_binary([Norm, "@", kapps_call:request_realm(Call)]), + To = list_to_binary([Norm, "@", kapps_call:to_realm(Call)]), + + lager:info("sending the call onto real destination of: ~s", [Norm]), + + Updates = [{fun kapps_call:set_request/2, Request} + ,{fun kapps_call:set_to/2, To} + ,{fun kapps_call:set_callee_id_number/2, Norm} + ], + cf_exe:set_call(kapps_call:exec(Updates, Call)). + +%%-------------------------------------------------------------------- +%% @private +%% @doc Lookup callflow and continue with the call +%% @end +%%-------------------------------------------------------------------- -spec maybe_route_to_callflow(kz_json:object(), kapps_call:call(), ne_binary()) -> 'ok'. maybe_route_to_callflow(Data, Call, Number) -> case cf_flow:lookup(Number, kapps_call:account_id(Call)) of {'ok', Flow, 'true'} -> - lager:info("callflow ~s satisfies request", [kz_json:get_value(<<"_id">>, Flow)]), - Updates = [{fun kapps_call:set_request/2 - ,list_to_binary([Number, "@", kapps_call:request_realm(Call)]) - } - ,{fun kapps_call:set_to/2 - ,list_to_binary([Number, "@", kapps_call:to_realm(Call)]) - } - ], - {'ok', C} = cf_exe:get_call(Call), - cf_exe:set_call(kapps_call:exec(Updates, C)), maybe_restrict_call(Data, Call, Number, Flow); _ -> lager:info("failed to find a callflow to satisfy ~s", [Number]), @@ -248,11 +271,15 @@ collect_cid_number(Data, Call) -> Else -> Else end, - Min = DynamicCID#dynamic_cid.min_digits, - Max = DynamicCID#dynamic_cid.max_digits, - Regex = DynamicCID#dynamic_cid.whitelist, + DefaultMin = DynamicCID#dynamic_cid.default_min_digits, + DefaultMax = DynamicCID#dynamic_cid.default_max_digits, + DefaultRegex = DynamicCID#dynamic_cid.default_whitelist, DefaultCID = kapps_call:caller_id_number(Call), + Min = kz_json:get_ne_value(<<"min_digits">>, Data, DefaultMin), + Max = kz_json:get_ne_value(<<"max_digits">>, Data, DefaultMax), + Regex = kz_json:get_ne_value(<<"min_digits">>, Data, DefaultRegex), + Interdigit = kz_json:get_integer_value(<<"interdigit_timeout">> ,Data ,kapps_call_command:default_interdigit_timeout() @@ -274,18 +301,38 @@ collect_cid_number(Data, Call) -> _ = kapps_call_command:play(Prompts#prompts.reject_tone, Call), DefaultCID end; + {'error', 'channel_hungup'} -> + lager:info("caller hungup while collecting caller id number"), + cf_exe:stop(Call); {'error', _} -> _ = kapps_call_command:play(Prompts#prompts.reject_tone, Call), DefaultCID end. +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Get static CID from callflow data +%% @end +%%-------------------------------------------------------------------- +-spec get_static_cid_entry(kz_json:object(), kapps_call:call()) -> cid(). +get_static_cid_entry(Data, Call) -> + case kz_json:get_ne_value(<<"caller_id">>, Data) of + 'undefined' -> + maybe_set_default_cid('undefined', 'undefined', Call); + NewCallerId -> + Name = kz_json:get_ne_binary_value(<<"name">>, NewCallerId), + Number = kz_json:get_ne_binary_value(<<"number">>, NewCallerId), + maybe_set_default_cid(Name, Number, Call) + end. + %%-------------------------------------------------------------------- %% @private %% @doc %% Pull in document from database with the callerid switching information inside %% @end %%-------------------------------------------------------------------- --spec get_list_entry(kz_json:object(), kapps_call:call()) -> cid_entry(). +-spec get_list_entry(kz_json:object(), kapps_call:call()) -> list_cid_entry(). get_list_entry(Data, Call) -> ListId = kz_json:get_ne_value(<<"id">>, Data), AccountDb = kapps_call:account_db(Call), @@ -293,7 +340,7 @@ get_list_entry(Data, Call) -> case kz_datamgr:open_cache_doc(AccountDb, ListId) of {'ok', ListJObj} -> {CIDKey, DestNumber} = find_key_and_dest(ListJObj, Data, Call), - {NewCallerIdName, NewCallerIdNumber} = get_new_caller_id(CIDKey, ListJObj), + {NewCallerIdName, NewCallerIdNumber} = get_new_caller_id(CIDKey, ListJObj, Call), {NewCallerIdName, NewCallerIdNumber, DestNumber}; {'error', _Reason}=E -> lager:info("failed to load match list document ~s: ~p", [ListId, _Reason]), @@ -319,17 +366,19 @@ find_key_and_dest(ListJObj, Call) -> <> = CaptureGroup, {CIDKey, Dest}. --spec get_new_caller_id(binary(), kz_json:object()) -> {binary(), binary()}. -get_new_caller_id(CIDKey, ListJObj) -> +-spec get_new_caller_id(binary(), kz_json:object(), kapps_call:call()) -> cid(). +get_new_caller_id(CIDKey, ListJObj, Call) -> JObj = kz_json:get_ne_value(<<"entries">>, ListJObj, kz_json:new()), case kz_json:get_value(CIDKey, JObj) of - 'undefined' -> {<<>>, <<>>}; + 'undefined' -> + maybe_set_default_cid('undefined', 'undefined', Call); NewCallerId -> - {kz_json:get_binary_value(<<"name">>, NewCallerId, <<>>) - ,kz_json:get_binary_value(<<"number">>, NewCallerId, <<>>)} + Name = kz_json:get_ne_binary_value(<<"name">>, NewCallerId), + Number = kz_json:get_ne_binary_value(<<"number">>, NewCallerId), + maybe_set_default_cid(Name, Number, Call) end. --spec get_lists_entry(kz_json:object(), kapps_call:call()) -> cid_entry(). +-spec get_lists_entry(kz_json:object(), kapps_call:call()) -> list_cid_entry(). get_lists_entry(Data, Call) -> ListId = kz_json:get_ne_value(<<"id">>, Data), AccountDb = kapps_call:account_db(Call), @@ -337,25 +386,60 @@ get_lists_entry(Data, Call) -> {'ok', Entries} -> CaptureGroup = kapps_call:kvs_fetch('cf_capture_group', Call), <> = CaptureGroup, - {NewCallerIdName, NewCallerIdNumber} = cid_key_lookup(CIDKey, Entries), + {NewCallerIdName, NewCallerIdNumber} = cid_key_lookup(CIDKey, Entries, Call), {NewCallerIdName, NewCallerIdNumber, Dest}; {'error', Reason} = E -> lager:info("failed to load match list document ~s: ~p", [ListId, Reason]), E end. --spec cid_key_lookup(binary(), kz_json:objects()) -> {binary(), binary()}. -cid_key_lookup(CIDKey, Entries) -> +-spec cid_key_lookup(binary(), kz_json:objects(), kapps_call:call()) -> cid(). +cid_key_lookup(CIDKey, Entries, Call) -> case lists:foldl(fun(Entry, Acc) -> cidkey_wanted(CIDKey, Entry, Acc) end, [], Entries) of - [{NewCallerIdName, NewCallerIdNumber}|_] -> {NewCallerIdName, NewCallerIdNumber}; - _ -> {<<>>, <<>>} + [{NewCallerIdName, NewCallerIdNumber}|_] -> + maybe_set_default_cid(NewCallerIdName, NewCallerIdNumber, Call); + _ -> + maybe_set_default_cid('undefined', 'undefined', Call) end. -spec cidkey_wanted(binary(), kz_json:object(), proplist()) -> proplist(). cidkey_wanted(CIDKey, Entry, Acc) -> case kz_json:get_binary_value([<<"value">>, <<"cid_key">>], Entry) == CIDKey of - 'true' -> Acc ++ [{kz_json:get_binary_value([<<"value">>, <<"cid_name">>], Entry, <<>>) - ,kz_json:get_binary_value([<<"value">>, <<"cid_number">>], Entry, <<>>) + 'true' -> Acc ++ [{kz_json:get_ne_binary_value([<<"value">>, <<"cid_name">>], Entry) + ,kz_json:get_ne_binary_value([<<"value">>, <<"cid_number">>], Entry) }]; 'false' -> Acc end. + +%%-------------------------------------------------------------------- +%% @private +%% @doc Play reject prompt if any of the caller id are empty +%% @end +%%-------------------------------------------------------------------- +-spec maybe_set_default_cid(api_ne_binary(), api_ne_binary(), kapps_call:call()) -> cid(). +maybe_set_default_cid('undefined', 'undefined', Call) -> + lager:debug("empty cid entry, set to default value"), + play_reject_prompt(Call), + {kapps_call:caller_id_name(Call), kapps_call:caller_id_number(Call)}; +maybe_set_default_cid('undefined', Number, Call) -> + lager:debug("empty cid name, set to default value"), + {kapps_call:caller_id_name(Call), Number}; +maybe_set_default_cid(Name, 'undefined', Call) -> + lager:debug("empty cid number, set to default value"), + play_reject_prompt(Call), + {Name, kapps_call:caller_id_number(Call)}; +maybe_set_default_cid(Name, Number, _Call) -> + {Name, Number}. + +%%-------------------------------------------------------------------- +%% @private +%% @doc play reject prompts when caller id number is empty or invalid +%% @end +%%-------------------------------------------------------------------- +-spec play_reject_prompt(kapps_call:call()) -> 'ok'. +play_reject_prompt(Call) -> + _ = kapps_call_command:play( + kz_media_util:get_prompt( + kapps_config:get_binary(?MOD_CONFIG_CAT, <<"reject_prompt">>, <<"dynamic-cid-invalid_using_default">>) + ), Call), + 'ok'. diff --git a/applications/callflow/src/module/cf_eavesdrop.erl b/applications/callflow/src/module/cf_eavesdrop.erl index c2f6e132695..fa07c3c5671 100644 --- a/applications/callflow/src/module/cf_eavesdrop.erl +++ b/applications/callflow/src/module/cf_eavesdrop.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz, INC +%%% @copyright (C) 2013-2017, 2600Hz, INC %%% @doc %%% Eacesdrop %%% diff --git a/applications/callflow/src/module/cf_eavesdrop_feature.erl b/applications/callflow/src/module/cf_eavesdrop_feature.erl index b5ef027cb94..9abe8636516 100644 --- a/applications/callflow/src/module/cf_eavesdrop_feature.erl +++ b/applications/callflow/src/module/cf_eavesdrop_feature.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz, INC +%%% @copyright (C) 2013-2017, 2600Hz, INC %%% @doc %%% Eacesdrop feature code %%% diff --git a/applications/callflow/src/module/cf_fax_detect.erl b/applications/callflow/src/module/cf_fax_detect.erl index fae29530d06..be9718488ac 100644 --- a/applications/callflow/src/module/cf_fax_detect.erl +++ b/applications/callflow/src/module/cf_fax_detect.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Detects if a call is fax %%% user(s). diff --git a/applications/callflow/src/module/cf_faxbox.erl b/applications/callflow/src/module/cf_faxbox.erl index d374c1e243a..6d3cf566741 100644 --- a/applications/callflow/src/module/cf_faxbox.erl +++ b/applications/callflow/src/module/cf_faxbox.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Instructs the switch to receive a fax from the caller %%% Stores the fax in the database and optionally emails a configured diff --git a/applications/callflow/src/module/cf_group.erl b/applications/callflow/src/module/cf_group.erl index 35496d7c265..e47ec5df7cc 100644 --- a/applications/callflow/src/module/cf_group.erl +++ b/applications/callflow/src/module/cf_group.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_group_pickup.erl b/applications/callflow/src/module/cf_group_pickup.erl index 78b211e784f..9eb176cf193 100644 --- a/applications/callflow/src/module/cf_group_pickup.erl +++ b/applications/callflow/src/module/cf_group_pickup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% Pickup a call in the specified group %%% diff --git a/applications/callflow/src/module/cf_group_pickup_feature.erl b/applications/callflow/src/module/cf_group_pickup_feature.erl index 747cac40f1b..9d70dd16fb7 100644 --- a/applications/callflow/src/module/cf_group_pickup_feature.erl +++ b/applications/callflow/src/module/cf_group_pickup_feature.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% Pickup a call in the specified group/device/user/extension %%% diff --git a/applications/callflow/src/module/cf_hangup.erl b/applications/callflow/src/module/cf_hangup.erl index b97d9b14cb0..8246c2c46a6 100644 --- a/applications/callflow/src/module/cf_hangup.erl +++ b/applications/callflow/src/module/cf_hangup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz, INC +%%% @copyright (C) 2013-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_hotdesk.erl b/applications/callflow/src/module/cf_hotdesk.erl index 8f7e6fcf7bc..0de7093817f 100644 --- a/applications/callflow/src/module/cf_hotdesk.erl +++ b/applications/callflow/src/module/cf_hotdesk.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% "data":{ %%% "action":"logout" | "login" | "toggle" | "bridge" diff --git a/applications/callflow/src/module/cf_intercept.erl b/applications/callflow/src/module/cf_intercept.erl index 642be24adec..99fe6d0f93f 100644 --- a/applications/callflow/src/module/cf_intercept.erl +++ b/applications/callflow/src/module/cf_intercept.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz, INC +%%% @copyright (C) 2013-2017, 2600Hz, INC %%% @doc %%% Intercept a call %%% diff --git a/applications/callflow/src/module/cf_intercept_feature.erl b/applications/callflow/src/module/cf_intercept_feature.erl index 08ae24dabfc..61248f48c08 100644 --- a/applications/callflow/src/module/cf_intercept_feature.erl +++ b/applications/callflow/src/module/cf_intercept_feature.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Intercept a call in the specified device/user/extension %%% diff --git a/applications/callflow/src/module/cf_intercom.erl b/applications/callflow/src/module/cf_intercom.erl index a3922de2d66..3f4c8a0ed05 100644 --- a/applications/callflow/src/module/cf_intercom.erl +++ b/applications/callflow/src/module/cf_intercom.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_language.erl b/applications/callflow/src/module/cf_language.erl index 6b0a3773fa2..dfd2546d9a7 100644 --- a/applications/callflow/src/module/cf_language.erl +++ b/applications/callflow/src/module/cf_language.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% "data":{"language":"en"} %%% diff --git a/applications/callflow/src/module/cf_lookupcidname.erl b/applications/callflow/src/module/cf_lookupcidname.erl index d4d3aebb983..0d58fd395a5 100644 --- a/applications/callflow/src/module/cf_lookupcidname.erl +++ b/applications/callflow/src/module/cf_lookupcidname.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% This module looks up the Caller ID Name by matching %%% numbers/patters with the provided lists. diff --git a/applications/callflow/src/module/cf_manual_presence.erl b/applications/callflow/src/module/cf_manual_presence.erl index e5e8332332c..59d0420a1cd 100644 --- a/applications/callflow/src/module/cf_manual_presence.erl +++ b/applications/callflow/src/module/cf_manual_presence.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% "data":{ %%% "presence_id":"foo" // for "foo@bar.com" diff --git a/applications/callflow/src/module/cf_menu.erl b/applications/callflow/src/module/cf_menu.erl index 53040ac251f..34c77e897ec 100644 --- a/applications/callflow/src/module/cf_menu.erl +++ b/applications/callflow/src/module/cf_menu.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% "data":{ %%% "id":"menu_id" diff --git a/applications/callflow/src/module/cf_move.erl b/applications/callflow/src/module/cf_move.erl index 3e6e0be4e80..36beaa89bd0 100644 --- a/applications/callflow/src/module/cf_move.erl +++ b/applications/callflow/src/module/cf_move.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_nomorobo.erl b/applications/callflow/src/module/cf_nomorobo.erl index 2e564a91408..bc91a18b90a 100644 --- a/applications/callflow/src/module/cf_nomorobo.erl +++ b/applications/callflow/src/module/cf_nomorobo.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Look up caller id number for spam score %%% "data":{ diff --git a/applications/callflow/src/module/cf_offnet.erl b/applications/callflow/src/module/cf_offnet.erl index 648fd07d955..39209c2c826 100644 --- a/applications/callflow/src/module/cf_offnet.erl +++ b/applications/callflow/src/module/cf_offnet.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% "data":{ %%% "to_did":"+14155550987" // statically dial DID diff --git a/applications/callflow/src/module/cf_page_group.erl b/applications/callflow/src/module/cf_page_group.erl index 1a376d9b21f..ac228eaf95f 100644 --- a/applications/callflow/src/module/cf_page_group.erl +++ b/applications/callflow/src/module/cf_page_group.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_park.erl b/applications/callflow/src/module/cf_park.erl index bc86d2225e4..ff77aeaea17 100644 --- a/applications/callflow/src/module/cf_park.erl +++ b/applications/callflow/src/module/cf_park.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_pivot.erl b/applications/callflow/src/module/cf_pivot.erl index 663d4d333cc..01fe6920ffe 100644 --- a/applications/callflow/src/module/cf_pivot.erl +++ b/applications/callflow/src/module/cf_pivot.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Accept third-party dialplan %%% "data":{ diff --git a/applications/callflow/src/module/cf_play.erl b/applications/callflow/src/module/cf_play.erl index 650027b53c9..59a7290c8f1 100644 --- a/applications/callflow/src/module/cf_play.erl +++ b/applications/callflow/src/module/cf_play.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% "data":{"id":"doc_id"} %%% @end diff --git a/applications/callflow/src/module/cf_prepend_cid.erl b/applications/callflow/src/module/cf_prepend_cid.erl index b56345f7210..05a6dece271 100644 --- a/applications/callflow/src/module/cf_prepend_cid.erl +++ b/applications/callflow/src/module/cf_prepend_cid.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% This callflow module can be used to prepend a value (or values) to the caller-id-name and caller-id-number of a call. %%% @end @@ -16,65 +16,37 @@ -export([handle/2]). --spec handle(kz_json:object(), kapps_call:call()) -> any(). +-spec handle(kz_json:object(), kapps_call:call()) -> 'ok'. handle(Data, Call) -> - Call1 = kapps_call:exec([ - fun maybe_set_orig_name/1 - ,fun maybe_set_orig_number/1 - ], Call), - handle(kz_json:get_value(<<"action">>, Data, <<"prepend">>), Data, Call1). + handle(kz_json:get_value(<<"action">>, Data, <<"prepend">>), Data, Call). --spec handle(binary(), kz_json:object(), kapps_call:call()) -> any(). +-spec handle(ne_binary(), kz_json:object(), kapps_call:call()) -> 'ok'. handle(<<"reset">>, _Data, Call) -> - Name = kapps_call:kvs_fetch(<<"original_cid_name">>, kapps_call:caller_id_name(Call), Call), - Number = kapps_call:kvs_fetch(<<"original_cid_number">>, kapps_call:caller_id_number(Call), Call), - - lager:info("reset prepend cid resulted in cid number ~s and cid name ~s", [Number, Name]), - set_values(Name, Number, Call); + lager:info("reset prepend cid"), + set_values('undefined', 'undefined', Call); handle(<<"prepend">>, Data, Call) -> NamePre = kz_json:get_value(<<"caller_id_name_prefix">>, Data, <<"">>), NumberPre = kz_json:get_value(<<"caller_id_number_prefix">>, Data, <<"">>), - OrigName = kapps_call:kvs_fetch(<<"original_cid_name">>, kapps_call:caller_id_name(Call), Call), - OrigNum = kapps_call:kvs_fetch(<<"original_cid_number">>, kapps_call:caller_id_number(Call), Call), + OrigPreName = kapps_call:kvs_fetch(<<"prepend_cid_name">>, <<"">>, Call), + OrigPreNum = kapps_call:kvs_fetch(<<"prepend_cid_number">>, <<"">>, Call), - {Name, Number} = case kz_json:get_value(<<"apply_to">>, Data, <<"original">>) of + {Name, Number} = case kz_json:get_value(<<"apply_to">>, Data, <<"current">>) of <<"original">> -> - {<> - ,<> - }; + {NamePre, NumberPre}; <<"current">> -> - {<> - ,<> + {<> + ,<> } end, - lager:info("prepend cid resulted in cid number ~s and cid name ~s", [Number, Name]), + lager:info("update prepend cid to <~s> ~s", [Name, Number]), set_values(Name, Number, Call). --spec maybe_set_orig_name(kapps_call:call()) -> kapps_call:call(). -maybe_set_orig_name(Call) -> - case kapps_call:kvs_fetch(<<"original_cid_name">>, 'undefined', Call) of - 'undefined' -> kapps_call:kvs_store(<<"original_cid_name">>, kapps_call:caller_id_name(Call), Call); - _Exists -> Call - end. - --spec maybe_set_orig_number(kapps_call:call()) -> kapps_call:call(). -maybe_set_orig_number(Call) -> - case kapps_call:kvs_fetch(<<"original_cid_number">>, 'undefined', Call) of - 'undefined' -> kapps_call:kvs_store(<<"original_cid_number">>, kapps_call:caller_id_number(Call), Call); - _Exists -> Call - end. - --spec set_values(binary(), binary(), kapps_call:call()) -> any(). +-spec set_values(api_binary(), api_binary(), kapps_call:call()) -> 'ok'. set_values(Name, Number, Call) -> - Props = [{<<"Retain-CID">>, 'true'} - ,{<<"Caller-ID-Number">>, Number} - ,{<<"Caller-ID-Name">>, Name} - ], - Updates = [fun(C) -> kapps_call:set_caller_id_number(Number, C) end - ,fun(C) -> kapps_call:set_caller_id_name(Name, C) end - ,fun(C) -> kapps_call:set_custom_channel_vars(Props, C) end + Updates = [fun(C) -> kapps_call:kvs_store('prepend_cid_number', Number, C) end + ,fun(C) -> kapps_call:kvs_store('prepend_cid_name', Name, C) end ], Call1 = kapps_call:exec(Updates, Call), cf_exe:set_call(Call1), diff --git a/applications/callflow/src/module/cf_privacy.erl b/applications/callflow/src/module/cf_privacy.erl index 9502b6e799e..d26b62efe12 100644 --- a/applications/callflow/src/module/cf_privacy.erl +++ b/applications/callflow/src/module/cf_privacy.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_receive_fax.erl b/applications/callflow/src/module/cf_receive_fax.erl index d6d57534cb8..cc050f0b531 100644 --- a/applications/callflow/src/module/cf_receive_fax.erl +++ b/applications/callflow/src/module/cf_receive_fax.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Instructs the switch to receive a fax from the caller %%% Stores the fax in the database and optionally emails a configured diff --git a/applications/callflow/src/module/cf_record_call.erl b/applications/callflow/src/module/cf_record_call.erl index b3d9878bfd2..37a4b3bf722 100644 --- a/applications/callflow/src/module/cf_record_call.erl +++ b/applications/callflow/src/module/cf_record_call.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Handles starting/stopping a call recording %%% diff --git a/applications/callflow/src/module/cf_record_caller.erl b/applications/callflow/src/module/cf_record_caller.erl index a68a65f9857..f21413b5f3b 100644 --- a/applications/callflow/src/module/cf_record_caller.erl +++ b/applications/callflow/src/module/cf_record_caller.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Handles starting/stopping a call recording %%% diff --git a/applications/callflow/src/module/cf_resources.erl b/applications/callflow/src/module/cf_resources.erl index 252943a3007..d622bc4aba4 100644 --- a/applications/callflow/src/module/cf_resources.erl +++ b/applications/callflow/src/module/cf_resources.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% "data":{ %%% "to_did":"+14155550987" // statically dial DID diff --git a/applications/callflow/src/module/cf_response.erl b/applications/callflow/src/module/cf_response.erl index 9323470379f..29bd322ddcc 100644 --- a/applications/callflow/src/module/cf_response.erl +++ b/applications/callflow/src/module/cf_response.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_ring_group.erl b/applications/callflow/src/module/cf_ring_group.erl index ee60ad34a5d..7495a0978fd 100644 --- a/applications/callflow/src/module/cf_ring_group.erl +++ b/applications/callflow/src/module/cf_ring_group.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_send_dtmf.erl b/applications/callflow/src/module/cf_send_dtmf.erl index 30071118de5..a85375858e8 100644 --- a/applications/callflow/src/module/cf_send_dtmf.erl +++ b/applications/callflow/src/module/cf_send_dtmf.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% "data":{ %%% "digits":"#123" // what sequence to send diff --git a/applications/callflow/src/module/cf_set.erl b/applications/callflow/src/module/cf_set.erl index 893dbe5b8d1..76a2c41b3cd 100644 --- a/applications/callflow/src/module/cf_set.erl +++ b/applications/callflow/src/module/cf_set.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_set_cid.erl b/applications/callflow/src/module/cf_set_cid.erl index e4863dcf990..3f2979cae82 100644 --- a/applications/callflow/src/module/cf_set_cid.erl +++ b/applications/callflow/src/module/cf_set_cid.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% params: diff --git a/applications/callflow/src/module/cf_set_variable.erl b/applications/callflow/src/module/cf_set_variable.erl index 6bcd457d54f..c3d4e098191 100644 --- a/applications/callflow/src/module/cf_set_variable.erl +++ b/applications/callflow/src/module/cf_set_variable.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% %%% "data":{ diff --git a/applications/callflow/src/module/cf_skel.erl b/applications/callflow/src/module/cf_skel.erl index 153b6220254..d10c07b4b89 100644 --- a/applications/callflow/src/module/cf_skel.erl +++ b/applications/callflow/src/module/cf_skel.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Base module for callflow action %%% @end diff --git a/applications/callflow/src/module/cf_sleep.erl b/applications/callflow/src/module/cf_sleep.erl index cc1e5cf50c9..8fe770ac799 100644 --- a/applications/callflow/src/module/cf_sleep.erl +++ b/applications/callflow/src/module/cf_sleep.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% data:{ diff --git a/applications/callflow/src/module/cf_temporal_route.erl b/applications/callflow/src/module/cf_temporal_route.erl index a5a9b8f4cd4..c03cd32f42a 100644 --- a/applications/callflow/src/module/cf_temporal_route.erl +++ b/applications/callflow/src/module/cf_temporal_route.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% "data":{ %%% "action": "menu" | "enable" | "disable" | "reset" diff --git a/applications/callflow/src/module/cf_tts.erl b/applications/callflow/src/module/cf_tts.erl index a1b134d1168..8f6821d8f5c 100644 --- a/applications/callflow/src/module/cf_tts.erl +++ b/applications/callflow/src/module/cf_tts.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% @doc %%% "data":{ %%% "text":"This is what should be said" diff --git a/applications/callflow/src/module/cf_user.erl b/applications/callflow/src/module/cf_user.erl index ba695309fa2..afce2e53a67 100644 --- a/applications/callflow/src/module/cf_user.erl +++ b/applications/callflow/src/module/cf_user.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/src/module/cf_voicemail.erl b/applications/callflow/src/module/cf_voicemail.erl index c5de37a32c8..07281646290 100644 --- a/applications/callflow/src/module/cf_voicemail.erl +++ b/applications/callflow/src/module/cf_voicemail.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% "data":{ %%% "action":"compose"|"check" @@ -29,6 +29,7 @@ -define(KEY_MIN_MESSAGE_SIZE, <<"min_message_size">>). -define(KEY_MAX_BOX_NUMBER_LENGTH, <<"max_box_number_length">>). -define(KEY_EXTENSION, <<"extension">>). +-define(KEY_MAX_LOGIN_ATTEMPTS, <<"max_login_attempts">>). -define(KEY_MAX_PIN_LENGTH, <<"max_pin_length">>). -define(KEY_DELETE_AFTER_NOTIFY, <<"delete_after_notify">>). -define(KEY_SAVE_AFTER_NOTIFY, <<"save_after_notify">>). @@ -60,6 +61,13 @@ ) ). +-define(MAX_LOGIN_ATTEMPTS + ,kapps_config:get(?CF_CONFIG_CAT + ,[?KEY_VOICEMAIL, ?KEY_MAX_LOGIN_ATTEMPTS] + ,3 + ) + ). + -define(ACCOUNT_VM_EXTENSION(AccountId) ,kapps_account_config:get_global(AccountId ,?CF_CONFIG_CAT @@ -89,6 +97,8 @@ ) ). +-define(DEFAULT_FIND_BOX_PROMPT, <<"vm-enter_id">>). + -record(keys, { %% Compose Voicemail operator = <<"0">> @@ -116,6 +126,7 @@ %% Post playbak ,keep = <<"1">> ,replay = <<"2">> + ,forward = <<"3">> ,prev = <<"4">> ,next = <<"6">> ,delete = <<"7">> @@ -134,7 +145,7 @@ ,name_media_id :: api_binary() ,pin = <<>> :: binary() ,timezone :: ne_binary() - ,max_login_attempts = 3 :: non_neg_integer() + ,max_login_attempts = ?MAX_LOGIN_ATTEMPTS :: non_neg_integer() ,require_pin = 'false' :: boolean() ,check_if_owner = 'true' :: boolean() ,owner_id :: api_binary() @@ -218,11 +229,16 @@ check_mailbox(#mailbox{max_login_attempts=MaxLoginAttempts}, _, Call, Loop) when lager:info("maximum number of invalid attempts to check mailbox"), _ = kapps_call_command:b_prompt(<<"vm-abort">>, Call), 'ok'; -check_mailbox(#mailbox{exists='false'}=Box, _ , Call, Loop) -> +check_mailbox(#mailbox{exists='false' + ,max_login_attempts=MaxLoginAttempts + }=Box, _ , Call, Loop) -> %% if the callflow did not define the mailbox to check then request the mailbox ID from the user - Resp = find_mailbox(Box, Call, Loop), - _ = send_mwi_update(Box, Call), - Resp; + case find_mailbox(Box, Call, ?DEFAULT_FIND_BOX_PROMPT, Loop) of + {'ok', PossibleBox, NewLoop} -> check_mailbox(PossibleBox, Call, NewLoop); + {'error', 'not_found'} -> + %% can't find mailbox, set Loop to max to play abort prompts in above func clause + check_mailbox(Box, Call, MaxLoginAttempts + 1) + end; check_mailbox(#mailbox{require_pin='false'}=Box, 'true', Call, _) -> %% If this is the owner of the mailbox calling in and it doesn't require a pin then jump %% right to the main menu @@ -270,17 +286,20 @@ check_mailbox(#mailbox{pin=Pin %% %% @end %%-------------------------------------------------------------------- --spec find_mailbox(mailbox(), kapps_call:call(), non_neg_integer()) -> 'ok'. +-spec find_mailbox(mailbox(), kapps_call:call(), ne_binary(), non_neg_integer()) -> + {'ok', mailbox(), non_neg_integer()} | + {'error', 'not_found'}. -find_mailbox(#mailbox{max_login_attempts=MaxLoginAttempts}, Call, Loop) when Loop > MaxLoginAttempts -> +find_mailbox(#mailbox{max_login_attempts=MaxLoginAttempts}, _Call, _VmEntryIdMedia, Loop) + when Loop > MaxLoginAttempts -> %% if we have exceeded the maximum loop attempts then terminate this call + %% Note: caller should play vm-abort or appropriate abort failure lager:info("maximum number of invalid attempts to find mailbox"), - _ = kapps_call_command:b_prompt(<<"vm-abort">>, Call), - 'ok'; -find_mailbox(#mailbox{interdigit_timeout=Interdigit}=Box, Call, Loop) -> + {'error', 'not_found'}; +find_mailbox(#mailbox{interdigit_timeout=Interdigit}=Box, Call, VmEntryIdMedia, Loop) -> lager:info("requesting mailbox number to check"), - NoopId = kapps_call_command:prompt(<<"vm-enter_id">>, Call), + NoopId = kapps_call_command:prompt(VmEntryIdMedia, Call), case kapps_call_command:collect_digits(?MAILBOX_DEFAULT_BOX_NUMBER_LENGTH ,kapps_call_command:default_collect_timeout() @@ -289,26 +308,67 @@ find_mailbox(#mailbox{interdigit_timeout=Interdigit}=Box, Call, Loop) -> ,Call ) of - {'ok', <<>>} -> find_mailbox(Box, Call, Loop + 1); + {'ok', <<>>} -> + _ = kapps_call_command:b_prompt(<<"menu-invalid_entry">>, Call), + find_mailbox(Box, Call, VmEntryIdMedia, Loop + 1); {'ok', Mailbox} -> BoxNum = try kz_util:to_integer(Mailbox) catch _:_ -> 0 end, - %% find the voicemail box, by making a fake 'callflow data payload' we look for it now because if the - %% caller is the owner, and the pin is not required then we skip requesting the pin - ViewOptions = [{'key', BoxNum}], - AccountDb = kapps_call:account_db(Call), - case kz_datamgr:get_single_result(AccountDb, <<"vmboxes/listing_by_mailbox">>, ViewOptions) of - {'ok', JObj} -> - lager:info("get profile of ~p", [JObj]), - ReqBox = get_mailbox_profile(kz_json:from_list([{<<"id">>, kz_doc:id(JObj)}]) - ,Call - ), - check_mailbox(ReqBox, Call, Loop); - _E -> - lager:info("mailbox ~s lookup failed: ~p", [Mailbox, _E]), - find_mailbox(Box, Call, Loop + 1) + case find_mailbox_by_number(BoxNum, Call) of + {'ok', FoundBox} -> {'ok', FoundBox, Loop}; + {'error', 'not_found'} -> + _ = kapps_call_command:b_prompt(<<"menu-invalid_entry">>, Call), + find_mailbox(Box, Call, VmEntryIdMedia, Loop + 1); + {'error', _R} -> + lager:info("mailbox ~s lookup failed: ~p", [Mailbox, _R]), + _ = kapps_call_command:b_prompt(<<"menu-invalid_entry">>, Call), + find_mailbox(Box, Call, VmEntryIdMedia, Loop + 1) end; _E -> - lager:info("recv other: ~p", [_E]) + lager:info("recv other: ~p", [_E]), + {'error', 'not_found'} + end. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% find the voicemail box, by making a fake 'callflow data payload' we look for it now because if the +%% caller is the owner, and the pin is not required then we skip requesting the pin +%% +%% Note: Check mailbox existence here to properly updating Loop in find_mailbox/4 +%% @end +%%-------------------------------------------------------------------- +-spec find_mailbox_by_number(non_neg_integer(), kapps_call:call()) -> + {'ok', mailbox()} | + {'error', any()}. +find_mailbox_by_number(BoxNum, Call) -> + ViewOptions = [{'key', BoxNum}], + AccountDb = kapps_call:account_db(Call), + case kz_datamgr:get_single_result(AccountDb, <<"vmboxes/listing_by_mailbox">>, ViewOptions) of + {'ok', JObj} -> + lager:info("get profile of ~p", [JObj]), + case get_mailbox_profile(kz_json:from_list([{<<"id">>, kz_doc:id(JObj)}]), Call) of + #mailbox{exists='false'} -> {'error', 'not_found'}; + Found -> {'ok', Found} + end; + Error -> Error + end. + +-spec find_destination_mailbox(mailbox(), kapps_call:call(), ne_binary(), non_neg_integer()) -> mailbox(). +find_destination_mailbox(#mailbox{max_login_attempts=MaxLoginAttempts}, Call, _SrcBoxId, Loop) + when Loop > MaxLoginAttempts -> + lager:info("maximum number of invalid attempts to find destination mailbox"), + _ = kapps_call_command:b_prompt(<<"vm-forward_abort">>, Call), + #mailbox{}; +find_destination_mailbox(#mailbox{max_login_attempts=MaxLoginAttempts}=Box, Call, SrcBoxId, Loop) -> + case find_mailbox(#mailbox{}, Call, <<"vm-enter_forward_id">>, Loop) of + {'ok', #mailbox{mailbox_id=SrcBoxId}, NewLoop} -> + lager:info("source mailbox can't be a destination mailbox"), + _ = kapps_call_command:b_prompt(<<"menu-invalid_entry">>, Call), + find_destination_mailbox(Box, Call, SrcBoxId, NewLoop + 1); + {'ok', DestBox, _NewLoop} -> DestBox; + {'error', 'not_found'} -> + %% can't find mailbox, set Loop to max to play abort prompts in above func clause + find_destination_mailbox(Box, Call, SrcBoxId, MaxLoginAttempts + 1) end. %%-------------------------------------------------------------------- @@ -773,6 +833,12 @@ play_messages([H|T]=Messages, PrevMessages, Count, #mailbox{timezone=Timezone {'ok', 'replay'} -> lager:info("caller chose to replay"), play_messages(Messages, PrevMessages, Count, Box, Call); + {'ok', 'forward'} -> + lager:info("caller chose to forward the message"), + forward_message(H, Box, Call), + {_, NMessage} = kvm_message:set_folder(?VM_FOLDER_SAVED, H, AccountId), + _ = kapps_call_command:prompt(<<"vm-saved">>, Call), + play_messages(T, [NMessage|PrevMessages], Count, Box, Call); {'error', _} -> lager:info("error during message playback") end; @@ -794,6 +860,134 @@ play_prev_message(Messages, [] = PrevMessages, Count, Box, Call) -> play_prev_message(Messages, [H|T], Count, Box, Call) -> play_messages([H|Messages], T, Count, Box, Call). +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Main function for forwarding a message to another vmbox of this account +%% @end +%%-------------------------------------------------------------------- +-spec forward_message(kz_json:object(), mailbox(), kapps_call:call()) -> 'ok'. +forward_message(Message, #mailbox{mailbox_id=SrcBoxId}, Call) -> + lager:info("enter destination mailbox number"), + _ = kapps_call_command:b_flush(Call), + PossibleBox = find_destination_mailbox(#mailbox{}, Call, SrcBoxId, 1), + forward_message(Message, SrcBoxId, PossibleBox, Call). + +-spec forward_message(kz_json:object(), ne_binary(), mailbox(), kapps_call:call()) -> 'ok'. +forward_message(_Message, _SrcBoxId, #mailbox{exists='false'}, _Call) -> + lager:info("unable to find destination mailbox, returning to message menu..."); +forward_message(Message, SrcBoxId, DestBox, Call) -> + case forward_message_menu(DestBox, Call) of + {'ok', 'return'} -> 'ok'; + {'ok', 'append'} -> + compose_forward_message(Message, SrcBoxId, DestBox, Call); + {'ok', 'forward'} -> + forward_message('undefined', 0, Message, SrcBoxId, DestBox, Call); + {'error', _R} -> + lager:info("error during forward message playback: ~p", [_R]) + end. + +-spec forward_message_menu(mailbox(), kapps_call:call()) -> + {'error', 'channel_hungup' | 'channel_unbridge' | kz_json:object()} | + {'ok', 'append' | 'forward' | 'return'}. +forward_message_menu(#mailbox{interdigit_timeout=Interdigit}=DestBox, Call) -> + lager:info("playing forward message menu"), + + Prompt = [{'prompt', <<"vm-message_forwarding">>}], + NoopId = kapps_call_command:audio_macro(Prompt, Call), + + case kapps_call_command:collect_digits(?KEY_LENGTH + ,kapps_call_command:default_collect_timeout() + ,Interdigit + ,NoopId + ,Call + ) + of + {'ok', <<"1">>} -> {'ok', 'append'}; + {'ok', <<"2">>} -> {'ok', 'forward'}; + {'ok', <<"0">>} -> {'ok', 'return'}; + {'error', _}=Error -> Error; + _ -> forward_message_menu(DestBox, Call) + end. + +-spec compose_forward_message(kz_json:object(), ne_binary(), mailbox(), kapps_call:call()) -> 'ok'. +compose_forward_message(Message, SrcBoxId, #mailbox{media_extension=Ext}=DestBox, Call) -> + lager:debug("playing forwarding instructions to caller"), + _ = play_instructions(DestBox, Call), + _NoopId = kapps_call_command:noop(Call), + %% timeout after 5 min for saftey, so this process cant hang around forever + case kapps_call_command:wait_for_application_or_dtmf(<<"noop">>, 300000) of + {'ok', _} -> + lager:info("played fowarding instructions to caller, recording new message"), + record_forward(tmp_file(Ext), Message, SrcBoxId, DestBox, Call); + {'dtmf', _Digits} -> + _ = kapps_call_command:b_flush(Call), + lager:info("recording forwarding message"), + record_forward(tmp_file(Ext), Message, SrcBoxId, DestBox, Call); + {'error', _R} -> + lager:info("error while playing voicemail greeting: ~p", [_R]) + end. + +-spec record_forward(ne_binary(), kz_json:object(), ne_binary(), mailbox(), kapps_call:call()) -> 'ok'. +record_forward(AttachmentName, Message, SrcBoxId, #mailbox{media_extension=Ext + ,max_message_length=MaxMessageLength + }=DestBox, Call) -> + lager:info("composing new forward voicemail to ~s", [AttachmentName]), + Tone = kz_json:from_list([{<<"Frequencies">>, [<<"440">>]} + ,{<<"Duration-ON">>, <<"500">>} + ,{<<"Duration-OFF">>, <<"100">>} + ]), + lager:info("composing new voicemail forward to ~s", [AttachmentName]), + kapps_call_command:tones([Tone], Call), + case kapps_call_command:b_record(AttachmentName, ?ANY_DIGIT, kz_util:to_binary(MaxMessageLength), Call) of + {'ok', Msg} -> + Length = kz_json:get_integer_value(<<"Length">>, Msg, 0), + IsCallUp = kz_json:get_value(<<"Hangup-Cause">>, Msg) =:= 'undefined', + case IsCallUp + andalso review_recording(AttachmentName, 'false', DestBox, Call) + of + 'false' -> + forward_message(AttachmentName, Length, Message, SrcBoxId, DestBox, Call); + {'ok', 'record'} -> + record_forward(tmp_file(Ext), Message, SrcBoxId, DestBox, Call); + {'ok', _Selection} -> + cf_util:start_task(fun forward_message/6 + ,[AttachmentName, Length, Message, SrcBoxId, DestBox] + , Call + ) + end; + {'error', _R} -> + lager:info("error while attempting to record a foward message: ~p", [_R]) + end. + +-spec forward_message(api_ne_binary(), non_neg_integer(), kz_json:object(), ne_binary(), mailbox(), kapps_call:call()) -> 'ok'. +forward_message(AttachmentName, Length, Message, SrcBoxId, #mailbox{mailbox_number=BoxNum + ,mailbox_id=BoxId + ,timezone=Timezone + ,owner_id=OwnerId + ,transcribe_voicemail=MaybeTranscribe + ,after_notify_action=Action + ,media_extension=Extension + }=DestBox, Call) -> + NewMsgProps = props:filter_undefined( + [{<<"Box-Id">>, BoxId} + ,{<<"Owner-Id">>, OwnerId} + ,{<<"Length">>, Length + kz_json:get_integer_value(<<"length">>, Message, 0)} + ,{<<"Transcribe-Voicemail">>, MaybeTranscribe} + ,{<<"After-Notify-Action">>, Action} + ,{<<"Attachment-Name">>, AttachmentName} + ,{<<"Box-Num">>, BoxNum} + ,{<<"Timezone">>, Timezone} + ,{<<"Description">>, <<"forwarded voicemail message with media">>} + ,{<<"Media-Extension">>, Extension} + ] + ), + case kvm_message:forward_message(Call, Message, SrcBoxId, NewMsgProps) of + 'ok' -> send_mwi_update(DestBox, Call); + {'error', _, _Msg} -> + lager:warning("failed to save forwarded voice mail message recorded media : ~p", [_Msg]) + end. + %%-------------------------------------------------------------------- %% @private %% @doc @@ -801,7 +995,7 @@ play_prev_message(Messages, [H|T], Count, Box, Call) -> %% user provides a valid option %% @end %%-------------------------------------------------------------------- --type message_menu_returns() :: {'ok', 'keep' | 'delete' | 'return' | 'replay' | 'prev' | 'next'}. +-type message_menu_returns() :: {'ok', 'keep' | 'delete' | 'return' | 'replay' | 'prev' | 'next' | 'forward'}. -spec message_menu(mailbox(), kapps_call:call()) -> {'error', 'channel_hungup' | 'channel_unbridge' | kz_json:object()} | @@ -813,6 +1007,7 @@ message_menu(Box, Call) -> message_menu([{'prompt', <<"vm-message_menu">>}], Box, Call). message_menu(Prompt, #mailbox{keys=#keys{replay=Replay ,keep=Keep + ,forward=Forward ,delete=Delete ,prev=Prev ,next=Next @@ -831,6 +1026,7 @@ message_menu(Prompt, #mailbox{keys=#keys{replay=Replay ) of {'ok', Keep} -> {'ok', 'keep'}; + {'ok', Forward} -> {'ok', 'forward'}; {'ok', Delete} -> {'ok', 'delete'}; {'ok', ReturnMain} -> {'ok', 'return'}; {'ok', Replay} -> {'ok', 'replay'}; @@ -1279,7 +1475,7 @@ collect_pin(Interdigit, Call, NoopId) -> %% @doc %% @end %%-------------------------------------------------------------------- --spec new_message(ne_binary(), pos_integer(), mailbox(), kapps_call:call()) -> any(). +-spec new_message(ne_binary(), non_neg_integer(), mailbox(), kapps_call:call()) -> any(). new_message(_, Length, #mailbox{min_message_length=MinLength}, _) when Length < MinLength -> lager:info("attachment length is ~B and must be larger than ~B to be stored", [Length, MinLength]); diff --git a/applications/callflow/src/module/cf_webhook.erl b/applications/callflow/src/module/cf_webhook.erl index 933b79aca5d..5689d4ef02d 100644 --- a/applications/callflow/src/module/cf_webhook.erl +++ b/applications/callflow/src/module/cf_webhook.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/test/cf_nomorobo_test.erl b/applications/callflow/test/cf_nomorobo_test.erl index 52326a460bd..c285fdc7b15 100644 --- a/applications/callflow/test/cf_nomorobo_test.erl +++ b/applications/callflow/test/cf_nomorobo_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/test/cf_ring_group_test.erl b/applications/callflow/test/cf_ring_group_test.erl index 00fd705c149..ba8d7423ead 100644 --- a/applications/callflow/test/cf_ring_group_test.erl +++ b/applications/callflow/test/cf_ring_group_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/callflow/test/cf_temporal_route_test.erl b/applications/callflow/test/cf_temporal_route_test.erl index b17d7246970..fa505b59062 100644 --- a/applications/callflow/test/cf_temporal_route_test.erl +++ b/applications/callflow/test/cf_temporal_route_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% @end %%% @contributors diff --git a/applications/callflow/test/cf_util_test.erl b/applications/callflow/test/cf_util_test.erl index 8a99155f66d..b67a7b0822b 100644 --- a/applications/callflow/test/cf_util_test.erl +++ b/applications/callflow/test/cf_util_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/camper/src/camper_app.erl b/applications/camper/src/camper_app.erl index 45e62d738bd..c09ce77bd9d 100644 --- a/applications/camper/src/camper_app.erl +++ b/applications/camper/src/camper_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/camper/src/camper_init.erl b/applications/camper/src/camper_init.erl index a429040bcab..bdfbd88c317 100644 --- a/applications/camper/src/camper_init.erl +++ b/applications/camper/src/camper_init.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/camper/src/camper_offnet_handler.erl b/applications/camper/src/camper_offnet_handler.erl index 0d3864b4005..2f785536040 100644 --- a/applications/camper/src/camper_offnet_handler.erl +++ b/applications/camper/src/camper_offnet_handler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% Read `tries`, 'try_interval' and 'stop_after' from app's config diff --git a/applications/camper/src/camper_offnet_sup.erl b/applications/camper/src/camper_offnet_sup.erl index 81bf7513182..720613a4b0e 100644 --- a/applications/camper/src/camper_offnet_sup.erl +++ b/applications/camper/src/camper_offnet_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/camper/src/camper_onnet_handler.erl b/applications/camper/src/camper_onnet_handler.erl index f25f32e89e9..ee08c50d85c 100644 --- a/applications/camper/src/camper_onnet_handler.erl +++ b/applications/camper/src/camper_onnet_handler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/camper/src/camper_request_listener.erl b/applications/camper/src/camper_request_listener.erl index 0de303af3af..501888d3a95 100644 --- a/applications/camper/src/camper_request_listener.erl +++ b/applications/camper/src/camper_request_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/camper/src/camper_sup.erl b/applications/camper/src/camper_sup.erl index 65a033098b2..8ee7b5384fa 100644 --- a/applications/camper/src/camper_sup.erl +++ b/applications/camper/src/camper_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/cccp/doc/README.md b/applications/cccp/doc/README.md index 3470276645d..a91c353ae44 100644 --- a/applications/cccp/doc/README.md +++ b/applications/cccp/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: CCCP -Title: Calling Card Callback Platform -Language: en-US -*/ cccp - Calling Card Callback Platform ==== diff --git a/applications/cccp/src/cccp_app.erl b/applications/cccp/src/cccp_app.erl index cb887d6ae89..2c65c6a2a15 100644 --- a/applications/cccp/src/cccp_app.erl +++ b/applications/cccp/src/cccp_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/cccp/src/cccp_callback_listener.erl b/applications/cccp/src/cccp_callback_listener.erl index 79b7884b66c..6f81d3e063c 100644 --- a/applications/cccp/src/cccp_callback_listener.erl +++ b/applications/cccp/src/cccp_callback_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/cccp/src/cccp_callback_sup.erl b/applications/cccp/src/cccp_callback_sup.erl index 98924ea7e6e..bd6ac638589 100644 --- a/applications/cccp/src/cccp_callback_sup.erl +++ b/applications/cccp/src/cccp_callback_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/cccp/src/cccp_handlers.erl b/applications/cccp/src/cccp_handlers.erl index 08a2f46dc6a..376f5ec9598 100644 --- a/applications/cccp/src/cccp_handlers.erl +++ b/applications/cccp/src/cccp_handlers.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/cccp/src/cccp_listener.erl b/applications/cccp/src/cccp_listener.erl index f0e1aeb9d2c..2c06240d045 100644 --- a/applications/cccp/src/cccp_listener.erl +++ b/applications/cccp/src/cccp_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/cccp/src/cccp_platform_listener.erl b/applications/cccp/src/cccp_platform_listener.erl index c6699da6324..ab7f005e707 100644 --- a/applications/cccp/src/cccp_platform_listener.erl +++ b/applications/cccp/src/cccp_platform_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/cccp/src/cccp_platform_sup.erl b/applications/cccp/src/cccp_platform_sup.erl index d99c9ccc4c7..c1c85ff4588 100644 --- a/applications/cccp/src/cccp_platform_sup.erl +++ b/applications/cccp/src/cccp_platform_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/cccp/src/cccp_sup.erl b/applications/cccp/src/cccp_sup.erl index 590192b3fc4..106c228d68d 100644 --- a/applications/cccp/src/cccp_sup.erl +++ b/applications/cccp/src/cccp_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/cccp/src/cccp_util.erl b/applications/cccp/src/cccp_util.erl index 8484c6a2f6d..7184e55ae04 100644 --- a/applications/cccp/src/cccp_util.erl +++ b/applications/cccp/src/cccp_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/cdr/doc/README.md b/applications/cdr/doc/README.md index 070b897b837..48929e76336 100644 --- a/applications/cdr/doc/README.md +++ b/applications/cdr/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: CDR -Title: Call Detail Records -Language: en-US -*/ # CDR *Call Detail Records* For all your call detailing needs diff --git a/applications/cdr/src/cdr_app.erl b/applications/cdr/src/cdr_app.erl index c1fea6793cb..93bf646f760 100644 --- a/applications/cdr/src/cdr_app.erl +++ b/applications/cdr/src/cdr_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/cdr/src/cdr_channel_destroy.erl b/applications/cdr/src/cdr_channel_destroy.erl index 673777f18ce..d517d2b88f7 100644 --- a/applications/cdr/src/cdr_channel_destroy.erl +++ b/applications/cdr/src/cdr_channel_destroy.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% Listen for CDR events and record them to the database %%% @end diff --git a/applications/cdr/src/cdr_listener.erl b/applications/cdr/src/cdr_listener.erl index 268dbea2aae..53ff582a6e1 100644 --- a/applications/cdr/src/cdr_listener.erl +++ b/applications/cdr/src/cdr_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% Listen for CDR events and record them to the database %%% @end diff --git a/applications/cdr/src/cdr_sup.erl b/applications/cdr/src/cdr_sup.erl index 5d1c6c8ba46..49cd749daaf 100644 --- a/applications/cdr/src/cdr_sup.erl +++ b/applications/cdr/src/cdr_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (c) 2010-2016, 2600Hz +%%% @copyright (c) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/cdr/src/cdr_util.erl b/applications/cdr/src/cdr_util.erl index aab0581c741..c6bf8ba970d 100644 --- a/applications/cdr/src/cdr_util.erl +++ b/applications/cdr/src/cdr_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (c) 2010-2016, 2600Hz +%%% @copyright (c) 2010-2017, 2600Hz %%% @doc %%% Utility module for CDR operations %%% @end diff --git a/applications/cdr/src/cdr_v3_migrate_lib.erl b/applications/cdr/src/cdr_v3_migrate_lib.erl index 85409738573..94e36cabe6b 100644 --- a/applications/cdr/src/cdr_v3_migrate_lib.erl +++ b/applications/cdr/src/cdr_v3_migrate_lib.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (c) 2010-2016, 2600Hz +%%% @copyright (c) 2010-2017, 2600Hz %%% @doc %%% Utility module for V3 Kazoo Migration %%% @end diff --git a/applications/cdr/src/csv_util.erl b/applications/cdr/src/csv_util.erl index 2adca0fe4f2..bc36bc5dd89 100644 --- a/applications/cdr/src/csv_util.erl +++ b/applications/cdr/src/csv_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (c) 2010-2016, 2600Hz +%%% @copyright (c) 2010-2017, 2600Hz %%% @doc %%% Utility module for V3 Kazoo Migration %%% @end diff --git a/applications/conference/doc/README.md b/applications/conference/doc/README.md index d51adfc060e..c4ba5d4f958 100644 --- a/applications/conference/doc/README.md +++ b/applications/conference/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Conference -Title: Conference -Language: en-US -*/ # Conference This app should have been called "party line"... diff --git a/applications/conference/src/conf_authn_req.erl b/applications/conference/src/conf_authn_req.erl index 192f530a2ba..05020f277c7 100644 --- a/applications/conference/src/conf_authn_req.erl +++ b/applications/conference/src/conf_authn_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Handle authn_req messages %%% @end diff --git a/applications/conference/src/conf_config_req.erl b/applications/conference/src/conf_config_req.erl index 8ff242c2466..a1ec35b1319 100644 --- a/applications/conference/src/conf_config_req.erl +++ b/applications/conference/src/conf_config_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/conference/src/conf_discovery_req.erl b/applications/conference/src/conf_discovery_req.erl index 86407bba855..c7709c248c9 100644 --- a/applications/conference/src/conf_discovery_req.erl +++ b/applications/conference/src/conf_discovery_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/conference/src/conf_participant.erl b/applications/conference/src/conf_participant.erl index 2c5028beb50..b0f45159f6b 100644 --- a/applications/conference/src/conf_participant.erl +++ b/applications/conference/src/conf_participant.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016 2600Hz Inc +%%% @copyright (C) 2013-2017 2600Hz Inc %%% @doc %%% Conference participant process %%% @end diff --git a/applications/conference/src/conf_participant_sup.erl b/applications/conference/src/conf_participant_sup.erl index a31cdd4080a..90dfce823fc 100644 --- a/applications/conference/src/conf_participant_sup.erl +++ b/applications/conference/src/conf_participant_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz Inc +%%% @copyright (C) 2012-2017, 2600Hz Inc %%% @doc %%% Supervisor for running conference participant processes %%% @end diff --git a/applications/conference/src/conf_pronounced_name.erl b/applications/conference/src/conf_pronounced_name.erl index a6ff72ea275..c5e56006157 100644 --- a/applications/conference/src/conf_pronounced_name.erl +++ b/applications/conference/src/conf_pronounced_name.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/conference/src/conf_route_req.erl b/applications/conference/src/conf_route_req.erl index bbd63b8b09b..fd7bc8b5971 100644 --- a/applications/conference/src/conf_route_req.erl +++ b/applications/conference/src/conf_route_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/conference/src/conference_app.erl b/applications/conference/src/conference_app.erl index 0fd0d2dee21..8a6a68cc235 100644 --- a/applications/conference/src/conference_app.erl +++ b/applications/conference/src/conference_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @author Karl Anderson %%% @doc %%% diff --git a/applications/conference/src/conference_listener.erl b/applications/conference/src/conference_listener.erl index bf3b2be0def..83459f3448b 100644 --- a/applications/conference/src/conference_listener.erl +++ b/applications/conference/src/conference_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/conference/src/conference_maintenance.erl b/applications/conference/src/conference_maintenance.erl index 1a6e1bc7b90..dbf70288266 100644 --- a/applications/conference/src/conference_maintenance.erl +++ b/applications/conference/src/conference_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016 2600Hz +%%% @copyright (C) 2011-2017 2600Hz %%% @doc %%% %%% @end diff --git a/applications/conference/src/conference_shared_listener.erl b/applications/conference/src/conference_shared_listener.erl index e088abfc84a..f58f6c1c48d 100644 --- a/applications/conference/src/conference_shared_listener.erl +++ b/applications/conference/src/conference_shared_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/conference/src/conference_sup.erl b/applications/conference/src/conference_sup.erl index 20136a603f1..5168da63dec 100644 --- a/applications/conference/src/conference_sup.erl +++ b/applications/conference/src/conference_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/applications/conference/src/kapi_conf_participant.erl b/applications/conference/src/kapi_conf_participant.erl index 128f0abfe2a..a9505204bad 100644 --- a/applications/conference/src/kapi_conf_participant.erl +++ b/applications/conference/src/kapi_conf_participant.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/doc/access_lists.md b/applications/crossbar/doc/access_lists.md index 89fc5f305b7..b2e60303442 100644 --- a/applications/crossbar/doc/access_lists.md +++ b/applications/crossbar/doc/access_lists.md @@ -18,6 +18,8 @@ Sections: #### Schema +Access Control List entries for device or account + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `cidrs` | Classless Inter-Domain Routing IP notation for use on the access lists | `array(string)` | | `true` @@ -26,6 +28,8 @@ Key | Description | Type | Default | Required `user_agent` | RegExp to match valid user agent strings | `string` | | `false` + + #### Remove account-level access lists > DELETE /v2/accounts/{ACCOUNT_ID}/access_lists diff --git a/applications/crossbar/doc/accounts.md b/applications/crossbar/doc/accounts.md index a308b4ddcf2..51e8fb41517 100644 --- a/applications/crossbar/doc/accounts.md +++ b/applications/crossbar/doc/accounts.md @@ -12,17 +12,19 @@ So given `"pvt_tree":["1", "2", "3"]`, it can be determined that "3" is the pare #### Schema +Accounts represent tenants or customers on the system. Each account represents an individual dataset or sandbox that only one tenant can access. The data set is architecturally independent from other tenants. + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `call_restriction` | Account level call restrictions for each available number classification | `object` | `{}` | `false` -`call_waiting` | | `#/definitions/call_waiting` | | `false` +`call_waiting` | | [#/definitions/call_waiting](#call_waiting) | | `false` `caller_id` | The account default caller ID parameters | `object` | `{}` | `false` `dial_plan` | A list of default rules used to modify dialed numbers | `object` | `{}` | `false` `do_not_disturb` | | `object` | | `false` `do_not_disturb.enabled` | The default value for do-not-disturb | `boolean` | | `false` `enabled` | Determines if the account is currently enabled | `boolean` | `true` | `false` `language` | The language for this account | `string` | `en-us` | `false` -`metaflows` | | `#/definitions/metaflows` | | `false` +`metaflows` | | [#/definitions/metaflows](#metaflows) | | `false` `music_on_hold` | The default music on hold parameters | `object` | `{}` | `false` `music_on_hold.media_id` | The ID of a media object that should be used as the default music on hold | `string(0..128)` | | `false` `name` | A friendly name for the account | `string(1..128)` | | `true` @@ -30,13 +32,278 @@ Key | Description | Type | Default | Required `preflow` | Each property provides functionality that can be applied to calls using the callflow application | `object` | `{}` | `false` `preflow.always` | The ID of a callflow to always execute prior to processing the callflow with numbers/patterns matching the request | `string` | | `false` `realm` | The realm of the account, ie: 'account1.2600hz.com' | `string(4..253)` | | `false` -`ringtones` | | `object` | `{}` | `false` +`ringtones` | Ringtone Parameters | `object` | `{}` | `false` `ringtones.external` | The alert info SIP header added when the call is from internal sources | `string(0..256)` | | `false` `ringtones.internal` | The alert info SIP header added when the call is from external sources | `string(0..256)` | | `false` -`timezone` | The default timezone | `string(5..32)` | `America/Los_Angeles` | `false` +`timezone` | The default timezone | `string(5..32)` | | `false` `voicemail` | | `object` | | `false` `voicemail.notify` | | `object` | | `false` -`voicemail.notify.callback` | | `#/definitions/notify.callback` | | `false` +`voicemail.notify.callback` | | [#/definitions/notify.callback](#notifycallback) | | `false` + + +##### call_waiting + +Parameters for server-side call waiting + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`enabled` | Determines if server side call waiting is enabled/disabled | `boolean` | | `false` + +##### caller_id + +Defines caller ID settings based on the type of call being made + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`emergency` | The caller ID used when a resource is flagged as 'emergency' | `object` | | `false` +`emergency.name` | The caller id name for the object type | `string(0..35)` | | `false` +`emergency.number` | The caller id name for the object type | `string(0..35)` | | `false` +`external` | The default caller ID used when dialing external numbers | `object` | | `false` +`external.name` | The caller id name for the object type | `string(0..35)` | | `false` +`external.number` | The caller id name for the object type | `string(0..35)` | | `false` +`internal` | The default caller ID used when dialing internal extensions | `object` | | `false` +`internal.name` | The caller id name for the object type | `string(0..35)` | | `false` +`internal.number` | The caller id name for the object type | `string(0..35)` | | `false` + +##### dialplans + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`system` | List of system dial plans | `array()` | | `false` + +##### metaflow + +A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- + +##### metaflow.audio_level + +audio_level metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string` | | `true` +`data.level` | | `string` | | `false` +`data.mode` | | `string` | | `false` +`module` | | `string('audio_level')` | | `true` + +##### metaflow.break + +break metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('break')` | | `true` + +##### metaflow.callflow + +callflow metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.id` | | `string` | | `true` +`module` | | `string('callflow')` | | `true` + +##### metaflow.hangup + +hangup metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('hangup')` | | `true` + +##### metaflow.hold + +hold metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.moh_aleg` | | `string` | | `false` +`data.moh_bleg` | | `string` | | `false` +`data.unhold_key` | | `string` | `1` | `false` +`module` | | `string('hold')` | | `true` + +##### metaflow.hold_control + +hold_control metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`data.action` | | `string('hold', 'unhold', 'toggle')` | `toggle` | `false` +`module` | | `string('hold_control')` | | `true` + +##### metaflow.intercept + +intercept metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.auto_answer` | | `boolean` | `false` | `false` +`data.target_id` | | `string` | | `true` +`data.target_type` | | `string('device', 'user', 'number')` | | `true` +`data.unbridged_only` | | `boolean` | `true` | `false` +`module` | | `string('intercept')` | | `true` + +##### metaflow.move + +move metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.auto_answer` | | `boolean` | `false` | `false` +`data.device_id` | | `string` | | `false` +`data.owner_id` | | `string` | | `false` +`module` | | `string('move')` | | `true` + +##### metaflow.play + +play metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.id` | | `string` | | `true` +`data.leg` | | `string('both', 'self', 'peer')` | `both` | `false` +`module` | | `string('play')` | | `true` + +##### metaflow.record_call + +record_call metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string('start', 'stop', 'toggle')` | `toggle` | `true` +`data.format` | | `string` | | `false` +`data.media_name` | | `string` | | `false` +`module` | | `string('record_call')` | | `true` + +##### metaflow.resume + +resume metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('resume')` | | `true` + +##### metaflow.say + +say metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.language` | | `string` | | `false` +`data.method` | | `string` | | `false` +`data.text` | | `string` | | `true` +`data.type` | | `string` | | `false` +`module` | | `string('say')` | | `true` + +##### metaflow.sound_touch + +sound_touch metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string('start', 'stop')` | | `true` +`data.adjust_in_octaves` | | `integer` | | `false` +`data.adjust_in_semitones` | | `integer` | | `false` +`data.hook_dtmf` | | `boolean` | `false` | `false` +`data.pitch` | | `integer` | | `false` +`data.rate` | | `integer` | | `false` +`data.sending_leg` | | `boolean` | `false` | `false` +`data.tempo` | | `integer` | | `false` +`module` | | `string('sound_touch')` | | `true` + +##### metaflow.transfer + +transfer metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.Transfer-Type` | | `string` | `attended` | `false` +`data.captures` | | `string` | | `false` +`data.target` | | `string` | | `false` +`module` | | `string('transfer')` | | `true` + +##### metaflow.tts + +tts metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.engine` | | `string` | `flite` | `false` +`data.language` | | `string` | | `false` +`data.leg` | | `string` | `self` | `false` +`data.terminators` | | `string` | | `false` +`data.text` | | `string` | | `true` +`data.voice` | | `string` | `female` | `false` +`module` | | `string('tts')` | | `true` + +##### metaflow_children + +A metaflow child nodes + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- + +##### metaflows + +Actions applied to a call outside of the normal callflow, initiated by the caller(s) + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`binding_digit` | What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#')` | `*` | `false` +`digit_timeout` | How long to wait between DTMF presses before processing the collected sequence (milliseconds) | `integer` | | `false` +`listen_on` | Which leg(s) of the call to listen for DTMF | `string('both', 'self', 'peer')` | | `false` +`numbers` | A list of static numbers with their flows | `object` | | `false` +`numbers./^[0-9]+$/` | | [#/definitions/metaflow](#metaflow) | | `false` +`patterns` | A list of patterns with their flows | `object` | | `false` +`patterns./.+/` | | [#/definitions/metaflow](#metaflow) | | `false` + +##### notify.callback + +Schema for a callback options + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`attempts` | How many attempts without answer will system do | `integer` | | `false` +`disabled` | Determines if the system will call to callback number | `boolean` | | `false` +`interval_s` | How long will system wait between call back notification attempts | `integer` | | `false` +`number` | Number for callback notifications about new messages | `string` | | `false` +`schedule` | Schedules interval between callbacks | `array(integer)` | | `false` +`timeout_s` | How long will system wait for answer to callback | `integer` | | `false` + + #### Create a new child account diff --git a/applications/crossbar/doc/acls.md b/applications/crossbar/doc/acls.md new file mode 100644 index 00000000000..a9731a3919e --- /dev/null +++ b/applications/crossbar/doc/acls.md @@ -0,0 +1,28 @@ +### Acls + +#### About Acls + +#### Schema + +Access Control List entries + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`cidr` | Classless Inter-Domain Routing IP notation for use on the ACL | `string` | | `true` +`description` | Will be added as a comment for quick identification later | `string(0..30)` | | `false` +`network-list-name` | The trusted list should represent anything that can issue calls without authorization. The authoritative list should indicate inter-network routing equipment (SBC, etc). | `string('authoritative', 'trusted')` | | `true` +`type` | Allow or deny this CIDR | `string('allow', 'deny')` | `allow` | `true` + + + + +#### List items + +> GET /v2/accounts/{ACCOUNT_ID}/acls + +```shell +curl -v -X GET \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/acls +``` + diff --git a/applications/crossbar/doc/allotments.md b/applications/crossbar/doc/allotments.md index 1cdc148ff73..8d9041c9cfb 100644 --- a/applications/crossbar/doc/allotments.md +++ b/applications/crossbar/doc/allotments.md @@ -8,6 +8,8 @@ Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- + + #### Get allotments configuration for a given account > GET /v2/accounts/{ACCOUNT_ID}/allotments diff --git a/applications/crossbar/doc/api_authentication.md b/applications/crossbar/doc/api_authentication.md index 00f8c0baffa..9f02c03e1d5 100644 --- a/applications/crossbar/doc/api_authentication.md +++ b/applications/crossbar/doc/api_authentication.md @@ -1,16 +1,20 @@ +### Api_auth -### Generating an auth token from your API token +Generating an auth token from your API token Use your account's API token to instruct Crossbar to create an authentication token to be used on subsequent requests requiring authentication. -#### The Authentication Process +#### About + +Get your API key for your account: -1. Get your API key for your account: - * This value can be obtained by users on an account via the accounts api endpoint `api_key`. - * This value can also be accessed by system administrators directly from the database by using curl to request the account doc from Couch: +* It can be obtained by users on an account via the accounts API endpoint `api_key`. +* It can also be accessed by system administrators directly from the database by using `curl` to request the account doc from CouchDB: ```shell -curl -v http://localhost:15984/accounts/{ACCOUNT_ID} +curl -v -X PUT \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://localhost:15984//accounts/{ACCOUNT_ID} ``` ```json @@ -20,13 +24,33 @@ curl -v http://localhost:15984/accounts/{ACCOUNT_ID} } ``` -2. Send an HTTP PUT: +#### Schema + +Provides an auth-token via an Account API key + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`api_key` | The Accounts API key | `string(64)` | | `true` + + + + +#### The Authentication Process + +> PUT /v2/api_auth + +Note: + +* `{AUTH_TOKEN}`: this is your authentication token to include in future requests +* `{ACCOUNT_ID}`: your account's ID, useful for constructing URIs +* `{OWNER_ID}`: the user's ID of the owner of the credentials used to generate this token +* `{RESELLER_ID}`: this account's reseller account ID, if any. +* `{REQUEST_ID}`: useful for debugging requests on your installation ```shell curl -v -X PUT \ - -H "content-type:application/json" \ - -d '{"data":{"api_key":"{API_KEY}"}' \ - http://{SERVER}:8000/v1/api_auth + -d '{"data": {"api_key":"{API_KEY}"} }' \ + http://{SERVER}:8000/v2/api_auth ``` ```json @@ -34,7 +58,7 @@ curl -v -X PUT \ "auth_token": "{AUTH_TOKEN}", "data": { "account_id": "{ACCOUNT_ID}", - "apps": [], + "apps": [...], "is_reseller": true, "language": "en-US", "owner_id": "{OWNER_ID}", @@ -45,11 +69,3 @@ curl -v -X PUT \ "status": "success" } ``` - -##### The Response - -* `{AUTH_TOKEN}`: this is your authentication token to include in future requests -* `{ACCOUNT_ID}`: your account's ID, useful for constructing URIs -* `{OWNER_ID}`: The user's ID of the owner of the credentials used to generate this token -* `{RESELLER_ID}`: The account's reseller account ID, if any -* `{REQUEST_ID}`: Useful for debugging requests on your installation diff --git a/applications/crossbar/doc/blacklists.md b/applications/crossbar/doc/blacklists.md index de76f32df0e..8a3d4e3f5a4 100644 --- a/applications/crossbar/doc/blacklists.md +++ b/applications/crossbar/doc/blacklists.md @@ -1,7 +1,21 @@ +### Blacklists +#### About Blacklists A blacklist is a map of caller id numbers that can be then apply to the account to block these callers to call the system. +#### Schema + +Schema for a blacklists + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`name` | A friendly name for the temporal rule set | `string(1..128)` | | `true` +`numbers` | Map of caller id number to block | `object` | `{}` | `false` + + + + #### Structure The structure is really simple: diff --git a/applications/crossbar/doc/callflows.md b/applications/crossbar/doc/callflows.md index 3588c4a4de5..faf09156f08 100644 --- a/applications/crossbar/doc/callflows.md +++ b/applications/crossbar/doc/callflows.md @@ -6,21 +6,253 @@ Callflows are the instructions Kazoo uses to process a call. A callflow includes #### Schema +Call flows describe steps to take in order to process a phone call. They are trees of information related to a phone call such as "answer, play file, record file" etc. that are logically grouped together and ordered. + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `featurecode` | When the callflow is used as a featurecode this object tracks the intended match of the pattern and name of the feature | `object` | | `false` `featurecode.name` | | `string(1..128)` | | `false` `featurecode.number` | | `string(1..30)` | | `false` -`flow` | A callflow node defines a module to execute, data to provide to that module, and zero or more children to branch to | `object` | | `true` -`flow.children` | Children callflows | `object` | `{}` | `false` -`flow.data` | The data/arguments of the callflow module | `object` | `{}` | `true` -`flow.module` | The name of the callflow module to excute at this node | `string(1..64)` | | `true` -`metaflow` | Actions applied to a call outside of the normal callflow, initiated by the caller(s) | `#/definitions/metaflows` | | `false` +`flow` | A callflow node defines a module to execute, data to provide to that module, and zero or more children to branch to | [#/definitions/callflows.action](#callflowsaction) | | `false` +`metaflow` | Actions applied to a call outside of the normal callflow, initiated by the caller(s) | [#/definitions/metaflows](#metaflows) | | `false` `numbers` | A list of static numbers that the callflow should execute for | `array(string(1..36))` | `[]` | `false` `numbers.[]` | | `string` | | `false` `patterns` | A list of regular expressions that the callflow should execute for, with optional capture groups | `array(string(1..))` | `[]` | `false` `patterns.[]` | | `string` | | `false` + +##### callflows.action + +Call flows describe steps to take in order to process a phone call. They are trees of information related to a phone call such as "answer, play file, record file" etc. that are logically grouped together and ordered. + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | Children callflows | `object` | | `false` +`children./.+/` | | [#/definitions/callflows.action](#callflowsaction) | | `false` +`data` | The data/arguments of the callflow module | `object` | | `true` +`module` | The name of the callflow module to excute at this node | `string(1..64)` | | `true` + +##### metaflow + +A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- + +##### metaflow.audio_level + +audio_level metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string` | | `true` +`data.level` | | `string` | | `false` +`data.mode` | | `string` | | `false` +`module` | | `string('audio_level')` | | `true` + +##### metaflow.break + +break metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('break')` | | `true` + +##### metaflow.callflow + +callflow metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.id` | | `string` | | `true` +`module` | | `string('callflow')` | | `true` + +##### metaflow.hangup + +hangup metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('hangup')` | | `true` + +##### metaflow.hold + +hold metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.moh_aleg` | | `string` | | `false` +`data.moh_bleg` | | `string` | | `false` +`data.unhold_key` | | `string` | `1` | `false` +`module` | | `string('hold')` | | `true` + +##### metaflow.hold_control + +hold_control metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`data.action` | | `string('hold', 'unhold', 'toggle')` | `toggle` | `false` +`module` | | `string('hold_control')` | | `true` + +##### metaflow.intercept + +intercept metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.auto_answer` | | `boolean` | `false` | `false` +`data.target_id` | | `string` | | `true` +`data.target_type` | | `string('device', 'user', 'number')` | | `true` +`data.unbridged_only` | | `boolean` | `true` | `false` +`module` | | `string('intercept')` | | `true` + +##### metaflow.move + +move metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.auto_answer` | | `boolean` | `false` | `false` +`data.device_id` | | `string` | | `false` +`data.owner_id` | | `string` | | `false` +`module` | | `string('move')` | | `true` + +##### metaflow.play + +play metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.id` | | `string` | | `true` +`data.leg` | | `string('both', 'self', 'peer')` | `both` | `false` +`module` | | `string('play')` | | `true` + +##### metaflow.record_call + +record_call metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string('start', 'stop', 'toggle')` | `toggle` | `true` +`data.format` | | `string` | | `false` +`data.media_name` | | `string` | | `false` +`module` | | `string('record_call')` | | `true` + +##### metaflow.resume + +resume metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('resume')` | | `true` + +##### metaflow.say + +say metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.language` | | `string` | | `false` +`data.method` | | `string` | | `false` +`data.text` | | `string` | | `true` +`data.type` | | `string` | | `false` +`module` | | `string('say')` | | `true` + +##### metaflow.sound_touch + +sound_touch metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string('start', 'stop')` | | `true` +`data.adjust_in_octaves` | | `integer` | | `false` +`data.adjust_in_semitones` | | `integer` | | `false` +`data.hook_dtmf` | | `boolean` | `false` | `false` +`data.pitch` | | `integer` | | `false` +`data.rate` | | `integer` | | `false` +`data.sending_leg` | | `boolean` | `false` | `false` +`data.tempo` | | `integer` | | `false` +`module` | | `string('sound_touch')` | | `true` + +##### metaflow.transfer + +transfer metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.Transfer-Type` | | `string` | `attended` | `false` +`data.captures` | | `string` | | `false` +`data.target` | | `string` | | `false` +`module` | | `string('transfer')` | | `true` + +##### metaflow.tts + +tts metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.engine` | | `string` | `flite` | `false` +`data.language` | | `string` | | `false` +`data.leg` | | `string` | `self` | `false` +`data.terminators` | | `string` | | `false` +`data.text` | | `string` | | `true` +`data.voice` | | `string` | `female` | `false` +`module` | | `string('tts')` | | `true` + +##### metaflow_children + +A metaflow child nodes + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- + +##### metaflows + +Actions applied to a call outside of the normal callflow, initiated by the caller(s) + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`binding_digit` | What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#')` | `*` | `false` +`digit_timeout` | How long to wait between DTMF presses before processing the collected sequence (milliseconds) | `integer` | | `false` +`listen_on` | Which leg(s) of the call to listen for DTMF | `string('both', 'self', 'peer')` | | `false` +`numbers` | A list of static numbers with their flows | `object` | | `false` +`numbers./^[0-9]+$/` | | [#/definitions/metaflow](#metaflow) | | `false` +`patterns` | A list of patterns with their flows | `object` | | `false` +`patterns./.+/` | | [#/definitions/metaflow](#metaflow) | | `false` + + + #### Fetch an account's callflows > GET /v2/accounts/{ACCOUNT_ID}/callflows diff --git a/applications/crossbar/doc/cccps.md b/applications/crossbar/doc/cccps.md new file mode 100644 index 00000000000..dcc6b70cc7d --- /dev/null +++ b/applications/crossbar/doc/cccps.md @@ -0,0 +1,29 @@ +### Cccps + +#### About Cccps + +#### Schema + +Calling cards callback platform user's info + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`active` | Show's whether CID/PIN active | `boolean` | `false` | `false` +`cid` | CID to authorize | `string` | | `false` +`max_concurent_calls_per_user` | Calls per user limit. Counts all user's legs and compares to max_concurent_calls_per_user multiplied by 2 | `integer` | | `false` +`pin` | PIN to authorize | `string` | | `false` +`retain_cid` | Pass initial caller number to the callee | `boolean` | | `false` +`user_id` | The ID of the user object that 'owns' cid/pin | `string(32)` | | `false` + + + + +#### List items + +> GET /v2/accounts/{ACCOUNT_ID}/cccps + +```shell +curl -v -X GET \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cccps +``` diff --git a/applications/crossbar/doc/cdrs.md b/applications/crossbar/doc/cdrs.md index 3f8aa3efea6..41ff13f9123 100644 --- a/applications/crossbar/doc/cdrs.md +++ b/applications/crossbar/doc/cdrs.md @@ -6,6 +6,8 @@ CDRs (Call Detail Records) provide a summary view of a call leg. #### Schema +Call Detail Records + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `app_name` | The Kazoo application that issued the CDR | `string` | | `false` @@ -51,6 +53,9 @@ Key | Description | Type | Default | Required `to_uri` | The To SIP URI | `string` | | `false` `user_agent` | User agent header from SIP packet | `string` | | `false` + + + #### Fetch a summary of CDRs > GET /v2/accounts/{ACCOUNT_ID}/cdrs diff --git a/applications/crossbar/doc/clicktocall.md b/applications/crossbar/doc/clicktocall.md new file mode 100644 index 00000000000..6f80a0b2384 --- /dev/null +++ b/applications/crossbar/doc/clicktocall.md @@ -0,0 +1,33 @@ +### Clicktocall + +#### About Clicktocall + +#### Schema + +Click-to-call allows you to create URLs that can be POSTed to with a phone number or SIP URI and create a phone call from the provided contact information to a destination you have pre-determined. + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`auth_required` | Determines if this click to call requires valid auth-tokens when invoked | `boolean` | `true` | `false` +`caller_id_number` | Explicitly set caller id number | `string` | | `false` +`dial_first` | Determinates what will be dialed first: extension or contact | `string('extension', 'contact')` | | `false` +`extension` | The extension to connect to when the click to call is invoked | `string` | | `true` +`name` | A friendly name for the click to call | `string(1..128)` | | `true` +`outbound_callee_id_name` | Callee ID Name of the device calling out to the contact number | `string` | | `false` +`outbound_callee_id_number` | Callee ID Number of the device calling out to the contact number | `string` | | `false` +`throttle` | The rate that this click to call can be invoked | `integer` | | `false` +`whitelist` | A list of regular expressions that the click to call can dial to | `array(string(1..))` | | `false` +`whitelist.[]` | | `string` | | `false` + + + + +#### List items + +> GET /v2/accounts/{ACCOUNT_ID}/clicktocall + +```shell +curl -v -X GET \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall +``` diff --git a/applications/crossbar/doc/conference.md b/applications/crossbar/doc/conference.md index ced694dcd4b..5821f0ee709 100644 --- a/applications/crossbar/doc/conference.md +++ b/applications/crossbar/doc/conference.md @@ -7,22 +7,24 @@ conference locked status. The realtime information is added to conference docume #### Schema +Schema for conferences + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `conference_numbers` | Defines conference numbers that can be used by members or moderators | `array(string)` | `[]` | `false` `conference_numbers.[]` | | `string` | | `false` `focus` | This is a read-only property indicating the media server hosting the conference | `string` | | `false` -`member` | Defines the discovery properties for a member | `object` | `{}` | `false` +`member` | Defines the discovery (call in) properties for a member | `object` | `{}` | `false` `member.join_deaf` | Determines if a member will join deaf | `boolean` | `false` | `false` `member.join_muted` | Determines if a member will join muted | `boolean` | `true` | `false` -`member.numbers` | Defines the conference number(s) for members | `array(string)` | `[]` | `false` +`member.numbers` | Defines the conference (call in) number(s) for members | `array(string)` | `[]` | `false` `member.numbers.[]` | | `string` | | `false` `member.pins` | Defines the pin number(s) for members | `array(string)` | `[]` | `false` `member.pins.[]` | | `string` | | `false` -`moderator` | Defines the discovery properties for a moderator | `object` | `{}` | `false` +`moderator` | Defines the discovery (call in) properties for a moderator | `object` | `{}` | `false` `moderator.join_deaf` | Determines if a moderator will join deaf | `boolean` | `false` | `false` `moderator.join_muted` | Determines if a moderator will join muted | `boolean` | `false` | `false` -`moderator.numbers` | Defines the conference number(s) for moderators | `array(string)` | `[]` | `false` +`moderator.numbers` | Defines the conference (call in) number(s) for moderators | `array(string)` | `[]` | `false` `moderator.numbers.[]` | | `string` | | `false` `moderator.pins` | Defines the pin number(s) for moderators | `array(string)` | `[]` | `false` `moderator.pins.[]` | | `string` | | `false` @@ -32,6 +34,8 @@ Key | Description | Type | Default | Required `profile` | The XML profile name used to configure the conference | `string` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/conferences diff --git a/applications/crossbar/doc/connectivity.md b/applications/crossbar/doc/connectivity.md new file mode 100644 index 00000000000..9d39a9ca446 --- /dev/null +++ b/applications/crossbar/doc/connectivity.md @@ -0,0 +1,53 @@ +### Connectivity + +#### About Connectivity + +#### Schema + +Trunkstore configuration document - this is old stuff; do not recommend building off this if possible + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`account` | Information that applies to the account as a whole | `object` | | `false` +`account.auth_realm` | The realm any device in the account will use to authenticate with | `string(1..)` | | `false` +`account.caller_id` | | `object` | | `false` +`account.caller_id.cid_name` | | `string(0..35)` | | `false` +`account.caller_id.cid_number` | | `string(0..35)` | | `false` +`account.emergency_caller_id` | | `object` | | `false` +`account.emergency_caller_id.cid_name` | | `string(0..35)` | | `false` +`account.emergency_caller_id.cid_number` | | `string(0..35)` | | `false` +`account.trunks` | The number of two-way trunks this account has purchased | `integer` | | `false` +`name` | Human-friendly name of the trunkstore account | `string` | | `false` +`servers` | | `array(object)` | `[]` | `false` +`servers.[].DIDs` | | `object` | | `false` +`servers.[].DIDs./^\+?\d*$/` | | `object` | | `false` +`servers.[].DIDs./^\+?\d*$/.caller_id` | | `object` | | `false` +`servers.[].DIDs./^\+?\d*$/.caller_id.cid_name` | | `string(1..35)` | | `true` +`servers.[].DIDs./^\+?\d*$/.caller_id.cid_number` | | `string(1..35)` | | `true` +`servers.[].DIDs./^\+?\d*$/.failover` | Route inbound call to another destination if this server fails to handle the call | `object` | | `false` +`servers.[].DIDs./^\+?\d*$/.failover.e164` | An E.164 formatted DID to dial for failover | `string` | | `false` +`servers.[].DIDs./^\+?\d*$/.failover.sip` | A SIP URI (sip:user@host) to call for failover | `string` | | `false` +`servers.[].DIDs./^\+?\d*$/.force_outbound` | | `boolean` | `false` | `false` +`servers.[].DIDs./^\+?\d*$/.options` | | `array(string)` | | `false` +`servers.[].DIDs./^\+?\d*$/.options.[]` | | `string` | | `false` +`servers.[].auth` | | `object` | | `true` +`servers.[].auth.auth_method` | What type of auth mechanism to use | `string('password', 'Password', 'IP', 'ip')` | `password` | `true` +`servers.[].auth.auth_password` | Password of the user@auth_realm | `string(1..)` | | `false` +`servers.[].auth.auth_user` | Username for authentication | `string(1..)` | | `false` +`servers.[].auth.ip` | IP (sip) address for this device | `string` | | `false` +`servers.[].auth.port` | Port to send SIP traffic for the remote device | `integer` | | `false` +`servers.[].name` | Human-friendly name of the server | `string(1..)` | | `false` +`servers.[].options` | | `object` | | `false` + + + + +#### List items + +> GET /v2/accounts/{ACCOUNT_ID}/connectivity + +```shell +curl -v -X GET \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity +``` diff --git a/applications/crossbar/doc/devices.md b/applications/crossbar/doc/devices.md index 1fa064e3328..403032e4160 100644 --- a/applications/crossbar/doc/devices.md +++ b/applications/crossbar/doc/devices.md @@ -7,6 +7,8 @@ Devices like fax machines, SIP phones, soft phone clients, and cell phones (via #### Schema +A device be it a SIP phone or landline number + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `call_forward` | The device call forward parameters | `object` | | `false` @@ -19,33 +21,33 @@ Key | Description | Type | Default | Required `call_forward.require_keypress` | Determines if the callee is prompted to press 1 to accept the call | `boolean` | `true` | `false` `call_forward.substitute` | Determines if the call forwarding replaces the device | `boolean` | `true` | `false` `call_restriction` | Device level call restrictions for each available number classification | `object` | `{}` | `false` -`call_waiting` | | `#/definitions/call_waiting` | | `false` +`call_waiting` | | [#/definitions/call_waiting](#call_waiting) | | `false` `caller_id` | The device caller ID parameters | `object` | `{}` | `false` -`contact_list` | | `object` | `{}` | `false` +`contact_list` | Contect List Parameters | `object` | `{}` | `false` `contact_list.exclude` | If set to true the device is excluded from the contact list | `boolean` | | `false` `device_type` | Arbitrary device type used by the UI and billing system | `string` | | `false` `dial_plan` | A list of rules used to modify dialed numbers | `object` | `{}` | `false` -`do_not_disturb` | | `object` | | `false` +`do_not_disturb` | DND Parameters | `object` | | `false` `do_not_disturb.enabled` | Is do-not-disturb enabled for this device? | `boolean` | | `false` `enabled` | Determines if the device is currently enabled | `boolean` | `true` | `false` `exclude_from_queues` | Do not ring this device when calling user/agent in queue | `boolean` | `false` | `false` `language` | The language for the device | `string` | | `false` `media` | The device media parameters | `object` | `{}` | `false` `media.audio` | The audio media parameters | `object` | `{}` | `false` -`media.audio.codecs` | A list of audio codecs the device supports | `array(string('OPUS', 'CELT@32000h', 'G7221@32000h', 'G7221@16000h', 'G722', 'speex@32000h', 'speex@16000h', 'PCMU', 'PCMA', 'G729', 'GSM', 'CELT@48000h', 'CELT@64000h', 'G722_16', 'G722_32', 'CELT_48', 'CELT_64', 'Speex', 'speex'))` | `PCMU` | `false` +`media.audio.codecs` | A list of audio codecs the device supports | `array(string('OPUS', 'CELT@32000h', 'G7221@32000h', 'G7221@16000h', 'G722', 'speex@32000h', 'speex@16000h', 'PCMU', 'PCMA', 'G729', 'GSM', 'CELT@48000h', 'CELT@64000h', 'G722_16', 'G722_32', 'CELT_48', 'CELT_64', 'Speex', 'speex'))` | `["PCMU"]` | `false` `media.audio.codecs.[]` | | `string` | | `false` `media.bypass_media` | Default bypass media mode | `boolean, string('true', 'false', 'auto')` | | `false` -`media.encryption` | | `object` | `{}` | `false` -`media.encryption.enforce_security` | | `boolean` | `false` | `false` -`media.encryption.methods` | | `array(string('zrtp', 'srtp'))` | `[]` | `false` +`media.encryption` | Encryption Parameters | `object` | `{}` | `false` +`media.encryption.enforce_security` | Is Encryption Enabled? | `boolean` | `false` | `false` +`media.encryption.methods` | Supported Encryption Types | `array(string('zrtp', 'srtp'))` | `[]` | `false` `media.encryption.methods.[]` | | `string` | | `false` -`media.fax_option` | Support T.38 | `boolean` | | `false` +`media.fax_option` | Is T.38 Supported? | `boolean` | | `false` `media.ignore_early_media` | The option to determine if early media from the device should always be ignored | `boolean` | | `false` -`media.progress_timeout` | The progress timeout to apply to the device | `integer` | | `false` +`media.progress_timeout` | The progress timeout to apply to the device (seconds) | `integer` | | `false` `media.video` | The video media parameters | `object` | `{}` | `false` `media.video.codecs` | A list of video codecs the device supports | `array(string('VP8', 'H264', 'H263', 'H261'))` | `[]` | `false` `media.video.codecs.[]` | | `string` | | `false` -`metaflows` | The device metaflow parameters | `#/definitions/metaflows` | | `false` +`metaflows` | The device metaflow parameters | [#/definitions/metaflows](#metaflows) | | `false` `music_on_hold` | The music on hold parameters used if not a property of the device owner | `object` | `{}` | `false` `music_on_hold.media_id` | The ID of a media object that should be used as the music on hold | `string(0..128)` | | `false` `mwi_unsolicitated_updates` | When true enables unsolicitated mwi notifications | `boolean` | `true` | `false` @@ -55,15 +57,15 @@ Key | Description | Type | Default | Required `owner_id` | The ID of the user object that 'owns' the device | `string(32)` | | `false` `presence_id` | Static presence ID (used instead of SIP username) | `string` | | `false` `provision` | Provision data | `object` | | `false` -`provision.feature_keys` | | `object` | | `false` -`provision.feature_keys.^[0-9]+$` | | `object` | | `false` -`provision.feature_keys.^[0-9]+$.type` | Feature key type | `string('presence', 'parking', 'personal_parking', 'speed_dial')` | | `true` -`provision.feature_keys.^[0-9]+$.value` | Feature key value | `string, integer` | | `true` +`provision.feature_keys` | Feature Keys | `object` | | `false` +`provision.feature_keys./^[0-9]+$/` | | `object` | | `false` +`provision.feature_keys./^[0-9]+$/.type` | Feature key type | `string('presence', 'parking', 'personal_parking', 'speed_dial')` | | `true` +`provision.feature_keys./^[0-9]+$/.value` | Feature key value | `string, integer` | | `true` `register_overwrite_notify` | When true enables overwrite notifications | `boolean` | `false` | `false` -`ringtones` | | `object` | `{}` | `false` +`ringtones` | Ringtone Parameters | `object` | `{}` | `false` `ringtones.external` | The alert info SIP header added when the call is from internal sources | `string(0..256)` | | `false` `ringtones.internal` | The alert info SIP header added when the call is from external sources | `string(0..256)` | | `false` -`sip` | | `object` | `{}` | `false` +`sip` | SIP Parameters | `object` | `{}` | `false` `sip.custom_sip_headers` | A property list of SIP headers beging with the prefix 'X-' | `object` | | `false` `sip.expire_seconds` | The time, in seconds, sent to the provisioner for the registration period that the device should be configured with. | `integer` | `300` | `false` `sip.ignore_completed_elsewhere` | When set to false the phone should not consider ring group calls answered elsewhere as missed | `boolean` | | `false` @@ -79,6 +81,258 @@ Key | Description | Type | Default | Required `suppress_unregister_notifications` | When true disables deregister notifications | `boolean` | `false` | `false` `timezone` | Device's timezone | `string` | | `false` + +##### call_waiting + +Parameters for server-side call waiting + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`enabled` | Determines if server side call waiting is enabled/disabled | `boolean` | | `false` + +##### caller_id + +Defines caller ID settings based on the type of call being made + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`emergency` | The caller ID used when a resource is flagged as 'emergency' | `object` | | `false` +`emergency.name` | The caller id name for the object type | `string(0..35)` | | `false` +`emergency.number` | The caller id name for the object type | `string(0..35)` | | `false` +`external` | The default caller ID used when dialing external numbers | `object` | | `false` +`external.name` | The caller id name for the object type | `string(0..35)` | | `false` +`external.number` | The caller id name for the object type | `string(0..35)` | | `false` +`internal` | The default caller ID used when dialing internal extensions | `object` | | `false` +`internal.name` | The caller id name for the object type | `string(0..35)` | | `false` +`internal.number` | The caller id name for the object type | `string(0..35)` | | `false` + +##### dialplans + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`system` | List of system dial plans | `array()` | | `false` + +##### metaflow + +A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- + +##### metaflow.audio_level + +audio_level metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string` | | `true` +`data.level` | | `string` | | `false` +`data.mode` | | `string` | | `false` +`module` | | `string('audio_level')` | | `true` + +##### metaflow.break + +break metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('break')` | | `true` + +##### metaflow.callflow + +callflow metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.id` | | `string` | | `true` +`module` | | `string('callflow')` | | `true` + +##### metaflow.hangup + +hangup metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('hangup')` | | `true` + +##### metaflow.hold + +hold metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.moh_aleg` | | `string` | | `false` +`data.moh_bleg` | | `string` | | `false` +`data.unhold_key` | | `string` | `1` | `false` +`module` | | `string('hold')` | | `true` + +##### metaflow.hold_control + +hold_control metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`data.action` | | `string('hold', 'unhold', 'toggle')` | `toggle` | `false` +`module` | | `string('hold_control')` | | `true` + +##### metaflow.intercept + +intercept metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.auto_answer` | | `boolean` | `false` | `false` +`data.target_id` | | `string` | | `true` +`data.target_type` | | `string('device', 'user', 'number')` | | `true` +`data.unbridged_only` | | `boolean` | `true` | `false` +`module` | | `string('intercept')` | | `true` + +##### metaflow.move + +move metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.auto_answer` | | `boolean` | `false` | `false` +`data.device_id` | | `string` | | `false` +`data.owner_id` | | `string` | | `false` +`module` | | `string('move')` | | `true` + +##### metaflow.play + +play metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.id` | | `string` | | `true` +`data.leg` | | `string('both', 'self', 'peer')` | `both` | `false` +`module` | | `string('play')` | | `true` + +##### metaflow.record_call + +record_call metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string('start', 'stop', 'toggle')` | `toggle` | `true` +`data.format` | | `string` | | `false` +`data.media_name` | | `string` | | `false` +`module` | | `string('record_call')` | | `true` + +##### metaflow.resume + +resume metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('resume')` | | `true` + +##### metaflow.say + +say metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.language` | | `string` | | `false` +`data.method` | | `string` | | `false` +`data.text` | | `string` | | `true` +`data.type` | | `string` | | `false` +`module` | | `string('say')` | | `true` + +##### metaflow.sound_touch + +sound_touch metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string('start', 'stop')` | | `true` +`data.adjust_in_octaves` | | `integer` | | `false` +`data.adjust_in_semitones` | | `integer` | | `false` +`data.hook_dtmf` | | `boolean` | `false` | `false` +`data.pitch` | | `integer` | | `false` +`data.rate` | | `integer` | | `false` +`data.sending_leg` | | `boolean` | `false` | `false` +`data.tempo` | | `integer` | | `false` +`module` | | `string('sound_touch')` | | `true` + +##### metaflow.transfer + +transfer metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.Transfer-Type` | | `string` | `attended` | `false` +`data.captures` | | `string` | | `false` +`data.target` | | `string` | | `false` +`module` | | `string('transfer')` | | `true` + +##### metaflow.tts + +tts metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.engine` | | `string` | `flite` | `false` +`data.language` | | `string` | | `false` +`data.leg` | | `string` | `self` | `false` +`data.terminators` | | `string` | | `false` +`data.text` | | `string` | | `true` +`data.voice` | | `string` | `female` | `false` +`module` | | `string('tts')` | | `true` + +##### metaflow_children + +A metaflow child nodes + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- + +##### metaflows + +Actions applied to a call outside of the normal callflow, initiated by the caller(s) + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`binding_digit` | What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#')` | `*` | `false` +`digit_timeout` | How long to wait between DTMF presses before processing the collected sequence (milliseconds) | `integer` | | `false` +`listen_on` | Which leg(s) of the call to listen for DTMF | `string('both', 'self', 'peer')` | | `false` +`numbers` | A list of static numbers with their flows | `object` | | `false` +`numbers./^[0-9]+$/` | | [#/definitions/metaflow](#metaflow) | | `false` +`patterns` | A list of patterns with their flows | `object` | | `false` +`patterns./.+/` | | [#/definitions/metaflow](#metaflow) | | `false` + + + #### Fetch summary of devices in account > GET /v2/accounts/{ACCOUNT_ID}/devices diff --git a/applications/crossbar/doc/dialplans.md b/applications/crossbar/doc/dialplans.md new file mode 100644 index 00000000000..38515ea0d78 --- /dev/null +++ b/applications/crossbar/doc/dialplans.md @@ -0,0 +1,23 @@ +### Dialplans + +#### About Dialplans + +#### Schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`system` | List of system dial plans | `array()` | | `false` + + + + +#### List items + +> GET /v2/accounts/{ACCOUNT_ID}/dialplans + +```shell +curl -v -X GET \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/dialplans +``` + diff --git a/applications/crossbar/doc/directories.md b/applications/crossbar/doc/directories.md index 63c3bf5a160..297e07a0dd7 100644 --- a/applications/crossbar/doc/directories.md +++ b/applications/crossbar/doc/directories.md @@ -6,6 +6,8 @@ Directories provide the ability to route a caller to a user by having the caller #### Schema +Allow a caller to search for a user/device by name instead of extension/DID + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `confirm_match` | When one match is found, require caller to confirm the match before connecting | `boolean` | `true` | `false` @@ -17,6 +19,8 @@ Key | Description | Type | Default | Required `users.[]` | | `string` | | `false` + + #### List directories > GET /v2/accounts/{ACCOUNT_ID}/directories diff --git a/applications/crossbar/doc/faxes.md b/applications/crossbar/doc/faxes.md index 32b44635ae6..4b5120cb2e4 100644 --- a/applications/crossbar/doc/faxes.md +++ b/applications/crossbar/doc/faxes.md @@ -5,14 +5,16 @@ The Faxes API exposes lots of ways to send, receive, track and manage faxes. As a general concept, faxes are either considered inbound or outbound faxes. In addition: + * API calls with the term "incoming" are used for tracking faxes currently in the process of being received * API calls with the term "inbox" are used for managing faxes which have already been received * API calls with the term "outgoing" are used for tracking faxes currently in the process of being sent * API calls with the term "outbox" are used for managing faxes which have already been sent - #### Schema +Faxes API allows you to update and access fax jobs for both sending and receiving + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `attempts` | The number of attempts made, this will be set by the system and reset automaticly on put/post | `integer` | `0` | `false` @@ -38,18 +40,21 @@ Key | Description | Type | Default | Required `tx_result.fax_bad_rows` | The number of bad rows | `integer` | `0` | `false` `tx_result.fax_error_correction` | True if fax error correction was used | `boolean` | `false` | `false` `tx_result.fax_receiver_id` | The receiver id reported by the remote fax device | `string` | "" | `false` -`tx_result.fax_speed` | The speed achieved during transmission | `integer` | `0` | `false` +`tx_result.fax_speed` | The speed (Baud-Rate) achieved during transmission | `integer` | `0` | `false` `tx_result.pages_sent` | The number of pages transmitted | `integer` | `0` | `false` `tx_result.success` | True if the fax transmission was successful | `boolean` | `false` | `false` `tx_result.time_elapsed` | The amount of time from submition to completion | `integer` | `0` | `false` + + + #### Processing States State | Description ----- | ----------- `attaching_files` | A fax job was submitted via the api (with a multipart/related content type) or smtp and we are in the process of attaching the files to the fax job. `pending` | Fax waiting to be picked up by the fax sending job -`failed` | If we can't retrieve the fax document via a requests URL, the state will be "failed" and the error text will contain "could not retrieve file, http response " +`failed` | If we can't retrieve the fax document via a requests URL, the state will be "failed" and the error text will contain "could not retrieve file, http response XXX" `processing` | Faxes that are actively picked up by the fax worker and are being processed `completed` | Faxes that are finished sending `failed` | Faxes that did not successfully send after all allotted retries are in state "failed". We pass-thru the FreeSWITCH error code in this case. diff --git a/applications/crossbar/doc/groups.md b/applications/crossbar/doc/groups.md index d0c9ea700c6..88cd71bba08 100644 --- a/applications/crossbar/doc/groups.md +++ b/applications/crossbar/doc/groups.md @@ -4,6 +4,8 @@ #### Schema +Validator for the group + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `endpoints` | Endpoints included into group | `object` | `{}` | `true` @@ -12,6 +14,8 @@ Key | Description | Type | Default | Required `name` | A friendly name for the group | `string(1..128)` | | `true` + + #### Get groups for a given account > GET /v2/accounts/{ACCOUNT_ID}/groups diff --git a/applications/crossbar/doc/ips.md b/applications/crossbar/doc/ips.md index 3a830e17845..205b0172d83 100644 --- a/applications/crossbar/doc/ips.md +++ b/applications/crossbar/doc/ips.md @@ -23,13 +23,18 @@ Key | Description | Type | Default | Required Once you've added IPs to the system, you can assign those to different customer accounts to proxy their calls through using the below Crossbar APIs. -#### Crossbar Schema +#### Schema + +IP addresses assigned to the account Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `ips` | List of IP addresses | `array(string)` | | `false` `ips.[]` | | `string` | | `false` + + + #### Fetch a list of IPs available to the account > GET /v2/accounts/{ACCOUNT_ID}/ips diff --git a/applications/crossbar/doc/ledgers.md b/applications/crossbar/doc/ledgers.md index 24ddbba1de5..56b8089ef3c 100644 --- a/applications/crossbar/doc/ledgers.md +++ b/applications/crossbar/doc/ledgers.md @@ -4,6 +4,8 @@ #### Schema +ledgers document + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `account` | Account info | `object` | | `false` @@ -24,6 +26,8 @@ Key | Description | Type | Default | Required `usage.unit` | Usage unit | `string` | | `true` + + #### List current Ledgers List current ledgers and value for an account. diff --git a/applications/crossbar/doc/limits.md b/applications/crossbar/doc/limits.md index 2ab605fd2e3..f7093ce7419 100644 --- a/applications/crossbar/doc/limits.md +++ b/applications/crossbar/doc/limits.md @@ -4,9 +4,11 @@ #### Schema +Limit an account's ability to place concurrent calls using flat rate trunks + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- -`allow_prepay` | Determines if the account would like to allow per-minute calls if they have credit | `boolean` | `true` | `false` +`allow_prepay` | Determines if the account would like to allow per-minute calls if they have no available credit | `boolean` | `true` | `false` `burst_trunks` | The number of two-way, flat-rate trunks used only if no other trunks are available | `integer` | | `false` `calls` | A hard limit for the total number calls | `integer` | | `false` `inbound_trunks` | The number of inbound, flat-rate trunks | `integer` | | `false` @@ -15,6 +17,8 @@ Key | Description | Type | Default | Required `twoway_trunks` | The number of two-way, flat-rate trunks | `integer` | | `false` + + #### Get limits for a given account > GET /v2/accounts/{ACCOUNT_ID}/limits diff --git a/applications/crossbar/doc/lists.md b/applications/crossbar/doc/lists.md index 3dd6b432c53..1ee3654afad 100644 --- a/applications/crossbar/doc/lists.md +++ b/applications/crossbar/doc/lists.md @@ -2,6 +2,8 @@ #### Schema +Schema for a match list + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `description` | A friendly list description | `string(1..128)` | | `false` @@ -9,6 +11,8 @@ Key | Description | Type | Default | Required `org` | Full legal name of the organization | `string` | | `false` + + #### Get all lists (doesn't return entries) > GET /v2/accounts/{ACCOUNT_ID}/lists diff --git a/applications/crossbar/doc/maintenance.md b/applications/crossbar/doc/maintenance.md index 10d54788eab..4553171ff00 100644 --- a/applications/crossbar/doc/maintenance.md +++ b/applications/crossbar/doc/maintenance.md @@ -6,3 +6,51 @@ The `migrate_ring_group_callflow` function will migrate callflow create with a ring group by **Monster UI before v3.19**. It will extract the ring group and create a new callflow and then reference this new callflow in the old one. This function will not impact any other callflows or ring group callflows create by Kazoo UI. + + +### Update UI apps metadata + +#### List all apps + +```shell +sup crossbar_maintenance apps +``` + +#### Get one app's metadata + +```shell +sup crossbar_maintenance app AppName_Or_AppId +``` + +#### Update an app's en-US fields + +```shell +sup crossbar_maintenance set_app_label AppId NewValue +``` + +```shell +sup crossbar_maintenance set_app_description AppId NewValue +``` + +```shell +sup crossbar_maintenance set_app_extended_description AppId NewValue +``` + +Note: features must be @-separated if more than one is supplied. + +```shell +sup crossbar_maintenance set_app_features AppId 'my feature' +sup crossbar_maintenance set_app_features AppId feature1@featureB@feat3 +``` + +#### Update an app's icon + +```shell +sup crossbar_maintenance set_app_icon AppId PathToPNGIcon +``` + +#### Update an app's screenshosts + +```shell +sup crossbar_maintenance set_app_screenshots AppId PathToScreenshotsFolder +``` diff --git a/applications/crossbar/doc/media.md b/applications/crossbar/doc/media.md index e4e4eff1313..0c584a9a8f0 100644 --- a/applications/crossbar/doc/media.md +++ b/applications/crossbar/doc/media.md @@ -73,6 +73,8 @@ Be sure to install sox with mp3 support! Conversion will not happen (assuming yo #### Schema +Schema for media + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `content_length` | Length, in bytes, of the file | `integer` | | `false` @@ -90,6 +92,8 @@ Key | Description | Type | Default | Required `tts.voice` | The voice to be used during the conversion | `string('female/en-US', 'male/en-US', 'female/en-CA', 'female/en-AU', 'female/en-GB', 'male/en-GB', 'female/es-US', 'male/es-US', 'female/us-US', 'female/zh-CN', 'male/zh-CN', 'female/zh-HK', 'female/zh-TW', 'female/ja-JP', 'male/ja-JP', 'female/ko-KR', 'male/ko-KR', 'female/da-DK', 'female/de-DE', 'male/de-DE', 'female/ca-ES', 'female/es-ES', 'male/es-ES', 'female/fi-FI', 'female/fr-CA', 'male/fr-CA', 'female/fr-FR', 'male/fr-FR', 'female/it-IT', 'male/it-IT', 'female/nb-NO', 'female/nl-NL', 'female/pl-PL', 'female/pt-BR', 'female/pt-PT', 'male/pt-PT', 'female/ru-RU', 'male/ru-RU', 'female/sv-SE', 'female/hu-HU', 'female/cs-CZ', 'female/tr-TR', 'male/tr-TR', 'male/ru-RU/Vladimir', 'female/ru-RU/Julia', 'female/ru-RU/Anna', 'female/ru-RU/Viktoria', 'male/ru-RU/Alexander', 'female/ru-RU/Maria', 'female/ru-RU/Lidia')` | `female/en-US` | `false` + + #### Get a listing of media files > GET /v2/accounts/{ACCOUNT_ID}/media @@ -191,6 +195,8 @@ A response: #### Remove metadata +Optional Parameter: "hard_delete": true - will perform a hard delete of the document (default is soft delete) + > DELETE /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID} ```shell diff --git a/applications/crossbar/doc/menus.md b/applications/crossbar/doc/menus.md index c7e82e17e56..a5923527e39 100644 --- a/applications/crossbar/doc/menus.md +++ b/applications/crossbar/doc/menus.md @@ -1,17 +1,49 @@ - +### Menus Menus, IVRs, what ever you call them, allow you to create branches in the callflow based on the caller's input. +#### About Menus + The DTMF entered is matched against the "children" keys and that branch is taken. Additionally, you can branch based on a timeout (no DTMF entered) by using "timeout" in the "children" keys": - {"module":"menu" - ,"data":{...} - ,"children":{ - "1":{"module":"...",...} - ,"2":{"module":"...",...} - "timeout":{"module":"...",...} - } +```json +{ + "module":"menu", + "data": {...}, + "children": { + "1": {"module":"...",...}, + "2": {"module":"...",...}, + "timeout": {"module":"...",...} + } +} +```` If no "timeout" child is specified, the menu is retried (until retries are exceeded). + +#### Schema + +Schema for a menus + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`allow_record_from_offnet` | Determines if the record pin can be used by external calls | `boolean` | `false` | `false` +`hunt` | Determines if the callers can dial internal extensions directly | `boolean` | `true` | `false` +`hunt_allow` | A regular expression that an extension the caller dialed must match to be allowed to continue | `string(1..256)` | | `false` +`hunt_deny` | A regular expression that if matched does not allow the caller to dial directly | `string(1..256)` | | `false` +`interdigit_timeout` | The amount of time (in milliseconds) to wait for the caller to press the next digit after pressing a digit | `integer` | | `false` +`max_extension_length` | The maximum number of digits that can be collected | `integer` | `4` | `false` +`media` | The media (prompt) parameters | `object` | `{}` | `false` +`media.exit_media` | When a call is transferred from the menu after all retries exhausted this media can be played (prior to transfer if enabled) | `boolean, string(3..64)` | | `false` +`media.greeting` | The ID of a media object that should be used as the menu greeting | `string(3..64)` | | `false` +`media.invalid_media` | When the collected digits dont result in a match or hunt this media can be played | `boolean, string(3..64)` | | `false` +`media.transfer_media` | When a call is transferred from the menu, either after all retries exhausted or a successful hunt, this media can be played | `boolean, string(3..64)` | | `false` +`name` | A friendly name for the menu | `string(1..128)` | | `true` +`record_pin` | The pin number used to record the menu prompt | `string(3..6)` | | `false` +`retries` | The number of times a menu should be played until a valid entry is collected | `integer` | `3` | `false` +`timeout` | The amount of time (in milliseconds) to wait for the caller to beging entering digits | `integer` | | `false` + + + + diff --git a/applications/crossbar/doc/metaflows.md b/applications/crossbar/doc/metaflows.md index 8a8a8175838..a58e78208d4 100644 --- a/applications/crossbar/doc/metaflows.md +++ b/applications/crossbar/doc/metaflows.md @@ -1,7 +1,231 @@ +### Metaflows +#### About Metaflows Metaflows allow functionality to be executed on an in-progress call, triggered by DTMFs from the caller/callee. For instance, a callee could setup a metaflow on their user doc such that when they receive a call, they can press "*9" to initiate a recording of the call. +#### Schema + +Actions applied to a call outside of the normal callflow, initiated by the caller(s) + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`binding_digit` | What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#')` | `*` | `false` +`digit_timeout` | How long to wait between DTMF presses before processing the collected sequence (milliseconds) | `integer` | | `false` +`listen_on` | Which leg(s) of the call to listen for DTMF | `string('both', 'self', 'peer')` | | `false` +`numbers` | A list of static numbers with their flows | `object` | | `false` +`numbers./^[0-9]+$/` | | [#/definitions/metaflow](#metaflow) | | `false` +`patterns` | A list of patterns with their flows | `object` | | `false` +`patterns./.+/` | | [#/definitions/metaflow](#metaflow) | | `false` + + +##### metaflow + +A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- + +##### metaflow.audio_level + +audio_level metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string` | | `true` +`data.level` | | `string` | | `false` +`data.mode` | | `string` | | `false` +`module` | | `string('audio_level')` | | `true` + +##### metaflow.break + +break metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('break')` | | `true` + +##### metaflow.callflow + +callflow metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.id` | | `string` | | `true` +`module` | | `string('callflow')` | | `true` + +##### metaflow.hangup + +hangup metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('hangup')` | | `true` + +##### metaflow.hold + +hold metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.moh_aleg` | | `string` | | `false` +`data.moh_bleg` | | `string` | | `false` +`data.unhold_key` | | `string` | `1` | `false` +`module` | | `string('hold')` | | `true` + +##### metaflow.hold_control + +hold_control metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`data.action` | | `string('hold', 'unhold', 'toggle')` | `toggle` | `false` +`module` | | `string('hold_control')` | | `true` + +##### metaflow.intercept + +intercept metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.auto_answer` | | `boolean` | `false` | `false` +`data.target_id` | | `string` | | `true` +`data.target_type` | | `string('device', 'user', 'number')` | | `true` +`data.unbridged_only` | | `boolean` | `true` | `false` +`module` | | `string('intercept')` | | `true` + +##### metaflow.move + +move metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.auto_answer` | | `boolean` | `false` | `false` +`data.device_id` | | `string` | | `false` +`data.owner_id` | | `string` | | `false` +`module` | | `string('move')` | | `true` + +##### metaflow.play + +play metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.id` | | `string` | | `true` +`data.leg` | | `string('both', 'self', 'peer')` | `both` | `false` +`module` | | `string('play')` | | `true` + +##### metaflow.record_call + +record_call metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string('start', 'stop', 'toggle')` | `toggle` | `true` +`data.format` | | `string` | | `false` +`data.media_name` | | `string` | | `false` +`module` | | `string('record_call')` | | `true` + +##### metaflow.resume + +resume metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('resume')` | | `true` + +##### metaflow.say + +say metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.language` | | `string` | | `false` +`data.method` | | `string` | | `false` +`data.text` | | `string` | | `true` +`data.type` | | `string` | | `false` +`module` | | `string('say')` | | `true` + +##### metaflow.sound_touch + +sound_touch metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string('start', 'stop')` | | `true` +`data.adjust_in_octaves` | | `integer` | | `false` +`data.adjust_in_semitones` | | `integer` | | `false` +`data.hook_dtmf` | | `boolean` | `false` | `false` +`data.pitch` | | `integer` | | `false` +`data.rate` | | `integer` | | `false` +`data.sending_leg` | | `boolean` | `false` | `false` +`data.tempo` | | `integer` | | `false` +`module` | | `string('sound_touch')` | | `true` + +##### metaflow.transfer + +transfer metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.Transfer-Type` | | `string` | `attended` | `false` +`data.captures` | | `string` | | `false` +`data.target` | | `string` | | `false` +`module` | | `string('transfer')` | | `true` + +##### metaflow.tts + +tts metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.engine` | | `string` | `flite` | `false` +`data.language` | | `string` | | `false` +`data.leg` | | `string` | `self` | `false` +`data.terminators` | | `string` | | `false` +`data.text` | | `string` | | `true` +`data.voice` | | `string` | `female` | `false` +`module` | | `string('tts')` | | `true` + +##### metaflow_children + +A metaflow child nodes + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- + + + #### Metaflow structure Any document can be amended with a "metaflows" top-level key; however, at the moment Kazoo only processes a "metaflows" key on: the account doc, a callflow doc, a user doc, or a device doc. diff --git a/applications/crossbar/doc/notifications.md b/applications/crossbar/doc/notifications.md index af96344acb1..3934f6c7082 100644 --- a/applications/crossbar/doc/notifications.md +++ b/applications/crossbar/doc/notifications.md @@ -39,6 +39,8 @@ The `macros` object is a per-template, system-defined set of macros you can use #### Schema +Notifications templates + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `bcc` | Bcc email field | `object` | | `false` @@ -62,6 +64,8 @@ Key | Description | Type | Default | Required `to.type` | | `string('original', 'specified', 'admins')` | | `false` + + #### Crossbar Using Crossbar to modify notifications is very simple: diff --git a/applications/crossbar/doc/phone_numbers.md b/applications/crossbar/doc/phone_numbers.md index 00a687b1b93..c079a68bb31 100644 --- a/applications/crossbar/doc/phone_numbers.md +++ b/applications/crossbar/doc/phone_numbers.md @@ -6,6 +6,8 @@ The 2600hz mobile API set: manage numbers. #### Schema +Schema for a number + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `cnam` | | `object` | | `false` @@ -13,7 +15,7 @@ Key | Description | Type | Default | Required `cnam.inbound_lookup` | | `boolean` | | `false` `e911` | | `object` | | `false` `e911.activated_time` | The time stamp e911 was provisioned | `string` | | `false` -`e911.caller_name` | The name that will show to emergency services | `string` | | `false` +`e911.caller_name` | The name that will show to emergency services | `string(3..)` | | `false` `e911.extended_address` | The suit/floor/apt. address where the number is in service | `string` | | `false` `e911.latitude` | The e911 provisioning system calculated service address latitude | `string` | | `false` `e911.legacy_data` | Legacy E911 information | `object` | | `false` @@ -46,6 +48,8 @@ Key | Description | Type | Default | Required `porting.service_provider` | The name of the losing carrier | `string` | | `false` + + #### Search for numbers Looks for numbers using the carrier module set up for your account. @@ -493,12 +497,14 @@ A non-conforming `{PHONE_NUMBER}`: `"+141510010+15"`. #### Check availability of phone numbers -This API check if the numbers are still available for purchase. +> POST /v2/accounts/{ACCOUNT_ID}/phone_numbers/check -- IN <- List of numbers -- OUT -> JSON; Key = Number, Value = status +This API checks if the numbers are still available for purchase. -> POST /v2/accounts/{ACCOUNT_ID}/phone_numbers/check +A status of `"error"` may be due to: + +* Number not being handled by carrier `knm_other` +* `phonebook` being unresponsive ```shell curl -v -X POST \ @@ -509,8 +515,6 @@ curl -v -X POST \ ##### Response -###### Success - ```json { "auth_token": "{AUTH_TOKEN}", @@ -524,25 +528,6 @@ curl -v -X POST \ } ``` -###### Failure - -When server encounters an error `"data": {}` is returned. - -It may be due to: - -* Number not being handled by carrier `other` -* `phonebook` being unresponsive - -```json -{ - "auth_token": "{AUTH_TOKEN}", - "data": {}, - "request_id": "{REQUEST_ID}", - "revision": "{REVISION}", - "status": "success" -} -``` - #### Get locality information for a collection of numbers diff --git a/applications/crossbar/doc/port_requests.md b/applications/crossbar/doc/port_requests.md index 4ea73c7df09..d936ae9df63 100644 --- a/applications/crossbar/doc/port_requests.md +++ b/applications/crossbar/doc/port_requests.md @@ -10,6 +10,32 @@ A port request can be in one of five **states**: * `completed`: The port request has been finished, and numbers are activated. * `rejected`: The port request has been cancelled, or something has gone wrong during the port process. The port can be resubmitted. +#### Schema + +Schema for a port request + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`bill` | Billing information of the losing carrier | `object` | | `false` +`bill.extended_address` | The suite/floor/apt of the billing address the losing carrier has on record | `string` | | `false` +`bill.locality` | The locality (city) of the billing address the losing carrier has on record | `string` | | `false` +`bill.name` | The losing carrier billing/account name | `string` | | `false` +`bill.postal_code` | The zip/postal code of the billing address the losing carrier has on record | `string` | | `false` +`bill.region` | The region (state) of the billing address the losing carrier has on record | `string` | | `false` +`bill.street_address` | The address of the billing address the losing carrier has on record | `string` | | `false` +`comments` | The history of comments made on a port request | `array(object)` | | `false` +`name` | A friendly name for the port request | `string(1..128)` | | `true` +`notifications` | Status notifications | `object` | | `false` +`notifications.email` | Inbound Email Notifications | `object` | | `false` +`notifications.email.send_to` | A list or string of email recipent(s) | `string, array(string)` | | `false` +`numbers` | The numbers to port in | `object` | | `true` +`numbers./\+?[0-9]+/` | | `object` | | `false` +`port_state` | What state the port request is currently in | `string('unconfirmed', 'pending', 'submitted', 'scheduled', 'completed', 'rejected', 'canceled')` | `unconfirmed` | `false` +`scheduled_date` | Requested scheduled date in gregorain timestamp | `integer` | | `false` +`transfer_date` | Requested transfer date in gregorain timestamp | `integer` | | `false` + + + #### List port requests diff --git a/applications/crossbar/doc/queues.md b/applications/crossbar/doc/queues.md index 079d64d7c57..2c254b83d74 100644 --- a/applications/crossbar/doc/queues.md +++ b/applications/crossbar/doc/queues.md @@ -6,6 +6,8 @@ When you have more callers than agents to handle those calls, you can create a c #### Schema +Call Queues - FIFO call queues for serializing callers connecting to agents + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `agent_ring_timeout` | In seconds, how long to ring an agent before progressing to the next agent available | `integer` | `15` | `false` @@ -25,6 +27,8 @@ Key | Description | Type | Default | Required `strategy` | The queue strategy for connecting agents to callers | `string('round_robin', 'most_idle')` | `round_robin` | `false` + + #### List queues > GET /v2/accounts/{ACCOUNT_ID}/queues diff --git a/applications/crossbar/doc/rates.md b/applications/crossbar/doc/rates.md index e8faa2f7b2e..16c1cfb2498 100644 --- a/applications/crossbar/doc/rates.md +++ b/applications/crossbar/doc/rates.md @@ -4,6 +4,8 @@ #### Schema +Defines a rate for a given prefix + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `carrier` | Friendly name for the carrier providing this rate | `string` | | `false` @@ -26,6 +28,8 @@ Key | Description | Type | Default | Required `weight` | Ordering against other rates, 1 being most preferred, 100 being least preferred | `integer` | | `false` + + #### Fetch available rates > GET /v2/rates diff --git a/applications/crossbar/doc/ref/access_lists.md b/applications/crossbar/doc/ref/access_lists.md index 461d0bf056e..179fbc650fc 100644 --- a/applications/crossbar/doc/ref/access_lists.md +++ b/applications/crossbar/doc/ref/access_lists.md @@ -4,6 +4,8 @@ #### Schema +Access Control List entries for device or account + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `cidrs` | Classless Inter-Domain Routing IP notation for use on the access lists | `array(string)` | | `true` @@ -12,15 +14,7 @@ Key | Description | Type | Default | Required `user_agent` | RegExp to match valid user agent strings | `string` | | `false` -#### Remove -> DELETE /v2/accounts/{ACCOUNT_ID}/access_lists - -```shell -curl -v -X DELETE \ - -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/access_lists -``` #### Fetch @@ -42,3 +36,13 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/access_lists ``` +#### Remove + +> DELETE /v2/accounts/{ACCOUNT_ID}/access_lists + +```shell +curl -v -X DELETE \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/access_lists +``` + diff --git a/applications/crossbar/doc/ref/accounts.md b/applications/crossbar/doc/ref/accounts.md index 2ad83dee743..599e4ab0b2b 100644 --- a/applications/crossbar/doc/ref/accounts.md +++ b/applications/crossbar/doc/ref/accounts.md @@ -4,6 +4,8 @@ #### Schema +Accounts represent tenants or customers on the system. Each account represents an individual dataset or sandbox that only one tenant can access. The data set is architecturally independent from other tenants. + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `call_restriction` | Account level call restrictions for each available number classification | `object` | `{}` | `false` @@ -33,12 +35,16 @@ Key | Description | Type | Default | Required ##### call_waiting +Parameters for server-side call waiting + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `enabled` | Determines if server side call waiting is enabled/disabled | `boolean` | | `false` ##### caller_id +Defines caller ID settings based on the type of call being made + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `emergency` | The caller ID used when a resource is flagged as 'emergency' | `object` | | `false` @@ -59,11 +65,15 @@ Key | Description | Type | Default | Required ##### metaflow +A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- ##### metaflow.audio_level +audio_level metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -75,6 +85,8 @@ Key | Description | Type | Default | Required ##### metaflow.break +break metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -83,6 +95,8 @@ Key | Description | Type | Default | Required ##### metaflow.callflow +callflow metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -92,6 +106,8 @@ Key | Description | Type | Default | Required ##### metaflow.hangup +hangup metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -100,6 +116,8 @@ Key | Description | Type | Default | Required ##### metaflow.hold +hold metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -111,6 +129,8 @@ Key | Description | Type | Default | Required ##### metaflow.hold_control +hold_control metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -120,6 +140,8 @@ Key | Description | Type | Default | Required ##### metaflow.intercept +intercept metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -132,6 +154,8 @@ Key | Description | Type | Default | Required ##### metaflow.move +move metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -143,6 +167,8 @@ Key | Description | Type | Default | Required ##### metaflow.play +play metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -153,6 +179,8 @@ Key | Description | Type | Default | Required ##### metaflow.record_call +record_call metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -164,6 +192,8 @@ Key | Description | Type | Default | Required ##### metaflow.resume +resume metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -172,6 +202,8 @@ Key | Description | Type | Default | Required ##### metaflow.say +say metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -184,6 +216,8 @@ Key | Description | Type | Default | Required ##### metaflow.sound_touch +sound_touch metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -200,6 +234,8 @@ Key | Description | Type | Default | Required ##### metaflow.transfer +transfer metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -211,6 +247,8 @@ Key | Description | Type | Default | Required ##### metaflow.tts +tts metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -225,11 +263,15 @@ Key | Description | Type | Default | Required ##### metaflow_children +A metaflow child nodes + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- ##### metaflows +Actions applied to a call outside of the normal callflow, initiated by the caller(s) + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `binding_digit` | What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#')` | `*` | `false` @@ -242,6 +284,8 @@ Key | Description | Type | Default | Required ##### notify.callback +Schema for a callback options + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `attempts` | How many attempts without answer will system do | `integer` | | `false` @@ -251,6 +295,8 @@ Key | Description | Type | Default | Required `schedule` | Schedules interval between callbacks | `array(integer)` | | `false` `timeout_s` | How long will system wait for answer to callback | `integer` | | `false` + + #### Create > PUT /v2/accounts @@ -261,52 +307,52 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID} +> GET /v2/accounts/{ACCOUNT_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID} ``` -#### Fetch +#### Create -> GET /v2/accounts/{ACCOUNT_ID} +> PUT /v2/accounts/{ACCOUNT_ID} ```shell -curl -v -X GET \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID} ``` -#### Patch +#### Change -> PATCH /v2/accounts/{ACCOUNT_ID} +> POST /v2/accounts/{ACCOUNT_ID} ```shell -curl -v -X PATCH \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID} ``` -#### Change +#### Patch -> POST /v2/accounts/{ACCOUNT_ID} +> PATCH /v2/accounts/{ACCOUNT_ID} ```shell -curl -v -X POST \ +curl -v -X PATCH \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID} ``` -#### Create +#### Remove -> PUT /v2/accounts/{ACCOUNT_ID} +> DELETE /v2/accounts/{ACCOUNT_ID} ```shell -curl -v -X PUT \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID} ``` @@ -371,22 +417,22 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/children ``` -#### Remove +#### Create -> DELETE /v2/accounts/{ACCOUNT_ID}/reseller +> PUT /v2/accounts/{ACCOUNT_ID}/reseller ```shell -curl -v -X DELETE \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/reseller ``` -#### Create +#### Remove -> PUT /v2/accounts/{ACCOUNT_ID}/reseller +> DELETE /v2/accounts/{ACCOUNT_ID}/reseller ```shell -curl -v -X PUT \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/reseller ``` diff --git a/applications/crossbar/doc/ref/acls.md b/applications/crossbar/doc/ref/acls.md index e2b862fd6f1..621aa6d8301 100644 --- a/applications/crossbar/doc/ref/acls.md +++ b/applications/crossbar/doc/ref/acls.md @@ -4,6 +4,8 @@ #### Schema +Access Control List entries + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `cidr` | Classless Inter-Domain Routing IP notation for use on the ACL | `string` | | `true` @@ -12,6 +14,8 @@ Key | Description | Type | Default | Required `type` | Allow or deny this CIDR | `string('allow', 'deny')` | `allow` | `true` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/acls diff --git a/applications/crossbar/doc/ref/alerts.md b/applications/crossbar/doc/ref/alerts.md index 55aff35987d..a8ad0b13240 100644 --- a/applications/crossbar/doc/ref/alerts.md +++ b/applications/crossbar/doc/ref/alerts.md @@ -26,22 +26,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/alerts ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/alerts/{ALERT_ID} +> GET /v2/accounts/{ACCOUNT_ID}/alerts/{ALERT_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/alerts/{ALERT_ID} ``` -#### Fetch +#### Remove -> GET /v2/accounts/{ACCOUNT_ID}/alerts/{ALERT_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/alerts/{ALERT_ID} ```shell -curl -v -X GET \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/alerts/{ALERT_ID} ``` diff --git a/applications/crossbar/doc/ref/allotments.md b/applications/crossbar/doc/ref/allotments.md index 32b74e5212a..f7771c605ed 100644 --- a/applications/crossbar/doc/ref/allotments.md +++ b/applications/crossbar/doc/ref/allotments.md @@ -8,6 +8,8 @@ Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/allotments diff --git a/applications/crossbar/doc/ref/api_auth.md b/applications/crossbar/doc/ref/api_auth.md index 4cf864440a7..cc0b85892c0 100644 --- a/applications/crossbar/doc/ref/api_auth.md +++ b/applications/crossbar/doc/ref/api_auth.md @@ -4,11 +4,15 @@ #### Schema +Provides an auth-token via an Account API key + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `api_key` | The Accounts API key | `string(64)` | | `true` + + #### Create > PUT /v2/api_auth diff --git a/applications/crossbar/doc/ref/apps_store.md b/applications/crossbar/doc/ref/apps_store.md index e79ca45b948..f264cd2849e 100644 --- a/applications/crossbar/doc/ref/apps_store.md +++ b/applications/crossbar/doc/ref/apps_store.md @@ -16,22 +16,22 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID} +> GET /v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID} ``` -#### Fetch +#### Create -> GET /v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID} +> PUT /v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID} ```shell -curl -v -X GET \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID} ``` @@ -46,12 +46,12 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID} ``` -#### Create +#### Remove -> PUT /v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID} ```shell -curl -v -X PUT \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/apps_store/{APP_ID} ``` diff --git a/applications/crossbar/doc/ref/auth.md b/applications/crossbar/doc/ref/auth.md index 916644ef69e..d7718d86049 100644 --- a/applications/crossbar/doc/ref/auth.md +++ b/applications/crossbar/doc/ref/auth.md @@ -6,32 +6,32 @@ -#### Remove +#### Fetch -> DELETE /v2/auth/links +> GET /v2/auth/links ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/auth/links ``` -#### Fetch +#### Change -> GET /v2/auth/links +> POST /v2/auth/links ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/auth/links ``` -#### Change +#### Remove -> POST /v2/auth/links +> DELETE /v2/auth/links ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/auth/links ``` diff --git a/applications/crossbar/doc/ref/blacklists.md b/applications/crossbar/doc/ref/blacklists.md index 0155f28a952..04e04b018e5 100644 --- a/applications/crossbar/doc/ref/blacklists.md +++ b/applications/crossbar/doc/ref/blacklists.md @@ -4,12 +4,16 @@ #### Schema +Schema for a blacklists + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `name` | A friendly name for the temporal rule set | `string(1..128)` | | `true` `numbers` | Map of caller id number to block | `object` | `{}` | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/blacklists @@ -30,22 +34,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID} +> GET /v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID} +> POST /v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID} ``` @@ -60,12 +64,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/blacklists/{BLACKLIST_ID} ``` diff --git a/applications/crossbar/doc/ref/braintree.md b/applications/crossbar/doc/ref/braintree.md index 2753499fe2b..013c245c400 100644 --- a/applications/crossbar/doc/ref/braintree.md +++ b/applications/crossbar/doc/ref/braintree.md @@ -116,16 +116,6 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/transactions/{TRANSACTION_ID} ``` -#### Remove - -> DELETE /v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID} - -```shell -curl -v -X DELETE \ - -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID} -``` - #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID} @@ -148,12 +138,12 @@ curl -v -X POST \ #### Remove -> DELETE /v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID} ```shell curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID} + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/addresses/{ADDRESS_ID} ``` #### Fetch @@ -176,3 +166,13 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID} ``` +#### Remove + +> DELETE /v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID} + +```shell +curl -v -X DELETE \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/braintree/cards/{CARD_ID} +``` + diff --git a/applications/crossbar/doc/ref/bulk.md b/applications/crossbar/doc/ref/bulk.md index 35f5aab3c54..ec0455b2673 100644 --- a/applications/crossbar/doc/ref/bulk.md +++ b/applications/crossbar/doc/ref/bulk.md @@ -6,32 +6,32 @@ -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/bulk +> GET /v2/accounts/{ACCOUNT_ID}/bulk ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/bulk ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/bulk +> POST /v2/accounts/{ACCOUNT_ID}/bulk ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/bulk ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/bulk +> DELETE /v2/accounts/{ACCOUNT_ID}/bulk ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/bulk ``` diff --git a/applications/crossbar/doc/ref/callflows.md b/applications/crossbar/doc/ref/callflows.md index bdab4e46e2c..a927f0d29f4 100644 --- a/applications/crossbar/doc/ref/callflows.md +++ b/applications/crossbar/doc/ref/callflows.md @@ -4,15 +4,14 @@ #### Schema +Call flows describe steps to take in order to process a phone call. They are trees of information related to a phone call such as "answer, play file, record file" etc. that are logically grouped together and ordered. + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `featurecode` | When the callflow is used as a featurecode this object tracks the intended match of the pattern and name of the feature | `object` | | `false` `featurecode.name` | | `string(1..128)` | | `false` `featurecode.number` | | `string(1..30)` | | `false` -`flow` | A callflow node defines a module to execute, data to provide to that module, and one or more children to branch to | `object` | | `true` -`flow.children` | Children callflows | `object` | `{}` | `false` -`flow.data` | The data/arguments of the callflow module | `object` | `{}` | `true` -`flow.module` | The name of the callflow module to excute at this node | `string(1..64)` | | `true` +`flow` | A callflow node defines a module to execute, data to provide to that module, and zero or more children to branch to | [#/definitions/callflows.action](#callflowsaction) | | `false` `metaflow` | Actions applied to a call outside of the normal callflow, initiated by the caller(s) | [#/definitions/metaflows](#metaflows) | | `false` `numbers` | A list of static numbers that the callflow should execute for | `array(string(1..36))` | `[]` | `false` `numbers.[]` | | `string` | | `false` @@ -20,13 +19,28 @@ Key | Description | Type | Default | Required `patterns.[]` | | `string` | | `false` +##### callflows.action + +Call flows describe steps to take in order to process a phone call. They are trees of information related to a phone call such as "answer, play file, record file" etc. that are logically grouped together and ordered. + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | Children callflows | `object` | | `false` +`children./.+/` | | [#/definitions/callflows.action](#callflowsaction) | | `false` +`data` | The data/arguments of the callflow module | `object` | | `true` +`module` | The name of the callflow module to excute at this node | `string(1..64)` | | `true` + ##### metaflow +A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- ##### metaflow.audio_level +audio_level metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -38,6 +52,8 @@ Key | Description | Type | Default | Required ##### metaflow.break +break metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -46,6 +62,8 @@ Key | Description | Type | Default | Required ##### metaflow.callflow +callflow metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -55,6 +73,8 @@ Key | Description | Type | Default | Required ##### metaflow.hangup +hangup metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -63,6 +83,8 @@ Key | Description | Type | Default | Required ##### metaflow.hold +hold metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -74,6 +96,8 @@ Key | Description | Type | Default | Required ##### metaflow.hold_control +hold_control metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -83,6 +107,8 @@ Key | Description | Type | Default | Required ##### metaflow.intercept +intercept metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -95,6 +121,8 @@ Key | Description | Type | Default | Required ##### metaflow.move +move metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -106,6 +134,8 @@ Key | Description | Type | Default | Required ##### metaflow.play +play metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -116,6 +146,8 @@ Key | Description | Type | Default | Required ##### metaflow.record_call +record_call metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -127,6 +159,8 @@ Key | Description | Type | Default | Required ##### metaflow.resume +resume metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -135,6 +169,8 @@ Key | Description | Type | Default | Required ##### metaflow.say +say metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -147,6 +183,8 @@ Key | Description | Type | Default | Required ##### metaflow.sound_touch +sound_touch metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -163,6 +201,8 @@ Key | Description | Type | Default | Required ##### metaflow.transfer +transfer metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -174,6 +214,8 @@ Key | Description | Type | Default | Required ##### metaflow.tts +tts metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -188,11 +230,15 @@ Key | Description | Type | Default | Required ##### metaflow_children +A metaflow child nodes + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- ##### metaflows +Actions applied to a call outside of the normal callflow, initiated by the caller(s) + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `binding_digit` | What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#')` | `*` | `false` @@ -203,6 +249,8 @@ Key | Description | Type | Default | Required `patterns` | A list of patterns with their flows | `object` | | `false` `patterns./.+/` | | [#/definitions/metaflow](#metaflow) | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/callflows @@ -223,22 +271,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID} +> GET /v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID} +> POST /v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID} ``` @@ -253,12 +301,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/callflows/{CALLFLOW_ID} ``` diff --git a/applications/crossbar/doc/ref/cccps.md b/applications/crossbar/doc/ref/cccps.md index 4e9848cffdd..27ec1920e03 100644 --- a/applications/crossbar/doc/ref/cccps.md +++ b/applications/crossbar/doc/ref/cccps.md @@ -4,6 +4,8 @@ #### Schema +Calling cards callback platform user's info + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `active` | Show's whether CID/PIN active | `boolean` | `false` | `false` @@ -14,6 +16,8 @@ Key | Description | Type | Default | Required `user_id` | The ID of the user object that 'owns' cid/pin | `string(32)` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/cccps @@ -34,22 +38,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cccps ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID} +> GET /v2/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID} ``` -#### Fetch +#### Create -> GET /v2/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID} +> PUT /v2/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID} ```shell -curl -v -X GET \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID} ``` @@ -64,12 +68,12 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID} ``` -#### Create +#### Remove -> PUT /v2/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID} ```shell -curl -v -X PUT \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cccps/{CCCP_ID} ``` diff --git a/applications/crossbar/doc/ref/cdrs.md b/applications/crossbar/doc/ref/cdrs.md index 0f5679ad8b2..e669af0be7b 100644 --- a/applications/crossbar/doc/ref/cdrs.md +++ b/applications/crossbar/doc/ref/cdrs.md @@ -4,6 +4,8 @@ #### Schema +Call Detail Records + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `app_name` | The Kazoo application that issued the CDR | `string` | | `false` @@ -50,6 +52,8 @@ Key | Description | Type | Default | Required `user_agent` | User agent header from SIP packet | `string` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/cdrs @@ -72,6 +76,16 @@ curl -v -X GET \ #### Fetch +> GET /v2/accounts/{ACCOUNT_ID}/cdrs/summary + +```shell +curl -v -X GET \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/cdrs/summary +``` + +#### Fetch + > GET /v2/accounts/{ACCOUNT_ID}/cdrs/interaction ```shell diff --git a/applications/crossbar/doc/ref/channels.md b/applications/crossbar/doc/ref/channels.md index 9c627d1f151..5c70c85446f 100644 --- a/applications/crossbar/doc/ref/channels.md +++ b/applications/crossbar/doc/ref/channels.md @@ -26,22 +26,22 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID} ``` -#### Change +#### Create -> POST /v2/accounts/{ACCOUNT_ID}/channels/{UUID} +> PUT /v2/accounts/{ACCOUNT_ID}/channels/{UUID} ```shell -curl -v -X POST \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID} ``` -#### Create +#### Change -> PUT /v2/accounts/{ACCOUNT_ID}/channels/{UUID} +> POST /v2/accounts/{ACCOUNT_ID}/channels/{UUID} ```shell -curl -v -X PUT \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/channels/{UUID} ``` diff --git a/applications/crossbar/doc/ref/clicktocall.md b/applications/crossbar/doc/ref/clicktocall.md index 70ef5038702..c33509fbe91 100644 --- a/applications/crossbar/doc/ref/clicktocall.md +++ b/applications/crossbar/doc/ref/clicktocall.md @@ -4,6 +4,8 @@ #### Schema +Click-to-call allows you to create URLs that can be POSTed to with a phone number or SIP URI and create a phone call from the provided contact information to a destination you have pre-determined. + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `auth_required` | Determines if this click to call requires valid auth-tokens when invoked | `boolean` | `true` | `false` @@ -18,6 +20,8 @@ Key | Description | Type | Default | Required `whitelist.[]` | | `string` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/clicktocall @@ -38,22 +42,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID} +> GET /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID} +> POST /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID} ``` @@ -68,12 +72,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/clicktocall/{C2C_ID} ``` diff --git a/applications/crossbar/doc/ref/comments.md b/applications/crossbar/doc/ref/comments.md index 2510214622b..3f8dc1750f3 100644 --- a/applications/crossbar/doc/ref/comments.md +++ b/applications/crossbar/doc/ref/comments.md @@ -6,16 +6,6 @@ -#### Remove - -> DELETE /v2/accounts/{ACCOUNT_ID}/comments - -```shell -curl -v -X DELETE \ - -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments -``` - #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/comments @@ -38,12 +28,12 @@ curl -v -X PUT \ #### Remove -> DELETE /v2/accounts/{ACCOUNT_ID}/comments/{COMMENT_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/comments ```shell curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments/{COMMENT_ID} + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments ``` #### Fetch @@ -66,3 +56,13 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments/{COMMENT_ID} ``` +#### Remove + +> DELETE /v2/accounts/{ACCOUNT_ID}/comments/{COMMENT_ID} + +```shell +curl -v -X DELETE \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/comments/{COMMENT_ID} +``` + diff --git a/applications/crossbar/doc/ref/conferences.md b/applications/crossbar/doc/ref/conferences.md index d8391fbee47..9e994ac43c8 100644 --- a/applications/crossbar/doc/ref/conferences.md +++ b/applications/crossbar/doc/ref/conferences.md @@ -4,6 +4,8 @@ #### Schema +Schema for conferences + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `conference_numbers` | Defines conference numbers that can be used by members or moderators | `array(string)` | `[]` | `false` @@ -29,6 +31,8 @@ Key | Description | Type | Default | Required `profile` | The XML profile name used to configure the conference | `string` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/conferences @@ -49,52 +53,52 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} +> GET /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} ``` -#### Fetch +#### Create -> GET /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} +> PUT /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} ```shell -curl -v -X GET \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} ``` -#### Patch +#### Change -> PATCH /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} +> POST /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} ```shell -curl -v -X PATCH \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} ``` -#### Change +#### Patch -> POST /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} +> PATCH /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} ```shell -curl -v -X POST \ +curl -v -X PATCH \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} ``` -#### Create +#### Remove -> PUT /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} ```shell -curl -v -X PUT \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/conferences/{CONFERENCE_ID} ``` diff --git a/applications/crossbar/doc/ref/configs.md b/applications/crossbar/doc/ref/configs.md index eb50233400c..7cb9aab0b7a 100644 --- a/applications/crossbar/doc/ref/configs.md +++ b/applications/crossbar/doc/ref/configs.md @@ -6,52 +6,52 @@ -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} +> GET /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} ``` -#### Fetch +#### Create -> GET /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} +> PUT /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} ```shell -curl -v -X GET \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} ``` -#### Patch +#### Change -> PATCH /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} +> POST /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} ```shell -curl -v -X PATCH \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} ``` -#### Change +#### Patch -> POST /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} +> PATCH /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} ```shell -curl -v -X POST \ +curl -v -X PATCH \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} ``` -#### Create +#### Remove -> PUT /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} ```shell -curl -v -X PUT \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/configs/{CONFIG_ID} ``` diff --git a/applications/crossbar/doc/ref/connectivity.md b/applications/crossbar/doc/ref/connectivity.md index 25a0e1a736b..1d4117dd553 100644 --- a/applications/crossbar/doc/ref/connectivity.md +++ b/applications/crossbar/doc/ref/connectivity.md @@ -4,6 +4,8 @@ #### Schema +Trunkstore configuration document - this is old stuff; do not recommend building off this if possible + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `account` | Information that applies to the account as a whole | `object` | | `false` @@ -38,6 +40,8 @@ Key | Description | Type | Default | Required `servers.[].options` | | `object` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/connectivity @@ -58,22 +62,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID} +> GET /v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID} +> POST /v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID} ``` @@ -88,12 +92,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/connectivity/{CONNECTIVITY_ID} ``` diff --git a/applications/crossbar/doc/ref/devices.md b/applications/crossbar/doc/ref/devices.md index ae9d35c7506..6cceab04479 100644 --- a/applications/crossbar/doc/ref/devices.md +++ b/applications/crossbar/doc/ref/devices.md @@ -4,6 +4,8 @@ #### Schema +A device be it a SIP phone or landline number + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `call_forward` | The device call forward parameters | `object` | | `false` @@ -79,12 +81,16 @@ Key | Description | Type | Default | Required ##### call_waiting +Parameters for server-side call waiting + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `enabled` | Determines if server side call waiting is enabled/disabled | `boolean` | | `false` ##### caller_id +Defines caller ID settings based on the type of call being made + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `emergency` | The caller ID used when a resource is flagged as 'emergency' | `object` | | `false` @@ -105,11 +111,15 @@ Key | Description | Type | Default | Required ##### metaflow +A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- ##### metaflow.audio_level +audio_level metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -121,6 +131,8 @@ Key | Description | Type | Default | Required ##### metaflow.break +break metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -129,6 +141,8 @@ Key | Description | Type | Default | Required ##### metaflow.callflow +callflow metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -138,6 +152,8 @@ Key | Description | Type | Default | Required ##### metaflow.hangup +hangup metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -146,6 +162,8 @@ Key | Description | Type | Default | Required ##### metaflow.hold +hold metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -157,6 +175,8 @@ Key | Description | Type | Default | Required ##### metaflow.hold_control +hold_control metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -166,6 +186,8 @@ Key | Description | Type | Default | Required ##### metaflow.intercept +intercept metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -178,6 +200,8 @@ Key | Description | Type | Default | Required ##### metaflow.move +move metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -189,6 +213,8 @@ Key | Description | Type | Default | Required ##### metaflow.play +play metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -199,6 +225,8 @@ Key | Description | Type | Default | Required ##### metaflow.record_call +record_call metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -210,6 +238,8 @@ Key | Description | Type | Default | Required ##### metaflow.resume +resume metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -218,6 +248,8 @@ Key | Description | Type | Default | Required ##### metaflow.say +say metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -230,6 +262,8 @@ Key | Description | Type | Default | Required ##### metaflow.sound_touch +sound_touch metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -246,6 +280,8 @@ Key | Description | Type | Default | Required ##### metaflow.transfer +transfer metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -257,6 +293,8 @@ Key | Description | Type | Default | Required ##### metaflow.tts +tts metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -271,11 +309,15 @@ Key | Description | Type | Default | Required ##### metaflow_children +A metaflow child nodes + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- ##### metaflows +Actions applied to a call outside of the normal callflow, initiated by the caller(s) + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `binding_digit` | What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#')` | `*` | `false` @@ -286,6 +328,8 @@ Key | Description | Type | Default | Required `patterns` | A list of patterns with their flows | `object` | | `false` `patterns./.+/` | | [#/definitions/metaflow](#metaflow) | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/devices @@ -306,22 +350,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID} +> GET /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID} +> POST /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID} ``` @@ -336,12 +380,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID} ``` diff --git a/applications/crossbar/doc/ref/dialplans.md b/applications/crossbar/doc/ref/dialplans.md index 6ebce0f86ee..29f3dd188b5 100644 --- a/applications/crossbar/doc/ref/dialplans.md +++ b/applications/crossbar/doc/ref/dialplans.md @@ -9,6 +9,8 @@ Key | Description | Type | Default | Required `system` | List of system dial plans | `array()` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/dialplans diff --git a/applications/crossbar/doc/ref/directories.md b/applications/crossbar/doc/ref/directories.md index 6168f8b5f72..f0a6598a3c7 100644 --- a/applications/crossbar/doc/ref/directories.md +++ b/applications/crossbar/doc/ref/directories.md @@ -4,6 +4,8 @@ #### Schema +Allow a caller to search for a user/device by name instead of extension/DID + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `confirm_match` | When one match is found, require caller to confirm the match before connecting | `boolean` | `true` | `false` @@ -15,6 +17,8 @@ Key | Description | Type | Default | Required `users.[]` | | `string` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/directories @@ -35,22 +39,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID} +> GET /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID} +> POST /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID} ``` @@ -65,12 +69,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/directories/{DIRECTORY_ID} ``` diff --git a/applications/crossbar/doc/ref/faxboxes.md b/applications/crossbar/doc/ref/faxboxes.md index 81bba4f5a5b..612db604ce3 100644 --- a/applications/crossbar/doc/ref/faxboxes.md +++ b/applications/crossbar/doc/ref/faxboxes.md @@ -26,22 +26,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID} +> GET /v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID} +> POST /v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID} ``` @@ -56,12 +56,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxboxes/{FAXBOX_ID} ``` diff --git a/applications/crossbar/doc/ref/faxes.md b/applications/crossbar/doc/ref/faxes.md index 3ee64919603..fde60d9bf1a 100644 --- a/applications/crossbar/doc/ref/faxes.md +++ b/applications/crossbar/doc/ref/faxes.md @@ -4,6 +4,8 @@ #### Schema +Faxes API allows you to update and access fax jobs for both sending and receiving + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `attempts` | The number of attempts made, this will be set by the system and reset automaticly on put/post | `integer` | `0` | `false` @@ -35,6 +37,8 @@ Key | Description | Type | Default | Required `tx_result.time_elapsed` | The amount of time from submition to completion | `integer` | `0` | `false` + + #### Create > PUT /v2/accounts/{ACCOUNT_ID}/faxes @@ -115,16 +119,6 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outgoing/{FAX_JOB_ID} ``` -#### Remove - -> DELETE /v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID} - -```shell -curl -v -X DELETE \ - -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID} -``` - #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID} @@ -147,12 +141,12 @@ curl -v -X PUT \ #### Remove -> DELETE /v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID} ```shell curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID} + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID} ``` #### Fetch @@ -175,34 +169,34 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID} ``` -#### Fetch +#### Remove -> GET /v2/accounts/{ACCOUNT_ID}/faxes/incoming/{FAX_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID} ```shell -curl -v -X GET \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/incoming/{FAX_ID} + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID} ``` #### Fetch -> GET /v2/accounts/{ACCOUNT_ID}/faxes/smtplog/{ATTEMPT_ID} +> GET /v2/accounts/{ACCOUNT_ID}/faxes/incoming/{FAX_ID} ```shell curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/smtplog/{ATTEMPT_ID} + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/incoming/{FAX_ID} ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}/attachment +> GET /v2/accounts/{ACCOUNT_ID}/faxes/smtplog/{ATTEMPT_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}/attachment + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/smtplog/{ATTEMPT_ID} ``` #### Fetch @@ -217,12 +211,12 @@ curl -v -X GET \ #### Remove -> DELETE /v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}/attachment +> DELETE /v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}/attachment ```shell curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}/attachment + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/outbox/{FAX_ID}/attachment ``` #### Fetch @@ -235,3 +229,13 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}/attachment ``` +#### Remove + +> DELETE /v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}/attachment + +```shell +curl -v -X DELETE \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/faxes/inbox/{FAX_ID}/attachment +``` + diff --git a/applications/crossbar/doc/ref/global_provisioner_templates.md b/applications/crossbar/doc/ref/global_provisioner_templates.md index 8d4ee9518af..1b67ec0e842 100644 --- a/applications/crossbar/doc/ref/global_provisioner_templates.md +++ b/applications/crossbar/doc/ref/global_provisioner_templates.md @@ -26,16 +26,6 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates ``` -#### Remove - -> DELETE /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID} - -```shell -curl -v -X DELETE \ - -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID} -``` - #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID} @@ -58,12 +48,12 @@ curl -v -X POST \ #### Remove -> DELETE /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image +> DELETE /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID} ```shell curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID} ``` #### Fetch @@ -86,3 +76,13 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image ``` +#### Remove + +> DELETE /v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image + +```shell +curl -v -X DELETE \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/global_provisioner_templates/{TEMPLATE_ID}/image +``` + diff --git a/applications/crossbar/doc/ref/groups.md b/applications/crossbar/doc/ref/groups.md index cf4fdde5da2..4064d919cb3 100644 --- a/applications/crossbar/doc/ref/groups.md +++ b/applications/crossbar/doc/ref/groups.md @@ -4,6 +4,8 @@ #### Schema +Validator for the group + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `endpoints` | Endpoints included into group | `object` | `{}` | `true` @@ -12,6 +14,8 @@ Key | Description | Type | Default | Required `name` | A friendly name for the group | `string(1..128)` | | `true` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/groups @@ -32,22 +36,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID} +> GET /v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID} +> POST /v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID} ``` @@ -62,12 +66,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/groups/{GROUP_ID} ``` diff --git a/applications/crossbar/doc/ref/ips.md b/applications/crossbar/doc/ref/ips.md index 4de8cd6625e..7a14af9d278 100644 --- a/applications/crossbar/doc/ref/ips.md +++ b/applications/crossbar/doc/ref/ips.md @@ -4,12 +4,16 @@ #### Schema +IP addresses assigned to the account + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `ips` | List of IP addresses | `array(string)` | | `false` `ips.[]` | | `string` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/ips @@ -30,32 +34,32 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ips ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/ips/{IP_ADDRESS} +> GET /v2/accounts/{ACCOUNT_ID}/ips/{IP_ADDRESS} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ips/{IP_ADDRESS} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/ips/{IP_ADDRESS} +> POST /v2/accounts/{ACCOUNT_ID}/ips/{IP_ADDRESS} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ips/{IP_ADDRESS} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/ips/{IP_ADDRESS} +> DELETE /v2/accounts/{ACCOUNT_ID}/ips/{IP_ADDRESS} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ips/{IP_ADDRESS} ``` diff --git a/applications/crossbar/doc/ref/killio.md b/applications/crossbar/doc/ref/killio.md index bf14dd31ee8..9ea257c81ed 100644 --- a/applications/crossbar/doc/ref/killio.md +++ b/applications/crossbar/doc/ref/killio.md @@ -6,22 +6,22 @@ -#### Change +#### Create -> POST /v2/accounts/{ACCOUNT_ID}/killio/call +> PUT /v2/accounts/{ACCOUNT_ID}/killio/call ```shell -curl -v -X POST \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/killio/call ``` -#### Create +#### Change -> PUT /v2/accounts/{ACCOUNT_ID}/killio/call +> POST /v2/accounts/{ACCOUNT_ID}/killio/call ```shell -curl -v -X PUT \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/killio/call ``` diff --git a/applications/crossbar/doc/ref/ledgers.md b/applications/crossbar/doc/ref/ledgers.md index cf5abe650d8..92d0e39b781 100644 --- a/applications/crossbar/doc/ref/ledgers.md +++ b/applications/crossbar/doc/ref/ledgers.md @@ -4,6 +4,8 @@ #### Schema +ledgers document + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `account` | Account info | `object` | | `false` @@ -24,6 +26,8 @@ Key | Description | Type | Default | Required `usage.unit` | Usage unit | `string` | | `true` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/ledgers diff --git a/applications/crossbar/doc/ref/limits.md b/applications/crossbar/doc/ref/limits.md index 92109b208c2..dd10d41fc0a 100644 --- a/applications/crossbar/doc/ref/limits.md +++ b/applications/crossbar/doc/ref/limits.md @@ -4,9 +4,11 @@ #### Schema +Limit an account's ability to place concurrent calls using flat rate trunks + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- -`allow_prepay` | Determines if the account would like to allow per-minute calls if they have credit | `boolean` | `true` | `false` +`allow_prepay` | Determines if the account would like to allow per-minute calls if they have no available credit | `boolean` | `true` | `false` `burst_trunks` | The number of two-way, flat-rate trunks used only if no other trunks are available | `integer` | | `false` `calls` | A hard limit for the total number calls | `integer` | | `false` `inbound_trunks` | The number of inbound, flat-rate trunks | `integer` | | `false` @@ -15,6 +17,8 @@ Key | Description | Type | Default | Required `twoway_trunks` | The number of two-way, flat-rate trunks | `integer` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/limits diff --git a/applications/crossbar/doc/ref/lists.md b/applications/crossbar/doc/ref/lists.md index a813cef044e..1c3c64e668e 100644 --- a/applications/crossbar/doc/ref/lists.md +++ b/applications/crossbar/doc/ref/lists.md @@ -4,6 +4,8 @@ #### Schema +Schema for a match list + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `description` | A friendly list description | `string(1..128)` | | `false` @@ -11,6 +13,8 @@ Key | Description | Type | Default | Required `org` | Full legal name of the organization | `string` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/lists @@ -31,16 +35,6 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists ``` -#### Remove - -> DELETE /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID} - -```shell -curl -v -X DELETE \ - -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID} -``` - #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID} @@ -51,34 +45,34 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID} ``` -#### Patch +#### Change -> PATCH /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID} +> POST /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID} ```shell -curl -v -X PATCH \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID} ``` -#### Change +#### Patch -> POST /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID} +> PATCH /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID} ```shell -curl -v -X POST \ +curl -v -X PATCH \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID} ``` #### Remove -> DELETE /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries +> DELETE /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID} ```shell curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID} ``` #### Fetch @@ -103,12 +97,12 @@ curl -v -X PUT \ #### Remove -> DELETE /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries ```shell curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID} + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries ``` #### Fetch @@ -121,6 +115,16 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID} ``` +#### Change + +> POST /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID} + +```shell +curl -v -X POST \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID} +``` + #### Patch > PATCH /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID} @@ -131,12 +135,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/lists/{LIST_ID}/entries/{LIST_ENTRY_ID} ``` diff --git a/applications/crossbar/doc/ref/local_provisioner_templates.md b/applications/crossbar/doc/ref/local_provisioner_templates.md index 5c1e0786617..a42c4e20cc6 100644 --- a/applications/crossbar/doc/ref/local_provisioner_templates.md +++ b/applications/crossbar/doc/ref/local_provisioner_templates.md @@ -26,16 +26,6 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates ``` -#### Remove - -> DELETE /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID} - -```shell -curl -v -X DELETE \ - -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID} -``` - #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID} @@ -58,12 +48,12 @@ curl -v -X POST \ #### Remove -> DELETE /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image +> DELETE /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID} ```shell curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID} ``` #### Fetch @@ -86,3 +76,13 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image ``` +#### Remove + +> DELETE /v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image + +```shell +curl -v -X DELETE \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/local_provisioner_templates/{TEMPLATE_ID}/image +``` + diff --git a/applications/crossbar/doc/ref/media.md b/applications/crossbar/doc/ref/media.md index 9ff0e4d8d12..14bc6c68870 100644 --- a/applications/crossbar/doc/ref/media.md +++ b/applications/crossbar/doc/ref/media.md @@ -4,6 +4,8 @@ #### Schema +Schema for media + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `content_length` | Length, in bytes, of the file | `integer` | | `false` @@ -21,6 +23,8 @@ Key | Description | Type | Default | Required `tts.voice` | The voice to be used during the conversion | `string('female/en-US', 'male/en-US', 'female/en-CA', 'female/en-AU', 'female/en-GB', 'male/en-GB', 'female/es-US', 'male/es-US', 'female/us-US', 'female/zh-CN', 'male/zh-CN', 'female/zh-HK', 'female/zh-TW', 'female/ja-JP', 'male/ja-JP', 'female/ko-KR', 'male/ko-KR', 'female/da-DK', 'female/de-DE', 'male/de-DE', 'female/ca-ES', 'female/es-ES', 'male/es-ES', 'female/fi-FI', 'female/fr-CA', 'male/fr-CA', 'female/fr-FR', 'male/fr-FR', 'female/it-IT', 'male/it-IT', 'female/nb-NO', 'female/nl-NL', 'female/pl-PL', 'female/pt-BR', 'female/pt-PT', 'male/pt-PT', 'female/ru-RU', 'male/ru-RU', 'female/sv-SE', 'female/hu-HU', 'female/cs-CZ', 'female/tr-TR', 'male/tr-TR', 'male/ru-RU/Vladimir', 'female/ru-RU/Julia', 'female/ru-RU/Anna', 'female/ru-RU/Viktoria', 'male/ru-RU/Alexander', 'female/ru-RU/Maria', 'female/ru-RU/Lidia')` | `female/en-US` | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/media @@ -41,32 +45,32 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID} +> GET /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID} +> POST /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/media/{MEDIA_ID} ``` diff --git a/applications/crossbar/doc/ref/menus.md b/applications/crossbar/doc/ref/menus.md index 5aaf441eb8f..55dde7145b6 100644 --- a/applications/crossbar/doc/ref/menus.md +++ b/applications/crossbar/doc/ref/menus.md @@ -4,6 +4,8 @@ #### Schema +Schema for a menus + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `allow_record_from_offnet` | Determines if the record pin can be used by external calls | `boolean` | `false` | `false` @@ -23,6 +25,8 @@ Key | Description | Type | Default | Required `timeout` | The amount of time (in milliseconds) to wait for the caller to beging entering digits | `integer` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/menus @@ -43,22 +47,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID} +> GET /v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID} +> POST /v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID} ``` @@ -73,12 +77,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/menus/{MENU_ID} ``` diff --git a/applications/crossbar/doc/ref/metaflows.md b/applications/crossbar/doc/ref/metaflows.md index 4138eef8fbc..c05ea8d1aa7 100644 --- a/applications/crossbar/doc/ref/metaflows.md +++ b/applications/crossbar/doc/ref/metaflows.md @@ -4,6 +4,8 @@ #### Schema +Actions applied to a call outside of the normal callflow, initiated by the caller(s) + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `binding_digit` | What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#')` | `*` | `false` @@ -17,11 +19,15 @@ Key | Description | Type | Default | Required ##### metaflow +A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- ##### metaflow.audio_level +audio_level metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -33,6 +39,8 @@ Key | Description | Type | Default | Required ##### metaflow.break +break metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -41,6 +49,8 @@ Key | Description | Type | Default | Required ##### metaflow.callflow +callflow metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -50,6 +60,8 @@ Key | Description | Type | Default | Required ##### metaflow.hangup +hangup metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -58,6 +70,8 @@ Key | Description | Type | Default | Required ##### metaflow.hold +hold metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -69,6 +83,8 @@ Key | Description | Type | Default | Required ##### metaflow.hold_control +hold_control metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -78,6 +94,8 @@ Key | Description | Type | Default | Required ##### metaflow.intercept +intercept metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -90,6 +108,8 @@ Key | Description | Type | Default | Required ##### metaflow.move +move metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -101,6 +121,8 @@ Key | Description | Type | Default | Required ##### metaflow.play +play metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -111,6 +133,8 @@ Key | Description | Type | Default | Required ##### metaflow.record_call +record_call metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -122,6 +146,8 @@ Key | Description | Type | Default | Required ##### metaflow.resume +resume metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -130,6 +156,8 @@ Key | Description | Type | Default | Required ##### metaflow.say +say metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -142,6 +170,8 @@ Key | Description | Type | Default | Required ##### metaflow.sound_touch +sound_touch metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -158,6 +188,8 @@ Key | Description | Type | Default | Required ##### metaflow.transfer +transfer metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -169,6 +201,8 @@ Key | Description | Type | Default | Required ##### metaflow.tts +tts metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -183,18 +217,12 @@ Key | Description | Type | Default | Required ##### metaflow_children +A metaflow child nodes + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- -#### Remove -> DELETE /v2/accounts/{ACCOUNT_ID}/metaflows - -```shell -curl -v -X DELETE \ - -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/metaflows -``` #### Fetch @@ -216,3 +244,13 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/metaflows ``` +#### Remove + +> DELETE /v2/accounts/{ACCOUNT_ID}/metaflows + +```shell +curl -v -X DELETE \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/metaflows +``` + diff --git a/applications/crossbar/doc/ref/notifications.md b/applications/crossbar/doc/ref/notifications.md index 220d6df8859..e58119fb0e4 100644 --- a/applications/crossbar/doc/ref/notifications.md +++ b/applications/crossbar/doc/ref/notifications.md @@ -4,6 +4,8 @@ #### Schema +Notifications templates + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `bcc` | Bcc email field | `object` | | `false` @@ -27,6 +29,8 @@ Key | Description | Type | Default | Required `to.type` | | `string('original', 'specified', 'admins')` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/notifications @@ -47,32 +51,32 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID} +> GET /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID} +> POST /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/notifications/{NOTIFICATION_ID} ``` diff --git a/applications/crossbar/doc/ref/phone_numbers.md b/applications/crossbar/doc/ref/phone_numbers.md index f581bda52b7..66c831f1cd9 100644 --- a/applications/crossbar/doc/ref/phone_numbers.md +++ b/applications/crossbar/doc/ref/phone_numbers.md @@ -4,6 +4,8 @@ #### Schema +Schema for a number + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `cnam` | | `object` | | `false` @@ -44,6 +46,8 @@ Key | Description | Type | Default | Required `porting.service_provider` | The name of the losing carrier | `string` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/phone_numbers @@ -54,22 +58,22 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER} +> GET /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER} ``` -#### Fetch +#### Create -> GET /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER} +> PUT /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER} ```shell -curl -v -X GET \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER} ``` @@ -84,12 +88,12 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER} ``` -#### Create +#### Remove -> PUT /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER} +> DELETE /v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER} ```shell -curl -v -X PUT \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/{PHONE_NUMBER} ``` @@ -124,12 +128,12 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/prefix ``` -#### Remove +#### Create -> DELETE /v2/accounts/{ACCOUNT_ID}/phone_numbers/collection +> PUT /v2/accounts/{ACCOUNT_ID}/phone_numbers/collection ```shell -curl -v -X DELETE \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection ``` @@ -144,12 +148,12 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection ``` -#### Create +#### Remove -> PUT /v2/accounts/{ACCOUNT_ID}/phone_numbers/collection +> DELETE /v2/accounts/{ACCOUNT_ID}/phone_numbers/collection ```shell -curl -v -X PUT \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/phone_numbers/collection ``` diff --git a/applications/crossbar/doc/ref/port_requests.md b/applications/crossbar/doc/ref/port_requests.md index 6e8ba544111..acb73bf3076 100644 --- a/applications/crossbar/doc/ref/port_requests.md +++ b/applications/crossbar/doc/ref/port_requests.md @@ -4,6 +4,8 @@ #### Schema +Schema for a port request + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `bill` | Billing information of the losing carrier | `object` | | `false` @@ -25,6 +27,8 @@ Key | Description | Type | Default | Required `transfer_date` | Requested transfer date in gregorain timestamp | `integer` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/port_requests @@ -45,32 +49,32 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID} +> GET /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID} +> POST /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID} ``` @@ -235,32 +239,32 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/submitted ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID} +> GET /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID} +> POST /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/port_requests/{PORT_REQUEST_ID}/attachments/{ATTACHMENT_ID} ``` diff --git a/applications/crossbar/doc/ref/queues.md b/applications/crossbar/doc/ref/queues.md index 6b74b454e13..fd3d50d472d 100644 --- a/applications/crossbar/doc/ref/queues.md +++ b/applications/crossbar/doc/ref/queues.md @@ -4,6 +4,8 @@ #### Schema +Call Queues - FIFO call queues for serializing callers connecting to agents + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `agent_ring_timeout` | In seconds, how long to ring an agent before progressing to the next agent available | `integer` | `15` | `false` @@ -23,6 +25,8 @@ Key | Description | Type | Default | Required `strategy` | The queue strategy for connecting agents to callers | `string('round_robin', 'most_idle')` | `round_robin` | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/queues @@ -43,22 +47,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID} +> GET /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID} +> POST /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID} ``` @@ -73,12 +77,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID} ``` @@ -113,32 +117,32 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/eavesdrop ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster +> GET /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster +> POST /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster +> DELETE /v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/queues/{QUEUE_ID}/roster ``` diff --git a/applications/crossbar/doc/ref/rate_limits.md b/applications/crossbar/doc/ref/rate_limits.md index 2d642754105..d290cdf7bf0 100644 --- a/applications/crossbar/doc/ref/rate_limits.md +++ b/applications/crossbar/doc/ref/rate_limits.md @@ -6,32 +6,32 @@ -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/rate_limits +> GET /v2/accounts/{ACCOUNT_ID}/rate_limits ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/rate_limits ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/rate_limits +> POST /v2/accounts/{ACCOUNT_ID}/rate_limits ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/rate_limits ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/rate_limits +> DELETE /v2/accounts/{ACCOUNT_ID}/rate_limits ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/rate_limits ``` diff --git a/applications/crossbar/doc/ref/rates.md b/applications/crossbar/doc/ref/rates.md index d0d82170981..e668d2d4ec3 100644 --- a/applications/crossbar/doc/ref/rates.md +++ b/applications/crossbar/doc/ref/rates.md @@ -4,6 +4,8 @@ #### Schema +Defines a rate for a given prefix + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `carrier` | Friendly name for the carrier providing this rate | `string` | | `false` @@ -26,6 +28,8 @@ Key | Description | Type | Default | Required `weight` | Ordering against other rates, 1 being most preferred, 100 being least preferred | `integer` | | `false` + + #### Fetch > GET /v2/rates @@ -36,42 +40,42 @@ curl -v -X GET \ http://{SERVER}:8000/v2/rates ``` -#### Change +#### Create -> POST /v2/rates +> PUT /v2/rates ```shell -curl -v -X POST \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/rates ``` -#### Create +#### Change -> PUT /v2/rates +> POST /v2/rates ```shell -curl -v -X PUT \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/rates ``` -#### Remove +#### Fetch -> DELETE /v2/rates/{RATE_ID} +> GET /v2/rates/{RATE_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/rates/{RATE_ID} ``` -#### Fetch +#### Change -> GET /v2/rates/{RATE_ID} +> POST /v2/rates/{RATE_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/rates/{RATE_ID} ``` @@ -86,12 +90,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/rates/{RATE_ID} ``` -#### Change +#### Remove -> POST /v2/rates/{RATE_ID} +> DELETE /v2/rates/{RATE_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/rates/{RATE_ID} ``` diff --git a/applications/crossbar/doc/ref/registrations.md b/applications/crossbar/doc/ref/registrations.md index f88acb78633..f1f820d3f47 100644 --- a/applications/crossbar/doc/ref/registrations.md +++ b/applications/crossbar/doc/ref/registrations.md @@ -6,22 +6,22 @@ -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/registrations +> GET /v2/accounts/{ACCOUNT_ID}/registrations ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/registrations ``` -#### Fetch +#### Remove -> GET /v2/accounts/{ACCOUNT_ID}/registrations +> DELETE /v2/accounts/{ACCOUNT_ID}/registrations ```shell -curl -v -X GET \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/registrations ``` diff --git a/applications/crossbar/doc/ref/resource_selectors.md b/applications/crossbar/doc/ref/resource_selectors.md index 8cf0a2c9800..1727c188e18 100644 --- a/applications/crossbar/doc/ref/resource_selectors.md +++ b/applications/crossbar/doc/ref/resource_selectors.md @@ -4,6 +4,8 @@ #### Schema +Schema for resource selector document + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `name` | Selector name | `string` | | `true` @@ -14,6 +16,8 @@ Key | Description | Type | Default | Required `value` | Extra selector data | `string` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/resource_selectors @@ -24,32 +28,32 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/resource_selectors/{UUID} +> GET /v2/accounts/{ACCOUNT_ID}/resource_selectors/{UUID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors/{UUID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/resource_selectors/{UUID} +> POST /v2/accounts/{ACCOUNT_ID}/resource_selectors/{UUID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors/{UUID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/resource_selectors/{UUID} +> DELETE /v2/accounts/{ACCOUNT_ID}/resource_selectors/{UUID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors/{UUID} ``` diff --git a/applications/crossbar/doc/ref/resource_templates.md b/applications/crossbar/doc/ref/resource_templates.md index 361a4798ef6..6e7d7e223c8 100644 --- a/applications/crossbar/doc/ref/resource_templates.md +++ b/applications/crossbar/doc/ref/resource_templates.md @@ -26,22 +26,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID} +> GET /v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID} +> POST /v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID} ``` @@ -56,12 +56,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resource_templates/{RESOURCE_TEMPLATE_ID} ``` diff --git a/applications/crossbar/doc/ref/resources.md b/applications/crossbar/doc/ref/resources.md index fad50a4744d..03905998ff0 100644 --- a/applications/crossbar/doc/ref/resources.md +++ b/applications/crossbar/doc/ref/resources.md @@ -4,6 +4,8 @@ #### Schema +Schema for resources + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `emergency` | Determines if the resource represents emergency services | `boolean` | `false` | `false` @@ -57,6 +59,8 @@ Key | Description | Type | Default | Required `weight_cost` | A value between 0 and 100 that determines the order of resources when multiple can be used | `integer` | `50` | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/resources @@ -77,32 +81,32 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID} +> GET /v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID} +> POST /v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/{RESOURCE_ID} ``` @@ -127,22 +131,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/jobs ``` -#### Change +#### Create -> POST /v2/accounts/{ACCOUNT_ID}/resources/collection +> PUT /v2/accounts/{ACCOUNT_ID}/resources/collection ```shell -curl -v -X POST \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/collection ``` -#### Create +#### Change -> PUT /v2/accounts/{ACCOUNT_ID}/resources/collection +> POST /v2/accounts/{ACCOUNT_ID}/resources/collection ```shell -curl -v -X PUT \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/resources/collection ``` diff --git a/applications/crossbar/doc/ref/service_plans.md b/applications/crossbar/doc/ref/service_plans.md index 9b879f405b0..355c4e49b63 100644 --- a/applications/crossbar/doc/ref/service_plans.md +++ b/applications/crossbar/doc/ref/service_plans.md @@ -4,6 +4,8 @@ #### Schema +Describes services offered to sub-accounts + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `bookkeepers` | | `object` | | `false` @@ -14,11 +16,15 @@ Key | Description | Type | Default | Required ##### bookkeepers +The bookkeeper modules provided by Kazoo + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `braintree` | | `object` | | `false` `local` | | `object` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/service_plans @@ -39,32 +45,32 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID} +> GET /v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID} +> POST /v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID} ``` diff --git a/applications/crossbar/doc/ref/shared_auth.md b/applications/crossbar/doc/ref/shared_auth.md index 3b5ca8d9f38..b370b20ab02 100644 --- a/applications/crossbar/doc/ref/shared_auth.md +++ b/applications/crossbar/doc/ref/shared_auth.md @@ -4,11 +4,15 @@ #### Schema +Provides a local auth-token via a shared auth-token + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `shared_auth` | The shared token | `string(64)` | | `true` + + #### Fetch > GET /v2/shared_auth diff --git a/applications/crossbar/doc/ref/skels.md b/applications/crossbar/doc/ref/skels.md index 23291440070..a7520917340 100644 --- a/applications/crossbar/doc/ref/skels.md +++ b/applications/crossbar/doc/ref/skels.md @@ -26,22 +26,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/skels/{THING} +> GET /v2/accounts/{ACCOUNT_ID}/skels/{THING} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels/{THING} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/skels/{THING} +> POST /v2/accounts/{ACCOUNT_ID}/skels/{THING} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels/{THING} ``` @@ -56,12 +56,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels/{THING} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/skels/{THING} +> DELETE /v2/accounts/{ACCOUNT_ID}/skels/{THING} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/skels/{THING} ``` diff --git a/applications/crossbar/doc/ref/sms.md b/applications/crossbar/doc/ref/sms.md index 83123ddb977..f36a93caa51 100644 --- a/applications/crossbar/doc/ref/sms.md +++ b/applications/crossbar/doc/ref/sms.md @@ -4,6 +4,8 @@ #### Schema +sms document + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `body` | text message | `string(1..700)` | | `true` @@ -12,6 +14,8 @@ Key | Description | Type | Default | Required `to` | callee-id-number | `string` | | `true` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/sms @@ -32,22 +36,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/sms ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/sms/{SMS_ID} +> GET /v2/accounts/{ACCOUNT_ID}/sms/{SMS_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/sms/{SMS_ID} ``` -#### Fetch +#### Remove -> GET /v2/accounts/{ACCOUNT_ID}/sms/{SMS_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/sms/{SMS_ID} ```shell -curl -v -X GET \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/sms/{SMS_ID} ``` diff --git a/applications/crossbar/doc/ref/storage.md b/applications/crossbar/doc/ref/storage.md index 3f2dae0af3a..ef2dcea3214 100644 --- a/applications/crossbar/doc/ref/storage.md +++ b/applications/crossbar/doc/ref/storage.md @@ -6,41 +6,50 @@ Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- -`attachments` | | [#/definitions/storage.attachments](#storageattachments) | | `false` -`connections` | | [#/definitions/storage.connections](#storageconnections) | | `false` -`plan` | | [#/definitions/storage.plan](#storageplan) | | `false` +`attachments` | Defines where and how to store attachments | [#/definitions/storage.attachments](#storageattachments) | | `false` +`connections` | Describes alternative connections to use (such as alternative CouchDB instances | [#/definitions/storage.connections](#storageconnections) | | `false` +`id` | ID of the storage document | `string` | | `false` +`plan` | Describes how to store documents depending on the database or document type | [#/definitions/storage.plan](#storageplan) | | `false` ##### storage.attachment.aws +schema for AWS attachment entry + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- -`handler` | | `string('s3')` | | `true` -`name` | | `string` | | `false` -`settings` | | `object` | | `true` -`settings.bucket` | | `string` | | `true` -`settings.host` | | `string` | | `false` -`settings.key` | | `string` | | `true` -`settings.path` | | `string` | | `false` -`settings.secret` | | `string` | | `true` +`handler` | What AWS service to use | `string('s3')` | | `true` +`name` | Friendly name for this configuration | `string` | | `false` +`settings` | AWS API settings | `object` | | `true` +`settings.bucket` | Bucket name to store data to | `string` | | `true` +`settings.host` | Region-specific hostname to use, if applicable | `string` | | `false` +`settings.key` | AWS Key to use | `string` | | `true` +`settings.path` | Custom path to use as a prefix when saving files | `string` | | `false` +`settings.secret` | AWS Secret to use | `string` | | `true` ##### storage.attachment.google_drive +schema for google drive attachment entry + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- -`handler` | | `string('google_drive')` | | `true` -`name` | | `string` | | `false` -`settings` | | `object` | | `true` -`settings.oauth_doc_id` | | `string` | | `true` -`settings.path` | | `string` | | `false` +`handler` | What handler module to use | `string('google_drive')` | | `true` +`name` | Friendly name for this configuration | `string` | | `false` +`settings` | Settings for the Google Drive account | `object` | | `true` +`settings.folder_id` | Folder ID in which to store the file, if any | `string` | | `false` +`settings.oauth_doc_id` | Doc ID in the system 'oauth' database | `string` | | `true` ##### storage.attachments +Keys are 32-character identifiers to be used in storage plans + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- ##### storage.connection.couchdb +schema for couchdb connection entry + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `driver` | | `string('kazoo_couch')` | | `true` @@ -63,6 +72,8 @@ Key | Description | Type | Default | Required ##### storage.plan +schema for storage plan + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `account` | | [#/definitions/storage.plan.database](#storageplan.database) | | `false` @@ -71,6 +82,8 @@ Key | Description | Type | Default | Required ##### storage.plan.database +schema for database storage plan + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `attachments` | | [#/definitions/storage.plan.database.attachment](#storageplan.database.attachment) | | `false` @@ -84,6 +97,8 @@ Key | Description | Type | Default | Required ##### storage.plan.database.attachment +schema for attachment ref type storage plan + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `handler` | | `string` | | `false` @@ -92,27 +107,31 @@ Key | Description | Type | Default | Required ##### storage.plan.database.document +schema for document type storage plan + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `attachments` | | [#/definitions/storage.plan.database.attachment](#storageplan.database.attachment) | | `false` `connection` | | `string` | | `false` -#### Remove -> DELETE /v2/accounts/{ACCOUNT_ID}/storage + +#### Fetch + +> GET /v2/accounts/{ACCOUNT_ID}/storage ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage ``` -#### Fetch +#### Create -> GET /v2/accounts/{ACCOUNT_ID}/storage +> PUT /v2/accounts/{ACCOUNT_ID}/storage ```shell -curl -v -X GET \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage ``` @@ -127,12 +146,22 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage ``` -#### Create +#### Patch -> PUT /v2/accounts/{ACCOUNT_ID}/storage +> PATCH /v2/accounts/{ACCOUNT_ID}/storage ```shell -curl -v -X PUT \ +curl -v -X PATCH \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage +``` + +#### Remove + +> DELETE /v2/accounts/{ACCOUNT_ID}/storage + +```shell +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage ``` @@ -157,32 +186,42 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} +> GET /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} +> POST /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} ``` -#### Change +#### Patch -> POST /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} +> PATCH /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} ```shell -curl -v -X POST \ +curl -v -X PATCH \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} +``` + +#### Remove + +> DELETE /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} + +```shell +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} ``` diff --git a/applications/crossbar/doc/ref/system_configs.md b/applications/crossbar/doc/ref/system_configs.md index 6ee98a7bc0e..e7d6c3483b8 100644 --- a/applications/crossbar/doc/ref/system_configs.md +++ b/applications/crossbar/doc/ref/system_configs.md @@ -16,16 +16,6 @@ curl -v -X GET \ http://{SERVER}:8000/v2/system_configs ``` -#### Remove - -> DELETE /v2/system_configs/{SYSTEM_CONFIG_ID} - -```shell -curl -v -X DELETE \ - -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/system_configs/{SYSTEM_CONFIG_ID} -``` - #### Fetch > GET /v2/system_configs/{SYSTEM_CONFIG_ID} @@ -36,34 +26,34 @@ curl -v -X GET \ http://{SERVER}:8000/v2/system_configs/{SYSTEM_CONFIG_ID} ``` -#### Change +#### Create -> POST /v2/system_configs/{SYSTEM_CONFIG_ID} +> PUT /v2/system_configs/{SYSTEM_CONFIG_ID} ```shell -curl -v -X POST \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/system_configs/{SYSTEM_CONFIG_ID} ``` -#### Create +#### Change -> PUT /v2/system_configs/{SYSTEM_CONFIG_ID} +> POST /v2/system_configs/{SYSTEM_CONFIG_ID} ```shell -curl -v -X PUT \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/system_configs/{SYSTEM_CONFIG_ID} ``` #### Remove -> DELETE /v2/system_configs/{SYSTEM_CONFIG_ID}/{NODE} +> DELETE /v2/system_configs/{SYSTEM_CONFIG_ID} ```shell curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/system_configs/{SYSTEM_CONFIG_ID}/{NODE} + http://{SERVER}:8000/v2/system_configs/{SYSTEM_CONFIG_ID} ``` #### Fetch @@ -86,3 +76,13 @@ curl -v -X POST \ http://{SERVER}:8000/v2/system_configs/{SYSTEM_CONFIG_ID}/{NODE} ``` +#### Remove + +> DELETE /v2/system_configs/{SYSTEM_CONFIG_ID}/{NODE} + +```shell +curl -v -X DELETE \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/system_configs/{SYSTEM_CONFIG_ID}/{NODE} +``` + diff --git a/applications/crossbar/doc/ref/tasks.md b/applications/crossbar/doc/ref/tasks.md index 7deb2bb77fd..ef72c178388 100644 --- a/applications/crossbar/doc/ref/tasks.md +++ b/applications/crossbar/doc/ref/tasks.md @@ -4,12 +4,16 @@ #### Schema +Input data to go through as part of a background task + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `file_name` | Human-readable name of a task's input file | `string` | | `false` `records` | List the rows of input data | `array(object)` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/tasks @@ -30,32 +34,32 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID} +> GET /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID} ``` -#### Fetch +#### Patch -> GET /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID} +> PATCH /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID} ```shell -curl -v -X GET \ +curl -v -X PATCH \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID} ``` -#### Patch +#### Remove -> PATCH /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID} ```shell -curl -v -X PATCH \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/tasks/{TASK_ID} ``` diff --git a/applications/crossbar/doc/ref/templates.md b/applications/crossbar/doc/ref/templates.md index ea7c0180280..8fc5c57b883 100644 --- a/applications/crossbar/doc/ref/templates.md +++ b/applications/crossbar/doc/ref/templates.md @@ -16,22 +16,22 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/templates ``` -#### Remove +#### Create -> DELETE /v2/accounts/{ACCOUNT_ID}/templates/{TEMPLATE_NAME} +> PUT /v2/accounts/{ACCOUNT_ID}/templates/{TEMPLATE_NAME} ```shell -curl -v -X DELETE \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/templates/{TEMPLATE_NAME} ``` -#### Create +#### Remove -> PUT /v2/accounts/{ACCOUNT_ID}/templates/{TEMPLATE_NAME} +> DELETE /v2/accounts/{ACCOUNT_ID}/templates/{TEMPLATE_NAME} ```shell -curl -v -X PUT \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/templates/{TEMPLATE_NAME} ``` diff --git a/applications/crossbar/doc/ref/temporal_rules.md b/applications/crossbar/doc/ref/temporal_rules.md index 714595521f7..ba3f50c731e 100644 --- a/applications/crossbar/doc/ref/temporal_rules.md +++ b/applications/crossbar/doc/ref/temporal_rules.md @@ -4,6 +4,8 @@ #### Schema +Schema for a temporal rules + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `cycle` | The recurrence cycle for this rule | `string('date', 'daily', 'weekly', 'monthly', 'yearly')` | | `true` @@ -18,6 +20,8 @@ Key | Description | Type | Default | Required `wdays.[]` | | `string` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/temporal_rules @@ -38,22 +42,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID} +> GET /v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID} +> POST /v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID} ``` @@ -68,12 +72,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules/{TEMPORAL_RULE_ID} ``` diff --git a/applications/crossbar/doc/ref/temporal_rules_sets.md b/applications/crossbar/doc/ref/temporal_rules_sets.md index 9034c0d5fdf..089e3c0ff83 100644 --- a/applications/crossbar/doc/ref/temporal_rules_sets.md +++ b/applications/crossbar/doc/ref/temporal_rules_sets.md @@ -4,6 +4,8 @@ #### Schema +Schema for a temporal rules sets + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `name` | A friendly name for the temporal rule set | `string(1..128)` | | `true` @@ -11,6 +13,8 @@ Key | Description | Type | Default | Required `temporal_rules.[]` | | `string` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets @@ -31,22 +35,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET} +> GET /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET} +> POST /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET} ``` @@ -61,12 +65,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET} +> DELETE /v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules_sets/{TEMPORAL_RULE_SET} ``` diff --git a/applications/crossbar/doc/ref/token_auth.md b/applications/crossbar/doc/ref/token_auth.md index bd70cde3977..f2c2f35e4b9 100644 --- a/applications/crossbar/doc/ref/token_auth.md +++ b/applications/crossbar/doc/ref/token_auth.md @@ -6,22 +6,22 @@ -#### Remove +#### Fetch -> DELETE /v2/token_auth +> GET /v2/token_auth ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/token_auth ``` -#### Fetch +#### Remove -> GET /v2/token_auth +> DELETE /v2/token_auth ```shell -curl -v -X GET \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/token_auth ``` diff --git a/applications/crossbar/doc/ref/token_restrictions.md b/applications/crossbar/doc/ref/token_restrictions.md index e489981112a..667b10a9602 100644 --- a/applications/crossbar/doc/ref/token_restrictions.md +++ b/applications/crossbar/doc/ref/token_restrictions.md @@ -4,6 +4,8 @@ #### Schema +Schema for token restrictions + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `restrictions` | | `object` | | `false` @@ -17,15 +19,7 @@ Key | Description | Type | Default | Required `restrictions./^\w+$/./^\w+$/./^\w+$/.[].rules./^[\w/#*]+$/.[]` | | `string` | | `false` -#### Remove -> DELETE /v2/accounts/{ACCOUNT_ID}/token_restrictions - -```shell -curl -v -X DELETE \ - -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/token_restrictions -``` #### Fetch @@ -47,3 +41,13 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/token_restrictions ``` +#### Remove + +> DELETE /v2/accounts/{ACCOUNT_ID}/token_restrictions + +```shell +curl -v -X DELETE \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/token_restrictions +``` + diff --git a/applications/crossbar/doc/ref/ubiquiti_auth.md b/applications/crossbar/doc/ref/ubiquiti_auth.md index 5c56be33efe..3884a56df83 100644 --- a/applications/crossbar/doc/ref/ubiquiti_auth.md +++ b/applications/crossbar/doc/ref/ubiquiti_auth.md @@ -4,12 +4,16 @@ #### Schema +Provides an auth-token via Ubiquiti's SSO + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `password` | Ubiquiti SSO Password | `string(1..64)` | | `true` `username` | Ubiquiti SSO Username | `string(1..64)` | | `true` + + #### Create > PUT /v2/ubiquiti_auth diff --git a/applications/crossbar/doc/ref/user_auth.md b/applications/crossbar/doc/ref/user_auth.md index 4e2638a8689..b3fda75ba90 100644 --- a/applications/crossbar/doc/ref/user_auth.md +++ b/applications/crossbar/doc/ref/user_auth.md @@ -4,6 +4,8 @@ #### Schema +Provides an auth-token via user credentials + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `account_name` | The account name of the user | `string(1..128)` | | `false` @@ -13,6 +15,8 @@ Key | Description | Type | Default | Required `phone_number` | A phone number assigned to the users account | `string(1..64)` | | `false` + + #### Create > PUT /v2/user_auth @@ -33,22 +37,22 @@ curl -v -X GET \ http://{SERVER}:8000/v2/user_auth/{AUTH_TOKEN} ``` -#### Change +#### Create -> POST /v2/user_auth/recovery +> PUT /v2/user_auth/recovery ```shell -curl -v -X POST \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/user_auth/recovery ``` -#### Create +#### Change -> PUT /v2/user_auth/recovery +> POST /v2/user_auth/recovery ```shell -curl -v -X PUT \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/user_auth/recovery ``` diff --git a/applications/crossbar/doc/ref/users.md b/applications/crossbar/doc/ref/users.md index 2cb08929d40..d017c9c4895 100644 --- a/applications/crossbar/doc/ref/users.md +++ b/applications/crossbar/doc/ref/users.md @@ -4,6 +4,8 @@ #### Schema +Schema for a user + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `call_forward` | The device call forward parameters | `object` | | `false` @@ -74,12 +76,16 @@ Key | Description | Type | Default | Required ##### call_waiting +Parameters for server-side call waiting + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `enabled` | Determines if server side call waiting is enabled/disabled | `boolean` | | `false` ##### caller_id +Defines caller ID settings based on the type of call being made + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `emergency` | The caller ID used when a resource is flagged as 'emergency' | `object` | | `false` @@ -100,11 +106,15 @@ Key | Description | Type | Default | Required ##### metaflow +A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- ##### metaflow.audio_level +audio_level metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -116,6 +126,8 @@ Key | Description | Type | Default | Required ##### metaflow.break +break metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -124,6 +136,8 @@ Key | Description | Type | Default | Required ##### metaflow.callflow +callflow metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -133,6 +147,8 @@ Key | Description | Type | Default | Required ##### metaflow.hangup +hangup metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -141,6 +157,8 @@ Key | Description | Type | Default | Required ##### metaflow.hold +hold metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -152,6 +170,8 @@ Key | Description | Type | Default | Required ##### metaflow.hold_control +hold_control metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -161,6 +181,8 @@ Key | Description | Type | Default | Required ##### metaflow.intercept +intercept metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -173,6 +195,8 @@ Key | Description | Type | Default | Required ##### metaflow.move +move metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -184,6 +208,8 @@ Key | Description | Type | Default | Required ##### metaflow.play +play metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -194,6 +220,8 @@ Key | Description | Type | Default | Required ##### metaflow.record_call +record_call metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -205,6 +233,8 @@ Key | Description | Type | Default | Required ##### metaflow.resume +resume metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -213,6 +243,8 @@ Key | Description | Type | Default | Required ##### metaflow.say +say metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -225,6 +257,8 @@ Key | Description | Type | Default | Required ##### metaflow.sound_touch +sound_touch metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -241,6 +275,8 @@ Key | Description | Type | Default | Required ##### metaflow.transfer +transfer metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -252,6 +288,8 @@ Key | Description | Type | Default | Required ##### metaflow.tts +tts metaflow schema + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` @@ -266,11 +304,15 @@ Key | Description | Type | Default | Required ##### metaflow_children +A metaflow child nodes + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- ##### metaflows +Actions applied to a call outside of the normal callflow, initiated by the caller(s) + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `binding_digit` | What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#')` | `*` | `false` @@ -283,6 +325,8 @@ Key | Description | Type | Default | Required ##### notify.callback +Schema for a callback options + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `attempts` | How many attempts without answer will system do | `integer` | | `false` @@ -294,6 +338,8 @@ Key | Description | Type | Default | Required ##### profile +Defines user extended properties + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `addresses` | To specify the components of the addresses | `array(object)` | | `false` @@ -308,6 +354,8 @@ Key | Description | Type | Default | Required `sort-string` | To specify the family name or given name text to be used for national-language-specific sorting of the FN and N types | `string` | | `false` `title` | To specify the position or job of the user | `string` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/users @@ -328,22 +376,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/users/{USER_ID} +> GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID} +> POST /v2/accounts/{ACCOUNT_ID}/users/{USER_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID} ``` @@ -358,12 +406,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/users/{USER_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/users/{USER_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID} ``` @@ -378,32 +426,32 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/vcard ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo +> GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo +> POST /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo +> DELETE /v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/photo ``` diff --git a/applications/crossbar/doc/ref/vmboxes.md b/applications/crossbar/doc/ref/vmboxes.md index b0190d4eeee..248f5a01539 100644 --- a/applications/crossbar/doc/ref/vmboxes.md +++ b/applications/crossbar/doc/ref/vmboxes.md @@ -4,6 +4,8 @@ #### Schema +Schema for a voicemail box + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `check_if_owner` | Determines if when the user calls their own voicemail they should be prompted to sign in | `boolean` | `true` | `false` @@ -29,6 +31,8 @@ Key | Description | Type | Default | Required ##### notify.callback +Schema for a callback options + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `attempts` | How many attempts without answer will system do | `integer` | | `false` @@ -38,6 +42,8 @@ Key | Description | Type | Default | Required `schedule` | Schedules interval between callbacks | `array(integer)` | | `false` `timeout_s` | How long will system wait for answer to callback | `integer` | | `false` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/vmboxes @@ -58,22 +64,22 @@ curl -v -X PUT \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID} +> GET /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID} +> POST /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID} ``` @@ -88,12 +94,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID} ``` @@ -108,16 +114,6 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/messages ``` -#### Remove - -> DELETE /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages - -```shell -curl -v -X DELETE \ - -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages -``` - #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages @@ -140,12 +136,12 @@ curl -v -X POST \ #### Remove -> DELETE /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/{VM_MSG_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages ```shell curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ - http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/{VM_MSG_ID} + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages ``` #### Fetch @@ -168,6 +164,16 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/{VM_MSG_ID} ``` +#### Remove + +> DELETE /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/{VM_MSG_ID} + +```shell +curl -v -X DELETE \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/{VM_MSG_ID} +``` + #### Change > POST /v2/accounts/{ACCOUNT_ID}/vmboxes/{VM_BOX_ID}/messages/raw diff --git a/applications/crossbar/doc/ref/webhooks.md b/applications/crossbar/doc/ref/webhooks.md index e7c85dd3d1f..0ece067d1ef 100644 --- a/applications/crossbar/doc/ref/webhooks.md +++ b/applications/crossbar/doc/ref/webhooks.md @@ -4,6 +4,8 @@ #### Schema +Web Hooks are subscriptions to allowed events that, when the event occurs, the event data is sent to the uri set in the Web Hook document. + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `custom_data` | These properties will be added to the event and will overwrite existing values. | `object` | | `false` @@ -16,6 +18,8 @@ Key | Description | Type | Default | Required `uri` | The 3rd party URI to call out to an event | `string` | | `true` + + #### Fetch > GET /v2/accounts/{ACCOUNT_ID}/webhooks @@ -26,42 +30,42 @@ curl -v -X GET \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks ``` -#### Patch +#### Create -> PATCH /v2/accounts/{ACCOUNT_ID}/webhooks +> PUT /v2/accounts/{ACCOUNT_ID}/webhooks ```shell -curl -v -X PATCH \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks ``` -#### Create +#### Patch -> PUT /v2/accounts/{ACCOUNT_ID}/webhooks +> PATCH /v2/accounts/{ACCOUNT_ID}/webhooks ```shell -curl -v -X PUT \ +curl -v -X PATCH \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks ``` -#### Remove +#### Fetch -> DELETE /v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID} +> GET /v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID} ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID} ``` -#### Fetch +#### Change -> GET /v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID} +> POST /v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID} ```shell -curl -v -X GET \ +curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID} ``` @@ -76,12 +80,12 @@ curl -v -X PATCH \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID} ``` -#### Change +#### Remove -> POST /v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID} +> DELETE /v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID} ```shell -curl -v -X POST \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/webhooks/{WEBHOOK_ID} ``` diff --git a/applications/crossbar/doc/ref/whitelabel.md b/applications/crossbar/doc/ref/whitelabel.md index 855989a4970..81baf91a11a 100644 --- a/applications/crossbar/doc/ref/whitelabel.md +++ b/applications/crossbar/doc/ref/whitelabel.md @@ -4,6 +4,8 @@ #### Schema +Whitelabel settings + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `company_name` | The company name to display to users | `string` | | `false` @@ -26,22 +28,24 @@ Key | Description | Type | Default | Required `twoway_trunks_price` | The price to show for twoway trunks, this is currently only for display purposes | `string` | | `false` -#### Remove -> DELETE /v2/accounts/{ACCOUNT_ID}/whitelabel + +#### Fetch + +> GET /v2/accounts/{ACCOUNT_ID}/whitelabel ```shell -curl -v -X DELETE \ +curl -v -X GET \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel ``` -#### Fetch +#### Create -> GET /v2/accounts/{ACCOUNT_ID}/whitelabel +> PUT /v2/accounts/{ACCOUNT_ID}/whitelabel ```shell -curl -v -X GET \ +curl -v -X PUT \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel ``` @@ -56,12 +60,12 @@ curl -v -X POST \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel ``` -#### Create +#### Remove -> PUT /v2/accounts/{ACCOUNT_ID}/whitelabel +> DELETE /v2/accounts/{ACCOUNT_ID}/whitelabel ```shell -curl -v -X PUT \ +curl -v -X DELETE \ -H "X-Auth-Token: {AUTH_TOKEN}" \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/whitelabel ``` diff --git a/applications/crossbar/doc/resource_selectors.md b/applications/crossbar/doc/resource_selectors.md index 34b50809902..9c8afe40cd7 100644 --- a/applications/crossbar/doc/resource_selectors.md +++ b/applications/crossbar/doc/resource_selectors.md @@ -4,6 +4,22 @@ Resource selectors is a new way to route Offnet-calls. Old way used regex rules and "flags" for select proper resources (gateways). With new "resource selectors" you have several small modules, which can be organaized in "chanin" (rules). +#### Schema + +Schema for resource selector document + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`name` | Selector name | `string` | | `true` +`resource` | Resource ID | `string` | | `true` +`selector` | Selector data | `string` | | `true` +`start_time` | Start time (gregorian seconds) | `integer` | | `false` +`stop_time` | Stop time (gregorian seconds) | `integer` | | `false` +`value` | Extra selector data | `string` | | `false` + + + + ## Rules Rules is array of JSON objects. Each object contain one item where key is name of the module, and value is another object, with parameters for that module. @@ -12,19 +28,20 @@ Example: ```json { - "filter_list": { - "value_a": "request:Flags", - "value_b": "resource:flags", - "action": "keep" - } + "filter_list": { + "value_a": "request:Flags", + "value_b": "resource:flags", + "action": "keep" + } } ``` + here we call modue `filter_list` (which filter resources comparing 2 lists). More info about modules and their parameters can be found [here](https://github.com/2600hz/kazoo/blob/master/applications/stepswitch/doc/resource_selectors.md). -Rules can be managed via http://{{IP}}:8000/v2/resource_selectors or http://{{IP}}:8000/v2/accounts/{{ACCOUNT_ID}}/resource_selectors/rules +Rules can be managed via `http://{IP}:8000/v2/resource_selectors` or `http://{IP}:8000/v2/accounts/{ACCOUNT_ID}/resource_selectors/rules` -Rules storred in `resource_selector_rules` file in Account database. System-wide rules is stored in Master-Account database, so http://{{IP}}:8000/v2/resource_selectors/rules is equal to http://{{IP}}:8000/v2/accounts/{{MASTER_ACCOUNT_ID}}/resource_selectors/rules +Rules storred in `resource_selector_rules` file in Account database. System-wide rules is stored in Master-Account database, so `http://{IP}:8000/v2/resource_selectors/rules` is equal to `http://{IP}:8000/v2/accounts/{MASTER_ACCOUNT_ID}/resource_selectors/rules` ### Show rules diff --git a/applications/crossbar/doc/resources.md b/applications/crossbar/doc/resources.md index 3d8923915c1..a8813801c6e 100644 --- a/applications/crossbar/doc/resources.md +++ b/applications/crossbar/doc/resources.md @@ -18,7 +18,9 @@ You can configure how frequently the system checks for failed jobs in `system_co You can configure how what is considered a 'stalled' job by defining how old the job is (the last time the job document was modified) relative to the current time. Configure in `system_config/crossbar.resources`, using the `job_recover_threshold_s` key (defaults to 1 hour). If a job is not completed, and hasn't been modified in over an hour, there's a good chance the job executor died. A new job executor will be started to pick up where the old one left off. -#### Resources Schema +#### Schema + +Schema for resources Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- @@ -43,7 +45,7 @@ Key | Description | Type | Default | Required `gateways.[].from_uri_realm` | When formating SIP From on outbound requests this can be used to override the realm | `string` | | `false` `gateways.[].invite_format` | The format of the DID needed by the underlying hardware/gateway | `string('route', 'username', 'e164', 'npan', '1npan')` | `route` | `false` `gateways.[].media` | The media parameters for the resource gateway | `object` | | `false` -`gateways.[].media.fax_option` | Support T.38 | `boolean` | | `false` +`gateways.[].media.fax_option` | Is T.38 Supported? | `boolean` | | `false` `gateways.[].password` | SIP authentication password | `string(0..32)` | | `false` `gateways.[].port` | This resource gateway port | `integer` | `5060` | `false` `gateways.[].prefix` | A string to prepend to the dialed number or capture group of the matching rule | `string(0..64)` | | `false` @@ -59,10 +61,10 @@ Key | Description | Type | Default | Required `grace_period` | The amount of time, in seconds, to wait before starting another resource | `integer` | `5` | `false` `media` | The default resouce media parameters applied if not present to all specified gateways | `object` | `{}` | `false` `media.audio` | The default audio media parameters | `object` | `{}` | `false` -`media.audio.codecs` | A list of default codecs to use | `array(string('OPUS', 'CELT@32000h', 'G7221@32000h', 'G7221@16000h', 'G722', 'speex@32000h', 'speex@16000h', 'PCMU', 'PCMA', 'G729', 'GSM', 'CELT@48000h', 'CELT@64000h', 'G722_16', 'G722_32', 'CELT_48', 'CELT_64', 'Speex', 'speex'))` | `PCMU` | `false` +`media.audio.codecs` | A list of default codecs to use | `array(string('OPUS', 'CELT@32000h', 'G7221@32000h', 'G7221@16000h', 'G722', 'speex@32000h', 'speex@16000h', 'PCMU', 'PCMA', 'G729', 'GSM', 'CELT@48000h', 'CELT@64000h', 'G722_16', 'G722_32', 'CELT_48', 'CELT_64', 'Speex', 'speex'))` | `["PCMU"]` | `false` `media.audio.codecs.[]` | | `string` | | `false` `media.bypass_media` | Default bypass media mode | `boolean` | | `false` -`media.fax_option` | Support T.38 | `boolean` | | `false` +`media.fax_option` | Is T.38 Supported? | `boolean` | | `false` `media.video` | The default video media parameters | `object` | `{}` | `false` `media.video.codecs` | A list of default codecs to use | `array(string('H261', 'H263', 'H264', 'VP8'))` | `[]` | `false` `media.video.codecs.[]` | | `string` | | `false` @@ -72,6 +74,9 @@ Key | Description | Type | Default | Required `rules.[]` | | `string` | | `false` `weight_cost` | A value between 0 and 100 that determines the order of resources when multiple can be used | `integer` | `50` | `false` + + + #### Fetch an account's resources > GET /v2/accounts/{ACCOUNT_ID}/resources diff --git a/applications/crossbar/doc/schemas.md b/applications/crossbar/doc/schemas.md index 9bcd2636ff1..72d0f0684ac 100644 --- a/applications/crossbar/doc/schemas.md +++ b/applications/crossbar/doc/schemas.md @@ -4,7 +4,8 @@ Kazoo uses [JSON Schemas](http://json-schema.org/) to validate incoming data from clients. -Any fields that aren't defined in the JSON schema will be stored, unmodified, along side the validated fields (assuming all is well). This excludes Kazoo-managed private fields (top-level keys prefixed with "_" and "pvt_"). +Any fields that aren't defined in the JSON schema will be stored, unmodified, along side the validated fields (assuming all is well). +This excludes Kazoo-managed private fields (top-level keys prefixed with `"_"` or `"pvt_"`). #### Schema diff --git a/applications/crossbar/doc/service_plans.md b/applications/crossbar/doc/service_plans.md index 974e1035a43..8302219d71f 100644 --- a/applications/crossbar/doc/service_plans.md +++ b/applications/crossbar/doc/service_plans.md @@ -6,6 +6,8 @@ Handle the service plans you can subscribe to. #### Schema +Describes services offered to sub-accounts + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `bookkeepers` | | `object` | | `false` @@ -14,6 +16,17 @@ Key | Description | Type | Default | Required `plan` | Outlines the service plan for various services | `object` | | `true` +##### bookkeepers + +The bookkeeper modules provided by Kazoo + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`braintree` | | `object` | | `false` +`local` | | `object` | | `false` + + + #### Retrieving your service plans. > GET /v2/accounts/{ACCOUNT_ID}/service_plans @@ -224,7 +237,7 @@ curl -v -X GET \ ```shell curl -v -X POST \ -H "X-Auth-Token: {AUTH_TOKEN}" \ - -d '{"data":{"id":"service_plan_id"}' \ + -d '{"data": {"id":"{PLAN_ID}"}}' \ http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/service_plans/{PLAN_ID} ``` diff --git a/applications/crossbar/doc/shared_auth.md b/applications/crossbar/doc/shared_auth.md new file mode 100644 index 00000000000..71345ee8f33 --- /dev/null +++ b/applications/crossbar/doc/shared_auth.md @@ -0,0 +1,24 @@ +### Shared_auth + +#### About Shared_auth + +#### Schema + +Provides a local auth-token via a shared auth-token + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`shared_auth` | The shared token | `string(64)` | | `true` + + + + +#### Detail a shared token + +> GET /v2/shared_auth + +```shell +curl -v -X GET \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/shared_auth +``` diff --git a/applications/crossbar/doc/sms.md b/applications/crossbar/doc/sms.md new file mode 100644 index 00000000000..66e4ba5ec85 --- /dev/null +++ b/applications/crossbar/doc/sms.md @@ -0,0 +1,27 @@ +### Sms + +#### About Sms + +#### Schema + +sms document + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`body` | text message | `string(1..700)` | | `true` +`from` | caller-id-number, taken from user if absent | `string` | | `false` +`scheduled` | The timestamp to start delivering the message | `integer` | | `false` +`to` | callee-id-number | `string` | | `true` + + + + +#### List items + +> GET /v2/accounts/{ACCOUNT_ID}/sms + +```shell +curl -v -X GET \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/sms +``` diff --git a/applications/crossbar/doc/storage.md b/applications/crossbar/doc/storage.md new file mode 100644 index 00000000000..121cdbc4b54 --- /dev/null +++ b/applications/crossbar/doc/storage.md @@ -0,0 +1,404 @@ +### Storage + +#### About Storage + +Storage plans allow an account to control where data related to their account is stored. This can be critical when compliance with regulations is required. + +A storage plan has three main components: + +1. `attachments`: configuration for where to store attachments (binary data typically, like voicemails or faxes) +2. `connections`: connection information to various third-party storage sites +3. `plan`: a description of the storage plan(s) for the account. + +#### Attachments + +Rather than storing binary data like voicemails, received faxes, and call recordings, in the Kazoo databases, it can be convenient to store them in third-party storage services like [Amazon S3](https://aws.amazon.com/s3), [Google Drive](https://www.google.com/drive/), etc. This keeps the binary data in a place that an account or user maintains control over. Kazoo keeps a pointer to the location when it needs to fetch the binary data (such as when you call into your voicemail box). + +The `attachments` object configures storage backends - for instance, if you want to store to S3, you'll add your AWS secret and key and your S3 bucket information here. + +#### Connections + +Connections can be used to point to an alternative CouchDB instance for storing the JSON documents or attachments (for instance: putting CDRs in their own cluster). These can be specified in the storage plans. + +#### Plans + +Plans determine what to do with certain classes of databases: + +1. `account`: where to store account data +2. `modb`: where to store temporal data, like CDRs or voicemails +3. `system`: where to store system data, like prompts + +Within the `database` classification, you can define things like the connection to use when reading/writing, what types of documents should be stored/retrieved, etc. + +#### Enabling the storage endpoint + +Crossbar must have the storage endpoint enabled first: + +``` +sup crossbar_maintenance start_module cb_storage +``` + +#### Schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`attachments` | Defines where and how to store attachments | [#/definitions/storage.attachments](#storageattachments) | | `false` +`connections` | Describes alternative connections to use (such as alternative CouchDB instances | [#/definitions/storage.connections](#storageconnections) | | `false` +`id` | ID of the storage document | `string` | | `false` +`plan` | Describes how to store documents depending on the database or document type | [#/definitions/storage.plan](#storageplan) | | `false` + + +##### storage.attachment.aws + +schema for AWS attachment entry + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`handler` | What AWS service to use | `string('s3')` | | `true` +`name` | Friendly name for this configuration | `string` | | `false` +`settings` | AWS API settings | `object` | | `true` +`settings.bucket` | Bucket name to store data to | `string` | | `true` +`settings.host` | Region-specific hostname to use, if applicable | `string` | | `false` +`settings.key` | AWS Key to use | `string` | | `true` +`settings.path` | Custom path to use as a prefix when saving files | `string` | | `false` +`settings.secret` | AWS Secret to use | `string` | | `true` + +##### storage.attachment.google_drive + +schema for google drive attachment entry + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`handler` | What handler module to use | `string('google_drive')` | | `true` +`name` | Friendly name for this configuration | `string` | | `false` +`settings` | Settings for the Google Drive account | `object` | | `true` +`settings.folder_id` | Folder ID in which to store the file, if any | `string` | | `false` +`settings.oauth_doc_id` | Doc ID in the system 'oauth' database | `string` | | `true` + +##### storage.attachments + +Keys are 32-character identifiers to be used in storage plans + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- + +##### storage.connection.couchdb + +schema for couchdb connection entry + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`driver` | | `string('kazoo_couch')` | | `true` +`name` | | `string` | | `false` +`settings` | | `object` | | `true` +`settings.connect_options` | | `object` | | `false` +`settings.connect_options.keepalive` | | `boolean` | | `false` +`settings.connect_timeout` | | `integer` | | `false` +`settings.credentials` | | [#/definitions/#/definitions/credentials](##/definitions/credentials) | | `false` +`settings.ip` | | `string` | | `true` +`settings.max_pipeline_size` | | `integer` | | `false` +`settings.max_sessions` | | `integer` | | `false` +`settings.pool` | | [#/definitions/#/definitions/pool](##/definitions/pool) | | `false` +`settings.port` | | `integer` | | `true` + +##### storage.connections + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- + +##### storage.plan + +schema for storage plan + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`account` | | [#/definitions/storage.plan.database](#storageplan.database) | | `false` +`modb` | | [#/definitions/storage.plan.database](#storageplan.database) | | `false` +`system` | | [#/definitions/storage.plan.database](#storageplan.database) | | `false` + +##### storage.plan.database + +schema for database storage plan + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`attachments` | | [#/definitions/storage.plan.database.attachment](#storageplan.database.attachment) | | `false` +`connection` | | `string` | | `false` +`database` | | [#/definitions/#/definitions/database](##/definitions/database) | | `false` +`types` | | `object` | | `false` +`types.call_recording` | | [#/definitions/storage.plan.database.document](#storageplan.database.document) | | `false` +`types.fax` | | [#/definitions/storage.plan.database.document](#storageplan.database.document) | | `false` +`types.mailbox_message` | | [#/definitions/storage.plan.database.document](#storageplan.database.document) | | `false` +`types.media` | | [#/definitions/storage.plan.database.document](#storageplan.database.document) | | `false` + +##### storage.plan.database.attachment + +schema for attachment ref type storage plan + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`handler` | | `string` | | `false` +`params` | | `object` | | `false` +`stub` | | `boolean` | | `false` + +##### storage.plan.database.document + +schema for document type storage plan + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`attachments` | | [#/definitions/storage.plan.database.attachment](#storageplan.database.attachment) | | `false` +`connection` | | `string` | | `false` + + + +##### storage.attachment.aws + +schema for AWS attachment entry + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`handler` | What AWS service to use | `string('s3')` | | `true` +`name` | Friendly name for this configuration | `string` | | `false` +`settings` | AWS API settings | `object` | | `true` +`settings.bucket` | Bucket name to store data to | `string` | | `true` +`settings.host` | Region-specific hostname to use, if applicable | `string` | | `false` +`settings.key` | AWS Key to use | `string` | | `true` +`settings.path` | Custom path to use as a prefix when saving files | `string` | | `false` +`settings.secret` | AWS Secret to use | `string` | | `true` + +##### storage.attachment.google_drive + +schema for google drive attachment entry + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`handler` | What handler module to use | `string('google_drive')` | | `true` +`name` | Friendly name for this configuration | `string` | | `false` +`settings` | Settings for the Google Drive account | `object` | | `true` +`settings.folder_id` | Folder ID in which to store the file, if any | `string` | | `false` +`settings.oauth_doc_id` | Doc ID in the system 'oauth' database | `string` | | `true` + +##### storage.attachments + +Keys are 32-character identifiers to be used in storage plans. + +One way to generate them: + +```shell +curl https://www.uuidgenerator.net/api/version4/1 | sed 's/-//g' +``` + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- + +##### storage.connection.couchdb + +schema for couchdb connection entry + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`driver` | | `string('kazoo_couch')` | | `true` +`name` | | `string` | | `false` +`settings` | | `object` | | `true` +`settings.connect_options` | | `object` | | `false` +`settings.connect_options.keepalive` | | `boolean` | | `false` +`settings.connect_timeout` | | `integer` | | `false` +`settings.credentials` | | [#/definitions/#/definitions/credentials](##/definitions/credentials) | | `false` +`settings.ip` | | `string` | | `true` +`settings.max_pipeline_size` | | `integer` | | `false` +`settings.max_sessions` | | `integer` | | `false` +`settings.pool` | | [#/definitions/#/definitions/pool](##/definitions/pool) | | `false` +`settings.port` | | `integer` | | `true` + +##### storage.connections + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- + +##### storage.plan + +schema for storage plan + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`account` | | [#/definitions/storage.plan.database](#storageplan.database) | | `false` +`modb` | | [#/definitions/storage.plan.database](#storageplan.database) | | `false` +`system` | | [#/definitions/storage.plan.database](#storageplan.database) | | `false` + +##### storage.plan.database + +schema for database storage plan + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`attachments` | | [#/definitions/storage.plan.database.attachment](#storageplan.database.attachment) | | `false` +`connection` | | `string` | | `false` +`database` | | [#/definitions/#/definitions/database](##/definitions/database) | | `false` +`types` | | `object` | | `false` +`types.call_recording` | | [#/definitions/storage.plan.database.document](#storageplan.database.document) | | `false` +`types.fax` | | [#/definitions/storage.plan.database.document](#storageplan.database.document) | | `false` +`types.mailbox_message` | | [#/definitions/storage.plan.database.document](#storageplan.database.document) | | `false` +`types.media` | | [#/definitions/storage.plan.database.document](#storageplan.database.document) | | `false` + +##### storage.plan.database.attachment + +schema for attachment ref type storage plan + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`handler` | | `string` | | `false` +`params` | | `object` | | `false` +`stub` | | `boolean` | | `false` + +##### storage.plan.database.document + +schema for document type storage plan + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`attachments` | | [#/definitions/storage.plan.database.attachment](#storageplan.database.attachment) | | `false` +`connection` | | `string` | | `false` + +#### Fetch + +> GET /v2/accounts/{ACCOUNT_ID}/storage + +```shell +curl -v -X GET \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage +``` +```json +{ + "auth_token": "{AUTH_TOKEN}" + "data": { + "attachments": { + "{UUID}": { + "handler": "s3", + "name": "S3 Storage", + "settings": { + "bucket": "{S3_BUCKET}", + "key": "{AWS_ACCESS_KEY}", + "secret": "{AWS_SECRET_KEY}" + } + } + }, + "id": "{ACCOUNT_ID}", + "plan": { + "modb": { + "types": { + "mailbox_message": { + "attachments": { + "handler": "{UUID}" + } + } + } + } + } + }, + "request_id": "{REQUEST_ID}", + "revision": "{REVISION}", + "status": "success" +} +``` + +#### Create + +> PUT /v2/accounts/{ACCOUNT_ID}/storage + +```shell +curl -v -X PUT \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage +``` + +#### Change + +> POST /v2/accounts/{ACCOUNT_ID}/storage + +```shell +curl -v -X POST \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage +``` + +#### Patch + +> PATCH /v2/accounts/{ACCOUNT_ID}/storage + +```shell +curl -v -X PATCH \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage +``` + +#### Remove + +> DELETE /v2/accounts/{ACCOUNT_ID}/storage + +```shell +curl -v -X DELETE \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage +``` + +#### Fetch + +> GET /v2/accounts/{ACCOUNT_ID}/storage/plans + +```shell +curl -v -X GET \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans +``` + +#### Create + +> PUT /v2/accounts/{ACCOUNT_ID}/storage/plans + +```shell +curl -v -X PUT \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans +``` + +#### Fetch + +> GET /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} + +```shell +curl -v -X GET \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} +``` + +#### Change + +> POST /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} + +```shell +curl -v -X POST \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} +``` + +#### Patch + +> PATCH /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} + +```shell +curl -v -X PATCH \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} +``` + +#### Remove + +> DELETE /v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} + +```shell +curl -v -X DELETE \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/storage/plans/{STORAGE_PLAN_ID} +``` diff --git a/applications/crossbar/doc/tasks.md b/applications/crossbar/doc/tasks.md index 02a11667dd5..692967a93d8 100644 --- a/applications/crossbar/doc/tasks.md +++ b/applications/crossbar/doc/tasks.md @@ -4,12 +4,16 @@ Kazoo Tasks enables listing, adding, starting & removing generic background task #### Schema +Input data to go through as part of a background task + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `file_name` | Human-readable name of a task's input file | `string` | | `false` `records` | List the rows of input data | `array(object)` | | `false` + + #### List available tasks > GET /v2/tasks diff --git a/applications/crossbar/doc/temporal_rules.md b/applications/crossbar/doc/temporal_rules.md new file mode 100644 index 00000000000..c1aeeabdfa4 --- /dev/null +++ b/applications/crossbar/doc/temporal_rules.md @@ -0,0 +1,33 @@ +### Temporal_rules + +#### About Temporal_rules + +#### Schema + +Schema for a temporal rules + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`cycle` | The recurrence cycle for this rule | `string('date', 'daily', 'weekly', 'monthly', 'yearly')` | | `true` +`days` | The recurrence days for this rule | `array(integer)` | | `false` +`interval` | The recurrence interval for this rule | `integer` | `1` | `false` +`month` | The recurrence month for this rule | `integer` | | `false` +`name` | A friendly name for the temporal rule | `string(1..128)` | | `true` +`ordinal` | The recurrence ordinal for this rule | `string('every', 'first', 'second', 'third', 'fourth', 'fifth', 'last')` | | `false` +`start_date` | The date that any recurrence should be calculated as starting on | `integer` | `62586115200` | `false` +`time_window_start` | Seconds from the start of a day to stop considering this rule valid | `integer` | | `false` +`wdays` | The recurrence weekdays for this rule | `array(string('monday', 'tuesday', 'wednesday', 'wensday', 'thursday', 'friday', 'saturday', 'sunday'))` | | `false` +`wdays.[]` | | `string` | | `false` + + + + +#### List items + +> GET /v2/accounts/{ACCOUNT_ID}/temporal_rules + +```shell +curl -v -X GET \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/temporal_rules +``` diff --git a/applications/crossbar/doc/temporal_rules_sets.md b/applications/crossbar/doc/temporal_rules_sets.md index 3c84802262e..cb50d9218c2 100644 --- a/applications/crossbar/doc/temporal_rules_sets.md +++ b/applications/crossbar/doc/temporal_rules_sets.md @@ -1,7 +1,22 @@ +### Temporal rules sets +#### About A temporal rule set is a collection of temporal rules that can be used in a callflow to match more that one rule. And can also be re-used. +#### Schema + +Schema for a temporal rules sets + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`name` | A friendly name for the temporal rule set | `string(1..128)` | | `true` +`temporal_rules` | Temporal Rules | `array(string)` | | `false` +`temporal_rules.[]` | | `string` | | `false` + + + + #### Structure The structure is really simple: diff --git a/applications/crossbar/doc/token_restrictions.md b/applications/crossbar/doc/token_restrictions.md index 36abad61116..886bb530ddb 100644 --- a/applications/crossbar/doc/token_restrictions.md +++ b/applications/crossbar/doc/token_restrictions.md @@ -12,14 +12,16 @@ System template located in `system_config/crossbar.token_restrictions`. Account template located in `{ACCOUNT_DB}/token_restrictions`. #### How it works? + When you make request to Crossbar (API), the system loads rules from auth token (used for authentitcation) and tries to apply the rules to URI (`/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/`). More information about URI structure can be found [here](basics.md). If Crossbar doesn't find a match for all parameters (endpoint name, account id, endpoint arguments, HTTP method), then it halts the request and returns a 403 error. #### Template structure + Each template can have different rules for different authentication methods and user privelege levels. -```JSON +```json { "AUTH_METHOD_1": { "PRIV_LEVEL_1": { @@ -47,7 +49,8 @@ Auth method and priv level can be matched with "catch all" term - `"_"`. If no e The rules are loaded into the auth token document when it is created (after successful authentication) and will be applied to any request using the auth token created. Example template: -```JSON + +```json { "cb_user_auth": { "admin": { @@ -70,7 +73,7 @@ Example template: #### Rules structure (saved in token document) -```JSON +```json { "ENDPOINT_1": [ { @@ -122,12 +125,13 @@ Example template: #### Match order ##### Endpoint match + At this step module compare resource from URI with resource names in token restrictions. If URI is `/v2/accounts/{ACCOUNT_ID}/users/{USER_ID}/{MODIFIER}/` then endpoint will be `users`, and `{USER_ID}`, `{MODIFIER}` are arguments of this endpoint. Rules applied to the last endpoint in URI. You can use "catch all" (`"_"`) endpoint name. First tries exact endpoint name: if not found, try the catch-all (if it exists). -```JSON +```json { "account": [ { ... }, @@ -150,7 +154,7 @@ Each endpoint contains a list of objects with rules. Appropriate object is selec After Crossbar finds the endpoint it tries to find rules for the requested account. -```JSON +```json { "devices": [ { @@ -187,7 +191,7 @@ The first endpoint-rule object matched to the requested account will be used in Endpoint argumnets matched with parameter `"rules"`. -```JSON +```json { "devices": [ { @@ -208,6 +212,7 @@ Endpoint argumnets matched with parameter `"rules"`. The search is performed in the order in which they appear in the rules for first match. No more search after that. ##### Rule keys + Key | Description --- | ----------- `/` | match empty argument list (or used as separator between other keys) @@ -220,39 +225,49 @@ Key | Description `/` - match empty argument list **Matches** + * `/v2/accounts/{ACCOUNT_ID}/devices` **Doesn't Match** + * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync` * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{DID}` --- + `*` - match any single, non-empty argument **Matches** + * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_1_ID}` * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_2_ID}` * etc **Doesn't Match** + * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync` --- + `#` - match any arguments (or no arguments) **Matches** + * `/v2/accounts/{ACCOUNT_ID}/devices` * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}` * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync` * etc --- + `{DEVICE_ID}` - exact match **Matches** + * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}` **Doesn't Match** + * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_1_ID}` * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_2_ID}` * etc @@ -260,39 +275,48 @@ Key | Description For matching more than one argument, you can use `/` to delineate how to process the arguments. You can mix and match special characters, explicit strings, etc. --- + `{DEVICE_ID}/quickcall/{DID}` - match exact list of arguments **Matches** + * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{DID}` **Doesn't Match** + * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}` * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync` * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{DID_2}` --- + `*/*/*` - match exactly three arguments **Matches** + * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{DID}` **Doesn't Match** + * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}` * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync` --- + `{DEVICE_ID}/#` - matches `{DEVICE_ID}` plus all arguments **Matches** + * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}` * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/sync` * `/v2/accounts/{ACCOUNT_ID}/devices/{DEVICE_ID}/quickcall/{DID}` * etc ##### HTTP method match + If endpoint matching fails to find a match, Crossbar will try to match the HTTP method used. -```JSON +```json { "devices": [ { @@ -320,17 +344,22 @@ List can contain any valid HTTP method ("GET", "PUT", "POST", "PATCH", "DELETE") #### Schema +Schema for token restrictions + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `restrictions` | | `object` | | `false` -`restrictions.^\w+$` | Name of athentication metod used when creating token. "_" for match any auth method | `object` | | `true` -`restrictions.^\w+$.^\w+$` | User privelege level. "_" for match any priv level | `object` | | `true` -`restrictions.^\w+$.^\w+$.^\w+$` | | `array(object)` | | `true` -`restrictions.^\w+$.^\w+$.^\w+$.[].allowed_accounts` | Account allowed to match this item | `array(string)` | | `false` -`restrictions.^\w+$.^\w+$.^\w+$.[].allowed_accounts.[]` | | `string` | | `false` -`restrictions.^\w+$.^\w+$.^\w+$.[].rules` | Rules applied to endpoint parameters | `object` | | `false` -`restrictions.^\w+$.^\w+$.^\w+$.[].rules.^[\w/#*]+$` | | `array(string('GET', 'PUT', 'POST', 'PATCH', 'DELETE', '_'))` | | `false` -`restrictions.^\w+$.^\w+$.^\w+$.[].rules.^[\w/#*]+$.[]` | | `string` | | `false` +`restrictions./^\w+$/` | Name of athentication metod used when creating token. "_" for match any auth method | `object` | | `true` +`restrictions./^\w+$/./^\w+$/` | User privelege level. "_" for match any priv level | `object` | | `true` +`restrictions./^\w+$/./^\w+$/./^\w+$/` | | `array(object)` | | `true` +`restrictions./^\w+$/./^\w+$/./^\w+$/.[].allowed_accounts` | Account allowed to match this item | `array(string)` | | `false` +`restrictions./^\w+$/./^\w+$/./^\w+$/.[].allowed_accounts.[]` | | `string` | | `false` +`restrictions./^\w+$/./^\w+$/./^\w+$/.[].rules` | Rules applied to endpoint parameters | `object` | | `false` +`restrictions./^\w+$/./^\w+$/./^\w+$/.[].rules./^[\w/#*]+$/` | verbs | `array(string('GET', 'PUT', 'POST', 'PATCH', 'DELETE', '_'))` | | `false` +`restrictions./^\w+$/./^\w+$/./^\w+$/.[].rules./^[\w/#*]+$/.[]` | | `string` | | `false` + + + #### Remove account's token restrictions @@ -364,12 +393,13 @@ curl -v -X POST \ ``` File `data.txt` contains this restrictions: + * `admin` has full access * `operator` can view/create/update devices (but not delete), full access to callflows, all other API restricted * `accountant` can only view transactions, all other API restricted * `user` can only view devices and other users. all other API restricted -```JSON +```json { "data": { "restrictions": { diff --git a/applications/crossbar/doc/transactions.md b/applications/crossbar/doc/transactions.md index 0a39b212bfc..50fcc6d1ede 100644 --- a/applications/crossbar/doc/transactions.md +++ b/applications/crossbar/doc/transactions.md @@ -114,7 +114,7 @@ curl -v -X GET \ Only for super duper admins and resellers. -Super admin can add `"credit_type": "free"` field to avoid bookkeeper and add credit "for free". +Super admin can add `"credit_type": "free"` field and change`"reason": "admin discretion"`to avoid bookkeeper and add credit "for free". ```shell curl -v -X PUT \ diff --git a/applications/crossbar/doc/ubiquiti_auth.md b/applications/crossbar/doc/ubiquiti_auth.md index 0a82ecbdab6..d272c1ee0e7 100644 --- a/applications/crossbar/doc/ubiquiti_auth.md +++ b/applications/crossbar/doc/ubiquiti_auth.md @@ -1,12 +1,34 @@ +### Ubiquiti auth -### Ubiquiti Single Sign On +Ubiquiti Single Sign On. -#### Crossbar Requests +#### About -##### PUT +#### Schema - curl -v -X PUT -H "Content-Type: application/json" http://crossbar:8000/v2/ubiquiti_auth -d '{"data":{"username":"{USERNAME}", "password":"{PASSWORD}"}}' - { +Provides an auth-token via Ubiquiti's SSO + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`password` | Ubiquiti SSO Password | `string(1..64)` | | `true` +`username` | Ubiquiti SSO Username | `string(1..64)` | | `true` + + + + +#### Create an auth token + +> PUT /v2/ubiquiti_auth + +```shell +curl -v -X PUT \ + -H "X-Auth-Token: {AUTH_TOKEN}" \ + -d '{"data": {"username":"{USERNAME}", "password":"{PASSWORD}"} }' \ + http://{SERVER}:8000/v2/ubiquiti_auth +``` + +```json +{ "auth_token": "{AUTH_TOKEN}", "data": { "sso": { @@ -34,4 +56,5 @@ "request_id": "{REQUEST_ID}", "revision": "{REVISION}", "status": "success" - } +} +``` diff --git a/applications/crossbar/doc/user_authentication.md b/applications/crossbar/doc/user_authentication.md index cc7bb6d47ce..2ab2a2bc137 100644 --- a/applications/crossbar/doc/user_authentication.md +++ b/applications/crossbar/doc/user_authentication.md @@ -6,6 +6,8 @@ Using your username and password, along with an account identifier, will instruc #### Schema +Provides an auth-token via user credentials + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `account_name` | The account name of the user | `string(1..128)` | | `false` @@ -14,6 +16,9 @@ Key | Description | Type | Default | Required `method` | The hash method | `string('md5', 'sha')` | `md5` | `false` `phone_number` | A phone number assigned to the users account | `string(1..64)` | | `false` + + + #### Create a new auth token Easy as 1, 2, 3: diff --git a/applications/crossbar/doc/users.md b/applications/crossbar/doc/users.md index b0dc8fdd83f..cf44baec5b7 100644 --- a/applications/crossbar/doc/users.md +++ b/applications/crossbar/doc/users.md @@ -6,6 +6,8 @@ Users represent just that, your users of the system. You can assign multiple dev #### Schema +Schema for a user + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `call_forward` | The device call forward parameters | `object` | | `false` @@ -18,13 +20,13 @@ Key | Description | Type | Default | Required `call_forward.require_keypress` | Determines if the callee is prompted to press 1 to accept the call | `boolean` | `true` | `false` `call_forward.substitute` | Determines if the call forwarding replaces the device | `boolean` | `true` | `false` `call_restriction` | Device level call restrictions for each available number classification | `object` | `{}` | `false` -`call_waiting` | | | | `false` +`call_waiting` | | [#/definitions/call_waiting](#call_waiting) | | `false` `caller_id` | The device caller ID parameters | `object` | `{}` | `false` -`contact_list` | | `object` | `{}` | `false` +`contact_list` | Contect List Parameters | `object` | `{}` | `false` `contact_list.exclude` | If set to true the device is excluded from the contact list | `boolean` | | `false` `dial_plan` | A list of rules used to modify dialed numbers | `object` | `{}` | `false` `directories` | Provides the mappings for what directory the user is a part of (the key), and what callflow (the value) to invoke if the user is selected by the caller. | `object` | | `false` -`do_not_disturb` | | `object` | | `false` +`do_not_disturb` | DND Parameters | `object` | | `false` `do_not_disturb.enabled` | Is do-not-disturb enabled for this user? | `boolean` | | `false` `email` | The email of the user | `string(1..254)` | | `false` `enabled` | Determines if the user is currently enabled | `boolean` | `true` | `false` @@ -40,20 +42,20 @@ Key | Description | Type | Default | Required `last_name` | The last name of the user | `string(1..128)` | | `true` `media` | The device media parameters | `object` | `{}` | `false` `media.audio` | The audio media parameters | `object` | `{}` | `false` -`media.audio.codecs` | A list of audio codecs the device supports | `array(string('OPUS', 'CELT@32000h', 'G7221@32000h', 'G7221@16000h', 'G722', 'speex@32000h', 'speex@16000h', 'PCMU', 'PCMA', 'G729', 'GSM', 'CELT@48000h', 'CELT@64000h', 'G722_16', 'G722_32', 'CELT_48', 'CELT_64', 'Speex', 'speex'))` | `PCMU` | `false` +`media.audio.codecs` | A list of audio codecs the device supports | `array(string('OPUS', 'CELT@32000h', 'G7221@32000h', 'G7221@16000h', 'G722', 'speex@32000h', 'speex@16000h', 'PCMU', 'PCMA', 'G729', 'GSM', 'CELT@48000h', 'CELT@64000h', 'G722_16', 'G722_32', 'CELT_48', 'CELT_64', 'Speex', 'speex'))` | `["PCMU"]` | `false` `media.audio.codecs.[]` | | `string` | | `false` `media.bypass_media` | Default bypass media mode | `boolean, string('true', 'false', 'auto')` | | `false` -`media.encryption` | | `object` | `{}` | `false` -`media.encryption.enforce_security` | | `boolean` | `false` | `false` -`media.encryption.methods` | | `array(string('zrtp', 'srtp'))` | `[]` | `false` +`media.encryption` | Encryption Parameters | `object` | `{}` | `false` +`media.encryption.enforce_security` | Is Encryption Enabled? | `boolean` | `false` | `false` +`media.encryption.methods` | Supported Encryption Types | `array(string('zrtp', 'srtp'))` | `[]` | `false` `media.encryption.methods.[]` | | `string` | | `false` -`media.fax_option` | Support T.38 | `boolean` | | `false` +`media.fax_option` | Is T.38 Supported? | `boolean` | | `false` `media.ignore_early_media` | The option to determine if early media from the device should always be ignored | `boolean` | | `false` -`media.progress_timeout` | The progress timeout to apply to the device | `integer` | | `false` +`media.progress_timeout` | The progress timeout to apply to the device (seconds) | `integer` | | `false` `media.video` | The video media parameters | `object` | `{}` | `false` `media.video.codecs` | A list of video codecs the device supports | `array(string('H261', 'H263', 'H264', 'VP8'))` | `[]` | `false` `media.video.codecs.[]` | | `string` | | `false` -`metaflows` | The device metaflow parameters | | | `false` +`metaflows` | The device metaflow parameters | [#/definitions/metaflows](#metaflows) | | `false` `music_on_hold` | The music on hold parameters used if not a property of the device owner | `object` | `{}` | `false` `music_on_hold.media_id` | The ID of a media object that should be used as the music on hold | `string(0..128)` | | `false` `presence_id` | Static presence ID (used instead of SIP username) | `string` | | `false` @@ -62,13 +64,299 @@ Key | Description | Type | Default | Required `pronounced_name` | Name pronounced by user to introduce himself to conference members | `object` | | `false` `pronounced_name.media_id` | The ID of a media object that should be used as the music on hold | `string(0..128)` | | `false` `require_password_update` | UI flag that the user should update their password. | `boolean` | `false` | `false` -`ringtones` | | `object` | `{}` | `false` +`ringtones` | Ringtone Parameters | `object` | `{}` | `false` `ringtones.external` | The alert info SIP header added when the call is from internal sources | `string(0..256)` | | `false` `ringtones.internal` | The alert info SIP header added when the call is from external sources | `string(0..256)` | | `false` `timezone` | User's timezone | `string` | | `false` `username` | The GUI login username - alpha-numeric, dashes, at symbol, periods, plusses, and underscores allowed | `string(1..256)` | | `false` `verified` | Determines if the user has been verified | `boolean` | `false` | `false` `vm_to_email_enabled` | Determines if the user would like voicemails emailed to them | `boolean` | `true` | `false` +`voicemail` | | `object` | | `false` +`voicemail.notify` | | `object` | | `false` +`voicemail.notify.callback` | | [#/definitions/notify.callback](#notifycallback) | | `false` + + +##### call_waiting + +Parameters for server-side call waiting + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`enabled` | Determines if server side call waiting is enabled/disabled | `boolean` | | `false` + +##### caller_id + +Defines caller ID settings based on the type of call being made + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`emergency` | The caller ID used when a resource is flagged as 'emergency' | `object` | | `false` +`emergency.name` | The caller id name for the object type | `string(0..35)` | | `false` +`emergency.number` | The caller id name for the object type | `string(0..35)` | | `false` +`external` | The default caller ID used when dialing external numbers | `object` | | `false` +`external.name` | The caller id name for the object type | `string(0..35)` | | `false` +`external.number` | The caller id name for the object type | `string(0..35)` | | `false` +`internal` | The default caller ID used when dialing internal extensions | `object` | | `false` +`internal.name` | The caller id name for the object type | `string(0..35)` | | `false` +`internal.number` | The caller id name for the object type | `string(0..35)` | | `false` + +##### dialplans + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`system` | List of system dial plans | `array()` | | `false` + +##### metaflow + +A metaflow node defines a module to execute, data to provide to that module, and one or more children to branch to + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- + +##### metaflow.audio_level + +audio_level metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string` | | `true` +`data.level` | | `string` | | `false` +`data.mode` | | `string` | | `false` +`module` | | `string('audio_level')` | | `true` + +##### metaflow.break + +break metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('break')` | | `true` + +##### metaflow.callflow + +callflow metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.id` | | `string` | | `true` +`module` | | `string('callflow')` | | `true` + +##### metaflow.hangup + +hangup metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('hangup')` | | `true` + +##### metaflow.hold + +hold metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.moh_aleg` | | `string` | | `false` +`data.moh_bleg` | | `string` | | `false` +`data.unhold_key` | | `string` | `1` | `false` +`module` | | `string('hold')` | | `true` + +##### metaflow.hold_control + +hold_control metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`data.action` | | `string('hold', 'unhold', 'toggle')` | `toggle` | `false` +`module` | | `string('hold_control')` | | `true` + +##### metaflow.intercept + +intercept metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.auto_answer` | | `boolean` | `false` | `false` +`data.target_id` | | `string` | | `true` +`data.target_type` | | `string('device', 'user', 'number')` | | `true` +`data.unbridged_only` | | `boolean` | `true` | `false` +`module` | | `string('intercept')` | | `true` + +##### metaflow.move + +move metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.auto_answer` | | `boolean` | `false` | `false` +`data.device_id` | | `string` | | `false` +`data.owner_id` | | `string` | | `false` +`module` | | `string('move')` | | `true` + +##### metaflow.play + +play metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.id` | | `string` | | `true` +`data.leg` | | `string('both', 'self', 'peer')` | `both` | `false` +`module` | | `string('play')` | | `true` + +##### metaflow.record_call + +record_call metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string('start', 'stop', 'toggle')` | `toggle` | `true` +`data.format` | | `string` | | `false` +`data.media_name` | | `string` | | `false` +`module` | | `string('record_call')` | | `true` + +##### metaflow.resume + +resume metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `false` +`module` | | `string('resume')` | | `true` + +##### metaflow.say + +say metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.language` | | `string` | | `false` +`data.method` | | `string` | | `false` +`data.text` | | `string` | | `true` +`data.type` | | `string` | | `false` +`module` | | `string('say')` | | `true` + +##### metaflow.sound_touch + +sound_touch metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.action` | | `string('start', 'stop')` | | `true` +`data.adjust_in_octaves` | | `integer` | | `false` +`data.adjust_in_semitones` | | `integer` | | `false` +`data.hook_dtmf` | | `boolean` | `false` | `false` +`data.pitch` | | `integer` | | `false` +`data.rate` | | `integer` | | `false` +`data.sending_leg` | | `boolean` | `false` | `false` +`data.tempo` | | `integer` | | `false` +`module` | | `string('sound_touch')` | | `true` + +##### metaflow.transfer + +transfer metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.Transfer-Type` | | `string` | `attended` | `false` +`data.captures` | | `string` | | `false` +`data.target` | | `string` | | `false` +`module` | | `string('transfer')` | | `true` + +##### metaflow.tts + +tts metaflow schema + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`children` | | [#/definitions/metaflow_children](#metaflow_children) | | `false` +`data` | | `object` | | `true` +`data.engine` | | `string` | `flite` | `false` +`data.language` | | `string` | | `false` +`data.leg` | | `string` | `self` | `false` +`data.terminators` | | `string` | | `false` +`data.text` | | `string` | | `true` +`data.voice` | | `string` | `female` | `false` +`module` | | `string('tts')` | | `true` + +##### metaflow_children + +A metaflow child nodes + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- + +##### metaflows + +Actions applied to a call outside of the normal callflow, initiated by the caller(s) + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`binding_digit` | What DTMF will trigger the collection and analysis of the subsequent DTMF sequence | `string('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#')` | `*` | `false` +`digit_timeout` | How long to wait between DTMF presses before processing the collected sequence (milliseconds) | `integer` | | `false` +`listen_on` | Which leg(s) of the call to listen for DTMF | `string('both', 'self', 'peer')` | | `false` +`numbers` | A list of static numbers with their flows | `object` | | `false` +`numbers./^[0-9]+$/` | | [#/definitions/metaflow](#metaflow) | | `false` +`patterns` | A list of patterns with their flows | `object` | | `false` +`patterns./.+/` | | [#/definitions/metaflow](#metaflow) | | `false` + +##### notify.callback + +Schema for a callback options + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`attempts` | How many attempts without answer will system do | `integer` | | `false` +`disabled` | Determines if the system will call to callback number | `boolean` | | `false` +`interval_s` | How long will system wait between call back notification attempts | `integer` | | `false` +`number` | Number for callback notifications about new messages | `string` | | `false` +`schedule` | Schedules interval between callbacks | `array(integer)` | | `false` +`timeout_s` | How long will system wait for answer to callback | `integer` | | `false` + +##### profile + +Defines user extended properties + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`addresses` | To specify the components of the addresses | `array(object)` | | `false` +`addresses.[].address` | To specify the address | `string` | | `false` +`addresses.[].types` | To specify types of the address | `array()` | | `false` +`assistant` | To specify the user's assistant | `string` | | `false` +`birthday` | To specify the birth date of the user | `string` | | `false` +`nicknames` | To specify the text corresponding to the nickname of the user | `array(string)` | | `false` +`nicknames.[]` | | `string` | | `false` +`note` | To specify supplemental information or a comment that is associated with the user | `string` | | `false` +`role` | To specify the function or part played in a particular situation by the user | `string` | | `false` +`sort-string` | To specify the family name or given name text to be used for national-language-specific sorting of the FN and N types | `string` | | `false` +`title` | To specify the position or job of the user | `string` | | `false` + + #### Fetch summary of users in account diff --git a/applications/crossbar/doc/voicemail.md b/applications/crossbar/doc/voicemail.md index cd078512fcd..e5b8925b75b 100644 --- a/applications/crossbar/doc/voicemail.md +++ b/applications/crossbar/doc/voicemail.md @@ -15,6 +15,8 @@ For more information about voicemail changes see documentation for kazoo_voicema #### Schema +Schema for a voicemail box + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `check_if_owner` | Determines if when the user calls their own voicemail they should be prompted to sign in | `boolean` | `true` | `false` @@ -26,7 +28,7 @@ Key | Description | Type | Default | Required `name` | A friendly name for the voicemail box | `string(1..128)` | | `true` `not_configurable` | Determines if the user can configure this voicemail. | `boolean` | `false` | `false` `notify` | | `object` | | `false` -`notify.callback` | | `#/definitions/notify.callback` | | `false` +`notify.callback` | | [#/definitions/notify.callback](#notifycallback) | | `false` `notify_email_addresses` | List of email addresses to send notifications to (in addition to owner's email, if any) | `array(string)` | `[]` | `false` `notify_email_addresses.[]` | | `string` | | `false` `owner_id` | The ID of the user object that 'owns' the voicemail box | `string(32)` | | `false` @@ -37,6 +39,22 @@ Key | Description | Type | Default | Required `skip_instructions` | Determines if the instructions after the greeting and prior to composing a message should be played | `boolean` | `false` | `false` `timezone` | The default timezone | `string(5..32)` | | `false` + +##### notify.callback + +Schema for a callback options + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`attempts` | How many attempts without answer will system do | `integer` | | `false` +`disabled` | Determines if the system will call to callback number | `boolean` | | `false` +`interval_s` | How long will system wait between call back notification attempts | `integer` | | `false` +`number` | Number for callback notifications about new messages | `string` | | `false` +`schedule` | Schedules interval between callbacks | `array(integer)` | | `false` +`timeout_s` | How long will system wait for answer to callback | `integer` | | `false` + + + #### List all account's voicemail boxes List a summary of voicemail boxes in an account. diff --git a/applications/crossbar/doc/webhooks.md b/applications/crossbar/doc/webhooks.md index 50f3891ba67..c5fad268fd3 100644 --- a/applications/crossbar/doc/webhooks.md +++ b/applications/crossbar/doc/webhooks.md @@ -6,6 +6,8 @@ Webhooks allow Kazoo to send HTTP requests to a third-party webserver, alerting #### Schema +Web Hooks are subscriptions to allowed events that, when the event occurs, the event data is sent to the uri set in the Web Hook document. + Key | Description | Type | Default | Required --- | ----------- | ---- | ------- | -------- `custom_data` | These properties will be added to the event and will overwrite existing values. | `object` | | `false` @@ -17,6 +19,9 @@ Key | Description | Type | Default | Required `retries` | Retry the request this many times (if it fails) | `integer` | `2` | `false` `uri` | The 3rd party URI to call out to an event | `string` | | `true` + + + #### List Installed Webhooks Webhooks are installed by the system administrator. You can query Crossbar to see which are installed. diff --git a/applications/crossbar/doc/whitelabeling.md b/applications/crossbar/doc/whitelabeling.md index d190032d59c..2e208f5af54 100644 --- a/applications/crossbar/doc/whitelabeling.md +++ b/applications/crossbar/doc/whitelabeling.md @@ -1,3 +1,34 @@ +### Whitelabeling + +#### About + +#### Schema + +Whitelabel settings + +Key | Description | Type | Default | Required +--- | ----------- | ---- | ------- | -------- +`company_name` | The company name to display to users | `string` | | `false` +`domain` | This is the whitelabeled domain that users will be entering to reach the UI | `string` | | `false` +`fake_api_url` | This is a whitelabeled API URL, primarily used by the developer application | `string` | | `false` +`hide_credits` | When checkef this hides the credits | `boolean` | `false` | `false` +`hide_powered` | When checked this hides the powered by 2600hz on the bottom right | `boolean` | `false` | `false` +`hide_registration` | When checked this hides the ability to register for a new account | `boolean` | `false` | `false` +`inbound_trunks_price` | The price to show for inbound trunks, this is currently only for display purposes | `string` | | `false` +`nav` | Properties related to navigation in the UI | `object` | | `false` +`nav.help` | The URL to use when the help link is clicked | `string` | | `false` +`nav.learn_more` | The URL to use when the 'Learn More!' link is clicked | `string` | | `false` +`outbound_trunks_price` | The price to show for outbound trunks, this is currently only for display purposes | `string` | | `false` +`port` | Parameters releated to whitelabeling port requests | `object` | | `false` +`port.features` | The URL to use when the features link is clicked | `string` | | `false` +`port.loa` | The URL to use when the LOA link is clicked | `string` | | `false` +`port.resporg` | The URL to use when the resporg link is clicked | `string` | | `false` +`port.support_email` | The support email address to display to the user | `string` | | `false` +`port.terms` | The URL to use when the terms and conditions link is clicked | `string` | | `false` +`twoway_trunks_price` | The price to show for twoway trunks, this is currently only for display purposes | `string` | | `false` + + + #### Domains diff --git a/applications/crossbar/priv/api/descriptions.system_config.json b/applications/crossbar/priv/api/descriptions.system_config.json index 402223faa9d..42be8653a9f 100644 --- a/applications/crossbar/priv/api/descriptions.system_config.json +++ b/applications/crossbar/priv/api/descriptions.system_config.json @@ -46,6 +46,7 @@ "callflow.default_pin_length": "callflow default pin length", "callflow.default_use_account_caller_id": "callflow default use account caller id", "callflow.delete_after_notify": "callflow delete after notify", + "callflow.dynamic_cid.reject_prompt": "callflow.dynamic_cid reject prompt", "callflow.ensure_valid_caller_id": "callflow ensure valid caller id", "callflow.extension": "callflow extension", "callflow.fax_detect_duration_s": "callflow fax detect duration in seconds", @@ -133,6 +134,7 @@ "crossbar.freeswitch.templates_to_process": "crossbar.freeswitch templates to process", "crossbar.freeswitch.work_dir": "crossbar.freeswitch work dir", "crossbar.freeswitch.{Module}": "crossbar.freeswitch {Module}", + "crossbar.ip": "crossbar ip", "crossbar.local_resources.allow_peers": "crossbar.local_resources allow peers", "crossbar.magic_path_patterns": "crossbar magic path patterns", "crossbar.max_upload_size": "crossbar maximum upload size", @@ -429,6 +431,7 @@ "notify.voicemail_full.default_to": "notify.voicemail_full default to", "notify.voicemail_to_email.html_content_transfer_encoding": "notify.voicemail_to_email html content transfer encoding", "notify.voicemail_to_email.text_content_transfer_encoding": "notify.voicemail_to_email text content transfer encoding", + "number_manager.allow": "Number features a number is allowed to enable or disable", "number_manager.available_module_name": "number_manager available module name", "number_manager.bandwidth.debug": "number_manager.bandwidth debug", "number_manager.bandwidth.developer_key": "number_manager.bandwidth developer key", @@ -455,6 +458,7 @@ "number_manager.dash_e911.debug": "number_manager.dash_e911 debug", "number_manager.dash_e911.emergency_provisioning_url": "number_manager.dash_e911 emergency provisioning url", "number_manager.default_force_outbound": "number_manager default force outbound", + "number_manager.denied": "Number features a number is disallowed to enable or disable", "number_manager.e164_converters": "number_manager e164 converters", "number_manager.fetch_account_from_ports": "number_manager fetch account from ports", "number_manager.force_local_outbound": "number_manager force local outbound", @@ -462,10 +466,12 @@ "number_manager.force_port_out_outbound": "number_manager force port out outbound", "number_manager.locality.url": "number_manager.locality url", "number_manager.maximum_search_quantity": "maximum number of returned DIDs in search query", + "number_manager.number_search_timeout_ms": "number manager number search timeout in milliseconds", "number_manager.other.default_country": "number_manager.other default country", "number_manager.other.endpoints": "number_manager.other endpoints", "number_manager.other.phonebook_url": "number_manager.other phonebook url", "number_manager.porting_module_name": "number manager porting module name", + "number_manager.providers": "Number features sub accounts are allowed to enable or disable", "number_manager.reconcile_regex": "number_manager reconcile regex", "number_manager.released_state": "number_manager released state", "number_manager.should_age": "number_manager should age", diff --git a/applications/crossbar/priv/api/swagger.json b/applications/crossbar/priv/api/swagger.json index 831c7ff6b55..2d25f2b3b28 100644 --- a/applications/crossbar/priv/api/swagger.json +++ b/applications/crossbar/priv/api/swagger.json @@ -640,30 +640,8 @@ "type": "object" }, "flow": { - "description": "A callflow node defines a module to execute, data to provide to that module, and one or more children to branch to", - "properties": { - "children": { - "default": {}, - "description": "Children callflows", - "required": false, - "type": "object" - }, - "data": { - "default": {}, - "description": "The data/arguments of the callflow module", - "required": true, - "type": "object" - }, - "module": { - "description": "The name of the callflow module to excute at this node", - "maxLength": 64, - "minLength": 1, - "required": true, - "type": "string" - } - }, - "required": true, - "type": "object" + "$ref": "callflows.action", + "description": "A callflow node defines a module to execute, data to provide to that module, and zero or more children to branch to" }, "metaflow": { "$ref": "metaflows", @@ -746,6 +724,35 @@ "required": true, "type": "object" }, + "callflows.action": { + "description": "Call flows describe steps to take in order to process a phone call. They are trees of information related to a phone call such as \"answer, play file, record file\" etc. that are logically grouped together and ordered.", + "properties": { + "children": { + "description": "Children callflows", + "patternProperties": { + ".+": { + "$ref": "callflows.action" + } + }, + "type": "object" + }, + "data": { + "description": "The data/arguments of the callflow module", + "type": "object" + }, + "module": { + "description": "The name of the callflow module to excute at this node", + "maxLength": 64, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "data", + "module" + ], + "type": "object" + }, "callflows.after_bridge": { "description": "Validator for the after_bridge callflow's data object", "properties": { @@ -1088,6 +1095,9 @@ "action": { "description": "" }, + "caller_id": { + "description": "" + }, "enforce_call_restriction": { "default": true, "description": "", @@ -1103,8 +1113,14 @@ "description": "", "type": "integer" }, + "max_digits": { + "description": "" + }, "media_id": { "description": "" + }, + "min_digits": { + "description": "" } }, "required": true, @@ -1676,7 +1692,7 @@ }, "time_limit": { "description": "Time limit, in seconds, for the recording", - "maximum": 3600, + "maximum": 10800, "minimum": 5, "required": false, "type": "integer" @@ -4190,7 +4206,7 @@ "properties": { "allow_prepay": { "default": true, - "description": "Determines if the account would like to allow per-minute calls if they have credit", + "description": "Determines if the account would like to allow per-minute calls if they have no available credit", "required": false, "type": "boolean" }, @@ -6763,6 +6779,7 @@ "additionalProperties": false, "patternProperties": { "^_": { + "description": "Ignores CouchDB fields prefixed by underscores", "type": [ "string", "integer", @@ -6771,6 +6788,7 @@ ] }, "^pvt_": { + "description": "Ignores Kazoo private fields prefixed by pvt_", "type": [ "string", "integer", @@ -6780,43 +6798,59 @@ }, "properties": { "attachments": { - "$ref": "storage.attachments" + "$ref": "storage.attachments", + "description": "Defines where and how to store attachments" }, "connections": { - "$ref": "storage.connections" + "$ref": "storage.connections", + "description": "Describes alternative connections to use (such as alternative CouchDB instances" + }, + "id": { + "description": "ID of the storage document", + "type": "string" }, "plan": { - "$ref": "storage.plan" + "$ref": "storage.plan", + "description": "Describes how to store documents depending on the database or document type" } }, "type": "object" }, "storage.attachment.aws": { - "description": "schema for aws attachment entry", + "description": "schema for AWS attachment entry", "properties": { "handler": { + "description": "What AWS service to use", "enum": [ "s3" - ] + ], + "type": "string" }, "name": { + "description": "Friendly name for this configuration", "type": "string" }, "settings": { + "description": "AWS API settings", "properties": { "bucket": { + "description": "Bucket name to store data to", "type": "string" }, "host": { + "description": "Region-specific hostname to use, if applicable", "type": "string" }, "key": { + "description": "AWS Key to use", "type": "string" }, "path": { + "description": "Custom path to use as a prefix when saving files", "type": "string" }, "secret": { + "description": "AWS Secret to use", "type": "string" } }, @@ -6838,19 +6872,25 @@ "description": "schema for google drive attachment entry", "properties": { "handler": { + "description": "What handler module to use", "enum": [ "google_drive" - ] + ], + "type": "string" }, "name": { + "description": "Friendly name for this configuration", "type": "string" }, "settings": { + "description": "Settings for the Google Drive account", "properties": { - "oauth_doc_id": { + "folder_id": { + "description": "Folder ID in which to store the file, if any", "type": "string" }, - "path": { + "oauth_doc_id": { + "description": "Doc ID in the system 'oauth' database", "type": "string" } }, @@ -6867,8 +6907,10 @@ "type": "object" }, "storage.attachments": { + "description": "Keys are 32-character identifiers to be used in storage plans", "patternProperties": { "^[a-z,0-9]{32}$": { + "description": "Configuration for the supported storage backends", "oneOf": [ { "$ref": "storage.attachment.aws" @@ -7541,6 +7583,17 @@ }, "type": "object" }, + "system_config.callflow.dynamic_cid": { + "description": "Schema for callflow.dynamic_cid system_config", + "properties": { + "reject_prompt": { + "default": "dynamic-cid-invalid_using_default", + "description": "callflow.dynamic_cid reject prompt", + "type": "string" + } + }, + "type": "object" + }, "system_config.callflow.hotdesk": { "description": "Schema for callflow.hotdesk system_config", "properties": { @@ -7806,6 +7859,10 @@ "description": "crossbar expiry percentage", "type": "integer" }, + "ip": { + "description": "crossbar ip", + "type": "string" + }, "magic_path_patterns": { "default": [ "/:version/accounts/:account_id/vmboxes/:box_id/messages/:message_id/raw", @@ -8614,9 +8671,6 @@ "description": "ecallmgr capabilities", "type": "array" }, - "configuration_handlers": { - "description": "ecallmgr configuration handlers" - }, "debug_channel": { "default": false, "description": "ecallmgr debug channel", @@ -8725,48 +8779,6 @@ "description": "ecallmgr maximum timeout for node restart", "type": "integer" }, - "modules": { - "default": { - "authn": { - "type": "worker" - }, - "channel": { - "type": "worker" - }, - "channel_hold": { - "type": "worker" - }, - "conference": { - "type": "worker" - }, - "config": { - "type": "worker" - }, - "event_stream_sup": { - "type": "supervisor" - }, - "msg": { - "type": "worker" - }, - "node": { - "type": "worker" - }, - "notify": { - "type": "worker" - }, - "recordings": { - "type": "worker" - }, - "resource": { - "type": "worker" - }, - "route_sup": { - "type": "supervisor" - } - }, - "description": "ecallmgr modules", - "type": "object" - }, "network_map": { "default": {}, "description": "ecallmgr network map", @@ -8906,7 +8918,6 @@ } }, "required": [ - "configuration_handlers", "default_ringback", "fs_reconnect_cmds", "node_commands", @@ -9203,12 +9214,12 @@ "description": "jonny5 default twoway trunks" }, "flat_rate_blacklist": { - "default": "^\\+?1(684|264|268|242|246|441|284|345|767|809|829|849|473|671|876|664|670|787|939|869|758|784|721|868|649|340|900|8(?:[0,2,3,4,5,6,7]{2}|8[0-9]))\\d{7}$", + "default": "^\\+1(684|264|268|242|246|441|284|345|767|809|829|849|473|671|876|664|670|787|939|869|758|784|721|868|649|340|900|800|888|877|866|855|844)\\d{7}$", "description": "jonny5 flat rate blacklist", "type": "string" }, "flat_rate_whitelist": { - "default": "^\\+?1\\d{10}$", + "default": "^\\+1\\d{10}$", "description": "jonny5 flat rate whitelist", "type": "string" } @@ -10255,6 +10266,15 @@ "e164_converters": { "description": "number_manager e164 converters" }, + "features": { + "properties": { + "allow": { + "properties": { + "description": "Number features a number is allowed to enable or disable" + } + } + } + }, "fetch_account_from_ports": { "default": true, "description": "number_manager fetch account from ports", @@ -10280,11 +10300,19 @@ "description": "maximum number of returned DIDs in search query", "type": "integer" }, + "number_search_timeout_ms": { + "default": 5000, + "description": "number manager number search timeout in milliseconds", + "type": "integer" + }, "porting_module_name": { "default": "knm_local", "description": "number manager porting module name", "type": "string" }, + "providers": { + "description": "Number features sub accounts are allowed to enable or disable" + }, "reconcile_regex": { "default": "^\\+?1?\\d{10}$|^\\+[2-9]\\d{7,}$|^011\\d*$|^00\\d*$", "description": "number_manager reconcile regex", @@ -10321,6 +10349,8 @@ }, "required": [ "e164_converters", + "features", + "providers", "released_state", "should_permanently_delete" ], @@ -14444,6 +14474,19 @@ ] } }, + "/accounts/{ACCOUNT_ID}/cdrs/summary": { + "get": { + "parameters": [ + { + "$ref": "#/parameters/auth_token_header", + "required": true + }, + { + "$ref": "#/parameters/account_id" + } + ] + } + }, "/accounts/{ACCOUNT_ID}/cdrs/{CDR_ID}": { "get": { "parameters": [ @@ -19417,6 +19460,17 @@ } ] }, + "patch": { + "parameters": [ + { + "$ref": "#/parameters/auth_token_header", + "required": true + }, + { + "$ref": "#/parameters/account_id" + } + ] + }, "post": { "parameters": [ { @@ -19517,6 +19571,20 @@ } ] }, + "patch": { + "parameters": [ + { + "$ref": "#/parameters/storage_plan_id" + }, + { + "$ref": "#/parameters/auth_token_header", + "required": true + }, + { + "$ref": "#/parameters/account_id" + } + ] + }, "post": { "parameters": [ { diff --git a/applications/crossbar/priv/couchdb/account/apps_store.json b/applications/crossbar/priv/couchdb/account/apps_store.json index 39893dd9102..35dd1f53170 100644 --- a/applications/crossbar/priv/couchdb/account/apps_store.json +++ b/applications/crossbar/priv/couchdb/account/apps_store.json @@ -3,7 +3,21 @@ "language": "javascript", "views": { "crossbar_listing": { - "map": "function (doc) {if (doc.pvt_type != 'app' || doc.pvt_deleted) return;emit(doc.name, {id: doc._id,name: doc.name, phase: doc.phase, 'i18n': doc['i18n'],tags: doc.tags,api_url: doc.api_url,source_url: doc.source_url, published: doc.published});}" + "map": [ + "function (doc) {", + " if (doc.pvt_type !== 'app' || doc.pvt_deleted) return;", + " emit(doc.name, {", + " id: doc._id,", + " name: doc.name,", + " phase: doc.phase,", + " 'i18n': doc['i18n'],", + " tags: doc.tags,", + " api_url: doc.api_url,", + " source_url: doc.source_url,", + " published: doc.published", + " });", + "}" + ] } } } diff --git a/applications/crossbar/priv/couchdb/account/phone_numbers.json b/applications/crossbar/priv/couchdb/account/phone_numbers.json index 289a15c40ce..ceba666b6ea 100644 --- a/applications/crossbar/priv/couchdb/account/phone_numbers.json +++ b/applications/crossbar/priv/couchdb/account/phone_numbers.json @@ -5,7 +5,7 @@ "crossbar_listing": { "map": [ "function(doc) {", - " if(doc.pvt_type != 'number' || doc.pvt_deleted) return;", + " if (doc.pvt_type != 'number' || doc.pvt_deleted) return;", " var features = [], o = doc.pvt_features || {};", " for (var p in o)", " if (o.hasOwnProperty(p))", @@ -13,7 +13,8 @@ " emit(doc._id, {", " state: doc.pvt_state,", " features: features,", - " features_available: doc.pvt_features_available,", + " features_allowed: doc.pvt_features_allowed || [],", + " features_denied: doc.pvt_features_denied || [],", " assigned_to: doc.pvt_assigned_to,", " used_by: doc.pvt_used_by,", " created: doc.pvt_created,", diff --git a/applications/crossbar/priv/couchdb/schemas/callflows.action.json b/applications/crossbar/priv/couchdb/schemas/callflows.action.json new file mode 100644 index 00000000000..a71e69d9b7a --- /dev/null +++ b/applications/crossbar/priv/couchdb/schemas/callflows.action.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "_id": "callflows.action", + "description": "Call flows describe steps to take in order to process a phone call. They are trees of information related to a phone call such as \"answer, play file, record file\" etc. that are logically grouped together and ordered.", + "properties": { + "children": { + "description": "Children callflows", + "patternProperties": { + ".+": { + "$ref": "callflows.action" + } + }, + "type": "object" + }, + "data": { + "description": "The data/arguments of the callflow module", + "type": "object" + }, + "module": { + "description": "The name of the callflow module to excute at this node", + "maxLength": 64, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "data", + "module" + ], + "type": "object" +} diff --git a/applications/crossbar/priv/couchdb/schemas/callflows.dynamic_cid.json b/applications/crossbar/priv/couchdb/schemas/callflows.dynamic_cid.json index c528cce64be..d16114dbbcd 100644 --- a/applications/crossbar/priv/couchdb/schemas/callflows.dynamic_cid.json +++ b/applications/crossbar/priv/couchdb/schemas/callflows.dynamic_cid.json @@ -6,6 +6,9 @@ "action": { "description": "" }, + "caller_id": { + "description": "" + }, "enforce_call_restriction": { "default": true, "description": "", @@ -21,8 +24,14 @@ "description": "", "type": "integer" }, + "max_digits": { + "description": "" + }, "media_id": { "description": "" + }, + "min_digits": { + "description": "" } }, "required": true, diff --git a/applications/crossbar/priv/couchdb/schemas/callflows.json b/applications/crossbar/priv/couchdb/schemas/callflows.json index 14558356e1c..1d964092927 100644 --- a/applications/crossbar/priv/couchdb/schemas/callflows.json +++ b/applications/crossbar/priv/couchdb/schemas/callflows.json @@ -23,30 +23,8 @@ "type": "object" }, "flow": { - "description": "A callflow node defines a module to execute, data to provide to that module, and one or more children to branch to", - "properties": { - "children": { - "default": {}, - "description": "Children callflows", - "required": false, - "type": "object" - }, - "data": { - "default": {}, - "description": "The data/arguments of the callflow module", - "required": true, - "type": "object" - }, - "module": { - "description": "The name of the callflow module to excute at this node", - "maxLength": 64, - "minLength": 1, - "required": true, - "type": "string" - } - }, - "required": true, - "type": "object" + "$ref": "callflows.action", + "description": "A callflow node defines a module to execute, data to provide to that module, and zero or more children to branch to" }, "metaflow": { "$ref": "metaflows", diff --git a/applications/crossbar/priv/couchdb/schemas/callflows.record_call.json b/applications/crossbar/priv/couchdb/schemas/callflows.record_call.json index d2b6de67be8..4d9c265b5ac 100644 --- a/applications/crossbar/priv/couchdb/schemas/callflows.record_call.json +++ b/applications/crossbar/priv/couchdb/schemas/callflows.record_call.json @@ -50,7 +50,7 @@ }, "time_limit": { "description": "Time limit, in seconds, for the recording", - "maximum": 3600, + "maximum": 10800, "minimum": 5, "required": false, "type": "integer" diff --git a/applications/crossbar/priv/couchdb/schemas/limits.json b/applications/crossbar/priv/couchdb/schemas/limits.json index 9daaccd4d0b..ccb17b8b24b 100644 --- a/applications/crossbar/priv/couchdb/schemas/limits.json +++ b/applications/crossbar/priv/couchdb/schemas/limits.json @@ -5,7 +5,7 @@ "properties": { "allow_prepay": { "default": true, - "description": "Determines if the account would like to allow per-minute calls if they have credit", + "description": "Determines if the account would like to allow per-minute calls if they have no available credit", "required": false, "type": "boolean" }, diff --git a/applications/crossbar/priv/couchdb/schemas/storage.attachment.aws.json b/applications/crossbar/priv/couchdb/schemas/storage.attachment.aws.json index b338d30df31..46ff2e8e882 100644 --- a/applications/crossbar/priv/couchdb/schemas/storage.attachment.aws.json +++ b/applications/crossbar/priv/couchdb/schemas/storage.attachment.aws.json @@ -1,31 +1,40 @@ { "$schema": "http://json-schema.org/draft-04/schema#", "_id": "storage.attachment.aws", - "description": "schema for aws attachment entry", + "description": "schema for AWS attachment entry", "properties": { "handler": { + "description": "What AWS service to use", "enum": [ "s3" - ] + ], + "type": "string" }, "name": { + "description": "Friendly name for this configuration", "type": "string" }, "settings": { + "description": "AWS API settings", "properties": { "bucket": { + "description": "Bucket name to store data to", "type": "string" }, "host": { + "description": "Region-specific hostname to use, if applicable", "type": "string" }, "key": { + "description": "AWS Key to use", "type": "string" }, "path": { + "description": "Custom path to use as a prefix when saving files", "type": "string" }, "secret": { + "description": "AWS Secret to use", "type": "string" } }, diff --git a/applications/crossbar/priv/couchdb/schemas/storage.attachment.google_drive.json b/applications/crossbar/priv/couchdb/schemas/storage.attachment.google_drive.json index 6bc766cc00f..663226f1598 100644 --- a/applications/crossbar/priv/couchdb/schemas/storage.attachment.google_drive.json +++ b/applications/crossbar/priv/couchdb/schemas/storage.attachment.google_drive.json @@ -4,19 +4,25 @@ "description": "schema for google drive attachment entry", "properties": { "handler": { + "description": "What handler module to use", "enum": [ "google_drive" - ] + ], + "type": "string" }, "name": { + "description": "Friendly name for this configuration", "type": "string" }, "settings": { + "description": "Settings for the Google Drive account", "properties": { - "oauth_doc_id": { + "folder_id": { + "description": "Folder ID in which to store the file, if any", "type": "string" }, - "path": { + "oauth_doc_id": { + "description": "Doc ID in the system 'oauth' database", "type": "string" } }, diff --git a/applications/crossbar/priv/couchdb/schemas/storage.attachments.json b/applications/crossbar/priv/couchdb/schemas/storage.attachments.json index d68348ac342..fde2599c3e6 100644 --- a/applications/crossbar/priv/couchdb/schemas/storage.attachments.json +++ b/applications/crossbar/priv/couchdb/schemas/storage.attachments.json @@ -1,8 +1,10 @@ { "$schema": "http://json-schema.org/draft-04/schema#", "_id": "storage.attachments", + "description": "Keys are 32-character identifiers to be used in storage plans", "patternProperties": { "^[a-z,0-9]{32}$": { + "description": "Configuration for the supported storage backends", "oneOf": [ { "$ref": "storage.attachment.aws" diff --git a/applications/crossbar/priv/couchdb/schemas/storage.json b/applications/crossbar/priv/couchdb/schemas/storage.json index 9f8724ca08b..c79ad9681cd 100644 --- a/applications/crossbar/priv/couchdb/schemas/storage.json +++ b/applications/crossbar/priv/couchdb/schemas/storage.json @@ -4,6 +4,7 @@ "additionalProperties": false, "patternProperties": { "^_": { + "description": "Ignores CouchDB fields prefixed by underscores", "type": [ "string", "integer", @@ -12,6 +13,7 @@ ] }, "^pvt_": { + "description": "Ignores Kazoo private fields prefixed by pvt_", "type": [ "string", "integer", @@ -21,13 +23,20 @@ }, "properties": { "attachments": { - "$ref": "storage.attachments" + "$ref": "storage.attachments", + "description": "Defines where and how to store attachments" }, "connections": { - "$ref": "storage.connections" + "$ref": "storage.connections", + "description": "Describes alternative connections to use (such as alternative CouchDB instances" + }, + "id": { + "description": "ID of the storage document", + "type": "string" }, "plan": { - "$ref": "storage.plan" + "$ref": "storage.plan", + "description": "Describes how to store documents depending on the database or document type" } }, "type": "object" diff --git a/applications/crossbar/priv/couchdb/schemas/system_config.callflow.dynamic_cid.json b/applications/crossbar/priv/couchdb/schemas/system_config.callflow.dynamic_cid.json new file mode 100644 index 00000000000..fb9068a1a53 --- /dev/null +++ b/applications/crossbar/priv/couchdb/schemas/system_config.callflow.dynamic_cid.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "_id": "system_config.callflow.dynamic_cid", + "description": "Schema for callflow.dynamic_cid system_config", + "properties": { + "reject_prompt": { + "default": "dynamic-cid-invalid_using_default", + "description": "callflow.dynamic_cid reject prompt", + "type": "string" + } + }, + "type": "object" +} diff --git a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.json b/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.json index 29e81a0e7ae..42d04da9a05 100644 --- a/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.json +++ b/applications/crossbar/priv/couchdb/schemas/system_config.crossbar.json @@ -41,6 +41,10 @@ "description": "crossbar expiry percentage", "type": "integer" }, + "ip": { + "description": "crossbar ip", + "type": "string" + }, "magic_path_patterns": { "default": [ "/:version/accounts/:account_id/vmboxes/:box_id/messages/:message_id/raw", diff --git a/applications/crossbar/priv/couchdb/schemas/system_config.ecallmgr.json b/applications/crossbar/priv/couchdb/schemas/system_config.ecallmgr.json index 76a8f063744..c0c65824b4c 100644 --- a/applications/crossbar/priv/couchdb/schemas/system_config.ecallmgr.json +++ b/applications/crossbar/priv/couchdb/schemas/system_config.ecallmgr.json @@ -121,9 +121,6 @@ "description": "ecallmgr capabilities", "type": "array" }, - "configuration_handlers": { - "description": "ecallmgr configuration handlers" - }, "debug_channel": { "default": false, "description": "ecallmgr debug channel", @@ -232,48 +229,6 @@ "description": "ecallmgr maximum timeout for node restart", "type": "integer" }, - "modules": { - "default": { - "authn": { - "type": "worker" - }, - "channel": { - "type": "worker" - }, - "channel_hold": { - "type": "worker" - }, - "conference": { - "type": "worker" - }, - "config": { - "type": "worker" - }, - "event_stream_sup": { - "type": "supervisor" - }, - "msg": { - "type": "worker" - }, - "node": { - "type": "worker" - }, - "notify": { - "type": "worker" - }, - "recordings": { - "type": "worker" - }, - "resource": { - "type": "worker" - }, - "route_sup": { - "type": "supervisor" - } - }, - "description": "ecallmgr modules", - "type": "object" - }, "network_map": { "default": {}, "description": "ecallmgr network map", @@ -413,7 +368,6 @@ } }, "required": [ - "configuration_handlers", "default_ringback", "fs_reconnect_cmds", "node_commands", diff --git a/applications/crossbar/priv/couchdb/schemas/system_config.jonny5.json b/applications/crossbar/priv/couchdb/schemas/system_config.jonny5.json index 798bfc043de..0db3fddbf5f 100644 --- a/applications/crossbar/priv/couchdb/schemas/system_config.jonny5.json +++ b/applications/crossbar/priv/couchdb/schemas/system_config.jonny5.json @@ -10,12 +10,12 @@ "description": "jonny5 default twoway trunks" }, "flat_rate_blacklist": { - "default": "^\\+?1(684|264|268|242|246|441|284|345|767|809|829|849|473|671|876|664|670|787|939|869|758|784|721|868|649|340|900|8(?:[0,2,3,4,5,6,7]{2}|8[0-9]))\\d{7}$", + "default": "^\\+1(684|264|268|242|246|441|284|345|767|809|829|849|473|671|876|664|670|787|939|869|758|784|721|868|649|340|900|800|888|877|866|855|844)\\d{7}$", "description": "jonny5 flat rate blacklist", "type": "string" }, "flat_rate_whitelist": { - "default": "^\\+?1\\d{10}$", + "default": "^\\+1\\d{10}$", "description": "jonny5 flat rate whitelist", "type": "string" } diff --git a/applications/crossbar/priv/couchdb/schemas/system_config.number_manager.json b/applications/crossbar/priv/couchdb/schemas/system_config.number_manager.json index ca02cd51d94..a7bb6b9fedd 100644 --- a/applications/crossbar/priv/couchdb/schemas/system_config.number_manager.json +++ b/applications/crossbar/priv/couchdb/schemas/system_config.number_manager.json @@ -69,6 +69,15 @@ "e164_converters": { "description": "number_manager e164 converters" }, + "features": { + "properties": { + "allow": { + "properties": { + "description": "Number features a number is allowed to enable or disable" + } + } + } + }, "fetch_account_from_ports": { "default": true, "description": "number_manager fetch account from ports", @@ -94,11 +103,19 @@ "description": "maximum number of returned DIDs in search query", "type": "integer" }, + "number_search_timeout_ms": { + "default": 5000, + "description": "number manager number search timeout in milliseconds", + "type": "integer" + }, "porting_module_name": { "default": "knm_local", "description": "number manager porting module name", "type": "string" }, + "providers": { + "description": "Number features sub accounts are allowed to enable or disable" + }, "reconcile_regex": { "default": "^\\+?1?\\d{10}$|^\\+[2-9]\\d{7,}$|^011\\d*$|^00\\d*$", "description": "number_manager reconcile regex", @@ -135,6 +152,8 @@ }, "required": [ "e164_converters", + "features", + "providers", "released_state", "should_permanently_delete" ], diff --git a/applications/crossbar/src/api_resource.erl b/applications/crossbar/src/api_resource.erl index 2b8d6b44a5a..f92d23b8ca2 100644 --- a/applications/crossbar/src/api_resource.erl +++ b/applications/crossbar/src/api_resource.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% API resource %%% @end diff --git a/applications/crossbar/src/api_util.erl b/applications/crossbar/src/api_util.erl index 6b7de68dda5..e85e2793121 100644 --- a/applications/crossbar/src/api_util.erl +++ b/applications/crossbar/src/api_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Moved util functions out of v1_resource so only REST-related calls %%% are in there. diff --git a/applications/crossbar/src/cb_apps_maintenance.erl b/applications/crossbar/src/cb_apps_maintenance.erl index dfc9a7740a0..c1b9ea51f11 100644 --- a/applications/crossbar/src/cb_apps_maintenance.erl +++ b/applications/crossbar/src/cb_apps_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/cb_apps_util.erl b/applications/crossbar/src/cb_apps_util.erl index 66215bde73b..2661b60a4a2 100644 --- a/applications/crossbar/src/cb_apps_util.erl +++ b/applications/crossbar/src/cb_apps_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/cb_context.erl b/applications/crossbar/src/cb_context.erl index 7619df0b08b..e6919bb597c 100644 --- a/applications/crossbar/src/cb_context.erl +++ b/applications/crossbar/src/cb_context.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Helpers for manipulating the #cb_context{} record %%% @end diff --git a/applications/crossbar/src/cb_devices_utils.erl b/applications/crossbar/src/cb_devices_utils.erl index edae9e4d3c8..95a4e2fa9c1 100644 --- a/applications/crossbar/src/cb_devices_utils.erl +++ b/applications/crossbar/src/cb_devices_utils.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/cb_mobile_manager.erl b/applications/crossbar/src/cb_mobile_manager.erl index 69ebe6361ac..b8e4dd57b9f 100644 --- a/applications/crossbar/src/cb_mobile_manager.erl +++ b/applications/crossbar/src/cb_mobile_manager.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/crossbar_app.erl b/applications/crossbar/src/crossbar_app.erl index 96ed660dc07..ea3365d7a48 100644 --- a/applications/crossbar/src/crossbar_app.erl +++ b/applications/crossbar/src/crossbar_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/crossbar_auth.erl b/applications/crossbar/src/crossbar_auth.erl index c39b58aba2b..60040f28b5c 100644 --- a/applications/crossbar/src/crossbar_auth.erl +++ b/applications/crossbar/src/crossbar_auth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/crossbar_bindings.erl b/applications/crossbar/src/crossbar_bindings.erl index c3e6d294b9e..e6655d6afda 100644 --- a/applications/crossbar/src/crossbar_bindings.erl +++ b/applications/crossbar/src/crossbar_bindings.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Store routing keys/pid bindings. When a binding is fired, %%% pass the payload to the pid for evaluation, accumulating @@ -181,7 +181,7 @@ modules_loaded() -> -spec is_cb_module(ne_binary() | atom()) -> boolean(). is_cb_module(<<"cb_", _/binary>>) -> 'true'; -is_cb_module(<<"crossbar_", _binary>>) -> 'true'; +is_cb_module(<<"crossbar_", _/binary>>) -> 'true'; is_cb_module(<<_/binary>>) -> 'false'; is_cb_module(Mod) -> is_cb_module(kz_util:to_binary(Mod)). diff --git a/applications/crossbar/src/crossbar_config.erl b/applications/crossbar/src/crossbar_config.erl index bf03e5d55aa..5090a846235 100644 --- a/applications/crossbar/src/crossbar_config.erl +++ b/applications/crossbar/src/crossbar_config.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/crossbar_default_handler.erl b/applications/crossbar/src/crossbar_default_handler.erl index d13ad8f9dc1..5953a1b970a 100644 --- a/applications/crossbar/src/crossbar_default_handler.erl +++ b/applications/crossbar/src/crossbar_default_handler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/crossbar_doc.erl b/applications/crossbar/src/crossbar_doc.erl index 60588ff2bdd..7475bef9346 100644 --- a/applications/crossbar/src/crossbar_doc.erl +++ b/applications/crossbar/src/crossbar_doc.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end @@ -160,20 +160,21 @@ load(DocId, Context, Options, _RespStatus) when is_binary(DocId) -> cb_context:add_system_error('bad_identifier', ErrorCause, Context) end end; + load([], Context, _Options, _RespStatus) -> cb_context:add_system_error('bad_identifier', Context); -load([_|_]=IDs, Context, Opts, _RespStatus) -> - Opts1 = [{'keys', IDs}, 'include_docs' | Opts], - case kz_datamgr:all_docs(cb_context:account_db(Context), Opts1) of +load([_|_]=IDs, Context, Options, _RespStatus) -> + OpenFun = get_bulk_open_function(Options), + case OpenFun(cb_context:account_db(Context), IDs, Options) of {'error', Error} -> handle_datamgr_errors(Error, IDs, Context); {'ok', JObjs} -> - Docs = extract_included_docs(JObjs), - case check_document_type(Context, Docs, Opts) of + {Docs, Context1} = extract_included_docs(Context, JObjs), + case check_document_type(Context1, Docs, Options) of 'true' -> - cb_context:store(handle_datamgr_success(Docs, Context), 'db_doc', Docs); + cb_context:store(handle_datamgr_success(Docs, Context1), 'db_doc', Docs); 'false' -> ErrorCause = kz_json:from_list([{<<"cause">>, IDs}]), - cb_context:add_system_error('bad_identifier', ErrorCause, Context) + cb_context:add_system_error('bad_identifier', ErrorCause, Context1) end end. @@ -184,6 +185,13 @@ get_open_function(Options) -> 'false' -> fun kz_datamgr:open_doc/3 end. +-spec get_bulk_open_function(kz_proplist()) -> function(). +get_bulk_open_function(Options) -> + case props:get_is_true('use_cache', Options, 'true') of + 'true' -> fun kz_datamgr:open_cache_docs/3; + 'false' -> fun kz_datamgr:open_docs/3 + end. + %%-------------------------------------------------------------------- %% @private %% @doc @@ -328,17 +336,19 @@ merge(DataJObj, JObj, Context) -> -spec patch_and_validate(ne_binary(), cb_context:context(), validate_fun()) -> cb_context:context(). +-spec patch_and_validate_doc(ne_binary(), cb_context:context(), validate_fun(), crossbar_status()) -> + cb_context:context(). patch_and_validate(Id, Context, ValidateFun) -> Context1 = load(Id, Context, ?TYPE_CHECK_OPTION_ANY), - Context2 = case cb_context:resp_status(Context1) of - 'success' -> - PubJObj = kz_doc:public_fields(cb_context:req_data(Context)), - PatchedJObj = kz_json:merge_recursive(cb_context:doc(Context1), PubJObj), - cb_context:set_req_data(Context, PatchedJObj); - _Status -> - Context1 - end, - ValidateFun(Id, Context2). + patch_and_validate_doc(Id, Context1, ValidateFun, cb_context:resp_status(Context1)). + +patch_and_validate_doc(Id, Context, ValidateFun, 'success') -> + PubJObj = kz_doc:public_fields(cb_context:req_data(Context)), + PatchedJObj = kz_json:merge(cb_context:doc(Context), PubJObj), + Context1 = cb_context:set_req_data(Context, PatchedJObj), + ValidateFun(Id, Context1); +patch_and_validate_doc(Id, Context, ValidateFun, _RespStatus) -> + ValidateFun(Id, Context). %%-------------------------------------------------------------------- %% @public @@ -1145,7 +1155,7 @@ version_specific_success(JObjs, Context, _Version) -> %% %% @end %%-------------------------------------------------------------------- --spec handle_datamgr_errors(kazoo_data:data_errors(), api_binary() | api_binaries(), cb_context:context()) -> +-spec handle_datamgr_errors(kazoo_data:data_errors(), api_ne_binary() | api_ne_binaries(), cb_context:context()) -> cb_context:context(). handle_datamgr_errors('invalid_db_name', _, Context) -> lager:debug("datastore ~s not_found", [cb_context:account_db(Context)]), @@ -1266,9 +1276,20 @@ add_pvt_auth(JObj, Context) -> %% %% @end %%-------------------------------------------------------------------- --spec extract_included_docs(kz_json:objects()) -> kz_json:objects(). -extract_included_docs(JObjs) -> - [kz_json:get_value(<<"doc">>, JObj) || JObj <- JObjs]. +-spec extract_included_docs(cb_context:context(), kz_json:objects()) -> + {kz_json:objects(), cb_context:context()}. +extract_included_docs(Context, JObjs) -> + lists:foldl(fun extract_included_docs_fold/2, {[], Context}, JObjs). + +extract_included_docs_fold(JObj, {Docs, Context}) -> + case kz_json:get_ne_value(<<"doc">>, JObj) of + undefined -> + Reason = kz_json:get_ne_value(<<"error">>, JObj), + ID = kz_json:get_ne_value(<<"key">>, JObj), + {Docs, handle_datamgr_errors(kz_util:to_atom(Reason,true), ID, Context)}; + Doc -> + {[Doc|Docs], Context} + end. %%-------------------------------------------------------------------- %% @public @@ -1279,9 +1300,7 @@ extract_included_docs(JObjs) -> %%-------------------------------------------------------------------- -spec has_qs_filter(cb_context:context()) -> boolean(). has_qs_filter(Context) -> - kz_json:any(fun is_filter_key/1 - ,cb_context:query_string(Context) - ). + kz_json:any(fun is_filter_key/1, cb_context:query_string(Context)). %%-------------------------------------------------------------------- %% @private diff --git a/applications/crossbar/src/crossbar_filter.erl b/applications/crossbar/src/crossbar_filter.erl index be5d2572e80..28c9abb4b3e 100644 --- a/applications/crossbar/src/crossbar_filter.erl +++ b/applications/crossbar/src/crossbar_filter.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/crossbar_freeswitch.erl b/applications/crossbar/src/crossbar_freeswitch.erl index b0319c55926..51d77030be3 100644 --- a/applications/crossbar/src/crossbar_freeswitch.erl +++ b/applications/crossbar/src/crossbar_freeswitch.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Create freeswitch offline configuration diff --git a/applications/crossbar/src/crossbar_init.erl b/applications/crossbar/src/crossbar_init.erl index a67617906d9..e518b067d65 100644 --- a/applications/crossbar/src/crossbar_init.erl +++ b/applications/crossbar/src/crossbar_init.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -190,8 +190,11 @@ maybe_start_plaintext(Dispatch) -> Workers = kapps_config:get_integer(?CONFIG_CAT, <<"workers">>, 100), %% Name, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts - try cowboy:start_http('api_resource', Workers - ,[{'ip', {0,0,0,0,0,0,0,0}} + try + IP = get_binding_ip(), + lager:info("trying to bind to address ~s port ~b", [inet:ntoa(IP), Port]), + cowboy:start_http('api_resource', Workers + ,[{'ip', IP} ,{'port', Port} ] ,[{'env', [{'dispatch', Dispatch} @@ -201,7 +204,8 @@ maybe_start_plaintext(Dispatch) -> ,{'onresponse', fun on_response/4} ,{'compress', ?USE_COMPRESSION} ] - ) of + ) + of {'ok', _} -> lager:info("started plaintext API server"); {'error', {'already_started', _P}} -> @@ -212,6 +216,56 @@ maybe_start_plaintext(Dispatch) -> end end. +-spec get_binding_ip() -> inet:ip_address(). +get_binding_ip() -> + IsIPv6Enabled = is_ip_family_supported("localhost", 'inet6'), + IsIPv4Enabled = is_ip_family_supported("localhost", 'inet'), + + %% expilicty convert to list to allow save the default value in human readable value + IP = kz_util:to_list(kapps_config:get_binary(?CONFIG_CAT, <<"ip">>, default_ip())), + + {'ok', DefaultIP} = inet:parse_address(kz_util:to_list(default_ip(IsIPv6Enabled))), + {'ok', DefaultIPv4} = inet:parse_address(kz_util:to_list(default_ip('false'))), + {'ok', DefaultIPv6} = inet:parse_address(kz_util:to_list(default_ip('true'))), + + case inet:parse_ipv6strict_address(IP) of + {'ok', IPv6} when IsIPv6Enabled -> IPv6; + {'ok', _} when IsIPv4Enabled -> + lager:warning("address ~s is ipv6, but ipv6 is not supported by the system, enforcing default ipv4 ~s" + ,[IP, inet:ntoa(DefaultIPv4)] + ), + DefaultIPv4; + {'error', 'einval'} -> + case inet:parse_ipv4strict_address(IP) of + {'ok', IPv4} when IsIPv4Enabled -> IPv4; + {'ok', _} when IsIPv6Enabled-> + lager:warning("address ~s is ipv4, but ipv4 is not supported by the system, enforcing default ipv6 ~s" + ,[IP, inet:ntoa(DefaultIPv6)] + ), + DefaultIPv6; + {'error', 'einval'} -> + lager:warning("address ~s is not a valid ipv6 or ipv4 address, enforcing default ip ~s" + ,[IP, inet:ntoa(DefaultIP)] + ), + DefaultIP + end + end. + +-spec default_ip() -> ne_binary(). +default_ip() -> + default_ip(is_ip_family_supported("localhost", 'inet6')). + +-spec default_ip(boolean()) -> ne_binary(). +default_ip('true') -> <<"::">>; +default_ip('false') -> <<"0.0.0.0">>. + +-spec is_ip_family_supported(string(), inet:address_family()) -> boolean(). +is_ip_family_supported(Host, Family) -> + case inet:getaddr(Host, Family) of + {'ok', _} -> 'true'; + {'error', _} -> 'false' + end. + -spec maybe_start_ssl(cowboy_router:dispatch_rules()) -> 'ok'. maybe_start_ssl(Dispatch) -> case kapps_config:get_is_true(?CONFIG_CAT, <<"use_ssl">>, 'false') of @@ -229,8 +283,15 @@ start_ssl(Dispatch) -> ReqTimeout = kapps_config:get_integer(?CONFIG_CAT, <<"request_timeout_ms">>, 10 * ?MILLISECONDS_IN_SECOND), Workers = kapps_config:get_integer(?CONFIG_CAT, <<"ssl_workers">>, 100), - try cowboy:start_https('api_resource_ssl', Workers - ,SSLOpts + try + IP = get_binding_ip(), + lager:info("trying to bind SSL API server to address ~s port ~b" + ,[inet:ntoa(IP) + ,props:get_value('port', SSLOpts) + ] + ), + cowboy:start_https('api_resource_ssl', Workers + ,[{'ip', IP} | SSLOpts] ,[{'env', [{'dispatch', Dispatch} ,{'timeout', ReqTimeout} ]} diff --git a/applications/crossbar/src/crossbar_maintenance.erl b/applications/crossbar/src/crossbar_maintenance.erl index f8cfe9ac229..549207f14fa 100644 --- a/applications/crossbar/src/crossbar_maintenance.erl +++ b/applications/crossbar/src/crossbar_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end @@ -35,6 +35,15 @@ -export([init_apps/2, init_app/2]). -export([init_apps/1, init_app/1]). +-export([apps/0, app/1 + ,set_app_field/3%, set_app_field/4, set_app_field/5 + ,set_app_label/2 + ,set_app_description/2 + ,set_app_extended_description/2 + ,set_app_features/2 + ,set_app_icon/2 + ,set_app_screenshots/2 + ]). -include("crossbar.hrl"). -include_lib("kazoo/include/kz_system_config.hrl"). @@ -818,7 +827,7 @@ maybe_create_app(AppPath, MetaData, MasterAccountDb) -> {'error', _E} -> io:format(" failed to find app ~s: ~p", [AppName, _E]) end. --spec maybe_update_app(file:filename_all(), kz_json:object(), ne_binary(), kz_json:object()) -> 'ok'. +-spec maybe_update_app(file:filename_all(), kz_json:object(), ne_binary(), kz_json:object()) -> no_return. maybe_update_app(AppPath, MetaData, MasterAccountDb, AppJObj) -> ApiUrlKey = <<"api_url">>, CurrentDocId = kzd_app:id(AppJObj), @@ -845,7 +854,7 @@ find_app(Db, Name) -> -spec create_app(file:filename_all(), kz_json:object(), ne_binary()) -> 'ok'. create_app(AppPath, MetaData, MasterAccountDb) -> Doc0 = kz_doc:update_pvt_parameters(MetaData, MasterAccountDb, [{'type', <<"app">>}]), - Doc = kz_json:delete_keys([<<"source_url">>], Doc0), + Doc = kz_json:delete_key(<<"source_url">>, Doc0), case kz_datamgr:save_doc(MasterAccountDb, Doc) of {'ok', AppJObj} -> AppId = kzd_app:id(AppJObj), @@ -871,7 +880,7 @@ safe_delete_image(AccountDb, AppId, Image) -> kz_datamgr:delete_attachment(AccountDb, AppId, Image) end. --spec maybe_add_images(file:filename_all(), ne_binary(), kz_json:object(), ne_binary()) -> 'ok'. +-spec maybe_add_images(file:filename_all(), ne_binary(), kz_json:object(), ne_binary()) -> no_return. maybe_add_images(AppPath, ?NE_BINARY=AppId, MetaData, MasterAccountDb) -> Icon = kzd_app:icon(MetaData), Screenshots = kzd_app:screenshots(MetaData), @@ -879,9 +888,16 @@ maybe_add_images(AppPath, ?NE_BINARY=AppId, MetaData, MasterAccountDb) -> SShotPaths = [{SShot, filename:join([AppPath, <<"metadata">>, <<"screenshots">>, SShot])} || SShot <- Screenshots ], + update_icon(AppId, MasterAccountDb, IconPath), + update_screenshots(AppId, MasterAccountDb, SShotPaths). + +update_icon(AppId, MA, IconPath) -> + update_images(AppId, MA, [IconPath], <<"icon">>), + no_return. - _ = update_images(AppId, MasterAccountDb, [IconPath], <<"icon">>), - _ = update_images(AppId, MasterAccountDb, SShotPaths, <<"screenshots">>). +update_screenshots(AppId, MA, SShotPaths) -> + update_images(AppId, MA, SShotPaths, <<"screenshots">>), + no_return. -type image_path() :: {file:filename_all(), file:filename_all()}. -type image_paths() :: [image_path()]. @@ -934,3 +950,104 @@ find_metadata(AppPath) -> {'error', Errors} -> {'invalid_data', [Error || {'data_invalid', _, Error, _, _} <- Errors]} end. + +-spec apps() -> no_return. +apps() -> + {ok, MA} = kapps_util:get_master_account_db(), + case kz_datamgr:get_results(MA, ?CB_APPS_STORE_LIST) of + {error, _R} -> lager:debug("failed to read apps in ~s: ~p", [MA, _R]); + {ok, JObjs} -> lists:foreach(fun print_app/1, JObjs) + end, + no_return. + +-spec app(ne_binary()) -> no_return. +app(AppNameOrId) -> + {ok, MA} = kapps_util:get_master_account_db(), + case find_app(MA, AppNameOrId) of + {ok, AppJObj} -> print_app(AppJObj); + {error, _} -> + case kz_datamgr:open_doc(MA, AppNameOrId) of + {ok, AppJObj} -> print_app(view_app(AppJObj)); + _ -> io:format("unknown app\n"), no_return + end + end. + +view_app(AppJObj) -> + M = maps:with([<<"name">>, <<"id">>, <<"phase">>, <<"i18n">> + ,<<"tags">>, <<"api_url">>, <<"source_url">>, <<"published">> + ] + ,kz_json:to_map(AppJObj) + ), + kz_json:from_list([{<<"key">>, kzd_app:name(AppJObj)} + ,{<<"value">>, kz_json:from_map(M)} + ]). + +print_app(AppJObj) -> + io:format("App ~s\n", [kz_json:get_ne_value(<<"key">>, AppJObj)]), + _ = put(pp_lvl, 1), + _ = print_k_v(kz_json:get_value(<<"value">>, AppJObj)), + io:format("\n"), + no_return. + +print_k_v(JObj) -> kz_json:map(fun print_k_v/2, JObj). +print_k_v(K, V) -> + Lvl = get(pp_lvl), + Indent = string:copies(" ", Lvl), + case kz_json:is_json_object(V) of + false -> io:format("~s~s: ~s\n", [Indent, K, kz_json:encode(V)]); + true -> + io:format("~s~s:\n", [Indent, K]), + _ = put(pp_lvl, Lvl + 1), + print_k_v(V), + _ = put(pp_lvl, Lvl) + end. + +update_app(AppId, Path, Value) -> + case lists:last(Path) of + <<"_id">> -> ok; + <<"pvt_", _/binary>> -> ok; + ?NE_BINARY -> + {ok, MA} = kapps_util:get_master_account_db(), + Update = [{Path, Value}], + case kz_datamgr:update_doc(MA, AppId, Update) of + {ok, _} -> app(AppId); + {error, _R} -> io:format("updating ~s failed: ~p\n", [AppId, _R]) + end + end, + no_return. + +-spec set_app_field(ne_binary(), ne_binary(), ne_binary()) -> no_return. +set_app_field(AppId, Field, Value) -> + update_app(AppId, [Field], Value). + +-spec set_app_label(ne_binary(), ne_binary()) -> no_return. +-spec set_app_description(ne_binary(), ne_binary()) -> no_return. +-spec set_app_extended_description(ne_binary(), ne_binary()) -> no_return. +-spec set_app_features(ne_binary(), ne_binary()) -> no_return. +set_app_label(AppId, Value) -> + update_app(AppId, [<<"i18n">>, <<"en-US">>, <<"label">>], Value). +set_app_description(AppId, Value) -> + update_app(AppId, [<<"i18n">>, <<"en-US">>, <<"description">>], Value). +set_app_extended_description(AppId, Value) -> + update_app(AppId, [<<"i18n">>, <<"en-US">>, <<"extended_description">>], Value). +set_app_features(AppId, Value) -> + Values = [V || V <- binary:split(Value, <<$@>>, [global]), + V =/= <<>> + ], + update_app(AppId, [<<"i18n">>, <<"en-US">>, <<"features">>], Values). + +-spec set_app_icon(ne_binary(), ne_binary()) -> no_return. +set_app_icon(AppId, PathToPNGIcon) -> + {ok, MA} = kapps_util:get_master_account_db(), + io:format("Processing...\n"), + Icon = {filename:basename(PathToPNGIcon), PathToPNGIcon}, + update_icon(AppId, MA, Icon). + +-spec set_app_screenshots(ne_binary(), ne_binary()) -> no_return. +set_app_screenshots(AppId, PathToScreenshotsFolder) -> + {ok, MA} = kapps_util:get_master_account_db(), + io:format("Processing...\n"), + SShots = [{filename:basename(SShot), SShot} + || SShot <- filelib:wildcard(kz_util:to_list(PathToScreenshotsFolder) ++ "/*.png") + ], + update_screenshots(AppId, MA, SShots). diff --git a/applications/crossbar/src/crossbar_module_sup.erl b/applications/crossbar/src/crossbar_module_sup.erl index f9df2d374c5..95c70318946 100644 --- a/applications/crossbar/src/crossbar_module_sup.erl +++ b/applications/crossbar/src/crossbar_module_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/crossbar_services.erl b/applications/crossbar/src/crossbar_services.erl index 6acaea3f40e..ac05a6e6f92 100644 --- a/applications/crossbar/src/crossbar_services.erl +++ b/applications/crossbar/src/crossbar_services.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end @@ -13,7 +13,7 @@ ]). -include("crossbar.hrl"). --include_lib("kazoo_number_manager/include/knm_phone_number.hrl"). %% PVT_FEATURES +-include_lib("kazoo_number_manager/include/knm_phone_number.hrl"). %% FEATURE_PORT %%-------------------------------------------------------------------- %% @public @@ -197,9 +197,10 @@ calc_service_updates(Context, <<"limits">>) -> ]), kz_service_limits:reconcile(Services, Updates); calc_service_updates(Context, <<"port_request">>) -> + PortNumbers = kz_json:get_value(<<"numbers">>, cb_context:doc(Context)), PhoneNumbers = - [knm_phone_number:set_feature(knm_phone_number:from_json(JObj), ?FEATURE_PORT, kz_json:new()) - || JObj <- kz_json:values(<<"numbers">>, cb_context:doc(Context)) + [knm_phone_number:set_feature(create_phone_number(Num, kz_json:values(Num, PortNumbers)), ?FEATURE_PORT, kz_json:new()) + || Num <- kz_json:get_keys(PortNumbers) ], kz_service_phone_numbers:reconcile(fetch_service(Context), PhoneNumbers); calc_service_updates(Context, <<"app">>) -> @@ -233,6 +234,16 @@ calc_service_updates(_Context, _Type, _Props) -> lager:warning("unknown type ~p, cannot execute dry run", [_Type]), 'undefined'. +-spec create_phone_number(ne_binary(), list() | kz_json:object()) -> + knm_phone_number:knm_phone_number(). +create_phone_number(Number, Features) -> + JObj = kz_json:from_list( + [{<<"_id">>, Number} + ,{<<"features">>, Features} + ] + ), + knm_phone_number:from_json(JObj). + %%-------------------------------------------------------------------- %% @private %% @doc diff --git a/applications/crossbar/src/crossbar_sup.erl b/applications/crossbar/src/crossbar_sup.erl index 2b697a2db6c..dbef5deef84 100644 --- a/applications/crossbar/src/crossbar_sup.erl +++ b/applications/crossbar/src/crossbar_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/crossbar_util.erl b/applications/crossbar/src/crossbar_util.erl index 5c663e1fb3b..ab93329028c 100644 --- a/applications/crossbar/src/crossbar_util.erl +++ b/applications/crossbar/src/crossbar_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end @@ -1099,7 +1099,7 @@ format_emergency_caller_id_number(Context) -> end. format_emergency_caller_id_number(Context, Emergency) -> - case kz_json:get_value(<<"number">>, Emergency) of + case kz_json:get_ne_binary_value(<<"number">>, Emergency) of 'undefined' -> Context; Number -> NEmergency = kz_json:set_value(<<"number">>, knm_converters:normalize(Number), Emergency), diff --git a/applications/crossbar/src/crossbar_view.erl b/applications/crossbar/src/crossbar_view.erl index 3149ce5fc6f..c445d9865e9 100644 --- a/applications/crossbar/src/crossbar_view.erl +++ b/applications/crossbar/src/crossbar_view.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_about.erl b/applications/crossbar/src/modules/cb_about.erl index 53365540204..25612b06d6c 100644 --- a/applications/crossbar/src/modules/cb_about.erl +++ b/applications/crossbar/src/modules/cb_about.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Display various informations %%% diff --git a/applications/crossbar/src/modules/cb_access_lists.erl b/applications/crossbar/src/modules/cb_access_lists.erl index d3cfe5afe4b..9f462ef7c17 100644 --- a/applications/crossbar/src/modules/cb_access_lists.erl +++ b/applications/crossbar/src/modules/cb_access_lists.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Acess lists diff --git a/applications/crossbar/src/modules/cb_accounts.erl b/applications/crossbar/src/modules/cb_accounts.erl index 45f13b02fea..1567a27838c 100644 --- a/applications/crossbar/src/modules/cb_accounts.erl +++ b/applications/crossbar/src/modules/cb_accounts.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Account module %%% @@ -1000,10 +1000,11 @@ fix_start_key([StartKey|_T]) -> StartKey. -spec load_account_tree(cb_context:context()) -> cb_context:context(). load_account_tree(Context) -> Tree = get_authorized_account_tree(Context), - Options = [{'keys', Tree}, 'include_docs'], - case kz_datamgr:all_docs(?KZ_ACCOUNTS_DB, Options) of + case kz_datamgr:open_cache_docs(?KZ_ACCOUNTS_DB, Tree) of {'error', R} -> crossbar_doc:handle_datamgr_errors(R, ?KZ_ACCOUNTS_DB, Context); - {'ok', JObjs} -> format_account_tree_results(Context, JObjs) + {'ok', JObjs} -> + %%FIXME: extract & handle errors from JObjs + format_account_tree_results(Context, JObjs) end. -spec get_authorized_account_tree(cb_context:context()) -> ne_binaries(). @@ -1387,6 +1388,7 @@ load_initial_views(Context)-> [{FirstId, _}|_] = Views = kapps_maintenance:get_all_account_views(), {LastId, _} = lists:last(Views), kapps_util:update_views(cb_context:account_db(Context), Views, 'true'), + _ = kazoo_number_manager_maintenance:update_number_services_view(cb_context:account_db(Context)), ensure_views(Context, [FirstId, LastId]). -spec ensure_views(cb_context:context(), ne_binaries()) -> 'ok'. diff --git a/applications/crossbar/src/modules/cb_acls.erl b/applications/crossbar/src/modules/cb_acls.erl index 5421114dc73..dacaaa8ff8f 100644 --- a/applications/crossbar/src/modules/cb_acls.erl +++ b/applications/crossbar/src/modules/cb_acls.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% ACLs from 7 to 77 diff --git a/applications/crossbar/src/modules/cb_agents.erl b/applications/crossbar/src/modules/cb_agents.erl index 42770564f15..59ef8e4968f 100644 --- a/applications/crossbar/src/modules/cb_agents.erl +++ b/applications/crossbar/src/modules/cb_agents.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% CRUD for call queues diff --git a/applications/crossbar/src/modules/cb_alerts.erl b/applications/crossbar/src/modules/cb_alerts.erl index 860b445252e..dea8f416755 100644 --- a/applications/crossbar/src/modules/cb_alerts.erl +++ b/applications/crossbar/src/modules/cb_alerts.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Listing of all expected v1 callbacks diff --git a/applications/crossbar/src/modules/cb_allotments.erl b/applications/crossbar/src/modules/cb_allotments.erl index eebb8647e54..f93e53cb74e 100644 --- a/applications/crossbar/src/modules/cb_allotments.erl +++ b/applications/crossbar/src/modules/cb_allotments.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_api_auth.erl b/applications/crossbar/src/modules/cb_api_auth.erl index 9d265f8f7b5..6aa48e78d29 100644 --- a/applications/crossbar/src/modules/cb_api_auth.erl +++ b/applications/crossbar/src/modules/cb_api_auth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Account API auth module %%% diff --git a/applications/crossbar/src/modules/cb_apps_link.erl b/applications/crossbar/src/modules/cb_apps_link.erl index b4e875d11fa..94615313b54 100644 --- a/applications/crossbar/src/modules/cb_apps_link.erl +++ b/applications/crossbar/src/modules/cb_apps_link.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Listing of all expected v1 callbacks diff --git a/applications/crossbar/src/modules/cb_apps_store.erl b/applications/crossbar/src/modules/cb_apps_store.erl index 5b9cde65a63..253e98a4e9f 100644 --- a/applications/crossbar/src/modules/cb_apps_store.erl +++ b/applications/crossbar/src/modules/cb_apps_store.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% Listing of all expected v1 callbacks diff --git a/applications/crossbar/src/modules/cb_auth.erl b/applications/crossbar/src/modules/cb_auth.erl index 9a70075c87d..0d681439069 100644 --- a/applications/crossbar/src/modules/cb_auth.erl +++ b/applications/crossbar/src/modules/cb_auth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_basic_auth.erl b/applications/crossbar/src/modules/cb_basic_auth.erl index af7ad038be0..0cc0472d83c 100644 --- a/applications/crossbar/src/modules/cb_basic_auth.erl +++ b/applications/crossbar/src/modules/cb_basic_auth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Basic auth module %%% diff --git a/applications/crossbar/src/modules/cb_blacklists.erl b/applications/crossbar/src/modules/cb_blacklists.erl index 3bc56f52f23..c301f74e9c2 100644 --- a/applications/crossbar/src/modules/cb_blacklists.erl +++ b/applications/crossbar/src/modules/cb_blacklists.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_braintree.erl b/applications/crossbar/src/modules/cb_braintree.erl index d1758996e9e..f01144a9699 100644 --- a/applications/crossbar/src/modules/cb_braintree.erl +++ b/applications/crossbar/src/modules/cb_braintree.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Handle client requests for braintree documents diff --git a/applications/crossbar/src/modules/cb_bulk.erl b/applications/crossbar/src/modules/cb_bulk.erl index 966b74ce323..1accebfd310 100644 --- a/applications/crossbar/src/modules/cb_bulk.erl +++ b/applications/crossbar/src/modules/cb_bulk.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% Listing of all expected v1 callbacks diff --git a/applications/crossbar/src/modules/cb_call_inspector.erl b/applications/crossbar/src/modules/cb_call_inspector.erl index f29ec1c07ca..42e6c1f8818 100644 --- a/applications/crossbar/src/modules/cb_call_inspector.erl +++ b/applications/crossbar/src/modules/cb_call_inspector.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_callflows.erl b/applications/crossbar/src/modules/cb_callflows.erl index 9566e856ccb..c444b95b492 100644 --- a/applications/crossbar/src/modules/cb_callflows.erl +++ b/applications/crossbar/src/modules/cb_callflows.erl @@ -1,5 +1,5 @@ %%%---------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Callflow gen server for CRUD %%% @@ -34,7 +34,7 @@ %%% API %%%=================================================================== --spec init() -> ok. +-spec init() -> 'ok'. init() -> _ = cb_modules_util:bind(?MODULE, [{<<"*.allowed_methods.callflows">>, 'allowed_methods'} ,{<<"*.resource_exists.callflows">>, 'resource_exists'} @@ -44,7 +44,7 @@ init() -> ,{<<"*.execute.patch.callflows">>, 'patch'} ,{<<"*.execute.delete.callflows">>, 'delete'} ]), - ok. + 'ok'. %%-------------------------------------------------------------------- %% @public @@ -413,7 +413,7 @@ maybe_reconcile_numbers(Context) -> Options = [{'assign_to', cb_context:account_id(Context)} ,{'dry_run', not cb_context:accepting_charges(Context)} ], - _ = knm_numbers:reconcile(lists:filter(fun knm_converters:is_reconcilable/1, NewNumbers), Options), + _ = knm_numbers:reconcile(NewNumbers, Options), Context end. @@ -430,8 +430,8 @@ track_assignment('post', Context) -> Unassigned = [{Num, 'undefined'} || Num <- OldNums, - not lists:member(Num, NewNums) - andalso Num =/= <<"undefined">> + not lists:member(Num, NewNums), + Num =/= <<"undefined">> ], Assigned = [{Num, kzd_callflow:type()} || Num <- NewNums, diff --git a/applications/crossbar/src/modules/cb_cccps.erl b/applications/crossbar/src/modules/cb_cccps.erl index 02652713e2e..e697db94d77 100644 --- a/applications/crossbar/src/modules/cb_cccps.erl +++ b/applications/crossbar/src/modules/cb_cccps.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_cdrs.erl b/applications/crossbar/src/modules/cb_cdrs.erl index 27c3d41953e..7ae5cfc6951 100644 --- a/applications/crossbar/src/modules/cb_cdrs.erl +++ b/applications/crossbar/src/modules/cb_cdrs.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% CDR @@ -38,9 +38,12 @@ -define(CB_INTERACTION_LIST, <<"cdrs/interaction_listing">>). -define(CB_INTERACTION_LIST_BY_USER, <<"cdrs/interaction_listing_by_owner">>). -define(CB_INTERACTION_LIST_BY_ID, <<"cdrs/interaction_listing_by_id">>). +-define(CB_SUMMARY_VIEW, <<"cdrs/summarize_cdrs">>). +-define(CB_SUMMARY_LIST, <<"format_summary">>). -define(PATH_INTERACTION, <<"interaction">>). -define(PATH_LEGS, <<"legs">>). +-define(PATH_SUMMARY, <<"summary">>). -define(KEY_CCV, <<"custom_channel_vars">>). @@ -194,6 +197,8 @@ allowed_methods() -> [?HTTP_GET]. allowed_methods(?PATH_INTERACTION) -> [?HTTP_GET]; +allowed_methods(?PATH_SUMMARY) -> + [?HTTP_GET]; allowed_methods(_CDRId) -> [?HTTP_GET]. allowed_methods(?PATH_LEGS, _InteractionId) -> @@ -246,6 +251,8 @@ validate(Context) -> validate(Context, ?PATH_INTERACTION) -> load_interaction_cdr_summary(Context, cb_context:req_nouns(Context)); +validate(Context, ?PATH_SUMMARY) -> + load_cdr_summary(Context); validate(Context, CDRId) -> load_cdr(CDRId, Context). @@ -320,6 +327,69 @@ load_interaction_cdr_summary(Context, _Nouns) -> lager:debug("invalid URL chain for interaction cdr summary request"), cb_context:add_system_error('faulty_request', Context). +-spec load_cdr_summary(cb_context:context()) -> cb_context:context(). +load_cdr_summary(Context) -> + lager:debug("loading cdr summary for account ~s" + ,[cb_context:account_id(Context)] + ), + case create_view_options('undefined' + ,fun create_summary_view_options/4 + ,Context + ) + of + {'ok', ViewOptions} -> + AccountId = cb_context:account_id(Context), + DBs = chunked_dbs(AccountId, ViewOptions, fun view_option/2), + load_cdr_summary(Context, ViewOptions, DBs); + ErrorContext -> ErrorContext + end. + +-spec load_cdr_summary(cb_context:context(), kz_proplist(), ne_binaries()) -> cb_context:context(). +load_cdr_summary(Context, _, []) -> + cb_context:set_resp_status(Context, 'success'); +load_cdr_summary(Context, ViewOptions, [Db|Dbs]) -> + Context1 = cb_context:set_account_db(Context, Db), + Context2 = crossbar_doc:load_view( + ?CB_SUMMARY_VIEW + ,ViewOptions + ,Context1 + ,fun normalize_summary_results/2 + ), + case cb_context:resp_status(Context2) of + 'success' -> + load_cdr_summary( + combine_cdr_summary(Context, Context2) + ,ViewOptions + ,Dbs + ); + _Else -> Context2 + end. + +-spec combine_cdr_summary(cb_context:context(), cb_context:context()) -> cb_context:context(). +combine_cdr_summary(Context1, Context2) -> + JObj1 = cb_context:resp_data(Context1), + [JObj2|_] = cb_context:doc(Context2), + cb_context:set_resp_data(Context1, merge_cdr_summary(JObj1, JObj2)). + +-spec merge_cdr_summary(api_object(), kz_json:object()) -> kz_json:object(). +merge_cdr_summary('undefined', JObj2) -> + merge_cdr_summary(kz_json:new(), JObj2); +merge_cdr_summary(JObj1, JObj2) -> + kz_json:foldl(fun(Key2, Value2, JObj) -> + case kz_json:get_value(Key2, JObj1) of + 'undefined' -> kz_json:set_value(Key2, Value2, JObj); + Value1 when is_integer(Value1) -> + kz_json:set_value(Key2, Value1 + Value2, JObj); + Value1 -> + Value = merge_cdr_summary(Value1, Value2), + kz_json:set_value(Key2, Value, JObj) + end + end, JObj1, JObj2). + +-spec normalize_summary_results(kz_json:object(), kz_json:objects()) -> kz_json:objects(). +normalize_summary_results(JObj, Acc) -> + [JObj | Acc]. + %%-------------------------------------------------------------------- %% @private %% @doc @@ -381,6 +451,15 @@ create_interaction_view_options(OwnerId, Context, CreatedFrom, CreatedTo) -> ,'descending' ]}. +-spec create_summary_view_options(api_binary(), cb_context:context(), pos_integer(), pos_integer()) -> + {'ok', crossbar_doc:view_options()}. +create_summary_view_options(_, _, CreatedFrom, CreatedTo) -> + {'ok', [{'startkey', CreatedTo} + ,{'endkey', CreatedFrom} + ,{'list', ?CB_SUMMARY_LIST} + ,'descending' + ]}. + %%-------------------------------------------------------------------- %% @private %% @doc @@ -546,11 +625,7 @@ load_chunked_cdrs(Db, Ids, {_, Context}=Payload) -> 'true' -> {Ids, []}; 'false' -> lists:split(?MAX_BULK, Ids) end, - ViewOptions = [{'keys', BulkIds} - ,{'doc_type', <<"cdr">>} - ,'include_docs' - ], - case kz_datamgr:all_docs(Db, ViewOptions) of + case kz_datamgr:open_cache_docs(Db, BulkIds, [{'doc_type', <<"cdr">>}]) of {'ok', Results} -> HasQSFilter = crossbar_doc:has_qs_filter(Context), JObjs = [kz_json:get_value(<<"doc">>, Result) diff --git a/applications/crossbar/src/modules/cb_channels.erl b/applications/crossbar/src/modules/cb_channels.erl index 5983b196472..1531e3acd46 100644 --- a/applications/crossbar/src/modules/cb_channels.erl +++ b/applications/crossbar/src/modules/cb_channels.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_clicktocall.erl b/applications/crossbar/src/modules/cb_clicktocall.erl index 9546d5dfd55..95fd0d69249 100644 --- a/applications/crossbar/src/modules/cb_clicktocall.erl +++ b/applications/crossbar/src/modules/cb_clicktocall.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Click to call @@ -451,10 +451,11 @@ build_originate_req(Contact, Context) -> ,{<<"Auto-Answer-Loopback">>, AutoAnswer} ,{<<"Authorizing-ID">>, kz_doc:id(JObj)} ,{<<"Inherit-Codec">>, <<"false">>} - ,{<<"Authorizing-Type">>, <<"device">>} + ,{<<"Authorizing-Type">>, <<"clicktocall">>} ,{<<"Loopback-Request-URI">>, <>} ,{<<"From-URI">>, <>} ,{<<"Request-URI">>, <>} + ,{<<"Retain-CID">>, 'true'} ], Endpoint = [{<<"Invite-Format">>, <<"loopback">>} @@ -488,12 +489,12 @@ build_originate_req(Contact, Context) -> ,{<<"Custom-SIP-Headers">>, kz_json:get_value(<<"custom_sip_headers">>, JObj)} ,{<<"Custom-Channel-Vars">>, kz_json:from_list(CCVs)} ,{<<"Export-Custom-Channel-Vars">>, [<<"Account-ID">>, <<"Authorizing-ID">>, <<"Authorizing-Type">> - ,<<"Auto-Answer-Loopback">>, <<"Loopback-Request-URI">> + ,<<"Loopback-Request-URI">> ,<<"From-URI">>, <<"Request-URI">> ] } - ,{<<"Simplify-Loopback">>, <<"true">>} - ,{<<"Loopback-Bowout">>, <<"true">>} + ,{<<"Simplify-Loopback">>, <<"false">>} + ,{<<"Loopback-Bowout">>, <<"false">>} ,{<<"Start-Control-Process">>, <<"false">>} | kz_api:default_headers(<<"resource">>, <<"originate_req">>, ?APP_NAME, ?APP_VERSION) ]). diff --git a/applications/crossbar/src/modules/cb_comments.erl b/applications/crossbar/src/modules/cb_comments.erl index 29ebb91e914..494bb8e4ab6 100644 --- a/applications/crossbar/src/modules/cb_comments.erl +++ b/applications/crossbar/src/modules/cb_comments.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Listing of all expected v1 callbacks diff --git a/applications/crossbar/src/modules/cb_conferences.erl b/applications/crossbar/src/modules/cb_conferences.erl index 642c7a0c9ec..6527ceb356f 100644 --- a/applications/crossbar/src/modules/cb_conferences.erl +++ b/applications/crossbar/src/modules/cb_conferences.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Conferences module %%% diff --git a/applications/crossbar/src/modules/cb_configs.erl b/applications/crossbar/src/modules/cb_configs.erl index 871dbcfb5a5..56e5d44e578 100644 --- a/applications/crossbar/src/modules/cb_configs.erl +++ b/applications/crossbar/src/modules/cb_configs.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Listing of all expected v1 callbacks diff --git a/applications/crossbar/src/modules/cb_connectivity.erl b/applications/crossbar/src/modules/cb_connectivity.erl index cefe98f69b3..1cabde48087 100644 --- a/applications/crossbar/src/modules/cb_connectivity.erl +++ b/applications/crossbar/src/modules/cb_connectivity.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Handle client requests for connectivity documents diff --git a/applications/crossbar/src/modules/cb_contact_list.erl b/applications/crossbar/src/modules/cb_contact_list.erl index 24ea49f35e0..9c312492b52 100644 --- a/applications/crossbar/src/modules/cb_contact_list.erl +++ b/applications/crossbar/src/modules/cb_contact_list.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% Listing of all expected v1 callbacks diff --git a/applications/crossbar/src/modules/cb_dialplans.erl b/applications/crossbar/src/modules/cb_dialplans.erl index b8a3ac0f5f9..775b0866e38 100644 --- a/applications/crossbar/src/modules/cb_dialplans.erl +++ b/applications/crossbar/src/modules/cb_dialplans.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_directories.erl b/applications/crossbar/src/modules/cb_directories.erl index b56ee652889..c64cfeb6086 100644 --- a/applications/crossbar/src/modules/cb_directories.erl +++ b/applications/crossbar/src/modules/cb_directories.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% Handle CRUD operations for Directories diff --git a/applications/crossbar/src/modules/cb_faxboxes.erl b/applications/crossbar/src/modules/cb_faxboxes.erl index 1e2bdefb46d..a71951df4ed 100644 --- a/applications/crossbar/src/modules/cb_faxboxes.erl +++ b/applications/crossbar/src/modules/cb_faxboxes.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% Fax Box API diff --git a/applications/crossbar/src/modules/cb_faxes.erl b/applications/crossbar/src/modules/cb_faxes.erl index b6906f07ea2..fb6ca8d1c10 100644 --- a/applications/crossbar/src/modules/cb_faxes.erl +++ b/applications/crossbar/src/modules/cb_faxes.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% diff --git a/applications/crossbar/src/modules/cb_freeswitch.erl b/applications/crossbar/src/modules/cb_freeswitch.erl index b392c72f1a3..72b159045b5 100644 --- a/applications/crossbar/src/modules/cb_freeswitch.erl +++ b/applications/crossbar/src/modules/cb_freeswitch.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% Handle CRUD operations for Directories diff --git a/applications/crossbar/src/modules/cb_global_provisioner_templates.erl b/applications/crossbar/src/modules/cb_global_provisioner_templates.erl index 13dfd2eb64a..fbddfe7c63b 100644 --- a/applications/crossbar/src/modules/cb_global_provisioner_templates.erl +++ b/applications/crossbar/src/modules/cb_global_provisioner_templates.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Provision template module %%% @@ -17,6 +17,7 @@ %%% Jon Blanton %%% Karl Anderson %%% James Aimonetti +%%% Pierre Fenoll %%%------------------------------------------------------------------- -module(cb_global_provisioner_templates). @@ -52,6 +53,7 @@ -spec init() -> ok. init() -> + init_db(), _ = crossbar_bindings:bind(<<"*.content_types_provided.global_provisioner_templates">>, ?MODULE, 'content_types_provided'), _ = crossbar_bindings:bind(<<"*.content_types_accepted.global_provisioner_templates">>, ?MODULE, 'content_types_accepted'), _ = crossbar_bindings:bind(<<"*.allowed_methods.global_provisioner_templates">>, ?MODULE, 'allowed_methods'), @@ -63,6 +65,11 @@ init() -> _ = crossbar_bindings:bind(<<"*.finish_request.put.devices">>, ?MODULE, 'device_updated'), ok. +init_db() -> + _ = kz_datamgr:db_create(?KZ_PROVISIONER_DB), + _ = kz_datamgr:revise_doc_from_file(?KZ_PROVISIONER_DB, 'crossbar', <<"account/provisioner_templates.json">>), + ok. + %%-------------------------------------------------------------------- %% @public %% @doc diff --git a/applications/crossbar/src/modules/cb_google_auth.erl b/applications/crossbar/src/modules/cb_google_auth.erl index eb4bb98b55b..14528f651b1 100644 --- a/applications/crossbar/src/modules/cb_google_auth.erl +++ b/applications/crossbar/src/modules/cb_google_auth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% User auth module %%% @end diff --git a/applications/crossbar/src/modules/cb_groups.erl b/applications/crossbar/src/modules/cb_groups.erl index c9dbc62b211..d330eae821b 100644 --- a/applications/crossbar/src/modules/cb_groups.erl +++ b/applications/crossbar/src/modules/cb_groups.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_hotdesks.erl b/applications/crossbar/src/modules/cb_hotdesks.erl index 2a49d11b737..046cdb9a058 100644 --- a/applications/crossbar/src/modules/cb_hotdesks.erl +++ b/applications/crossbar/src/modules/cb_hotdesks.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Hotdesks module %%% diff --git a/applications/crossbar/src/modules/cb_ip_auth.erl b/applications/crossbar/src/modules/cb_ip_auth.erl index fb81178d17e..38e067b1220 100644 --- a/applications/crossbar/src/modules/cb_ip_auth.erl +++ b/applications/crossbar/src/modules/cb_ip_auth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Account IP auth module %%% diff --git a/applications/crossbar/src/modules/cb_ips.erl b/applications/crossbar/src/modules/cb_ips.erl index 300c0c4cfd6..c60bd8f1393 100644 --- a/applications/crossbar/src/modules/cb_ips.erl +++ b/applications/crossbar/src/modules/cb_ips.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% diff --git a/applications/crossbar/src/modules/cb_jobs_listener.erl b/applications/crossbar/src/modules/cb_jobs_listener.erl index 9b7764e1b81..d91d1f45c1c 100644 --- a/applications/crossbar/src/modules/cb_jobs_listener.erl +++ b/applications/crossbar/src/modules/cb_jobs_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_killio.erl b/applications/crossbar/src/modules/cb_killio.erl index c8b8b51e076..a58ebe980c6 100644 --- a/applications/crossbar/src/modules/cb_killio.erl +++ b/applications/crossbar/src/modules/cb_killio.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% /call %%% methods: PUT, POST diff --git a/applications/crossbar/src/modules/cb_ledgers.erl b/applications/crossbar/src/modules/cb_ledgers.erl index 0be7734b134..e98fc9cef33 100644 --- a/applications/crossbar/src/modules/cb_ledgers.erl +++ b/applications/crossbar/src/modules/cb_ledgers.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_local_provisioner_templates.erl b/applications/crossbar/src/modules/cb_local_provisioner_templates.erl index dc31c83c156..0274f35f96b 100644 --- a/applications/crossbar/src/modules/cb_local_provisioner_templates.erl +++ b/applications/crossbar/src/modules/cb_local_provisioner_templates.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Provision template module %%% diff --git a/applications/crossbar/src/modules/cb_local_resources.erl b/applications/crossbar/src/modules/cb_local_resources.erl index 3165df0c010..64ea07eb00e 100644 --- a/applications/crossbar/src/modules/cb_local_resources.erl +++ b/applications/crossbar/src/modules/cb_local_resources.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Handle client requests for local resource documents diff --git a/applications/crossbar/src/modules/cb_media.erl b/applications/crossbar/src/modules/cb_media.erl index 9b2033c7507..65278fde1ab 100644 --- a/applications/crossbar/src/modules/cb_media.erl +++ b/applications/crossbar/src/modules/cb_media.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Account module %%% @@ -345,12 +345,11 @@ normalize_upload(Context, MediaId, FileJObj, UploadContentType) -> ,MediaId ,NewFileJObj ); - {'error', Reason} -> - lager:warning("failed to convert to ~s: ~s", [ToExt, Reason]), - + {'error', _R} -> + lager:warning("failed to convert to ~s: ~p", [ToExt, _R]), + Reason = <<"failed to communicate with conversion utility">>, validate_upload(cb_context:set_doc(Context ,kz_json:set_value(<<"normalization_error">>, Reason, cb_context:doc(Context)) - ) ,MediaId ,FileJObj @@ -542,13 +541,23 @@ maybe_merge_tts(Context, MediaId, Text, Voice, 'success') -> maybe_merge_tts(Context, _MediaId, _Text, _Voice, _Status) -> Context. +-spec delete_type(boolean() | cb_context:context()) -> 'permanent' | 'soft'. +delete_type('true') -> + 'permanent'; + +delete_type('false') -> + 'soft'; + +delete_type(Context) -> + Prompt = kzd_media:is_prompt(cb_context:resp_data(Context)), + Hard = kz_json:is_true(<<"hard_delete">>, cb_context:req_data(Context)), + + delete_type(Prompt or Hard). + -spec delete(cb_context:context(), path_token()) -> cb_context:context(). -spec delete(cb_context:context(), path_token(), path_token()) -> cb_context:context(). delete(Context, _MediaId) -> - case kzd_media:is_prompt(cb_context:resp_data(Context)) of - 'true' -> crossbar_doc:delete(Context, 'permanent'); - 'false' -> crossbar_doc:delete(Context) - end. + crossbar_doc:delete(Context, delete_type(Context)). delete(Context, MediaId, ?BIN_DATA) -> delete_media_binary(kz_http_util:urlencode(MediaId), Context, cb_context:account_id(Context)). diff --git a/applications/crossbar/src/modules/cb_menus.erl b/applications/crossbar/src/modules/cb_menus.erl index 58fbb6c1078..37ef9befd06 100644 --- a/applications/crossbar/src/modules/cb_menus.erl +++ b/applications/crossbar/src/modules/cb_menus.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Menus module %%% diff --git a/applications/crossbar/src/modules/cb_metaflows.erl b/applications/crossbar/src/modules/cb_metaflows.erl index 8ae886194a1..44f9d93743f 100644 --- a/applications/crossbar/src/modules/cb_metaflows.erl +++ b/applications/crossbar/src/modules/cb_metaflows.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Metaflows execute on top of a call diff --git a/applications/crossbar/src/modules/cb_modules_util.erl b/applications/crossbar/src/modules/cb_modules_util.erl index f28c74df286..ebdad5fa92b 100644 --- a/applications/crossbar/src/modules/cb_modules_util.erl +++ b/applications/crossbar/src/modules/cb_modules_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Functions shared between crossbar modules %%% @end diff --git a/applications/crossbar/src/modules/cb_noauthn.erl b/applications/crossbar/src/modules/cb_noauthn.erl index ed6f1f14f4f..f09cbe6a5ec 100644 --- a/applications/crossbar/src/modules/cb_noauthn.erl +++ b/applications/crossbar/src/modules/cb_noauthn.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% NoAuthN module %%% diff --git a/applications/crossbar/src/modules/cb_noauthz.erl b/applications/crossbar/src/modules/cb_noauthz.erl index ef36bc7862a..52f131d8f31 100644 --- a/applications/crossbar/src/modules/cb_noauthz.erl +++ b/applications/crossbar/src/modules/cb_noauthz.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% NoAuthZ module %%% diff --git a/applications/crossbar/src/modules/cb_notifications.erl b/applications/crossbar/src/modules/cb_notifications.erl index 8f9a208b5cb..d366bbf7036 100644 --- a/applications/crossbar/src/modules/cb_notifications.erl +++ b/applications/crossbar/src/modules/cb_notifications.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -1068,12 +1068,13 @@ merge_available(AccountAvailable, Available) -> -spec merge_fold(kz_json:object(), kz_json:objects()) -> kz_json:objects(). merge_fold(Overridden, Acc) -> Id = kz_doc:id(Overridden), + {[Master], Filtered} = lists:partition(fun(JObj) -> kz_doc:id(JObj) =:= Id end, Acc), + Values = [{<<"friendly_name">>, kz_json:get_value(<<"friendly_name">>, Master)} + ,{<<"macros">>, kz_json:get_value(<<"macros">>, Master)} + ], + JObj = kz_json:set_values(Values, Overridden), lager:debug("noting ~s is overridden in account", [Id]), - [note_account_override(Overridden) - | [JObj || JObj <- Acc, - kz_doc:id(JObj) =/= Id - ] - ]. + [note_account_override(JObj) | Filtered]. -type normalize_fun() :: fun((kz_json:object(), kz_json:objects()) -> kz_json:objects()). diff --git a/applications/crossbar/src/modules/cb_onboard.erl b/applications/crossbar/src/modules/cb_onboard.erl index 12202595f42..e32d44910f6 100644 --- a/applications/crossbar/src/modules/cb_onboard.erl +++ b/applications/crossbar/src/modules/cb_onboard.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% Handle client requests for onboard documents diff --git a/applications/crossbar/src/modules/cb_parked_calls.erl b/applications/crossbar/src/modules/cb_parked_calls.erl index a21643ae5d8..5d3fd6d6c22 100644 --- a/applications/crossbar/src/modules/cb_parked_calls.erl +++ b/applications/crossbar/src/modules/cb_parked_calls.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @contributors: %%% Roman Galeev %%%------------------------------------------------------------------- diff --git a/applications/crossbar/src/modules/cb_pivot.erl b/applications/crossbar/src/modules/cb_pivot.erl index 8c8452f79da..08ed354d8a1 100644 --- a/applications/crossbar/src/modules/cb_pivot.erl +++ b/applications/crossbar/src/modules/cb_pivot.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Listing of all expected v1 callbacks diff --git a/applications/crossbar/src/modules/cb_port_requests.erl b/applications/crossbar/src/modules/cb_port_requests.erl index fac04112506..a423ce20a33 100644 --- a/applications/crossbar/src/modules/cb_port_requests.erl +++ b/applications/crossbar/src/modules/cb_port_requests.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% %%% Handles port request life cycles diff --git a/applications/crossbar/src/modules/cb_presence.erl b/applications/crossbar/src/modules/cb_presence.erl index 247b92841b2..8b043395d3c 100644 --- a/applications/crossbar/src/modules/cb_presence.erl +++ b/applications/crossbar/src/modules/cb_presence.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_profile.erl b/applications/crossbar/src/modules/cb_profile.erl index 89ae6a0cb47..6630c103d88 100644 --- a/applications/crossbar/src/modules/cb_profile.erl +++ b/applications/crossbar/src/modules/cb_profile.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Listing of all expected v1 callbacks diff --git a/applications/crossbar/src/modules/cb_queues.erl b/applications/crossbar/src/modules/cb_queues.erl index 10e26f277fb..e8c8faf0c6b 100644 --- a/applications/crossbar/src/modules/cb_queues.erl +++ b/applications/crossbar/src/modules/cb_queues.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% CRUD for call queues diff --git a/applications/crossbar/src/modules/cb_rate_limits.erl b/applications/crossbar/src/modules/cb_rate_limits.erl index 6cfd8d338e3..5800c35dc9a 100644 --- a/applications/crossbar/src/modules/cb_rate_limits.erl +++ b/applications/crossbar/src/modules/cb_rate_limits.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% SBC Rate limits diff --git a/applications/crossbar/src/modules/cb_rates.erl b/applications/crossbar/src/modules/cb_rates.erl index bbb5c0c31c2..a3c359105a0 100644 --- a/applications/crossbar/src/modules/cb_rates.erl +++ b/applications/crossbar/src/modules/cb_rates.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Upload a rate deck, query rates for a given DID %%% @end diff --git a/applications/crossbar/src/modules/cb_recordings.erl b/applications/crossbar/src/modules/cb_recordings.erl index e0e2107248b..b476626d324 100644 --- a/applications/crossbar/src/modules/cb_recordings.erl +++ b/applications/crossbar/src/modules/cb_recordings.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% Provides access to stored call recordings. diff --git a/applications/crossbar/src/modules/cb_registrations.erl b/applications/crossbar/src/modules/cb_registrations.erl index ff4ae6397e3..0f3482c5a66 100644 --- a/applications/crossbar/src/modules/cb_registrations.erl +++ b/applications/crossbar/src/modules/cb_registrations.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Registration viewer / creator %%% diff --git a/applications/crossbar/src/modules/cb_resource_selectors.erl b/applications/crossbar/src/modules/cb_resource_selectors.erl index 53e01acd4b3..949d42fa368 100644 --- a/applications/crossbar/src/modules/cb_resource_selectors.erl +++ b/applications/crossbar/src/modules/cb_resource_selectors.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% diff --git a/applications/crossbar/src/modules/cb_resource_templates.erl b/applications/crossbar/src/modules/cb_resource_templates.erl index 68658225c45..0e50ac37fef 100644 --- a/applications/crossbar/src/modules/cb_resource_templates.erl +++ b/applications/crossbar/src/modules/cb_resource_templates.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Handle client requests for local resource documents diff --git a/applications/crossbar/src/modules/cb_resources.erl b/applications/crossbar/src/modules/cb_resources.erl index bd06b0960ea..35e528bd345 100644 --- a/applications/crossbar/src/modules/cb_resources.erl +++ b/applications/crossbar/src/modules/cb_resources.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Handle client requests for resource documents @@ -284,7 +284,7 @@ validate_collection_resource(Resource, Context, ?HTTP_PUT) -> {'ok', cb_context:context()} | {'error', kz_json:object()}. validate_collection_resource_patch(PatchJObj, Context) -> - PatchedJObj = kz_json:merge_jobjs(kz_doc:public_fields(PatchJObj), cb_context:doc(Context)), + PatchedJObj = kz_json:merge_recursive(cb_context:doc(Context), kz_doc:public_fields(PatchJObj)), Context1 = update(kz_doc:id(PatchedJObj) ,cb_context:set_req_data(Context, PatchedJObj) ), diff --git a/applications/crossbar/src/modules/cb_schemas.erl b/applications/crossbar/src/modules/cb_schemas.erl index 87228f65f64..07f7cee5be5 100644 --- a/applications/crossbar/src/modules/cb_schemas.erl +++ b/applications/crossbar/src/modules/cb_schemas.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_search.erl b/applications/crossbar/src/modules/cb_search.erl index 019b956e0d5..90711b0ecf9 100644 --- a/applications/crossbar/src/modules/cb_search.erl +++ b/applications/crossbar/src/modules/cb_search.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Listing of all expected v1 callbacks diff --git a/applications/crossbar/src/modules/cb_service_plans.erl b/applications/crossbar/src/modules/cb_service_plans.erl index cc40e70b191..27e61ac212f 100644 --- a/applications/crossbar/src/modules/cb_service_plans.erl +++ b/applications/crossbar/src/modules/cb_service_plans.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_services.erl b/applications/crossbar/src/modules/cb_services.erl index 5ae1a97778b..d08f6b454a4 100644 --- a/applications/crossbar/src/modules/cb_services.erl +++ b/applications/crossbar/src/modules/cb_services.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% diff --git a/applications/crossbar/src/modules/cb_shared_auth.erl b/applications/crossbar/src/modules/cb_shared_auth.erl index 08422b6d271..8de87bb3712 100644 --- a/applications/crossbar/src/modules/cb_shared_auth.erl +++ b/applications/crossbar/src/modules/cb_shared_auth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Shared token auth module, this module validates the token %%% against a trusted central token server. If the token diff --git a/applications/crossbar/src/modules/cb_signup.erl b/applications/crossbar/src/modules/cb_signup.erl index 20f0d581fb7..4b1accd887d 100644 --- a/applications/crossbar/src/modules/cb_signup.erl +++ b/applications/crossbar/src/modules/cb_signup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Signup module %%% diff --git a/applications/crossbar/src/modules/cb_simple_authz.erl b/applications/crossbar/src/modules/cb_simple_authz.erl index b6f4ddce1db..69ac7e97a5f 100644 --- a/applications/crossbar/src/modules/cb_simple_authz.erl +++ b/applications/crossbar/src/modules/cb_simple_authz.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Simple authorization module %%% diff --git a/applications/crossbar/src/modules/cb_skels.erl b/applications/crossbar/src/modules/cb_skels.erl index 25952a42a30..88b558dd159 100644 --- a/applications/crossbar/src/modules/cb_skels.erl +++ b/applications/crossbar/src/modules/cb_skels.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Listing of all expected v1 callbacks diff --git a/applications/crossbar/src/modules/cb_sms.erl b/applications/crossbar/src/modules/cb_sms.erl index 09968fad721..11d09a7048d 100644 --- a/applications/crossbar/src/modules/cb_sms.erl +++ b/applications/crossbar/src/modules/cb_sms.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% diff --git a/applications/crossbar/src/modules/cb_storage.erl b/applications/crossbar/src/modules/cb_storage.erl index eaf78eee0ac..eaaf557a1e1 100644 --- a/applications/crossbar/src/modules/cb_storage.erl +++ b/applications/crossbar/src/modules/cb_storage.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% storage @@ -16,6 +16,7 @@ ,validate/1, validate/2, validate/3 ,put/1, put/2 ,post/1, post/3 + ,patch/1, patch/3 ,delete/1, delete/3 ]). @@ -60,6 +61,7 @@ init() -> _ = crossbar_bindings:bind(<<"*.execute.get.storage">>, ?MODULE, 'get'), _ = crossbar_bindings:bind(<<"*.execute.put.storage">>, ?MODULE, 'put'), _ = crossbar_bindings:bind(<<"*.execute.post.storage">>, ?MODULE, 'post'), + _ = crossbar_bindings:bind(<<"*.execute.patch.storage">>, ?MODULE, 'patch'), _ = crossbar_bindings:bind(<<"*.execute.delete.storage">>, ?MODULE, 'delete'). @@ -120,7 +122,7 @@ do_authorize(Context, {'user', UserId, AccountId}) -> %%-------------------------------------------------------------------- -spec allowed_methods() -> http_methods(). allowed_methods() -> - [?HTTP_GET, ?HTTP_PUT, ?HTTP_POST, ?HTTP_DELETE]. + [?HTTP_GET, ?HTTP_PUT, ?HTTP_POST, ?HTTP_PATCH, ?HTTP_DELETE]. -spec allowed_methods(path_token()) -> http_methods(). allowed_methods(?PLANS_TOKEN) -> @@ -128,7 +130,7 @@ allowed_methods(?PLANS_TOKEN) -> -spec allowed_methods(path_token(), path_token()) -> http_methods(). allowed_methods(?PLANS_TOKEN, _StoragePlanId) -> - [?HTTP_GET, ?HTTP_POST, ?HTTP_DELETE]. + [?HTTP_GET, ?HTTP_POST, ?HTTP_PATCH, ?HTTP_DELETE]. %%-------------------------------------------------------------------- %% @public @@ -178,6 +180,8 @@ validate_storage(Context, ?HTTP_PUT) -> create(Context); validate_storage(Context, ?HTTP_POST) -> update(Context); +validate_storage(Context, ?HTTP_PATCH) -> + patch_update(Context); validate_storage(Context, ?HTTP_DELETE) -> read(Context). @@ -192,6 +196,8 @@ validate_storage_plan(Context, PlanId, ?HTTP_GET) -> read(Context, PlanId); validate_storage_plan(Context, PlanId, ?HTTP_POST) -> update(Context, PlanId); +validate_storage_plan(Context, PlanId, ?HTTP_PATCH) -> + patch_update(Context, PlanId); validate_storage_plan(Context, PlanId, ?HTTP_DELETE) -> read(Context, PlanId). @@ -224,6 +230,14 @@ post(Context) -> post(Context, ?PLANS_TOKEN, _PlanId) -> crossbar_doc:save(Context). +-spec patch(cb_context:context()) -> cb_context:context(). +patch(Context) -> + post(Context). + +-spec patch(cb_context:context(), path_token(), path_token()) -> cb_context:context(). +patch(Context, ?PLANS_TOKEN, PlanId) -> + post(Context, ?PLANS_TOKEN, PlanId). + %%-------------------------------------------------------------------- %% @public %% @doc @@ -275,11 +289,21 @@ update(Context) -> OnSuccess = fun(C) -> on_successful_validation(doc_id(Context), C) end, cb_context:validate_request_data(<<"storage">>, Context, OnSuccess). +-spec patch_update(cb_context:context()) -> cb_context:context(). +patch_update(Context) -> + VFun = fun(_Id, LoadedContext) -> update(LoadedContext) end, + crossbar_doc:patch_and_validate(doc_id(Context), Context, VFun). + -spec update(cb_context:context(), path_token()) -> cb_context:context(). update(Context, PlanId) -> OnSuccess = fun(C) -> on_successful_validation(PlanId, C) end, cb_context:validate_request_data(<<"storage">>, Context, OnSuccess). +-spec patch_update(cb_context:context(), path_token()) -> cb_context:context(). +patch_update(Context, PlanId) -> + VFun = fun(Id, LoadedContext) -> update(LoadedContext, Id) end, + crossbar_doc:patch_and_validate(PlanId, Context, VFun). + %%-------------------------------------------------------------------- %% @private %% @doc @@ -327,6 +351,8 @@ on_successful_validation(Id, ?HTTP_PUT, Context) -> ], cb_context:set_doc(Context, kz_json:exec(Routines, JObj)); on_successful_validation(Id, ?HTTP_POST, Context) -> + crossbar_doc:load_merge(Id, Context, ?STORAGE_CHECK_OPTIONS); +on_successful_validation(Id, ?HTTP_PATCH, Context) -> crossbar_doc:load_merge(Id, Context, ?STORAGE_CHECK_OPTIONS). %%-------------------------------------------------------------------- diff --git a/applications/crossbar/src/modules/cb_sup.erl b/applications/crossbar/src/modules/cb_sup.erl index e296e8fa539..61ec839b9b4 100644 --- a/applications/crossbar/src/modules/cb_sup.erl +++ b/applications/crossbar/src/modules/cb_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% %%% Provides a similar interface to the SUP command-line utility. Maps to SUP diff --git a/applications/crossbar/src/modules/cb_system_configs.erl b/applications/crossbar/src/modules/cb_system_configs.erl index 492dd183ba4..08ed9f25c49 100644 --- a/applications/crossbar/src/modules/cb_system_configs.erl +++ b/applications/crossbar/src/modules/cb_system_configs.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Listing of all expected v1 callbacks diff --git a/applications/crossbar/src/modules/cb_tasks.erl b/applications/crossbar/src/modules/cb_tasks.erl index 88e2028779f..b899a17222b 100644 --- a/applications/crossbar/src/modules/cb_tasks.erl +++ b/applications/crossbar/src/modules/cb_tasks.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Handle client requests for phone_number documents %%% @end diff --git a/applications/crossbar/src/modules/cb_templates.erl b/applications/crossbar/src/modules/cb_templates.erl index 4f9113a0522..2f7ef1cf773 100644 --- a/applications/crossbar/src/modules/cb_templates.erl +++ b/applications/crossbar/src/modules/cb_templates.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% Handle client requests for template documents diff --git a/applications/crossbar/src/modules/cb_temporal_rules.erl b/applications/crossbar/src/modules/cb_temporal_rules.erl index 8d71bcfcc34..2191fc3518f 100644 --- a/applications/crossbar/src/modules/cb_temporal_rules.erl +++ b/applications/crossbar/src/modules/cb_temporal_rules.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_temporal_rules_sets.erl b/applications/crossbar/src/modules/cb_temporal_rules_sets.erl index 9a111f5fdfa..e064b9cf3d0 100644 --- a/applications/crossbar/src/modules/cb_temporal_rules_sets.erl +++ b/applications/crossbar/src/modules/cb_temporal_rules_sets.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_token_auth.erl b/applications/crossbar/src/modules/cb_token_auth.erl index 6c8862d3607..ec4d9e4bd8a 100644 --- a/applications/crossbar/src/modules/cb_token_auth.erl +++ b/applications/crossbar/src/modules/cb_token_auth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Token auth module %%% diff --git a/applications/crossbar/src/modules/cb_token_restrictions.erl b/applications/crossbar/src/modules/cb_token_restrictions.erl index dab56b2961e..1a49373affa 100644 --- a/applications/crossbar/src/modules/cb_token_restrictions.erl +++ b/applications/crossbar/src/modules/cb_token_restrictions.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Token auth module %%% diff --git a/applications/crossbar/src/modules/cb_transactions.erl b/applications/crossbar/src/modules/cb_transactions.erl index 638bb93714c..aba8f23ed72 100644 --- a/applications/crossbar/src/modules/cb_transactions.erl +++ b/applications/crossbar/src/modules/cb_transactions.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_ubiquiti_auth.erl b/applications/crossbar/src/modules/cb_ubiquiti_auth.erl index 57b317584f0..c1d64436dce 100644 --- a/applications/crossbar/src/modules/cb_ubiquiti_auth.erl +++ b/applications/crossbar/src/modules/cb_ubiquiti_auth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Ubiquiti SSO auth module %%% @end diff --git a/applications/crossbar/src/modules/cb_ubiquiti_util.erl b/applications/crossbar/src/modules/cb_ubiquiti_util.erl index 8a4f9f8395c..5bd69c7577e 100644 --- a/applications/crossbar/src/modules/cb_ubiquiti_util.erl +++ b/applications/crossbar/src/modules/cb_ubiquiti_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% Ubiquiti SSO Utilities %%% @end diff --git a/applications/crossbar/src/modules/cb_user_auth.erl b/applications/crossbar/src/modules/cb_user_auth.erl index bbb75016545..f9f9fbfc133 100644 --- a/applications/crossbar/src/modules/cb_user_auth.erl +++ b/applications/crossbar/src/modules/cb_user_auth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% User auth module %%% @end @@ -223,7 +223,6 @@ maybe_authenticate_user(Context) -> AccountRealm = kz_json:get_first_defined([<<"account_realm">>, <<"realm">>], JObj), case find_account(PhoneNumber, AccountRealm, AccountName, Context) of {'error', _} -> - lager:debug("failed to find account DB from realm ~s", [AccountRealm]), cb_context:add_system_error('invalid_credentials', Context); {'ok', ?NE_BINARY=Account} -> maybe_auth_account(Context, Credentials, Method, Account); @@ -503,13 +502,7 @@ find_account('undefined', 'undefined', AccountName, Context) -> lager:debug("the account name returned multiple results"), {'ok', AccountDbs}; {'error', _} -> - Msg = - kz_json:from_list( - [{<<"message">>, <<"The provided account name could not be found">>} - ,{<<"cause">>, AccountName} - ]), - C = cb_context:add_validation_error(<<"account_name">>, <<"not_found">>, Msg, Context), - find_account('undefined', 'undefined', 'undefined', C) + {'error', error_no_account_name(Context, AccountName)} end; find_account('undefined', AccountRealm, AccountName, Context) -> case kapps_util:get_account_by_realm(AccountRealm) of @@ -520,13 +513,8 @@ find_account('undefined', AccountRealm, AccountName, Context) -> lager:debug("the account realm returned multiple results"), {'ok', AccountDbs}; {'error', _} -> - Msg = - kz_json:from_list( - [{<<"message">>, <<"The provided account realm could not be found">>} - ,{<<"cause">>, AccountRealm} - ]), - C = cb_context:add_validation_error(<<"account_realm">>, <<"not_found">>, Msg, Context), - find_account('undefined', 'undefined', AccountName, C) + ErrorContext = error_no_account_realm(Context, AccountRealm), + find_account('undefined', 'undefined', AccountName, ErrorContext) end; find_account(PhoneNumber, AccountRealm, AccountName, Context) -> case knm_number:lookup_account(PhoneNumber) of @@ -535,15 +523,38 @@ find_account(PhoneNumber, AccountRealm, AccountName, Context) -> lager:debug("found account by phone number '~s': ~s", [PhoneNumber, AccountDb]), {'ok', AccountDb}; {'error', _} -> - Msg = - kz_json:from_list( - [{<<"message">>, <<"The provided phone number could not be found">>} - ,{<<"cause">>, PhoneNumber} - ]), - C = cb_context:add_validation_error(<<"phone_number">>, <<"not_found">>, Msg, Context), - find_account('undefined', AccountRealm, AccountName, C) + ErrorContext = error_no_account_phone_number(Context, PhoneNumber), + find_account('undefined', AccountRealm, AccountName, ErrorContext) end. +-spec error_no_account_phone_number(cb_context:context(), ne_binary()) -> cb_context:context(). +error_no_account_phone_number(Context, PhoneNumber) -> + Msg = + kz_json:from_list( + [{<<"message">>, <<"The provided phone number could not be found">>} + ,{<<"cause">>, PhoneNumber} + ]), + cb_context:add_validation_error(<<"phone_number">>, <<"not_found">>, Msg, Context). + +-spec error_no_account_realm(cb_context:context(), ne_binary()) -> cb_context:context(). +error_no_account_realm(Context, AccountRealm) -> + Msg = + kz_json:from_list( + [{<<"message">>, <<"The provided account realm could not be found">>} + ,{<<"cause">>, AccountRealm} + ]), + cb_context:add_validation_error(<<"account_realm">>, <<"not_found">>, Msg, Context). + +-spec error_no_account_name(cb_context:context(), ne_binary()) -> cb_context:context(). +error_no_account_name(Context, AccountName) -> + Msg = + kz_json:from_list( + [{<<"message">>, <<"The provided account name could not be found">>} + ,{<<"cause">>, AccountName} + ]), + lager:debug("failed to find account by name: '~s'", [AccountName]), + cb_context:add_validation_error(<<"account_name">>, <<"not_found">>, Msg, Context). + -spec consume_tokens(cb_context:context()) -> cb_context:context(). consume_tokens(Context) -> BucketName = cb_modules_util:bucket_name(Context), diff --git a/applications/crossbar/src/modules/cb_vmboxes.erl b/applications/crossbar/src/modules/cb_vmboxes.erl index 8953fc7cbd9..797b37c5bd0 100644 --- a/applications/crossbar/src/modules/cb_vmboxes.erl +++ b/applications/crossbar/src/modules/cb_vmboxes.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% VMBoxes module %%% diff --git a/applications/crossbar/src/modules/cb_webhooks.erl b/applications/crossbar/src/modules/cb_webhooks.erl index c3ec2e47f20..5f8601bb76d 100644 --- a/applications/crossbar/src/modules/cb_webhooks.erl +++ b/applications/crossbar/src/modules/cb_webhooks.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Handle CRUD operations for WebHooks diff --git a/applications/crossbar/src/modules/cb_websockets.erl b/applications/crossbar/src/modules/cb_websockets.erl index 28da8bcee20..f1c51a9719e 100644 --- a/applications/crossbar/src/modules/cb_websockets.erl +++ b/applications/crossbar/src/modules/cb_websockets.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules/cb_whitelabel.erl b/applications/crossbar/src/modules/cb_whitelabel.erl index 90e032ec61f..63a22e351f5 100644 --- a/applications/crossbar/src/modules/cb_whitelabel.erl +++ b/applications/crossbar/src/modules/cb_whitelabel.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Account module %%% diff --git a/applications/crossbar/src/modules/provisioner_contact_list.erl b/applications/crossbar/src/modules/provisioner_contact_list.erl index dc3b66f321d..a779cfb7a2e 100644 --- a/applications/crossbar/src/modules/provisioner_contact_list.erl +++ b/applications/crossbar/src/modules/provisioner_contact_list.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% Common functions for the provisioner modules diff --git a/applications/crossbar/src/modules/provisioner_util.erl b/applications/crossbar/src/modules/provisioner_util.erl index fdb1a2531cb..1ef996bac89 100644 --- a/applications/crossbar/src/modules/provisioner_util.erl +++ b/applications/crossbar/src/modules/provisioner_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% Common functions for the provisioner modules diff --git a/applications/crossbar/src/modules/provisioner_v5.erl b/applications/crossbar/src/modules/provisioner_v5.erl index 1080e4102c5..6827fd3b838 100644 --- a/applications/crossbar/src/modules/provisioner_v5.erl +++ b/applications/crossbar/src/modules/provisioner_v5.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% Common functions for the provisioner modules diff --git a/applications/crossbar/src/modules_v1/cb_devices_v1.erl b/applications/crossbar/src/modules_v1/cb_devices_v1.erl index aa3bc8ede05..7127aa0661e 100644 --- a/applications/crossbar/src/modules_v1/cb_devices_v1.erl +++ b/applications/crossbar/src/modules_v1/cb_devices_v1.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Devices module %%% diff --git a/applications/crossbar/src/modules_v1/cb_limits_v1.erl b/applications/crossbar/src/modules_v1/cb_limits_v1.erl index 6996616d5b8..ccd85fb3390 100644 --- a/applications/crossbar/src/modules_v1/cb_limits_v1.erl +++ b/applications/crossbar/src/modules_v1/cb_limits_v1.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules_v1/cb_lists_v1.erl b/applications/crossbar/src/modules_v1/cb_lists_v1.erl index 7269a1d5d23..fcf18bfc2bb 100644 --- a/applications/crossbar/src/modules_v1/cb_lists_v1.erl +++ b/applications/crossbar/src/modules_v1/cb_lists_v1.erl @@ -1,5 +1,5 @@ %%%---------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Match list module %%% diff --git a/applications/crossbar/src/modules_v1/cb_phone_numbers_v1.erl b/applications/crossbar/src/modules_v1/cb_phone_numbers_v1.erl index 21e56a08190..37b949d139a 100644 --- a/applications/crossbar/src/modules_v1/cb_phone_numbers_v1.erl +++ b/applications/crossbar/src/modules_v1/cb_phone_numbers_v1.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Handle client requests for phone_number documents @@ -54,6 +54,8 @@ -define(PREFIX, <<"prefix">>). -define(COUNTRY, <<"country">>). +-define(OFFSET, <<"offset">>). +-define(QUANTITY, <<"quantity">>). %%%=================================================================== %%% API @@ -385,14 +387,31 @@ read(Context, Number) -> %%-------------------------------------------------------------------- -spec find_numbers(cb_context:context()) -> cb_context:context(). find_numbers(Context) -> - Options = get_find_numbers_req(Context), + AccountId = cb_context:auth_account_id(Context), + QS = cb_context:query_string(Context), + Country = kz_json:get_ne_value(?COUNTRY, QS, ?KNM_DEFAULT_COUNTRY), + Prefix = kz_util:remove_white_spaces(kz_json:get_ne_value(?PREFIX, QS)), + Offset = kz_json:get_integer_value(?OFFSET, QS, 0), + Token = cb_context:auth_token(Context), + HashKey = <>, + Hash = kz_base64url:encode(crypto:hash(sha, HashKey)), + QueryId = list_to_binary([Country, "-", Prefix, "-", Hash]), + Dialcode = knm_util:prefix_for_country(Country), + NormalizedPrefix = <>, + Options = props:filter_undefined( + [{'quantity', max(1, kz_json:get_integer_value(?QUANTITY, QS, 1))} + ,{'prefix', Prefix} + ,{'normalized_prefix', NormalizedPrefix} + ,{'country', Country} + ,{'dialcode', Dialcode} + ,{'offset', Offset} + ,{'account_id', AccountId} + ,{'reseller_id', cb_context:reseller_id(Context)} + ,{'query_id', QueryId} + ]), OnSuccess = fun(C) -> - lager:debug("carriers find: ~p", [Options]), - Found = - [kz_json:get_value(<<"number">>, JObj) - || JObj <- knm_carriers:find(knm_carriers:prefix(Options), Options) - ], + Found = knm_search:find(Options), cb_context:setters(C ,[{fun cb_context:set_resp_data/2, Found} ,{fun cb_context:set_resp_status/2, 'success'} @@ -402,17 +421,6 @@ find_numbers(Context) -> Context1 = cb_context:set_req_data(Context, knm_carriers:options_to_jobj(Options)), cb_context:validate_request_data(Schema, Context1, OnSuccess). --spec get_find_numbers_req(cb_context:context()) -> kz_proplist(). -get_find_numbers_req(Context) -> - QS = cb_context:query_string(Context), - [{'quantity', kz_json:get_ne_value(<<"quantity">>, QS, 1)} - ,{'prefix', kz_json:get_ne_value(?PREFIX, QS)} - ,{'country', kz_json:get_ne_value(?COUNTRY, QS, ?KNM_DEFAULT_COUNTRY)} - ,{'offset', kz_json:get_integer_value(<<"offset">>, QS, 0)} - ,{'account_id', cb_context:auth_account_id(Context)} - ,{'reseller_id', cb_context:reseller_id(Context)} - ]. - %%-------------------------------------------------------------------- %% @private %% @doc diff --git a/applications/crossbar/src/modules_v1/cb_users_v1.erl b/applications/crossbar/src/modules_v1/cb_users_v1.erl index f84f1459158..0cc831287da 100644 --- a/applications/crossbar/src/modules_v1/cb_users_v1.erl +++ b/applications/crossbar/src/modules_v1/cb_users_v1.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Users module %%% diff --git a/applications/crossbar/src/modules_v2/cb_devices_v2.erl b/applications/crossbar/src/modules_v2/cb_devices_v2.erl index c01050d9344..a231f3a1694 100644 --- a/applications/crossbar/src/modules_v2/cb_devices_v2.erl +++ b/applications/crossbar/src/modules_v2/cb_devices_v2.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Devices module %%% diff --git a/applications/crossbar/src/modules_v2/cb_limits_v2.erl b/applications/crossbar/src/modules_v2/cb_limits_v2.erl index ea011d9e3db..5015f33a3ef 100644 --- a/applications/crossbar/src/modules_v2/cb_limits_v2.erl +++ b/applications/crossbar/src/modules_v2/cb_limits_v2.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/crossbar/src/modules_v2/cb_lists_v2.erl b/applications/crossbar/src/modules_v2/cb_lists_v2.erl index 884fca76bf9..faf5053f84e 100644 --- a/applications/crossbar/src/modules_v2/cb_lists_v2.erl +++ b/applications/crossbar/src/modules_v2/cb_lists_v2.erl @@ -1,5 +1,5 @@ %%%---------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Match list module %%% diff --git a/applications/crossbar/src/modules_v2/cb_phone_numbers_v2.erl b/applications/crossbar/src/modules_v2/cb_phone_numbers_v2.erl index f5c87fb1d3a..8057c7f08a3 100644 --- a/applications/crossbar/src/modules_v2/cb_phone_numbers_v2.erl +++ b/applications/crossbar/src/modules_v2/cb_phone_numbers_v2.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Handle client requests for phone_number documents @@ -331,9 +331,7 @@ post(Context, ?FIX) -> summary(Context); post(Context, ?CHECK) -> Numbers = cb_context:req_value(Context, ?COLLECTION_NUMBERS), - Unformatted = knm_carriers:check(Numbers), - RespData = format_carriers_check(Unformatted), - cb_context:set_resp_data(Context, RespData); + cb_context:set_resp_data(Context, knm_carriers:check(Numbers)); post(Context, ?COLLECTION) -> Results = collection_process(Context, ?HTTP_POST), CB = fun() -> post(cb_context:set_accepting_charges(Context), ?COLLECTION) end, @@ -341,8 +339,8 @@ post(Context, ?COLLECTION) -> post(Context, ?LOCALITY) -> fetch_locality(Context); post(Context, Number) -> - Options = [{'assign_to', cb_context:account_id(Context)} - ,{'auth_by', cb_context:auth_account_id(Context)} + Options = [{'auth_by', cb_context:auth_account_id(Context)} + ,{'assign_to', cb_context:account_id(Context)} ], JObj = cb_context:doc(Context), Result = knm_number:update(Number, [{fun knm_phone_number:reset_doc/2, JObj}], Options), @@ -355,8 +353,8 @@ put(Context, ?COLLECTION) -> CB = fun() -> ?MODULE:put(cb_context:set_accepting_charges(Context), ?COLLECTION) end, set_response(Results, Context, CB); put(Context, Number) -> - Options = [{'assign_to', cb_context:account_id(Context)} - ,{'auth_by', cb_context:auth_account_id(Context)} + Options = [{'auth_by', cb_context:auth_account_id(Context)} + ,{'assign_to', cb_context:account_id(Context)} ,{'dry_run', not cb_context:accepting_charges(Context)} ,{'public_fields', cb_context:doc(Context)} ], @@ -377,8 +375,8 @@ put(Context, Number, ?ACTIVATE) -> CB = fun() -> put(cb_context:set_accepting_charges(Context), Number, ?ACTIVATE) end, set_response(Result, Context, CB); put(Context, Number, ?RESERVE) -> - Options = [{'assign_to', cb_context:account_id(Context)} - ,{'auth_by', cb_context:auth_account_id(Context)} + Options = [{'auth_by', cb_context:auth_account_id(Context)} + ,{'assign_to', cb_context:account_id(Context)} ,{'dry_run', not cb_context:accepting_charges(Context)} ,{'public_fields', cb_context:doc(Context)} ], @@ -386,8 +384,8 @@ put(Context, Number, ?RESERVE) -> CB = fun() -> put(cb_context:set_accepting_charges(Context), Number, ?RESERVE) end, set_response(Result, Context, CB); put(Context, Number, ?PORT) -> - Options = [{'assign_to', cb_context:account_id(Context)} - ,{'auth_by', cb_context:auth_account_id(Context)} + Options = [{'auth_by', cb_context:auth_account_id(Context)} + ,{'assign_to', cb_context:account_id(Context)} ,{'dry_run', not cb_context:accepting_charges(Context)} ,{'public_fields', cb_context:doc(Context)} ,{'state', ?NUMBER_STATE_PORT_IN} @@ -423,7 +421,9 @@ delete(Context, Number) -> %%-------------------------------------------------------------------- %% @private -%% @doc Lists number on GET /v2/accounts/{{ACCOUNT_ID}}/phone_numbers/{{DID}} +%% @doc +%% Lists number on GET /v2/accounts/{{ACCOUNT_ID}}/phone_numbers/{{DID}} +%% @end %%-------------------------------------------------------------------- -spec summary(cb_context:context(), ne_binary()) -> cb_context:context(). summary(Context, Number) -> @@ -502,7 +502,7 @@ view_account_phone_numbers(Context) -> ,rename_qs_filters(Context) ,fun normalize_view_results/2 ), - ListOfNumProps = cb_context:resp_data(Context1), + ListOfNumProps = lists:map(fun fix_available/1, cb_context:resp_data(Context1)), PortNumberJObj = maybe_add_port_request_numbers(Context), NumbersJObj = lists:foldl(fun kz_json:merge_jobjs/2, PortNumberJObj, ListOfNumProps), Service = kz_services:fetch(cb_context:account_id(Context)), @@ -512,6 +512,19 @@ view_account_phone_numbers(Context) -> ]), cb_context:set_resp_data(Context1, NewRespData). +-spec fix_available(kz_json:object()) -> kz_json:object(). +fix_available(NumJObj) -> + [{Num, JObj}] = kz_json:to_proplist(NumJObj), + IsLocal = lists:member(?FEATURE_LOCAL, kz_json:get_list_value(<<"features">>, JObj, [])), + Allowed = knm_providers:available_features(IsLocal + ,kz_json:get_ne_binary_value(<<"assigned_to">>, JObj) + ,kz_json:get_ne_binary_value(<<"used_by">>, JObj) + ,kz_json:get_list_value(<<"features_allowed">>, JObj, []) + ,kz_json:get_list_value(<<"features_denied">>, JObj, []) + ), + NewJObj = kz_json:set_value(<<"features_available">>, Allowed, JObj), + kz_json:from_list([{Num, NewJObj}]). + %% @private -spec maybe_add_port_request_numbers(cb_context:context()) -> kz_json:object(). -spec maybe_add_port_request_numbers(cb_context:context(), boolean()) -> kz_json:object(). @@ -706,29 +719,6 @@ validate_collection_request(Context, _E) -> ]), cb_context:add_validation_error(?COLLECTION_NUMBERS, <<"type">>, Msg, Context). -%%-------------------------------------------------------------------- -%% @private -%% @doc -%% @end -%%-------------------------------------------------------------------- --spec format_carriers_check(list()) -> kz_json:object(). --spec format_carriers_check(list(), kz_json:object()) -> kz_json:object(). -format_carriers_check(Checked) -> - format_carriers_check(Checked, kz_json:new()). -format_carriers_check([], JObj) -> JObj; -format_carriers_check([{_Module, {'ok', ModuleResults}}|Rest], JObj) -> - JObj1 = - lists:foldl( - fun ({Number, Status}, Acc) -> - kz_json:set_value(Number, Status, Acc) - end - ,JObj - ,kz_json:to_proplist(ModuleResults) - ), - format_carriers_check(Rest, JObj1); -format_carriers_check([_|Rest], JObj) -> - format_carriers_check(Rest, JObj). - %%-------------------------------------------------------------------- %% @private %% @doc @@ -894,7 +884,7 @@ set_response(Result, Context) -> set_response(Result, Context, fun() -> Context end). -type result() :: {'ok', kz_json:object()} | - {ne_binary(), [kz_services:services()], kz_json:object()} | + knm_numbers:ret() | knm_number_return() | {binary(), binary()}. -type cb() :: fun(() -> cb_context:context()). @@ -906,20 +896,23 @@ set_response({'ok', Thing}, Context, _) -> 'false' -> crossbar_util:response(Thing, Context) end; -set_response({?COLLECTION, ServicesList, ResultJObj}, Context, CB) -> - case kz_json:get_value(<<"error">>, ResultJObj) of - 'undefined' -> - case ServicesList of - [] -> crossbar_util:response(ResultJObj, Context); - _ -> - RespJObj = fold_dry_runs(ServicesList), - case kz_json:is_empty(RespJObj) of - 'true' -> CB(); - 'false' -> crossbar_util:response_402(RespJObj, Context) - end +set_response(Ret=#{ko := KOs, services := Services, options := Options}, Context, CB) -> + case {KOs =/= #{}, Services =:= undefined, knm_number_options:dry_run(Options)} of + {true, _, _} -> + ResultJObj = knm_numbers:to_json(Ret), + crossbar_util:response_400(<<"client error">>, ResultJObj, Context); + {_, true, _} -> + ResultJObj = knm_numbers:to_json(Ret), + crossbar_util:response(ResultJObj, Context); + {_, _, true} -> + RespJObj = kz_services:dry_run(Services), + case kz_json:is_empty(RespJObj) of + true -> CB(); + false -> crossbar_util:response_402(RespJObj, Context) end; - _Errors -> - crossbar_util:response_400(<<"client error">>, ResultJObj, Context) + _ -> + ResultJObj = knm_numbers:to_json(Ret), + crossbar_util:response(ResultJObj, Context) end; set_response({'dry_run', Services, _ActivationCharges}, Context, CB) -> @@ -974,39 +967,15 @@ reply_number_not_found(Context) -> %% %% @end %%-------------------------------------------------------------------- --type process_result() :: {kz_services:services(), kz_json:object()}. --spec collection_process(cb_context:context(), ne_binary()) -> {ne_binary(), kz_services:services(), kz_json:object()}. +-spec collection_process(cb_context:context(), ne_binary()) -> knm_numbers:ret(). collection_process(Context, Action) -> ReqData = cb_context:req_data(Context), Numbers = kz_json:get_value(<<"numbers">>, ReqData), Context1 = cb_context:set_req_data(Context, kz_json:delete_key(<<"numbers">>, ReqData)), - {ServicesList, ResultJObj} = - collection_process(Context1, Action, Numbers), - {?COLLECTION, ServicesList, ResultJObj}. - --spec collection_process(cb_context:context(), ne_binary(), ne_binaries()) -> process_result(). -collection_process(Context, Action, Numbers) -> - lists:foldl(fun ({Number, {'ok', KNMNumber}}, {ServicesAcc, JObjAcc}) -> - JObj = knm_number:to_public_json(KNMNumber), - {ServicesAcc - ,kz_json:set_value([<<"success">>, Number], JObj, JObjAcc) - }; - ({Number, {'dry_run', Services, ActivationCharges}}, {ServicesAcc, JObjAcc}) -> - {[Services | ServicesAcc] - ,kz_json:set_value([<<"charges">>, Number], ActivationCharges, JObjAcc) - }; - ({Number, {'error', KNMError}}, {ServicesAcc, JObjAcc}) -> - {ServicesAcc - ,kz_json:set_value([<<"error">>, Number], KNMError, JObjAcc) - } - end - ,{[], kz_json:new()} - ,numbers_action(Context, Action, Numbers) - ). + numbers_action(Context1, Action, Numbers). %% @private --spec numbers_action(cb_context:context(), ne_binary(), ne_binaries()) -> - knm_numbers:numbers_return(). +-spec numbers_action(cb_context:context(), ne_binary(), ne_binaries()) -> knm_numbers:ret(). numbers_action(Context, ?ACTIVATE, Numbers) -> Options = [{'auth_by', cb_context:auth_account_id(Context)} ,{'dry_run', not cb_context:accepting_charges(Context)} @@ -1014,15 +983,15 @@ numbers_action(Context, ?ACTIVATE, Numbers) -> ], knm_numbers:move(Numbers, cb_context:account_id(Context), Options); numbers_action(Context, ?HTTP_PUT, Numbers) -> - Options = [{'assign_to', cb_context:account_id(Context)} - ,{'auth_by', cb_context:auth_account_id(Context)} + Options = [{'auth_by', cb_context:auth_account_id(Context)} + ,{'assign_to', cb_context:account_id(Context)} ,{'dry_run', not cb_context:accepting_charges(Context)} ,{'public_fields', cb_context:req_data(Context)} ], knm_numbers:create(Numbers, Options); numbers_action(Context, ?HTTP_POST, Numbers) -> - Options = [{'assign_to', cb_context:account_id(Context)} - ,{'auth_by', cb_context:auth_account_id(Context)} + Options = [{'auth_by', cb_context:auth_account_id(Context)} + ,{'assign_to', cb_context:account_id(Context)} ], JObj = cb_context:req_data(Context), knm_numbers:update(Numbers, [{fun knm_phone_number:reset_doc/2, JObj}], Options); @@ -1032,11 +1001,6 @@ numbers_action(Context, ?HTTP_DELETE, Numbers) -> Releaser = pick_release_or_delete(Context, Options), knm_numbers:Releaser(Numbers, Options). --spec fold_dry_runs([kz_services:services(), ...]) -> kz_json:object(). -fold_dry_runs(ServicesList) -> - F = fun(Services, _Acc) -> kz_services:dry_run(Services) end, - lists:foldl(F, [], ServicesList). - %% @private -spec pick_release_or_delete(cb_context:context(), knm_number_options:options()) -> 'release' | 'delete'. pick_release_or_delete(Context, Options) -> diff --git a/applications/crossbar/src/modules_v2/cb_users_v2.erl b/applications/crossbar/src/modules_v2/cb_users_v2.erl index ccbeaa9181c..a6b89cd669b 100644 --- a/applications/crossbar/src/modules_v2/cb_users_v2.erl +++ b/applications/crossbar/src/modules_v2/cb_users_v2.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Users module %%% diff --git a/applications/crossbar/test/cb_notifications_test.erl b/applications/crossbar/test/cb_notifications_test.erl index 8050ac7955a..1f327daeb8d 100644 --- a/applications/crossbar/test/cb_notifications_test.erl +++ b/applications/crossbar/test/cb_notifications_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/test/cb_token_restrictions_test.erl b/applications/crossbar/test/cb_token_restrictions_test.erl index c26c9e7d22f..52c03056cba 100644 --- a/applications/crossbar/test/cb_token_restrictions_test.erl +++ b/applications/crossbar/test/cb_token_restrictions_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% @contributors %%% James Aimonetti diff --git a/applications/crossbar/test/cb_ubiquiti_util_test.erl b/applications/crossbar/test/cb_ubiquiti_util_test.erl index bfb8d2a0068..771bd6648db 100644 --- a/applications/crossbar/test/cb_ubiquiti_util_test.erl +++ b/applications/crossbar/test/cb_ubiquiti_util_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/test/crossbar_doc_test.erl b/applications/crossbar/test/crossbar_doc_test.erl index b4dacea599c..fac0fafbcaa 100644 --- a/applications/crossbar/test/crossbar_doc_test.erl +++ b/applications/crossbar/test/crossbar_doc_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/crossbar/test/crossbar_util_test.erl b/applications/crossbar/test/crossbar_util_test.erl index ee0a36ec696..037c5a45386 100644 --- a/applications/crossbar/test/crossbar_util_test.erl +++ b/applications/crossbar/test/crossbar_util_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/doodle/doc/README.md b/applications/doodle/doc/README.md index 8115e08588e..4f30090b8a3 100644 --- a/applications/doodle/doc/README.md +++ b/applications/doodle/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Doodle -Title: Doodle -Language: en-US -*/ # Doodle *Store and Forward SMS* "Stop that pigeon!" diff --git a/applications/doodle/doc/configuration.md b/applications/doodle/doc/configuration.md index d561199a600..bd4ae362ac6 100644 --- a/applications/doodle/doc/configuration.md +++ b/applications/doodle/doc/configuration.md @@ -1,9 +1,3 @@ -/* -Section: Doodle -Title: Doodle -Language: en-US -Version: 3.20 -*/ # Configure inbound listeners diff --git a/applications/doodle/src/doodle_api.erl b/applications/doodle/src/doodle_api.erl index 4e8f0ac2691..1878ac49222 100644 --- a/applications/doodle/src/doodle_api.erl +++ b/applications/doodle/src/doodle_api.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Handle sms api docs %%% @end diff --git a/applications/doodle/src/doodle_app.erl b/applications/doodle/src/doodle_app.erl index dd7124772de..d25e6ede2e3 100644 --- a/applications/doodle/src/doodle_app.erl +++ b/applications/doodle/src/doodle_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/doodle/src/doodle_delivery_handler.erl b/applications/doodle/src/doodle_delivery_handler.erl index 4917d3305cd..576b9a64ae4 100644 --- a/applications/doodle/src/doodle_delivery_handler.erl +++ b/applications/doodle/src/doodle_delivery_handler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Handlers for various AMQP payloads %%% @end diff --git a/applications/doodle/src/doodle_doc_handler.erl b/applications/doodle/src/doodle_doc_handler.erl index ce93adeb7a8..a6e1cc6735e 100644 --- a/applications/doodle/src/doodle_doc_handler.erl +++ b/applications/doodle/src/doodle_doc_handler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Handlers for various AMQP payloads %%% @end diff --git a/applications/doodle/src/doodle_event_handler_sup.erl b/applications/doodle/src/doodle_event_handler_sup.erl index f428e0445c4..ec98d97a8a8 100644 --- a/applications/doodle/src/doodle_event_handler_sup.erl +++ b/applications/doodle/src/doodle_event_handler_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/doodle/src/doodle_exe.erl b/applications/doodle/src/doodle_exe.erl index 656f22479af..8e29da2af34 100644 --- a/applications/doodle/src/doodle_exe.erl +++ b/applications/doodle/src/doodle_exe.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% @end %%% @contributors diff --git a/applications/doodle/src/doodle_exe_sup.erl b/applications/doodle/src/doodle_exe_sup.erl index a6e4c7ed5c5..c4e53bc6b4c 100644 --- a/applications/doodle/src/doodle_exe_sup.erl +++ b/applications/doodle/src/doodle_exe_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/doodle/src/doodle_inbound_handler.erl b/applications/doodle/src/doodle_inbound_handler.erl index 3360b89eeb5..5c63be9f94c 100644 --- a/applications/doodle/src/doodle_inbound_handler.erl +++ b/applications/doodle/src/doodle_inbound_handler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Handler for sms inbound AMQP payload %%% @end diff --git a/applications/doodle/src/doodle_inbound_listener.erl b/applications/doodle/src/doodle_inbound_listener.erl index 43c09f5651e..ce886aded45 100644 --- a/applications/doodle/src/doodle_inbound_listener.erl +++ b/applications/doodle/src/doodle_inbound_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/doodle/src/doodle_inbound_listener_sup.erl b/applications/doodle/src/doodle_inbound_listener_sup.erl index 8b3635442ce..abd5684baad 100644 --- a/applications/doodle/src/doodle_inbound_listener_sup.erl +++ b/applications/doodle/src/doodle_inbound_listener_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/doodle/src/doodle_listener.erl b/applications/doodle/src/doodle_listener.erl index 8f8f1328128..a560747a61a 100644 --- a/applications/doodle/src/doodle_listener.erl +++ b/applications/doodle/src/doodle_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/doodle/src/doodle_maintenance.erl b/applications/doodle/src/doodle_maintenance.erl index bfcada37f5e..d018cd16ded 100644 --- a/applications/doodle/src/doodle_maintenance.erl +++ b/applications/doodle/src/doodle_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/doodle/src/doodle_notify_handler.erl b/applications/doodle/src/doodle_notify_handler.erl index 9922c2c1deb..f9cff185959 100644 --- a/applications/doodle/src/doodle_notify_handler.erl +++ b/applications/doodle/src/doodle_notify_handler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Handlers for various AMQP payloads %%% @end diff --git a/applications/doodle/src/doodle_route_req.erl b/applications/doodle/src/doodle_route_req.erl index aacee9878f9..7355e999417 100644 --- a/applications/doodle/src/doodle_route_req.erl +++ b/applications/doodle/src/doodle_route_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Handlers for various AMQP payloads %%% @end @@ -118,7 +118,7 @@ bucket_cost(Flow) -> -spec send_route_response(kz_json:object(), kz_json:object(), kapps_call:call()) -> 'ok'. send_route_response(_Flow, JObj, Call) -> - lager:info("doodle knows how to route the message! sending sms response"), + lager:info("doodle knows how to route the message! sending sms response"), Resp = props:filter_undefined([{?KEY_MSG_ID, kz_api:msg_id(JObj)} ,{?KEY_MSG_REPLY_ID, kapi_route:fetch_id(JObj)} ,{<<"Routes">>, []} diff --git a/applications/doodle/src/doodle_route_win.erl b/applications/doodle/src/doodle_route_win.erl index 8660d849918..b131ef9d374 100644 --- a/applications/doodle/src/doodle_route_win.erl +++ b/applications/doodle/src/doodle_route_win.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% handler for route wins, bootstraps callflow execution %%% @end @@ -173,9 +173,13 @@ get_callee_extension_info(Call) -> FirstModule = kz_json:get_value(<<"module">>, Flow), FirstId = kz_json:get_value([<<"data">>, <<"id">>], Flow), SecondModule = kz_json:get_value([<<"_">>, <<"module">>], Flow), - case (FirstModule =:= <<"device">> orelse FirstModule =:= <<"user">>) + case (FirstModule =:= <<"device">> + orelse + FirstModule =:= <<"user">>) andalso - (SecondModule =:= <<"voicemail">> orelse SecondModule =:= 'undefined') + (SecondModule =:= <<"voicemail">> + orelse + SecondModule =:= 'undefined') andalso FirstId =/= 'undefined' of diff --git a/applications/doodle/src/doodle_shared_listener.erl b/applications/doodle/src/doodle_shared_listener.erl index c983544424b..66252733bdf 100644 --- a/applications/doodle/src/doodle_shared_listener.erl +++ b/applications/doodle/src/doodle_shared_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/doodle/src/doodle_sup.erl b/applications/doodle/src/doodle_sup.erl index d7af5087e96..c2a2fcb3a38 100644 --- a/applications/doodle/src/doodle_sup.erl +++ b/applications/doodle/src/doodle_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/doodle/src/doodle_util.erl b/applications/doodle/src/doodle_util.erl index 11304128129..06bb84a8fc0 100644 --- a/applications/doodle/src/doodle_util.erl +++ b/applications/doodle/src/doodle_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/doodle/src/module/cf_sms_device.erl b/applications/doodle/src/module/cf_sms_device.erl index db2fcea6a2d..fcccc51aa54 100644 --- a/applications/doodle/src/module/cf_sms_device.erl +++ b/applications/doodle/src/module/cf_sms_device.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/doodle/src/module/cf_sms_offnet.erl b/applications/doodle/src/module/cf_sms_offnet.erl index 57f4e6e4388..97a6afeacc5 100644 --- a/applications/doodle/src/module/cf_sms_offnet.erl +++ b/applications/doodle/src/module/cf_sms_offnet.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/doodle/src/module/cf_sms_resources.erl b/applications/doodle/src/module/cf_sms_resources.erl index f9786752886..d863461d17a 100644 --- a/applications/doodle/src/module/cf_sms_resources.erl +++ b/applications/doodle/src/module/cf_sms_resources.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/doodle/src/module/cf_sms_user.erl b/applications/doodle/src/module/cf_sms_user.erl index f992254244b..77f9eca837b 100644 --- a/applications/doodle/src/module/cf_sms_user.erl +++ b/applications/doodle/src/module/cf_sms_user.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/dth/doc/README.md b/applications/dth/doc/README.md index 3e40194253e..43bae315f94 100644 --- a/applications/dth/doc/README.md +++ b/applications/dth/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: DTH -Title: DTH -Language: en-US -*/ Getting started: diff --git a/applications/dth/src/dth.erl b/applications/dth/src/dth.erl index ea3587053f0..350ab87a94e 100644 --- a/applications/dth/src/dth.erl +++ b/applications/dth/src/dth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/dth/src/dth_api.erl b/applications/dth/src/dth_api.erl index 8e52c45fc46..7f1e7dd60a6 100644 --- a/applications/dth/src/dth_api.erl +++ b/applications/dth/src/dth_api.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Builder and validator, much like kz_api.erl, of the AMQP APIs %%% exposed by this WhApp diff --git a/applications/dth/src/dth_app.erl b/applications/dth/src/dth_app.erl index 4676829cc41..27da05f4ed1 100644 --- a/applications/dth/src/dth_app.erl +++ b/applications/dth/src/dth_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/dth/src/dth_blacklist_req.erl b/applications/dth/src/dth_blacklist_req.erl index fecb7a9a422..2f3b8e52060 100644 --- a/applications/dth/src/dth_blacklist_req.erl +++ b/applications/dth/src/dth_blacklist_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @author James Aimonetti %%% @doc %%% Handle requests from WhApps for the blacklist diff --git a/applications/dth/src/dth_cdr_handler.erl b/applications/dth/src/dth_cdr_handler.erl index 1f38ed63f24..c8145c034f3 100644 --- a/applications/dth/src/dth_cdr_handler.erl +++ b/applications/dth/src/dth_cdr_handler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @author James Aimonetti %%% @doc %%% Send a CDR payload to DTH diff --git a/applications/dth/src/dth_listener.erl b/applications/dth/src/dth_listener.erl index bcba5472497..382d3badcaf 100644 --- a/applications/dth/src/dth_listener.erl +++ b/applications/dth/src/dth_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @author James Aimonetti %%% @doc %%% Listener for authn_req, reg_success, and reg_query AMQP requests diff --git a/applications/dth/src/dth_sup.erl b/applications/dth/src/dth_sup.erl index 25b76202ed0..37abc907993 100644 --- a/applications/dth/src/dth_sup.erl +++ b/applications/dth/src/dth_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/dth/src/dth_util.erl b/applications/dth/src/dth_util.erl index 54aafa5ca86..3059e7264cc 100644 --- a/applications/dth/src/dth_util.erl +++ b/applications/dth/src/dth_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @author James Aimonetti %%% @doc %%% diff --git a/applications/ecallmgr/doc/README.md b/applications/ecallmgr/doc/README.md index 4d63822958f..d846ca41afd 100644 --- a/applications/ecallmgr/doc/README.md +++ b/applications/ecallmgr/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: eCallMgr -Title: Erlang Call Manager -Language: en-US -*/ # eCallMgr *Erlang Call Manager* Manging your calls from Erlang diff --git a/applications/ecallmgr/doc/acls.md b/applications/ecallmgr/doc/acls.md index 2f3d44c7f91..75744ceb8da 100644 --- a/applications/ecallmgr/doc/acls.md +++ b/applications/ecallmgr/doc/acls.md @@ -1,8 +1,3 @@ -/* -Section: ACLs -Title: Managing your ACLs -Language: en-US -*/ ACLs control whether to request username/password authentication from a source IP address or not. Kazoo maintains two lists of ACLs, one for the SBCs (typically Kamailio) and one for upstream carriers to send inbound traffic to Kazoo. diff --git a/applications/ecallmgr/doc/config.md b/applications/ecallmgr/doc/config.md index cdbc6c4e052..5613391421e 100644 --- a/applications/ecallmgr/doc/config.md +++ b/applications/ecallmgr/doc/config.md @@ -1,9 +1,3 @@ -/* -Section: eCallmgr -Title: eCallmgr System Config -Language: en-US -Version: 3.19 -*/ # System configuration options in ecallmgr diff --git a/applications/ecallmgr/doc/maintenance.md b/applications/ecallmgr/doc/maintenance.md index b71e07589a4..11fb6021329 100644 --- a/applications/ecallmgr/doc/maintenance.md +++ b/applications/ecallmgr/doc/maintenance.md @@ -1,9 +1,3 @@ -/* -Section: eCallMgr -Title: SUP Maintenance commands -Language: en-US -Version: 3.18 -*/ Here's a run down of the available SUP commands for manipulating ecallmgr! diff --git a/applications/ecallmgr/src/ecallmgr.app.src b/applications/ecallmgr/src/ecallmgr.app.src index fafe9ff27bd..e670a0302e6 100644 --- a/applications/ecallmgr/src/ecallmgr.app.src +++ b/applications/ecallmgr/src/ecallmgr.app.src @@ -44,5 +44,18 @@ ] ,'loopback::bowout' ]} + ,{node_modules, ["config" + ,"node" + ,"authn" + ,"channel" + ,"conference" + ,"event_stream_sup" + ,"msg" + ,"notify" + ,"recordings" + ,"resource" + ,"route_sup" + ,"channel_hold" + ]} ]} ]}. diff --git a/applications/ecallmgr/src/ecallmgr.hrl b/applications/ecallmgr/src/ecallmgr.hrl index 635efcae4e4..bf9175b8bf2 100644 --- a/applications/ecallmgr/src/ecallmgr.hrl +++ b/applications/ecallmgr/src/ecallmgr.hrl @@ -177,6 +177,7 @@ -define(SET_CCV(Key, Value), <>). -define(GET_CCV_HEADER(Key), <<"variable_sip_h_X-", ?CHANNEL_VAR_PREFIX, Key/binary>>). -define(GET_CUSTOM_HEADER(Key), <<"variable_sip_h_X-", Key/binary>>). +-define(CUSTOM_HEADER(Key), <<"sip_h_X-", Key/binary>>). -define(GET_VAR(Key), <<"variable_", Key/binary>>). -define(CREDS_KEY(Realm, Username), {'authn', Username, Realm}). @@ -198,6 +199,10 @@ ,{<<"Caller-ID-Number">>, <<"effective_caller_id_number">>} ,{<<"Callee-ID-Name">>, <<"effective_callee_id_name">>} ,{<<"Callee-ID-Number">>, <<"effective_callee_id_number">>} + ,{<<"Caller-Callee-ID-Name">>, <<"caller_callee_id_name">>} + ,{<<"Caller-Callee-ID-Number">>, <<"caller_callee_id_number">>} + ,{<<"Caller-Caller-ID-Name">>, <<"caller_caller_id_name">>} + ,{<<"Caller-Caller-ID-Number">>, <<"caller_caller_id_number">>} ,{<<"Progress-Timeout">>, <<"progress_timeout">>} ,{<<"Ignore-Early-Media">>, <<"ignore_early_media">>} @@ -289,6 +294,7 @@ ,{<<"To-URI">>, <<"sip_to_uri">>} ,{<<"Request-URI">>, <<"sip_req_uri">>} ,{<<"Loopback-Request-URI">>, <<"sip_loopback_req_uri">>} + ,{<<"Loopback-Export">>, <<"loopback_export">>} ,{<<"Hold-Media">>, <<"hold_music">>} ,{<<"Diversions">>, <<"sip_h_Diversion">>} ,{<<"Bridge-Execute-On-Answer">>, <<"execute_on_answer">>} @@ -516,5 +522,22 @@ ) ). +%% if we change this, we should also in .app file +%% +-define(NODE_MODULES, + [<<"config">> + ,<<"node">> + ,<<"event_stream_sup">> + ,<<"authn">> + ,<<"channel">> + ,<<"conference">> + ,<<"msg">> + ,<<"notify">> + ,<<"recordings">> + ,<<"resource">> + ,<<"route_sup">> + ,<<"channel_hold">> + ]). + -define(ECALLMGR_HRL, 'true'). -endif. diff --git a/applications/ecallmgr/src/ecallmgr_app.erl b/applications/ecallmgr/src/ecallmgr_app.erl index e4a7df03bc6..4c012b44021 100644 --- a/applications/ecallmgr/src/ecallmgr_app.erl +++ b/applications/ecallmgr/src/ecallmgr_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end @@ -9,13 +9,14 @@ -behaviour(application). --include_lib("kazoo/include/kz_types.hrl"). +-include("ecallmgr.hrl"). -export([start/2 ,request/1 ]). -export([stop/1]). +-export([freeswitch_node_modules/0]). %% Application callbacks @@ -25,6 +26,7 @@ start(_StartType, _StartArgs) -> _ = declare_exchanges(), _ = node_bindings(), + _ = freeswitch_nodesup_bind(), ecallmgr_sup:start_link(). -spec request(kz_nodes:request_acc()) -> kz_nodes:request_acc(). @@ -48,6 +50,8 @@ request(Acc) -> %% @doc Implement the application stop behaviour -spec stop(any()) -> any(). stop(_State) -> + _ = freeswitch_nodesup_unbind(), + _ = kz_nodes_bindings:unbind('ecallmgr', ?MODULE), 'ok'. -spec declare_exchanges() -> 'ok'. @@ -72,3 +76,17 @@ declare_exchanges() -> node_bindings() -> _ = kz_nodes_bindings:bind('ecallmgr', ?MODULE), 'ok'. + +-spec freeswitch_nodesup_bind() -> 'ok'. +freeswitch_nodesup_bind() -> + _ = kazoo_bindings:bind(<<"freeswitch.node.modules">>, ?MODULE, 'freeswitch_node_modules'), + 'ok'. + +-spec freeswitch_nodesup_unbind() -> 'ok'. +freeswitch_nodesup_unbind() -> + _ = kazoo_bindings:unbind(<<"freeswitch.node.modules">>, ?MODULE, 'freeswitch_node_modules'), + 'ok'. + +-spec freeswitch_node_modules() -> ne_binaries(). +freeswitch_node_modules() -> + application:get_env(?APP, 'node_modules', ?NODE_MODULES). diff --git a/applications/ecallmgr/src/ecallmgr_auxiliary_sup.erl b/applications/ecallmgr/src/ecallmgr_auxiliary_sup.erl index 59050814486..589cedfbc6d 100644 --- a/applications/ecallmgr/src/ecallmgr_auxiliary_sup.erl +++ b/applications/ecallmgr/src/ecallmgr_auxiliary_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_balance_crawler_fsm.erl b/applications/ecallmgr/src/ecallmgr_balance_crawler_fsm.erl index ab0b2319196..c432da4f728 100644 --- a/applications/ecallmgr/src/ecallmgr_balance_crawler_fsm.erl +++ b/applications/ecallmgr/src/ecallmgr_balance_crawler_fsm.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Ecallmgr module (FSM) for disconnect calls when account %%% balance drops below zero diff --git a/applications/ecallmgr/src/ecallmgr_balance_crawler_worker.erl b/applications/ecallmgr/src/ecallmgr_balance_crawler_worker.erl index e2ef8c5894e..9d06aca7254 100644 --- a/applications/ecallmgr/src/ecallmgr_balance_crawler_worker.erl +++ b/applications/ecallmgr/src/ecallmgr_balance_crawler_worker.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz, INC +%%% @copyright (C) 2017, 2600Hz, INC %%% @doc %%% Jonny5 module (worker) for disconnect calls when account %%% balance drops below zero diff --git a/applications/ecallmgr/src/ecallmgr_call_command.erl b/applications/ecallmgr/src/ecallmgr_call_command.erl index d6c40a8ccd2..d61bfd8df76 100644 --- a/applications/ecallmgr/src/ecallmgr_call_command.erl +++ b/applications/ecallmgr/src/ecallmgr_call_command.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Execute call commands %%% @end @@ -691,6 +691,16 @@ connect_leg(Node, UUID, JObj) -> {'error', ne_binary()}. prepare_app(Node, UUID, JObj) -> Target = kz_json:get_value(<<"Target-Call-ID">>, JObj), + prepare_app(Target, Node, UUID, JObj). + +-spec prepare_app(ne_binary(), atom(), ne_binary(), kz_json:object() ) -> + {ne_binary(), ne_binary()} | + {'execute', atom(), ne_binary(), kz_json:object(), ne_binary()} | + {'return', ne_binary()} | + {'error', ne_binary()}. +prepare_app(Target, _Node, Target, _JObj) -> + {'error', <<"intercept target is the same as the caller">>}; +prepare_app(Target, Node, UUID, JObj) -> case ecallmgr_fs_channel:fetch(Target, 'record') of {'ok', #channel{node=Node ,answered=IsAnswered diff --git a/applications/ecallmgr/src/ecallmgr_call_control.erl b/applications/ecallmgr/src/ecallmgr_call_control.erl index c07f25d41b0..928a14cbe7d 100644 --- a/applications/ecallmgr/src/ecallmgr_call_control.erl +++ b/applications/ecallmgr/src/ecallmgr_call_control.erl @@ -1,5 +1,5 @@ %%%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% Created when a call hits a fetch_handler in ecallmgr_route. %%% A Control Queue is created by the lookup_route function in the diff --git a/applications/ecallmgr/src/ecallmgr_call_control_sup.erl b/applications/ecallmgr/src/ecallmgr_call_control_sup.erl index 511621c3a9d..8ef60dd8934 100644 --- a/applications/ecallmgr/src/ecallmgr_call_control_sup.erl +++ b/applications/ecallmgr/src/ecallmgr_call_control_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Simple-One-For-One strategy for restarting call event processes %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_call_event_sup.erl b/applications/ecallmgr/src/ecallmgr_call_event_sup.erl index d89d85cbaa9..3d4268e2513 100644 --- a/applications/ecallmgr/src/ecallmgr_call_event_sup.erl +++ b/applications/ecallmgr/src/ecallmgr_call_event_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Simple-One-For-One strategy for restarting call event processes %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_call_events.erl b/applications/ecallmgr/src/ecallmgr_call_events.erl index 599e24239dc..3b3bc0d4e20 100644 --- a/applications/ecallmgr/src/ecallmgr_call_events.erl +++ b/applications/ecallmgr/src/ecallmgr_call_events.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% Receive call events from freeSWITCH, publish to the call's event queue %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_call_sup.erl b/applications/ecallmgr/src/ecallmgr_call_sup.erl index b0d6dc0a57d..1d08cdfd064 100644 --- a/applications/ecallmgr/src/ecallmgr_call_sup.erl +++ b/applications/ecallmgr/src/ecallmgr_call_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_channel_move.erl b/applications/ecallmgr/src/ecallmgr_channel_move.erl index 20b1052cb98..1d35039ee3f 100644 --- a/applications/ecallmgr/src/ecallmgr_channel_move.erl +++ b/applications/ecallmgr/src/ecallmgr_channel_move.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Handle channel move logic %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_channel_redirect.erl b/applications/ecallmgr/src/ecallmgr_channel_redirect.erl index c378c6840f3..432087e97ea 100644 --- a/applications/ecallmgr/src/ecallmgr_channel_redirect.erl +++ b/applications/ecallmgr/src/ecallmgr_channel_redirect.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_conference_command.erl b/applications/ecallmgr/src/ecallmgr_conference_command.erl index c774f5b3a9c..99f7b5fb19a 100644 --- a/applications/ecallmgr/src/ecallmgr_conference_command.erl +++ b/applications/ecallmgr/src/ecallmgr_conference_command.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016 2600Hz INC +%%% @copyright (C) 2011-2017 2600Hz INC %%% @doc %%% Execute conference commands %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_conference_control.erl b/applications/ecallmgr/src/ecallmgr_conference_control.erl index 1d5dd869a35..300beba639f 100644 --- a/applications/ecallmgr/src/ecallmgr_conference_control.erl +++ b/applications/ecallmgr/src/ecallmgr_conference_control.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016 2600Hz INC +%%% @copyright (C) 2011-2017 2600Hz INC %%% @doc %%% Execute conference commands %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_conference_sup.erl b/applications/ecallmgr/src/ecallmgr_conference_sup.erl index e60f68c27c5..35c37750f3b 100644 --- a/applications/ecallmgr/src/ecallmgr_conference_sup.erl +++ b/applications/ecallmgr/src/ecallmgr_conference_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_config.erl b/applications/ecallmgr/src/ecallmgr_config.erl index ca21267508e..bf696670502 100644 --- a/applications/ecallmgr/src/ecallmgr_config.erl +++ b/applications/ecallmgr/src/ecallmgr_config.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_authn.erl b/applications/ecallmgr/src/ecallmgr_fs_authn.erl index fcbb17c7281..334ae60434d 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_authn.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_authn.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Directory lookups from FS %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_authz.erl b/applications/ecallmgr/src/ecallmgr_fs_authz.erl index 5ca673b17c4..34e5ad4ef72 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_authz.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_authz.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz, INC +%%% @copyright (C) 2011-2017, 2600Hz, INC %%% @doc %%% Make a request for authorization, and answer queries about the CallID %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_bridge.erl b/applications/ecallmgr/src/ecallmgr_fs_bridge.erl index 0fc57b3091d..1e3eec66fd2 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_bridge.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_bridge.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Helpers for bridging in FreeSWITCH %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_channel.erl b/applications/ecallmgr/src/ecallmgr_fs_channel.erl index 5b892629128..7077be12cae 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_channel.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_channel.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Track the FreeSWITCH channel information, and provide accessors %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_channel_hold.erl b/applications/ecallmgr/src/ecallmgr_fs_channel_hold.erl index ec2bb3e7956..d2828cd0e64 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_channel_hold.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_channel_hold.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Receives HOLD/UNHOLD CHANNEL event %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_channels.erl b/applications/ecallmgr/src/ecallmgr_fs_channels.erl index bc83dc27c1e..ecd132065e8 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_channels.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_channels.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Track the FreeSWITCH channel information, and provide accessors %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_command.erl b/applications/ecallmgr/src/ecallmgr_fs_command.erl index cc6d7618d59..d221e9e41fe 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_command.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_command.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_conference.erl b/applications/ecallmgr/src/ecallmgr_fs_conference.erl index 023a1c74546..6e004a99830 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_conference.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_conference.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016 2600Hz INC +%%% @copyright (C) 2011-2017 2600Hz INC %%% @doc %%% Execute conference commands %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_conferences.erl b/applications/ecallmgr/src/ecallmgr_fs_conferences.erl index d6f5c01f5d3..8228bc79536 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_conferences.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_conferences.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Track FreeSWITCH conference information and provide accessors %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_config.erl b/applications/ecallmgr/src/ecallmgr_fs_config.erl index 9929583d940..bb1738c48f8 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_config.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_config.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Send config commands to FS %%% @end @@ -213,22 +213,10 @@ handle_config_req(Node, Id, <<"kazoo.conf">>, Data) -> fetch_mod_kazoo_config(Node, Id, kzd_freeswitch:event_name(Data), Data); handle_config_req(Node, Id, Conf, Data) -> kz_util:put_callid(Id), - handle_config_req(Node, Id, Conf, Data, ecallmgr_config:get(<<"configuration_handlers">>)). - --spec handle_config_req(atom(), ne_binary(), ne_binary(), kz_proplist() | 'undefined', api_object() | binary()) -> fs_sendmsg_ret(). -handle_config_req(Node, Id, Conf, _Data, 'undefined') -> - config_req_not_handled(Node, Id, Conf); -handle_config_req(Node, Id, Conf, Data, <<_/binary>> = Module) -> - lager:debug("relaying configuration ~s to ~s", [Conf, Module]), - try - (kz_util:to_atom(Module, 'true')):handle_config_req(Node, Id, Conf, Data) - catch - _E1:_E2 -> - lager:debug("exception ~p/~p calling module ~s for configuration ~s", [_E1, _E2, Module, Conf]), - config_req_not_handled(Node, Id, Conf) - end; -handle_config_req(Node, Id, Conf, Data, JObj) -> - handle_config_req(Node, Id, Conf, Data, kz_json:get_binary_value(Conf, JObj)). + case kazoo_bindings:map(<<"freeswitch.config.", Conf/binary>>, [Node, Id, Conf, Data]) of + [] -> config_req_not_handled(Node, Id, Conf); + _ -> 'ok' + end. -spec config_req_not_handled(atom(), ne_binary(), ne_binary()) -> fs_sendmsg_ret(). config_req_not_handled(Node, Id, Conf) -> diff --git a/applications/ecallmgr/src/ecallmgr_fs_event_stream.erl b/applications/ecallmgr/src/ecallmgr_fs_event_stream.erl index 7a234c0a110..e7ef47f3dda 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_event_stream.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_event_stream.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -367,6 +367,12 @@ process_stream(<<"sofia::intercepted">> = EventName, UUID, Props, Node) -> ecallmgr_fs_command:set(Node, InterceptedBy, Vars); _ -> 'ok' end, + ChannelUUID = props:get_value(<<"Channel-Call-UUID">>, Props), + Updates = props:filter_undefined( + [{<<"Caller-Callee-ID-Name">>, props:get_value(<<"Caller-Callee-ID-Name">>, Props)} + ,{<<"Caller-Callee-ID-Number">>, props:get_value(<<"Caller-Callee-ID-Number">>, Props)} + ]), + ecallmgr_fs_command:set(Node, ChannelUUID, Updates), maybe_send_event(EventName, UUID, Props, Node), process_event(EventName, UUID, Props, Node); process_stream(<<"CHANNEL_HOLD">> = EventName, UUID, Props, Node) -> @@ -374,6 +380,7 @@ process_stream(<<"CHANNEL_HOLD">> = EventName, UUID, Props, Node) -> process_stream(<<"CHANNEL_UNHOLD">> = EventName, UUID, Props, Node) -> gproc:send({'p', 'l', ?FS_EVENT_REG_MSG(Node, EventName)}, {'event', [UUID | Props]}); process_stream(EventName, UUID, EventProps, Node) -> + kz_util:put_callid(UUID), maybe_send_event(EventName, UUID, EventProps, Node), process_event(EventName, UUID, EventProps, Node). diff --git a/applications/ecallmgr/src/ecallmgr_fs_event_stream_sup.erl b/applications/ecallmgr/src/ecallmgr_fs_event_stream_sup.erl index 4ec6e3cc9ef..d0b39880a1c 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_event_stream_sup.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_event_stream_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_fax.erl b/applications/ecallmgr/src/ecallmgr_fs_fax.erl index fc193deaf48..0269aaba6b8 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_fax.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_fax.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016 2600Hz INC +%%% @copyright (C) 2011-2017 2600Hz INC %%% @doc %%% Dialplan API commands %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_flite.erl b/applications/ecallmgr/src/ecallmgr_fs_flite.erl index 3f923819b7c..7fa2f7a5a57 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_flite.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_flite.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Helpers for mod_flite %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_loopback.erl b/applications/ecallmgr/src/ecallmgr_fs_loopback.erl index cbc1661ac32..bff31a3fea8 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_loopback.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_loopback.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Filter loopback properties %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_msg.erl b/applications/ecallmgr/src/ecallmgr_fs_msg.erl index 6676a620d64..6386c810b64 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_msg.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_msg.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Notify-type requests, like MWI updates, received and processed here %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_node.erl b/applications/ecallmgr/src/ecallmgr_fs_node.erl index 03cd7d1bf13..4eaaca01b41 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_node.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_node.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Manage a FreeSWITCH node and its resources %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_node_command.erl b/applications/ecallmgr/src/ecallmgr_fs_node_command.erl index 372c2164f00..becd3013ee9 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_node_command.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_node_command.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Execute node commands %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_node_sup.erl b/applications/ecallmgr/src/ecallmgr_fs_node_sup.erl index f1543355670..93f793ee777 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_node_sup.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_node_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -35,21 +35,6 @@ -define(NODE_WORKER, ?NODE_CHILD_TYPE(<<"worker">>)). -define(NODE_SUPERVISOR, ?NODE_CHILD_TYPE(<<"supervisor">>)). --define(CHILDREN, kz_json:from_list( - [{<<"config">>, ?NODE_WORKER} - ,{<<"node">>, ?NODE_WORKER} - ,{<<"authn">>, ?NODE_WORKER} - ,{<<"channel">>, ?NODE_WORKER} - ,{<<"conference">>, ?NODE_WORKER} - ,{<<"event_stream_sup">>, ?NODE_SUPERVISOR} - ,{<<"msg">>, ?NODE_WORKER} - ,{<<"notify">>, ?NODE_WORKER} - ,{<<"recordings">>, ?NODE_WORKER} - ,{<<"resource">>, ?NODE_WORKER} - ,{<<"route_sup">>, ?NODE_SUPERVISOR} - ,{<<"channel_hold">>, ?NODE_WORKER} - ])). - %% =================================================================== %% API functions %% =================================================================== @@ -137,7 +122,8 @@ init([Node, Options]) -> NodeB = kz_util:to_binary(Node), Args = [Node, Options], - Modules = ecallmgr_config:get(<<"modules">>, ?CHILDREN), + M = kazoo_bindings:map(<<"freeswitch.node.modules">>, []), + Modules = lists:foldl(fun(A, B) -> A ++ B end, [], M), JObj = maybe_correct_modules(Modules), Children = kz_json:foldr(fun(Module, V, Acc) -> Type = kz_json:get_ne_binary_value(<<"type">>, V), @@ -170,7 +156,7 @@ maybe_correct_modules(Modules) when is_list(Modules) -> FixedModules = [fix_module(Mod) || Mod <- Modules], maybe_correct_modules(kz_json:from_list(FixedModules)); -maybe_correct_modules(JObj) -> set_order(kz_json:merge_jobjs(JObj, ?CHILDREN)). +maybe_correct_modules(JObj) -> set_order(JObj). -spec fix_module_type(ne_binary()) -> kz_json:object(). fix_module_type(<<"pus_", _/binary>>) -> @@ -182,7 +168,10 @@ fix_module_type(_) -> maybe_module_deprecated(<<"route">>) -> <<"route_sup">>; maybe_module_deprecated(Mod) -> Mod. --spec fix_module(ne_binary()) -> {ne_binary(), kz_json:object()}. +-spec fix_module(ne_binary() | string()) -> {ne_binary(), kz_json:object()}. +fix_module(Mod) + when not is_binary(Mod)-> + fix_module(kz_util:to_binary(Mod)); fix_module(Mod) -> Module = maybe_module_deprecated(Mod), ModInv = list_to_binary(lists:reverse(binary_to_list(Module))), @@ -194,6 +183,8 @@ set_order(JObj) -> -spec set_config_first(tuple(), tuple()) -> boolean(). set_config_first({<<"config">>, _}, _) -> 'true'; +set_config_first({<<"node">>, <<"config">>}, _) -> 'false'; +set_config_first({<<"node">>, _}, _) -> 'true'; set_config_first(_, _) -> 'false'. -spec which_children(SupRef) -> [{Id,Child,Type,Modules}] | {'EXIT', any()} when diff --git a/applications/ecallmgr/src/ecallmgr_fs_nodes.erl b/applications/ecallmgr/src/ecallmgr_fs_nodes.erl index a67f620a74f..076f5155c04 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_nodes.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_nodes.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% %%% When connecting to a FreeSWITCH node, we create three processes: one to diff --git a/applications/ecallmgr/src/ecallmgr_fs_notify.erl b/applications/ecallmgr/src/ecallmgr_fs_notify.erl index 990939f2a58..254747a4d4b 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_notify.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_notify.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Notify-type requests, like MWI updates, received and processed here %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_pinger.erl b/applications/ecallmgr/src/ecallmgr_fs_pinger.erl index 0ba74883101..2e22f6495d2 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_pinger.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_pinger.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% %%% When connecting to a FreeSWITCH node, we create three processes: one to diff --git a/applications/ecallmgr/src/ecallmgr_fs_pinger_sup.erl b/applications/ecallmgr/src/ecallmgr_fs_pinger_sup.erl index ee19b5cd22c..fe4bdd670aa 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_pinger_sup.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_pinger_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_recordings.erl b/applications/ecallmgr/src/ecallmgr_fs_recordings.erl index a94205d24f2..88834c8a11a 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_recordings.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_recordings.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Receives START/STOP RECORD event %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_resource.erl b/applications/ecallmgr/src/ecallmgr_fs_resource.erl index fbaee72112c..e26d4f080da 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_resource.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_resource.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_route.erl b/applications/ecallmgr/src/ecallmgr_fs_route.erl index 88f739de24e..7deb83d3ec5 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_route.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_route.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Receive route(dialplan) requests from FS, request routes and respond %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_route_sup.erl b/applications/ecallmgr/src/ecallmgr_fs_route_sup.erl index bc087109cb3..fffe354f3ca 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_route_sup.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_route_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_router_call.erl b/applications/ecallmgr/src/ecallmgr_fs_router_call.erl index c73d1e8126d..223ab6e30bd 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_router_call.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_router_call.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Receive route(dialplan) requests from FS, request routes and respond %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_router_text.erl b/applications/ecallmgr/src/ecallmgr_fs_router_text.erl index d21416e71a7..01c191629ae 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_router_text.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_router_text.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Receive route(dialplan) requests from FS, request routes and respond %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_router_util.erl b/applications/ecallmgr/src/ecallmgr_fs_router_util.erl index c9ba72c867b..5d3c85eb35d 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_router_util.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_router_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Receive route(dialplan) requests from FS, request routes and respond %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_sup.erl b/applications/ecallmgr/src/ecallmgr_fs_sup.erl index 361211b0da7..619b5a46c9f 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_sup.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_fs_xml.erl b/applications/ecallmgr/src/ecallmgr_fs_xml.erl index 36cc6e5d29f..8d6b38e549d 100644 --- a/applications/ecallmgr/src/ecallmgr_fs_xml.erl +++ b/applications/ecallmgr/src/ecallmgr_fs_xml.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Generate the XML for various FS responses %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_maintenance.erl b/applications/ecallmgr/src/ecallmgr_maintenance.erl index 5b0f3768938..e0278d1ca7f 100644 --- a/applications/ecallmgr/src/ecallmgr_maintenance.erl +++ b/applications/ecallmgr/src/ecallmgr_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_originate.erl b/applications/ecallmgr/src/ecallmgr_originate.erl index b75e98f3316..62a9423922b 100644 --- a/applications/ecallmgr/src/ecallmgr_originate.erl +++ b/applications/ecallmgr/src/ecallmgr_originate.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_originate_sup.erl b/applications/ecallmgr/src/ecallmgr_originate_sup.erl index 75ad82c4c2b..7e5b420cc0e 100644 --- a/applications/ecallmgr/src/ecallmgr_originate_sup.erl +++ b/applications/ecallmgr/src/ecallmgr_originate_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Simple-One-For-One strategy for restarting call event processes %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_registrar.erl b/applications/ecallmgr/src/ecallmgr_registrar.erl index df2def2055d..a18ed6a06f2 100644 --- a/applications/ecallmgr/src/ecallmgr_registrar.erl +++ b/applications/ecallmgr/src/ecallmgr_registrar.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Listener for reg_success, and reg_query AMQP requests %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_sup.erl b/applications/ecallmgr/src/ecallmgr_sup.erl index cd24f08d93b..a4495e404bf 100644 --- a/applications/ecallmgr/src/ecallmgr_sup.erl +++ b/applications/ecallmgr/src/ecallmgr_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/applications/ecallmgr/src/ecallmgr_util.erl b/applications/ecallmgr/src/ecallmgr_util.erl index 80548892745..e441930142d 100644 --- a/applications/ecallmgr/src/ecallmgr_util.erl +++ b/applications/ecallmgr/src/ecallmgr_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% Various utilities specific to ecallmgr. More general utilities go %%% in kazoo_util.erl @@ -178,15 +178,25 @@ get_interface_properties(Node, Interface) -> %% retrieves the sip address for the 'to' field -spec get_sip_to(kz_proplist()) -> ne_binary(). get_sip_to(Props) -> - get_sip_to(Props, kzd_freeswitch:call_direction(Props)). + get_sip_to(Props, kzd_freeswitch:original_call_direction(Props)). get_sip_to(Props, <<"outbound">>) -> case props:get_value(<<"Channel-Presence-ID">>, Props) of - 'undefined' -> get_sip_request(Props); + 'undefined' -> + Number = props:get_first_defined([<<"Other-Leg-ANI">> + ,<<"Other-Leg-Callee-ID-Number">> + ,<<"variable_sip_to_user">> + ], Props, <<"nouser">>), + Realm = props:get_first_defined([?GET_CCV(<<"Realm">>) + ,<<"variable_sip_to_host">> + ], Props, ?DEFAULT_REALM), + <>; PresenceId -> PresenceId end; get_sip_to(Props, _) -> - case props:get_value(<<"variable_sip_to_uri">>, Props) of + case props:get_first_defined([<<"variable_sip_to_uri">> + ,<<"variable_sip_req_uri">> + ], Props) of 'undefined' -> get_sip_request(Props); ToUri -> ToUri end. @@ -195,47 +205,30 @@ get_sip_to(Props, _) -> -spec get_sip_from(kz_proplist()) -> ne_binary(). -spec get_sip_from(kz_proplist(), api_binary()) -> ne_binary(). get_sip_from(Props) -> - get_sip_from(Props, kzd_freeswitch:call_direction(Props)). + get_sip_from(Props, kzd_freeswitch:original_call_direction(Props)). get_sip_from(Props, <<"outbound">>) -> + Num = props:get_first_defined([<<"Other-Leg-RDNIS">> + ,<<"Other-Leg-Caller-ID-Number">> + ,<<"variable_sip_from_user">> + ,<<"variable_sip_from_uri">> + ], Props, <<"nouser">>), + [Number | _] = binary:split(Num, <<"@">>, ['global']), Realm = props:get_first_defined([?GET_CCV(<<"Realm">>) - ,<<"variable_sip_invite_domain">> ,<<"variable_sip_auth_realm">> - ,<<"variable_sip_to_host">> ], Props, ?DEFAULT_REALM), - User = props:get_first_defined([?GET_CCV(<<"Username">>) - ,<<"Hunt-Callee-ID-Number">> - ,<<"variable_sip_contact_user">> - ,<<"Other-Leg-Callee-ID-Number">> - ,<<"Caller-Callee-ID-Number">> - ,<<"variable_sip_from_user">> - ], Props, <<"nouser">>), - props:get_first_defined([<<"variable_presence_id">> - ,<<"variable_sip_req_uri">> - ,<<"variable_sip_from_uri">> - ] - ,Props - ,<> - ); + <>; get_sip_from(Props, _) -> - Default = <<(props:get_value(<<"variable_sip_from_user">>, Props, <<"nouser">>))/binary + Default = <<(props:get_value(<<"sip_from_user">>, Props, <<"nouser">>))/binary ,"@" ,(props:get_first_defined([?GET_CCV(<<"Realm">>) ,<<"variable_sip_from_host">> ,<<"sip_from_host">> - ] - ,Props - ,?DEFAULT_REALM - ) - )/binary + ], Props, ?DEFAULT_REALM))/binary >>, props:get_first_defined([<<"Channel-Presence-ID">> - ,<<"variable_presence_id">> ,<<"variable_sip_from_uri">> - ] - ,Props - ,Default - ). + ], Props, Default). %% retrieves the sip address for the 'request' field -spec get_sip_request(kz_proplist()) -> ne_binary(). @@ -243,26 +236,16 @@ get_sip_request(Props) -> [User | _] = binary:split( props:get_first_defined( [<<"Hunt-Destination-Number">> - ,<<"Caller-Destination-Number">> - ,<<"variable_sip_to_user">> ,<<"variable_sip_req_uri">> ,<<"variable_sip_loopback_req_uri">> - ,<<"sip_req_uri">> - ,<<"sip_to_user">> + ,<<"Caller-Destination-Number">> + ,<<"variable_sip_to_user">> ], Props, <<"nouser">>), <<"@">>, ['global']), - Realm = lists:last(binary:split( - props:get_first_defined([?GET_CCV(<<"Realm">>) - ,<<"variable_sip_auth_realm">> - ,<<"variable_sip_to_host">> - ,<<"sip_auth_realm">> - ,<<"sip_to_host">> - ,<<"variable_sip_req_host">> - ,<<"sip_req_host">> - ,<<"variable_sip_req_uri">> - ,<<"sip_req_uri">> - ,<<"variable_sip_loopback_req_uri">> - ,<<"sip_loopback_req_uri">> - ], Props, ?DEFAULT_REALM), <<"@">>, ['global'])), + Realm = props:get_first_defined([?GET_CCV(<<"Realm">>) + ,<<"variable_sip_auth_realm">> + ,<<"variable_sip_to_host">> + ,<<"variable_sip_req_host">> + ], Props, ?DEFAULT_REALM), <>. -spec get_orig_ip(kz_proplist()) -> api_binary(). @@ -538,6 +521,7 @@ get_fs_kv(Key, Val, _) -> -spec get_fs_key(ne_binary()) -> binary(). get_fs_key(<>) -> get_fs_key(Key); +get_fs_key(<<"X-", _/binary>>=Key) -> <<"sip_h_", Key/binary>>; get_fs_key(Key) -> case lists:keyfind(Key, 1, ?SPECIAL_CHANNEL_VARS) of 'false' -> <>; diff --git a/applications/ecallmgr/src/fs_event_filters.hrl b/applications/ecallmgr/src/fs_event_filters.hrl index cc6941c6f49..efb59026350 100644 --- a/applications/ecallmgr/src/fs_event_filters.hrl +++ b/applications/ecallmgr/src/fs_event_filters.hrl @@ -44,10 +44,10 @@ ,<<"Event-Subclass">> ,<<"FreeSWITCH-Hostname">> ,<<"Hangup-Cause">> - ,<<"Hunt-Callee-ID-Number">> ,<<"Hunt-Context">> ,<<"Hunt-Destination-Number">> ,<<"Join-Time">> + ,<<"Other-Leg-ANI">> ,<<"Other-Leg-Call-ID">> ,<<"Other-Leg-Callee-ID-Number">> ,<<"Other-Leg-Caller-ID-Name">> @@ -55,6 +55,7 @@ ,<<"Other-Leg-Channel-Name">> ,<<"Other-Leg-Destination-Number">> ,<<"Other-Leg-Direction">> + ,<<"Other-Leg-RDNIS">> ,<<"Other-Leg-Unique-ID">> ,<<"Publish-Channel-State">> ,<<"Record-File-Path">> @@ -88,12 +89,8 @@ ,<<"sip_auth_response">> ,<<"sip_auth_uri">> ,<<"sip_call_id">> - ,<<"sip_loopback_req_uri">> - ,<<"sip_req_host">> - ,<<"sip_req_uri">> ,<<"sip_request_host">> ,<<"sip_to_host">> - ,<<"sip_to_user">> ,<<"sip_user_agent">> ,<<"technology">> ,<<"to_user">> @@ -149,6 +146,10 @@ ,<<"variable_loopback_leg">> ,<<"variable_media_group_id">> ,<<"variable_originate_disposition">> + ,<<"variable_origination_callee_id_name">> + ,<<"variable_origination_callee_id_number">> + ,<<"variable_origination_caller_id_name">> + ,<<"variable_origination_caller_id_number">> ,<<"variable_origination_uuid">> ,<<"variable_other_loopback_leg_uuid">> ,<<"variable_playback_terminator_used">> @@ -163,11 +164,9 @@ ,<<"variable_silence_hits_exhausted">> ,<<"variable_sip_auth_realm">> ,<<"variable_sip_call_id">> - ,<<"variable_sip_contact_user">> ,<<"variable_sip_from_tag">> ,<<"variable_sip_from_uri">> ,<<"variable_sip_from_user">> - ,<<"variable_sip_invite_domain">> ,<<"variable_sip_loopback_req_uri">> ,<<"variable_sip_received_ip">> ,<<"variable_sip_received_port">> diff --git a/applications/ecallmgr/src/fs_xml.erl b/applications/ecallmgr/src/fs_xml.erl index a8794c1b692..a942e85fbc2 100644 --- a/applications/ecallmgr/src/fs_xml.erl +++ b/applications/ecallmgr/src/fs_xml.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% XML-formatter for FreeSWITCH XML responses %%% Copy of xmerl/src/xmerl_xml.erl diff --git a/applications/ecallmgr/test/ecallmgr_call_command_test.erl b/applications/ecallmgr/test/ecallmgr_call_command_test.erl index ca73325b02c..517c3c2e086 100644 --- a/applications/ecallmgr/test/ecallmgr_call_command_test.erl +++ b/applications/ecallmgr/test/ecallmgr_call_command_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Execute call commands %%% @end diff --git a/applications/ecallmgr/test/ecallmgr_registrar_test.erl b/applications/ecallmgr/test/ecallmgr_registrar_test.erl index cd575af3990..76df78109b1 100644 --- a/applications/ecallmgr/test/ecallmgr_registrar_test.erl +++ b/applications/ecallmgr/test/ecallmgr_registrar_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Listener for reg_success, and reg_query AMQP requests %%% @end diff --git a/applications/fax/doc/README.md b/applications/fax/doc/README.md index 5e28f427c92..cb3428eb88b 100644 --- a/applications/fax/doc/README.md +++ b/applications/fax/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Fax -Title: Fax -Language: en-US -*/ # Fax *Facsimile Services* Why is this still a thing? diff --git a/applications/fax/doc/dns.md b/applications/fax/doc/dns.md index cb1d513d63a..10b9b671a0b 100644 --- a/applications/fax/doc/dns.md +++ b/applications/fax/doc/dns.md @@ -1,8 +1,3 @@ -/* -Section: DNS -Title: DNS -Language: en-US -*/ # DNS configuration for smtp-to-fax diff --git a/applications/fax/doc/gcp.md b/applications/fax/doc/gcp.md index 83ffcef3286..1174a2d0bb4 100644 --- a/applications/fax/doc/gcp.md +++ b/applications/fax/doc/gcp.md @@ -1,8 +1,3 @@ -/* -Section: GCP -Title: Google Cloud Printer -Language: en-US -*/ # Google Cloud Printer ## Features diff --git a/applications/fax/doc/haproxy.md b/applications/fax/doc/haproxy.md index d6130117d28..3156878c9bc 100644 --- a/applications/fax/doc/haproxy.md +++ b/applications/fax/doc/haproxy.md @@ -1,8 +1,3 @@ -/* -Section: HAPROXY -Title: HAPROXY -Language: en-US -*/ # HAPROXY role in smtp to fax if you have more than one kapps node running the fax application, you may want to distribute the load from smtp among the several nodes. diff --git a/applications/fax/doc/postfix.md b/applications/fax/doc/postfix.md index 9c5bf5e7505..2e138438605 100644 --- a/applications/fax/doc/postfix.md +++ b/applications/fax/doc/postfix.md @@ -1,8 +1,3 @@ -/* -Section: POSTFIX -Title: Postfix -Language: en-US -*/ # Postfix role in smtp-to-fax although you can expose kazoo fax on port 25 or use haproxy, we recommend to use postfix to filter email spam before delivering to haproxy/kazoo diff --git a/applications/fax/doc/smtp.md b/applications/fax/doc/smtp.md index 47e9a20eb52..61a274b3312 100644 --- a/applications/fax/doc/smtp.md +++ b/applications/fax/doc/smtp.md @@ -1,8 +1,3 @@ -/* -Section: SMTP -Title: SMTP Integration -Language: en-US -*/ # SMTP Integration kazoo will generate an smtp domain address for each faxbox on its creation. diff --git a/applications/fax/doc/user.md b/applications/fax/doc/user.md index e0aad3ad0b9..2e526d03296 100644 --- a/applications/fax/doc/user.md +++ b/applications/fax/doc/user.md @@ -1,8 +1,3 @@ -/* -Section: USER -Title: User utilities -Language: en-US -*/ # Internet fax for Office 2010 * Create a fax.reg file with the contents below replacing xxx.fax.kazoo.io with the smtp address of faxbox. diff --git a/applications/fax/src/fax_app.erl b/applications/fax/src/fax_app.erl index 1eb6092235f..ad25c0f0b8c 100644 --- a/applications/fax/src/fax_app.erl +++ b/applications/fax/src/fax_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_cloud.erl b/applications/fax/src/fax_cloud.erl index 1aa181fa985..6268f007dfc 100644 --- a/applications/fax/src/fax_cloud.erl +++ b/applications/fax/src/fax_cloud.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -195,14 +195,14 @@ download_file(URL, Authorization) -> Headers = [?GPC_PROXY_HEADER , {"Authorization",Authorization}], case kz_http:get(kz_util:to_list(URL), Headers) of {'ok', 200, RespHeaders, RespBody} -> - CT = kz_util:to_binary(props:get_value("Content-Type", RespHeaders)), + CT = kz_util:to_binary(props:get_value("content-type", RespHeaders)), Ext = kz_mime:to_extension(CT), FileName = <<"/tmp/fax_printer_" ,(kz_util:to_binary(kz_util:current_tstamp()))/binary ,"." ,Ext/binary >>, - case file:write_file(FileName,RespBody) of + case file:write_file(FileName, RespBody) of 'ok' -> {'ok', CT, RespBody}; {'error', _}=Error -> lager:debug("error writing file ~s from ~s : ~p", [URL, FileName, Error]), @@ -403,7 +403,7 @@ check_registration(AppId, <<"registered">>, JObj) -> {'ok', 200, _RespHeaders, RespXML} -> JObjPool = kz_json:decode(RespXML), Result = kz_json:get_value(<<"success">>, JObjPool, 'false'), - process_registration_result(Result, AppId, JObj,JObjPool ); + process_registration_result(Result, AppId, JObj, JObjPool); _A -> lager:debug("unexpected result checking registration of printer ~s: ~p", [PrinterId, _A]) end; diff --git a/applications/fax/src/fax_file_proxy.erl b/applications/fax/src/fax_file_proxy.erl index 0fe7638a0df..9f0d2a8fd78 100644 --- a/applications/fax/src/fax_file_proxy.erl +++ b/applications/fax/src/fax_file_proxy.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_init.erl b/applications/fax/src/fax_init.erl index e1b6bf06ca5..4837bef1cc9 100644 --- a/applications/fax/src/fax_init.erl +++ b/applications/fax/src/fax_init.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_jobs.erl b/applications/fax/src/fax_jobs.erl index 78f9c9244ef..d6ac8c66e15 100644 --- a/applications/fax/src/fax_jobs.erl +++ b/applications/fax/src/fax_jobs.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_jobs_sup.erl b/applications/fax/src/fax_jobs_sup.erl index f3d6ef8e109..5c75a14f426 100644 --- a/applications/fax/src/fax_jobs_sup.erl +++ b/applications/fax/src/fax_jobs_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_maintenance.erl b/applications/fax/src/fax_maintenance.erl index ed6f1b711bb..e06a78bd335 100644 --- a/applications/fax/src/fax_maintenance.erl +++ b/applications/fax/src/fax_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_monitor.erl b/applications/fax/src/fax_monitor.erl index 6003504e9de..b4369765e12 100644 --- a/applications/fax/src/fax_monitor.erl +++ b/applications/fax/src/fax_monitor.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_request.erl b/applications/fax/src/fax_request.erl index f8f3572f216..0ee16201702 100644 --- a/applications/fax/src/fax_request.erl +++ b/applications/fax/src/fax_request.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_requests_sup.erl b/applications/fax/src/fax_requests_sup.erl index b80060c23aa..31a0855705d 100644 --- a/applications/fax/src/fax_requests_sup.erl +++ b/applications/fax/src/fax_requests_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_shared_listener.erl b/applications/fax/src/fax_shared_listener.erl index 12c4beeb21f..4236a2f0016 100644 --- a/applications/fax/src/fax_shared_listener.erl +++ b/applications/fax/src/fax_shared_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_smtp.erl b/applications/fax/src/fax_smtp.erl index f55c19cf8e6..e55db94bce9 100644 --- a/applications/fax/src/fax_smtp.erl +++ b/applications/fax/src/fax_smtp.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_sup.erl b/applications/fax/src/fax_sup.erl index 2f959c0a802..34760426322 100644 --- a/applications/fax/src/fax_sup.erl +++ b/applications/fax/src/fax_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_util.erl b/applications/fax/src/fax_util.erl index a2dbb0ddbc4..b580f326b46 100644 --- a/applications/fax/src/fax_util.erl +++ b/applications/fax/src/fax_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_worker.erl b/applications/fax/src/fax_worker.erl index f29c2c54d46..16455a11aa0 100644 --- a/applications/fax/src/fax_worker.erl +++ b/applications/fax/src/fax_worker.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -939,7 +939,7 @@ fetch_document_from_url(JObj) -> prepare_contents(JobId, RespHeaders, RespContent) -> lager:debug("preparing fax contents", []), TmpDir = kapps_config:get_binary(?CONFIG_CAT, <<"file_cache_path">>, <<"/tmp/">>), - case fax_util:normalize_content_type(props:get_value("Content-Type", RespHeaders, <<"application/octet-stream">>)) of + case fax_util:normalize_content_type(props:get_value("content-type", RespHeaders, <<"application/octet-stream">>)) of <<"image/tiff">> -> OutputFile = list_to_binary([TmpDir, JobId, ".tiff"]), kz_util:write_file(OutputFile, RespContent), diff --git a/applications/fax/src/fax_worker_sup.erl b/applications/fax/src/fax_worker_sup.erl index 203542ec9a1..17d6bfc2116 100644 --- a/applications/fax/src/fax_worker_sup.erl +++ b/applications/fax/src/fax_worker_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_xmpp.erl b/applications/fax/src/fax_xmpp.erl index 1567f8413dd..19c1f4a5425 100644 --- a/applications/fax/src/fax_xmpp.erl +++ b/applications/fax/src/fax_xmpp.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/fax/src/fax_xmpp_sup.erl b/applications/fax/src/fax_xmpp_sup.erl index c7ac1daa2f0..e79ab73e5f2 100644 --- a/applications/fax/src/fax_xmpp_sup.erl +++ b/applications/fax/src/fax_xmpp_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/fax/src/kapi_xmpp.erl b/applications/fax/src/kapi_xmpp.erl index 0847011bddf..9c140aa57a1 100644 --- a/applications/fax/src/kapi_xmpp.erl +++ b/applications/fax/src/kapi_xmpp.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/frontier/doc/README.md b/applications/frontier/doc/README.md index 78f0b6bc06d..80304dd2220 100644 --- a/applications/frontier/doc/README.md +++ b/applications/frontier/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Frontier -Title: Frontier -Language: en-US -*/ # Frontier *The Guard of your SIP kingdom* Provides Kamailio with information on account and device-level access-lists and incoming packet rate limits. diff --git a/applications/frontier/src/frontier_app.erl b/applications/frontier/src/frontier_app.erl index 64594c0e697..301a17490da 100644 --- a/applications/frontier/src/frontier_app.erl +++ b/applications/frontier/src/frontier_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/frontier/src/frontier_handle_acl.erl b/applications/frontier/src/frontier_handle_acl.erl index dc51c5f85df..3015520a7a1 100644 --- a/applications/frontier/src/frontier_handle_acl.erl +++ b/applications/frontier/src/frontier_handle_acl.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/frontier/src/frontier_handle_rate.erl b/applications/frontier/src/frontier_handle_rate.erl index 4c9eeb3e98e..11cf996d539 100644 --- a/applications/frontier/src/frontier_handle_rate.erl +++ b/applications/frontier/src/frontier_handle_rate.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/frontier/src/frontier_init.erl b/applications/frontier/src/frontier_init.erl index b117a0d290b..24ef15b7159 100644 --- a/applications/frontier/src/frontier_init.erl +++ b/applications/frontier/src/frontier_init.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/frontier/src/frontier_maintenance.erl b/applications/frontier/src/frontier_maintenance.erl index 538c9506ac4..cfb80d84c8f 100644 --- a/applications/frontier/src/frontier_maintenance.erl +++ b/applications/frontier/src/frontier_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/frontier/src/frontier_shared_listener.erl b/applications/frontier/src/frontier_shared_listener.erl index a40d800d2a8..488b11037d7 100644 --- a/applications/frontier/src/frontier_shared_listener.erl +++ b/applications/frontier/src/frontier_shared_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/frontier/src/frontier_sup.erl b/applications/frontier/src/frontier_sup.erl index 4501580ab93..f53690b4ef0 100644 --- a/applications/frontier/src/frontier_sup.erl +++ b/applications/frontier/src/frontier_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/frontier/src/frontier_utils.erl b/applications/frontier/src/frontier_utils.erl index 8e0ea14a5e5..0e4ade393a1 100644 --- a/applications/frontier/src/frontier_utils.erl +++ b/applications/frontier/src/frontier_utils.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/frontier/src/kapi_frontier.erl b/applications/frontier/src/kapi_frontier.erl index d2d0addf44e..dc5a9f4ed53 100644 --- a/applications/frontier/src/kapi_frontier.erl +++ b/applications/frontier/src/kapi_frontier.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/hangups/src/hangups_app.erl b/applications/hangups/src/hangups_app.erl index 1e39ca2a9a4..68e1b0a69cb 100644 --- a/applications/hangups/src/hangups_app.erl +++ b/applications/hangups/src/hangups_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/hangups/src/hangups_channel_destroy.erl b/applications/hangups/src/hangups_channel_destroy.erl index 77d41b922e5..18308ee4af1 100644 --- a/applications/hangups/src/hangups_channel_destroy.erl +++ b/applications/hangups/src/hangups_channel_destroy.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/hangups/src/hangups_listener.erl b/applications/hangups/src/hangups_listener.erl index 183f227180b..85fb2bcee20 100644 --- a/applications/hangups/src/hangups_listener.erl +++ b/applications/hangups/src/hangups_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/hangups/src/hangups_maintenance.erl b/applications/hangups/src/hangups_maintenance.erl index 2d04e23f6bb..7cf23f57240 100644 --- a/applications/hangups/src/hangups_maintenance.erl +++ b/applications/hangups/src/hangups_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/hangups/src/hangups_monitoring.erl b/applications/hangups/src/hangups_monitoring.erl index 441f97ef203..3a72b8b547e 100644 --- a/applications/hangups/src/hangups_monitoring.erl +++ b/applications/hangups/src/hangups_monitoring.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz Inc +%%% @copyright (C) 2017, 2600Hz Inc %%% @doc %%% Periodically checks the hangup stats for anomalies %%% diff --git a/applications/hangups/src/hangups_query_listener.erl b/applications/hangups/src/hangups_query_listener.erl index c1909a85326..af46aca2d50 100644 --- a/applications/hangups/src/hangups_query_listener.erl +++ b/applications/hangups/src/hangups_query_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/hangups/src/hangups_sup.erl b/applications/hangups/src/hangups_sup.erl index 24e8f41267d..3666f6e2590 100644 --- a/applications/hangups/src/hangups_sup.erl +++ b/applications/hangups/src/hangups_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/hangups/src/hangups_util.erl b/applications/hangups/src/hangups_util.erl index 6180ce158c4..f2efd8558d7 100644 --- a/applications/hangups/src/hangups_util.erl +++ b/applications/hangups/src/hangups_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/hotornot/doc/README.md b/applications/hotornot/doc/README.md index c593af05c26..30a73f96044 100644 --- a/applications/hotornot/doc/README.md +++ b/applications/hotornot/doc/README.md @@ -1,7 +1,2 @@ -/* -Section: Hot or Not -Title: Hot or Not -Language: en-US -*/ # Hot or Not *Call rating* diff --git a/applications/hotornot/src/hon_rater.erl b/applications/hotornot/src/hon_rater.erl index 1e67d0cc3fa..0aa7a7ea232 100644 --- a/applications/hotornot/src/hon_rater.erl +++ b/applications/hotornot/src/hon_rater.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Given a rate_req, find appropriate rate for the call %%% @end diff --git a/applications/hotornot/src/hon_trie.erl b/applications/hotornot/src/hon_trie.erl index 3d8aa1a90eb..671870016a9 100644 --- a/applications/hotornot/src/hon_trie.erl +++ b/applications/hotornot/src/hon_trie.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Rater whapp; send me a DID, get a rate back %%% diff --git a/applications/hotornot/src/hon_util.erl b/applications/hotornot/src/hon_util.erl index 93f784cc0ec..e1d2f858ce1 100644 --- a/applications/hotornot/src/hon_util.erl +++ b/applications/hotornot/src/hon_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/hotornot/src/hotornot_app.erl b/applications/hotornot/src/hotornot_app.erl index d8b4e01212b..4a013e40e93 100644 --- a/applications/hotornot/src/hotornot_app.erl +++ b/applications/hotornot/src/hotornot_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/hotornot/src/hotornot_listener.erl b/applications/hotornot/src/hotornot_listener.erl index ba6902f9e04..903c77caaf3 100644 --- a/applications/hotornot/src/hotornot_listener.erl +++ b/applications/hotornot/src/hotornot_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Rater whapp; send me a DID, get a rate back %%% @end diff --git a/applications/hotornot/src/hotornot_maintenance.erl b/applications/hotornot/src/hotornot_maintenance.erl index fdf6aad97de..d985525536a 100644 --- a/applications/hotornot/src/hotornot_maintenance.erl +++ b/applications/hotornot/src/hotornot_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Helper functions for users to inspect how HotOrNot is running %%% @end diff --git a/applications/hotornot/src/hotornot_sup.erl b/applications/hotornot/src/hotornot_sup.erl index 03b1beb989a..06758d7b4af 100644 --- a/applications/hotornot/src/hotornot_sup.erl +++ b/applications/hotornot/src/hotornot_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/hotornot/test/hon_util_test.erl b/applications/hotornot/test/hon_util_test.erl index ed73daffa0e..e4beccde21c 100644 --- a/applications/hotornot/test/hon_util_test.erl +++ b/applications/hotornot/test/hon_util_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/jonny5/doc/README.md b/applications/jonny5/doc/README.md index d5be188ee4e..2765c983d1f 100644 --- a/applications/jonny5/doc/README.md +++ b/applications/jonny5/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Jonny5 -Title: Jonny5 -Language: en-US -*/ # Overview diff --git a/applications/jonny5/src/j5_allotments.erl b/applications/jonny5/src/j5_allotments.erl index 71a77175e8c..4be6312fc80 100644 --- a/applications/jonny5/src/j5_allotments.erl +++ b/applications/jonny5/src/j5_allotments.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/jonny5/src/j5_authz_req.erl b/applications/jonny5/src/j5_authz_req.erl index 1e4b3526c7d..0447e809d90 100644 --- a/applications/jonny5/src/j5_authz_req.erl +++ b/applications/jonny5/src/j5_authz_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Handlers for various AMQP payloads %%% @end diff --git a/applications/jonny5/src/j5_balance_check_req.erl b/applications/jonny5/src/j5_balance_check_req.erl index 9142b250412..16740617e37 100644 --- a/applications/jonny5/src/j5_balance_check_req.erl +++ b/applications/jonny5/src/j5_balance_check_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Handlers for various AMQP payloads %%% @end diff --git a/applications/jonny5/src/j5_channel_destroy.erl b/applications/jonny5/src/j5_channel_destroy.erl index 6da6267f3dc..9f36b07fb1a 100644 --- a/applications/jonny5/src/j5_channel_destroy.erl +++ b/applications/jonny5/src/j5_channel_destroy.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Handlers for various AMQP payloads %%% @end diff --git a/applications/jonny5/src/j5_channels.erl b/applications/jonny5/src/j5_channels.erl index f7e7c2387fe..8cc2bcb64f5 100644 --- a/applications/jonny5/src/j5_channels.erl +++ b/applications/jonny5/src/j5_channels.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/jonny5/src/j5_flat_rate.erl b/applications/jonny5/src/j5_flat_rate.erl index faa8069a65f..42498d8a81a 100644 --- a/applications/jonny5/src/j5_flat_rate.erl +++ b/applications/jonny5/src/j5_flat_rate.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -12,8 +12,8 @@ -include("jonny5.hrl"). --define(DEFAULT_WHITELIST, <<"^\\+?1\\d{10}$">>). --define(DEFAULT_BLACKLIST, <<"^\\+?1(684|264|268|242|246|441|284|345|767|809|829|849|473|671|876|664|670|787|939|869|758|784|721|868|649|340|900|8(?:[0,2,3,4,5,6,7]{2}|8[0-9]))\\d{7}$">>). +-define(DEFAULT_WHITELIST, <<"^\\+1\\d{10}$">>). +-define(DEFAULT_BLACKLIST, <<"^\\+1(684|264|268|242|246|441|284|345|767|809|829|849|473|671|876|664|670|787|939|869|758|784|721|868|649|340|900|800|888|877|866|855|844)\\d{7}$">>). -ifdef(TEST). -define(WHITELIST, ?DEFAULT_WHITELIST). diff --git a/applications/jonny5/src/j5_hard_limit.erl b/applications/jonny5/src/j5_hard_limit.erl index f5273e9a4db..25e713042eb 100644 --- a/applications/jonny5/src/j5_hard_limit.erl +++ b/applications/jonny5/src/j5_hard_limit.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/jonny5/src/j5_limits.erl b/applications/jonny5/src/j5_limits.erl index a97dcc14468..5f9fcda4fe3 100644 --- a/applications/jonny5/src/j5_limits.erl +++ b/applications/jonny5/src/j5_limits.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/jonny5/src/j5_per_minute.erl b/applications/jonny5/src/j5_per_minute.erl index c239f14e437..44d9385dccb 100644 --- a/applications/jonny5/src/j5_per_minute.erl +++ b/applications/jonny5/src/j5_per_minute.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/jonny5/src/j5_request.erl b/applications/jonny5/src/j5_request.erl index 7d48bc222f3..e746f97a557 100644 --- a/applications/jonny5/src/j5_request.erl +++ b/applications/jonny5/src/j5_request.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Handlers for various AMQP payloads %%% @end diff --git a/applications/jonny5/src/j5_util.erl b/applications/jonny5/src/j5_util.erl index 4eabb399592..c6f5c4dc1e8 100644 --- a/applications/jonny5/src/j5_util.erl +++ b/applications/jonny5/src/j5_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Handlers for various AMQP payloads %%% @end diff --git a/applications/jonny5/src/jonny5_app.erl b/applications/jonny5/src/jonny5_app.erl index fa87a0ff93f..3551451821a 100644 --- a/applications/jonny5/src/jonny5_app.erl +++ b/applications/jonny5/src/jonny5_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/jonny5/src/jonny5_listener.erl b/applications/jonny5/src/jonny5_listener.erl index 7993b955d38..e3fdbc5db54 100644 --- a/applications/jonny5/src/jonny5_listener.erl +++ b/applications/jonny5/src/jonny5_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/jonny5/src/jonny5_maintenance.erl b/applications/jonny5/src/jonny5_maintenance.erl index 6a9cbb2f74d..a054f2c09f1 100644 --- a/applications/jonny5/src/jonny5_maintenance.erl +++ b/applications/jonny5/src/jonny5_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Handlers for various AMQP payloads %%% @end diff --git a/applications/jonny5/src/jonny5_sup.erl b/applications/jonny5/src/jonny5_sup.erl index 1228b154bec..7ee0ab23a9b 100644 --- a/applications/jonny5/src/jonny5_sup.erl +++ b/applications/jonny5/src/jonny5_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/konami/doc/README.md b/applications/konami/doc/README.md index 5efe0c8e109..297430a4e11 100644 --- a/applications/konami/doc/README.md +++ b/applications/konami/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Konami -Title: Konami -Language: en-US -*/ # Konami *In-Call Feature Codes* up up down down left right left right B A diff --git a/applications/konami/doc/hold.md b/applications/konami/doc/hold.md index 42e8f9d4daf..f74830a09a1 100644 --- a/applications/konami/doc/hold.md +++ b/applications/konami/doc/hold.md @@ -1,9 +1,3 @@ -/* -Section: Konami -Title: Hold -Language: en-US -Version: 3.22 -*/ Some phones do not support putting the other line on hold or making it easy to set custom music to play while on hold. The Konami *hold* module permits both. diff --git a/applications/konami/doc/move.md b/applications/konami/doc/move.md index 2700dbcf6bb..7508a451ed0 100644 --- a/applications/konami/doc/move.md +++ b/applications/konami/doc/move.md @@ -1,9 +1,3 @@ -/* -Section: Konami -Title: Move -Language: en-US -Version: 3.19 -*/ When a user is talking on one of their endpoints (say their Kazoo Mobile phone) and they move locations to have access to their IP Desk phone, it is helpful to move the call from the mobile phone to the deskphone with the other party unware of the change. diff --git a/applications/konami/doc/resume.md b/applications/konami/doc/resume.md index 87d436a6aa0..2d295625b51 100644 --- a/applications/konami/doc/resume.md +++ b/applications/konami/doc/resume.md @@ -1,8 +1,3 @@ -/* -Section: Konami -Title: Resume -Language: en-US -*/ Some Konami actions put the other leg on hold (say for a transfer). The *resume* module allows the initiating party to reconnect with the on-hold party (cancelling whatever metaflow module had initiated the hold). diff --git a/applications/konami/doc/transfer.md b/applications/konami/doc/transfer.md index 12165226d48..09b09876cb7 100644 --- a/applications/konami/doc/transfer.md +++ b/applications/konami/doc/transfer.md @@ -1,8 +1,3 @@ -/* -Section: Konami -Title: Transfers -Language: en-US -*/ # In-Call Attended Transfer diff --git a/applications/konami/src/kapi_konami.erl b/applications/konami/src/kapi_konami.erl index 6461f42351d..43bc2171e33 100644 --- a/applications/konami/src/kapi_konami.erl +++ b/applications/konami/src/kapi_konami.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/konami/src/konami_app.erl b/applications/konami/src/konami_app.erl index e80612e3b87..2e5d73de64b 100644 --- a/applications/konami/src/konami_app.erl +++ b/applications/konami/src/konami_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/konami/src/konami_code_exe.erl b/applications/konami/src/konami_code_exe.erl index 7fc31443fab..b885cdcfd9c 100644 --- a/applications/konami/src/konami_code_exe.erl +++ b/applications/konami/src/konami_code_exe.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Execute a metaflow %%% @end diff --git a/applications/konami/src/konami_code_fsm.erl b/applications/konami/src/konami_code_fsm.erl index 849d038f559..aca98b18107 100644 --- a/applications/konami/src/konami_code_fsm.erl +++ b/applications/konami/src/konami_code_fsm.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/konami/src/konami_config.erl b/applications/konami/src/konami_config.erl index 2ed4afd984e..a93930ed2c6 100644 --- a/applications/konami/src/konami_config.erl +++ b/applications/konami/src/konami_config.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Handles Konami code configs %%% @end @@ -9,10 +9,10 @@ -module(konami_config). -export([numbers/0, numbers/1 - ,patterns/0, patterns/1 - ,binding_digit/0, binding_digit/1 - ,timeout/0, timeout/1 - ,listen_on/0, listen_on/1 + ,patterns/0, patterns/1 + ,binding_digit/0, binding_digit/1 + ,timeout/0, timeout/1 + ,listen_on/0, listen_on/1 ]). -include("konami.hrl"). @@ -21,7 +21,7 @@ -define(DEFAULT_DIGIT_TIMEOUT, 800). -define(META_SAY_HI, kz_json:from_list([{<<"module">>, <<"say">>} - ,{<<"data">>, kz_json:from_list([{<<"text">>, <<"hi">>}])} + ,{<<"data">>, kz_json:from_list([{<<"text">>, <<"hi">>}])} ])). -define(DEFAULT_NUMBERS, kz_json:from_list([{<<"2">>, ?META_SAY_HI} diff --git a/applications/konami/src/konami_event_listener.erl b/applications/konami/src/konami_event_listener.erl index 1088fe6cf06..c65bcf5f307 100644 --- a/applications/konami/src/konami_event_listener.erl +++ b/applications/konami/src/konami_event_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/konami/src/konami_init.erl b/applications/konami/src/konami_init.erl index abfe18ada8d..bc4f07f4ad0 100644 --- a/applications/konami/src/konami_init.erl +++ b/applications/konami/src/konami_init.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Handles setup/initialization of Konami %%% @end diff --git a/applications/konami/src/konami_listener.erl b/applications/konami/src/konami_listener.erl index 0c44fade0c8..d1ce95f0d52 100644 --- a/applications/konami/src/konami_listener.erl +++ b/applications/konami/src/konami_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end @@ -35,7 +35,7 @@ ,{'route', []} ]). -define(RESPONDERS, [{{?MODULE, 'handle_metaflow'} - ,[{<<"metaflow">>, <<"bindings">>}] + ,[{<<"metaflow">>, <<"bind">>}] } ,{{?MODULE, 'handle_channel_create'} ,[{<<"call_event">>, <<"CHANNEL_CREATE">>}] diff --git a/applications/konami/src/konami_maintenance.erl b/applications/konami/src/konami_maintenance.erl index b917d0243e8..b69fc9dbcdd 100644 --- a/applications/konami/src/konami_maintenance.erl +++ b/applications/konami/src/konami_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/konami/src/konami_sup.erl b/applications/konami/src/konami_sup.erl index 351b928f5d6..d061e3c26ff 100644 --- a/applications/konami/src/konami_sup.erl +++ b/applications/konami/src/konami_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/konami/src/konami_util.erl b/applications/konami/src/konami_util.erl index 444b9be0c6b..d17d4b2ab07 100644 --- a/applications/konami/src/konami_util.erl +++ b/applications/konami/src/konami_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/konami/src/module/konami_break.erl b/applications/konami/src/module/konami_break.erl index f763b56d5de..20102a430ad 100644 --- a/applications/konami/src/module/konami_break.erl +++ b/applications/konami/src/module/konami_break.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Hang up the call %%% Data = {} diff --git a/applications/konami/src/module/konami_callflow.erl b/applications/konami/src/module/konami_callflow.erl index 526a300f4a2..8ecafde8178 100644 --- a/applications/konami/src/module/konami_callflow.erl +++ b/applications/konami/src/module/konami_callflow.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Overlay a callflow onto the caller %%% data:{ diff --git a/applications/konami/src/module/konami_hangup.erl b/applications/konami/src/module/konami_hangup.erl index 45420650266..262c6c38b82 100644 --- a/applications/konami/src/module/konami_hangup.erl +++ b/applications/konami/src/module/konami_hangup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Hang up the call %%% Data = {} diff --git a/applications/konami/src/module/konami_hold.erl b/applications/konami/src/module/konami_hold.erl index 87773cdb035..c0d9eb5bfa7 100644 --- a/applications/konami/src/module/konami_hold.erl +++ b/applications/konami/src/module/konami_hold.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% Put the call on hold %%% Data = { diff --git a/applications/konami/src/module/konami_intercept.erl b/applications/konami/src/module/konami_intercept.erl index d5fd82d01ea..7a17d4a06b8 100644 --- a/applications/konami/src/module/konami_intercept.erl +++ b/applications/konami/src/module/konami_intercept.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% data: %%% target_type: "user" or "device" diff --git a/applications/konami/src/module/konami_move.erl b/applications/konami/src/module/konami_move.erl index c0e30fb802e..3a8dc0e896c 100644 --- a/applications/konami/src/module/konami_move.erl +++ b/applications/konami/src/module/konami_move.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% data: %%% owner_id: User-ID to fetch devices for diff --git a/applications/konami/src/module/konami_play.erl b/applications/konami/src/module/konami_play.erl index a22131b1c37..53bbd1edf83 100644 --- a/applications/konami/src/module/konami_play.erl +++ b/applications/konami/src/module/konami_play.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Play a media file %%% Data = { diff --git a/applications/konami/src/module/konami_record_call.erl b/applications/konami/src/module/konami_record_call.erl index 71833bbbd17..ccf4fe1e93c 100644 --- a/applications/konami/src/module/konami_record_call.erl +++ b/applications/konami/src/module/konami_record_call.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Record something %%% "data":{ diff --git a/applications/konami/src/module/konami_resume.erl b/applications/konami/src/module/konami_resume.erl index 5503d6ed4b8..f103b7093ca 100644 --- a/applications/konami/src/module/konami_resume.erl +++ b/applications/konami/src/module/konami_resume.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Reconnect the two legs of the call, if possible %%% Data = { diff --git a/applications/konami/src/module/konami_say.erl b/applications/konami/src/module/konami_say.erl index 8d37d514261..adb337ff781 100644 --- a/applications/konami/src/module/konami_say.erl +++ b/applications/konami/src/module/konami_say.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Say something %%% Data = { diff --git a/applications/konami/src/module/konami_transfer.erl b/applications/konami/src/module/konami_transfer.erl index f21c56d8b9b..ab57b3a8ab6 100644 --- a/applications/konami/src/module/konami_transfer.erl +++ b/applications/konami/src/module/konami_transfer.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% Transfers caller to the extension extracted in the regex %%% Data = { diff --git a/applications/konami/src/module/konami_tts.erl b/applications/konami/src/module/konami_tts.erl index e904f2c292a..8a75dde467e 100644 --- a/applications/konami/src/module/konami_tts.erl +++ b/applications/konami/src/module/konami_tts.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Text To Speech %%% Data = { diff --git a/applications/media_mgr/doc/README.md b/applications/media_mgr/doc/README.md index f386f5db474..583068e8f0a 100644 --- a/applications/media_mgr/doc/README.md +++ b/applications/media_mgr/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Media Manager -Title: Media Manager -Language: en-US -*/ # Media Manager Single play stream diff --git a/applications/media_mgr/src/media_listener.erl b/applications/media_mgr/src/media_listener.erl index c9f31ab743d..0ce713ee944 100644 --- a/applications/media_mgr/src/media_listener.erl +++ b/applications/media_mgr/src/media_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/media_mgr/src/media_mgr_app.erl b/applications/media_mgr/src/media_mgr_app.erl index 7f0295fdf1f..6de0429ecd7 100644 --- a/applications/media_mgr/src/media_mgr_app.erl +++ b/applications/media_mgr/src/media_mgr_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/media_mgr/src/media_mgr_maintenance.erl b/applications/media_mgr/src/media_mgr_maintenance.erl index 650f87df0f0..6231546b787 100644 --- a/applications/media_mgr/src/media_mgr_maintenance.erl +++ b/applications/media_mgr/src/media_mgr_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/media_mgr/src/media_mgr_sup.erl b/applications/media_mgr/src/media_mgr_sup.erl index 1cea1addc50..e8785d19340 100644 --- a/applications/media_mgr/src/media_mgr_sup.erl +++ b/applications/media_mgr/src/media_mgr_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016 2600Hz +%%% @copyright (C) 2010-2017 2600Hz %%% @doc %%% %%% @end diff --git a/applications/milliwatt/doc/README.md b/applications/milliwatt/doc/README.md index 875d1896a89..ec0e5854204 100644 --- a/applications/milliwatt/doc/README.md +++ b/applications/milliwatt/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Milliwatt -Title: Milliwatt -Language: en-US -*/ # Milliwatt *Echo and tone for monitoring* Beeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep diff --git a/applications/milliwatt/src/milliwatt.hrl b/applications/milliwatt/src/milliwatt.hrl index 2d0841500c8..b8ede910b05 100644 --- a/applications/milliwatt/src/milliwatt.hrl +++ b/applications/milliwatt/src/milliwatt.hrl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz, INC +%%% @copyright (C) 2013-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/applications/milliwatt/src/milliwatt_app.erl b/applications/milliwatt/src/milliwatt_app.erl index 47d097b5e93..867ff81db1e 100644 --- a/applications/milliwatt/src/milliwatt_app.erl +++ b/applications/milliwatt/src/milliwatt_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/milliwatt/src/milliwatt_echo.erl b/applications/milliwatt/src/milliwatt_echo.erl index 822bd480058..6ec4260882f 100644 --- a/applications/milliwatt/src/milliwatt_echo.erl +++ b/applications/milliwatt/src/milliwatt_echo.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/milliwatt/src/milliwatt_listener.erl b/applications/milliwatt/src/milliwatt_listener.erl index cc458d61126..bd152aee12e 100644 --- a/applications/milliwatt/src/milliwatt_listener.erl +++ b/applications/milliwatt/src/milliwatt_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/milliwatt/src/milliwatt_route_req.erl b/applications/milliwatt/src/milliwatt_route_req.erl index d0a603b6bad..110ca47780e 100644 --- a/applications/milliwatt/src/milliwatt_route_req.erl +++ b/applications/milliwatt/src/milliwatt_route_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/milliwatt/src/milliwatt_sup.erl b/applications/milliwatt/src/milliwatt_sup.erl index 03d5597d585..9cf63f22473 100644 --- a/applications/milliwatt/src/milliwatt_sup.erl +++ b/applications/milliwatt/src/milliwatt_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/milliwatt/src/milliwatt_tone.erl b/applications/milliwatt/src/milliwatt_tone.erl index 6dd3bc033a7..cf622338509 100644 --- a/applications/milliwatt/src/milliwatt_tone.erl +++ b/applications/milliwatt/src/milliwatt_tone.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/notify/doc/README.md b/applications/notify/doc/README.md index c838889363a..5daf3b8eecc 100644 --- a/applications/notify/doc/README.md +++ b/applications/notify/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Notify -Title: Notify -Language: en-US -*/ # Notify diff --git a/applications/notify/src/notify_app.erl b/applications/notify/src/notify_app.erl index c466949af34..89a101f66be 100644 --- a/applications/notify/src/notify_app.erl +++ b/applications/notify/src/notify_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/notify/src/notify_cnam_request.erl b/applications/notify/src/notify_cnam_request.erl index 065415caf23..caece6e2808 100644 --- a/applications/notify/src/notify_cnam_request.erl +++ b/applications/notify/src/notify_cnam_request.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with voicemail attachment to the user. diff --git a/applications/notify/src/notify_deregister.erl b/applications/notify/src/notify_deregister.erl index 60aa6145095..740b24d32b4 100644 --- a/applications/notify/src/notify_deregister.erl +++ b/applications/notify/src/notify_deregister.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with voicemail attachment to the user. diff --git a/applications/notify/src/notify_fax_inbound_error_to_email.erl b/applications/notify/src/notify_fax_inbound_error_to_email.erl index 5970684c4cc..be4293b8be2 100644 --- a/applications/notify/src/notify_fax_inbound_error_to_email.erl +++ b/applications/notify/src/notify_fax_inbound_error_to_email.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with fax attachment to the user. diff --git a/applications/notify/src/notify_fax_inbound_to_email.erl b/applications/notify/src/notify_fax_inbound_to_email.erl index 71efd578668..ef94316c59c 100644 --- a/applications/notify/src/notify_fax_inbound_to_email.erl +++ b/applications/notify/src/notify_fax_inbound_to_email.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with fax attachment to the user. diff --git a/applications/notify/src/notify_fax_outbound_error_to_email.erl b/applications/notify/src/notify_fax_outbound_error_to_email.erl index 293f3093775..863e5894960 100644 --- a/applications/notify/src/notify_fax_outbound_error_to_email.erl +++ b/applications/notify/src/notify_fax_outbound_error_to_email.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with fax attachment to the user. diff --git a/applications/notify/src/notify_fax_outbound_to_email.erl b/applications/notify/src/notify_fax_outbound_to_email.erl index 5dc70d13efc..c8086af5ad0 100644 --- a/applications/notify/src/notify_fax_outbound_to_email.erl +++ b/applications/notify/src/notify_fax_outbound_to_email.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with fax attachment to the user. @@ -35,12 +35,21 @@ handle_req(JObj, _Props) -> lager:debug("new outbound fax left, sending to email if enabled"), - AccountId = kz_json:get_value(<<"Account-ID">>, JObj), + AccountDb = kapi_notifications:account_db(JObj), JobId = kz_json:get_value(<<"Fax-JobId">>, JObj), - lager:debug("account-id: ~s, fax-id: ~s", [AccountId, JobId]), - {'ok', FaxDoc} = kz_datamgr:open_doc(?KZ_FAXES_DB, JobId), + lager:debug("account-db: ~s, fax-id: ~s", [AccountDb, JobId]), + + case kz_datamgr:open_cache_doc(AccountDb, JobId) of + {'ok', FaxDoc} -> + process_req(FaxDoc, JObj, _Props); + {'error', Err} -> + lager:error("could not load fax document: ~p", [Err]) + end. +-spec process_req(kzd_fax:doc(), kz_json:object(), kz_proplist()) -> any(). +process_req(FaxDoc, JObj, _Props) -> Emails = kz_json:get_value([<<"notifications">>,<<"email">>,<<"send_to">>], FaxDoc, []), + AccountId = kz_json:get_value(<<"Account-ID">>, JObj), {'ok', AcctObj} = kz_account:fetch(AccountId), Docs = [FaxDoc, JObj, AcctObj], @@ -56,11 +65,13 @@ handle_req(JObj, _Props) -> <<"outbound_fax_to_email">>, <<"email_subject_template">>], AcctObj), + AccountDb = kapi_notifications:account_db(JObj), + {'ok', TxtBody} = notify_util:render_template(CustomTxtTemplate, ?DEFAULT_TEXT_TMPL, Props), {'ok', HTMLBody} = notify_util:render_template(CustomHtmlTemplate, ?DEFAULT_HTML_TMPL, Props), {'ok', Subject} = notify_util:render_template(CustomSubjectTemplate, ?DEFAULT_SUBJ_TMPL, Props), - try build_and_send_email(TxtBody, HTMLBody, Subject, Emails, props:filter_empty(Props)) of + try build_and_send_email(TxtBody, HTMLBody, Subject, Emails, props:filter_empty(Props), AccountDb) of _ -> lager:debug("built and sent") catch C:R -> @@ -106,7 +117,7 @@ create_template_props(Event, [FaxDoc | _Others]=_Docs, Account) -> ,{<<"call_id">>, kz_json:get_value(<<"Call-ID">>, Event)} | fax_values(kz_json:get_value(<<"Fax-Info">>, Event)) ]} - ,{<<"account_db">>, kz_doc:account_db(Account)} + ,{<<"account_db">>, kapi_notifications:account_db(Event)} ]. fax_values(Event) -> @@ -120,14 +131,14 @@ fax_values(Event) -> %% process the AMQP requests %% @end %%-------------------------------------------------------------------- --spec build_and_send_email(iolist(), iolist(), iolist(), ne_binary() | ne_binaries(), kz_proplist()) -> any(). -build_and_send_email(TxtBody, HTMLBody, Subject, To, Props) when is_list(To) -> - _ = [build_and_send_email(TxtBody, HTMLBody, Subject, T, Props) || T <- To]; -build_and_send_email(TxtBody, HTMLBody, Subject, To, Props) -> +-spec build_and_send_email(iolist(), iolist(), iolist(), ne_binary() | ne_binaries(), kz_proplist(), ne_binary()) -> any(). +build_and_send_email(TxtBody, HTMLBody, Subject, To, Props, AccountDb) when is_list(To) -> + _ = [build_and_send_email(TxtBody, HTMLBody, Subject, T, Props, AccountDb) || T <- To]; +build_and_send_email(TxtBody, HTMLBody, Subject, To, Props, AccountDb) -> Service = props:get_value(<<"service">>, Props), From = props:get_value(<<"send_from">>, Service), - {ContentType, AttachmentFileName, AttachmentBin} = notify_fax_util:get_attachment(?MOD_CONFIG_CAT, Props), + {ContentType, AttachmentFileName, AttachmentBin} = notify_fax_util:get_attachment(AccountDb, ?MOD_CONFIG_CAT, Props), [ContentTypeA,ContentTypeB] = binary:split(ContentType,<<"/">>), {ContentTypeParams, CharsetString} = notify_util:get_charset_params(Service), diff --git a/applications/notify/src/notify_fax_util.erl b/applications/notify/src/notify_fax_util.erl index adc2aed617a..3a66a25ad16 100644 --- a/applications/notify/src/notify_fax_util.erl +++ b/applications/notify/src/notify_fax_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% @end %%% @contributors @@ -7,7 +7,7 @@ %%%------------------------------------------------------------------- -module(notify_fax_util). --export([get_attachment/2]). +-export([get_attachment/2, get_attachment/3]). -include("notify.hrl"). @@ -42,7 +42,18 @@ get_file_name(Props, Ext) -> {ne_binary(), ne_binary(), ne_binary()} | {'error', any()}. get_attachment(Category, Props) -> - {'ok', AttachmentBin, ContentType} = raw_attachment_binary(Props), + UseDb = props:get_value(<<"account_db">>, Props, ?KZ_FAXES_DB), + get_attachment(UseDb, Category, Props). + +-spec get_attachment(ne_binary(), ne_binary(), kz_proplist()) -> + {ne_binary(), ne_binary(), ne_binary()} | + {'error', any()}. +get_attachment(UseDb, Category, Props) -> + Fax = props:get_value(<<"fax">>, Props), + FaxId = props:get_first_defined([<<"fax_jobid">>, <<"fax_id">>], Fax), + + {'ok', AttachmentBin, ContentType} = raw_attachment_binary(UseDb, FaxId), + case kapps_config:get_binary(Category, <<"attachment_format">>, <<"pdf">>) of <<"pdf">> -> convert_to_pdf(AttachmentBin, Props, ContentType); _Else -> convert_to_tiff(AttachmentBin, Props, ContentType) @@ -54,23 +65,16 @@ get_attachment(Category, Props) -> %% %% @end %%-------------------------------------------------------------------- --spec raw_attachment_binary(kz_proplist()) -> - {'ok', ne_binary(), ne_binary()}. -spec raw_attachment_binary(ne_binary(), ne_binary()) -> {'ok', ne_binary(), ne_binary()}. -spec raw_attachment_binary(ne_binary(), ne_binary(), non_neg_integer()) -> {'ok', ne_binary(), ne_binary()}. -raw_attachment_binary(Props) -> - Fax = props:get_value(<<"fax">>, Props), - FaxId = props:get_first_defined([<<"fax_jobid">>, <<"fax_id">>], Fax), - Db = props:get_value(<<"account_db">>, Props, ?KZ_FAXES_DB), - lager:debug("raw attachment ~s / ~s", [Db, FaxId]), - raw_attachment_binary(Db, FaxId). - raw_attachment_binary(Db, FaxId) -> raw_attachment_binary(Db, FaxId, 2). raw_attachment_binary(Db, FaxId, Retries) when Retries > 0 -> + lager:debug("get raw attachment ~s / ~s", [Db, FaxId]), + case kz_datamgr:open_doc(Db, FaxId) of {'error','not_found'} when Db =/= ?KZ_FAXES_DB -> raw_attachment_binary(?KZ_FAXES_DB, FaxId, Retries); diff --git a/applications/notify/src/notify_first_occurrence.erl b/applications/notify/src/notify_first_occurrence.erl index f772e753cbb..89a985cf3a7 100644 --- a/applications/notify/src/notify_first_occurrence.erl +++ b/applications/notify/src/notify_first_occurrence.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Notification for 'first' registration and call %%% @end diff --git a/applications/notify/src/notify_listener.erl b/applications/notify/src/notify_listener.erl index 4b0950fc3c6..952c9a09284 100644 --- a/applications/notify/src/notify_listener.erl +++ b/applications/notify/src/notify_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Handle updating devices and emails about voicemails %%% @end diff --git a/applications/notify/src/notify_low_balance.erl b/applications/notify/src/notify_low_balance.erl index c532cdef98c..521f19da995 100644 --- a/applications/notify/src/notify_low_balance.erl +++ b/applications/notify/src/notify_low_balance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with voicemail attachment to the user. diff --git a/applications/notify/src/notify_maintenance.erl b/applications/notify/src/notify_maintenance.erl index aa50185dff9..e3ee953d67e 100644 --- a/applications/notify/src/notify_maintenance.erl +++ b/applications/notify/src/notify_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/notify/src/notify_new_account.erl b/applications/notify/src/notify_new_account.erl index d60fcd3b402..9c4d57dd9e0 100644 --- a/applications/notify/src/notify_new_account.erl +++ b/applications/notify/src/notify_new_account.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with voicemail attachment to the user. @@ -54,7 +54,7 @@ handle_req(JObj, _Props) -> end, lager:debug("attempting to load all docs in account db ~s", [AccountDb]), - {'ok', AllDocs} = kz_datamgr:all_docs(AccountDb, [{<<"include_docs">>, 'true'}]), + {'ok', AllDocs} = kz_datamgr:all_docs(AccountDb, ['include_docs']), Account = find_account(AllDocs), Admin = find_admin(AllDocs), diff --git a/applications/notify/src/notify_password_recovery.erl b/applications/notify/src/notify_password_recovery.erl index 74a69676054..8ade60409eb 100644 --- a/applications/notify/src/notify_password_recovery.erl +++ b/applications/notify/src/notify_password_recovery.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with voicemail attachment to the user. diff --git a/applications/notify/src/notify_port_cancel.erl b/applications/notify/src/notify_port_cancel.erl index 0ac1a2ea1ca..b424d6bed13 100644 --- a/applications/notify/src/notify_port_cancel.erl +++ b/applications/notify/src/notify_port_cancel.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with port request information to configured email address diff --git a/applications/notify/src/notify_port_request.erl b/applications/notify/src/notify_port_request.erl index beebb523769..f8987d8cf21 100644 --- a/applications/notify/src/notify_port_request.erl +++ b/applications/notify/src/notify_port_request.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with port request information to configured email address diff --git a/applications/notify/src/notify_ported.erl b/applications/notify/src/notify_ported.erl index 1517cf73cc9..43eef2d43ec 100644 --- a/applications/notify/src/notify_ported.erl +++ b/applications/notify/src/notify_ported.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with voicemail attachment to the user. diff --git a/applications/notify/src/notify_sup.erl b/applications/notify/src/notify_sup.erl index 2310b418f8a..f06388132e8 100644 --- a/applications/notify/src/notify_sup.erl +++ b/applications/notify/src/notify_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/notify/src/notify_system_alert.erl b/applications/notify/src/notify_system_alert.erl index 811188a97ae..c73ad5df992 100644 --- a/applications/notify/src/notify_system_alert.erl +++ b/applications/notify/src/notify_system_alert.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with voicemail attachment to the user. diff --git a/applications/notify/src/notify_topup.erl b/applications/notify/src/notify_topup.erl index c42a7645b29..a4db4c25f7c 100644 --- a/applications/notify/src/notify_topup.erl +++ b/applications/notify/src/notify_topup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Renders a custom account email template, or the system default, %%% @end diff --git a/applications/notify/src/notify_transaction.erl b/applications/notify/src/notify_transaction.erl index fabb7e3090c..3764526a8e8 100644 --- a/applications/notify/src/notify_transaction.erl +++ b/applications/notify/src/notify_transaction.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Renders a custom account email template, or the system default, %%% @end diff --git a/applications/notify/src/notify_util.erl b/applications/notify/src/notify_util.erl index c7e0488ab5a..5eb1ceb0e61 100644 --- a/applications/notify/src/notify_util.erl +++ b/applications/notify/src/notify_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @docg %%% @end %%% @contributors diff --git a/applications/notify/src/notify_voicemail_full.erl b/applications/notify/src/notify_voicemail_full.erl index 98e163e4d11..fb0c073ad4b 100644 --- a/applications/notify/src/notify_voicemail_full.erl +++ b/applications/notify/src/notify_voicemail_full.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with voicemail attachment to the user. diff --git a/applications/notify/src/notify_voicemail_to_email.erl b/applications/notify/src/notify_voicemail_to_email.erl index 5d38015b174..46b6c8b08b4 100644 --- a/applications/notify/src/notify_voicemail_to_email.erl +++ b/applications/notify/src/notify_voicemail_to_email.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Renders a custom account email template, or the system default, %%% and sends the email with voicemail attachment to the user. diff --git a/applications/omnipresence/doc/README.md b/applications/omnipresence/doc/README.md index feaf7261fce..0654783eb36 100644 --- a/applications/omnipresence/doc/README.md +++ b/applications/omnipresence/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Omnipresence -Title: Omnipresence -Language: en-US -*/ # Omnipresence *It knows* _the call is from inside the house_ diff --git a/applications/omnipresence/doc/maintenance.md b/applications/omnipresence/doc/maintenance.md index 89d2001be00..d9643311808 100644 --- a/applications/omnipresence/doc/maintenance.md +++ b/applications/omnipresence/doc/maintenance.md @@ -1,9 +1,3 @@ -/* -Section: Omnipresence -Title: Maintenance -Language: en-US -Version: 3.16 -*/ ## Current Subscriptions diff --git a/applications/omnipresence/src/kapi_omnipresence.erl b/applications/omnipresence/src/kapi_omnipresence.erl index d8bfbd42241..b79162100cc 100644 --- a/applications/omnipresence/src/kapi_omnipresence.erl +++ b/applications/omnipresence/src/kapi_omnipresence.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Intra-whapp comm %%% @end diff --git a/applications/omnipresence/src/omnip_dialog_amqp.erl b/applications/omnipresence/src/omnip_dialog_amqp.erl index 5d8c7a6fa8e..d2aaee479bd 100644 --- a/applications/omnipresence/src/omnip_dialog_amqp.erl +++ b/applications/omnipresence/src/omnip_dialog_amqp.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% %%% @end @@ -98,26 +98,20 @@ handle_cast({'gen_listener',{'created_queue',_Queue}}, State) -> handle_cast({'gen_listener',{'is_consuming',_IsConsuming}}, State) -> {'noreply', State}; handle_cast({'omnipresence',{'channel_event', JObj}}, State) -> - kz_util:put_callid(JObj), - EventType = kz_json:get_value(<<"Event-Name">>, JObj), - _ = kz_util:spawn(fun channel_event/2, [EventType, JObj]), + _ = kz_util:spawn(fun channel_event/1, [JObj]), {'noreply', State}; handle_cast({'omnipresence',{'presence_update', JObj}}, State) -> - kz_util:put_callid(JObj), _ = kz_util:spawn(fun presence_event/1, [JObj]), {'noreply', State}; handle_cast({'omnipresence',{'mwi_update', JObj}}, State) -> - kz_util:put_callid(JObj), _ = kz_util:spawn(fun mwi_event/1, [JObj]), {'noreply', State}; handle_cast({'omnipresence',{'presence_reset', JObj}}, State) -> - kz_util:put_callid(JObj), _ = kz_util:spawn(fun presence_reset/1, [JObj]), {'noreply', State}; handle_cast({'omnipresence',{'probe', <<"dialog">> = Package, User, - #omnip_subscription{call_id=CallId}=_Subscription + #omnip_subscription{}=_Subscription }}, State) -> - kz_util:put_callid(CallId), omnip_util:request_probe(Package, User), {'noreply', State}; handle_cast({'omnipresence', _}, State) -> @@ -183,6 +177,12 @@ code_change(_OldVsn, State, _Extra) -> %%%=================================================================== %%% Internal functions %%%=================================================================== +-spec channel_event(kz_json:object()) -> 'ok'. +channel_event(JObj) -> + 'true' = kapi_call:event_v(JObj), + kz_util:put_callid(JObj), + EventType = kz_json:get_value(<<"Event-Name">>, JObj), + channel_event(EventType, JObj). -spec channel_event(ne_binary(), kz_json:object()) -> 'ok'. channel_event(<<"CHANNEL_CREATE">>, JObj) -> handle_new_channel(JObj); @@ -194,29 +194,21 @@ channel_event(_, _JObj) -> 'ok'. -spec handle_new_channel(kz_json:object()) -> 'ok'. handle_new_channel(JObj) -> - 'true' = kapi_call:event_v(JObj), - kz_util:put_callid(JObj), lager:debug("received channel create, checking for dialog subscribers"), handle_update(JObj, ?PRESENCE_RINGING). -spec handle_answered_channel(kz_json:object()) -> 'ok'. handle_answered_channel(JObj) -> - 'true' = kapi_call:event_v(JObj), - kz_util:put_callid(JObj), lager:debug("received channel answer, checking for subscribers"), handle_update(JObj, ?PRESENCE_ANSWERED). -spec handle_destroyed_channel(kz_json:object()) -> 'ok'. handle_destroyed_channel(JObj) -> - 'true' = kapi_call:event_v(JObj), - kz_util:put_callid(JObj), lager:debug("received channel destroy, checking for dialog subscribers"), handle_update(JObj, ?PRESENCE_HANGUP). -spec handle_disconnected_channel(kz_json:object()) -> 'ok'. handle_disconnected_channel(JObj) -> - 'true' = kapi_call:event_v(JObj), - kz_util:put_callid(JObj), lager:debug("channel has been disconnected, checking status of channel on the cluster"), CallId = kz_json:get_value(<<"Call-ID">>, JObj), case kapps_call_command:b_channel_status(CallId) of @@ -374,12 +366,7 @@ maybe_send_update(User, Props) -> -spec send_update(binaries(), kz_proplist()) -> 'ok'. send_update(Stalkers, Props) -> - lager:debug("sending amqp dialog update state ~p for ~s/~s to ~p", - [props:get_value(<<"State">>, Props) - ,props:get_value(<<"From-User">>, Props) - ,props:get_value(<<"To-User">>, Props) - ,Stalkers - ]), + _ = log_send_update(Stalkers, Props), {'ok', Worker} = kz_amqp_worker:checkout_worker(), _ = [kz_amqp_worker:cast(Props ,fun(P) -> kapi_omnipresence:publish_update(S, P) end @@ -389,6 +376,18 @@ send_update(Stalkers, Props) -> ], kz_amqp_worker:checkin_worker(Worker). +-spec log_send_update(binaries(), kz_proplist()) -> 'ok'. +log_send_update([], _) -> 'ok'; +log_send_update([Stalker|Stalkers], Props) -> + lager:debug("sending amqp dialog update state ~s for ~s/~s to ~s with message id ~s", + [props:get_value(<<"State">>, Props) + ,props:get_value(<<"From">>, Props) + ,props:get_value(<<"To">>, Props) + ,Stalker + ,props:get_value(<<"Msg-ID">>, Props) + ]), + log_send_update(Stalkers, Props). + -spec presence_reset(kz_json:object()) -> any(). presence_reset(JObj) -> User = <<(kz_json:get_value(<<"Username">>, JObj))/binary, "@", (kz_json:get_value(<<"Realm">>, JObj))/binary>>, @@ -427,4 +426,4 @@ mwi_event(JObj) -> ,{<<"Flush-Level">>, 1} ,{<<"Call-Direction">>, <<"inbound">>} ]), - handle_update(kz_json:from_list(Props), State, 0). + handle_update(kz_json:from_list(Props), State, 60 * ?SECONDS_IN_DAY). diff --git a/applications/omnipresence/src/omnip_message_summary_amqp.erl b/applications/omnipresence/src/omnip_message_summary_amqp.erl index 84d957d5a44..90ca2f2c0d8 100644 --- a/applications/omnipresence/src/omnip_message_summary_amqp.erl +++ b/applications/omnipresence/src/omnip_message_summary_amqp.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end @@ -192,6 +192,7 @@ handle_update(JObj, To) -> MessagesUrgent = kz_json:get_integer_value(<<"Messages-Urgent">>, JObj, 0), MessagesUrgentSaved = kz_json:get_integer_value(<<"Messages-Urgent-Saved">>, JObj, 0), MessagesWaiting = case MessagesNew of 0 -> <<"no">>; _ -> <<"yes">> end, + Expires = 60 * ?SECONDS_IN_DAY, Update = props:filter_undefined( [{<<"To">>, <<"sip:", To/binary>>} ,{<<"To-User">>, ToUsername} @@ -200,6 +201,7 @@ handle_update(JObj, To) -> ,{<<"From-User">>, ToUsername} ,{<<"From-Realm">>, ToRealm} ,{<<"Call-ID">>, ?FAKE_CALLID(To)} + ,{<<"Expires">>, Expires} ,{<<"Message-Account">>, <<"sip:", To/binary>>} ,{<<"Messages-Waiting">>, MessagesWaiting} ,{<<"Messages-New">>, MessagesNew} diff --git a/applications/omnipresence/src/omnip_presence_amqp.erl b/applications/omnipresence/src/omnip_presence_amqp.erl index 1f4ce0519e3..8b213345ea5 100644 --- a/applications/omnipresence/src/omnip_presence_amqp.erl +++ b/applications/omnipresence/src/omnip_presence_amqp.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end @@ -24,6 +24,10 @@ -define(SERVER, ?MODULE). +-define(DEFAULT_VM_NUMBER, <<"*98">>). +-define(VM_NUMBER_KEY, <<"presence_subscribed_mwi_prefix">>). +-define(VM_NUMBER(A), kapps_account_config:get_global(A, ?CONFIG_CAT, ?VM_NUMBER_KEY, ?DEFAULT_VM_NUMBER)). + -record(state, {}). -type state() :: #state{}. @@ -111,6 +115,10 @@ handle_cast({'omnipresence',{'channel_event', JObj}}, State) -> EventType = kz_json:get_value(<<"Event-Name">>, JObj), _ = kz_util:spawn(fun channel_event/2, [EventType, JObj]), {'noreply', State}; +handle_cast({'omnipresence',{'mwi_update', JObj}}, State) -> + kz_util:put_callid(JObj), + _ = kz_util:spawn(fun mwi_event/1, [JObj]), + {'noreply', State}; handle_cast({'omnipresence', _}, State) -> {'noreply', State}; handle_cast(_Msg, State) -> @@ -222,11 +230,11 @@ presence_event(JObj) -> -spec maybe_handle_presence_state(kz_json:object(), api_binary()) -> 'ok'. maybe_handle_presence_state(JObj, <<"online">>=State) -> - handle_update(JObj, State, 0); + handle_update(JObj, State, ?OTHER_TIME); maybe_handle_presence_state(JObj, <<"offline">>=State) -> - handle_update(JObj, State, 0); + handle_update(JObj, State, ?OTHER_TIME); maybe_handle_presence_state(JObj, State) -> - handle_update(kz_json:delete_keys([<<"From">>, <<"To">>], JObj), State, 0). + handle_update(kz_json:delete_keys([<<"From">>, <<"To">>], JObj), State, ?OTHER_TIME). -spec handle_update(kz_json:object(), ne_binary()) -> 'ok'. handle_update(JObj, ?PRESENCE_HANGUP) -> @@ -331,3 +339,20 @@ presence_reset(JObj) -> set_presence_state(PresenceId, State) -> Headers = [{<<"Presence-ID">>, PresenceId }], handle_update(kz_json:from_list(Headers), State, 0). + +-spec mwi_event(kz_json:object()) -> 'ok'. +mwi_event(JObj) -> + To = kz_json:get_value(<<"To">>, JObj), + [_, ToRealm] = binary:split(To, <<"@">>), + {ok, AccountDb} = kapps_util:get_account_by_realm(ToRealm), + AccountId = kz_util:format_account_id(AccountDb), + State = case kz_json:get_integer_value(<<"Messages-New">>, JObj, 0) of + 0 -> ?PRESENCE_HANGUP; + _ -> ?PRESENCE_ANSWERED + end, + Props = props:filter_undefined( + [{<<"Presence-ID">>, <<(?VM_NUMBER(AccountId))/binary, To/binary>>} + ,{<<"Flush-Level">>, 1} + ,{<<"Call-Direction">>, <<"inbound">>} + ]), + handle_update(kz_json:from_list(Props), State, 60 * ?SECONDS_IN_DAY). diff --git a/applications/omnipresence/src/omnip_subscriptions.erl b/applications/omnipresence/src/omnip_subscriptions.erl index eb46901abf6..b6f83d1fbcd 100644 --- a/applications/omnipresence/src/omnip_subscriptions.erl +++ b/applications/omnipresence/src/omnip_subscriptions.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/omnipresence/src/omnip_sup.erl b/applications/omnipresence/src/omnip_sup.erl index e2ffeb9ff02..205057313c7 100644 --- a/applications/omnipresence/src/omnip_sup.erl +++ b/applications/omnipresence/src/omnip_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/omnipresence/src/omnip_util.erl b/applications/omnipresence/src/omnip_util.erl index 9d216b83a53..2eeeb473201 100644 --- a/applications/omnipresence/src/omnip_util.erl +++ b/applications/omnipresence/src/omnip_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/omnipresence/src/omnipresence.hrl b/applications/omnipresence/src/omnipresence.hrl index b142fa6bcd4..772a9328ee2 100644 --- a/applications/omnipresence/src/omnipresence.hrl +++ b/applications/omnipresence/src/omnipresence.hrl @@ -24,7 +24,7 @@ -define(RINGING_TIME, 24 * ?SECONDS_IN_HOUR). -define(ANSWERED_TIME, 24 * ?SECONDS_IN_HOUR). -define(HANGUP_TIME, 10). --define(OTHER_TIME, 36000). +-define(OTHER_TIME, 24 * ?SECONDS_IN_HOUR). -define(FAKE_CALLID(C), kz_util:to_hex_binary(crypto:hash(md5, C))). diff --git a/applications/omnipresence/src/omnipresence_app.erl b/applications/omnipresence/src/omnipresence_app.erl index eefc7f5a8fe..2a5ebfb907e 100644 --- a/applications/omnipresence/src/omnipresence_app.erl +++ b/applications/omnipresence/src/omnipresence_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/omnipresence/src/omnipresence_listener.erl b/applications/omnipresence/src/omnipresence_listener.erl index 14a6ac65a68..8d8b706e343 100644 --- a/applications/omnipresence/src/omnipresence_listener.erl +++ b/applications/omnipresence/src/omnipresence_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/omnipresence/src/omnipresence_maintenance.erl b/applications/omnipresence/src/omnipresence_maintenance.erl index 697ed3d1087..be1be4065aa 100644 --- a/applications/omnipresence/src/omnipresence_maintenance.erl +++ b/applications/omnipresence/src/omnipresence_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Maintenance functions for all %%% @end diff --git a/applications/omnipresence/src/omnipresence_shared_listener.erl b/applications/omnipresence/src/omnipresence_shared_listener.erl index 379549881cb..90b8f8cd1ae 100644 --- a/applications/omnipresence/src/omnipresence_shared_listener.erl +++ b/applications/omnipresence/src/omnipresence_shared_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/omnipresence/src/omnipresence_sup.erl b/applications/omnipresence/src/omnipresence_sup.erl index 649102df89b..f809958077a 100644 --- a/applications/omnipresence/src/omnipresence_sup.erl +++ b/applications/omnipresence/src/omnipresence_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/pivot/doc/README.md b/applications/pivot/doc/README.md index 3625f60eb03..e3a34335a91 100644 --- a/applications/pivot/doc/README.md +++ b/applications/pivot/doc/README.md @@ -1,9 +1,3 @@ -/* -Section: Pivot -Title: Pivot -Language: en-US -Version: 3.18 -*/ # Overview diff --git a/applications/pivot/doc/issues.md b/applications/pivot/doc/issues.md index 73b9f53a6c6..178519fb6ce 100644 --- a/applications/pivot/doc/issues.md +++ b/applications/pivot/doc/issues.md @@ -1,8 +1,3 @@ -/* -Section: Pivot -Title: Issues -Language: en-US -*/ * Default data submitted on request: CallerName, Direction, ApiVerson, CallStatus, To, From, AccountSid, CallSid * Play diff --git a/applications/pivot/doc/kazoo/README.md b/applications/pivot/doc/kazoo/README.md index 7df5cdb4bed..dc2f0b614c2 100644 --- a/applications/pivot/doc/kazoo/README.md +++ b/applications/pivot/doc/kazoo/README.md @@ -1,8 +1,3 @@ -/* -Section: Pivot -Title: Build your callflows on-demand -Language: en-US -*/ # Overview diff --git a/applications/pivot/doc/kazoo/bridging.md b/applications/pivot/doc/kazoo/bridging.md index 6eb42e5070b..d32a6fd0862 100644 --- a/applications/pivot/doc/kazoo/bridging.md +++ b/applications/pivot/doc/kazoo/bridging.md @@ -1,9 +1,3 @@ -/* -Section: Pivot -Title: Bridging -Language: en-US -Version: 3.18 -*/ # Overview diff --git a/applications/pivot/doc/kazoo/collect.md b/applications/pivot/doc/kazoo/collect.md index 2e04ee64b07..4a316b8ebc0 100644 --- a/applications/pivot/doc/kazoo/collect.md +++ b/applications/pivot/doc/kazoo/collect.md @@ -1,8 +1,3 @@ -/* -Section: Pivot -Title: DTMF Collection -Language: en-US -*/ # Overview diff --git a/applications/pivot/doc/kazoo/conferencing.md b/applications/pivot/doc/kazoo/conferencing.md index dff64f8541f..b9f4640d2d8 100644 --- a/applications/pivot/doc/kazoo/conferencing.md +++ b/applications/pivot/doc/kazoo/conferencing.md @@ -1,9 +1,3 @@ -/* -Section: Pivot -Title: Conferencing -Language: en-US -Version: 3.18 -*/ # Overview diff --git a/applications/pivot/doc/kazoo/dtmf.md b/applications/pivot/doc/kazoo/dtmf.md index 677e6226374..27cbd7ad8c7 100644 --- a/applications/pivot/doc/kazoo/dtmf.md +++ b/applications/pivot/doc/kazoo/dtmf.md @@ -1,9 +1,3 @@ -/* -Section: Pivot -Title: DTMF -Language: en-US -Version: 3.18 -*/ # Overview diff --git a/applications/pivot/doc/kazoo/hangups.md b/applications/pivot/doc/kazoo/hangups.md index 6372789207a..63cc1ccb850 100644 --- a/applications/pivot/doc/kazoo/hangups.md +++ b/applications/pivot/doc/kazoo/hangups.md @@ -1,9 +1,3 @@ -/* -Section: Pivot -Title: Hangups -Language: en-US -Version: 3.18 -*/ # Overview diff --git a/applications/pivot/doc/kazoo/play.md b/applications/pivot/doc/kazoo/play.md index 0031b1d6264..3ed0b730924 100644 --- a/applications/pivot/doc/kazoo/play.md +++ b/applications/pivot/doc/kazoo/play.md @@ -1,8 +1,3 @@ -/* -Section: Pivot -Title: Playing Files -Language: en-US -*/ # Overview diff --git a/applications/pivot/doc/kazoo/presence.md b/applications/pivot/doc/kazoo/presence.md index 608a025e026..9c9f037ca01 100644 --- a/applications/pivot/doc/kazoo/presence.md +++ b/applications/pivot/doc/kazoo/presence.md @@ -1,9 +1,3 @@ -/* -Section: Pivot -Title: Presence -Language: en-US -Version: 3.18 -*/ # Overview diff --git a/applications/pivot/doc/kazoo/recording.md b/applications/pivot/doc/kazoo/recording.md index a281aa568bc..4bd184e4bd5 100644 --- a/applications/pivot/doc/kazoo/recording.md +++ b/applications/pivot/doc/kazoo/recording.md @@ -1,9 +1,3 @@ -/* -Section: Pivot -Title: Recording -Language: en-US -Version: 3.18 -*/ # Overview diff --git a/applications/pivot/doc/kazoo/say.md b/applications/pivot/doc/kazoo/say.md index 7e7f27c5d44..c0462e32ea1 100644 --- a/applications/pivot/doc/kazoo/say.md +++ b/applications/pivot/doc/kazoo/say.md @@ -1,8 +1,3 @@ -/* -Section: Pivot -Title: Saying Text -Language: en-US -*/ # Overview diff --git a/applications/pivot/doc/twiml/README.md b/applications/pivot/doc/twiml/README.md index 177a5c3bccb..5fa180545ea 100644 --- a/applications/pivot/doc/twiml/README.md +++ b/applications/pivot/doc/twiml/README.md @@ -1,9 +1,3 @@ -/* -Section: Pivot -Title: Pivot -Language: en-US -Version: 3.18 -*/ # Overview diff --git a/applications/pivot/src/kapi_pivot.erl b/applications/pivot/src/kapi_pivot.erl index 49d069ad17b..2a11b91374b 100644 --- a/applications/pivot/src/kapi_pivot.erl +++ b/applications/pivot/src/kapi_pivot.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Pivot API %%% @end diff --git a/applications/pivot/src/pivot_app.erl b/applications/pivot/src/pivot_app.erl index 8e38882ecd3..cd70303dd2e 100644 --- a/applications/pivot/src/pivot_app.erl +++ b/applications/pivot/src/pivot_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/pivot/src/pivot_call.erl b/applications/pivot/src/pivot_call.erl index 54be68c41d5..498aa2be4fb 100644 --- a/applications/pivot/src/pivot_call.erl +++ b/applications/pivot/src/pivot_call.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Handle processing of the pivot call %%% @end diff --git a/applications/pivot/src/pivot_calls_sup.erl b/applications/pivot/src/pivot_calls_sup.erl index 94896a20328..0a68a688407 100644 --- a/applications/pivot/src/pivot_calls_sup.erl +++ b/applications/pivot/src/pivot_calls_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/pivot/src/pivot_handlers.erl b/applications/pivot/src/pivot_handlers.erl index 016b38fa597..009277be9d4 100644 --- a/applications/pivot/src/pivot_handlers.erl +++ b/applications/pivot/src/pivot_handlers.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Handlers for various AMQP payloads %%% @end diff --git a/applications/pivot/src/pivot_listener.erl b/applications/pivot/src/pivot_listener.erl index 1225aef55be..13a2282bcd9 100644 --- a/applications/pivot/src/pivot_listener.erl +++ b/applications/pivot/src/pivot_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/pivot/src/pivot_sup.erl b/applications/pivot/src/pivot_sup.erl index f7604485925..5c1b503c3fd 100644 --- a/applications/pivot/src/pivot_sup.erl +++ b/applications/pivot/src/pivot_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/pusher/doc/pusher.md b/applications/pusher/doc/pusher.md index 9abcf39f6bd..ae2930e35cb 100644 --- a/applications/pusher/doc/pusher.md +++ b/applications/pusher/doc/pusher.md @@ -1,8 +1,3 @@ -/* -Section: Pusher -Title: Pusher -Language: en-US -*/ # Pusher pusher app allows kazoo to send a push message to a device when the device is the target of a bridge call and is not registered, so that the device can "wake up", register and receive the call. diff --git a/applications/pusher/src/kapi_pusher.erl b/applications/pusher/src/kapi_pusher.erl index 78c778d32d8..9da4edf569a 100644 --- a/applications/pusher/src/kapi_pusher.erl +++ b/applications/pusher/src/kapi_pusher.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/pusher/src/pusher_app.erl b/applications/pusher/src/pusher_app.erl index 06a3414a9a3..d6d4a6ae6ca 100644 --- a/applications/pusher/src/pusher_app.erl +++ b/applications/pusher/src/pusher_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/pusher/src/pusher_listener.erl b/applications/pusher/src/pusher_listener.erl index 185c09c02eb..72809e81539 100644 --- a/applications/pusher/src/pusher_listener.erl +++ b/applications/pusher/src/pusher_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/pusher/src/pusher_maintenance.erl b/applications/pusher/src/pusher_maintenance.erl index 09ce9f982f2..f660209e3a5 100644 --- a/applications/pusher/src/pusher_maintenance.erl +++ b/applications/pusher/src/pusher_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Maintenance functions for all %%% @end diff --git a/applications/pusher/src/pusher_module_sup.erl b/applications/pusher/src/pusher_module_sup.erl index 3b7df345a4d..b35e4e1dee2 100644 --- a/applications/pusher/src/pusher_module_sup.erl +++ b/applications/pusher/src/pusher_module_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/pusher/src/pusher_sup.erl b/applications/pusher/src/pusher_sup.erl index 860742feac1..292f51e86a6 100644 --- a/applications/pusher/src/pusher_sup.erl +++ b/applications/pusher/src/pusher_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/pusher/src/pusher_util.erl b/applications/pusher/src/pusher_util.erl index 6165b07d000..0b9562afa56 100644 --- a/applications/pusher/src/pusher_util.erl +++ b/applications/pusher/src/pusher_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/registrar/doc/README.md b/applications/registrar/doc/README.md index 6d184b724e0..6b3b8fe1a26 100644 --- a/applications/registrar/doc/README.md +++ b/applications/registrar/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Registrar -Title: Registrar -Language: en-US -*/ # Registrar *The star registration application* Papers, please. diff --git a/applications/registrar/src/reg_authn_req.erl b/applications/registrar/src/reg_authn_req.erl index 48a6e72a302..6ad2e8bf5c4 100644 --- a/applications/registrar/src/reg_authn_req.erl +++ b/applications/registrar/src/reg_authn_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Handle authn_req messages %%% @end diff --git a/applications/registrar/src/reg_route_req.erl b/applications/registrar/src/reg_route_req.erl index e5ff722eef9..750dd34f892 100644 --- a/applications/registrar/src/reg_route_req.erl +++ b/applications/registrar/src/reg_route_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Look up IP for authorization/replaying of route_req %%% @end diff --git a/applications/registrar/src/registrar_app.erl b/applications/registrar/src/registrar_app.erl index faf295d9938..e0b1298866c 100644 --- a/applications/registrar/src/registrar_app.erl +++ b/applications/registrar/src/registrar_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/registrar/src/registrar_init.erl b/applications/registrar/src/registrar_init.erl index 268120faa25..905e5a2f93e 100644 --- a/applications/registrar/src/registrar_init.erl +++ b/applications/registrar/src/registrar_init.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Init to be done %%% @end diff --git a/applications/registrar/src/registrar_maintenance.erl b/applications/registrar/src/registrar_maintenance.erl index 3f98a557543..a57d2eacd88 100644 --- a/applications/registrar/src/registrar_maintenance.erl +++ b/applications/registrar/src/registrar_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/registrar/src/registrar_shared_listener.erl b/applications/registrar/src/registrar_shared_listener.erl index 6df9c5b343d..99d61160fd7 100644 --- a/applications/registrar/src/registrar_shared_listener.erl +++ b/applications/registrar/src/registrar_shared_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Listener for authn_req, reg_success, and reg_query AMQP requests %%% @end diff --git a/applications/registrar/src/registrar_shared_listener_sup.erl b/applications/registrar/src/registrar_shared_listener_sup.erl index e78a9142cb3..42051ed0701 100644 --- a/applications/registrar/src/registrar_shared_listener_sup.erl +++ b/applications/registrar/src/registrar_shared_listener_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/registrar/src/registrar_sup.erl b/applications/registrar/src/registrar_sup.erl index 22d2879ca5f..b63e86becab 100644 --- a/applications/registrar/src/registrar_sup.erl +++ b/applications/registrar/src/registrar_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/reorder/doc/README.md b/applications/reorder/doc/README.md index 08582449296..6e6c90cd772 100644 --- a/applications/reorder/doc/README.md +++ b/applications/reorder/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Reorder -Title: Reorder -Language: en-US -*/ # Reorder *Misconfigured Number Replies* 404 diff --git a/applications/reorder/src/reorder_app.erl b/applications/reorder/src/reorder_app.erl index fa8c383d4e5..951ae026470 100644 --- a/applications/reorder/src/reorder_app.erl +++ b/applications/reorder/src/reorder_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/reorder/src/reorder_listener.erl b/applications/reorder/src/reorder_listener.erl index eed0b56681a..cfb539bcb76 100644 --- a/applications/reorder/src/reorder_listener.erl +++ b/applications/reorder/src/reorder_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/reorder/src/reorder_route_req.erl b/applications/reorder/src/reorder_route_req.erl index 7a8b2580364..355342bc178 100644 --- a/applications/reorder/src/reorder_route_req.erl +++ b/applications/reorder/src/reorder_route_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% handler for route requests, responds if reorder match %%% @end diff --git a/applications/reorder/src/reorder_sup.erl b/applications/reorder/src/reorder_sup.erl index e360c76b964..d6681a6f6be 100644 --- a/applications/reorder/src/reorder_sup.erl +++ b/applications/reorder/src/reorder_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/skel/doc/README.md b/applications/skel/doc/README.md index e1f1911520f..8198d7a21bd 100644 --- a/applications/skel/doc/README.md +++ b/applications/skel/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Skel -Title: Skel -Language: en-US -*/ # Overview diff --git a/applications/skel/src/skel_app.erl b/applications/skel/src/skel_app.erl index 35f29194337..7387ee23b10 100644 --- a/applications/skel/src/skel_app.erl +++ b/applications/skel/src/skel_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/skel/src/skel_handlers.erl b/applications/skel/src/skel_handlers.erl index 21f8eb44acc..a82f4e1c966 100644 --- a/applications/skel/src/skel_handlers.erl +++ b/applications/skel/src/skel_handlers.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Handlers for various AMQP payloads %%% @end diff --git a/applications/skel/src/skel_listener.erl b/applications/skel/src/skel_listener.erl index 21a148333ff..f9509c61cec 100644 --- a/applications/skel/src/skel_listener.erl +++ b/applications/skel/src/skel_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/skel/src/skel_sup.erl b/applications/skel/src/skel_sup.erl index dab18a87b12..a916c217c19 100644 --- a/applications/skel/src/skel_sup.erl +++ b/applications/skel/src/skel_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/skel/test/skel_test.erl b/applications/skel/test/skel_test.erl index 9d59e723d73..60cd5cdcb8f 100644 --- a/applications/skel/test/skel_test.erl +++ b/applications/skel/test/skel_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/spyvsspy/doc/README.md b/applications/spyvsspy/doc/README.md index ad22e0cbcff..c5b1d5c15a3 100644 --- a/applications/spyvsspy/doc/README.md +++ b/applications/spyvsspy/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Spy vs Spy -Title: Spy vs Spy -Language: en-US -*/ # Spy vs Spy *Call Eavesdropping* **BOOM** diff --git a/applications/spyvsspy/src/spyvsspy_app.erl b/applications/spyvsspy/src/spyvsspy_app.erl index 7c1a50c4bab..ec7e23bc780 100644 --- a/applications/spyvsspy/src/spyvsspy_app.erl +++ b/applications/spyvsspy/src/spyvsspy_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/spyvsspy/src/spyvsspy_handlers.erl b/applications/spyvsspy/src/spyvsspy_handlers.erl index 9d9c7893c0d..99ce18bf736 100644 --- a/applications/spyvsspy/src/spyvsspy_handlers.erl +++ b/applications/spyvsspy/src/spyvsspy_handlers.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Handlers for various AMQP payloads %%% @end diff --git a/applications/spyvsspy/src/spyvsspy_listener.erl b/applications/spyvsspy/src/spyvsspy_listener.erl index d8969f036d0..1a628da09be 100644 --- a/applications/spyvsspy/src/spyvsspy_listener.erl +++ b/applications/spyvsspy/src/spyvsspy_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/spyvsspy/src/spyvsspy_sup.erl b/applications/spyvsspy/src/spyvsspy_sup.erl index 395151adc90..286fade13a7 100644 --- a/applications/spyvsspy/src/spyvsspy_sup.erl +++ b/applications/spyvsspy/src/spyvsspy_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stats/doc/README.md b/applications/stats/doc/README.md index 54b547da4e1..fc2e75a5723 100644 --- a/applications/stats/doc/README.md +++ b/applications/stats/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Stats -Title: Stats -Language: en-US -*/ Events counts are collected by kazoo_stats.erl running on every kazoo cluster node and are regularly sent via the targeted/statistics amqp queue to diff --git a/applications/stats/src/kazoo_snmp.erl b/applications/stats/src/kazoo_snmp.erl index 79b5a7f0cd3..7b6ddb71a98 100644 --- a/applications/stats/src/kazoo_snmp.erl +++ b/applications/stats/src/kazoo_snmp.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stats/src/stats_app.erl b/applications/stats/src/stats_app.erl index 45169f2b2a3..672a1a27b3c 100644 --- a/applications/stats/src/stats_app.erl +++ b/applications/stats/src/stats_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stats/src/stats_handler.erl b/applications/stats/src/stats_handler.erl index 26d8789adf8..82891bbeeb3 100644 --- a/applications/stats/src/stats_handler.erl +++ b/applications/stats/src/stats_handler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stats/src/stats_listener.erl b/applications/stats/src/stats_listener.erl index 1501ca95287..3d8b71bc1dd 100644 --- a/applications/stats/src/stats_listener.erl +++ b/applications/stats/src/stats_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Master process to gather information send by all kazoo nodes. %%% It listens to targeted/statistics AMPQ messages, and is accessed by diff --git a/applications/stats/src/stats_sup.erl b/applications/stats/src/stats_sup.erl index 5850034c81f..3d24309100a 100644 --- a/applications/stats/src/stats_sup.erl +++ b/applications/stats/src/stats_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stepswitch/doc/README.md b/applications/stepswitch/doc/README.md index cf902ae52ff..7b10d84c77e 100644 --- a/applications/stepswitch/doc/README.md +++ b/applications/stepswitch/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Stepswitch -Title: Stepswitch -Language: en-US -*/ # Stepswitch *VoIP line finder* click, click, click, clack diff --git a/applications/stepswitch/doc/rules.md b/applications/stepswitch/doc/rules.md index 98323c9f0eb..ad4ab5d7dc3 100644 --- a/applications/stepswitch/doc/rules.md +++ b/applications/stepswitch/doc/rules.md @@ -1,9 +1,3 @@ -/* -Section: Stepswitch -Title: Rules -Language: en-US -Version: 3.18 -*/ # Rules fields diff --git a/applications/stepswitch/src/kz_srs_util.erl b/applications/stepswitch/src/kz_srs_util.erl index 7efbbe5813b..befd671bfc4 100644 --- a/applications/stepswitch/src/kz_srs_util.erl +++ b/applications/stepswitch/src/kz_srs_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stepswitch/src/resource_selectors/kz_srs_filter_list.erl b/applications/stepswitch/src/resource_selectors/kz_srs_filter_list.erl index 82af88f2336..64c3bbcb6b8 100644 --- a/applications/stepswitch/src/resource_selectors/kz_srs_filter_list.erl +++ b/applications/stepswitch/src/resource_selectors/kz_srs_filter_list.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end @@ -60,7 +60,8 @@ handle_req(Resources, Number, OffnetJObj, DB, Params) -> filter_list(Set, Set, <<"axact">>) -> 'true'; filter_list(SetA, SetB, <<"subset">>) -> sets:is_subset(SetA, SetB); filter_list(SetA, SetB, <<"ne_subset">>) -> - sets:size(SetA) > 0 andalso sets:is_subset(SetA, SetB); + sets:size(SetA) > 0 + andalso sets:is_subset(SetA, SetB); filter_list(SetA, SetB, <<"ne_subset_or_exact">>) -> case sets:size(SetA) > 0 of 'true' -> sets:is_subset(SetA, SetB); diff --git a/applications/stepswitch/src/resource_selectors/kz_srs_filter_prefix.erl b/applications/stepswitch/src/resource_selectors/kz_srs_filter_prefix.erl index a79db21fa62..43b17af19f0 100644 --- a/applications/stepswitch/src/resource_selectors/kz_srs_filter_prefix.erl +++ b/applications/stepswitch/src/resource_selectors/kz_srs_filter_prefix.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stepswitch/src/resource_selectors/kz_srs_filter_regex.erl b/applications/stepswitch/src/resource_selectors/kz_srs_filter_regex.erl index 9fcbf4f64d2..9f1f35388c9 100644 --- a/applications/stepswitch/src/resource_selectors/kz_srs_filter_regex.erl +++ b/applications/stepswitch/src/resource_selectors/kz_srs_filter_regex.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stepswitch/src/resource_selectors/kz_srs_get_resources.erl b/applications/stepswitch/src/resource_selectors/kz_srs_get_resources.erl index 065de9a99f7..80f4c949e25 100644 --- a/applications/stepswitch/src/resource_selectors/kz_srs_get_resources.erl +++ b/applications/stepswitch/src/resource_selectors/kz_srs_get_resources.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stepswitch/src/resource_selectors/kz_srs_null.erl b/applications/stepswitch/src/resource_selectors/kz_srs_null.erl index 91113d09ef2..2ea827030fd 100644 --- a/applications/stepswitch/src/resource_selectors/kz_srs_null.erl +++ b/applications/stepswitch/src/resource_selectors/kz_srs_null.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stepswitch/src/resource_selectors/kz_srs_order.erl b/applications/stepswitch/src/resource_selectors/kz_srs_order.erl index 582fb933238..a7c94c1d2cc 100644 --- a/applications/stepswitch/src/resource_selectors/kz_srs_order.erl +++ b/applications/stepswitch/src/resource_selectors/kz_srs_order.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stepswitch/src/stepswitch_app.erl b/applications/stepswitch/src/stepswitch_app.erl index 60b4196b224..82ddaf10f23 100644 --- a/applications/stepswitch/src/stepswitch_app.erl +++ b/applications/stepswitch/src/stepswitch_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% stepswitch routing WhApp entry module %%% @end diff --git a/applications/stepswitch/src/stepswitch_authn_req.erl b/applications/stepswitch/src/stepswitch_authn_req.erl index 57195af9c9c..139b1f2511f 100644 --- a/applications/stepswitch/src/stepswitch_authn_req.erl +++ b/applications/stepswitch/src/stepswitch_authn_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Handle authn_req messages %%% @end diff --git a/applications/stepswitch/src/stepswitch_bridge.erl b/applications/stepswitch/src/stepswitch_bridge.erl index 9192669958e..b78ac66c6bc 100644 --- a/applications/stepswitch/src/stepswitch_bridge.erl +++ b/applications/stepswitch/src/stepswitch_bridge.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end @@ -327,11 +327,32 @@ maybe_deny_emergency_bridge(State, 'undefined', Name) -> ) end; maybe_deny_emergency_bridge(#state{control_queue=ControlQ}=State, Number, Name) -> + State0 = update_endpoint_emergency_cid(State, Number, Name), kapi_dialplan:publish_command(ControlQ - ,build_bridge(State, Number, Name) + ,build_bridge(State0, Number, Name) ), lager:debug("sent bridge command to ~s", [ControlQ]). +-spec update_endpoint_emergency_cid(state() | kz_json:object(), ne_binary(), api_binary()) -> state(). +update_endpoint_emergency_cid(#state{endpoints=Endpoints}=State, Number, Name) -> + State#state{endpoints=[update_endpoint_emergency_cid(Endpoint, Number, Name) + || Endpoint <- Endpoints + ]}; +update_endpoint_emergency_cid(Endpoint, Number, Name) -> + case {kz_json:get_value(<<"Outbound-Caller-ID-Number">>, Endpoint, Number) + ,kz_json:get_value(<<"Outbound-Caller-ID-Name">>, Endpoint, Name) + } + of + {Number, Name} -> Endpoint; + {Number, _} -> kz_json:set_value(<<"Outbound-Caller-ID-Name">>, Name, Endpoint); + {_, Name} -> kz_json:set_value(<<"Outbound-Caller-ID-Number">>, Number, Endpoint); + {_, _} -> + Props = [{<<"Outbound-Caller-ID-Name">>, Name} + ,{<<"Outbound-Caller-ID-Number">>, Number} + ], + kz_json:set_values(Props, Endpoint) + end. + -spec build_bridge(state(), api_binary(), api_binary()) -> kz_proplist(). build_bridge(#state{endpoints=Endpoints ,resource_req=OffnetReq @@ -346,6 +367,7 @@ build_bridge(#state{endpoints=Endpoints kz_json:set_values(props:filter_undefined([{<<"Ignore-Display-Updates">>, <<"true">>} ,{<<"Account-ID">>, AccountId} ,{<<"From-URI">>, bridge_from_uri(Number, OffnetReq)} + ,{<<"Realm">>, stepswitch_util:default_realm(OffnetReq)} ,{<<"Reseller-ID">>, kz_services:find_reseller_id(AccountId)} ]) ,kapi_offnet_resource:custom_channel_vars(OffnetReq, kz_json:new()) diff --git a/applications/stepswitch/src/stepswitch_cnam.erl b/applications/stepswitch/src/stepswitch_cnam.erl index e9201da329f..b716733781c 100644 --- a/applications/stepswitch/src/stepswitch_cnam.erl +++ b/applications/stepswitch/src/stepswitch_cnam.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Lookup cnam %%% @end diff --git a/applications/stepswitch/src/stepswitch_cnam_pool_sup.erl b/applications/stepswitch/src/stepswitch_cnam_pool_sup.erl index 28a5338fe68..8dbad3dbb0f 100644 --- a/applications/stepswitch/src/stepswitch_cnam_pool_sup.erl +++ b/applications/stepswitch/src/stepswitch_cnam_pool_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stepswitch/src/stepswitch_inbound.erl b/applications/stepswitch/src/stepswitch_inbound.erl index 39a74847536..597fa8e6080 100644 --- a/applications/stepswitch/src/stepswitch_inbound.erl +++ b/applications/stepswitch/src/stepswitch_inbound.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Handle route requests from carrier resources %%% @end diff --git a/applications/stepswitch/src/stepswitch_listener.erl b/applications/stepswitch/src/stepswitch_listener.erl index ee2b65e88fa..95e6b799694 100644 --- a/applications/stepswitch/src/stepswitch_listener.erl +++ b/applications/stepswitch/src/stepswitch_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% @end %%%------------------------------------------------------------------- diff --git a/applications/stepswitch/src/stepswitch_local_extension.erl b/applications/stepswitch/src/stepswitch_local_extension.erl index 217a504b054..a9a6afe480e 100644 --- a/applications/stepswitch/src/stepswitch_local_extension.erl +++ b/applications/stepswitch/src/stepswitch_local_extension.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end @@ -293,6 +293,7 @@ build_local_extension(#state{number_props=Props ,{<>, kz_json:get_value(<<"Retain-CID">>, CCVsOrig)} ,{<<"Resource-ID">>, AccountId} ,{<<"Loopback-Request-URI">>, <>} + ,{<>, OriginalAccountId} ]), Endpoint = kz_json:from_list( @@ -327,6 +328,7 @@ build_local_extension(#state{number_props=Props ,{<<"Caller-ID-Number">>, CIDNum} ,{<<"Simplify-Loopback">>, <<"false">>} ,{<<"Loopback-Bowout">>, <<"false">>} + ,{<<"Media">>, <<"process">>} | kz_api:default_headers(Q, <<"call">>, <<"command">>, ?APP_NAME, ?APP_VERSION) ]). diff --git a/applications/stepswitch/src/stepswitch_local_sms.erl b/applications/stepswitch/src/stepswitch_local_sms.erl index a90dacd000d..921c1b7ce77 100644 --- a/applications/stepswitch/src/stepswitch_local_sms.erl +++ b/applications/stepswitch/src/stepswitch_local_sms.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stepswitch/src/stepswitch_maintenance.erl b/applications/stepswitch/src/stepswitch_maintenance.erl index 21ac6e9569e..ba91aee2c21 100644 --- a/applications/stepswitch/src/stepswitch_maintenance.erl +++ b/applications/stepswitch/src/stepswitch_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Preforms maintenance operations against the stepswitch dbs %%% @end diff --git a/applications/stepswitch/src/stepswitch_originate.erl b/applications/stepswitch/src/stepswitch_originate.erl index 72a03c1d1a0..f022b3682f1 100644 --- a/applications/stepswitch/src/stepswitch_originate.erl +++ b/applications/stepswitch/src/stepswitch_originate.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end @@ -263,6 +263,7 @@ build_originate(#state{endpoints=Endpoints [{<<"Global-Resource">>, <<"true">>} ,{<<"Account-ID">>, AccountId} ,{<<"From-URI">>, originate_from_uri(CIDNum, OffnetReq)} + ,{<<"Realm">>, stepswitch_util:default_realm(OffnetReq)} ,{<<"Reseller-ID">>, kz_services:find_reseller_id(AccountId)} ]), Application = kz_json:get_value(<<"Application-Name">>, OffnetReq, <<"park">>), diff --git a/applications/stepswitch/src/stepswitch_outbound.erl b/applications/stepswitch/src/stepswitch_outbound.erl index ad38cb6588c..47ba10fbbfb 100644 --- a/applications/stepswitch/src/stepswitch_outbound.erl +++ b/applications/stepswitch/src/stepswitch_outbound.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Handle offnet requests, including rating them %%% @end diff --git a/applications/stepswitch/src/stepswitch_request_sup.erl b/applications/stepswitch/src/stepswitch_request_sup.erl index 0d869280018..d526cf7857b 100644 --- a/applications/stepswitch/src/stepswitch_request_sup.erl +++ b/applications/stepswitch/src/stepswitch_request_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stepswitch/src/stepswitch_resource_selectors.erl b/applications/stepswitch/src/stepswitch_resource_selectors.erl index c1487028bb7..a8c520f764f 100644 --- a/applications/stepswitch/src/stepswitch_resource_selectors.erl +++ b/applications/stepswitch/src/stepswitch_resource_selectors.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stepswitch/src/stepswitch_resources.erl b/applications/stepswitch/src/stepswitch_resources.erl index 0695ffe966a..911937ba460 100644 --- a/applications/stepswitch/src/stepswitch_resources.erl +++ b/applications/stepswitch/src/stepswitch_resources.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stepswitch/src/stepswitch_sms.erl b/applications/stepswitch/src/stepswitch_sms.erl index c516bdfc984..68637e9cc46 100644 --- a/applications/stepswitch/src/stepswitch_sms.erl +++ b/applications/stepswitch/src/stepswitch_sms.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/stepswitch/src/stepswitch_sup.erl b/applications/stepswitch/src/stepswitch_sup.erl index 1487d3711e9..8b89fc5d23f 100644 --- a/applications/stepswitch/src/stepswitch_sup.erl +++ b/applications/stepswitch/src/stepswitch_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% Root supervisor tree for stepswitch routing WhApp %%% @end diff --git a/applications/stepswitch/src/stepswitch_util.erl b/applications/stepswitch/src/stepswitch_util.erl index 6e8f081e7e0..a7e215ea8cf 100644 --- a/applications/stepswitch/src/stepswitch_util.erl +++ b/applications/stepswitch/src/stepswitch_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/sysconf/doc/README.md b/applications/sysconf/doc/README.md index 1aff9bb7f16..7783c11d6e3 100644 --- a/applications/sysconf/doc/README.md +++ b/applications/sysconf/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: System Config -Title: System Config -Language: en-US -*/ Kazoo configuration, for the most part, lives in the `system_config` database (with a few exceptions for BigCouch, RabbitMQ, and basic Kazoo settings). diff --git a/applications/sysconf/src/sysconf_acls.erl b/applications/sysconf/src/sysconf_acls.erl index fc4ecb8d46b..20246ae4929 100644 --- a/applications/sysconf/src/sysconf_acls.erl +++ b/applications/sysconf/src/sysconf_acls.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/sysconf/src/sysconf_app.erl b/applications/sysconf/src/sysconf_app.erl index 06c20cfaafb..0fa93f09d4d 100644 --- a/applications/sysconf/src/sysconf_app.erl +++ b/applications/sysconf/src/sysconf_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/sysconf/src/sysconf_flush.erl b/applications/sysconf/src/sysconf_flush.erl index 14598149fa7..50c6310f89a 100644 --- a/applications/sysconf/src/sysconf_flush.erl +++ b/applications/sysconf/src/sysconf_flush.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% @end %%% @contributors diff --git a/applications/sysconf/src/sysconf_gateways.erl b/applications/sysconf/src/sysconf_gateways.erl index 41cd421869b..2554922856c 100644 --- a/applications/sysconf/src/sysconf_gateways.erl +++ b/applications/sysconf/src/sysconf_gateways.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/sysconf/src/sysconf_get.erl b/applications/sysconf/src/sysconf_get.erl index a3a5bc11a2f..dbc1bd2ec8b 100644 --- a/applications/sysconf/src/sysconf_get.erl +++ b/applications/sysconf/src/sysconf_get.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Handle requests to read configuration data %%% Support nested keys a la kz_json, with a # diff --git a/applications/sysconf/src/sysconf_listener.erl b/applications/sysconf/src/sysconf_listener.erl index d5e94a04fd2..d4c03bbd0b6 100644 --- a/applications/sysconf/src/sysconf_listener.erl +++ b/applications/sysconf/src/sysconf_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Listener for sysconf_read, and sysconf_write AMQP requests %%% @end diff --git a/applications/sysconf/src/sysconf_set.erl b/applications/sysconf/src/sysconf_set.erl index 48acf938e0f..eaedd69c9ec 100644 --- a/applications/sysconf/src/sysconf_set.erl +++ b/applications/sysconf/src/sysconf_set.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Handle AMQP requests to write system configuration data. %%% Support nested keys like key#subkey#subsubkey diff --git a/applications/sysconf/src/sysconf_sup.erl b/applications/sysconf/src/sysconf_sup.erl index 99ff9331329..45a8c54c4bb 100644 --- a/applications/sysconf/src/sysconf_sup.erl +++ b/applications/sysconf/src/sysconf_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/tasks/doc/README.md b/applications/tasks/doc/README.md index 3c66faccd19..00b9f26774e 100644 --- a/applications/tasks/doc/README.md +++ b/applications/tasks/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Tasks -Title: Tasks -Language: en-US -*/ # Kazoo Tasks diff --git a/applications/tasks/src/knm_number_crawler.erl b/applications/tasks/src/knm_number_crawler.erl index 1b8fd97ada8..bb77d4df54b 100644 --- a/applications/tasks/src/knm_number_crawler.erl +++ b/applications/tasks/src/knm_number_crawler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/tasks/src/knm_port_request_crawler.erl b/applications/tasks/src/knm_port_request_crawler.erl index f98a459e0e7..505a795ec6a 100644 --- a/applications/tasks/src/knm_port_request_crawler.erl +++ b/applications/tasks/src/knm_port_request_crawler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/tasks/src/kz_account_crawler.erl b/applications/tasks/src/kz_account_crawler.erl index 5d92dbf7775..d0e1172a61c 100644 --- a/applications/tasks/src/kz_account_crawler.erl +++ b/applications/tasks/src/kz_account_crawler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/applications/tasks/src/kz_task_noinput_worker.erl b/applications/tasks/src/kz_task_noinput_worker.erl index b291790ce34..1d9b6cc5ed7 100644 --- a/applications/tasks/src/kz_task_noinput_worker.erl +++ b/applications/tasks/src/kz_task_noinput_worker.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Run tasks without CSV input file, scheduled by kz_tasks. %%% @end diff --git a/applications/tasks/src/kz_task_worker.erl b/applications/tasks/src/kz_task_worker.erl index 57d4b621469..a65b703cafc 100644 --- a/applications/tasks/src/kz_task_worker.erl +++ b/applications/tasks/src/kz_task_worker.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Run tasks scheduled by kz_tasks. %%% @end diff --git a/applications/tasks/src/kz_tasks_help.erl b/applications/tasks/src/kz_tasks_help.erl index 8b738153ef2..95c3e580311 100644 --- a/applications/tasks/src/kz_tasks_help.erl +++ b/applications/tasks/src/kz_tasks_help.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Discover available tasks. %%% @end diff --git a/applications/tasks/src/kz_tasks_scheduler.erl b/applications/tasks/src/kz_tasks_scheduler.erl index 4821ebccc39..986d19b00f8 100644 --- a/applications/tasks/src/kz_tasks_scheduler.erl +++ b/applications/tasks/src/kz_tasks_scheduler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Schedule one-off tasks only once per cluster %%% @end diff --git a/applications/tasks/src/kz_tasks_trigger.erl b/applications/tasks/src/kz_tasks_trigger.erl index da0d272997c..f14e1261ec4 100644 --- a/applications/tasks/src/kz_tasks_trigger.erl +++ b/applications/tasks/src/kz_tasks_trigger.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Trigger jobs for execution %%% @end diff --git a/applications/tasks/src/modules/kt_cleanup.erl b/applications/tasks/src/modules/kt_cleanup.erl index 059c6259e54..e4d582b5f92 100644 --- a/applications/tasks/src/modules/kt_cleanup.erl +++ b/applications/tasks/src/modules/kt_cleanup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/tasks/src/modules/kt_modb.erl b/applications/tasks/src/modules/kt_modb.erl index eacd3ade440..baa0ecfed41 100644 --- a/applications/tasks/src/modules/kt_modb.erl +++ b/applications/tasks/src/modules/kt_modb.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/tasks/src/modules/kt_numbers.erl b/applications/tasks/src/modules/kt_numbers.erl index 8eb72183ea1..7e796704c07 100644 --- a/applications/tasks/src/modules/kt_numbers.erl +++ b/applications/tasks/src/modules/kt_numbers.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end @@ -262,20 +262,8 @@ account_id(?MATCH_ACCOUNT_RAW(_)) -> 'true'; account_id(_) -> 'false'. -spec carrier_module(ne_binary()) -> boolean(). -carrier_module(<<"knm_bandwidth2">>) -> 'true'; -carrier_module(<<"knm_bandwidth">>) -> 'true'; -carrier_module(<<"knm_inum">>) -> 'true'; -carrier_module(<<"knm_local">>) -> 'true'; -carrier_module(<<"knm_managed">>) -> 'true'; -carrier_module(<<"knm_mdn">>) -> 'true'; -carrier_module(<<"knm_other">>) -> 'true'; -carrier_module(<<"knm_reserved">>) -> 'true'; -carrier_module(<<"knm_reserved_reseller">>) -> 'true'; -carrier_module(<<"knm_simwood">>) -> 'true'; -carrier_module(<<"knm_telnyx">>) -> 'true'; -carrier_module(<<"knm_vitelity">>) -> 'true'; -carrier_module(<<"knm_voip_innovations">>) -> 'true'; -carrier_module(_) -> 'false'. +carrier_module(Data) -> + lists:member(Data, knm_carriers:all_modules()). %%% Appliers diff --git a/applications/tasks/src/modules/kt_port_requests.erl b/applications/tasks/src/modules/kt_port_requests.erl index bdc7f993beb..1a6b3b44800 100644 --- a/applications/tasks/src/modules/kt_port_requests.erl +++ b/applications/tasks/src/modules/kt_port_requests.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/tasks/src/modules/kt_resource_selectors.erl b/applications/tasks/src/modules/kt_resource_selectors.erl index f287394ebfb..8558d9f8901 100644 --- a/applications/tasks/src/modules/kt_resource_selectors.erl +++ b/applications/tasks/src/modules/kt_resource_selectors.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/tasks/src/modules/kt_services.erl b/applications/tasks/src/modules/kt_services.erl index a85ff7560e9..1a0ef4417e7 100644 --- a/applications/tasks/src/modules/kt_services.erl +++ b/applications/tasks/src/modules/kt_services.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/tasks/src/modules/kt_skel.erl b/applications/tasks/src/modules/kt_skel.erl index 40d5b85817b..fafc419197b 100644 --- a/applications/tasks/src/modules/kt_skel.erl +++ b/applications/tasks/src/modules/kt_skel.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/tasks/src/modules/kt_token_auth.erl b/applications/tasks/src/modules/kt_token_auth.erl index 6cab5905179..31c1f416462 100644 --- a/applications/tasks/src/modules/kt_token_auth.erl +++ b/applications/tasks/src/modules/kt_token_auth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/tasks/src/modules/kt_user_auth.erl b/applications/tasks/src/modules/kt_user_auth.erl index f88f7e15535..553171998ab 100644 --- a/applications/tasks/src/modules/kt_user_auth.erl +++ b/applications/tasks/src/modules/kt_user_auth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/tasks/src/modules/kt_webhooks.erl b/applications/tasks/src/modules/kt_webhooks.erl index 4fc912398de..36910848cf0 100644 --- a/applications/tasks/src/modules/kt_webhooks.erl +++ b/applications/tasks/src/modules/kt_webhooks.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/tasks/src/tasks_app.erl b/applications/tasks/src/tasks_app.erl index c82cea0f1c8..82f5a8aeb74 100644 --- a/applications/tasks/src/tasks_app.erl +++ b/applications/tasks/src/tasks_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/tasks/src/tasks_bindings.erl b/applications/tasks/src/tasks_bindings.erl index 08bf662fc17..4259002ef48 100644 --- a/applications/tasks/src/tasks_bindings.erl +++ b/applications/tasks/src/tasks_bindings.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Store routing keys/pid bindings. When a binding is fired, %%% pass the payload to the pid for evaluation, accumulating diff --git a/applications/tasks/src/tasks_listener.erl b/applications/tasks/src/tasks_listener.erl index 689f6d78cc4..e9de3d41a98 100644 --- a/applications/tasks/src/tasks_listener.erl +++ b/applications/tasks/src/tasks_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/tasks/src/tasks_sup.erl b/applications/tasks/src/tasks_sup.erl index e9de505b855..32b177e189c 100644 --- a/applications/tasks/src/tasks_sup.erl +++ b/applications/tasks/src/tasks_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/teletype/doc/README.md b/applications/teletype/doc/README.md index 338e0a502c7..5f5d790d8b3 100644 --- a/applications/teletype/doc/README.md +++ b/applications/teletype/doc/README.md @@ -1,9 +1,3 @@ -/* -Section: Teletype -Title: Index -Language: en-US -Version: 3.19 -*/ # Overview diff --git a/applications/teletype/doc/maintenance.md b/applications/teletype/doc/maintenance.md index 9e45bb5cc55..8481aa23cc6 100644 --- a/applications/teletype/doc/maintenance.md +++ b/applications/teletype/doc/maintenance.md @@ -1,9 +1,3 @@ -/* -Section: Teletype -Title: Maintenance -Language: en-US -Version: 3.19 -*/ # Overview diff --git a/applications/teletype/src/teletype_app.erl b/applications/teletype/src/teletype_app.erl index d806e023a9e..525f7f7fb7d 100644 --- a/applications/teletype/src/teletype_app.erl +++ b/applications/teletype/src/teletype_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/teletype/src/teletype_listener.erl b/applications/teletype/src/teletype_listener.erl index c786843aa5f..5d003b2b3d5 100644 --- a/applications/teletype/src/teletype_listener.erl +++ b/applications/teletype/src/teletype_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/teletype/src/teletype_maintenance.erl b/applications/teletype/src/teletype_maintenance.erl index 79c4a3ff111..e4bb192747b 100644 --- a/applications/teletype/src/teletype_maintenance.erl +++ b/applications/teletype/src/teletype_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end @@ -12,6 +12,7 @@ ,restore_system_templates/0 ,restore_system_template/1 ]). +-export([renderer_status/0]). -include("teletype.hrl"). @@ -104,3 +105,20 @@ list_system_templates() -> io:format("failed to query existing notifications: ~p~n", [_E]), [] end. + +-spec renderer_status() -> 'no_return'. +renderer_status() -> + Workers = [{Pid, process_info(Pid, 'message_queue_len')} + || {_, Pid, _, _} <- gen_server:call(teletype_sup:render_farm_name(), 'get_all_workers') + ], + {StateName, TotalWorkers, TotalOverflow, TotalInUse} = poolboy:status(teletype_sup:render_farm_name()), + io:format("Renderer Pool~n", []), + io:format(" State : ~s~n", [StateName]), + io:format(" Total Workers : ~p~n", [TotalWorkers]), + io:format(" Overflow Workers: ~p~n", [TotalOverflow]), + io:format(" Busy Workers : ~p~n", [TotalInUse]), + io:format("Renderer Workers~n", []), + _ = [io:format(" ~p has ~p pending jobs~n", [Pid, QueueLength]) + || {Pid, {_, QueueLength}} <- Workers + ], + 'no_return'. diff --git a/applications/teletype/src/teletype_renderer.erl b/applications/teletype/src/teletype_renderer.erl index bf57b60ec25..c422e8d4efb 100644 --- a/applications/teletype/src/teletype_renderer.erl +++ b/applications/teletype/src/teletype_renderer.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% %%% @end @@ -11,6 +11,7 @@ -include("teletype.hrl"). -define(SERVER, ?MODULE). +-define(RENDER_TIMEOUT, 1000 * 60 * 10). -export([start_link/1 ,render/3 @@ -35,16 +36,43 @@ start_link(Args) -> {'error', any()}. render(TemplateId, Template, TemplateData) -> Renderer = next_renderer(), + render(Renderer, TemplateId, Template, TemplateData, 3). + +-spec render(pid(), ne_binary(), binary(), kz_proplist(), integer()) -> + {'ok', iolist()} | + {'error', any()}. + +render(Renderer, TemplateId, _Template, _TemplateData, 0) -> + lager:error("rendering of ~p failed after several tries", [TemplateId]), + exit(Renderer, 'kill'), + {'error', 'render_failed'}; + +render(Renderer, TemplateId, Template, TemplateData, Tries) -> + Start = kz_util:current_tstamp(), + PoolStatus = poolboy:status('teletype_render_farm'), + lager:info("starting render of ~p", [TemplateId]), + case do_render(Renderer, TemplateId, Template, TemplateData) of + {'error', 'render_failed'} -> + lager:info("render failed in ~p, pool: ~p", [kz_util:current_tstamp() - Start, PoolStatus]), + render(Renderer, TemplateId, Template, TemplateData, Tries-1); + GoodReturn -> + lager:info("render completed in ~p, pool: ~p", [kz_util:current_tstamp() - Start, PoolStatus]), + poolboy:checkin(teletype_sup:render_farm_name(), Renderer), + GoodReturn + end. + +-spec do_render(pid(), ne_binary(), binary(), kz_proplist()) -> + {'ok', iolist()} | + {'error', any()}. +do_render(Renderer, TemplateId, Template, TemplateData) -> try gen_server:call(Renderer ,{'render', TemplateId, Template, TemplateData} - ,?MILLISECONDS_IN_HOUR + ,?RENDER_TIMEOUT ) catch _E:_R -> lager:debug("rendering failed: ~s: ~p", [_E, _R]), {'error', 'render_failed'} - after - poolboy:checkin(teletype_sup:render_farm_name(), Renderer) end. -spec next_renderer() -> pid(). diff --git a/applications/teletype/src/teletype_shared_listener.erl b/applications/teletype/src/teletype_shared_listener.erl index 7cbeb9d173e..7dedf961d3c 100644 --- a/applications/teletype/src/teletype_shared_listener.erl +++ b/applications/teletype/src/teletype_shared_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/teletype/src/teletype_sup.erl b/applications/teletype/src/teletype_sup.erl index b2fdf24395b..7708add7e87 100644 --- a/applications/teletype/src/teletype_sup.erl +++ b/applications/teletype/src/teletype_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/teletype/src/teletype_templates.erl b/applications/teletype/src/teletype_templates.erl index 8ab342f9c46..cd4cc2802ab 100644 --- a/applications/teletype/src/teletype_templates.erl +++ b/applications/teletype/src/teletype_templates.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -480,7 +480,8 @@ update_field(Value, {_IsUpdated, TemplateJObj}=Acc, GetFun, SetFun) -> ,[Value, GetFun, kz_doc:revision(TemplateJObj)] ), {'true', SetFun(TemplateJObj, Value)}; - _V -> Acc + Value -> Acc; + _V -> {'true', SetFun(TemplateJObj, Value)} end. -spec update_subject(ne_binary(), update_acc()) -> diff --git a/applications/teletype/src/teletype_tests.erl b/applications/teletype/src/teletype_tests.erl index 58b92eac90c..f92f3431471 100644 --- a/applications/teletype/src/teletype_tests.erl +++ b/applications/teletype/src/teletype_tests.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Send test API notifications %%% @end diff --git a/applications/teletype/src/teletype_util.erl b/applications/teletype/src/teletype_util.erl index 41b9d31b6e2..abf70e7c8bc 100644 --- a/applications/teletype/src/teletype_util.erl +++ b/applications/teletype/src/teletype_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -20,7 +20,7 @@ ,find_account_admin_email/1 ,find_account_admin/1 ,find_account_id/1 - ,find_account_db/1, find_account_db/2 + ,find_account_db/2 ,is_notice_enabled/3, is_notice_enabled_default/1 ,should_handle_notification/1 @@ -450,19 +450,11 @@ find_account_id(JObj) -> -spec find_account_db(ne_binary(), kz_json:object()) -> api_binary(). find_account_db(<<"account">>, JObj) -> find_account_db_from_id(JObj); find_account_db(<<"user">>, JObj) -> find_account_db_from_id(JObj); -find_account_db(<<"fax">>, JObj) -> find_account_db(JObj); +find_account_db(<<"fax">>, JObj) -> kapi_notifications:account_db(JObj); find_account_db(<<"port_request">>, _JObj) -> ?KZ_PORT_REQUESTS_DB; find_account_db(<<"webhook">>, _JObj) -> ?KZ_WEBHOOKS_DB; find_account_db(_, JObj) -> find_account_db_from_id(JObj). --spec find_account_db(kz_json:object()) -> api_binary(). -find_account_db(JObj) -> - PossibleDbs = [<<"account_db">>, <<"pvt_account_db">>, <<"Account-DB">>], - case kz_json:get_first_defined(PossibleDbs, JObj) of - 'undefined' -> find_account_db_from_id(JObj); - Db -> Db - end. - -spec find_account_db_from_id(kz_json:object()) -> api_binary(). find_account_db_from_id(JObj) -> case find_account_id(JObj) of diff --git a/applications/teletype/src/templates/teletype_cnam_request.erl b/applications/teletype/src/templates/teletype_cnam_request.erl index f50817eb260..62606b37e30 100644 --- a/applications/teletype/src/templates/teletype_cnam_request.erl +++ b/applications/teletype/src/templates/teletype_cnam_request.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz Inc +%%% @copyright (C) 2015-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_customer_update.erl b/applications/teletype/src/templates/teletype_customer_update.erl index a64aa88a50b..afc3a77a951 100644 --- a/applications/teletype/src/templates/teletype_customer_update.erl +++ b/applications/teletype/src/templates/teletype_customer_update.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz Inc +%%% @copyright (C) 2014-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_denied_emergency_bridge.erl b/applications/teletype/src/templates/teletype_denied_emergency_bridge.erl index 4b99e7743ff..98606c15d1f 100644 --- a/applications/teletype/src/templates/teletype_denied_emergency_bridge.erl +++ b/applications/teletype/src/templates/teletype_denied_emergency_bridge.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz Inc +%%% @copyright (C) 2014-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_deregister.erl b/applications/teletype/src/templates/teletype_deregister.erl index bcb8021d440..886256ba4a1 100644 --- a/applications/teletype/src/templates/teletype_deregister.erl +++ b/applications/teletype/src/templates/teletype_deregister.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz Inc +%%% @copyright (C) 2014-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_fax_inbound_error_to_email.erl b/applications/teletype/src/templates/teletype_fax_inbound_error_to_email.erl index dc71eda4ce1..608215d3668 100644 --- a/applications/teletype/src/templates/teletype_fax_inbound_error_to_email.erl +++ b/applications/teletype/src/templates/teletype_fax_inbound_error_to_email.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz Inc +%%% @copyright (C) 2014-2017, 2600Hz Inc %%% @doc %%% %%% @end @@ -35,7 +35,8 @@ -define(TEMPLATE_SUBJECT, <<"Error Receiving Fax from {% firstof caller_id.name fax.remote_station_id caller_id.number \"unknown number\" %} ({% firstof fax.remote_station_id caller_id.number \"unknown number\" %})">>). -define(TEMPLATE_CATEGORY, <<"fax">>). --define(TEMPLATE_NAME, <<"Inbound Fax Error to Email">>). +-define(TEMPLATE_NAME, <<"Inbound Fax Negotiation Error to Email">>). +-define(FILTERED_TEMPLATE_NAME, <<"Inbound Fax Receive Error to Email">>). -define(TEMPLATE_TO, ?CONFIGURED_EMAILS(?EMAIL_ORIGINAL)). -define(TEMPLATE_FROM, teletype_util:default_from_address(?MOD_CONFIG_CAT)). @@ -49,14 +50,13 @@ init() -> Fields = [{'macros', ?TEMPLATE_MACROS} ,{'subject', ?TEMPLATE_SUBJECT} ,{'category', ?TEMPLATE_CATEGORY} - ,{'friendly_name', ?TEMPLATE_NAME} ,{'to', ?TEMPLATE_TO} ,{'from', ?TEMPLATE_FROM} ,{'cc', ?TEMPLATE_CC} ,{'bcc', ?TEMPLATE_BCC} ,{'reply_to', ?TEMPLATE_REPLY_TO}], - teletype_templates:init(?TEMPLATE_ID_FILTERED, Fields), - teletype_templates:init(?TEMPLATE_ID, Fields). + teletype_templates:init(?TEMPLATE_ID_FILTERED, [{'friendly_name', ?FILTERED_TEMPLATE_NAME} | Fields]), + teletype_templates:init(?TEMPLATE_ID, [{'friendly_name', ?TEMPLATE_NAME} | Fields]). -spec handle_fax_inbound_error(kz_json:object(), kz_proplist()) -> 'ok'. handle_fax_inbound_error(JObj, _Props) -> @@ -72,7 +72,9 @@ handle_fax_inbound_error(JObj, _Props) -> 'false' -> lager:debug("notification handling not configured for this account"); 'true' -> handle_fax_inbound(DataJObj, ?TEMPLATE_ID) end, - case teletype_util:is_notice_enabled(AccountId, JObj, ?TEMPLATE_ID_FILTERED) and is_true_fax_error(AccountId, JObj) of + case teletype_util:is_notice_enabled(AccountId, JObj, ?TEMPLATE_ID_FILTERED) + andalso is_true_fax_error(AccountId, JObj) + of 'false' -> lager:debug("filtered notification handling not configured for this account"); 'true' -> handle_fax_inbound(DataJObj, ?TEMPLATE_ID_FILTERED) end. diff --git a/applications/teletype/src/templates/teletype_fax_inbound_to_email.erl b/applications/teletype/src/templates/teletype_fax_inbound_to_email.erl index 8be0ad71cfe..d67308ba2cf 100644 --- a/applications/teletype/src/templates/teletype_fax_inbound_to_email.erl +++ b/applications/teletype/src/templates/teletype_fax_inbound_to_email.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz Inc +%%% @copyright (C) 2014-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_fax_outbound_error_to_email.erl b/applications/teletype/src/templates/teletype_fax_outbound_error_to_email.erl index 499fde6935f..40c86e96615 100644 --- a/applications/teletype/src/templates/teletype_fax_outbound_error_to_email.erl +++ b/applications/teletype/src/templates/teletype_fax_outbound_error_to_email.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz Inc +%%% @copyright (C) 2014-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_fax_outbound_to_email.erl b/applications/teletype/src/templates/teletype_fax_outbound_to_email.erl index a0ebdcc98ea..5e2c6266c00 100644 --- a/applications/teletype/src/templates/teletype_fax_outbound_to_email.erl +++ b/applications/teletype/src/templates/teletype_fax_outbound_to_email.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz Inc +%%% @copyright (C) 2014-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_fax_util.erl b/applications/teletype/src/templates/teletype_fax_util.erl index 195b74c6c8e..2c31c416ecc 100644 --- a/applications/teletype/src/templates/teletype_fax_util.erl +++ b/applications/teletype/src/templates/teletype_fax_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end @@ -60,23 +60,23 @@ get_fax_doc(DataJObj) -> get_fax_doc(DataJObj, teletype_util:is_preview(DataJObj)). get_fax_doc(DataJObj, 'true') -> - FaxId = kz_json:get_value(<<"fax_id">>, DataJObj), - case teletype_util:open_doc(<<"fax">>, FaxId, DataJObj) of - {'ok', JObj} -> JObj; - {'error', _E} -> kz_json:new() + FaxId = kz_json:get_value(<<"fax_id">>, DataJObj), + AccountDb = kapi_notifications:account_db(DataJObj), + + case kz_datamgr:open_cache_doc(AccountDb, FaxId) of + {'ok', JObj} -> + JObj; + {'error', _E} -> + kz_json:new() end; + get_fax_doc(DataJObj, 'false') -> - FaxId = kz_json:get_value(<<"fax_id">>, DataJObj), - case teletype_util:open_doc(<<"fax">>, FaxId, DataJObj) of - {'ok', JObj} -> JObj; - {'error', _E} -> get_fax_doc_from_modb(DataJObj, FaxId) - end. + FaxId = kz_json:get_value(<<"fax_id">>, DataJObj), + AccountDb = kapi_notifications:account_db(DataJObj), --spec get_fax_doc_from_modb(kz_json:object(), ne_binary()) -> kz_json:object(). -get_fax_doc_from_modb(DataJObj, FaxId) -> - AccountId = teletype_util:find_account_id(DataJObj), - case kazoo_modb:open_doc(AccountId, {<<"fax">>, FaxId}) of - {'ok', FaxJObj} -> FaxJObj; + case kz_datamgr:open_cache_doc(AccountDb, FaxId) of + {'ok', JObj} -> + JObj; {'error', _E} -> lager:debug("failed to find fax ~s: ~p", [FaxId, _E]), teletype_util:send_update(DataJObj, <<"failed">>, <<"Fax-ID was invalid">>), @@ -189,7 +189,7 @@ get_attachment(ContentType, Bin) -> -spec fax_db(kz_json:object()) -> ne_binary(). fax_db(DataJObj) -> - case teletype_util:find_account_db(DataJObj) of + case kapi_notifications:account_db(DataJObj) of 'undefined' -> ?KZ_FAXES_DB; Db -> Db end. diff --git a/applications/teletype/src/templates/teletype_first_occurrence.erl b/applications/teletype/src/templates/teletype_first_occurrence.erl index 5749257a7f4..359ccb2844a 100644 --- a/applications/teletype/src/templates/teletype_first_occurrence.erl +++ b/applications/teletype/src/templates/teletype_first_occurrence.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz Inc +%%% @copyright (C) 2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_low_balance.erl b/applications/teletype/src/templates/teletype_low_balance.erl index ce3d5e63d90..f6bdf62f28f 100644 --- a/applications/teletype/src/templates/teletype_low_balance.erl +++ b/applications/teletype/src/templates/teletype_low_balance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz Inc +%%% @copyright (C) 2014-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_new_account.erl b/applications/teletype/src/templates/teletype_new_account.erl index d5bc77581de..52047027c69 100644 --- a/applications/teletype/src/templates/teletype_new_account.erl +++ b/applications/teletype/src/templates/teletype_new_account.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz Inc +%%% @copyright (C) 2015-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_new_user.erl b/applications/teletype/src/templates/teletype_new_user.erl index c82a9b7685d..0abb4fe7de5 100644 --- a/applications/teletype/src/templates/teletype_new_user.erl +++ b/applications/teletype/src/templates/teletype_new_user.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz Inc +%%% @copyright (C) 2015-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_password_recovery.erl b/applications/teletype/src/templates/teletype_password_recovery.erl index dc86e809479..02579b3fa23 100644 --- a/applications/teletype/src/templates/teletype_password_recovery.erl +++ b/applications/teletype/src/templates/teletype_password_recovery.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz Inc +%%% @copyright (C) 2015-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_port_cancel.erl b/applications/teletype/src/templates/teletype_port_cancel.erl index a7c58157d4d..b7cee1abb47 100644 --- a/applications/teletype/src/templates/teletype_port_cancel.erl +++ b/applications/teletype/src/templates/teletype_port_cancel.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz Inc +%%% @copyright (C) 2015-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_port_comment.erl b/applications/teletype/src/templates/teletype_port_comment.erl index 521fb0cb7da..1ae885f67b5 100644 --- a/applications/teletype/src/templates/teletype_port_comment.erl +++ b/applications/teletype/src/templates/teletype_port_comment.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz Inc +%%% @copyright (C) 2015-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_port_pending.erl b/applications/teletype/src/templates/teletype_port_pending.erl index 79ccba47757..a130c52dcad 100644 --- a/applications/teletype/src/templates/teletype_port_pending.erl +++ b/applications/teletype/src/templates/teletype_port_pending.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz Inc +%%% @copyright (C) 2015-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_port_rejected.erl b/applications/teletype/src/templates/teletype_port_rejected.erl index 1244215dd62..502eeb82853 100644 --- a/applications/teletype/src/templates/teletype_port_rejected.erl +++ b/applications/teletype/src/templates/teletype_port_rejected.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz Inc +%%% @copyright (C) 2015-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_port_request.erl b/applications/teletype/src/templates/teletype_port_request.erl index b380bc2e026..75a0243eb33 100644 --- a/applications/teletype/src/templates/teletype_port_request.erl +++ b/applications/teletype/src/templates/teletype_port_request.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz Inc +%%% @copyright (C) 2015-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_port_request_admin.erl b/applications/teletype/src/templates/teletype_port_request_admin.erl index d96e9371f2b..db9208cb65b 100644 --- a/applications/teletype/src/templates/teletype_port_request_admin.erl +++ b/applications/teletype/src/templates/teletype_port_request_admin.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz Inc +%%% @copyright (C) 2015-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_port_scheduled.erl b/applications/teletype/src/templates/teletype_port_scheduled.erl index 2333f1cf4b5..f5cdfdb0a04 100644 --- a/applications/teletype/src/templates/teletype_port_scheduled.erl +++ b/applications/teletype/src/templates/teletype_port_scheduled.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz Inc +%%% @copyright (C) 2015-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_port_unconfirmed.erl b/applications/teletype/src/templates/teletype_port_unconfirmed.erl index f405647207b..6c604a55e53 100644 --- a/applications/teletype/src/templates/teletype_port_unconfirmed.erl +++ b/applications/teletype/src/templates/teletype_port_unconfirmed.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz Inc +%%% @copyright (C) 2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_port_utils.erl b/applications/teletype/src/templates/teletype_port_utils.erl index 90902174d5e..6902f5a98eb 100644 --- a/applications/teletype/src/templates/teletype_port_utils.erl +++ b/applications/teletype/src/templates/teletype_port_utils.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz Inc +%%% @copyright (C) 2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_ported.erl b/applications/teletype/src/templates/teletype_ported.erl index 551235606d6..a1448423629 100644 --- a/applications/teletype/src/templates/teletype_ported.erl +++ b/applications/teletype/src/templates/teletype_ported.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz Inc +%%% @copyright (C) 2015-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_service_added.erl b/applications/teletype/src/templates/teletype_service_added.erl index 38f9cccb13e..a859d527dd8 100644 --- a/applications/teletype/src/templates/teletype_service_added.erl +++ b/applications/teletype/src/templates/teletype_service_added.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz Inc +%%% @copyright (C) 2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_system_alert.erl b/applications/teletype/src/templates/teletype_system_alert.erl index 2b70c110667..442654a7edf 100644 --- a/applications/teletype/src/templates/teletype_system_alert.erl +++ b/applications/teletype/src/templates/teletype_system_alert.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz Inc +%%% @copyright (C) 2015-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_template_skel.erl b/applications/teletype/src/templates/teletype_template_skel.erl index 8f32639251c..a21fc68b311 100644 --- a/applications/teletype/src/templates/teletype_template_skel.erl +++ b/applications/teletype/src/templates/teletype_template_skel.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz Inc +%%% @copyright (C) 2014-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_topup.erl b/applications/teletype/src/templates/teletype_topup.erl index 8eb9244de82..e02e7d0d8b9 100644 --- a/applications/teletype/src/templates/teletype_topup.erl +++ b/applications/teletype/src/templates/teletype_topup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz Inc +%%% @copyright (C) 2014-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_transaction.erl b/applications/teletype/src/templates/teletype_transaction.erl index aebe91f6f5a..d02ffcd04d3 100644 --- a/applications/teletype/src/templates/teletype_transaction.erl +++ b/applications/teletype/src/templates/teletype_transaction.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz Inc +%%% @copyright (C) 2014-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_voicemail_full.erl b/applications/teletype/src/templates/teletype_voicemail_full.erl index f234c96aa07..924c2550e5e 100644 --- a/applications/teletype/src/templates/teletype_voicemail_full.erl +++ b/applications/teletype/src/templates/teletype_voicemail_full.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz Inc +%%% @copyright (C) 2014-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_voicemail_to_email.erl b/applications/teletype/src/templates/teletype_voicemail_to_email.erl index ba4a1920dd2..5f2b9cab069 100644 --- a/applications/teletype/src/templates/teletype_voicemail_to_email.erl +++ b/applications/teletype/src/templates/teletype_voicemail_to_email.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz Inc +%%% @copyright (C) 2014-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/teletype/src/templates/teletype_webhook_disabled.erl b/applications/teletype/src/templates/teletype_webhook_disabled.erl index a839d990cc1..e0de5146656 100644 --- a/applications/teletype/src/templates/teletype_webhook_disabled.erl +++ b/applications/teletype/src/templates/teletype_webhook_disabled.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz Inc +%%% @copyright (C) 2015-2017, 2600Hz Inc %%% @doc %%% %%% @end diff --git a/applications/trunkstore/doc/README.md b/applications/trunkstore/doc/README.md index d97606107b4..23c10aa33dc 100644 --- a/applications/trunkstore/doc/README.md +++ b/applications/trunkstore/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: Trunkstore -Title: Trunkstore -Language: en-US -*/ # Trunkstore *Lightweight trunking services* Keep on trunk'n diff --git a/applications/trunkstore/src/trunkstore_app.erl b/applications/trunkstore/src/trunkstore_app.erl index d41a26b645a..3d695634258 100644 --- a/applications/trunkstore/src/trunkstore_app.erl +++ b/applications/trunkstore/src/trunkstore_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/trunkstore/src/trunkstore_handlers.erl b/applications/trunkstore/src/trunkstore_handlers.erl index 0fcbfe0c883..086d0d618a2 100644 --- a/applications/trunkstore/src/trunkstore_handlers.erl +++ b/applications/trunkstore/src/trunkstore_handlers.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Handlers for various AMQP payloads %%% @end diff --git a/applications/trunkstore/src/trunkstore_listener.erl b/applications/trunkstore/src/trunkstore_listener.erl index 64c00a4f6f2..3802b263f73 100644 --- a/applications/trunkstore/src/trunkstore_listener.erl +++ b/applications/trunkstore/src/trunkstore_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/trunkstore/src/trunkstore_maintenance.erl b/applications/trunkstore/src/trunkstore_maintenance.erl index fb4f62eb818..f9381392415 100644 --- a/applications/trunkstore/src/trunkstore_maintenance.erl +++ b/applications/trunkstore/src/trunkstore_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/trunkstore/src/trunkstore_sup.erl b/applications/trunkstore/src/trunkstore_sup.erl index c3c6a29ed97..608eef83afa 100644 --- a/applications/trunkstore/src/trunkstore_sup.erl +++ b/applications/trunkstore/src/trunkstore_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/trunkstore/src/ts_callflow.erl b/applications/trunkstore/src/ts_callflow.erl index 52e475ebeff..26b89cf4257 100644 --- a/applications/trunkstore/src/ts_callflow.erl +++ b/applications/trunkstore/src/ts_callflow.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Common functionality for onnet and offnet call handling %%% @end diff --git a/applications/trunkstore/src/ts_from_offnet.erl b/applications/trunkstore/src/ts_from_offnet.erl index be6d48d23ee..355403f83fa 100644 --- a/applications/trunkstore/src/ts_from_offnet.erl +++ b/applications/trunkstore/src/ts_from_offnet.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Calls coming from offnet (in this case, likely stepswitch) potentially %%% destined for a trunkstore client, or, if the account exists and @@ -62,7 +62,7 @@ proceed_with_endpoint(State, Endpoint, JObj) -> CallID = ts_callflow:get_aleg_id(State), 'true' = kapi_dialplan:bridge_endpoint_v(Endpoint), - MediaHandling = case kz_json:is_true([<<"Custom-Channel-Vars">>, <<"Executing-Extension">>], JObj) + MediaHandling = case kz_json:get_value([<<"Custom-Channel-Vars">>, <<"Inception-Account-ID">>], JObj) =/= 'undefined' orelse kz_util:is_false(kz_json:get_value(<<"Bypass-Media">>, Endpoint)) of 'true' -> <<"process">>; %% bypass media is false, process media @@ -290,21 +290,29 @@ get_endpoint_data(State, JObj, ToDID, AccountId, NumberProps) -> AuthzId = props:get_value(<<"Authorizing-ID">>, RoutingData), InFormat = props:get_value(<<"Invite-Format">>, RoutingData, <<"username">>), Invite = ts_util:invite_format(kz_util:to_lower_binary(InFormat), ToDID) ++ RoutingData, - {'endpoint', kz_json:from_list( - [{<<"Custom-Channel-Vars">>, kz_json:from_list([{<<"Auth-User">>, AuthUser} - ,{<<"Auth-Realm">>, AuthRealm} - ,{<<"Direction">>, <<"inbound">>} - ,{<<"Account-ID">>, AccountId} - ,{<<"Authorizing-ID">>, AuthzId} - ,{<<"Authorizing-Type">>, <<"sys_info">>} - ]) - } - ,{<<"Custom-SIP-Headers">>, kz_json:from_list([{<<"X-KAZOO-AOR">>, <<"sip:", AuthUser/binary, "@", AuthRealm/binary>>} - ]) - } - | Invite - ]) - }. + Routines = [fun(E) -> get_endpoint_ccvs(E, AuthUser, AuthRealm, AccountId, AuthzId) end + ,fun(E) -> get_endpoint_sip_headers(E, AuthUser, AuthRealm) end + ], + Endpoint = lists:foldl(fun(F, E) -> F(E) end, Invite, Routines), + {'endpoint', kz_json:from_list(Endpoint)}. + +-spec get_endpoint_ccvs(kz_proplist(), api_binary(), api_binary(), ne_binary(), ne_binary()) -> kz_proplist(). +get_endpoint_ccvs(Endpoint, AuthUser, AuthRealm, AccountId, AuthzId) -> + Props = props:filter_undefined([{<<"Auth-User">>, AuthUser} + ,{<<"Auth-Realm">>, AuthRealm} + ,{<<"Direction">>, <<"inbound">>} + ,{<<"Account-ID">>, AccountId} + ,{<<"Authorizing-ID">>, AuthzId} + ,{<<"Authorizing-Type">>, <<"sys_info">>} + ]), + [{<<"Custom-Channel-Vars">>, kz_json:from_list(Props)} | Endpoint]. + +-spec get_endpoint_sip_headers(kz_proplist(), api_binary(), api_binary()) -> kz_proplist(). +get_endpoint_sip_headers(Endpoint, 'undefined', _) -> Endpoint; +get_endpoint_sip_headers(Endpoint, _, 'undefined') -> Endpoint; +get_endpoint_sip_headers(Endpoint, AuthUser, AuthRealm) -> + Props = [{<<"X-KAZOO-AOR">>, <<"sip:", AuthUser/binary, "@", AuthRealm/binary>>}], + [{<<"Custom-SIP-Headers">>, kz_json:from_list(Props)} | Endpoint]. -spec routing_data(ne_binary(), ne_binary()) -> [{<<_:48,_:_*8>>, any()}]. -spec routing_data(ne_binary(), ne_binary(), kz_json:object()) -> [{<<_:48,_:_*8>>, any()}]. @@ -354,7 +362,8 @@ routing_data(ToDID, AccountId, Settings) -> 'true' -> 'ok' end, - CidOptions = kz_json:get_ne_value(<<"caller_id_options">>, SrvOptions), + AcctCidOptions = kz_json:get_ne_value(<<"caller_id_options">>, AcctStuff), + CidOptions = kz_json:get_ne_value(<<"caller_id_options">>, SrvOptions, AcctCidOptions), InboundFormat = kz_json:get_value(<<"inbound_format">>, SrvOptions, <<"npan">>), {CalleeName, CalleeNumber} = callee_id([kz_json:get_value(<<"caller_id">>, DIDOptions) diff --git a/applications/trunkstore/src/ts_from_onnet.erl b/applications/trunkstore/src/ts_from_onnet.erl index a5a71e48694..330bd2a1175 100644 --- a/applications/trunkstore/src/ts_from_onnet.erl +++ b/applications/trunkstore/src/ts_from_onnet.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Calls coming from known clients, getting settings for caller-id and %%% what not, and sending the calls offnet. diff --git a/applications/trunkstore/src/ts_offnet_sup.erl b/applications/trunkstore/src/ts_offnet_sup.erl index d74b2b35a75..af008eb12ef 100644 --- a/applications/trunkstore/src/ts_offnet_sup.erl +++ b/applications/trunkstore/src/ts_offnet_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Manage offnet calls %%% @end diff --git a/applications/trunkstore/src/ts_onnet_sup.erl b/applications/trunkstore/src/ts_onnet_sup.erl index 13c4728e059..459bb3a8a7f 100644 --- a/applications/trunkstore/src/ts_onnet_sup.erl +++ b/applications/trunkstore/src/ts_onnet_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Manage onnet calls %%% @end diff --git a/applications/trunkstore/src/ts_responder.erl b/applications/trunkstore/src/ts_responder.erl index 47011f25d3e..212cf5839ad 100644 --- a/applications/trunkstore/src/ts_responder.erl +++ b/applications/trunkstore/src/ts_responder.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% Trunk-Store responder waits for Auth and Route requests on the broadcast %%% Exchange, and delievers the requests to the corresponding handler. diff --git a/applications/trunkstore/src/ts_route_req.erl b/applications/trunkstore/src/ts_route_req.erl index 1dfc8d23243..bf510eeed8d 100644 --- a/applications/trunkstore/src/ts_route_req.erl +++ b/applications/trunkstore/src/ts_route_req.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Handle route requests off AMQP %%% @end diff --git a/applications/trunkstore/src/ts_util.erl b/applications/trunkstore/src/ts_util.erl index 6440d3bdd46..35728844f05 100644 --- a/applications/trunkstore/src/ts_util.erl +++ b/applications/trunkstore/src/ts_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% utility functions for Trunkstore %%% @@ -167,7 +167,9 @@ lookup_user_flags('undefined', _, AccountId, DID) -> ]), {'ok', kz_json:from_list( [{<<"server">>, Server} - ,{<<"account">>, kz_json:get_value(<<"account">>, JObj, kz_json:new())} + ,{<<"account">>, + merge_account_attributes(AccountId, kz_json:get_value(<<"account">>, JObj, kz_json:new())) + } ,{<<"call_restriction">>, kz_json:new()} ]) } @@ -200,7 +202,12 @@ lookup_user_flags(Name, Realm, AccountId, _) -> {'ok', AccountJObj} = kz_account:fetch(AccountId), Restriction = kz_json:get_value(<<"call_restriction">>, AccountJObj, kz_json:new()), - FlagsJObj = kz_json:set_value(<<"call_restriction">>, Restriction, JObj), + Props = [{<<"call_restriction">>, Restriction} + ,{<<"account">> + ,merge_account_attributes(AccountJObj, kz_json:get_value(<<"account">>, JObj, kz_json:new())) + } + ], + FlagsJObj = kz_json:set_values(Props, JObj), kz_cache:store_local(?CACHE_NAME ,{'lookup_user_flags', Realm, Name, AccountId} ,FlagsJObj @@ -209,6 +216,20 @@ lookup_user_flags(Name, Realm, AccountId, _) -> end end. +-spec merge_account_attributes(ne_binary() | kz_json:object(), kz_json:object()) -> kz_json:object(). +merge_account_attributes(?NE_BINARY=AccountId, JObj) -> + case kz_account:fetch(AccountId) of + {'ok', Account} -> merge_account_attributes(Account, JObj); + {'error', _} -> JObj + end; +merge_account_attributes(Account, JObj) -> + CidOptions = kz_json:get_ne_value(<<"caller_id_options">>, Account), + Props = props:filter_undefined( + [{<<"caller_id_options">>, CidOptions} + ] + ), + kz_json:set_values(Props, JObj). + -spec get_call_duration(kz_json:object()) -> integer(). get_call_duration(JObj) -> kz_util:to_integer(kz_json:get_value(<<"Billing-Seconds">>, JObj)). diff --git a/applications/webhooks/doc/README.md b/applications/webhooks/doc/README.md index b08a676bc96..ff10f374f2e 100644 --- a/applications/webhooks/doc/README.md +++ b/applications/webhooks/doc/README.md @@ -1,8 +1,3 @@ -/* -Section: WebHooks -Title: WebHooks -Language: en-US -*/ # WebHooks *Event driven HTTP callbacks* Smee: I've just had an apostrophe. diff --git a/applications/webhooks/doc/maintenance.md b/applications/webhooks/doc/maintenance.md index 31c824c49b2..57df863c48d 100644 --- a/applications/webhooks/doc/maintenance.md +++ b/applications/webhooks/doc/maintenance.md @@ -1,9 +1,3 @@ -/* -Section: WebHooks -Title: Maintenance -Language: en-US -Version: 3.21 -*/ ## See what hooks are active diff --git a/applications/webhooks/src/modules/webhooks_callflow.erl b/applications/webhooks/src/modules/webhooks_callflow.erl index f71d9c10d99..e7aabd26a6a 100644 --- a/applications/webhooks/src/modules/webhooks_callflow.erl +++ b/applications/webhooks/src/modules/webhooks_callflow.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% %%% @contributors %%% Peter Defebvre diff --git a/applications/webhooks/src/modules/webhooks_channel_answer.erl b/applications/webhooks/src/modules/webhooks_channel_answer.erl index b46fa0cff21..31b1bd38517 100644 --- a/applications/webhooks/src/modules/webhooks_channel_answer.erl +++ b/applications/webhooks/src/modules/webhooks_channel_answer.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% %%% @contributors %%%------------------------------------------------------------------- diff --git a/applications/webhooks/src/modules/webhooks_channel_bridge.erl b/applications/webhooks/src/modules/webhooks_channel_bridge.erl index 2e468313e8c..e6d2f1f9e32 100644 --- a/applications/webhooks/src/modules/webhooks_channel_bridge.erl +++ b/applications/webhooks/src/modules/webhooks_channel_bridge.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% %%% @contributors %%%------------------------------------------------------------------- diff --git a/applications/webhooks/src/modules/webhooks_channel_create.erl b/applications/webhooks/src/modules/webhooks_channel_create.erl index f41767b59e9..2315bb34675 100644 --- a/applications/webhooks/src/modules/webhooks_channel_create.erl +++ b/applications/webhooks/src/modules/webhooks_channel_create.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% %%% @contributors %%%------------------------------------------------------------------- diff --git a/applications/webhooks/src/modules/webhooks_channel_destroy.erl b/applications/webhooks/src/modules/webhooks_channel_destroy.erl index 62054270bc8..0d27fe4086a 100644 --- a/applications/webhooks/src/modules/webhooks_channel_destroy.erl +++ b/applications/webhooks/src/modules/webhooks_channel_destroy.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% %%% @contributors %%%------------------------------------------------------------------- diff --git a/applications/webhooks/src/modules/webhooks_inbound_fax.erl b/applications/webhooks/src/modules/webhooks_inbound_fax.erl index 8de5e78908e..cca433b5cd8 100644 --- a/applications/webhooks/src/modules/webhooks_inbound_fax.erl +++ b/applications/webhooks/src/modules/webhooks_inbound_fax.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% %%% @contributors %%% Peter Defebvre diff --git a/applications/webhooks/src/modules/webhooks_object.erl b/applications/webhooks/src/modules/webhooks_object.erl index 23f797f0761..ef4d675218e 100644 --- a/applications/webhooks/src/modules/webhooks_object.erl +++ b/applications/webhooks/src/modules/webhooks_object.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% %%% @contributors %%%------------------------------------------------------------------- diff --git a/applications/webhooks/src/modules/webhooks_outbound_fax.erl b/applications/webhooks/src/modules/webhooks_outbound_fax.erl index ecad2295ac2..11e0ee152e0 100644 --- a/applications/webhooks/src/modules/webhooks_outbound_fax.erl +++ b/applications/webhooks/src/modules/webhooks_outbound_fax.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% %%% @contributors %%% Peter Defebvre diff --git a/applications/webhooks/src/modules/webhooks_parking.erl b/applications/webhooks/src/modules/webhooks_parking.erl index d227e5ed919..b3ddeaf54e4 100644 --- a/applications/webhooks/src/modules/webhooks_parking.erl +++ b/applications/webhooks/src/modules/webhooks_parking.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% %%% @contributors %%% Peter Defebvre diff --git a/applications/webhooks/src/modules/webhooks_skel.erl b/applications/webhooks/src/modules/webhooks_skel.erl index e1c277220df..31d934cbc80 100644 --- a/applications/webhooks/src/modules/webhooks_skel.erl +++ b/applications/webhooks/src/modules/webhooks_skel.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% %%% @contributors %%%------------------------------------------------------------------- diff --git a/applications/webhooks/src/webhooks_app.erl b/applications/webhooks/src/webhooks_app.erl index a8534a29a9c..0a5a7230409 100644 --- a/applications/webhooks/src/webhooks_app.erl +++ b/applications/webhooks/src/webhooks_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/webhooks/src/webhooks_channel_util.erl b/applications/webhooks/src/webhooks_channel_util.erl index 0979a57057a..c96f8b1fb8f 100644 --- a/applications/webhooks/src/webhooks_channel_util.erl +++ b/applications/webhooks/src/webhooks_channel_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% %%% @contributors %%%------------------------------------------------------------------- diff --git a/applications/webhooks/src/webhooks_disabler.erl b/applications/webhooks/src/webhooks_disabler.erl index 4bb8f8896be..bf5f98f1c17 100644 --- a/applications/webhooks/src/webhooks_disabler.erl +++ b/applications/webhooks/src/webhooks_disabler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz +%%% @copyright (C) 2015-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/webhooks/src/webhooks_init.erl b/applications/webhooks/src/webhooks_init.erl index dfbe2204749..a1b129429a5 100644 --- a/applications/webhooks/src/webhooks_init.erl +++ b/applications/webhooks/src/webhooks_init.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/webhooks/src/webhooks_listener.erl b/applications/webhooks/src/webhooks_listener.erl index fba3bf5d081..455e708114f 100644 --- a/applications/webhooks/src/webhooks_listener.erl +++ b/applications/webhooks/src/webhooks_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/webhooks/src/webhooks_shared_listener.erl b/applications/webhooks/src/webhooks_shared_listener.erl index 26ea6d16937..39f9d2e8e17 100644 --- a/applications/webhooks/src/webhooks_shared_listener.erl +++ b/applications/webhooks/src/webhooks_shared_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/webhooks/src/webhooks_sup.erl b/applications/webhooks/src/webhooks_sup.erl index 090cefa3aa6..006a650f743 100644 --- a/applications/webhooks/src/webhooks_sup.erl +++ b/applications/webhooks/src/webhooks_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/applications/webhooks/src/webhooks_util.erl b/applications/webhooks/src/webhooks_util.erl index a35e36c0128..655187c1d3c 100644 --- a/applications/webhooks/src/webhooks_util.erl +++ b/applications/webhooks/src/webhooks_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/circle.yml b/circle.yml index 9a3a41dfd6b..f51824f9699 100644 --- a/circle.yml +++ b/circle.yml @@ -19,6 +19,8 @@ dependencies: pre: - bash ./scripts/circleci-build-erlang.sh: timeout: 1800 + - pip install --upgrade pip + - pip install PyYAML test: pre: @@ -29,11 +31,12 @@ test: if [[ ! -z "$($CHANGED)" ]]; then TO_FMT="$(echo $($CHANGED))" make fmt fi - - make bump-copyright + - if [[ "$CIRCLE_BRANCH" = 'master' ]]; then make bump-copyright; fi - . ~/.kerl/$OTP_VERSION/activate && make - . ~/.kerl/$OTP_VERSION/activate && make code_checks - ./scripts/validate-js.sh $($CHANGED) - . ~/.kerl/$OTP_VERSION/activate && make apis + - make docs - make validate-swagger - | if [[ 0 -ne `git status --porcelain | wc -l` ]]; then diff --git a/core/amqp_cron/test/amqp_cron_task_tests.erl b/core/amqp_cron/test/amqp_cron_task_tests.erl index ce713874840..ed31a47d706 100644 --- a/core/amqp_cron/test/amqp_cron_task_tests.erl +++ b/core/amqp_cron/test/amqp_cron_task_tests.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/amqp_cron/test/amqp_cron_tests.erl b/core/amqp_cron/test/amqp_cron_tests.erl index 464708affd8..9b9b59f2039 100644 --- a/core/amqp_cron/test/amqp_cron_tests.erl +++ b/core/amqp_cron/test/amqp_cron_tests.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/amqp_leader/src/amqp_leader.erl b/core/amqp_leader/src/amqp_leader.erl index 6331b509918..fd79f74e777 100644 --- a/core/amqp_leader/src/amqp_leader.erl +++ b/core/amqp_leader/src/amqp_leader.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/amqp_leader/src/amqp_leader_app.erl b/core/amqp_leader/src/amqp_leader_app.erl index 9b6e2c42ba7..d89d1292d45 100644 --- a/core/amqp_leader/src/amqp_leader_app.erl +++ b/core/amqp_leader/src/amqp_leader_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/amqp_leader/src/amqp_leader_listener.erl b/core/amqp_leader/src/amqp_leader_listener.erl index 51c6de7324f..2c12d6540d4 100644 --- a/core/amqp_leader/src/amqp_leader_listener.erl +++ b/core/amqp_leader/src/amqp_leader_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/amqp_leader/src/amqp_leader_proc.erl b/core/amqp_leader/src/amqp_leader_proc.erl index 30862d28cb0..4e4ef48b10c 100644 --- a/core/amqp_leader/src/amqp_leader_proc.erl +++ b/core/amqp_leader/src/amqp_leader_proc.erl @@ -5,20 +5,20 @@ %% API functions -export([start/6 - ,start_link/6 - ,leader_call/2, leader_call/3 - ,leader_cast/2 - ,call/2, call/3 - ,cast/2 - ,reply/2 + ,start_link/6 + ,leader_call/2, leader_call/3 + ,leader_cast/2 + ,call/2, call/3 + ,cast/2 + ,reply/2 ]). -export([alive/1 - ,down/1 - ,candidates/1 - ,workers/1 - ,broadcast/3 - ,leader_node/1 + ,down/1 + ,candidates/1 + ,workers/1 + ,broadcast/3 + ,leader_node/1 ]). -export([s/1]). @@ -47,8 +47,7 @@ ,node = node() :: atom() ,name :: atom() ,sync :: any() -% ,candidates :: atoms() - }). + }). -record(?MODULE, {from, msg}). diff --git a/core/amqp_leader/src/amqp_leader_proc_sup.erl b/core/amqp_leader/src/amqp_leader_proc_sup.erl index b31c3d5ed5b..c43aefbb00e 100644 --- a/core/amqp_leader/src/amqp_leader_proc_sup.erl +++ b/core/amqp_leader/src/amqp_leader_proc_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/amqp_leader/src/amqp_leader_sup.erl b/core/amqp_leader/src/amqp_leader_sup.erl index 81d3bc3c90b..08eb53730fe 100644 --- a/core/amqp_leader/src/amqp_leader_sup.erl +++ b/core/amqp_leader/src/amqp_leader_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/braintree/src/braintree_addon.erl b/core/braintree/src/braintree_addon.erl index 46d81db18e7..170bc8325ad 100644 --- a/core/braintree/src/braintree_addon.erl +++ b/core/braintree/src/braintree_addon.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @author Karl Anderson %%% @doc %%% diff --git a/core/braintree/src/braintree_address.erl b/core/braintree/src/braintree_address.erl index a4fcfc2c70e..a0fcd4c146b 100644 --- a/core/braintree/src/braintree_address.erl +++ b/core/braintree/src/braintree_address.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/braintree/src/braintree_card.erl b/core/braintree/src/braintree_card.erl index 05bea1f3286..f2a17e38260 100644 --- a/core/braintree/src/braintree_card.erl +++ b/core/braintree/src/braintree_card.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/braintree/src/braintree_client_token.erl b/core/braintree/src/braintree_client_token.erl index 395f18a8cc3..d413133ebd7 100644 --- a/core/braintree/src/braintree_client_token.erl +++ b/core/braintree/src/braintree_client_token.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/braintree/src/braintree_customer.erl b/core/braintree/src/braintree_customer.erl index c9e9847a160..d2243d71efc 100644 --- a/core/braintree/src/braintree_customer.erl +++ b/core/braintree/src/braintree_customer.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/braintree/src/braintree_discount.erl b/core/braintree/src/braintree_discount.erl index 060f3acc960..b85c135a3a4 100644 --- a/core/braintree/src/braintree_discount.erl +++ b/core/braintree/src/braintree_discount.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @author Karl Anderson %%% @doc %%% diff --git a/core/braintree/src/braintree_request.erl b/core/braintree/src/braintree_request.erl index b13461d15ec..869bb3332f2 100644 --- a/core/braintree/src/braintree_request.erl +++ b/core/braintree/src/braintree_request.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/braintree/src/braintree_subscription.erl b/core/braintree/src/braintree_subscription.erl index 6f71b25b402..7ebc2160ab4 100644 --- a/core/braintree/src/braintree_subscription.erl +++ b/core/braintree/src/braintree_subscription.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/braintree/src/braintree_transaction.erl b/core/braintree/src/braintree_transaction.erl index 20c37dd39eb..287e071475b 100644 --- a/core/braintree/src/braintree_transaction.erl +++ b/core/braintree/src/braintree_transaction.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/braintree/src/braintree_util.erl b/core/braintree/src/braintree_util.erl index 7d2b5437a66..1d57357d0c4 100644 --- a/core/braintree/src/braintree_util.erl +++ b/core/braintree/src/braintree_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo/src/kazoo_maintenance.erl b/core/kazoo/src/kazoo_maintenance.erl index d2221ec8c7d..66ca2cc8edf 100644 --- a/core/kazoo/src/kazoo_maintenance.erl +++ b/core/kazoo/src/kazoo_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo/src/kz_doc.erl b/core/kazoo/src/kz_doc.erl index 5853b0cf0e1..7a82e12e0f8 100644 --- a/core/kazoo/src/kz_doc.erl +++ b/core/kazoo/src/kz_doc.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Utilities for manipulating Kazoo/Kazoo documents %%% @end diff --git a/core/kazoo/src/kz_network_utils.erl b/core/kazoo/src/kz_network_utils.erl index f27a59a65f7..27904ad0bf1 100644 --- a/core/kazoo/src/kz_network_utils.erl +++ b/core/kazoo/src/kz_network_utils.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Various utilities - a veritable cornicopia %%% @end @@ -17,7 +17,6 @@ -export([to_cidr/1 ,to_cidr/2 ,verify_cidr/2 -%% ,expand_cidr/1 ]). -export([find_nameservers/1 ,find_nameservers/2 diff --git a/core/kazoo/src/kz_perf_transform.erl b/core/kazoo/src/kz_perf_transform.erl index 352aaf6fe7f..b3bfabe2525 100644 --- a/core/kazoo/src/kz_perf_transform.erl +++ b/core/kazoo/src/kz_perf_transform.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo/src/kz_util.erl b/core/kazoo/src/kz_util.erl index 3e1b0756d9c..b4eab7fb346 100644 --- a/core/kazoo/src/kz_util.erl +++ b/core/kazoo/src/kz_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Various utilities - a veritable cornicopia %%% @end @@ -131,6 +131,7 @@ ]). -export([write_file/2, write_file/3 + ,rename_file/2 ,delete_file/1 ,make_dir/1 ]). @@ -174,12 +175,19 @@ log_stacktrace(ST) -> ], 'ok'. +-ifdef(TEST). +log_stacktrace_mfa(M, F, Arity, Info) when is_integer(Arity) -> + io:format(user, "st: ~s:~s/~b at (~b)\n", [M, F, Arity, props:get_value('line', Info, 0)]); +log_stacktrace_mfa(M, F, Args, Info) -> + io:format(user, "st: ~s:~s at ~p\n", [M, F, props:get_value('line', Info, 0)]), + lists:foreach(fun (Arg) -> io:format(user, "args: ~p\n", [Arg]) end, Args). +-else. log_stacktrace_mfa(M, F, Arity, Info) when is_integer(Arity) -> lager:error("st: ~s:~s/~b at (~b)", [M, F, Arity, props:get_value('line', Info, 0)]); log_stacktrace_mfa(M, F, Args, Info) -> lager:error("st: ~s:~s at ~p", [M, F, props:get_value('line', Info, 0)]), - _ = [lager:error("args: ~p", [Arg]) || Arg <- Args], - 'ok'. + lists:foreach(fun (Arg) -> lager:error("args: ~p", [Arg]) end, Args). +-endif. -define(LOG_LEVELS, ['emergency' ,'alert' @@ -1634,6 +1642,14 @@ write_file(Filename, Bytes, Modes) -> lager:error("writing file ~s (~p) failed : ~p", [Filename, Modes, _E]) end. +-spec rename_file(file:filename_all(), file:filename_all()) -> 'ok'. +rename_file(FromFilename, ToFilename) -> + case file:rename(FromFilename, ToFilename) of + 'ok' -> 'ok'; + {'error', _}=_E -> + lager:error("moving file ~s into ~s failed : ~p", [FromFilename, ToFilename, _E]) + end. + %% @public -spec delete_file(file:filename_all()) -> 'ok'. delete_file(Filename) -> diff --git a/core/kazoo/src/props.erl b/core/kazoo/src/props.erl index d5a6564c72a..aa88e749d2a 100644 --- a/core/kazoo/src/props.erl +++ b/core/kazoo/src/props.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Mostly a drop-in replacement and extension of the proplists module, %%% but using the lists module to implement diff --git a/core/kazoo/test/kz_util_test.erl b/core/kazoo/test/kz_util_test.erl index a1470de2796..5ca324cec5d 100644 --- a/core/kazoo/test/kz_util_test.erl +++ b/core/kazoo/test/kz_util_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Various utilities - a veritable cornicopia %%% @end diff --git a/core/kazoo/test/props_test.erl b/core/kazoo/test/props_test.erl index 499f3b91c94..e1b92c5ec65 100644 --- a/core/kazoo/test/props_test.erl +++ b/core/kazoo/test/props_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Mostly a drop-in replacement and extension of the proplists module, %%% but using the lists module to implement diff --git a/core/kazoo_amqp/include/kz_amqp.hrl b/core/kazoo_amqp/include/kz_amqp.hrl index 6586df7336f..23c14b07703 100644 --- a/core/kazoo_amqp/include/kz_amqp.hrl +++ b/core/kazoo_amqp/include/kz_amqp.hrl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% AMQP-specific things for Kazoo %%% @end diff --git a/core/kazoo_amqp/src/amqp_util.erl b/core/kazoo_amqp/src/amqp_util.erl index 5dcbf5b4ed7..36d628a8c25 100644 --- a/core/kazoo_amqp/src/amqp_util.erl +++ b/core/kazoo_amqp/src/amqp_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Utilities to facilitate AMQP interaction %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_asr.erl b/core/kazoo_amqp/src/api/kapi_asr.erl index 74689894687..d10c22a5174 100644 --- a/core/kazoo_amqp/src/api/kapi_asr.erl +++ b/core/kazoo_amqp/src/api/kapi_asr.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% ASR requests, responses, and errors %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_authn.erl b/core/kazoo_amqp/src/api/kapi_authn.erl index 57d0af6c555..e163ff5aa79 100644 --- a/core/kazoo_amqp/src/api/kapi_authn.erl +++ b/core/kazoo_amqp/src/api/kapi_authn.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Handles authentication requests, responses, queue bindings %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_authz.erl b/core/kazoo_amqp/src/api/kapi_authz.erl index 10f7a9075b8..78688ee9abc 100644 --- a/core/kazoo_amqp/src/api/kapi_authz.erl +++ b/core/kazoo_amqp/src/api/kapi_authz.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Handles authorization requests, responses, queue bindings %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_blackhole.erl b/core/kazoo_amqp/src/api/kapi_blackhole.erl index c5cb725d096..cdfb5eaca9a 100644 --- a/core/kazoo_amqp/src/api/kapi_blackhole.erl +++ b/core/kazoo_amqp/src/api/kapi_blackhole.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% @end %%% @contributors diff --git a/core/kazoo_amqp/src/api/kapi_call.erl b/core/kazoo_amqp/src/api/kapi_call.erl index a396d175ce2..021b8bfbd4a 100644 --- a/core/kazoo_amqp/src/api/kapi_call.erl +++ b/core/kazoo_amqp/src/api/kapi_call.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Call-related messages, like switch events, status requests, etc %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_callflow.erl b/core/kazoo_amqp/src/api/kapi_callflow.erl index c1cb7bb6ce6..37ab73cfb3e 100644 --- a/core/kazoo_amqp/src/api/kapi_callflow.erl +++ b/core/kazoo_amqp/src/api/kapi_callflow.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_conf.erl b/core/kazoo_amqp/src/api/kapi_conf.erl index bfd043932d5..9cf2ec6149e 100644 --- a/core/kazoo_amqp/src/api/kapi_conf.erl +++ b/core/kazoo_amqp/src/api/kapi_conf.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Configuration updates (like DB doc changes) can be communicated across %%% the AMQP bus so WhApps can flush cache entries, update settings, etc. diff --git a/core/kazoo_amqp/src/api/kapi_conference.erl b/core/kazoo_amqp/src/api/kapi_conference.erl index 86d1cbfd3c7..6b6101c2b74 100644 --- a/core/kazoo_amqp/src/api/kapi_conference.erl +++ b/core/kazoo_amqp/src/api/kapi_conference.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_delegate.erl b/core/kazoo_amqp/src/api/kapi_delegate.erl index 1c3edcc1816..4e3ab39f57f 100644 --- a/core/kazoo_amqp/src/api/kapi_delegate.erl +++ b/core/kazoo_amqp/src/api/kapi_delegate.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% Delegate job from one app to another app. diff --git a/core/kazoo_amqp/src/api/kapi_dialplan.erl b/core/kazoo_amqp/src/api/kapi_dialplan.erl index 8ee5e48ee3c..776e66bf395 100644 --- a/core/kazoo_amqp/src/api/kapi_dialplan.erl +++ b/core/kazoo_amqp/src/api/kapi_dialplan.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Dialplan API commands %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_fax.erl b/core/kazoo_amqp/src/api/kapi_fax.erl index 9e924befc51..9bc1a333370 100644 --- a/core/kazoo_amqp/src/api/kapi_fax.erl +++ b/core/kazoo_amqp/src/api/kapi_fax.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -8,7 +8,11 @@ %%%------------------------------------------------------------------- -module(kapi_fax). --export([account_id/1, job_id/1, to_number/1, state/1]). +-export([account_id/1 + ,job_id/1 + ,to_number/1 + ,state/1 + ]). -export([req/1, req_v/1 ,query_status/1, query_status_v/1 diff --git a/core/kazoo_amqp/src/api/kapi_fs.erl b/core/kazoo_amqp/src/api/kapi_fs.erl index ad67a2ea85b..cb902475600 100644 --- a/core/kazoo_amqp/src/api/kapi_fs.erl +++ b/core/kazoo_amqp/src/api/kapi_fs.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016 2600Hz +%%% @copyright (C) 2017 2600Hz %%% @doc %%% FS passthrough API %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_globals.erl b/core/kazoo_amqp/src/api/kapi_globals.erl index 5dba9b85a27..2dd050b9d4f 100644 --- a/core/kazoo_amqp/src/api/kapi_globals.erl +++ b/core/kazoo_amqp/src/api/kapi_globals.erl @@ -1,5 +1,5 @@ %%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Globals API %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_hangups.erl b/core/kazoo_amqp/src/api/kapi_hangups.erl index a7025e82feb..473260ae62c 100644 --- a/core/kazoo_amqp/src/api/kapi_hangups.erl +++ b/core/kazoo_amqp/src/api/kapi_hangups.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% @end %%% @contributors diff --git a/core/kazoo_amqp/src/api/kapi_leader.erl b/core/kazoo_amqp/src/api/kapi_leader.erl index e460f20f1bb..1b3e8eda5b9 100644 --- a/core/kazoo_amqp/src/api/kapi_leader.erl +++ b/core/kazoo_amqp/src/api/kapi_leader.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016 2600Hz +%%% @copyright (C) 2017 2600Hz %%% @doc %%% FS passthrough API %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_media.erl b/core/kazoo_amqp/src/api/kapi_media.erl index 0027732d2d2..3639808b6ac 100644 --- a/core/kazoo_amqp/src/api/kapi_media.erl +++ b/core/kazoo_amqp/src/api/kapi_media.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Media requests, responses, and errors %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_metaflow.erl b/core/kazoo_amqp/src/api/kapi_metaflow.erl index 55abbbf89f3..e16b09cbba8 100644 --- a/core/kazoo_amqp/src/api/kapi_metaflow.erl +++ b/core/kazoo_amqp/src/api/kapi_metaflow.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Metaflow requests, responses, and errors %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_money.erl b/core/kazoo_amqp/src/api/kapi_money.erl index 3408888c2ec..435d3778c05 100644 --- a/core/kazoo_amqp/src/api/kapi_money.erl +++ b/core/kazoo_amqp/src/api/kapi_money.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% APIs for events concerning money (like credits, debits, and others) %%% diff --git a/core/kazoo_amqp/src/api/kapi_nodes.erl b/core/kazoo_amqp/src/api/kapi_nodes.erl index 30e0cb0e0d0..988c096fdbf 100644 --- a/core/kazoo_amqp/src/api/kapi_nodes.erl +++ b/core/kazoo_amqp/src/api/kapi_nodes.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_notifications.erl b/core/kazoo_amqp/src/api/kapi_notifications.erl index 42e2d55a33f..78893027901 100644 --- a/core/kazoo_amqp/src/api/kapi_notifications.erl +++ b/core/kazoo_amqp/src/api/kapi_notifications.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Notification messages, like voicemail left %%% @end @@ -47,6 +47,7 @@ ,customer_update/1, customer_update_v/1 ,skel/1, skel_v/1 ,headers/1 + ,account_db/1 ]). -export([publish_voicemail/1, publish_voicemail/2 @@ -522,6 +523,16 @@ ]). -define(SKEL_TYPES, []). +-spec account_db(kz_json:object()) -> api_binary(). +account_db(JObj) -> + Check = [<<"account_db">>, <<"pvt_account_db">>, <<"Account-DB">>], + case kz_json:get_first_defined(Check, JObj) of + 'undefined' -> + kz_util:format_account_id(kz_json:get_ne_binary_value(<<"Account-ID">>, JObj), 'encoded'); + Value -> + Value + end. + -spec headers(ne_binary()) -> ne_binaries(). headers(<<"voicemail">>) -> ?VOICEMAIL_HEADERS ++ ?OPTIONAL_VOICEMAIL_HEADERS; diff --git a/core/kazoo_amqp/src/api/kapi_offnet_resource.erl b/core/kazoo_amqp/src/api/kapi_offnet_resource.erl index 77466924e80..a09999215eb 100644 --- a/core/kazoo_amqp/src/api/kapi_offnet_resource.erl +++ b/core/kazoo_amqp/src/api/kapi_offnet_resource.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_presence.erl b/core/kazoo_amqp/src/api/kapi_presence.erl index a453bc41cf8..c156997e9d1 100644 --- a/core/kazoo_amqp/src/api/kapi_presence.erl +++ b/core/kazoo_amqp/src/api/kapi_presence.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_rate.erl b/core/kazoo_amqp/src/api/kapi_rate.erl index ee29559e341..71fcebc9529 100644 --- a/core/kazoo_amqp/src/api/kapi_rate.erl +++ b/core/kazoo_amqp/src/api/kapi_rate.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Handles authorization requests, responses, queue bindings %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_registration.erl b/core/kazoo_amqp/src/api/kapi_registration.erl index d9ee10173a3..642fb0391d2 100644 --- a/core/kazoo_amqp/src/api/kapi_registration.erl +++ b/core/kazoo_amqp/src/api/kapi_registration.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Handle registration-related APIs, like reg_success and reg_lookup. %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_resource.erl b/core/kazoo_amqp/src/api/kapi_resource.erl index 22b777c71a6..811693f2bc0 100644 --- a/core/kazoo_amqp/src/api/kapi_resource.erl +++ b/core/kazoo_amqp/src/api/kapi_resource.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_route.erl b/core/kazoo_amqp/src/api/kapi_route.erl index d7a31aba078..bd794ec8ef8 100644 --- a/core/kazoo_amqp/src/api/kapi_route.erl +++ b/core/kazoo_amqp/src/api/kapi_route.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Routing requests, responses, and wins! %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_self.erl b/core/kazoo_amqp/src/api/kapi_self.erl index 48a6a9e6376..9cdac57a266 100644 --- a/core/kazoo_amqp/src/api/kapi_self.erl +++ b/core/kazoo_amqp/src/api/kapi_self.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% For gen_listeners that bind to targeted for direct messaging %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_switch.erl b/core/kazoo_amqp/src/api/kapi_switch.erl index 799b1612a8a..06d9bfd402a 100644 --- a/core/kazoo_amqp/src/api/kapi_switch.erl +++ b/core/kazoo_amqp/src/api/kapi_switch.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Switch events messages %%% @end diff --git a/core/kazoo_amqp/src/api/kapi_sysconf.erl b/core/kazoo_amqp/src/api/kapi_sysconf.erl index a08cc622250..55b60a4a085 100644 --- a/core/kazoo_amqp/src/api/kapi_sysconf.erl +++ b/core/kazoo_amqp/src/api/kapi_sysconf.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Expose system configuration data. %%% System configuration data is stored as key/values in a namespace diff --git a/core/kazoo_amqp/src/api/kapi_tasks.erl b/core/kazoo_amqp/src/api/kapi_tasks.erl index 95ae749c0c6..42cc1992307 100644 --- a/core/kazoo_amqp/src/api/kapi_tasks.erl +++ b/core/kazoo_amqp/src/api/kapi_tasks.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/gen_listener.erl b/core/kazoo_amqp/src/gen_listener.erl index 8cde5a1b61f..33492523edb 100644 --- a/core/kazoo_amqp/src/gen_listener.erl +++ b/core/kazoo_amqp/src/gen_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% Behaviour for setting up an AMQP listener. diff --git a/core/kazoo_amqp/src/kazoo_amqp_maintenance.erl b/core/kazoo_amqp/src/kazoo_amqp_maintenance.erl index 5732908e891..a9fc87adeb8 100644 --- a/core/kazoo_amqp/src/kazoo_amqp_maintenance.erl +++ b/core/kazoo_amqp/src/kazoo_amqp_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/kz_amqp_assignments.erl b/core/kazoo_amqp/src/kz_amqp_assignments.erl index ee6909e4eac..4aebd0f2e9a 100644 --- a/core/kazoo_amqp/src/kz_amqp_assignments.erl +++ b/core/kazoo_amqp/src/kz_amqp_assignments.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/kz_amqp_bootstrap.erl b/core/kazoo_amqp/src/kz_amqp_bootstrap.erl index 72cb1b2212e..5eeeaaface4 100644 --- a/core/kazoo_amqp/src/kz_amqp_bootstrap.erl +++ b/core/kazoo_amqp/src/kz_amqp_bootstrap.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Karls Hackity Hack.... %%% We want to block during startup until we have a AMQP connection diff --git a/core/kazoo_amqp/src/kz_amqp_channel.erl b/core/kazoo_amqp/src/kz_amqp_channel.erl index 844cd442a43..27d834c5657 100644 --- a/core/kazoo_amqp/src/kz_amqp_channel.erl +++ b/core/kazoo_amqp/src/kz_amqp_channel.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/kz_amqp_connection.erl b/core/kazoo_amqp/src/kz_amqp_connection.erl index 10d97fb5b4b..a4b7f3d1731 100644 --- a/core/kazoo_amqp/src/kz_amqp_connection.erl +++ b/core/kazoo_amqp/src/kz_amqp_connection.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Handle a host's connection/channels %%% @end diff --git a/core/kazoo_amqp/src/kz_amqp_connection_sup.erl b/core/kazoo_amqp/src/kz_amqp_connection_sup.erl index eeea685cd64..e84042a3a6c 100644 --- a/core/kazoo_amqp/src/kz_amqp_connection_sup.erl +++ b/core/kazoo_amqp/src/kz_amqp_connection_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/kz_amqp_connections.erl b/core/kazoo_amqp/src/kz_amqp_connections.erl index 21d4338ecdf..9a840525ba8 100644 --- a/core/kazoo_amqp/src/kz_amqp_connections.erl +++ b/core/kazoo_amqp/src/kz_amqp_connections.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/kz_amqp_history.erl b/core/kazoo_amqp/src/kz_amqp_history.erl index 3d1e6c6208f..22f561fa728 100644 --- a/core/kazoo_amqp/src/kz_amqp_history.erl +++ b/core/kazoo_amqp/src/kz_amqp_history.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/kz_amqp_sup.erl b/core/kazoo_amqp/src/kz_amqp_sup.erl index bef9181aaac..72acd7a9cbf 100644 --- a/core/kazoo_amqp/src/kz_amqp_sup.erl +++ b/core/kazoo_amqp/src/kz_amqp_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/kz_amqp_worker.erl b/core/kazoo_amqp/src/kz_amqp_worker.erl index bfee5f40289..7ffcd41e4c9 100644 --- a/core/kazoo_amqp/src/kz_amqp_worker.erl +++ b/core/kazoo_amqp/src/kz_amqp_worker.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Worker with a dedicated targeted queue. %%% diff --git a/core/kazoo_amqp/src/kz_notify.erl b/core/kazoo_amqp/src/kz_notify.erl index c04ee2f4634..dbb59953ec0 100644 --- a/core/kazoo_amqp/src/kz_notify.erl +++ b/core/kazoo_amqp/src/kz_notify.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/listener_federator.erl b/core/kazoo_amqp/src/listener_federator.erl index ef84b17e295..e2cdc9cf7e6 100644 --- a/core/kazoo_amqp/src/listener_federator.erl +++ b/core/kazoo_amqp/src/listener_federator.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_amqp/src/listener_utils.erl b/core/kazoo_amqp/src/listener_utils.erl index 1c4075f57c7..aa118db7855 100644 --- a/core/kazoo_amqp/src/listener_utils.erl +++ b/core/kazoo_amqp/src/listener_utils.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Utility functions for AMQP listeners to use to add/remove responders %%% @end diff --git a/core/kazoo_amqp/test/amqp_util_test.erl b/core/kazoo_amqp/test/amqp_util_test.erl index 0e0c6df8e52..751c5bd2ee8 100644 --- a/core/kazoo_amqp/test/amqp_util_test.erl +++ b/core/kazoo_amqp/test/amqp_util_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Utilities to facilitate AMQP interaction %%% @end diff --git a/core/kazoo_apps/src/kapps_alert.erl b/core/kazoo_apps/src/kapps_alert.erl index 362193ab76f..67ff005ade4 100644 --- a/core/kazoo_apps/src/kapps_alert.erl +++ b/core/kazoo_apps/src/kapps_alert.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz inc +%%% @copyright (C) 2015-2017, 2600Hz inc %%% @doc %%% @end %%% @contributors diff --git a/core/kazoo_apps/src/kapps_controller.erl b/core/kazoo_apps/src/kapps_controller.erl index d051db43858..66cfc58bb28 100644 --- a/core/kazoo_apps/src/kapps_controller.erl +++ b/core/kazoo_apps/src/kapps_controller.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end @@ -120,7 +120,7 @@ initialize_kapps() -> Started = [KApp || KApp <- lists:sort(fun sysconf_first/2, ToStart), {'ok',_} <- [start_app(KApp)] ], - lager:notice("auto-started kapps ~p", [Started]). + lager:notice("auto-started kapps ~p", [lists:sort(Started)]). -spec start_which_kapps() -> [ne_binary() | atom() | nonempty_string()]. start_which_kapps() -> diff --git a/core/kazoo_apps/src/kapps_maintenance.erl b/core/kazoo_apps/src/kapps_maintenance.erl index e97741547a0..68ba4bdf3c5 100644 --- a/core/kazoo_apps/src/kapps_maintenance.erl +++ b/core/kazoo_apps/src/kapps_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -186,7 +186,7 @@ refresh([Database|Databases], Pause, Total) -> -spec get_databases() -> ne_binaries(). get_databases() -> {'ok', Databases} = kz_datamgr:db_info(), - lists:sort(fun get_database_sort/2, Databases). + lists:sort(fun get_database_sort/2, lists:usort(Databases ++ ?KZ_SYSTEM_DBS)). -spec get_database_sort(ne_binary(), ne_binary()) -> boolean(). get_database_sort(Db1, Db2) -> @@ -387,8 +387,8 @@ refresh_account_db(Database) -> AccountId = kz_util:format_account_id(Database, 'raw'), _ = remove_depreciated_account_views(AccountDb), _ = ensure_account_definition(AccountDb, AccountId), - Views = get_all_account_views(), - _ = kapps_util:update_views(AccountDb, Views, 'true'), + _ = kapps_util:update_views(AccountDb, get_all_account_views(), 'true'), + _ = kazoo_number_manager_maintenance:update_number_services_view(AccountDb), kapps_account_config:migrate(AccountDb), _ = kazoo_bindings:map(binding({'refresh_account', AccountDb}), AccountId), 'ok'. diff --git a/core/kazoo_apps/src/kapps_speech.erl b/core/kazoo_apps/src/kapps_speech.erl index 1e534b664ad..d6976cf74da 100644 --- a/core/kazoo_apps/src/kapps_speech.erl +++ b/core/kazoo_apps/src/kapps_speech.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% For TTS (Text To Speech), use the create/* methods %%% To do ASR (Automatic Speech Recognition), there are two options: @@ -367,8 +367,8 @@ create_response(<<"voicefabric">> = _Engine, {'ok', 200, Headers, Content}) -> {'ok', WavContent} -> kz_util:delete_file(WavFile), lager:debug("media converted"), - NewHeaders = props:set_values([{"Content-Type", "audio/wav"} - ,{"Content-Length", integer_to_list(byte_size(WavContent))} + NewHeaders = props:set_values([{"content-type", "audio/wav"} + ,{"content-length", integer_to_list(byte_size(WavContent))} ] ,Headers ), diff --git a/core/kazoo_apps/src/kapps_sup.erl b/core/kazoo_apps/src/kapps_sup.erl index deb49171ad5..b5717861a5a 100644 --- a/core/kazoo_apps/src/kapps_sup.erl +++ b/core/kazoo_apps/src/kapps_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_apps/src/kapps_util.erl b/core/kazoo_apps/src/kapps_util.erl index ad94e9e9a61..930ff2381f2 100644 --- a/core/kazoo_apps/src/kapps_util.erl +++ b/core/kazoo_apps/src/kapps_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Utilities shared by a subset of kapps %%% @end diff --git a/core/kazoo_apps/src/kazoo_apps_app.erl b/core/kazoo_apps/src/kazoo_apps_app.erl index ec4376ab1b0..5e16ee011db 100644 --- a/core/kazoo_apps/src/kazoo_apps_app.erl +++ b/core/kazoo_apps/src/kazoo_apps_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_apps/src/kazoo_apps_init.erl b/core/kazoo_apps/src/kazoo_apps_init.erl index ac6f029a7cd..7b0b41f3251 100644 --- a/core/kazoo_apps/src/kazoo_apps_init.erl +++ b/core/kazoo_apps/src/kazoo_apps_init.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Init to be done %%% @end diff --git a/core/kazoo_apps/src/kazoo_apps_sup.erl b/core/kazoo_apps/src/kazoo_apps_sup.erl index a3080271e49..743bf76da14 100644 --- a/core/kazoo_apps/src/kazoo_apps_sup.erl +++ b/core/kazoo_apps/src/kazoo_apps_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_apps/src/kz_hooks.erl b/core/kazoo_apps/src/kz_hooks.erl index f44d996be09..85472cba78f 100644 --- a/core/kazoo_apps/src/kz_hooks.erl +++ b/core/kazoo_apps/src/kz_hooks.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% @end %%% @contributors diff --git a/core/kazoo_apps/src/kz_hooks_listener.erl b/core/kazoo_apps/src/kz_hooks_listener.erl index c2d14b700f6..595f70bcd1e 100644 --- a/core/kazoo_apps/src/kz_hooks_listener.erl +++ b/core/kazoo_apps/src/kz_hooks_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Listens for a list of events and gproc-sends them out to folks who %%% want them diff --git a/core/kazoo_apps/src/kz_hooks_listener_sup.erl b/core/kazoo_apps/src/kz_hooks_listener_sup.erl index 179c89d40a2..5776b0b35ed 100644 --- a/core/kazoo_apps/src/kz_hooks_listener_sup.erl +++ b/core/kazoo_apps/src/kz_hooks_listener_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_apps/src/kz_hooks_shared_listener.erl b/core/kazoo_apps/src/kz_hooks_shared_listener.erl index b705a379798..755a862d6c0 100644 --- a/core/kazoo_apps/src/kz_hooks_shared_listener.erl +++ b/core/kazoo_apps/src/kz_hooks_shared_listener.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Listens for a list of events and gproc-sends them out to folks who %%% want them diff --git a/core/kazoo_apps/src/kz_hooks_util.erl b/core/kazoo_apps/src/kz_hooks_util.erl index 08ca4972052..3b12152563b 100644 --- a/core/kazoo_apps/src/kz_hooks_util.erl +++ b/core/kazoo_apps/src/kz_hooks_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% @end %%% @contributors diff --git a/core/kazoo_ast/src/cb_api_endpoints.erl b/core/kazoo_ast/src/cb_api_endpoints.erl index 806194a9cf7..6cc2c35faac 100644 --- a/core/kazoo_ast/src/cb_api_endpoints.erl +++ b/core/kazoo_ast/src/cb_api_endpoints.erl @@ -9,6 +9,11 @@ ,schema_to_table/1 ]). +-ifdef(TEST). +-export([sort_methods/1]). + +-endif. + -include_lib("kazoo_ast/include/kz_ast.hrl"). -include_lib("crossbar/src/crossbar.hrl"). @@ -74,9 +79,26 @@ methods_to_section(ModuleName, {Path, Methods}, Acc) -> method_to_section(Method, Acc1, APIPath) end ,Acc - ,Methods + ,sort_methods(Methods) ). +-spec sort_methods(ne_binaries()) -> ne_binaries(). +sort_methods(Methods) -> + Ordering = [?HTTP_GET, ?HTTP_PUT, ?HTTP_POST, ?HTTP_PATCH, ?HTTP_DELETE], + sort_methods(Methods, Ordering, []). + +sort_methods([], _Ordering, Acc) -> lists:reverse(Acc); +sort_methods(Methods, [], Acc) -> lists:reverse(Methods ++ Acc); +sort_methods(Methods, [Method | Ordering], Acc) -> + case lists:member(Method, Methods) of + 'false' -> sort_methods(Methods, Ordering, Acc); + 'true' -> + sort_methods(lists:delete(Method, Methods) + ,Ordering + ,[Method | Acc] + ) + end. + method_to_section(Method, Acc, APIPath) -> [[ "#### ", method_as_action(Method), "\n\n" ,"> ", Method, " ", APIPath, "\n\n" @@ -105,7 +127,7 @@ maybe_add_schema(BaseName) -> 'undefined' -> [?SCHEMA_SECTION, "\n\n"]; SchemaJObj -> [Table | RefTables] = schema_to_table(SchemaJObj), - [?SCHEMA_SECTION, Table, "\n\n", ref_tables_to_doc(RefTables)] + [?SCHEMA_SECTION, Table, "\n\n", ref_tables_to_doc(RefTables), "\n\n"] end. %% This looks for "#### Schema" in the doc file and adds the JSON schema formatted as the markdown table @@ -172,6 +194,7 @@ schema_to_table(SchemaJObj) -> schema_to_table(SchemaJObj, []). schema_to_table(SchemaJObj, BaseRefs) -> + Description = kz_json:get_binary_value(<<"description">>, SchemaJObj, <<>>), Properties = kz_json:get_value(<<"properties">>, SchemaJObj, kz_json:new()), F = fun (K, V, Acc) -> property_to_row(SchemaJObj, K, V, Acc) end, {Reversed, RefSchemas} = kz_json:foldl(F, {[?TABLE_HEADER], BaseRefs}, Properties), @@ -183,7 +206,7 @@ schema_to_table(SchemaJObj, BaseRefs) -> WithSubRefs = include_sub_refs(OneOfRefs), - [[lists:reverse(Reversed)] + [[schema_description(Description), lists:reverse(Reversed)] |[{RefSchemaName, RefTable} || RefSchemaName <- WithSubRefs, BaseRefs =:= [], @@ -192,6 +215,10 @@ schema_to_table(SchemaJObj, BaseRefs) -> ] ]. +-spec schema_description(binary()) -> iodata(). +schema_description(<<>>) -> <<>>; +schema_description(Description) -> [Description, "\n\n"]. + include_sub_refs(Refs) -> lists:usort(lists:foldl(fun include_sub_ref/2, [], Refs)). diff --git a/core/kazoo_ast/test/cb_api_endpoint_tests.erl b/core/kazoo_ast/test/cb_api_endpoint_tests.erl new file mode 100644 index 00000000000..6b3e1ffe9a8 --- /dev/null +++ b/core/kazoo_ast/test/cb_api_endpoint_tests.erl @@ -0,0 +1,25 @@ +-module(cb_api_endpoint_tests). + +-include_lib("eunit/include/eunit.hrl"). +-include_lib("crossbar/src/crossbar.hrl"). + +sort_methods_test_() -> + Tests = + [{[?HTTP_GET, ?HTTP_DELETE], [?HTTP_GET, ?HTTP_DELETE]} + ,{[?HTTP_GET, ?HTTP_PUT], [?HTTP_GET, ?HTTP_PUT]} + ,{[?HTTP_GET, ?HTTP_PUT, ?HTTP_POST, ?HTTP_PATCH, ?HTTP_DELETE], [?HTTP_GET, ?HTTP_PUT, ?HTTP_POST, ?HTTP_PATCH, ?HTTP_DELETE]} + ], + lists:foldl(fun create_test_generator/2, [], Tests). + +create_test_generator({Input, Output}, Tests) -> + lists:foldl(fun(Perm, Acc) -> add_generator(Perm, Output, Acc) end + ,Tests + ,perms(Input) + ). + +add_generator(Input, Output, Tests) -> + [?_assertEqual(Output, cb_api_endpoints:sort_methods(Input)) | Tests]. + +%% from http://erlang.org/doc/programming_examples/list_comprehensions.html +perms([]) -> [[]]; +perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])]. diff --git a/core/kazoo_attachments/src/aws/kz_aws.erl b/core/kazoo_attachments/src/aws/kz_aws.erl index 91a607e6020..7ef9691f4b1 100644 --- a/core/kazoo_attachments/src/aws/kz_aws.erl +++ b/core/kazoo_attachments/src/aws/kz_aws.erl @@ -378,21 +378,24 @@ timeout(#aws_config{timeout = 'undefined'}) -> ?DEFAULT_TIMEOUT; timeout(#aws_config{timeout = Timeout}) -> Timeout. %% Convert an aws_request record to return value as returned by http_headers_body --spec request_to_return(#aws_request{}) -> {'ok', {headers(), binary()}} | - {'error', any()}. +-spec request_to_return(aws_request()) -> {'ok', {headers(), binary()}} | + {'error', any()}. request_to_return(#aws_request{response_type = 'ok' ,response_headers = Headers - ,response_body = Body}) -> + ,response_body = Body + }) -> {'ok', {[{string:to_lower(H), V} || {H, V} <- Headers], Body}}; request_to_return(#aws_request{response_type = 'error' ,error_type = httpc - ,httpc_error_reason = Reason}) -> + ,httpc_error_reason = Reason + }) -> {'error', {'socket_error', Reason}}; request_to_return(#aws_request{response_type = 'error' ,error_type = 'aws' ,response_status = Status ,response_status_line = StatusLine - ,response_body = Body}) -> + ,response_body = Body + }) -> {'error', {'http_error', Status, StatusLine, Body}}. %% http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html diff --git a/core/kazoo_attachments/src/aws/kz_aws.hrl b/core/kazoo_attachments/src/aws/kz_aws.hrl index 99decff0f24..2900104268e 100644 --- a/core/kazoo_attachments/src/aws/kz_aws.hrl +++ b/core/kazoo_attachments/src/aws/kz_aws.hrl @@ -83,6 +83,7 @@ %% Service specific error information should_retry :: boolean() }). +-type aws_request() :: #aws_request{}. -define(KZ_ATT_AWS_HRL, 'true'). -endif. diff --git a/core/kazoo_attachments/src/aws/kz_aws_http.erl b/core/kazoo_attachments/src/aws/kz_aws_http.erl index 6559a6df89d..75f5c431f0a 100644 --- a/core/kazoo_attachments/src/aws/kz_aws_http.erl +++ b/core/kazoo_attachments/src/aws/kz_aws_http.erl @@ -20,11 +20,11 @@ encode_query_term(Key, Value, _) -> %% sign url differently, S3 requires that empty arguments have no %% '=' (/?acl) while SQS requires it (/?QueuePrefix=) %% default behaviour is adding '=' --spec make_query_string([{nonempty_string(), any()}]) -> nonempty_string(). +-spec make_query_string([{nonempty_string(), any()}]) -> string(). make_query_string(Params) -> make_query_string(Params, 'empty_assignment'). --spec make_query_string([{nonempty_string(), any()}], atom()) -> nonempty_string(). +-spec make_query_string([{nonempty_string(), any()}], atom()) -> string(). make_query_string(Params, EmptyQueryOpt) -> string:join([encode_query_term(Key, Value, EmptyQueryOpt) || {Key, Value} <- Params, diff --git a/core/kazoo_attachments/src/aws/kz_aws_httpc.erl b/core/kazoo_attachments/src/aws/kz_aws_httpc.erl index d4894e9cf1b..b9c270a6b4f 100644 --- a/core/kazoo_attachments/src/aws/kz_aws_httpc.erl +++ b/core/kazoo_attachments/src/aws/kz_aws_httpc.erl @@ -18,7 +18,7 @@ {'error', any()}). -export_type([request_fun/0]). --spec request(string(), kz_aws:method(), kz_aws:headers(), binary(), pos_integer(), aws_config()) -> +-spec request(string(), kz_aws:method(), kz_aws:headers(), iodata(), pos_integer(), aws_config()) -> {'ok', {{pos_integer(), string()}, kz_aws:headers(), binary()}} | {'error', any()}. request(URL, Method, Hdrs, Body, Timeout, diff --git a/core/kazoo_attachments/src/aws/kz_aws_retry.erl b/core/kazoo_attachments/src/aws/kz_aws_retry.erl index 20f00da7e08..617eacb6d39 100644 --- a/core/kazoo_attachments/src/aws/kz_aws_retry.erl +++ b/core/kazoo_attachments/src/aws/kz_aws_retry.erl @@ -11,14 +11,14 @@ ]). -export_type([should_retry/0, retry_fun/0]). --type should_retry() :: {'retry' | 'error', #aws_request{}}. --type retry_fun() :: fun((#aws_request{}) -> should_retry()). +-type should_retry() :: {'retry' | 'error', aws_request()}. +-type retry_fun() :: fun((aws_request()) -> should_retry()). %% Internal impl api -export([request/3]). %% Error returns maintained for backwards compatibility --spec no_retry(#aws_request{}) -> should_retry(). +-spec no_retry(aws_request()) -> should_retry(). no_retry(Request) -> {'error', Request}. @@ -32,11 +32,11 @@ backoff(Attempt) -> %% It's likely this is too many retries for other services -define(NUM_ATTEMPTS, 10). --spec default_retry(#aws_request{}) -> should_retry(). +-spec default_retry(aws_request()) -> should_retry(). default_retry(Request) -> default_retry(Request, ?NUM_ATTEMPTS). --spec default_retry(#aws_request{}, integer()) -> should_retry(). +-spec default_retry(aws_request(), integer()) -> should_retry(). default_retry(#aws_request{attempt = Attempt} = Request, MaxAttempts) when Attempt >= MaxAttempts -> {'error', Request}; @@ -46,7 +46,7 @@ default_retry(#aws_request{attempt = Attempt} = Request, _) -> backoff(Attempt), {'retry', Request}. --spec request(aws_config(), #aws_request{}, retry_fun()) -> #aws_request{}. +-spec request(aws_config(), aws_request(), retry_fun()) -> aws_request(). request(Config, #aws_request{attempt = 0} = Request, ResultFun) -> request_and_retry(Config, ResultFun, {'retry', Request}). diff --git a/core/kazoo_attachments/src/aws/kz_aws_s3.erl b/core/kazoo_attachments/src/aws/kz_aws_s3.erl index 22ea77c8c40..051ec0d5ed2 100644 --- a/core/kazoo_attachments/src/aws/kz_aws_s3.erl +++ b/core/kazoo_attachments/src/aws/kz_aws_s3.erl @@ -220,15 +220,20 @@ delete_objects_batch(Bucket, KeyList, Config) -> 'utf8'), Len = integer_to_list(string:len(Payload)), - Url = lists:flatten([Config#aws_config.s3_scheme, - Bucket, ".", Config#aws_config.s3_host, port_spec(Config), "/?delete"]), Host = Bucket ++ "." ++ Config#aws_config.s3_host, + Url = lists:flatten([Config#aws_config.s3_scheme + ,Host + ,port_spec(Config), "/?delete" + ]), + ContentMD5 = base64:encode(kz_att_util:md5(Payload)), Headers = [{"host", Host}, {"content-md5", binary_to_list(ContentMD5)}, - {"content-length", Len}], - Result = kz_aws_httpc:request( - Url, "POST", Headers, Payload, delete_objects_batch_timeout(Config), Config), + {"content-length", Len} + ], + Result = kz_aws_httpc:request(Url, 'post', Headers, Payload + ,delete_objects_batch_timeout(Config), Config + ), kz_aws:http_headers_body(Result). delete_objects_batch_timeout(#aws_config{timeout = 'undefined'}) -> 1000; @@ -392,10 +397,12 @@ list_objects(BucketName, Options, Config) ], kz_aws_xml:decode(Attributes, Doc). +-spec extract_prefixes(list(kz_aws_xml:xml())) -> list(kz_aws_xml:decoded()). extract_prefixes(Nodes) -> Attributes = [{'prefix', "Prefix", 'text'}], [kz_aws_xml:decode(Attributes, Node) || Node <- Nodes]. +-spec extract_contents(list(kz_aws_xml:xml())) -> list(kz_aws_xml:decoded()). extract_contents(Nodes) -> Attributes = [{'key', "Key", 'text'} ,{'last_modified', "LastModified", 'time'} @@ -406,6 +413,7 @@ extract_contents(Nodes) -> ], [kz_aws_xml:decode(Attributes, Node) || Node <- Nodes]. +-spec extract_user(list(kz_aws_xml:xml())) -> kz_aws_xml:decoded(). extract_user([]) -> []; extract_user([Node]) -> Attributes = [{'id', "ID", 'optional_text'} @@ -420,57 +428,66 @@ get_bucket_attribute(BucketName, AttributeName) -> get_bucket_attribute(BucketName, AttributeName, default_config()). -spec get_bucket_attribute(string(), s3_bucket_attribute_name(), aws_config()) -> term(). - get_bucket_attribute(BucketName, AttributeName, Config) when is_list(BucketName), is_atom(AttributeName) -> Attr = case AttributeName of - 'acl' -> "acl"; - 'location' -> "location"; - 'logging' -> "logging"; 'request_payment' -> "requestPayment"; - 'versioning' -> "versioning" + AN -> kz_util:to_list(AN) end, + Doc = s3_xml_request(Config, 'get', BucketName, "/", Attr, [], <<>>, []), - case AttributeName of - 'acl' -> - Attributes = [{'owner', "Owner", fun extract_user/1} - ,{'access_control_list', "AccessControlList/Grant", fun extract_acl/1} + get_bucket_attribute_from_xml(AttributeName, Doc). + +-spec get_bucket_attribute_from_xml(s3_bucket_attribute_name(), xml_el() | {'error', any()}) -> + {'error', any()} | + kz_aws_xml:decoded() | + {'enabled', boolean()} | + atom() | + string(). +get_bucket_attribute_from_xml(_AttributeName, {'error', _}=Error) -> Error; +get_bucket_attribute_from_xml('acl', Doc) -> + Attributes = [{'owner', "Owner", fun extract_user/1} + ,{'access_control_list', "AccessControlList/Grant", fun extract_acl/1} + ], + kz_aws_xml:decode(Attributes, Doc); +get_bucket_attribute_from_xml('location', Doc) -> + case kz_aws_xml:get_text("/LocationConstraint", Doc) of + %% logic according to http://s3tools.org/s3cmd + %% s3cmd-1.5.2/S3/S3.py : line 342 (function get_bucket_location) + [] -> "us-east-1"; + ["US"] -> "us-east-1"; + ["EU"] -> "eu-west-1"; + Loc -> Loc + end; +get_bucket_attribute_from_xml('logging', Doc) -> + case xmerl_xpath:string("/BucketLoggingStatus/LoggingEnabled", Doc) of + [] -> {'enabled', 'false'}; + [LoggingEnabled] -> + Attributes = [{'target_bucket', "TargetBucket", 'text'}, + {'target_prefix', "TargetPrefix", 'text'}, + {'target_trants', "TargetGrants/Grant", fun extract_acl/1} ], - kz_aws_xml:decode(Attributes, Doc); - 'location' -> - case kz_aws_xml:get_text("/LocationConstraint", Doc) of - %% logic according to http://s3tools.org/s3cmd - %% s3cmd-1.5.2/S3/S3.py : line 342 (function get_bucket_location) - [] -> "us-east-1"; - ["US"] -> "us-east-1"; - ["EU"] -> "eu-west-1"; - Loc -> Loc - end; - 'logging' -> - case xmerl_xpath:string("/BucketLoggingStatus/LoggingEnabled", Doc) of - [] -> {'enabled', 'false'}; - [LoggingEnabled] -> - Attributes = [{'target_bucket', "TargetBucket", 'text'}, - {'target_prefix', "TargetPrefix", 'text'}, - {'target_trants', "TargetGrants/Grant", fun extract_acl/1}], - [{'enabled', 'true'} | kz_aws_xml:decode(Attributes, LoggingEnabled)] - end; - 'request_payment' -> - case kz_aws_xml:get_text("/RequestPaymentConfiguration/Payer", Doc) of - "Requester" -> 'requester'; - _ -> 'bucket_owner' - end; - 'versioning' -> - case kz_aws_xml:get_text("/VersioningConfiguration/Status", Doc) of - "Enabled" -> 'enabled'; - "Suspended" -> 'suspended'; - _ -> 'disabled' - end + [{'enabled', 'true'} + | kz_aws_xml:decode(Attributes, LoggingEnabled) + ] + end; +get_bucket_attribute_from_xml('request_payment', Doc) -> + case kz_aws_xml:get_text("/RequestPaymentConfiguration/Payer", Doc) of + "Requester" -> 'requester'; + _ -> 'bucket_owner' + end; +get_bucket_attribute_from_xml('versioning', Doc) -> + case kz_aws_xml:get_text("/VersioningConfiguration/Status", Doc) of + "Enabled" -> 'enabled'; + "Suspended" -> 'suspended'; + _ -> 'disabled' end. +-spec extract_acl(xml_els()) -> kz_proplists(). extract_acl(ACL) -> [extract_grant(Item) || Item <- ACL]. +-spec extract_grant(xml_el()) -> kz_proplist(). extract_grant(Node) -> [{'grantee', extract_user(xmerl_xpath:string("Grantee", Node))} ,{'permission', decode_permission(kz_aws_xml:get_text("Permission", Node))} @@ -1114,6 +1131,9 @@ s3_simple_request(Config, Method, Host, Path, Subresource, Params, POSTData, Hea {'error', _}=E -> E end. +-spec s3_xml_request(aws_config(), kz_aws:method(), string(), string(), string(), kz_proplist(), iodata(), kz_proplist()) -> + {'error', any()} | + xml_el(). s3_xml_request(Config, Method, Host, Path, Subresource, Params, POSTData, Headers) -> case s3_request(Config, Method, Host, Path, Subresource, Params, POSTData, Headers) of {'ok', {_Headers, Body}} -> @@ -1228,6 +1248,7 @@ query_string_from_params(Params, "") -> query_string_from_params(Params, _SubResource) -> [$&, kz_aws_http:make_query_string(Params, 'no_assignment')]. +-spec s3_result_fun(aws_request()) -> aws_request(). s3_result_fun(#aws_request{response_type = 'ok'} = Request) -> Request; s3_result_fun(#aws_request{response_type = 'error' @@ -1241,19 +1262,18 @@ s3_result_fun(#aws_request{response_type = 'error' } = Request) -> Request#aws_request{should_retry = 'false'}. -make_authorization(Config, Method, ContentMD5, ContentType, Date, AmzHeaders, - Host, Resource, Subresource, Params) -> +make_authorization(#aws_config{secret_access_key=Secret + ,access_key_id=AccessKey + } + ,Method, ContentMD5, ContentType, Date, AmzHeaders + ,Host, Resource, Subresource, Params) -> CanonizedAmzHeaders = [[Name, $:, Value, $\n] || {Name, Value} <- lists:sort(AmzHeaders)], - SubResourcesToInclude = ["acl", "lifecycle", "location", "logging", "notification", "partNumber", "policy", "requestPayment", "torrent", "uploadId", "uploads", "versionId", "versioning", "versions", "website"], - FilteredParams = [NV - || {Name, _Value}=NV <- Params, - lists:member(Name, SubResourcesToInclude) - ], + FilteredParams = filter_sub_resources(Params), - ParamsQueryString = kz_aws_http:make_query_string(lists:keysort(1, FilteredParams), - 'no_assignment' + ParamsQueryString = kz_aws_http:make_query_string(lists:keysort(1, FilteredParams) + ,'no_assignment' ), StringToSign = [string:to_upper(atom_to_list(Method)), $\n ,ContentMD5, $\n @@ -1265,18 +1285,30 @@ make_authorization(Config, Method, ContentMD5, ContentType, Date, AmzHeaders, ,case Subresource of "" -> ""; _ -> [$?, Subresource] end ,string_from_params_QS(ParamsQueryString, Subresource) ], - Signature = base64:encode(kz_att_util:sha_mac(Config#aws_config.secret_access_key, StringToSign)), - ["AWS ", Config#aws_config.access_key_id, $:, Signature]. + Signature = base64:encode(kz_att_util:sha_mac(Secret, StringToSign)), + ["AWS ", AccessKey, $:, Signature]. + +-spec filter_sub_resources(kz_proplist()) -> kz_proplist(). +filter_sub_resources(Params) -> + SubResourcesToInclude = ["acl", "lifecycle", "location", "logging", "notification", "partNumber", "policy", "requestPayment", "torrent", "uploadId", "uploads", "versionId", "versioning", "versions", "website"], + + [NV + || {Name, _Value}=NV <- Params, + lists:member(Name, SubResourcesToInclude) + ]. +-spec string_from_params_QS(string(), string()) -> iolist(). string_from_params_QS("", _SubResource) -> ""; string_from_params_QS(ParamsQueryString, "") -> [$?, ParamsQueryString]; string_from_params_QS(ParamsQueryString, _SubResource) -> [$&, ParamsQueryString]. +-spec default_config() -> aws_config(). default_config() -> kz_aws:default_config(). +-spec port_spec(aws_config()) -> iolist(). port_spec(#aws_config{s3_port=80}) -> ""; port_spec(#aws_config{s3_port=Port}) -> - [":", erlang:integer_to_list(Port)]. + [":", kz_util:to_list(Port)]. diff --git a/core/kazoo_attachments/src/aws/kz_aws_xml.erl b/core/kazoo_attachments/src/aws/kz_aws_xml.erl index e040a74f2d9..54fab613a53 100644 --- a/core/kazoo_attachments/src/aws/kz_aws_xml.erl +++ b/core/kazoo_attachments/src/aws/kz_aws_xml.erl @@ -11,13 +11,19 @@ ,get_time/2 ]). +-export_type([xml/0 + ,decoded/0 + ]). + -include("kz_aws.hrl"). -type xml() :: tuple(). --type xpath() :: {string(), string()}. --type attribute() :: {atom(), string(), fun()}. +-type xpath() :: {string(), string()} | string(). +-type attribute() :: {atom(), string(), fun() | atom()}. +-type attributes() :: [attribute()]. +-type decoded() :: [{atom(), any()}]. --spec decode([attribute()], xml()) -> [{atom(), any()}]. +-spec decode(attributes(), xml()) -> decoded(). decode(Values, Node) -> lists:reverse( lists:foldl(fun ({Name, XPath, Type}, Output) -> @@ -32,7 +38,7 @@ decode(Values, Node) -> ) ). --spec decode([attribute()], xml(), A) -> A. +-spec decode(attributes(), xml(), A) -> A. decode(Values, Node, Record) -> lists:foldl(fun ({Index, XPath, Type}, Output) -> case get_value(XPath, Type, Node) of @@ -100,8 +106,8 @@ get_text(#xmlText{value=Value}) -> Value; get_text(#xmlElement{content=Content}) -> lists:flatten([get_text(Node) || Node <- Content]). --spec get_text(xpath(), xml()) -> string(). --spec get_text(xpath(), xml(), Default) -> string() | Default. +-spec get_text(xpath(), xml()) -> string() | [string()]. +-spec get_text(xpath(), xml(), Default) -> string() | [string()] | Default. get_text(XPath, Doc) -> get_text(XPath, Doc, ""). get_text({XPath, AttrName}, Doc, Default) -> case xmerl_xpath:string(XPath ++ "/@" ++ AttrName, Doc) of @@ -112,7 +118,7 @@ get_text(XPath, Doc, Default) -> case xmerl_xpath:string(XPath ++ "/text()", Doc) of [] -> Default; TextNodes -> - lists:flatten([Node#xmlText.value || Node <- TextNodes]) + lists:flatten([V || #xmlText{value=V} <- TextNodes]) end. -spec get_list(xpath(), xml()) -> [string()]. diff --git a/core/kazoo_attachments/src/kz_att_ftp.erl b/core/kazoo_attachments/src/kz_att_ftp.erl index 900902b8346..8432387dbe6 100644 --- a/core/kazoo_attachments/src/kz_att_ftp.erl +++ b/core/kazoo_attachments/src/kz_att_ftp.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Simple Url Storage for attachments %%% @end @@ -145,11 +145,15 @@ format_url(Fields, JObj, Args, Separator) -> format_url_field(JObj, Args, Fields, Acc) when is_list(Fields) -> [format_url(Fields, JObj, Args, <<>>) | Acc]; +format_url_field(JObj, Args, #{<<"arg">> := Arg}, Fields) -> + format_url_field(JObj, Args, {arg, Arg}, Fields); format_url_field(_JObj, Args, {arg, Arg}, Fields) -> case props:get_value(Arg, Args) of 'undefined' -> Fields; V -> [kz_util:uri_encode(V) | Fields] end; +format_url_field(JObj, Args, #{<<"field">> := Field}, Fields) -> + format_url_field(JObj, Args, {field, Field}, Fields); format_url_field(JObj, _Args, {field, Field}, Fields) -> case kz_json:get_value(Field, JObj) of 'undefined' -> Fields; @@ -161,6 +165,6 @@ format_url_field(_JObj, _Args, Field, Fields) -> default_format() -> [{field, <<"pvt_account_id">>} ,{field, <<"owner_id">>} - ,{args, <<"id">>} + ,{arg, <<"id">>} ,{arg, <<"attachment">>} ]. diff --git a/core/kazoo_attachments/src/kz_att_google_drive.erl b/core/kazoo_attachments/src/kz_att_google_drive.erl index 6f9e6d94663..acb13b6b32b 100644 --- a/core/kazoo_attachments/src/kz_att_google_drive.erl +++ b/core/kazoo_attachments/src/kz_att_google_drive.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Google Drive for attachments %%% @end @@ -60,8 +60,17 @@ put_attachment(#{oauth_doc_id := TokenDocId, folder_id := Folder}, _DbName, _Doc ,{<<"appProperties">>, kz_json:from_list(props:get_value('metadata', Options, [])) } ,{<<"properties">>, kz_json:from_list(props:get_value('metadata', Options, [])) } ])), - JsonPart = {kz_json:encode(JObj), [{<<"Content-Type">>, <<"application/json">>}] }, - FilePart = {base64:encode(Contents), [{<<"Content-Type">>, CT},{<<"Content-Transfer-Encoding">>, <<"base64">>}] }, + + JsonPart = {kz_json:encode(JObj) + ,[{<<"Content-Type">>, <<"application/json">>}] + }, + + FilePart = {base64:encode(Contents) + ,[{<<"Content-Type">>, CT} + ,{<<"Content-Transfer-Encoding">>, <<"base64">>} + ] + }, + Boundary = <<"------", (kz_util:rand_hex_binary(16))/binary>>, Body = encode_multipart([JsonPart, FilePart], Boundary), @@ -94,7 +103,9 @@ convert_kv({K, V}) convert_kv({K, kz_util:to_binary(V)}); convert_kv(KV) -> KV. --spec fetch_attachment(kz_data:connection(), ne_binary(), ne_binary(), ne_binary()) -> any(). +-spec fetch_attachment(kz_data:connection(), ne_binary(), ne_binary(), ne_binary()) -> + {'ok', iodata()} | + {'error', 'invalid_data' | 'not_found'}. fetch_attachment(HandlerProps, _DbName, _DocId, _AName) -> case kz_json:get_value(<<"gdrive">>, HandlerProps) of 'undefined' -> {'error', 'invalid_data'}; diff --git a/core/kazoo_attachments/src/kz_att_http.erl b/core/kazoo_attachments/src/kz_att_http.erl index 711192b92f2..cde3d03c080 100644 --- a/core/kazoo_attachments/src/kz_att_http.erl +++ b/core/kazoo_attachments/src/kz_att_http.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Simple Url Storage for attachments %%% @end @@ -104,7 +104,7 @@ fetch_attachment(HandlerProps, _DbName, _DocId, _AName) -> fetch_attachment(URL) -> case fetch_attachment(URL, 0, kz_json:new()) of - {'ok', _Url, Body, _Debug} -> {'ok', Body}; + {'ok', Body} -> {'ok', Body}; {'error', _} = Error -> Error end. @@ -139,11 +139,15 @@ format_url(Fields, JObj, Args, Separator) -> format_url_field(JObj, Args, Fields, Acc) when is_list(Fields) -> [format_url(Fields, JObj, Args, <<>>) | Acc]; +format_url_field(JObj, Args, #{<<"arg">> := Arg}, Fields) -> + format_url_field(JObj, Args, {arg, Arg}, Fields); format_url_field(_JObj, Args, {arg, Arg}, Fields) -> case props:get_value(Arg, Args) of 'undefined' -> Fields; V -> [kz_util:uri_encode(V) | Fields] end; +format_url_field(JObj, Args, #{<<"field">> := Field}, Fields) -> + format_url_field(JObj, Args, {field, Field}, Fields); format_url_field(JObj, _Args, {field, Field}, Fields) -> case kz_json:get_value(Field, JObj) of 'undefined' -> Fields; @@ -155,6 +159,6 @@ format_url_field(_JObj, _Args, Field, Fields) -> default_format() -> [{field, <<"pvt_account_id">>} ,{field, <<"owner_id">>} - ,{args, <<"id">>} + ,{arg, <<"id">>} ,{arg, <<"attachment">>} ]. diff --git a/core/kazoo_attachments/src/kz_att_link.erl b/core/kazoo_attachments/src/kz_att_link.erl index 8ed5793c421..4218060fa22 100644 --- a/core/kazoo_attachments/src/kz_att_link.erl +++ b/core/kazoo_attachments/src/kz_att_link.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% DB Link for attachments %%% @end diff --git a/core/kazoo_attachments/src/kz_att_s3.erl b/core/kazoo_attachments/src/kz_att_s3.erl index 241b1eeb400..39a031dbafa 100644 --- a/core/kazoo_attachments/src/kz_att_s3.erl +++ b/core/kazoo_attachments/src/kz_att_s3.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% S3 Storage for attachments %%% @end diff --git a/core/kazoo_auth/c_src/kz_auth_rsa_drv.c b/core/kazoo_auth/c_src/kz_auth_rsa_drv.c index 6771be114e8..cb2da03c37c 100644 --- a/core/kazoo_auth/c_src/kz_auth_rsa_drv.c +++ b/core/kazoo_auth/c_src/kz_auth_rsa_drv.c @@ -134,7 +134,7 @@ static ErlDrvSSizeT call(ErlDrvData edd, unsigned int cmd, char *buf, if (cmd == CUTKEY_CMD_RSA) { errno = CUTKEY_ERR_ARG; ei_decode_ei_term(buf, &index, &tuple); - if (!tuple.ei_type == ERL_TUPLE || tuple.arity != 3) { + if (tuple.ei_type != ERL_SMALL_TUPLE_EXT || tuple.arity != 3) { goto error; } ei_decode_ei_term(buf, &index, &ref); @@ -185,8 +185,23 @@ static void ready_async(ErlDrvData edd, ErlDrvThreadData async_data) { ck_job_t* job = (ck_job_t*) async_data; if (job->cmd == CUTKEY_CMD_RSA) { if (job->rsa != NULL) { - RSA* rsa = job->rsa; CUTKEY_SILENCE_DEPRECATED_ON_OSX_START +#if OPENSSL_VERSION_NUMBER > 0x1010000fL + const BIGNUM *bn_e, *bn_n, *bn_d, *bn_p, *bn_q; + const BIGNUM *bn_dmp1, *bn_dmq1, *bn_iqmp; + RSA_get0_factors(job->rsa, &bn_p, &bn_q); + RSA_get0_key(job->rsa, &bn_n, &bn_e, &bn_d); + RSA_get0_crt_params(job->rsa, &bn_dmp1, &bn_dmq1, &bn_iqmp); + int esize = BN_bn2mpi(bn_e, NULL); + int nsize = BN_bn2mpi(bn_n, NULL); + int dsize = BN_bn2mpi(bn_d, NULL); + int psize = BN_bn2mpi(bn_p, NULL); + int qsize = BN_bn2mpi(bn_q, NULL); + int dmp1size = BN_bn2mpi(bn_dmp1, NULL); + int dmq1size = BN_bn2mpi(bn_dmq1, NULL); + int iqmpsize = BN_bn2mpi(bn_iqmp, NULL); +#else + RSA* rsa = job->rsa; int esize = BN_bn2mpi(rsa->e, NULL); int nsize = BN_bn2mpi(rsa->n, NULL); int dsize = BN_bn2mpi(rsa->d, NULL); @@ -195,6 +210,8 @@ static void ready_async(ErlDrvData edd, ErlDrvThreadData async_data) { int dmp1size = BN_bn2mpi(rsa->dmp1, NULL); int dmq1size = BN_bn2mpi(rsa->dmq1, NULL); int iqmpsize = BN_bn2mpi(rsa->iqmp, NULL); +#endif + CUTKEY_SILENCE_DEPRECATED_ON_OSX_END unsigned char *e = driver_alloc(esize); unsigned char *n = driver_alloc(nsize); @@ -205,6 +222,16 @@ static void ready_async(ErlDrvData edd, ErlDrvThreadData async_data) { unsigned char *dmq1 = driver_alloc(dmq1size); unsigned char *iqmp = driver_alloc(iqmpsize); CUTKEY_SILENCE_DEPRECATED_ON_OSX_START +#if OPENSSL_VERSION_NUMBER > 0x1010000fL + esize = BN_bn2mpi(bn_e, e); + nsize = BN_bn2mpi(bn_n, n); + dsize = BN_bn2mpi(bn_d, d); + psize = BN_bn2mpi(bn_p, p); + qsize = BN_bn2mpi(bn_q, q); + dmp1size = BN_bn2mpi(bn_dmp1, dmp1); + dmq1size = BN_bn2mpi(bn_dmq1, dmq1); + iqmpsize = BN_bn2mpi(bn_iqmp, iqmp); +#else esize = BN_bn2mpi(rsa->e, e); nsize = BN_bn2mpi(rsa->n, n); dsize = BN_bn2mpi(rsa->d, d); @@ -213,6 +240,7 @@ static void ready_async(ErlDrvData edd, ErlDrvThreadData async_data) { dmp1size = BN_bn2mpi(rsa->dmp1, dmp1); dmq1size = BN_bn2mpi(rsa->dmq1, dmq1); iqmpsize = BN_bn2mpi(rsa->iqmp, iqmp); +#endif CUTKEY_SILENCE_DEPRECATED_ON_OSX_END ErlDrvTermData spec[] = {ERL_DRV_PORT, dd->term_port, @@ -253,8 +281,20 @@ static void ready_async(ErlDrvData edd, ErlDrvThreadData async_data) { } static void do_rsa_job(void* data) { + RSA *r = NULL; + BIGNUM *bne = NULL; + int ret = 0; ck_job_t* job = (ck_job_t*) data; + bne = BN_new(); + BN_set_word(bne, job->e); CUTKEY_SILENCE_DEPRECATED_ON_OSX_START - job->rsa = RSA_generate_key(job->num, job->e, NULL, NULL); + r = RSA_new(); + ret = RSA_generate_key_ex(r, job->num, bne, NULL); + if(ret != 1) { + RSA_free(r); + } else { + job->rsa = r; + } + BN_free(bne); CUTKEY_SILENCE_DEPRECATED_ON_OSX_END } diff --git a/core/kazoo_auth/src/kazoo_auth_app.erl b/core/kazoo_auth/src/kazoo_auth_app.erl index 371743c2c89..3c5389aa5e6 100644 --- a/core/kazoo_auth/src/kazoo_auth_app.erl +++ b/core/kazoo_auth/src/kazoo_auth_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_auth/src/kazoo_auth_sup.erl b/core/kazoo_auth/src/kazoo_auth_sup.erl index 5e522d6c216..c95344c39f6 100644 --- a/core/kazoo_auth/src/kazoo_auth_sup.erl +++ b/core/kazoo_auth/src/kazoo_auth_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_auth/src/kz_auth.erl b/core/kazoo_auth/src/kz_auth.erl index d1efbcfa2c0..1a7f95adb16 100644 --- a/core/kazoo_auth/src/kz_auth.erl +++ b/core/kazoo_auth/src/kz_auth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_auth/src/kz_auth_apps.erl b/core/kazoo_auth/src/kz_auth_apps.erl index 7a6d2f02f17..fb549445655 100644 --- a/core/kazoo_auth/src/kz_auth_apps.erl +++ b/core/kazoo_auth/src/kz_auth_apps.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_auth/src/kz_auth_identity.erl b/core/kazoo_auth/src/kz_auth_identity.erl index 075cd6d99ea..e29180add8f 100644 --- a/core/kazoo_auth/src/kz_auth_identity.erl +++ b/core/kazoo_auth/src/kz_auth_identity.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_auth/src/kz_auth_init.erl b/core/kazoo_auth/src/kz_auth_init.erl index 8d2f470130a..071a2b97241 100644 --- a/core/kazoo_auth/src/kz_auth_init.erl +++ b/core/kazoo_auth/src/kz_auth_init.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_auth/src/kz_auth_jwt.erl b/core/kazoo_auth/src/kz_auth_jwt.erl index df179a4a0a6..7925b05d425 100644 --- a/core/kazoo_auth/src/kz_auth_jwt.erl +++ b/core/kazoo_auth/src/kz_auth_jwt.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_auth/src/kz_auth_keys.erl b/core/kazoo_auth/src/kz_auth_keys.erl index 13c0956ca81..aad67e9fce3 100644 --- a/core/kazoo_auth/src/kz_auth_keys.erl +++ b/core/kazoo_auth/src/kz_auth_keys.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_auth/src/kz_auth_profile.erl b/core/kazoo_auth/src/kz_auth_profile.erl index c0822f44e32..80d1d762588 100644 --- a/core/kazoo_auth/src/kz_auth_profile.erl +++ b/core/kazoo_auth/src/kz_auth_profile.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_auth/src/kz_auth_providers.erl b/core/kazoo_auth/src/kz_auth_providers.erl index 200450c6f2a..74d5da516f7 100644 --- a/core/kazoo_auth/src/kz_auth_providers.erl +++ b/core/kazoo_auth/src/kz_auth_providers.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_auth/src/kz_auth_rsa.erl b/core/kazoo_auth/src/kz_auth_rsa.erl index 50c97048cbb..7d6b5d9706b 100644 --- a/core/kazoo_auth/src/kz_auth_rsa.erl +++ b/core/kazoo_auth/src/kz_auth_rsa.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_auth/src/kz_auth_rsa_drv.erl b/core/kazoo_auth/src/kz_auth_rsa_drv.erl index dcd9755612a..214253f4da0 100644 --- a/core/kazoo_auth/src/kz_auth_rsa_drv.erl +++ b/core/kazoo_auth/src/kz_auth_rsa_drv.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_auth/src/kz_auth_token_util.erl b/core/kazoo_auth/src/kz_auth_token_util.erl index 327b676fba9..63f039f1e35 100644 --- a/core/kazoo_auth/src/kz_auth_token_util.erl +++ b/core/kazoo_auth/src/kz_auth_token_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_auth/src/kz_auth_util.erl b/core/kazoo_auth/src/kz_auth_util.erl index f5bf656e7eb..3afe0793b4b 100644 --- a/core/kazoo_auth/src/kz_auth_util.erl +++ b/core/kazoo_auth/src/kz_auth_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_auth/src/kz_base64url.erl b/core/kazoo_auth/src/kz_base64url.erl index 65ed4284905..7dc3faa61ac 100644 --- a/core/kazoo_auth/src/kz_base64url.erl +++ b/core/kazoo_auth/src/kz_base64url.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_bindings/src/kazoo_bindings.erl b/core/kazoo_bindings/src/kazoo_bindings.erl index 00f24bb4be2..202d0c50111 100644 --- a/core/kazoo_bindings/src/kazoo_bindings.erl +++ b/core/kazoo_bindings/src/kazoo_bindings.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Store routing keys/pid bindings. When a binding is fired, %%% pass the payload to the pid for evaluation, accumulating @@ -227,6 +227,8 @@ matches([<<"#">>, <<"*">>], []) -> 'false'; matches([<<"#">>, <<"*">>], [<<>>]) -> 'false'; matches([<<"#">>, <<"*">>], [_]) -> 'true'; % match one item: #.* matches foo +matches([<<"#">>, <<"#">> | Bs], Rs) -> + matches([<<"#">> | Bs], Rs); matches([<<"#">> | Bs], []) -> % sadly, #.# would match foo, foo.bar, foo.bar.baz, etc matches(Bs, []); % so keep checking by stipping of the first # @@ -239,10 +241,15 @@ matches([_|_], [<<>>]) -> 'false'; matches([<<"*">> | Bs], [_|Rs]) -> matches(Bs, Rs); % so ignore what the routing segment is and continue +matches([<<"#">>, B | Bs], [B, B | Rs]) -> + matches(Bs, Rs) + orelse matches([<<"#">>|Bs], [B | Rs]); + %% # can match 0 or more segments matches([<<"#">>, B | Bs], [B | Rs]) -> - %% Since the segment in B could be repeated later in the Routing Key, we need to bifurcate here - %% but we'll short circuit if this was indeed the end of the # matching + %% Since the segment in B could be repeated later in the Routing Key, + %% we need to bifurcate here but we'll short circuit if this was indeed + %% the end of the # matching %% see binding_matches(<<"#.A.*">>,<<"A.a.A.a">>) case lists:member(B, Rs) of diff --git a/core/kazoo_bindings/src/kazoo_bindings_app.erl b/core/kazoo_bindings/src/kazoo_bindings_app.erl index d19a9196e74..2b3bb0b72c8 100644 --- a/core/kazoo_bindings/src/kazoo_bindings_app.erl +++ b/core/kazoo_bindings/src/kazoo_bindings_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_bindings/src/kazoo_bindings_rt.erl b/core/kazoo_bindings/src/kazoo_bindings_rt.erl index b7f999acf4c..2e4ab813357 100644 --- a/core/kazoo_bindings/src/kazoo_bindings_rt.erl +++ b/core/kazoo_bindings/src/kazoo_bindings_rt.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% runtime options for bindings %%% @end diff --git a/core/kazoo_bindings/src/kazoo_bindings_sup.erl b/core/kazoo_bindings/src/kazoo_bindings_sup.erl index a43477903c2..9a8bc44c096 100644 --- a/core/kazoo_bindings/src/kazoo_bindings_sup.erl +++ b/core/kazoo_bindings/src/kazoo_bindings_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_bindings/test/kazoo_bindings_test.erl b/core/kazoo_bindings/test/kazoo_bindings_test.erl index 945f22782e2..6e8f689fd66 100644 --- a/core/kazoo_bindings/test/kazoo_bindings_test.erl +++ b/core/kazoo_bindings/test/kazoo_bindings_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Store routing keys/pid bindings. When a binding is fired, %%% pass the payload to the pid for evaluation, accumulating @@ -28,11 +28,11 @@ %% EUNIT and PropEr TESTING %% -spec binding_matches(ne_binary(), ne_binary()) -> boolean(). -binding_matches(B, R) when erlang:byte_size(B) > 0 andalso erlang:byte_size(R) > 0 -> - kazoo_bindings:matches( - lists:reverse(binary:split(B, <<".">>, ['global'])) - ,lists:reverse(binary:split(R, <<".">>, ['global'])) - ). +binding_matches(B, R) -> + BRev = lists:reverse(binary:split(B, <<".">>, ['global'])), + RRev = lists:reverse(binary:split(R, <<".">>, ['global'])), + + kazoo_bindings:matches(BRev, RRev). -define(ROUTINGS, [<<"foo.bar.zot">> ,<<"foo.quux.zot">> @@ -54,19 +54,39 @@ binding_matches(B, R) when erlang:byte_size(B) > 0 andalso erlang:byte_size(R) > ,{<<"#.bar.*">>, ['true', 'false', 'false', 'false', 'false', 'false']} ]). -bindings_match_test() -> - lists:foreach(fun({B, _}=Expected) -> - Actual = lists:foldr(fun(R, Acc) -> [binding_matches(B, R) | Acc] end, [], ?ROUTINGS), - ?assertEqual(Expected, {B, Actual}) - end, ?BINDINGS). +bindings_match_test_() -> + lists:map(fun({B, _}=Expected) -> + Actual = lists:foldr(fun(R, Acc) -> [binding_matches(B, R) | Acc] end, [], ?ROUTINGS), + ?_assertEqual(Expected, {B, Actual}) + end + ,?BINDINGS + ). + +%% Left commented out because this was really useful for stepping through +%% individual tests and I want to keep it here for reference in the future +%% dbg_test() -> +%% dbg:start(), + +%% dbg:tracer(), + +%% dbg:tpl(kazoo_bindings, [{'_', [], [$_]}]), +%% dbg:p(all, c), + +%% Result = binding_matches(<<"#.c.#.c.#">>, <<"c.c">>), + +%% dbg:stop_clear(), +%% dbg:stop(), +%% ?assertEqual('true', Result). weird_bindings_test_() -> [?_assertEqual('true', binding_matches(<<"#.A.*">>,<<"A.a.A.a">>)) ,?_assertEqual('true', binding_matches(<<"#.*">>, <<"foo">>)) ,?_assertEqual('true', binding_matches(<<"#.*">>, <<"foo.bar">>)) ,?_assertEqual('false', binding_matches(<<"foo.#.*">>, <<"foo">>)) - %% ,?_assertEqual('false', binding_matches(<<"#.*">>, <<>>)) + ,?_assertEqual('false', binding_matches(<<"#.*">>, <<>>)) ,?_assertEqual('true', binding_matches(<<"#.6.*.1.4.*">>,<<"6.a.a.6.a.1.4.a">>)) + ,?_assertEqual('true', binding_matches(<<"*.u.*.7.7.#">>,<<"i.u.e.7.7.7.a">>)) + ,?_assertEqual('true', binding_matches(<<"#.c.#.c.#">>, <<"c.c">>)) ]. %%% PropEr tests diff --git a/core/kazoo_caches/src/kazoo_caches_app.erl b/core/kazoo_caches/src/kazoo_caches_app.erl index 98b2c17a9e7..e3a20f5672e 100644 --- a/core/kazoo_caches/src/kazoo_caches_app.erl +++ b/core/kazoo_caches/src/kazoo_caches_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_caches/src/kazoo_caches_sup.erl b/core/kazoo_caches/src/kazoo_caches_sup.erl index a46799c89aa..b0c9c14efe2 100644 --- a/core/kazoo_caches/src/kazoo_caches_sup.erl +++ b/core/kazoo_caches/src/kazoo_caches_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_caches/src/kz_cache.erl b/core/kazoo_caches/src/kz_cache.erl index 55eaf212f72..9b399be9e17 100644 --- a/core/kazoo_caches/src/kz_cache.erl +++ b/core/kazoo_caches/src/kz_cache.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Simple cache server %%% @end @@ -209,7 +209,6 @@ fetch_local(Srv, K) -> {'error', 'not_found'}=E -> E; {'ok', _Value}=Ok -> ets:update_element(Srv, K, {#cache_obj.timestamp, kz_util:current_tstamp()}), - % gen_server:cast(Srv, {'update_timestamp', K, }), Ok end. diff --git a/core/kazoo_call/src/kapps_call.erl b/core/kazoo_call/src/kapps_call.erl index f45acb17345..396b64951f1 100644 --- a/core/kazoo_call/src/kapps_call.erl +++ b/core/kazoo_call/src/kapps_call.erl @@ -1,5 +1,5 @@ %%============================================================================ -%%% @copyright (C) 2011-2016 2600Hz Inc +%%% @copyright (C) 2011-2017 2600Hz Inc %%% @doc %%% %%% @end @@ -41,6 +41,8 @@ -export([set_caller_id_number/2, caller_id_number/1]). -export([set_callee_id_name/2, callee_id_name/1]). -export([set_callee_id_number/2, callee_id_number/1]). +-export([set_callee_id/3, callee_id/1]). +-export([set_caller_id/3, caller_id/1]). -export([set_request/2, request/1, request_user/1, request_realm/1]). -export([set_from/2, from/1, from_user/1, from_realm/1]). @@ -640,6 +642,31 @@ maybe_append_caller_id(CallerId, Suffix) -> lager:info("appending cid with ~s~n", [BinSuffix]), <>. +-spec set_caller_id(ne_binary(), ne_binary(), call()) -> call(). +-ifdef(TEST). +set_caller_id(CIDNumber, CIDName, #kapps_call{}=Call) + when is_binary(CIDNumber) + andalso is_binary(CIDName) -> + Call#kapps_call{caller_id_number=CIDNumber + ,callee_id_name=CIDName + }. +-else. +set_caller_id(CIDNumber, CIDName, #kapps_call{}=Call) + when is_binary(CIDNumber) + andalso is_binary(CIDName) -> + JObj = kz_json:from_list([{<<"Caller-ID-Number">>, CIDNumber} + ,{<<"Caller-ID-Name">>, CIDName} + ]), + kapps_call_command:set(JObj, 'undefined', Call), + Call#kapps_call{caller_id_number=CIDNumber + ,callee_id_name=CIDName + }. +-endif. + +-spec caller_id(call()) -> {ne_binary(), ne_binary()}. +caller_id(Call) -> + {caller_id_number(Call), caller_id_name(Call)}. + -spec set_caller_id_name(ne_binary(), call()) -> call(). -ifdef(TEST). set_caller_id_name(CIDName, Call) -> @@ -674,13 +701,37 @@ caller_id_number(#kapps_call{caller_id_number=CIDNumber}) -> 'false' -> CIDNumber end. +-spec set_callee_id(ne_binary(), ne_binary(), call()) -> call(). +-ifdef(TEST). +set_callee_id(CIDNumber, CIDName, #kapps_call{}=Call) + when is_binary(CIDNumber) + andalso is_binary(CIDName) -> + Call#kapps_call{callee_id_number=CIDNumber + ,callee_id_name=CIDName + }. +-else. +set_callee_id(CIDNumber, CIDName, #kapps_call{}=Call) + when is_binary(CIDNumber) + andalso is_binary(CIDName) -> + kapps_call_command:set(kz_json:from_list([{<<"Callee-ID-Number">>, CIDNumber} + ,{<<"Callee-ID-Name">>, CIDName} + ]), 'undefined', Call), + Call#kapps_call{callee_id_number=CIDNumber + ,callee_id_name=CIDName + }. +-endif. + +-spec callee_id(call()) -> {ne_binary(), ne_binary()}. +callee_id(Call) -> + {callee_id_number(Call), callee_id_name(Call)}. + -spec set_callee_id_name(ne_binary(), call()) -> call(). -ifdef(TEST). set_callee_id_name(CIDName, Call) -> Call#kapps_call{callee_id_name=CIDName}. -else. set_callee_id_name(CIDName, #kapps_call{}=Call) when is_binary(CIDName) -> - kapps_call_command:set(kz_json:from_list([{<<"Callee-ID-Number">>, CIDName}]), 'undefined', Call), + kapps_call_command:set(kz_json:from_list([{<<"Callee-ID-Name">>, CIDName}]), 'undefined', Call), Call#kapps_call{callee_id_name=CIDName}. -endif. diff --git a/core/kazoo_call/src/kapps_call_command.erl b/core/kazoo_call/src/kapps_call_command.erl index 313c962fb9c..4f8411f10a6 100644 --- a/core/kazoo_call/src/kapps_call_command.erl +++ b/core/kazoo_call/src/kapps_call_command.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_call/src/kapps_conference.erl b/core/kazoo_call/src/kapps_conference.erl index a77fa8e6f42..35c5da5f1d3 100644 --- a/core/kazoo_call/src/kapps_conference.erl +++ b/core/kazoo_call/src/kapps_conference.erl @@ -1,5 +1,5 @@ %%%============================================================================ -%%% @copyright (C) 2012-2016 2600Hz Inc +%%% @copyright (C) 2012-2017 2600Hz Inc %%% @doc %%% %%% @end diff --git a/core/kazoo_call/src/kapps_conference_command.erl b/core/kazoo_call/src/kapps_conference_command.erl index 1b6c54cd8aa..bc0cbf6a743 100644 --- a/core/kazoo_call/src/kapps_conference_command.erl +++ b/core/kazoo_call/src/kapps_conference_command.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_call/src/kapps_sms_command.erl b/core/kazoo_call/src/kapps_sms_command.erl index a9a26cb8b62..475d247fde0 100644 --- a/core/kazoo_call/src/kapps_sms_command.erl +++ b/core/kazoo_call/src/kapps_sms_command.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_call/src/kz_call_response.erl b/core/kazoo_call/src/kz_call_response.erl index fb99a1afa1d..a8b402ed376 100644 --- a/core/kazoo_call/src/kz_call_response.erl +++ b/core/kazoo_call/src/kz_call_response.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_config/src/kapps_account_config.erl b/core/kazoo_config/src/kapps_account_config.erl index e3d9c081537..655c6789e74 100644 --- a/core/kazoo_config/src/kapps_account_config.erl +++ b/core/kazoo_config/src/kapps_account_config.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end @@ -13,7 +13,7 @@ -export([get/2, get/3, get/4 ,get_global/3, get_global/4 - ,get_from_reseller/4 + ,get_from_reseller/3, get_from_reseller/4 ,set/4 ,set_global/4 ,flush/1, flush/2 @@ -49,6 +49,11 @@ get_global(Account, Category, Key, Default) -> %% i.e. makes sure to skip reading from Account (i.e. sub-account of reseller). %% @end %%-------------------------------------------------------------------- +-spec get_from_reseller(account(), ne_binary(), kz_json:path()) -> + kz_json:api_json_term(). +get_from_reseller(Account, Category, Key) -> + get_from_reseller(Account, Category, Key, 'undefined'). + -spec get_from_reseller(account(), ne_binary(), kz_json:path(), kz_json:api_json_term()) -> kz_json:api_json_term(). -ifdef(TEST). diff --git a/core/kazoo_config/src/kapps_config.erl b/core/kazoo_config/src/kapps_config.erl index 874f5b7a8a8..8b776857f2f 100644 --- a/core/kazoo_config/src/kapps_config.erl +++ b/core/kazoo_config/src/kapps_config.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% @end %%% @contributors diff --git a/core/kazoo_config/src/kazoo_config_app.erl b/core/kazoo_config/src/kazoo_config_app.erl index 4c99f9edc80..456cbc4840d 100644 --- a/core/kazoo_config/src/kazoo_config_app.erl +++ b/core/kazoo_config/src/kazoo_config_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_config/src/kazoo_config_init.erl b/core/kazoo_config/src/kazoo_config_init.erl index f9a385c37d8..5e936614b32 100644 --- a/core/kazoo_config/src/kazoo_config_init.erl +++ b/core/kazoo_config/src/kazoo_config_init.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016 2600Hz, INC +%%% @copyright (C) 2011-2017 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_config/src/kazoo_config_sup.erl b/core/kazoo_config/src/kazoo_config_sup.erl index 9c125764b2e..58223feb2bf 100644 --- a/core/kazoo_config/src/kazoo_config_sup.erl +++ b/core/kazoo_config/src/kazoo_config_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_config/src/kz_config.erl b/core/kazoo_config/src/kz_config.erl index c977c5117ad..071db5d251d 100644 --- a/core/kazoo_config/src/kz_config.erl +++ b/core/kazoo_config/src/kz_config.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz, INC +%%% @copyright (C) 2013-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_couch/src/kazoo_couch.erl b/core/kazoo_couch/src/kazoo_couch.erl index 10e0cbf54af..a03a2200ba0 100644 --- a/core/kazoo_couch/src/kazoo_couch.erl +++ b/core/kazoo_couch/src/kazoo_couch.erl @@ -148,7 +148,8 @@ save_doc(Server, DbName, Doc, Options) -> save_docs(Server, DbName, Docs, Options) -> kz_couch_doc:save_docs(Server, DbName, Docs, Options). --spec del_doc(kz_data:connection(), ne_binary(), kz_data:documents(), kz_data:options()) -> any(). +-spec del_doc(kz_data:connection(), ne_binary(), kz_data:document(), kz_data:options()) -> + any(). del_doc(Server, DbName, Doc, Options) -> kz_couch_doc:del_doc(Server, DbName, Doc, Options). @@ -194,8 +195,8 @@ attachment_url(Server, DbName, DocId, AName, Options) -> design_info(Server, DBName, Design) -> kz_couch_view:design_info(Server, DBName, Design). --spec all_design_docs(kz_data:connection(), ne_binary(), kz_data:connection()) -> any(). -all_design_docs(Server, DBName, Options) -> +-spec all_design_docs(kz_data:connection(), ne_binary(), kz_data:options()) -> any(). +all_design_docs(#server{}=Server, ?NE_BINARY = DBName, Options) -> kz_couch_view:all_design_docs(Server, DBName, Options). -spec get_results(kz_data:connection(), ne_binary(), ne_binary(), kz_data:options()) -> any(). @@ -214,12 +215,21 @@ all_docs(Server, DbName, Options) -> version(#server{options=Options}) -> props:get_value('driver_version', Options). +-spec db_local_filter(ne_binaries(), kz_data:options()) -> ne_binaries(). db_local_filter(List, Options) -> [DB || DB <- List, - lists:all(fun(Option) -> - db_local_filter_option(Option, DB) - end, Options)]. - + all_valid_options(Options, DB) + ]. + +-spec all_valid_options(kz_data:options(), ne_binary()) -> boolean(). +all_valid_options(Options, DB) -> + lists:all(fun(Option) -> + db_local_filter_option(Option, DB) + end + ,Options + ). + +-spec db_local_filter_option(kz_data:option(), ne_binary()) -> boolean(). db_local_filter_option({'start_key', Value}, DB) -> DB >= Value; db_local_filter_option({'startkey', Value}, DB) -> diff --git a/core/kazoo_couch/src/kazoo_couch_maintenance.erl b/core/kazoo_couch/src/kazoo_couch_maintenance.erl index 49eee9e6037..de4a2f76530 100644 --- a/core/kazoo_couch/src/kazoo_couch_maintenance.erl +++ b/core/kazoo_couch/src/kazoo_couch_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_couch/src/kazoo_couch_sup.erl b/core/kazoo_couch/src/kazoo_couch_sup.erl index 01395531532..5920d2f27d3 100644 --- a/core/kazoo_couch/src/kazoo_couch_sup.erl +++ b/core/kazoo_couch/src/kazoo_couch_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_couch/src/kz_couch_attachments.erl b/core/kazoo_couch/src/kz_couch_attachments.erl index cee38c0bd27..b68893e1cb5 100644 --- a/core/kazoo_couch/src/kz_couch_attachments.erl +++ b/core/kazoo_couch/src/kz_couch_attachments.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Util functions used by kazoo_couch %%% @end @@ -83,10 +83,14 @@ do_fetch_attachment(#db{}=Db, DocId, AName) -> ?RETRY_504(couchbeam:fetch_attachment(Db, DocId, AName)). -spec do_stream_attachment(couchbeam_db(), ne_binary(), ne_binary(), pid()) -> - {'ok', reference()} | + {'ok', reference() | atom()} | couchbeam_error(). do_stream_attachment(#db{}=Db, DocId, AName, Caller) -> - case couchbeam:fetch_attachment(Db, DocId, AName, [{stream, true},{async,true}]) of + case couchbeam:fetch_attachment(Db, DocId, AName, [{'stream', 'true'} + ,{'async', 'true'} + ] + ) + of {'ok', Ref}=Ret -> Msg = couchbeam:stream_attachment(Ref), St = get(Ref), @@ -126,4 +130,3 @@ maybe_add_revision(Options) -> 'undefined' -> <<>>; Rev -> <<"?rev=", Rev/binary>> end. - diff --git a/core/kazoo_couch/src/kz_couch_compactor.erl b/core/kazoo_couch/src/kz_couch_compactor.erl index 2a575d11233..af32fcf4fe8 100644 --- a/core/kazoo_couch/src/kz_couch_compactor.erl +++ b/core/kazoo_couch/src/kz_couch_compactor.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_couch/src/kz_couch_db.erl b/core/kazoo_couch/src/kz_couch_db.erl index 636147b4161..15d91bc4467 100644 --- a/core/kazoo_couch/src/kz_couch_db.erl +++ b/core/kazoo_couch/src/kz_couch_db.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Util functions used by kazoo_couch %%% @end diff --git a/core/kazoo_couch/src/kz_couch_doc.erl b/core/kazoo_couch/src/kz_couch_doc.erl index cf1c0dfb0b6..a39a7e99991 100644 --- a/core/kazoo_couch/src/kz_couch_doc.erl +++ b/core/kazoo_couch/src/kz_couch_doc.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Util functions used by kazoo_couch %%% @end diff --git a/core/kazoo_couch/src/kz_couch_util.erl b/core/kazoo_couch/src/kz_couch_util.erl index fbe2a924691..0b410819edb 100644 --- a/core/kazoo_couch/src/kz_couch_util.erl +++ b/core/kazoo_couch/src/kz_couch_util.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Util functions used by kazoo_couch %%% @end @@ -90,7 +90,7 @@ retry504s(Fun, Cnt) -> %% @doc %% @end %%------------------------------------------------------------------------------ --spec new_connection(couch_connection() | #{}) -> +-spec new_connection(couch_connection() | map()) -> server() | {'error', 'timeout' | 'ehostunreach' | _}. new_connection(#{}=Map) -> @@ -112,7 +112,7 @@ check_options(Options) -> maybe_default_recv_timeout(Options) -> case props:get_value('recv_timeout', Options) of 'undefined' -> [{'recv_timeout', 20000} | Options]; - _Else -> Options + _Else -> Options end. filter_options(Options) -> @@ -203,7 +203,7 @@ db_url(#server{}=Conn, DbName) -> %% returns the #db{} record %% @end %%------------------------------------------------------------------------------ --spec get_db(server(), ne_binary()) -> db(). +-spec get_db(kz_data:connection(), ne_binary()) -> db(). get_db(#server{}=Conn, DbName) -> {'ok', Db} = couchbeam:open_db(Conn, DbName), Db. diff --git a/core/kazoo_couch/src/kz_couch_view.erl b/core/kazoo_couch/src/kz_couch_view.erl index 753b6e581d5..7c569fd0fe2 100644 --- a/core/kazoo_couch/src/kz_couch_view.erl +++ b/core/kazoo_couch/src/kz_couch_view.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% Util functions used by kazoo_couch %%% @end @@ -20,7 +20,7 @@ -include("kz_couch.hrl"). --type ddoc() :: atom() | ne_binary() | {ne_binary(), ne_binary()}. +-type ddoc() :: 'all_docs' | ne_binary() | {ne_binary(), ne_binary()}. %%% View-related functions ----------------------------------------------------- -spec design_compact(server(), ne_binary(), ne_binary()) -> boolean(). @@ -39,7 +39,7 @@ design_info(#server{}=Conn, DBName, Design) -> Db = kz_couch_util:get_db(Conn, DBName), do_get_design_info(Db, Design). --spec all_design_docs(server(), ne_binary(), view_options()) -> +-spec all_design_docs(kz_data:connection(), ne_binary(), view_options()) -> {'ok', kz_json:objects()} | couchbeam_error(). all_design_docs(#server{}=Conn, DBName, Options) -> diff --git a/core/kazoo_data/src/kazoo_data_bootstrap.erl b/core/kazoo_data/src/kazoo_data_bootstrap.erl index 632d47fe574..fca3cfc9eab 100644 --- a/core/kazoo_data/src/kazoo_data_bootstrap.erl +++ b/core/kazoo_data/src/kazoo_data_bootstrap.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_data/src/kazoo_data_init.erl b/core/kazoo_data/src/kazoo_data_init.erl index 3ada2431cd4..90821afb2e0 100644 --- a/core/kazoo_data/src/kazoo_data_init.erl +++ b/core/kazoo_data/src/kazoo_data_init.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_data/src/kazoo_data_maintenance.erl b/core/kazoo_data/src/kazoo_data_maintenance.erl index 3380718c7b8..1ae46e03a6d 100644 --- a/core/kazoo_data/src/kazoo_data_maintenance.erl +++ b/core/kazoo_data/src/kazoo_data_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_data/src/kazoo_data_sup.erl b/core/kazoo_data/src/kazoo_data_sup.erl index b8f7ab9e326..337d0d10bc5 100644 --- a/core/kazoo_data/src/kazoo_data_sup.erl +++ b/core/kazoo_data/src/kazoo_data_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_data/src/kazoo_dataconnection_error.erl b/core/kazoo_data/src/kazoo_dataconnection_error.erl index ab293e58cde..3ea4c6f685c 100644 --- a/core/kazoo_data/src/kazoo_dataconnection_error.erl +++ b/core/kazoo_data/src/kazoo_dataconnection_error.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% data connection with error %%% @end @@ -62,12 +62,12 @@ -type error(Type) :: {'error', Type}. -type error() :: error('resource_not_available'). - %% Server operations --spec new_connection(kz_data:connection()) -> error(). --spec format_error(error(A)) -> error(A). +-spec new_connection(map()) -> error(). new_connection(_Map) -> {'error', 'resource_not_available'}. + +-spec format_error(error(A)) -> error(A). format_error(Error) -> Error. diff --git a/core/kazoo_data/src/kz_data.erl b/core/kazoo_data/src/kz_data.erl index 18b4ef04b1d..8eaee397241 100644 --- a/core/kazoo_data/src/kz_data.erl +++ b/core/kazoo_data/src/kz_data.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% data adapter behaviour %%% @end @@ -10,16 +10,20 @@ -include("kz_data.hrl"). -type connection() :: server() | any(). --type options() :: kz_proplist(). +-type option() :: {atom(), term()}. +-type options() :: [option()]. -type document() :: kz_json:object(). -type documents() :: [document()]. --export_type([connection/0, options/0, document/0, documents/0]). +-export_type([connection/0 + ,option/0, options/0 + ,document/0 + ,documents/0 + ]). --callback new_connection(ne_binary()) -> connection(). +-callback new_connection(map()) -> connection(). -callback format_error(any()) -> any(). - %% Connection operations -callback get_db(connection(), ne_binary()) -> any(). -callback server_url(connection()) -> diff --git a/core/kazoo_data/src/kz_data.hrl b/core/kazoo_data/src/kz_data.hrl index d377acef155..b8b36b060c1 100644 --- a/core/kazoo_data/src/kz_data.hrl +++ b/core/kazoo_data/src/kz_data.hrl @@ -129,9 +129,5 @@ -define(MAX_BULK_INSERT, 2000). --define(VALID_DBNAME, is_binary(DbName) - andalso byte_size(DbName) > 0 - ). - -define(KZ_DATA_HRL, 'true'). -endif. diff --git a/core/kazoo_data/src/kz_dataconnection.erl b/core/kazoo_data/src/kz_dataconnection.erl index 2e5b65b1192..436dd7362d6 100644 --- a/core/kazoo_data/src/kz_dataconnection.erl +++ b/core/kazoo_data/src/kz_dataconnection.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_data/src/kz_dataconnection_sup.erl b/core/kazoo_data/src/kz_dataconnection_sup.erl index 3c92f5a207b..609dab06e63 100644 --- a/core/kazoo_data/src/kz_dataconnection_sup.erl +++ b/core/kazoo_data/src/kz_dataconnection_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_data/src/kz_dataconnections.erl b/core/kazoo_data/src/kz_dataconnections.erl index 5e0d16838ec..97f5b42c8d5 100644 --- a/core/kazoo_data/src/kz_dataconnections.erl +++ b/core/kazoo_data/src/kz_dataconnections.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_data/src/kz_datamgr.erl b/core/kazoo_data/src/kz_datamgr.erl index 560fc67fdb9..5be991a03f0 100644 --- a/core/kazoo_data/src/kz_datamgr.erl +++ b/core/kazoo_data/src/kz_datamgr.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% Manage data connections %%% @end @@ -33,11 +33,13 @@ -export([save_doc/2, save_doc/3 ,save_docs/2, save_docs/3 ,open_cache_doc/2, open_cache_doc/3 + ,open_cache_docs/2, open_cache_docs/3 ,update_cache_doc/3 ,flush_cache_doc/2, flush_cache_doc/3 ,flush_cache_docs/0, flush_cache_docs/1 ,add_to_doc_cache/3 ,open_doc/2,open_doc/3 + ,open_docs/2, open_docs/3 ,del_doc/2, del_docs/2 ,del_doc/3, del_docs/3 ,lookup_doc_rev/2, lookup_doc_rev/3 @@ -90,11 +92,16 @@ -include("kz_data.hrl"). +-define(VALID_DBNAME(DbName), + is_binary(DbName) + andalso byte_size(DbName) > 0). + -define(UUID_SIZE, 16). %%%=================================================================== %%% Couch Functions %%%=================================================================== + %%-------------------------------------------------------------------- %% @public %% @doc @@ -129,7 +136,7 @@ load_doc_from_file(DbName, App, File) -> -spec update_doc_from_file(ne_binary(), atom(), nonempty_string() | ne_binary()) -> {'ok', kz_json:object()} | data_error(). -update_doc_from_file(DbName, App, File) when ?VALID_DBNAME -> +update_doc_from_file(DbName, App, File) when ?VALID_DBNAME(DbName) -> Path = list_to_binary([code:priv_dir(App), "/couchdb/", File]), lager:debug("update db ~s from CouchDB file: ~s", [DbName, Path]), try @@ -288,7 +295,7 @@ do_load_fixtures_from_folder(DbName, [F|Fs]) -> %% @end %%-------------------------------------------------------------------- -spec db_exists(text()) -> boolean(). -db_exists(DbName) when ?VALID_DBNAME -> +db_exists(DbName) when ?VALID_DBNAME(DbName) -> kzs_db:db_exists(kzs_plan:plan(DbName), DbName); db_exists(DbName) -> case maybe_convert_dbname(DbName) of @@ -300,13 +307,12 @@ db_exists(DbName) -> db_exists(DbName, 'undefined') -> db_exists(DbName); db_exists(DbName, Type) - when ?VALID_DBNAME - andalso is_binary(Type) -> + when ?VALID_DBNAME(DbName), is_binary(Type) -> case add_doc_type_from_view(Type, []) of [] -> db_exists(DbName, [{'doc_type', Type}]); Options -> db_exists(DbName, Options) end; -db_exists(DbName, Options) when ?VALID_DBNAME -> +db_exists(DbName, Options) when ?VALID_DBNAME(DbName) -> kzs_db:db_exists(kzs_plan:plan(DbName, Options), DbName); db_exists(DbName, Options) -> case maybe_convert_dbname(DbName) of @@ -321,7 +327,7 @@ db_exists(DbName, Options) -> %% @end %%-------------------------------------------------------------------- -spec db_exists_all(text()) -> boolean(). -db_exists_all(DbName) when ?VALID_DBNAME -> +db_exists_all(DbName) when ?VALID_DBNAME(DbName) -> kzs_db:db_exists_all(kzs_plan:plan(DbName), DbName); db_exists_all(DbName) -> case maybe_convert_dbname(DbName) of @@ -348,7 +354,7 @@ db_info() -> %%-------------------------------------------------------------------- -spec db_info(text()) -> {'ok', kz_json:object()} | data_error(). -db_info(DbName) when ?VALID_DBNAME -> +db_info(DbName) when ?VALID_DBNAME(DbName) -> kzs_db:db_info(kzs_plan:plan(DbName), DbName); db_info(DbName) -> case maybe_convert_dbname(DbName) of @@ -366,7 +372,7 @@ db_info(DbName) -> {'ok', kz_json:object()} | data_error(). -design_info(DbName, DesignName) when ?VALID_DBNAME -> +design_info(DbName, DesignName) when ?VALID_DBNAME(DbName) -> kzs_view:design_info(kzs_plan:plan(DbName, DesignName), DbName, DesignName); design_info(DbName, DesignName) -> case maybe_convert_dbname(DbName) of @@ -376,7 +382,7 @@ design_info(DbName, DesignName) -> -spec design_compact(ne_binary(), ne_binary()) -> boolean(). -design_compact(DbName, DesignName) when ?VALID_DBNAME-> +design_compact(DbName, DesignName) when ?VALID_DBNAME(DbName)-> kzs_view:design_compact(kzs_plan:plan(DbName, DesignName), DbName, DesignName); design_compact(DbName, DesignName) -> case maybe_convert_dbname(DbName) of @@ -386,7 +392,7 @@ design_compact(DbName, DesignName) -> -spec db_view_cleanup(ne_binary()) -> boolean(). -db_view_cleanup(DbName) when ?VALID_DBNAME -> +db_view_cleanup(DbName) when ?VALID_DBNAME(DbName) -> kzs_db:db_view_cleanup(kzs_plan:plan(DbName), DbName); db_view_cleanup(DbName) -> case maybe_convert_dbname(DbName) of @@ -400,7 +406,7 @@ db_view_cleanup(DbName) -> db_view_update(DbName, Views) -> db_view_update(DbName, Views, 'false'). -db_view_update(DbName, Views0, Remove) when ?VALID_DBNAME -> +db_view_update(DbName, Views0, Remove) when ?VALID_DBNAME(DbName) -> Views = lists:keymap(fun maybe_adapt_multilines/1, 2, Views0), kzs_db:db_view_update(kzs_plan:plan(DbName), DbName, Views, Remove); db_view_update(DbName, Views, Remove) -> @@ -462,7 +468,7 @@ db_replicate(JObj) -> db_create(DbName) -> db_create(DbName, []). -db_create(DbName, Options) when ?VALID_DBNAME -> +db_create(DbName, Options) when ?VALID_DBNAME(DbName) -> kzs_db:db_create(kzs_plan:plan(DbName), DbName, Options); db_create(DbName, Options) -> case maybe_convert_dbname(DbName) of @@ -478,7 +484,7 @@ db_create(DbName, Options) -> %%-------------------------------------------------------------------- -spec db_compact(text()) -> boolean(). -db_compact(DbName) when ?VALID_DBNAME -> +db_compact(DbName) when ?VALID_DBNAME(DbName) -> kzs_db:db_compact(kzs_plan:plan(DbName), DbName); db_compact(DbName) -> case maybe_convert_dbname(DbName) of @@ -493,7 +499,7 @@ db_compact(DbName) -> %% @end %%-------------------------------------------------------------------- -spec db_delete(text()) -> 'ok' | data_error(). -db_delete(DbName) when ?VALID_DBNAME -> +db_delete(DbName) when ?VALID_DBNAME(DbName) -> kzs_db:db_delete(kzs_plan:plan(DbName), DbName); db_delete(DbName) -> case maybe_convert_dbname(DbName) of @@ -513,7 +519,7 @@ db_archive(DbName) -> Folder = kapps_config:get(?CONFIG_CAT, <<"default_archive_folder">>, <<"/tmp">>), db_archive(DbName, filename:join([<>])). -db_archive(DbName, Filename) when ?VALID_DBNAME -> +db_archive(DbName, Filename) when ?VALID_DBNAME(DbName) -> kzs_db:db_archive(kzs_plan:plan(DbName), DbName, Filename); db_archive(DbName, Filename) -> case maybe_convert_dbname(DbName) of @@ -522,7 +528,7 @@ db_archive(DbName, Filename) -> end. -spec db_import(ne_binary(), file:filename_all()) -> 'ok' | data_error(). -db_import(DbName, ArchiveFile) when ?VALID_DBNAME -> +db_import(DbName, ArchiveFile) when ?VALID_DBNAME(DbName) -> kzs_db:db_import(kzs_plan:plan(DbName), DbName, ArchiveFile); db_import(DbName, ArchiveFile) -> case maybe_convert_dbname(DbName) of @@ -556,7 +562,7 @@ open_cache_doc(DbName, DocId) -> open_cache_doc(DbName, {DocType, DocId}, Options) -> open_cache_doc(DbName, DocId, maybe_add_doc_type(DocType, Options)); -open_cache_doc(DbName, DocId, Options) when ?VALID_DBNAME -> +open_cache_doc(DbName, DocId, Options) when ?VALID_DBNAME(DbName) -> kzs_cache:open_cache_doc(DbName, DocId, Options); open_cache_doc(DbName, DocId, Options) -> case maybe_convert_dbname(DbName) of @@ -567,7 +573,7 @@ open_cache_doc(DbName, DocId, Options) -> -spec add_to_doc_cache(text(), ne_binary(), kz_json:object()) -> {'ok', kz_json:objects()} | data_error(). -add_to_doc_cache(DbName, DocId, Doc) when ?VALID_DBNAME -> +add_to_doc_cache(DbName, DocId, Doc) when ?VALID_DBNAME(DbName) -> kzs_cache:add_to_doc_cache(DbName, DocId, Doc); add_to_doc_cache(DbName, DocId, Doc) -> case maybe_convert_dbname(DbName) of @@ -605,7 +611,7 @@ flush_cache_doc(DbName, Doc) -> -spec flush_cache_doc(ne_binary(), ne_binary() | kz_json:object(), kz_proplist()) -> 'ok' | {'error', 'invalid_db_name'}. -flush_cache_doc(DbName, Doc, Options) when ?VALID_DBNAME -> +flush_cache_doc(DbName, Doc, Options) when ?VALID_DBNAME(DbName) -> kzs_cache:flush_cache_doc(DbName, Doc, Options); flush_cache_doc(DbName, Doc, Options) -> case maybe_convert_dbname(DbName) of @@ -644,7 +650,7 @@ open_doc(DbName, DocId) -> open_doc(DbName, {DocType, DocId}, Options) -> open_doc(DbName, DocId, maybe_add_doc_type(DocType, Options)); -open_doc(DbName, DocId, Options) when ?VALID_DBNAME -> +open_doc(DbName, DocId, Options) when ?VALID_DBNAME(DbName) -> kzs_doc:open_doc(kzs_plan:plan(DbName, Options), DbName, DocId, Options); open_doc(DbName, DocId, Options) -> case maybe_convert_dbname(DbName) of @@ -652,6 +658,61 @@ open_doc(DbName, DocId, Options) -> {'error', _}=E -> E end. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Open documents given doc ids returns an error tuple or the json. +%% Each returned JObj contains either an <<"doc">> or <<"error">> field. +%% So: match both error tuple & each JSON of the list. +%% @end +%%-------------------------------------------------------------------- +-spec open_docs(text(), docids()) -> + {'ok', kz_json:objects()} | + data_error() | + {'error', 'not_found'}. +-spec open_docs(text(), docids(), kz_proplist()) -> + {'ok', kz_json:objects()} | + data_error() | + {'error', 'not_found'}. + +open_docs(DbName, DocIds) -> + open_docs(DbName, DocIds, []). + +open_docs(DbName, DocIds, Options) -> + NewOptions = [{keys, DocIds}, include_docs | Options], + all_docs(DbName, NewOptions). + +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Open documents given doc ids returns an error tuple or the json. +%% Attempts to fetch from cache before making an ad-hoc bulk read. +%% Each returned JObj contains either an <<"doc">> or <<"error">> field. +%% So: match both error tuple & each JSON of the list. +%% Note: no guaranty on order of results is provided. +%% @end +%%-------------------------------------------------------------------- +-spec open_cache_docs(text(), docids()) -> + {'ok', kz_json:objects()} | + data_error() | + {'error', 'not_found'}. +-spec open_cache_docs(text(), docids(), kz_proplist()) -> + {'ok', kz_json:objects()} | + data_error() | + {'error', 'not_found'}. + +open_cache_docs(DbName, DocIds) -> + open_cache_docs(DbName, DocIds, []). + +open_cache_docs(DbName, DocIds, Options) when ?VALID_DBNAME(DbName) -> + kzs_cache:open_cache_docs(DbName, DocIds, Options); +open_cache_docs(DbName, DocIds, Options) -> + case maybe_convert_dbname(DbName) of + {'ok', Db} -> open_cache_docs(Db, DocIds, Options); + {'error', _}=E -> E + end. + + -spec all_docs(text()) -> {'ok', kz_json:objects()} | data_error(). @@ -662,7 +723,7 @@ open_doc(DbName, DocId, Options) -> all_docs(DbName) -> all_docs(DbName, []). -all_docs(DbName, Options) when ?VALID_DBNAME -> +all_docs(DbName, Options) when ?VALID_DBNAME(DbName) -> kzs_view:all_docs(kzs_plan:plan(DbName, Options), DbName, Options); all_docs(DbName, Options) -> case maybe_convert_dbname(DbName) of @@ -687,7 +748,7 @@ db_list(Options) -> all_design_docs(DbName) -> all_design_docs(DbName, []). -all_design_docs(DbName, Options) when ?VALID_DBNAME -> +all_design_docs(DbName, Options) when ?VALID_DBNAME(DbName) -> kzs_view:all_design_docs(kzs_plan:plan(DbName), DbName, Options); all_design_docs(DbName, Options) -> case maybe_convert_dbname(DbName) of @@ -713,7 +774,7 @@ lookup_doc_rev(DbName, DocId) -> {'ok', ne_binary()} | data_error(). lookup_doc_rev(DbName, {DocType, DocId}, Options) -> lookup_doc_rev(DbName, DocId, maybe_add_doc_type(DocType, Options)); -lookup_doc_rev(DbName, DocId, Options) when ?VALID_DBNAME -> +lookup_doc_rev(DbName, DocId, Options) when ?VALID_DBNAME(DbName) -> kzs_doc:lookup_doc_rev(kzs_plan:plan(DbName, Options), DbName, DocId); lookup_doc_rev(DbName, DocId, Options) -> case maybe_convert_dbname(DbName) of @@ -752,7 +813,7 @@ save_doc(DbName, Doc) -> ensure_saved(DbName, Doc) -> ensure_saved(DbName, Doc, []). -ensure_saved(DbName, Doc, Options) when ?VALID_DBNAME -> +ensure_saved(DbName, Doc, Options) when ?VALID_DBNAME(DbName) -> kzs_doc:ensure_saved(kzs_plan:plan(DbName, Doc), DbName, Doc, Options); ensure_saved(DbName, Doc, Options) -> case maybe_convert_dbname(DbName) of @@ -763,7 +824,7 @@ ensure_saved(DbName, Doc, Options) -> -spec save_doc(text(), kz_json:object(), kz_proplist()) -> {'ok', kz_json:object()} | data_error(). -save_doc(DbName, Doc, Options) when ?VALID_DBNAME -> +save_doc(DbName, Doc, Options) when ?VALID_DBNAME(DbName) -> OldSetting = maybe_toggle_publish(Options), Result = kzs_doc:save_doc(kzs_plan:plan(DbName, Doc), DbName, Doc, Options), maybe_revert_publish(OldSetting), @@ -800,8 +861,8 @@ maybe_revert_publish('false') -> save_docs(DbName, Docs) when is_list(Docs) -> save_docs(DbName, Docs, []). -save_docs(DbName, [Doc|_]=Docs, Options) when is_list(Docs) - andalso ?VALID_DBNAME -> +save_docs(DbName, [Doc|_]=Docs, Options) + when is_list(Docs), ?VALID_DBNAME(DbName) -> OldSetting = maybe_toggle_publish(Options), Result = kzs_doc:save_docs(kzs_plan:plan(DbName, Doc), DbName, Docs, Options), maybe_revert_publish(OldSetting), @@ -859,7 +920,7 @@ del_doc(DbName, Doc) -> data_error(). del_doc(DbName, Doc, Options) when is_list(Doc) -> del_docs(DbName, Doc, Options); -del_doc(DbName, Doc, Options) when ?VALID_DBNAME -> +del_doc(DbName, Doc, Options) when ?VALID_DBNAME(DbName) -> kzs_doc:del_doc(kzs_plan:plan(DbName, Doc), DbName, Doc, Options); del_doc(DbName, Doc, Options) -> case maybe_convert_dbname(DbName) of @@ -882,8 +943,8 @@ del_docs(DbName, Docs) -> -spec del_docs(text(), kz_json:objects() | ne_binaries(), kz_proplist()) -> {'ok', kz_json:objects()} | data_error(). -del_docs(DbName, Docs, Options) when is_list(Docs) - andalso ?VALID_DBNAME -> +del_docs(DbName, Docs, Options) + when is_list(Docs), ?VALID_DBNAME(DbName) -> kzs_doc:del_docs(kzs_plan:plan(DbName), DbName, Docs, Options); del_docs(DbName, Docs, Options) when is_list(Docs) -> case maybe_convert_dbname(DbName) of @@ -894,6 +955,7 @@ del_docs(DbName, Docs, Options) when is_list(Docs) -> %%%=================================================================== %%% Attachment Functions %%%=================================================================== + -spec fetch_attachment(text(), docid(), ne_binary()) -> {'ok', binary()} | data_error(). @@ -906,9 +968,9 @@ fetch_attachment(DbName, {DocType, DocId}, AName) -> fetch_attachment(DbName, DocId, AName) -> fetch_attachment(DbName, DocId, AName, []). -fetch_attachment(DbName, {DocType, DocId}, AName, Options) when ?VALID_DBNAME -> +fetch_attachment(DbName, {DocType, DocId}, AName, Options) when ?VALID_DBNAME(DbName) -> fetch_attachment(DbName, DocId, AName, maybe_add_doc_type(DocType, Options)); -fetch_attachment(DbName, DocId, AName, Options) when ?VALID_DBNAME -> +fetch_attachment(DbName, DocId, AName, Options) when ?VALID_DBNAME(DbName) -> kzs_attachments:fetch_attachment(kzs_plan:plan(DbName, Options), DbName, DocId, AName); fetch_attachment(DbName, DocId, AName, Options) -> case maybe_convert_dbname(DbName) of @@ -931,9 +993,9 @@ stream_attachment(DbName, DocId, AName, Options) -> -spec stream_attachment(text(), docid(), ne_binary(), kz_proplist(), pid()) -> {'ok', reference()} | {'error', any()}. -stream_attachment(DbName, {DocType, DocId}, AName, Options, Pid) when ?VALID_DBNAME -> +stream_attachment(DbName, {DocType, DocId}, AName, Options, Pid) when ?VALID_DBNAME(DbName) -> stream_attachment(DbName, DocId, AName, maybe_add_doc_type(DocType, Options), Pid); -stream_attachment(DbName, DocId, AName, Options, Pid) when ?VALID_DBNAME -> +stream_attachment(DbName, DocId, AName, Options, Pid) when ?VALID_DBNAME(DbName) -> kzs_attachments:stream_attachment(kzs_plan:plan(DbName, Options), DbName, DocId, AName, Pid); stream_attachment(DbName, DocId, AName, Options, Pid) -> case maybe_convert_dbname(DbName) of @@ -953,7 +1015,7 @@ put_attachment(DbName, DocId, AName, Contents) -> put_attachment(DbName, {DocType, DocId}, AName, Contents, Options) -> put_attachment(DbName, DocId, AName, Contents, maybe_add_doc_type(DocType, Options)); -put_attachment(DbName, DocId, AName, Contents, Options) when ?VALID_DBNAME -> +put_attachment(DbName, DocId, AName, Contents, Options) when ?VALID_DBNAME(DbName) -> case attachment_options(DbName, DocId, Options) of {'ok', NewOptions} -> kzs_attachments:put_attachment(kzs_plan:plan(DbName, NewOptions) ,DbName @@ -979,7 +1041,7 @@ put_attachment(DbName, DocId, AName, Contents, Options) -> delete_attachment(DbName, DocId, AName) -> delete_attachment(DbName, DocId, AName, []). -delete_attachment(DbName, DocId, AName, Options) when ?VALID_DBNAME -> +delete_attachment(DbName, DocId, AName, Options) when ?VALID_DBNAME(DbName) -> kzs_attachments:delete_attachment(kzs_plan:plan(DbName, DocId), DbName, DocId, AName, Options); delete_attachment(DbName, DocId, AName, Options) -> case maybe_convert_dbname(DbName) of @@ -998,9 +1060,9 @@ delete_attachment(DbName, DocId, AName, Options) -> attachment_url(DbName, DocId, AttachmentId) -> attachment_url(DbName, DocId, AttachmentId, []). -attachment_url(DbName, {DocType, DocId}, AttachmentId, Options) when ?VALID_DBNAME -> +attachment_url(DbName, {DocType, DocId}, AttachmentId, Options) when ?VALID_DBNAME(DbName) -> attachment_url(DbName, DocId, AttachmentId, maybe_add_doc_type(DocType, Options)); -attachment_url(DbName, DocId, AttachmentId, Options) when ?VALID_DBNAME -> +attachment_url(DbName, DocId, AttachmentId, Options) when ?VALID_DBNAME(DbName) -> Plan = kzs_plan:plan(DbName, Options), case kzs_doc:open_doc(Plan, DbName, DocId, props:delete('plan_override', Options)) of {'ok', JObj} -> @@ -1020,6 +1082,7 @@ attachment_url(DbName, DocId, AttachmentId, Options) -> %%%=================================================================== %%% Attachment Helper Functions %%%=================================================================== + attachment_options(DbName, DocId, Options) -> RequiredOptions = [{'doc_type', fun kz_doc:type/1} ,{'rev', fun kz_doc:revision/1} @@ -1033,14 +1096,12 @@ attachment_options(DbName, DocId, Options, RequiredOptions) -> end end, case maybe_add_required_options(Options, RequiredOptions, Fun) of - {'ok', _} = Ok -> Ok; - {'error', _} = Error -> log_attachment_options(Error) + {'ok', _}=Ok -> Ok; + {'error', _Missing}=Error -> + lager:error("missing required options: ~p", [_Missing]), + Error end. -log_attachment_options({'error', Missing}=Error) -> - lager:error("missing required options : ~p", [Missing]), - Error. - maybe_add_required_options(Options, RequiredOptions, Fun) -> case has_required_options(Options, RequiredOptions) of 'true' -> {'ok', Options}; @@ -1079,6 +1140,7 @@ add_required_option({Key, Fun}, {JObj, Options}=Acc) -> %%%=================================================================== %%% View Functions %%%=================================================================== + %%-------------------------------------------------------------------- %% @public %% @doc @@ -1098,9 +1160,18 @@ get_all_results(DbName, DesignDoc) -> get_results(DbName, DesignDoc) -> get_results(DbName, DesignDoc, []). -get_results(DbName, DesignDoc, Options) when ?VALID_DBNAME -> +get_results(DbName, DesignDoc, Options) when ?VALID_DBNAME(DbName) -> Opts = maybe_add_doc_type_from_view(DesignDoc, Options), - kzs_view:get_results(kzs_plan:plan(DbName, Opts), DbName, DesignDoc, Options); + Plan = kzs_plan:plan(DbName, Opts), + + case kzs_view:get_results(Plan, DbName, DesignDoc, Options) of + {'error', 'not_found'} -> + maybe_create_view(DbName, Plan, DesignDoc, Options); + + Other -> + Other + end; + get_results(DbName, DesignDoc, Options) -> case maybe_convert_dbname(DbName) of {'ok', Db} -> get_results(Db, DesignDoc, Options); @@ -1111,6 +1182,17 @@ get_results_count(DbName, DesignDoc, Options) -> Opts = maybe_add_doc_type_from_view(DesignDoc, Options), kzs_view:get_results_count(kzs_plan:plan(DbName, Opts), DbName, DesignDoc, Options). +-spec maybe_create_view(ne_binary(), map(), ne_binary(), view_options()) -> get_results_return(). +maybe_create_view(DbName, Plan, DesignDoc, Options) -> + case props:get_value('view_json', Options) of + 'undefined' -> + {'error', 'not_found'}; + + ViewJson -> + db_view_update(DbName, ViewJson), + kzs_view:get_results(Plan, DbName, DesignDoc, Options) + end. + -spec get_result_keys(ne_binary(), ne_binary(), view_options()) -> {'ok', ne_binaries()} | data_error(). get_result_keys(DbName, DesignDoc, Options) -> @@ -1166,6 +1248,7 @@ get_uuids(Count, Size) -> [get_uuid(Size) || _ <- lists:seq(1, Count)]. %%%=================================================================== %%% Misc functions %%%=================================================================== + -spec suppress_change_notice() -> 'false'. suppress_change_notice() -> put('$kz_data_change_notice', 'false'). @@ -1182,7 +1265,6 @@ change_notice() -> end. - %%%=================================================================== %%% Internal functions %%%=================================================================== diff --git a/core/kazoo_data/src/kzs_attachments.erl b/core/kazoo_data/src/kzs_attachments.erl index 24e63b44fee..34a75372144 100644 --- a/core/kazoo_data/src/kzs_attachments.erl +++ b/core/kazoo_data/src/kzs_attachments.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% data adapter behaviour %%% @end @@ -131,7 +131,7 @@ put_attachment(#{server := {App, Conn}}, DbName, DocId, AName, Contents, Options attachment_from_handler(AName, AttHandler, Size, CT) -> Props = [{<<"content_type">>, kz_util:to_binary(CT)} ,{<<"length">>, Size} - ,{<<"stub">>, false} + ,{<<"stub">>, 'false'} ,{<<"handler">>, AttHandler} ], kz_json:set_value(AName, kz_json:from_list(Props), kz_json:new()). diff --git a/core/kazoo_data/src/kzs_cache.erl b/core/kazoo_data/src/kzs_cache.erl index b7fbcd7a3eb..e8ccf899648 100644 --- a/core/kazoo_data/src/kzs_cache.erl +++ b/core/kazoo_data/src/kzs_cache.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% data adapter behaviour %%% @end @@ -7,10 +7,9 @@ %%%----------------------------------------------------------------------------- -module(kzs_cache). - - %% Doc related -export([open_cache_doc/3, open_cache_doc/4 + ,open_cache_docs/3 ,add_to_doc_cache/3 ,flush_cache_doc/2 ,flush_cache_doc/3 @@ -51,16 +50,16 @@ open_cache_doc(DbName, DocId, Options) -> {'ok', {'error', _}=E} -> E; {'ok', _}=Ok -> Ok; {'error', 'not_found'} -> - case kz_datamgr:open_doc(DbName, DocId, remove_cache_options(Options)) of - {'error', _}=E -> - maybe_cache_failure(DbName, DocId, Options, E), - E; - {'ok', JObj}=Ok -> - add_to_doc_cache(DbName, DocId, JObj), - Ok - end + R = kz_datamgr:open_doc(DbName, DocId, remove_cache_options(Options)), + _ = maybe_cache(DbName, DocId, Options, R), + R end. +maybe_cache(DbName, DocId, Options, {error, _}=E) -> + maybe_cache_failure(DbName, DocId, Options, E); +maybe_cache(DbName, DocId, _, {ok, JObj}) -> + add_to_doc_cache(DbName, DocId, JObj). + -spec open_cache_doc(map(), text(), ne_binary(), kz_proplist()) -> {'ok', kz_json:object()} | data_error() | @@ -70,16 +69,75 @@ open_cache_doc(Server, DbName, DocId, Options) -> {'ok', {'error', _}=E} -> E; {'ok', _}=Ok -> Ok; {'error', 'not_found'} -> - case kzs_doc:open_doc(Server, DbName, DocId, remove_cache_options(Options)) of - {'error', _}=E -> - maybe_cache_failure(DbName, DocId, Options, E), - E; - {'ok', JObj}=Ok -> - add_to_doc_cache(DbName, DocId, JObj), - Ok - end + R = kzs_doc:open_doc(Server, DbName, DocId, remove_cache_options(Options)), + _ = maybe_cache(DbName, DocId, Options, R), + R + end. + +-spec open_cache_docs(text(), ne_binaries(), kz_proplist()) -> + {'ok', kz_json:objects()} | + data_error(). +open_cache_docs(DbName, DocIds, Options) -> + {Cached, MissedDocIds} = fetch_locals(DbName, DocIds), + lager:debug("misses ~p", [MissedDocIds]), + JObjs1 = assemble_jobjs(Cached), + case kz_datamgr:open_docs(DbName, MissedDocIds, remove_cache_options(Options)) of + {error, _}=E -> E; + {ok, JObjs} -> + JObjs2 = assemble_jobjs(JObjs1, disassemble_jobjs(DbName, Options, JObjs)), + {ok, JObjs2} end. +fetch_locals(DbName, DocIds) -> + F = fun (DocId, {Cached, Missed}) -> + case kz_cache:fetch_local(?CACHE_NAME, {?MODULE, DbName, DocId}) of + {error, not_found} -> {Cached, [DocId|Missed]}; + {ok, {error, Reason}} -> + {[{DocId, error, Reason}|Cached], Missed}; + {ok, Doc} -> + {[{DocId, ok, Doc}|Cached], Missed} + end + end, + lists:foldl(F, {[], []}, DocIds). + +-type docs_returned() :: [{ne_binary(), ok, kz_json:object()} | + {ne_binary(), error, ne_binary()} + ]. +-spec disassemble_jobjs(ne_binary(), kz_proplist(), kz_json:objects()) -> docs_returned(). +disassemble_jobjs(DbName, Options, JObjs) -> + [case kz_json:get_ne_value(<<"doc">>, JObj) of + undefined -> + Reason = kz_json:get_ne_value(<<"error">>, JObj), + _ = maybe_cache_failure(DbName, DocId, Options, {error, Reason}), + {DocId, error, Reason}; + Doc -> + _ = add_to_doc_cache(DbName, DocId, Doc), + {DocId, ok, Doc} + end + || JObj <- JObjs, + DocId <- [kz_json:get_ne_value(<<"key">>, JObj)] + ]. + +-spec assemble_jobjs(docs_returned()) -> kz_json:objects(). +-spec assemble_jobjs(kz_json:objects(), docs_returned()) -> kz_json:objects(). +assemble_jobjs(DocsReturned) -> + assemble_jobjs([], DocsReturned). +assemble_jobjs(JObjs, DocsReturned) -> + [case Returned of + {DocId, ok, Doc} -> + kz_json:from_list( + [{<<"key">>, DocId} + ,{<<"doc">>, Doc} + ]); + {DocId, error, Reason} -> + kz_json:from_list( + [{<<"key">>, DocId} + ,{<<"error">>, kz_util:to_atom(Reason, true)} + ]) + end + || Returned <- DocsReturned + ] ++ JObjs. + -spec remove_cache_options(kz_proplist()) -> kz_proplist(). remove_cache_options(Options) -> props:delete_keys(['cache_failures'], Options). @@ -119,11 +177,11 @@ cache_if_not_media(CacheProps, DbName, DocId, CacheValue) -> %% NOTE: this is currently necessary because when a http_put is issued to %% freeswitch and the media is uploaded it goes directly to bigcouch %% and therefore no doc change notice is pushed. This results in the - %% doc cache containing a document tha thas no attachements (or the wrong - %% attachments). What needs to happen is a change notice get sent on the + %% doc cache containing a document that has no attachements (or the wrong + %% attachments). What needs to happen is a change notice get sent on the %% message bus anytime a http_put is issued (or maybe if the store %% url is built in media IF everything uses that helper function, - % which is not currently the case...) + %% which is not currently the case...) case kzs_util:db_classification(DbName) =/= 'system' andalso lists:member(kz_doc:type(CacheValue), ?NO_CACHING_TYPES) of 'true' -> 'ok'; diff --git a/core/kazoo_data/src/kzs_db.erl b/core/kazoo_data/src/kzs_db.erl index 5a8ad5062c3..e29cb0d238d 100644 --- a/core/kazoo_data/src/kzs_db.erl +++ b/core/kazoo_data/src/kzs_db.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% data adapter behaviour %%% @end diff --git a/core/kazoo_data/src/kzs_doc.erl b/core/kazoo_data/src/kzs_doc.erl index 256bc50297f..f95229d12c2 100644 --- a/core/kazoo_data/src/kzs_doc.erl +++ b/core/kazoo_data/src/kzs_doc.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% data adapter behaviour %%% @end diff --git a/core/kazoo_data/src/kzs_perf.erl b/core/kazoo_data/src/kzs_perf.erl index 62f1bec1788..36809e0b452 100644 --- a/core/kazoo_data/src/kzs_perf.erl +++ b/core/kazoo_data/src/kzs_perf.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% Profiling diff --git a/core/kazoo_data/src/kzs_plan.erl b/core/kazoo_data/src/kzs_plan.erl index 8f31cba28b2..f4674606f23 100644 --- a/core/kazoo_data/src/kzs_plan.erl +++ b/core/kazoo_data/src/kzs_plan.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% data plan %%% @end diff --git a/core/kazoo_data/src/kzs_publish.erl b/core/kazoo_data/src/kzs_publish.erl index 3b699ae0cb2..1cf9b31dc59 100644 --- a/core/kazoo_data/src/kzs_publish.erl +++ b/core/kazoo_data/src/kzs_publish.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% data adapter behaviour %%% @end diff --git a/core/kazoo_data/src/kzs_server.erl b/core/kazoo_data/src/kzs_server.erl index 7bea5a6f6d0..f0558d041d9 100644 --- a/core/kazoo_data/src/kzs_server.erl +++ b/core/kazoo_data/src/kzs_server.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% data adapter behaviour %%% @end diff --git a/core/kazoo_data/src/kzs_util.erl b/core/kazoo_data/src/kzs_util.erl index 78e25d82eb1..08bd08ed2cf 100644 --- a/core/kazoo_data/src/kzs_util.erl +++ b/core/kazoo_data/src/kzs_util.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% kazoo data utils %%% @end @@ -69,7 +69,7 @@ db_classification(?MATCH_ACCOUNT_encoded(_AccountId)) -> 'account'; db_classification(?MATCH_ACCOUNT_ENCODED(_AccountId)) -> 'account'; db_classification(_Database) -> lager:warning("unknown type for database ~s", [_Database]), - lager:debug("unknown database classification : ~p", [erlang:process_info(self(),current_stacktrace)]), + lager:debug("unknown database classification: ~p", [erlang:process_info(self(),current_stacktrace)]), 'undefined'. %%------------------------------------------------------------------------------ diff --git a/core/kazoo_data/src/kzs_view.erl b/core/kazoo_data/src/kzs_view.erl index ead275f93cc..ff00d0c2c3d 100644 --- a/core/kazoo_data/src/kzs_view.erl +++ b/core/kazoo_data/src/kzs_view.erl @@ -1,5 +1,5 @@ %%%----------------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% data adapter behaviour %%% @end diff --git a/core/kazoo_documents/src/kz_account.erl b/core/kazoo_documents/src/kz_account.erl index 0d961a73c83..8297d4ab575 100644 --- a/core/kazoo_documents/src/kz_account.erl +++ b/core/kazoo_documents/src/kz_account.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Account document %%% @end @@ -59,6 +59,9 @@ -define(API_KEY, <<"pvt_api_key">>). -define(IS_SUPERDUPER_ADMIN, <<"pvt_superduper_admin">>). -define(ALLOW_NUMBER_ADDITIONS, <<"pvt_wnm_allow_additions">>). +-define(NOTIFY_CONFIG, <<"notifications">>). +-define(NOTIFY_VM_TO_EMAIL, [?NOTIFY_CONFIG, <<"voicemail_to_email">>]). +-define(NOTIFY_FAX_TO_EMAIL, [?NOTIFY_CONFIG, <<"fax_to_email">>]). -define(NOTIFY_PREF, <<"pvt_notification_preference">>). -define(KEY_TRIAL_EXPIRATION, <<"pvt_trial_expires">>). -define(KEY_TRIAL_ACCOUNT, <<"is_trial_account">>). @@ -435,7 +438,29 @@ set_tree(JObj, Tree) -> %%-------------------------------------------------------------------- -spec notification_preference(doc()) -> api_binary(). notification_preference(JObj) -> - kz_json:get_value(?NOTIFY_PREF, JObj). + Pref = notification_preference(JObj, [ + ?NOTIFY_PREF + ,?NOTIFY_VM_TO_EMAIL + ,?NOTIFY_FAX_TO_EMAIL + ]), + + case Pref of + 'undefined' -> 'undefined'; + <<"teletype">> -> <<"teletype">>; + _Default -> <<"notify">> + end. + +-spec notification_preference(doc(), list()) -> api_binary(). +notification_preference(_JObj, []) -> + 'undefined'; + +notification_preference(JObj, [H|T]) -> + case kz_json:get_ne_value(H, JObj) of + 'undefined' -> + notification_preference(JObj, T); + Value -> + Value + end. %%-------------------------------------------------------------------- %% @public diff --git a/core/kazoo_documents/src/kz_attachment.erl b/core/kazoo_documents/src/kz_attachment.erl index 6c8e6ca43e2..a429d340739 100644 --- a/core/kazoo_documents/src/kz_attachment.erl +++ b/core/kazoo_documents/src/kz_attachment.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Account document %%% @end diff --git a/core/kazoo_documents/src/kz_call_event.erl b/core/kazoo_documents/src/kz_call_event.erl index aa501a96bc7..e84f083b46e 100644 --- a/core/kazoo_documents/src/kz_call_event.erl +++ b/core/kazoo_documents/src/kz_call_event.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz +%%% @copyright (C) 2015-2017, 2600Hz %%% @doc %%% Call Event JSON Object %%% @end diff --git a/core/kazoo_documents/src/kz_device.erl b/core/kazoo_documents/src/kz_device.erl index 2084e994343..21586a7129d 100644 --- a/core/kazoo_documents/src/kz_device.erl +++ b/core/kazoo_documents/src/kz_device.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% Device document manipulation %%% @end diff --git a/core/kazoo_documents/src/kz_documents.hrl b/core/kazoo_documents/src/kz_documents.hrl index b8f3eb93546..71f2de2d7ee 100644 --- a/core/kazoo_documents/src/kz_documents.hrl +++ b/core/kazoo_documents/src/kz_documents.hrl @@ -20,6 +20,40 @@ -define(SYSTEM_FAX_SETTINGS, kz_json:set_value(?FAX_TIMEZONE_KEY, ?DEFAULT_TIMEZONE, ?DEFAULT_FAX_SETTINGS)). +-ifdef(TEST). +-define(SCHEMA_KEY1 + ,kz_json:from_list([{<<"type">>, <<"string">>}]) + ). + +-define(SCHEMA_KEY2 + ,kz_json:from_list([{<<"type">>, <<"integer">>}]) + ). + +-define(SCHEMA_KEY3 + ,kz_json:from_list([{<<"type">>, <<"string">>} + ,{<<"default">>, <<"value3">>} + ] + ) + ). + +-define(PROPERTIES_JOBJ + ,kz_json:from_list( + [{<<"key1">>, ?SCHEMA_KEY1} + ,{<<"key2">>, ?SCHEMA_KEY2} + ,{<<"key3">>, ?SCHEMA_KEY3} + ] + ) + ). + +-define(SCHEMA_JOBJ + ,kz_json:from_list( + [{<<"$schema">>, <<"http://json-schema.org/draft-04/schema#">>} + ,{<<"properties">>, ?PROPERTIES_JOBJ} + ,{<<"required">>, [<<"key1">>, <<"key2">>]} + ] + ) + ). +-endif. -define(KZ_DOCUMENTS_HRL, 'true'). -endif. diff --git a/core/kazoo_documents/src/kz_notification.erl b/core/kazoo_documents/src/kz_notification.erl index 9f8940e2458..c4cb1920365 100644 --- a/core/kazoo_documents/src/kz_notification.erl +++ b/core/kazoo_documents/src/kz_notification.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% Device document manipulation %%% @end diff --git a/core/kazoo_documents/src/kz_whitelabel.erl b/core/kazoo_documents/src/kz_whitelabel.erl index c50eadbca79..21d002a96b2 100644 --- a/core/kazoo_documents/src/kz_whitelabel.erl +++ b/core/kazoo_documents/src/kz_whitelabel.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Account document %%% @end diff --git a/core/kazoo_documents/src/kzd_agent.erl b/core/kazoo_documents/src/kzd_agent.erl index fd727225384..4f297c85307 100644 --- a/core/kazoo_documents/src/kzd_agent.erl +++ b/core/kazoo_documents/src/kzd_agent.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_documents/src/kzd_alert.erl b/core/kazoo_documents/src/kzd_alert.erl index 6939d83f8b8..7099f928acf 100644 --- a/core/kazoo_documents/src/kzd_alert.erl +++ b/core/kazoo_documents/src/kzd_alert.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz +%%% @copyright (C) 2015-2017, 2600Hz %%% @doc %%% Alert document %%% @end diff --git a/core/kazoo_documents/src/kzd_app.erl b/core/kazoo_documents/src/kzd_app.erl index 95597cf3ffc..064b582f3d0 100644 --- a/core/kazoo_documents/src/kzd_app.erl +++ b/core/kazoo_documents/src/kzd_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Account document %%% @end diff --git a/core/kazoo_documents/src/kzd_apps_store.erl b/core/kazoo_documents/src/kzd_apps_store.erl index 14af78681fb..cf8eb70b0e4 100644 --- a/core/kazoo_documents/src/kzd_apps_store.erl +++ b/core/kazoo_documents/src/kzd_apps_store.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Account document %%% @end diff --git a/core/kazoo_documents/src/kzd_audit_log.erl b/core/kazoo_documents/src/kzd_audit_log.erl index fb71ab8ae04..3dd4fdc8b2a 100644 --- a/core/kazoo_documents/src/kzd_audit_log.erl +++ b/core/kazoo_documents/src/kzd_audit_log.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Audit Log document manipulation %%% @end diff --git a/core/kazoo_documents/src/kzd_box_message.erl b/core/kazoo_documents/src/kzd_box_message.erl index 18db84f32e9..6f9f418bbf0 100644 --- a/core/kazoo_documents/src/kzd_box_message.erl +++ b/core/kazoo_documents/src/kzd_box_message.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Mailbox message document manipulation %%% @end @@ -108,11 +108,12 @@ new(AccountId, Props) -> Name = create_message_name(props:get_value(<<"Box-Num">>, Props) ,props:get_value(<<"Timezone">>, Props) ,UtcSeconds), + Description = props:get_value(<<"Description">>, Props, <<"voicemail message with media">>), DocProps = props:filter_undefined( [{<<"_id">>, MsgId} ,{?KEY_NAME, Name} - ,{?KEY_DESC, <<"mailbox message media">>} + ,{?KEY_DESC, Description} ,{?KEY_SOURCE_TYPE, ?KEY_VOICEMAIL} ,{?KEY_SOURCE_ID, props:get_value(<<"Box-Id">>, Props)} ,{?KEY_MEDIA_SOURCE, <<"recording">>} @@ -289,7 +290,7 @@ to_sip(JObj, Default) -> set_to_sip(To, Metadata) -> kz_json:set_value(?KEY_META_TO, To, Metadata). --spec utc_seconds(doc()) -> pos_integer(). +-spec utc_seconds(doc()) -> non_neg_integer(). utc_seconds(JObj) -> kz_json:get_integer_value(?KEY_UTC_SEC, JObj, 0). diff --git a/core/kazoo_documents/src/kzd_callflow.erl b/core/kazoo_documents/src/kzd_callflow.erl index 00bd4f48d70..05dd83b04ea 100644 --- a/core/kazoo_documents/src/kzd_callflow.erl +++ b/core/kazoo_documents/src/kzd_callflow.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% Callflow document manipulation %%% @end @@ -14,7 +14,9 @@ ,patterns/1, set_patterns/2 ,is_feature_code/1 ,flow/1, flow/2 - ,set_flow/2, validate_flow/1 + ,set_flow/2 + ,validate/1 + ,validate_flow/1 ]). -include("kz_documents.hrl"). @@ -30,47 +32,6 @@ -define(NUMBERS, <<"numbers">>). -define(PATTERNS, <<"patterns">>). --ifdef(TEST). --include_lib("eunit/include/eunit.hrl"). - --define(SCHEMA_KEY1 - ,kz_json:from_list([{<<"type">>, <<"string">>} - ,{<<"required">>, 'true'} - ] - ) - ). - --define(SCHEMA_KEY2 - ,kz_json:from_list([{<<"type">>, <<"integer">>} - ,{<<"required">>, 'true'} - ] - ) - ). - --define(SCHEMA_KEY3 - ,kz_json:from_list([{<<"type">>, <<"string">>} - ,{<<"required">>, 'false'} - ,{<<"default">>, <<"value3">>} - ] - ) - ). - --define(PROPERTIES_JOBJ - ,kz_json:from_list( - [{<<"key1">>, ?SCHEMA_KEY1} - ,{<<"key2">>, ?SCHEMA_KEY2} - ,{<<"key3">>, ?SCHEMA_KEY3} - ] - ) - ). - --define(SCHEMA_JOBJ - ,kz_json:from_list( - [{<<"properties">>, ?PROPERTIES_JOBJ}] - ) - ). --endif. - %%-------------------------------------------------------------------- %% @public %% @doc @@ -145,30 +106,62 @@ flow(Doc, Default) -> set_flow(Doc, Flow) -> kz_json:set_value(?FLOW, Flow, Doc). +-spec validate(doc()) -> {'ok', doc()} | + {'error', kz_json_schema:validation_errors()}. +validate(Doc) -> + case kz_json_schema:validate(<<"callflows">>, Doc) of + {'ok', ValidatedDoc} -> validate_flow(ValidatedDoc); + {'error', Errors} -> + {'error', kz_json_schema:errors_to_jobj(Errors)} + end. + -spec validate_flow(doc()) -> {'ok', doc()} | - {'error', list()}. + {'error', kz_json_schema:validation_errors()}. validate_flow(Doc) -> case validate_flow_elements(flow(Doc)) of - {Flow, []} -> - {'ok', set_flow(Doc, Flow)}; + {Flow, []} -> {'ok', set_flow(Doc, Flow)}; {_Flow, Errors} -> {'error', Errors} end. -type validate_acc() :: {kz_json:object(), [jesse_error:error_reason()]}. -spec validate_flow_elements(kz_json:object()) -> validate_acc(). +-spec validate_flow_elements(kz_json:object(), validate_acc(), ne_binaries()) -> validate_acc(). validate_flow_elements(Flow) -> validate_flow_elements(Flow, {Flow, []}, []). --spec validate_flow_elements(kz_json:object(), validate_acc(), ne_binaries()) -> validate_acc(). -validate_flow_elements(Flow, Acc, Path) -> - Module = kz_json:get_binary_value(<<"module">>, Flow), - Data = kz_json:get_json_value(<<"data">>, Flow), - Children = kz_json:get_json_value(<<"children">>, Flow, kz_json:new()), +-ifdef(TEST). +validate_flow_elements(Flow, {_RootFlow, ErrorsSoFar}=Acc, Path) -> + case kz_json_schema:validate(<<"callflows.action">> + ,Flow + ,[{'schema_loader_fun', fun kz_json_schema:fload/1} + ,{'allowed_errors', 'infinity'} + ]) + of + {'ok', ValidatedFlow} -> + Module = kz_json:get_binary_value(<<"module">>, ValidatedFlow), + Data = kz_json:get_json_value(<<"data">>, ValidatedFlow), + Children = kz_json:get_json_value(<<"children">>, ValidatedFlow, kz_json:new()), - validate_action_schema(Module, Data, Children, Acc, Path). + validate_action_schema(Module, Data, Children, Acc, Path); + {'error', Errors} -> + {Flow, update_error_key_paths(Path, Errors) ++ ErrorsSoFar} + end. +-else. +validate_flow_elements(Flow, {_RootFlow, ErrorsSoFar}=Acc, Path) -> + case kz_json_schema:validate(<<"callflows.action">>, Flow) of + {'ok', ValidatedFlow} -> + Module = kz_json:get_binary_value(<<"module">>, ValidatedFlow), + Data = kz_json:get_json_value(<<"data">>, ValidatedFlow), + Children = kz_json:get_json_value(<<"children">>, ValidatedFlow, kz_json:new()), + + validate_action_schema(Module, Data, Children, Acc, Path); + {'error', Errors} -> + {Flow, update_error_key_paths(Path, Errors) ++ ErrorsSoFar} + end. +-endif. --spec validate_action_schema(ne_binary(), kz_json:object(), kz_json:object(), validate_acc(), ne_binaries()) -> +-spec validate_action_schema(api_binary(), api_object(), kz_json:object(), validate_acc(), ne_binaries()) -> validate_acc(). validate_action_schema(Module, Data, Children, {RootFlow, ErrorsSoFar}, Path) -> {UpdatedData, Errors} = @@ -207,6 +200,9 @@ update_error_key_path(Path, {'data_invalid', SchemaJObj, Error, Value, Key}) -> validate_action_schema(Module, Data) -> validate_action_schema(Module, Data, {'ok', ?SCHEMA_JOBJ}). -else. +-spec validate_action_schema(ne_binary(), kz_json:object()) -> + {'true', kz_json:object()} | + {'false', kz_json_schema:validation_errors()}. validate_action_schema(Module, Data) -> Schema = <<"callflows.", Module/binary>>, validate_action_schema(Module, Data, kz_json_schema:load(Schema)). @@ -257,8 +253,9 @@ validate_action(<<"record_call">>, Data, SchemaJObj) -> validate_action(_Module, Data, _SchemaJObj) -> {'true', Data}. --spec maybe_fix_js_types(ne_binary(), kz_json:object(), kz_json:object(), list()) -> - {boolean(), kz_json:object() | list()}. +-spec maybe_fix_js_types(ne_binary(), kz_json:object(), kz_json:object(), kz_json_schema:validation_errors()) -> + {'true', kz_json:object()} | + {'false', kz_json_schema:validation_errors()}. maybe_fix_js_types(Module, Data, SchemaJObj, Errors) -> case maybe_fix_js_types(Data, Errors) of {'false', _} -> {'false', Errors}; @@ -288,7 +285,7 @@ maybe_fix_js_integer(Key, Value, Data) -> {'false', Data} end. --spec maybe_fix_index(kz_json:path() | kz_json:path()) -> kz_json:path() | kz_json:path(). +-spec maybe_fix_index(kz_json:path() | kz_json:path()) -> kz_json:path(). maybe_fix_index(Keys) when is_list(Keys) -> lists:map(fun(K) when is_integer(K) -> @@ -299,107 +296,3 @@ maybe_fix_index(Keys) ); maybe_fix_index(Key) -> Key. - - --ifdef(TEST). - -simple_successful_validation_test_() -> - ChildData = kz_json:from_list([{<<"key1">>, <<"value1">>} - ,{<<"key2">>, 1} - ] - ), - Child = kz_json:from_list([{<<"module">>, <<"test">>} - ,{<<"data">>, ChildData} - ] - ), - Doc = kz_json:from_list([{?FLOW, Child}]), - - {'ok', ValidatedDoc} = validate_flow(Doc), - ValidatedFlow = flow(ValidatedDoc), - - [?_assertEqual(<<"value3">>, kz_json:get_value([<<"data">>, <<"key3">>], ValidatedFlow))]. - -nested_children_test_() -> - ChildData = kz_json:from_list([{<<"key1">>, <<"value1">>} - ,{<<"key2">>, 1} - ,{<<"key3">>, <<"top">>} - ] - ), - Child = kz_json:from_list([{<<"module">>, <<"test">>} - ,{<<"data">>, ChildData} - ] - ), - - Nested = kz_json:set_value([<<"children">>, <<"_">>] - ,kz_json:delete_key([<<"data">>, <<"key3">>], Child) - ,Child - ), - - Doc = kz_json:from_list([{?FLOW, Nested}]), - - {'ok', ValidatedDoc} = validate_flow(Doc), - ValidatedFlow = flow(ValidatedDoc), - - [?_assertEqual(<<"top">>, kz_json:get_value([<<"data">>, <<"key3">>], ValidatedFlow)) - ,?_assertEqual(<<"value3">>, kz_json:get_value([<<"children">>, <<"_">>, <<"data">>, <<"key3">>], ValidatedFlow)) - ]. - -simple_failed_test_() -> - ChildData = kz_json:from_list([{<<"key1">>, 'true'} - ,{<<"key2">>, 1} - ] - ), - Child = kz_json:from_list([{<<"module">>, <<"test">>} - ,{<<"data">>, ChildData} - ] - ), - Doc = kz_json:from_list([{?FLOW, Child}]), - - {'error', Errors} = validate_flow(Doc), - [?_assertMatch([{'data_invalid', _SchemaJObj, 'wrong_type', 'true', [<<"key1">>]}], Errors)]. - -complex_failed_test_() -> - ChildData = kz_json:from_list([{<<"key2">>, 'true'}]), - Child = kz_json:from_list([{<<"module">>, <<"test">>} - ,{<<"data">>, ChildData} - ] - ), - Doc = kz_json:from_list([{?FLOW, Child}]), - - {'error', Errors} = validate_flow(Doc), - [?_assertMatch([{'data_invalid', _Key2SchemaJObj, 'wrong_type', 'true', [<<"key2">>]} - ,{'data_invalid', _Key1SchemaJObj, {'missing_required_property', <<"key1">>}, _Value, []} - ] - ,Errors - ) - ]. - -nested_children_failure_test_() -> - ChildData = kz_json:from_list([{<<"key1">>, <<"value1">>} - ,{<<"key2">>, 'true'} - ,{<<"key3">>, <<"top">>} - ] - ), - Child = kz_json:from_list([{<<"module">>, <<"test">>} - ,{<<"data">>, ChildData} - ] - ), - - Nested = kz_json:set_value([<<"children">>, <<"_">>] - ,kz_json:delete_key([<<"data">>, <<"key3">>], Child) - ,Child - ), - - Doc = kz_json:from_list([{?FLOW, Nested}]), - - {'error', Errors} = validate_flow(Doc), - - [?_assertMatch([{'data_invalid', _SchemaJObj, 'wrong_type', 'true', [<<"children">>, <<"_">>, <<"key2">>]} - ,{'data_invalid', _SchemaJObj, 'wrong_type', 'true', [<<"key2">>]} - ] - ,Errors - ) - ]. - - --endif. diff --git a/core/kazoo_documents/src/kzd_domains.erl b/core/kazoo_documents/src/kzd_domains.erl index e3ec91d2e46..5e6f4f36b72 100644 --- a/core/kazoo_documents/src/kzd_domains.erl +++ b/core/kazoo_documents/src/kzd_domains.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Domains document for white-label %%% @end diff --git a/core/kazoo_documents/src/kzd_fax.erl b/core/kazoo_documents/src/kzd_fax.erl index c54ff809177..9af0ffc2950 100644 --- a/core/kazoo_documents/src/kzd_fax.erl +++ b/core/kazoo_documents/src/kzd_fax.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% Fax document manipulation %%% @end diff --git a/core/kazoo_documents/src/kzd_fax_box.erl b/core/kazoo_documents/src/kzd_fax_box.erl index f77a23eb67b..d9495635b04 100644 --- a/core/kazoo_documents/src/kzd_fax_box.erl +++ b/core/kazoo_documents/src/kzd_fax_box.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% Device document manipulation %%% @end diff --git a/core/kazoo_documents/src/kzd_freeswitch.erl b/core/kazoo_documents/src/kzd_freeswitch.erl index ddd4466d2dc..fde86f906ae 100644 --- a/core/kazoo_documents/src/kzd_freeswitch.erl +++ b/core/kazoo_documents/src/kzd_freeswitch.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% FreeSWITCH proplists %%% @end @@ -15,7 +15,7 @@ ,dialed_number/1 ,call_id/1 ,other_leg_call_id/1 - ,call_direction/1 + ,call_direction/1, original_call_direction/1 ,resource_type/1, resource_type/2 ,channel_authorized/1 ,hunt_destination_number/1 @@ -63,7 +63,8 @@ caller_id_name(Props) -> caller_id_name(Props, 'undefined'). caller_id_name(Props, Default) -> - props:get_first_defined([<<"variable_effective_caller_id_name">> + props:get_first_defined([<<"variable_origination_caller_id_name">> + ,<<"variable_effective_caller_id_name">> ,<<"Caller-Caller-ID-Name">> ] ,Props @@ -75,7 +76,8 @@ caller_id_name(Props, Default) -> caller_id_number(Props) -> caller_id_number(Props, 'undefined'). caller_id_number(Props, Default) -> - props:get_first_defined([<<"variable_effective_caller_id_number">> + props:get_first_defined([<<"variable_origination_caller_id_number">> + ,<<"variable_effective_caller_id_number">> ,<<"Caller-Caller-ID-Number">> ] ,Props @@ -87,7 +89,8 @@ caller_id_number(Props, Default) -> callee_id_name(Props) -> callee_id_name(Props, 'undefined'). callee_id_name(Props, Default) -> - props:get_first_defined([<<"variable_effective_callee_id_name">> + props:get_first_defined([<<"variable_origination_callee_id_name">> + ,<<"variable_effective_callee_id_name">> ,<<"Caller-Callee-ID-Name">> ] ,Props @@ -99,7 +102,8 @@ callee_id_name(Props, Default) -> callee_id_number(Props) -> callee_id_number(Props, 'undefined'). callee_id_number(Props, Default) -> - props:get_first_defined([<<"variable_effective_callee_id_number">> + props:get_first_defined([<<"variable_origination_callee_id_number">> + ,<<"variable_effective_callee_id_number">> ,<<"Caller-Callee-ID-Number">> ] ,Props @@ -129,6 +133,10 @@ call_id(Props) -> other_leg_call_id(Props) -> props:get_value(<<"Other-Leg-Unique-ID">>, Props). +-spec original_call_direction(data()) -> api_binary(). +original_call_direction(Props) -> + props:get_value(<<"Call-Direction">>, Props). + -spec call_direction(data()) -> api_binary(). call_direction(Props) -> props:get_first_defined([<<"Application-Logical-Direction">> diff --git a/core/kazoo_documents/src/kzd_item_plan.erl b/core/kazoo_documents/src/kzd_item_plan.erl index e95381f8521..bae3c5ce55e 100644 --- a/core/kazoo_documents/src/kzd_item_plan.erl +++ b/core/kazoo_documents/src/kzd_item_plan.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz, INC +%%% @copyright (C) 2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_documents/src/kzd_media.erl b/core/kazoo_documents/src/kzd_media.erl index d05241e47e7..c3725eebfd6 100644 --- a/core/kazoo_documents/src/kzd_media.erl +++ b/core/kazoo_documents/src/kzd_media.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% Device document manipulation %%% @end diff --git a/core/kazoo_documents/src/kzd_schema.erl b/core/kazoo_documents/src/kzd_schema.erl index 305a4a6af3c..fac885b2b88 100644 --- a/core/kazoo_documents/src/kzd_schema.erl +++ b/core/kazoo_documents/src/kzd_schema.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% General schema manipulation %%% @end diff --git a/core/kazoo_documents/src/kzd_schema_caller_id.erl b/core/kazoo_documents/src/kzd_schema_caller_id.erl index bf11de77293..0869de6197d 100644 --- a/core/kazoo_documents/src/kzd_schema_caller_id.erl +++ b/core/kazoo_documents/src/kzd_schema_caller_id.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% General schema manipulation %%% @end diff --git a/core/kazoo_documents/src/kzd_service_plan.erl b/core/kazoo_documents/src/kzd_service_plan.erl index 2c02205b2d4..33e5a53cb92 100644 --- a/core/kazoo_documents/src/kzd_service_plan.erl +++ b/core/kazoo_documents/src/kzd_service_plan.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz, INC +%%% @copyright (C) 2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_documents/src/kzd_services.erl b/core/kazoo_documents/src/kzd_services.erl index 864a59dd81f..74f4011bcf8 100644 --- a/core/kazoo_documents/src/kzd_services.erl +++ b/core/kazoo_documents/src/kzd_services.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz, INC +%%% @copyright (C) 2015-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_documents/src/kzd_task.erl b/core/kazoo_documents/src/kzd_task.erl index ab9f59218e4..e868dda54df 100644 --- a/core/kazoo_documents/src/kzd_task.erl +++ b/core/kazoo_documents/src/kzd_task.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Task document %%% @end diff --git a/core/kazoo_documents/src/kzd_user.erl b/core/kazoo_documents/src/kzd_user.erl index a9c865dfa9d..dc58fdba3b5 100644 --- a/core/kazoo_documents/src/kzd_user.erl +++ b/core/kazoo_documents/src/kzd_user.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% Device document manipulation %%% @end diff --git a/core/kazoo_documents/src/kzd_voicemail_box.erl b/core/kazoo_documents/src/kzd_voicemail_box.erl index 95f1ad0fc73..fe9ddc12234 100644 --- a/core/kazoo_documents/src/kzd_voicemail_box.erl +++ b/core/kazoo_documents/src/kzd_voicemail_box.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% Device document manipulation %%% @end diff --git a/core/kazoo_documents/src/kzd_webhook.erl b/core/kazoo_documents/src/kzd_webhook.erl index 78fe3bf9d84..b025b01e001 100644 --- a/core/kazoo_documents/src/kzd_webhook.erl +++ b/core/kazoo_documents/src/kzd_webhook.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% Webhook document accessors diff --git a/core/kazoo_documents/test/kz_account_test.erl b/core/kazoo_documents/test/kz_account_test.erl index 4ede5318d68..38d7119919c 100644 --- a/core/kazoo_documents/test/kz_account_test.erl +++ b/core/kazoo_documents/test/kz_account_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Account document %%% @end diff --git a/core/kazoo_documents/test/kz_attachment_test.erl b/core/kazoo_documents/test/kz_attachment_test.erl index 56d200e4e69..f53eb4100e9 100644 --- a/core/kazoo_documents/test/kz_attachment_test.erl +++ b/core/kazoo_documents/test/kz_attachment_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Account document %%% @end diff --git a/core/kazoo_documents/test/kzd_agent_test.erl b/core/kazoo_documents/test/kzd_agent_test.erl index 0a271769904..b2e12c893a0 100644 --- a/core/kazoo_documents/test/kzd_agent_test.erl +++ b/core/kazoo_documents/test/kzd_agent_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz +%%% @copyright (C) 2010-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_documents/test/kzd_callflow_test.erl b/core/kazoo_documents/test/kzd_callflow_test.erl new file mode 100644 index 00000000000..0123e3158bd --- /dev/null +++ b/core/kazoo_documents/test/kzd_callflow_test.erl @@ -0,0 +1,218 @@ +-module(kzd_callflow_test). + +-include_lib("eunit/include/eunit.hrl"). + +-include("kz_documents.hrl"). + +-define(FLOW, <<"flow">>). + +simple_successful_validation_test_() -> + ChildData = kz_json:from_list([{<<"key1">>, <<"value1">>} + ,{<<"key2">>, 1} + ] + ), + Child = kz_json:from_list([{<<"module">>, <<"test">>} + ,{<<"data">>, ChildData} + ] + ), + Doc = kz_json:from_list([{?FLOW, Child}]), + + {'ok', ValidatedDoc} = kzd_callflow:validate_flow(Doc), + + ValidatedFlow = kzd_callflow:flow(ValidatedDoc), + + [?_assertEqual(<<"value3">>, kz_json:get_value([<<"data">>, <<"key3">>], ValidatedFlow))]. + +nested_children_test_() -> + ChildData = kz_json:from_list([{<<"key1">>, <<"value1">>} + ,{<<"key2">>, 1} + ,{<<"key3">>, <<"top">>} + ] + ), + Child = kz_json:from_list([{<<"module">>, <<"test">>} + ,{<<"data">>, ChildData} + ] + ), + + Nested = kz_json:set_value([<<"children">>, <<"_">>] + ,kz_json:delete_key([<<"data">>, <<"key3">>], Child) + ,Child + ), + + Doc = kz_json:from_list([{?FLOW, Nested}]), + + {'ok', ValidatedDoc} = kzd_callflow:validate_flow(Doc), + ValidatedFlow = kzd_callflow:flow(ValidatedDoc), + + [?_assertEqual(<<"top">>, kz_json:get_value([<<"data">>, <<"key3">>], ValidatedFlow)) + ,?_assertEqual(<<"value3">>, kz_json:get_value([<<"children">>, <<"_">>, <<"data">>, <<"key3">>], ValidatedFlow)) + ]. + +simple_failed_test_() -> + ChildData = kz_json:from_list([{<<"key1">>, 'true'} + ,{<<"key2">>, 1} + ] + ), + Child = kz_json:from_list([{<<"module">>, <<"test">>} + ,{<<"data">>, ChildData} + ] + ), + Doc = kz_json:from_list([{?FLOW, Child}]), + + {'error', Errors} = kzd_callflow:validate_flow(Doc), + [?_assertMatch([{'data_invalid', _SchemaJObj, 'wrong_type', 'true', [<<"key1">>]}], Errors)]. + +complex_failed_test_() -> + ChildData = kz_json:from_list([{<<"key2">>, 'true'}]), + Child = kz_json:from_list([{<<"module">>, <<"test">>} + ,{<<"data">>, ChildData} + ] + ), + Doc = kz_json:from_list([{?FLOW, Child}]), + + {'error', Errors} = kzd_callflow:validate_flow(Doc), + [?_assertMatch([{'data_invalid', _Key1SchemaJObj, 'missing_required_property', _Value, []} + ,{'data_invalid', _Key2SchemaJObj, 'wrong_type', 'true', [<<"key2">>]} + ] + ,Errors + ) + ]. + +nested_children_failure_test_() -> + ChildData = kz_json:from_list([{<<"key1">>, <<"value1">>} + ,{<<"key2">>, 'true'} + ,{<<"key3">>, <<"top">>} + ] + ), + Child = kz_json:from_list([{<<"module">>, <<"test">>} + ,{<<"data">>, ChildData} + ] + ), + + Nested = kz_json:set_value([<<"children">>, <<"_">>] + ,kz_json:delete_key([<<"data">>, <<"key3">>], Child) + ,Child + ), + + Doc = kz_json:from_list([{?FLOW, Nested}]), + + {'error', Errors} = kzd_callflow:validate_flow(Doc), + + [?_assertMatch([{'data_invalid', _SchemaJObj, 'wrong_type', 'true', [<<"children">>, <<"_">>, <<"key2">>]} + ,{'data_invalid', _SchemaJObj, 'wrong_type', 'true', [<<"key2">>]} + ] + ,Errors + ) + ]. + +action_failure_test_() -> + Doc = kz_json:from_list([{?FLOW, kz_json:new()}]), + {'error', Errors} = kzd_callflow:validate_flow(Doc), + + [?_assertEqual(2, length(Errors)) + ,?_assertMatch([{'data_invalid', _SchemaJObj + ,'missing_required_property' + ,<<"module">> + ,[] + } + ,{'data_invalid', _SchemaJObj + ,'missing_required_property' + ,<<"data">> + ,[] + } + ] + ,Errors + ) + ]. + +child_action_failure_test_() -> + Children = kz_json:from_list([{<<"ca1">>, kz_json:new()}]), + + Child = kz_json:from_list([{<<"module">>, <<"test">>} + ,{<<"data">>, kz_json:new()} + ,{<<"children">>, Children} + ]), + + Doc = kz_json:from_list([{?FLOW, Child}]), + {'error', Errors} = kzd_callflow:validate_flow(Doc), + + [?_assertEqual(2, length(Errors)) + ,?_assertMatch([{'data_invalid', _SchemaJObj + ,'missing_required_property' + ,<<"module">> + ,[<<"ca1">>, <<"children">>] + } + ,{'data_invalid', _SchemaJObj + ,'missing_required_property' + ,<<"data">> + ,[<<"ca1">>, <<"children">>] + } + ] + ,Errors + ) + ]. + +child_action_failure_data_test_() -> + Children = kz_json:from_list([{<<"ca2">>, kz_json:from_list([{<<"module">>, <<"child_test">>}])}]), + + Child = kz_json:from_list([{<<"module">>, <<"test">>} + ,{<<"data">>, kz_json:new()} + ,{<<"children">>, Children} + ]), + + Doc = kz_json:from_list([{?FLOW, Child}]), + {'error', Errors} = kzd_callflow:validate_flow(Doc), + + [?_assertEqual(1, length(Errors)) + ,?_assertMatch([{'data_invalid', _SchemaJObj + ,'missing_required_property' + ,<<"data">> + ,[<<"ca2">>, <<"children">>] + } + ] + ,Errors + ) + ]. + +multiple_child_action_failures_test_() -> + Children = kz_json:from_list([{<<"mp1">>, kz_json:new()} + ,{<<"mp2">>, kz_json:new()} + ]), + + ChildData = kz_json:from_list([{<<"key1">>, <<"value1">>} + ,{<<"key2">>, 1} + ] + ), + Child = kz_json:from_list([{<<"module">>, <<"test">>} + ,{<<"data">>, ChildData} + ,{<<"children">>, Children} + ]), + + Doc = kz_json:from_list([{?FLOW, Child}]), + {'error', Errors} = kzd_callflow:validate_flow(Doc), + + [?_assertEqual(4, length(Errors)) + ,?_assertMatch([{'data_invalid', _SchemaJObj + ,'missing_required_property' + ,<<"module">> + ,[<<"mp1">>, <<"children">>] + } + ,{'data_invalid', _SchemaJObj + ,'missing_required_property' + ,<<"data">> + ,[<<"mp1">>, <<"children">>] + } + ,{'data_invalid', _SchemaJObj + ,'missing_required_property' + ,<<"module">> + ,[<<"mp2">>, <<"children">>] + } + ,{'data_invalid', _SchemaJObj + ,'missing_required_property' + ,<<"data">> + ,[<<"mp2">>, <<"children">>] + } + ] + ,Errors + ) + ]. diff --git a/core/kazoo_documents/test/kzd_domains_test.erl b/core/kazoo_documents/test/kzd_domains_test.erl index 38e13ba37ba..ba9516ffc71 100644 --- a/core/kazoo_documents/test/kzd_domains_test.erl +++ b/core/kazoo_documents/test/kzd_domains_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Account document %%% @end diff --git a/core/kazoo_documents/test/kzd_user_test.erl b/core/kazoo_documents/test/kzd_user_test.erl index 6e9cf9a656c..fda00a5e426 100644 --- a/core/kazoo_documents/test/kzd_user_test.erl +++ b/core/kazoo_documents/test/kzd_user_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% User document: tests %%% @end diff --git a/core/kazoo_endpoint/src/kazoo_endpoint_app.erl b/core/kazoo_endpoint/src/kazoo_endpoint_app.erl index 5259093fc6a..79b1ade6259 100644 --- a/core/kazoo_endpoint/src/kazoo_endpoint_app.erl +++ b/core/kazoo_endpoint/src/kazoo_endpoint_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_endpoint/src/kazoo_endpoint_sup.erl b/core/kazoo_endpoint/src/kazoo_endpoint_sup.erl index acccf423de1..b2d89d42aed 100644 --- a/core/kazoo_endpoint/src/kazoo_endpoint_sup.erl +++ b/core/kazoo_endpoint/src/kazoo_endpoint_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_endpoint/src/kz_attributes.erl b/core/kazoo_endpoint/src/kz_attributes.erl index d509afe7b84..87f9ce90526 100644 --- a/core/kazoo_endpoint/src/kz_attributes.erl +++ b/core/kazoo_endpoint/src/kz_attributes.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% @end %%% @contributors @@ -31,6 +31,8 @@ ) ). +-type cid() :: {api_binary(), api_binary()}. + %%----------------------------------------------------------------------------- %% @public %% @doc @@ -67,8 +69,7 @@ groups(Call, ViewOptions) -> %% @doc %% @end %%----------------------------------------------------------------------------- --spec caller_id(ne_binary(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec caller_id(ne_binary(), kapps_call:call()) -> cid(). caller_id(Attribute, Call) -> CCVs = kapps_call:custom_channel_vars(Call), Inception = kapps_call:inception(Call), @@ -86,8 +87,7 @@ caller_id(Attribute, Call) -> maybe_get_dynamic_cid('true', Attribute, Call) end. --spec maybe_get_dynamic_cid(boolean(), ne_binary(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_get_dynamic_cid(boolean(), ne_binary(), kapps_call:call()) -> cid(). maybe_get_dynamic_cid(Validate, Attribute, Call) -> case kapps_call:kvs_fetch('dynamic_cid', Call) of 'undefined' -> maybe_get_endpoint_cid(Validate, Attribute, Call); @@ -96,8 +96,7 @@ maybe_get_dynamic_cid(Validate, Attribute, Call) -> maybe_normalize_cid(DynamicCID, 'undefined', Validate, Attribute, Call) end. --spec maybe_get_endpoint_cid(boolean(), ne_binary(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_get_endpoint_cid(boolean(), ne_binary(), kapps_call:call()) -> cid(). maybe_get_endpoint_cid(Validate, Attribute, Call) -> case kz_endpoint:get(Call) of {'error', _R} -> @@ -107,9 +106,22 @@ maybe_get_endpoint_cid(Validate, Attribute, Call) -> Number = get_cid_or_default(Attribute, <<"number">>, JObj), Name = get_cid_or_default(Attribute, <<"name">>, JObj), _ = log_configured_endpoint_cid(Attribute, Name, Number), - maybe_use_presence_number(Number, Name, JObj, Validate, Attribute, Call) + Call1 = maybe_add_originals_to_kvs(Number, Name, Call), + maybe_use_presence_number(Number, Name, JObj, Validate, Attribute, Call1) end. +-spec maybe_add_originals_to_kvs(api_ne_binary(), api_ne_binary(), kapps_call:call()) -> kapps_call:call(). +maybe_add_originals_to_kvs('undefined', 'undefined', Call) -> Call; +maybe_add_originals_to_kvs('undefined', ?NE_BINARY=Name, Call) -> + kapps_call:exec([fun(C) -> kapps_call:kvs_store('original_cid_name', Name, C) end], Call); +maybe_add_originals_to_kvs(?NE_BINARY=Number, 'undefined', Call) -> + kapps_call:exec([fun(C) -> kapps_call:kvs_store('original_cid_number', Number, C) end], Call); +maybe_add_originals_to_kvs(Number, Name, Call) -> + Updates = [fun(C) -> kapps_call:kvs_store('original_cid_number', Number, C) end + ,fun(C) -> kapps_call:kvs_store('original_cid_name', Name, C) end + ], + kapps_call:exec(Updates, Call). + -spec log_configured_endpoint_cid(ne_binary(), api_binary(), api_binary()) -> 'ok'. log_configured_endpoint_cid(Attribute, 'undefined', 'undefined') -> lager:debug("endpoint not configured with an ~s caller id", [Attribute]); @@ -120,20 +132,30 @@ log_configured_endpoint_cid(Attribute, 'undefined', Number) -> log_configured_endpoint_cid(Attribute, Name, Number) -> lager:debug("endpoint configured with ~s caller id <~s> ~s", [Attribute, Name, Number]). --spec maybe_use_presence_number(api_binary(), api_binary(), kz_json:object(), boolean(), ne_binary(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_use_presence_number(api_binary(), api_binary(), kz_json:object(), boolean(), ne_binary(), kapps_call:call()) -> cid(). maybe_use_presence_number('undefined', Name, Endpoint, Validate, <<"internal">> = Attribute, Call) -> case maybe_get_presence_number(Endpoint, Call) of - 'undefined' -> maybe_normalize_cid('undefined', Name, Validate, Attribute, Call); + 'undefined' -> + maybe_format_cid_number('undefined', Name, Endpoint, Validate, Attribute, Call); Number -> lager:debug("replacing empty caller id number with presence number ~s", [Number]), - maybe_normalize_cid(Number, Name, Validate, Attribute, Call) + maybe_format_cid_number(Number, Name, Endpoint, Validate, Attribute, Call) end; -maybe_use_presence_number(Number, Name, _Endpoint, Validate, Attribute, Call) -> - maybe_normalize_cid(Number, Name, Validate, Attribute, Call). +maybe_use_presence_number(Number, Name, Endpoint, Validate, Attribute, Call) -> + maybe_format_cid_number(Number, Name, Endpoint, Validate, Attribute, Call). --spec maybe_normalize_cid(api_binary(), api_binary(), boolean(), ne_binary(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_format_cid_number(api_binary(), api_binary(), kz_json:object(), boolean(), ne_binary(), kapps_call:call()) -> cid(). +maybe_format_cid_number('undefined', Name, Endpoint, Validate, Attribute, Call) -> + Number = kapps_call:caller_id_number(Call), + Format = kz_json:get_ne_value([<<"caller_id_options">>, <<"format">>], Endpoint), + Formatted = kapps_call:maybe_format_caller_id_str(Number, Format), + maybe_normalize_cid(Formatted, Name, Validate, Attribute, Call); +maybe_format_cid_number(Number, Name, Endpoint, Validate, Attribute, Call) -> + Format = kz_json:get_ne_value([<<"caller_id_options">>, <<"format">>], Endpoint), + Formatted = kapps_call:maybe_format_caller_id_str(Number, Format), + maybe_normalize_cid(Formatted, Name, Validate, Attribute, Call). + +-spec maybe_normalize_cid(api_binary(), api_binary(), boolean(), ne_binary(), kapps_call:call()) -> cid(). maybe_normalize_cid('undefined', Name, Validate, Attribute, Call) -> Number = kapps_call:caller_id_number(Call), lager:debug("replacing empty caller id number with SIP caller id number ~s", [Number]), @@ -145,30 +167,29 @@ maybe_normalize_cid(Number, 'undefined', Validate, Attribute, Call) -> maybe_normalize_cid(Number, Name, Validate, Attribute, Call) -> maybe_prefix_cid_number(kz_util:to_binary(Number), Name, Validate, Attribute, Call). --spec maybe_prefix_cid_number(ne_binary(), ne_binary(), boolean(), ne_binary(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_prefix_cid_number(ne_binary(), ne_binary(), boolean(), ne_binary(), kapps_call:call()) -> cid(). maybe_prefix_cid_number(Number, Name, Validate, Attribute, Call) -> + OrigNumber = kapps_call:kvs_fetch('original_cid_number', Number, Call), case kapps_call:kvs_fetch('prepend_cid_number', Call) of 'undefined' -> maybe_prefix_cid_name(Number, Name, Validate, Attribute, Call); Prefix -> lager:debug("prepending caller id number with ~s", [Prefix]), - Prefixed = <<(kz_util:to_binary(Prefix))/binary, Number/binary>>, + Prefixed = <<(kz_util:to_binary(Prefix))/binary, OrigNumber/binary>>, maybe_prefix_cid_name(Prefixed, Name, Validate, Attribute, Call) end. --spec maybe_prefix_cid_name(ne_binary(), ne_binary(), boolean(), ne_binary(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_prefix_cid_name(ne_binary(), ne_binary(), boolean(), ne_binary(), kapps_call:call()) -> cid(). maybe_prefix_cid_name(Number, Name, Validate, Attribute, Call) -> + OrigName = kapps_call:kvs_fetch('original_cid_name', Name, Call), case kapps_call:kvs_fetch('prepend_cid_name', Call) of 'undefined' -> maybe_rewrite_cid_number(Number, Name, Validate, Attribute, Call); Prefix -> lager:debug("prepending caller id name with ~s", [Prefix]), - Prefixed = <<(kz_util:to_binary(Prefix))/binary, Name/binary>>, + Prefixed = <<(kz_util:to_binary(Prefix))/binary, OrigName/binary>>, maybe_rewrite_cid_number(Number, Prefixed, Validate, Attribute, Call) end. --spec maybe_rewrite_cid_number(ne_binary(), ne_binary(), boolean(), ne_binary(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_rewrite_cid_number(ne_binary(), ne_binary(), boolean(), ne_binary(), kapps_call:call()) -> cid(). maybe_rewrite_cid_number(Number, Name, Validate, Attribute, Call) -> case kapps_call:kvs_fetch('rewrite_cid_number', Call) of 'undefined' -> maybe_rewrite_cid_name(Number, Name, Validate, Attribute, Call); @@ -177,8 +198,7 @@ maybe_rewrite_cid_number(Number, Name, Validate, Attribute, Call) -> maybe_rewrite_cid_name(NewNumber, Name, Validate, Attribute, Call) end. --spec maybe_rewrite_cid_name(ne_binary(), ne_binary(), boolean(), ne_binary(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_rewrite_cid_name(ne_binary(), ne_binary(), boolean(), ne_binary(), kapps_call:call()) -> cid(). maybe_rewrite_cid_name(Number, Name, Validate, Attribute, Call) -> case kapps_call:kvs_fetch('rewrite_cid_name', Call) of 'undefined' -> maybe_ensure_cid_valid(Number, Name, Validate, Attribute, Call); @@ -187,8 +207,7 @@ maybe_rewrite_cid_name(Number, Name, Validate, Attribute, Call) -> maybe_ensure_cid_valid(Number, NewName, Validate, Attribute, Call) end. --spec maybe_ensure_cid_valid(ne_binary(), ne_binary(), boolean(), ne_binary(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_ensure_cid_valid(ne_binary(), ne_binary(), boolean(), ne_binary(), kapps_call:call()) -> cid(). maybe_ensure_cid_valid(Number, Name, 'true', <<"emergency">>, _Call) -> lager:info("determined emergency caller id is <~s> ~s", [Name, Number]), {Number, Name}; @@ -203,8 +222,7 @@ maybe_ensure_cid_valid(Number, Name, _, Attribute, Call) -> lager:info("determined ~s caller id is <~s> ~s", [Attribute, Name, Number]), maybe_cid_privacy(Number, Name, Call). --spec maybe_cid_privacy(api_binary(), api_binary(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_cid_privacy(api_binary(), api_binary(), kapps_call:call()) -> cid(). maybe_cid_privacy(Number, Name, Call) -> case kz_util:is_true(kapps_call:kvs_fetch('cf_privacy', Call)) orelse ?CALLER_PRIVACY(kapps_call:custom_channel_vars(Call)) @@ -223,8 +241,7 @@ maybe_cid_privacy(Number, Name, Call) -> 'false' -> {Number, Name} end. --spec ensure_valid_caller_id(ne_binary(), ne_binary(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec ensure_valid_caller_id(ne_binary(), ne_binary(), kapps_call:call()) -> cid(). ensure_valid_caller_id(Number, Name, Call) -> case is_valid_caller_id(Number, Call) of 'true' -> @@ -235,8 +252,7 @@ ensure_valid_caller_id(Number, Name, Call) -> maybe_get_account_cid(Number, Name, Call) end. --spec get_account_external_cid(kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec get_account_external_cid(kapps_call:call()) -> cid(). get_account_external_cid(Call) -> Number = kapps_call:caller_id_number(Call), Name = kapps_call:caller_id_name(Call), @@ -245,16 +261,14 @@ get_account_external_cid(Call) -> maybe_get_account_cid(Number, Name, Call). --spec maybe_get_account_cid(ne_binary(), ne_binary(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_get_account_cid(ne_binary(), ne_binary(), kapps_call:call()) -> cid(). maybe_get_account_cid(Number, Name, Call) -> case kz_account:fetch(kapps_call:account_id(Call)) of {'error', _} -> maybe_get_assigned_number(Number, Name, Call); {'ok', JObj} -> maybe_get_account_external_number(Number, Name, JObj, Call) end. --spec maybe_get_account_external_number(ne_binary(), ne_binary(), kz_json:object(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_get_account_external_number(ne_binary(), ne_binary(), kz_json:object(), kapps_call:call()) -> cid(). maybe_get_account_external_number(Number, Name, Account, Call) -> External = kz_json:get_ne_value([<<"caller_id">>, <<"external">>, <<"number">>], Account), case is_valid_caller_id(External, Call) of @@ -265,8 +279,7 @@ maybe_get_account_external_number(Number, Name, Account, Call) -> maybe_get_account_default_number(Number, Name, Account, Call) end. --spec maybe_get_account_default_number(ne_binary(), ne_binary(), kz_json:object(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_get_account_default_number(ne_binary(), ne_binary(), kz_json:object(), kapps_call:call()) -> cid(). maybe_get_account_default_number(Number, Name, Account, Call) -> Default = kz_json:get_ne_value([<<"caller_id">>, <<"default">>, <<"number">>], Account), case is_valid_caller_id(Default, Call) of @@ -277,8 +290,7 @@ maybe_get_account_default_number(Number, Name, Account, Call) -> maybe_get_assigned_number(Number, Name, Call) end. --spec maybe_get_assigned_number(api_ne_binary(), api_ne_binary(), api_ne_binary()|kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_get_assigned_number(api_ne_binary(), api_ne_binary(), api_ne_binary()|kapps_call:call()) -> cid(). maybe_get_assigned_number(CandidateNumber, Name, ?MATCH_ACCOUNT_ENCODED(_)=AccountDb) -> case knm_numbers:account_listing(AccountDb) of [_|_] = NumbersList -> @@ -287,10 +299,8 @@ maybe_get_assigned_number(CandidateNumber, Name, ?MATCH_ACCOUNT_ENCODED(_)=Accou kz_json:get_value(<<"state">>, JObj) =:= ?NUMBER_STATE_IN_SERVICE ], case lists:member(CandidateNumber, Numbers) of - 'true' -> - {CandidateNumber, Name}; - 'false' -> - maybe_get_assigned_numbers(Numbers, Name) + 'true' -> {CandidateNumber, Name}; + 'false' -> maybe_get_assigned_numbers(Numbers, Name) end; _ -> Number = default_cid_number(), @@ -300,8 +310,7 @@ maybe_get_assigned_number(CandidateNumber, Name, ?MATCH_ACCOUNT_ENCODED(_)=Accou maybe_get_assigned_number(CandidateNumber, Name, Call) -> AccountDb = kapps_call:account_db(Call), maybe_get_assigned_number(CandidateNumber, Name, AccountDb). - --spec maybe_get_assigned_numbers(ne_binaries(), ne_binary()) -> {api_binary(), api_binary()}. +-spec maybe_get_assigned_numbers(ne_binaries(), ne_binary()) -> cid(). maybe_get_assigned_numbers([], Name) -> Number = default_cid_number(), lager:info("failed to find any in-service numbers, using default <~s> ~s", [Name, Number]), @@ -337,8 +346,7 @@ maybe_get_presence_number(Endpoint, Call) -> %% @doc %% @end %%----------------------------------------------------------------------------- --spec callee_id(api_binary() | kz_json:object(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec callee_id(api_binary() | kz_json:object(), kapps_call:call()) -> cid(). callee_id(EndpointId, Call) when is_binary(EndpointId) -> case kz_endpoint:get(EndpointId, Call) of {'ok', Endpoint} -> callee_id(Endpoint, Call); @@ -351,8 +359,7 @@ callee_id(Endpoint, Call) -> Name = get_cid_or_default(Attribute, <<"name">>, Endpoint), maybe_normalize_callee(Number, Name, Endpoint, Call). --spec maybe_normalize_callee(api_binary(), api_binary(), kz_json:object(), kapps_call:call()) -> - {api_binary(), api_binary()}. +-spec maybe_normalize_callee(api_binary(), api_binary(), kz_json:object(), kapps_call:call()) -> cid(). maybe_normalize_callee('undefined', Name, Endpoint, Call) -> maybe_normalize_callee(kapps_call:request_user(Call), Name, Endpoint, Call); maybe_normalize_callee(Number, 'undefined', Endpoint, Call) -> diff --git a/core/kazoo_endpoint/src/kz_endpoint.erl b/core/kazoo_endpoint/src/kz_endpoint.erl index 28d050f5a39..987095ca0ea 100644 --- a/core/kazoo_endpoint/src/kz_endpoint.erl +++ b/core/kazoo_endpoint/src/kz_endpoint.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -568,20 +568,11 @@ build(Endpoint, Properties, Call) -> {'ok', kz_json:objects()} | {'error', build_errors()}. build_endpoint(Endpoint, Properties, Call) -> - Call1 = maybe_rewrite_caller_id(Endpoint, Call), - case should_create_endpoint(Endpoint, Properties, Call1) of - 'ok' -> create_endpoints(Endpoint, Properties, Call1); + case should_create_endpoint(Endpoint, Properties, Call) of + 'ok' -> create_endpoints(Endpoint, Properties, Call); {'error', _}=E -> E end. --spec maybe_rewrite_caller_id(kz_json:object(), kapps_call:call()) -> kapps_call:call(). -maybe_rewrite_caller_id(Endpoint, Call) -> - case kz_json:get_ne_value(<<"caller_id_options">>, Endpoint) of - 'undefined' -> Call; - CidOptions -> - kapps_call:maybe_format_caller_id(Call, kz_json:get_value(<<"format">>, CidOptions)) - end. - -spec should_create_endpoint(kz_json:object(), kz_json:object(), kapps_call:call()) -> 'ok' | {'error', any()}. should_create_endpoint(Endpoint, Properties, Call) -> @@ -1437,10 +1428,10 @@ maybe_retain_caller_id({_Endpoint, _Call, 'undefined', _JObj}=Acc) -> maybe_retain_caller_id({Endpoint, Call, CallFwd, JObj}) -> {Endpoint, Call, CallFwd ,case kapps_call:inception(Call) =:= 'undefined' - orelse kz_json:is_true(<<"keep_caller_id">>, CallFwd) + andalso kz_json:is_true(<<"keep_caller_id">>, CallFwd) of 'true' -> - lager:info("call forwarding will keep set retain caller id"), + lager:info("call forwarding will retain caller id"), kz_json:set_value(<<"Retain-CID">>, <<"true">>, JObj); 'false' -> JObj end diff --git a/core/kazoo_endpoint/src/kz_endpoints.erl b/core/kazoo_endpoint/src/kz_endpoints.erl index a0e7cf5fbae..269354f86bf 100644 --- a/core/kazoo_endpoint/src/kz_endpoints.erl +++ b/core/kazoo_endpoint/src/kz_endpoints.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_endpoint/src/kz_formatters.erl b/core/kazoo_endpoint/src/kz_formatters.erl index dd12ca7fe98..22d2b1002ef 100644 --- a/core/kazoo_endpoint/src/kz_formatters.erl +++ b/core/kazoo_endpoint/src/kz_formatters.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_endpoint/test/kz_formatters_test.erl b/core/kazoo_endpoint/test/kz_formatters_test.erl index 626aa1e1761..ad8f31d676c 100644 --- a/core/kazoo_endpoint/test/kz_formatters_test.erl +++ b/core/kazoo_endpoint/test/kz_formatters_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% %%% @end @@ -32,28 +32,28 @@ regex_inbound_test_() -> Formatter = kz_json:from_list([{<<"to">> - ,[kz_json:from_list([{<<"regex">>, <<"^\\+?1?(\\d{10})$">>} + ,[kz_json:from_list([{<<"regex">>, <<"^\\+?1?(\\d{10})\$">>} ,{<<"prefix">>, <<"+1">>} ,{<<"direction">>, <<"inbound">>} ]) ] } ,{<<"from">> - ,[kz_json:from_list([{<<"regex">>, <<"^\\+?1?(\\d{10})$">>} + ,[kz_json:from_list([{<<"regex">>, <<"^\\+?1?(\\d{10})\$">>} ,{<<"prefix">>, <<"+1">>} ,{<<"direction">>, <<"inbound">>} ]) ] } ,{<<"request">> - ,[kz_json:from_list([{<<"regex">>, <<"^\\+?1?(\\d{10})$">>} + ,[kz_json:from_list([{<<"regex">>, <<"^\\+?1?(\\d{10})\$">>} ,{<<"prefix">>, <<"+1">>} ,{<<"direction">>, <<"inbound">>} ]) ] } ,{<<"caller_id_number">> - ,[kz_json:from_list([{<<"regex">>, <<"^\\+?1?(\\d{10})$">>} + ,[kz_json:from_list([{<<"regex">>, <<"^\\+?1?(\\d{10})\$">>} ,{<<"direction">>, <<"inbound">>} ]) ] @@ -70,7 +70,7 @@ regex_inbound_test_() -> strip_inbound_test_() -> Formatter = kz_json:from_list([{<<"to">> - ,[kz_json:from_list([{<<"regex">>, <<"^\\+?1?(\\d{10})$">>} + ,[kz_json:from_list([{<<"regex">>, <<"^\\+?1?(\\d{10})\$">>} ,{<<"prefix">>, <<"+1">>} ,{<<"direction">>, <<"inbound">>} ,{<<"strip">>, 'true'} @@ -78,7 +78,7 @@ strip_inbound_test_() -> ] } ,{<<"caller_id_number">> - ,[kz_json:from_list([{<<"regex">>, <<"^\\+?1?(\\d{10})$">>} + ,[kz_json:from_list([{<<"regex">>, <<"^\\+?1?(\\d{10})\$">>} ,{<<"direction">>, <<"inbound">>} ,{<<"strip">>, 'true'} ]) diff --git a/core/kazoo_etsmgr/src/kazoo_etsmgr_srv.erl b/core/kazoo_etsmgr/src/kazoo_etsmgr_srv.erl index cdce1081a64..78656ea9ac2 100644 --- a/core/kazoo_etsmgr/src/kazoo_etsmgr_srv.erl +++ b/core/kazoo_etsmgr/src/kazoo_etsmgr_srv.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Manage the ETS table separate from the main process to use the ETS table %%% Protects against the main writer dying diff --git a/core/kazoo_globals/src/kazoo_globals_app.erl b/core/kazoo_globals/src/kazoo_globals_app.erl index 20d702e4483..8591b32a427 100644 --- a/core/kazoo_globals/src/kazoo_globals_app.erl +++ b/core/kazoo_globals/src/kazoo_globals_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_globals/src/kazoo_globals_init.erl b/core/kazoo_globals/src/kazoo_globals_init.erl index 1885a24534a..04ffd77652b 100644 --- a/core/kazoo_globals/src/kazoo_globals_init.erl +++ b/core/kazoo_globals/src/kazoo_globals_init.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Wait for Globals %%% @end diff --git a/core/kazoo_globals/src/kazoo_globals_sup.erl b/core/kazoo_globals/src/kazoo_globals_sup.erl index 75264b8f90a..98201a51acc 100644 --- a/core/kazoo_globals/src/kazoo_globals_sup.erl +++ b/core/kazoo_globals/src/kazoo_globals_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_globals/src/kz_global.erl b/core/kazoo_globals/src/kz_global.erl index 039157789c6..5bcac32e44f 100644 --- a/core/kazoo_globals/src/kz_global.erl +++ b/core/kazoo_globals/src/kz_global.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_globals/src/kz_global_proxies_sup.erl b/core/kazoo_globals/src/kz_global_proxies_sup.erl index f6c2bb95793..a8a1c0c2e3c 100644 --- a/core/kazoo_globals/src/kz_global_proxies_sup.erl +++ b/core/kazoo_globals/src/kz_global_proxies_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_globals/src/kz_global_proxy.erl b/core/kazoo_globals/src/kz_global_proxy.erl index e2bb16659f5..b42c070fe9a 100644 --- a/core/kazoo_globals/src/kz_global_proxy.erl +++ b/core/kazoo_globals/src/kz_global_proxy.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_globals/src/kz_globals.erl b/core/kazoo_globals/src/kz_globals.erl index 329ac60b0d7..218fd7d4dee 100644 --- a/core/kazoo_globals/src/kz_globals.erl +++ b/core/kazoo_globals/src/kz_globals.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_globals/src/kz_nodes.erl b/core/kazoo_globals/src/kz_nodes.erl index 3ce28f1578f..ff62dc56deb 100644 --- a/core/kazoo_globals/src/kz_nodes.erl +++ b/core/kazoo_globals/src/kz_nodes.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_ips/src/kazoo_ips_maintenance.erl b/core/kazoo_ips/src/kazoo_ips_maintenance.erl index 9d3202eaf91..468df9609b8 100644 --- a/core/kazoo_ips/src/kazoo_ips_maintenance.erl +++ b/core/kazoo_ips/src/kazoo_ips_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016 2600Hz, INC +%%% @copyright (C) 2011-2017 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_ips/src/kz_ip.erl b/core/kazoo_ips/src/kz_ip.erl index 8d03627507c..7f6931aad84 100644 --- a/core/kazoo_ips/src/kz_ip.erl +++ b/core/kazoo_ips/src/kz_ip.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016 2600Hz, INC +%%% @copyright (C) 2011-2017 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_ips/src/kz_ip_utils.erl b/core/kazoo_ips/src/kz_ip_utils.erl index 2127157dff4..3a5ebb170d6 100644 --- a/core/kazoo_ips/src/kz_ip_utils.erl +++ b/core/kazoo_ips/src/kz_ip_utils.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016 2600Hz, INC +%%% @copyright (C) 2011-2017 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_ips/src/kz_ips.erl b/core/kazoo_ips/src/kz_ips.erl index 70fc25f49e5..b1157a94d49 100644 --- a/core/kazoo_ips/src/kz_ips.erl +++ b/core/kazoo_ips/src/kz_ips.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016 2600Hz, INC +%%% @copyright (C) 2011-2017 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_json/src/kz_json.erl b/core/kazoo_json/src/kz_json.erl index cb8915ab3aa..1969f3abad9 100644 --- a/core/kazoo_json/src/kz_json.erl +++ b/core/kazoo_json/src/kz_json.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% proplists-like interface to json objects %%% @end @@ -80,7 +80,7 @@ ,normalize_jobj/3 ,normalize/1 ,normalize_key/1 - ,are_identical/2, are_equal/2 + ,are_equal/2 ]). -export([public_fields/1 ,private_fields/1 @@ -93,6 +93,9 @@ -export([flatten/3]). +-export([sum/2, sum/3]). +-export_type([sumer/0]). + -include_lib("kazoo/include/kz_log.hrl"). -include_lib("kazoo_json/include/kazoo_json.hrl"). @@ -213,25 +216,6 @@ is_json_term({'json', IOList}) when is_list(IOList) -> 'true'; is_json_term(MaybeJObj) -> is_json_object(MaybeJObj). -%%-------------------------------------------------------------------- -%% @public -%% @doc -%% -%% @end -%%-------------------------------------------------------------------- --spec are_identical(api_object(), api_object()) -> boolean(). -are_identical('undefined', 'undefined') -> 'true'; -are_identical('undefined', _) -> 'false'; -are_identical(_, 'undefined') -> 'false'; -are_identical(JObj1, JObj2) -> - [KV || {_, V}=KV <- to_proplist(JObj1), - not kz_util:is_empty(V) - ] - =:= - [KV || {_, V}=KV <- to_proplist(JObj2), - not kz_util:is_empty(V) - ]. - %%-------------------------------------------------------------------- %% @public %% @doc @@ -245,13 +229,18 @@ are_equal(_, 'undefined') -> 'false'; are_equal(JObj1, JObj2) -> to_map(JObj1) =:= to_map(JObj2). -%% converts top-level proplist to json object, but only if sub-proplists have been converted +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Converts top-level proplist to json object, but only if sub-proplists have been converted %% first. %% For example: %% [{a, b}, {c, [{d, e}]}] %% would be converted to json by %% kz_json:from_list([{a,b}, {c, kz_json:from_list([{d, e}])}]). %% the sub-proplist [{d,e}] needs converting before being passed to the next level +%% @end +%%-------------------------------------------------------------------- -spec from_list(json_proplist()) -> object(). from_list([]) -> new(); from_list(L) when is_list(L) -> ?JSON_WRAPPER(L). @@ -301,8 +290,11 @@ merge_right(_K, {'both', ?JSON_WRAPPER(_)=Left, ?JSON_WRAPPER(_)=Right}) -> {'ok', merge(fun merge_right/2, Left, Right)}; merge_right(_K, {'both', _Left, Right}) -> {'ok', Right}. -%% only a top-level merge -%% merges JObj1 into JObj2 +%% @public +%% @doc +%% Only a top-level merge. +%% Merges JObj1 into JObj2 +%% @end -spec merge_jobjs(object(), object()) -> object(). merge_jobjs(?JSON_WRAPPER(Props1), ?JSON_WRAPPER(_)=JObj2) -> lists:foldr(fun({K, V}, JObj2Acc) -> @@ -350,6 +342,42 @@ merge_recursive(?JSON_WRAPPER(_)=JObj1, Value, Pred, Keys) when is_function(Pred 'true' -> set_value(Syek, Value, JObj1) end. +%% @public +%% @doc +%% Sum two (deep) JSON objects. +%% Default sumer function only sums numbers. For other kinds of values, +%% the value from JObj1 is kept untouched. If it is undefined it's the one from JObj2. +%% @end +-spec sum(object(), object()) -> object(). +sum(?JSON_WRAPPER(_)=JObj1, ?JSON_WRAPPER(_)=JObj2) -> + sum(JObj1, JObj2, fun default_sumer/2). + +-type sumer() :: fun((json_term(), json_term()) -> json_term()). +-spec default_sumer(json_term(), json_term()) -> json_term(). +default_sumer(Value1, undefined) -> Value1; +default_sumer(undefined, Value2) -> Value2; +default_sumer(Value1, Value2) when is_number(Value1), + is_number(Value2) -> + Value1 + Value2; +default_sumer(Value1, _) -> + Value1. + +-spec sum(object(), object(), sumer()) -> object(). +sum(?JSON_WRAPPER(_)=JObj1, ?JSON_WRAPPER(_)=JObj2, Sumer) + when is_function(Sumer, 2) -> + sum(JObj1, JObj2, Sumer, []). + +-spec sum(object(), object(), sumer(), keys()) -> object(). +sum(?JSON_WRAPPER(_)=JObj1, ?JSON_WRAPPER(_)=JObj2, Sumer, Keys) + when is_function(Sumer, 2) -> + F = fun(Key2, Value2, JObj1Acc) -> sum(JObj1Acc, Value2, Sumer, [Key2|Keys]) end, + foldl(F, JObj1, JObj2); +sum(?JSON_WRAPPER(_)=JObj1, Value, Sumer, Keys) + when is_function(Sumer, 2) -> + Syek = lists:reverse(Keys), + V = get_value(Syek, JObj1), + set_value(Syek, Sumer(V, Value), JObj1). + -spec to_proplist(object() | objects()) -> json_proplist() | json_proplists(). -spec to_proplist(path(), object() | objects()) -> json_proplist() | json_proplists(). %% Convert a json object to a proplist diff --git a/core/kazoo_json/src/kz_json_schema.erl b/core/kazoo_json/src/kz_json_schema.erl index 4d486c41205..dcd17083eb7 100644 --- a/core/kazoo_json/src/kz_json_schema.erl +++ b/core/kazoo_json/src/kz_json_schema.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% @doc %%% Module for interacting with JSON schema docs %%% @end @@ -18,6 +18,8 @@ ,build_error_message/2 ]). +-export_type([validation_error/0, validation_errors/0]). + -include_lib("kazoo/include/kz_types.hrl"). -include_lib("kazoo/include/kz_databases.hrl"). -include_lib("kazoo_documents/include/kazoo_documents.hrl"). @@ -36,14 +38,20 @@ load(Schema) -> load(kz_util:to_binary(Schema)). {'error', any()}. fload(<<"./", Schema/binary>>) -> fload(Schema); fload(<<_/binary>> = Schema) -> - io:format("loading schema ~s~n", [Schema]), - Path = <<"/opt/kazoo/applications/crossbar/priv/couchdb/schemas/", Schema/binary, ".json">>, - case file:read_file(Path) of - {'error', _E}=E -> E; - {'ok', Bin} -> {'ok', kz_json:insert_value(<<"id">>, Schema, kz_json:decode(Bin))} - end; + PrivDir = code:priv_dir('crossbar'), + SchemaPath = filename:join([PrivDir, "couchdb", "schemas", maybe_add_ext(Schema)]), + {'ok', SchemaJSON} = file:read_file(SchemaPath), + SchemaJObj = kz_json:decode(SchemaJSON), + {'ok', kz_json:insert_value(<<"id">>, Schema, SchemaJObj)}; fload(Schema) -> fload(kz_util:to_binary(Schema)). +-spec maybe_add_ext(ne_binary()) -> ne_binary(). +maybe_add_ext(Schema) -> + case filename:extension(Schema) of + <<".json">> -> Schema; + _Ext -> <> + end. + -spec flush() -> 'ok'. -spec flush(ne_binary()) -> 'ok'. flush() -> @@ -147,11 +155,12 @@ validate(SchemaJObj, DataJObj, Options) -> -type options() :: [option()]. -type validation_error() :: {integer(), ne_binary(), kz_json:object()}. +-type validation_errors() :: [validation_error()]. -spec errors_to_jobj([jesse_error:error_reason()]) -> - [validation_error()]. + validation_errors(). -spec errors_to_jobj([jesse_error:error_reason()], options()) -> - [validation_error()]. + validation_errors(). errors_to_jobj(Errors) -> errors_to_jobj(Errors, [{'version', ?CURRENT_VERSION}]). @@ -664,6 +673,8 @@ validation_error(Property, <<"invalid">> = C, Message, Options) -> depreciated_validation_error(Property, C, Message, Options); validation_error(Property, <<"schema">> = C, Message, Options) -> depreciated_validation_error(Property, C, Message, Options); +validation_error(Property, <<"additionalProperties">> = C, Message, Options) -> + depreciated_validation_error(Property, C, Message, Options); validation_error(Property, Code, Message, Options) -> lager:warning("UNKNOWN ERROR CODE: ~p", [Code]), depreciated_validation_error(Property, Code, Message, Options). diff --git a/core/kazoo_json/test/kz_json_schema_test.erl b/core/kazoo_json/test/kz_json_schema_test.erl index 4ace04d1562..30a3e00388a 100644 --- a/core/kazoo_json/test/kz_json_schema_test.erl +++ b/core/kazoo_json/test/kz_json_schema_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% @doc %%% Module for interacting with JSON schema docs %%% @end diff --git a/core/kazoo_json/test/kz_json_test.erl b/core/kazoo_json/test/kz_json_test.erl index b97ee53389d..3be174fca7e 100644 --- a/core/kazoo_json/test/kz_json_test.erl +++ b/core/kazoo_json/test/kz_json_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% proplists-like interface to json objects %%% @end @@ -519,8 +519,6 @@ get_ne_json_object_test_() -> }). to_map_test_() -> - io:format(user, "\n>1> ~p\n", [kz_json:to_map(?MAP_JSON)]), - io:format(user, "\n>2> ~p\n", [kz_json:from_map(?JSON_MAP)]), [?_assertEqual(?JSON_MAP, kz_json:to_map(?MAP_JSON)) ,?_assertEqual(?MAP_JSON, kz_json:from_map(?JSON_MAP)) ,?_assertEqual(?JSON_MAP, kz_json:to_map(kz_json:from_map(?JSON_MAP))) @@ -530,4 +528,32 @@ to_map_test_() -> are_equal_test_() -> JObj = kz_json:from_map(kz_json:to_map(?MAP_JSON)), [?_assertEqual(true, kz_json:are_equal(?MAP_JSON, JObj)) + ,?_assertEqual(true, kz_json:are_equal(JObj, ?MAP_JSON)) + ,?_assertEqual(true, kz_json:are_equal(undefined, undefined)) + ,?_assertEqual(false, kz_json:are_equal(undefined, kz_json:new())) + ,?_assertEqual(false, kz_json:are_equal(kz_json:new(), undefined)) + ]. + +-define(CHARGES_SIMPLE, + kz_json:decode(<<"{\"phone_numbers\":{\"did_us\":{\"category\":\"phone_numbers\",\"item\":\"did_us\",\"name\":\"US DID\",\"quantity\":1,\"rate\":1.0,\"single_discount\":true,\"single_discount_rate\":0.0,\"cumulative_discount\":1,\"cumulative_discount_rate\":0.5,\"activation_charge\":2.0,\"minimum\":0,\"exceptions\":[],\"activation_charges\":2.0}},\"activation_charges\":2.0}">>)). +-define(CHARGES_DOUBLE, + kz_json:decode(<<"{\"phone_numbers\":{\"did_us\":{\"category\":\"phone_numbers\",\"item\":\"did_us\",\"name\":\"US DID\",\"quantity\":2,\"rate\":2.0,\"single_discount\":true,\"single_discount_rate\":0.0,\"cumulative_discount\":2,\"cumulative_discount_rate\":1.0,\"activation_charge\":4.0,\"minimum\":0,\"exceptions\":[],\"activation_charges\":4.0}},\"activation_charges\":4.0}">>)). + +sum_test_() -> + E = kz_json:new(), + A42 = kz_json:from_list([{<<"a">>, 42}]), + A40 = kz_json:from_list([{<<"a">>, 40}]), + A2 = kz_json:from_list([{<<"a">>, 2}]), + A42Bhi = kz_json:from_list([{<<"a">>, 42}, {<<"b">>, <<"hi">>}]), + A2Bhi = kz_json:from_list([{<<"a">>, 2}, {<<"b">>, <<"hi">>}]), + [?_assertEqual(E, kz_json:sum(E, E)) + ,?_assertEqual(A42, kz_json:sum(A42, E)) + ,?_assertEqual(A42, kz_json:sum(E, A42)) + ,?_assertEqual(A42Bhi, kz_json:sum(A42Bhi, E)) + ,?_assertEqual(A42Bhi, kz_json:sum(E, A42Bhi)) + ,?_assertEqual(A42, kz_json:sum(A40, A2)) + ,?_assertEqual(A42, kz_json:sum(A2, A40)) + ,?_assertEqual(A42Bhi, kz_json:sum(A40, A2Bhi)) + ,?_assertEqual(A42Bhi, kz_json:sum(A2Bhi, A40)) + ,?_assertEqual(?CHARGES_DOUBLE, kz_json:sum(?CHARGES_SIMPLE, ?CHARGES_SIMPLE)) ]. diff --git a/core/kazoo_ledgers/src/kazoo_ledger.erl b/core/kazoo_ledgers/src/kazoo_ledger.erl index 576a7ed03db..7a30700c730 100644 --- a/core/kazoo_ledgers/src/kazoo_ledger.erl +++ b/core/kazoo_ledgers/src/kazoo_ledger.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz, INC +%%% @copyright (C) 2011-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_ledgers/src/kz_ledger.erl b/core/kazoo_ledgers/src/kz_ledger.erl index 906975bfbc7..09b1df07d69 100644 --- a/core/kazoo_ledgers/src/kz_ledger.erl +++ b/core/kazoo_ledgers/src/kz_ledger.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz, INC +%%% @copyright (C) 2011-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_ledgers/src/kz_ledgers.erl b/core/kazoo_ledgers/src/kz_ledgers.erl index 39fb4fd7dec..0304ec69e9e 100644 --- a/core/kazoo_ledgers/src/kz_ledgers.erl +++ b/core/kazoo_ledgers/src/kz_ledgers.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz, INC +%%% @copyright (C) 2011-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_media/src/kazoo_media_app.erl b/core/kazoo_media/src/kazoo_media_app.erl index 2cfa8c2b2c7..06915dcfb3a 100644 --- a/core/kazoo_media/src/kazoo_media_app.erl +++ b/core/kazoo_media/src/kazoo_media_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_media/src/kazoo_media_init.erl b/core/kazoo_media/src/kazoo_media_init.erl index 8002186dc57..469bfe2f41a 100644 --- a/core/kazoo_media/src/kazoo_media_init.erl +++ b/core/kazoo_media/src/kazoo_media_init.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016, 2600Hz INC +%%% @copyright (C) 2010-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_media/src/kazoo_media_maintenance.erl b/core/kazoo_media/src/kazoo_media_maintenance.erl index 0c6bd9293e0..b30818fdef0 100644 --- a/core/kazoo_media/src/kazoo_media_maintenance.erl +++ b/core/kazoo_media/src/kazoo_media_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end @@ -378,8 +378,12 @@ fix_media_name(JObj) -> -spec fix_media_names() -> any(). fix_media_names() -> - {'ok', JObjs} = kz_datamgr:all_docs(?KZ_MEDIA_DB), - case [ JObj || JObj <- JObjs, filter_media_names(JObj)] of - [] -> kapps_config:set(?CONFIG_CAT, <<"fix_media_names">>, 'false'); - List -> lists:foreach(fun fix_media_name/1, List) + case kz_datamgr:all_docs(?KZ_MEDIA_DB) of + {'ok', JObjs} -> + case [ JObj || JObj <- JObjs, filter_media_names(JObj)] of + [] -> kapps_config:set(?CONFIG_CAT, <<"fix_media_names">>, 'false'); + List -> lists:foreach(fun fix_media_name/1, List) + end; + {'error', Error} -> + lager:debug("error '~p' getting media names", [Error]) end. diff --git a/core/kazoo_media/src/kazoo_media_sup.erl b/core/kazoo_media/src/kazoo_media_sup.erl index e4aecff5af2..aa44b3fa452 100644 --- a/core/kazoo_media/src/kazoo_media_sup.erl +++ b/core/kazoo_media/src/kazoo_media_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_media/src/kz_media.erl b/core/kazoo_media/src/kz_media.erl index 4a170b26d0c..1a58a73fbca 100644 --- a/core/kazoo_media/src/kz_media.erl +++ b/core/kazoo_media/src/kz_media.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Handles starting/stopping a call recording %%% diff --git a/core/kazoo_media/src/kz_media_cache_sup.erl b/core/kazoo_media/src/kz_media_cache_sup.erl index fa9e93cda29..be06a4054ac 100644 --- a/core/kazoo_media/src/kz_media_cache_sup.erl +++ b/core/kazoo_media/src/kz_media_cache_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_media/src/kz_media_continuous_proxy.erl b/core/kazoo_media/src/kz_media_continuous_proxy.erl index 1af89c9f4c5..2faa1ae8c58 100644 --- a/core/kazoo_media/src/kz_media_continuous_proxy.erl +++ b/core/kazoo_media/src/kz_media_continuous_proxy.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Handles continuous requests for media binaries %%% New requests enter the stream with the rest of requestors diff --git a/core/kazoo_media/src/kz_media_doc.erl b/core/kazoo_media/src/kz_media_doc.erl index 82d12fb9862..a48c7918fb7 100644 --- a/core/kazoo_media/src/kz_media_doc.erl +++ b/core/kazoo_media/src/kz_media_doc.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_media/src/kz_media_file.erl b/core/kazoo_media/src/kz_media_file.erl index 0a7c2179249..4af43ffa118 100644 --- a/core/kazoo_media/src/kz_media_file.erl +++ b/core/kazoo_media/src/kz_media_file.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_media/src/kz_media_file_cache.erl b/core/kazoo_media/src/kz_media_file_cache.erl index 6a9dc8309b0..189ba855ec8 100644 --- a/core/kazoo_media/src/kz_media_file_cache.erl +++ b/core/kazoo_media/src/kz_media_file_cache.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_media/src/kz_media_map.erl b/core/kazoo_media/src/kz_media_map.erl index 2137fe201b2..cd74ad6f9ac 100644 --- a/core/kazoo_media/src/kz_media_map.erl +++ b/core/kazoo_media/src/kz_media_map.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_media/src/kz_media_proxy.erl b/core/kazoo_media/src/kz_media_proxy.erl index de040614b96..d94c1c4c41a 100644 --- a/core/kazoo_media/src/kz_media_proxy.erl +++ b/core/kazoo_media/src/kz_media_proxy.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2010-2016 2600Hz INC +%%% @copyright (C) 2010-2017 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_media/src/kz_media_proxy_util.erl b/core/kazoo_media/src/kz_media_proxy_util.erl index 6e572e7dbdd..f3564c994dd 100644 --- a/core/kazoo_media/src/kz_media_proxy_util.erl +++ b/core/kazoo_media/src/kz_media_proxy_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Utils shared by the various proxy servers %%% @end diff --git a/core/kazoo_media/src/kz_media_recording.erl b/core/kazoo_media/src/kz_media_recording.erl index 81556211059..70d454abdac 100644 --- a/core/kazoo_media/src/kz_media_recording.erl +++ b/core/kazoo_media/src/kz_media_recording.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Handles starting/stopping a call recording %%% diff --git a/core/kazoo_media/src/kz_media_recording_sup.erl b/core/kazoo_media/src/kz_media_recording_sup.erl index f77027b306b..94d98643208 100644 --- a/core/kazoo_media/src/kz_media_recording_sup.erl +++ b/core/kazoo_media/src/kz_media_recording_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_media/src/kz_media_single_proxy.erl b/core/kazoo_media/src/kz_media_single_proxy.erl index b8651be943b..d0cb3e18033 100644 --- a/core/kazoo_media/src/kz_media_single_proxy.erl +++ b/core/kazoo_media/src/kz_media_single_proxy.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Handles single requests for media binaries %%% @end diff --git a/core/kazoo_media/src/kz_media_store_proxy.erl b/core/kazoo_media/src/kz_media_store_proxy.erl index a2ee2811e04..613254bca58 100644 --- a/core/kazoo_media/src/kz_media_store_proxy.erl +++ b/core/kazoo_media/src/kz_media_store_proxy.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Handles storage proxy requests for media binaries %%% @end diff --git a/core/kazoo_media/src/kz_media_tts.erl b/core/kazoo_media/src/kz_media_tts.erl index 43424d67771..01c0c6bec36 100644 --- a/core/kazoo_media/src/kz_media_tts.erl +++ b/core/kazoo_media/src/kz_media_tts.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_media/src/kz_media_tts_cache.erl b/core/kazoo_media/src/kz_media_tts_cache.erl index 3ca14d00c27..97eda69eab4 100644 --- a/core/kazoo_media/src/kz_media_tts_cache.erl +++ b/core/kazoo_media/src/kz_media_tts_cache.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_media/src/kz_media_url.erl b/core/kazoo_media/src/kz_media_url.erl index edde3ce0a94..43f4bd1e7de 100644 --- a/core/kazoo_media/src/kz_media_url.erl +++ b/core/kazoo_media/src/kz_media_url.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_media/src/kz_media_util.erl b/core/kazoo_media/src/kz_media_util.erl index 598d327e5fa..c112ad457d6 100644 --- a/core/kazoo_media/src/kz_media_util.erl +++ b/core/kazoo_media/src/kz_media_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -11,7 +11,12 @@ -export([recording_url/2]). -export([base_url/2, base_url/3]). -export([convert_stream_type/1 - ,normalize_media/3 + ,normalize_media/3, normalize_media/4 + ,normalize_media_file/3, normalize_media_file/4 + ,synthesize_tone/3, synthesize_tone/4 + ,detect_file_sample_rate/1 + ,detect_file_format/1 + ,join_media_files/1, join_media_files/2 ]). -export([media_path/1, media_path/2]). -export([max_recording_time_limit/0]). @@ -36,86 +41,301 @@ -define(NORMALIZE_SOURCE_ARGS, kapps_config:get_binary(?CONFIG_CAT, <<"normalize_source_args">>, <<>>)). -define(NORMALIZE_DEST_ARGS, kapps_config:get_binary(?CONFIG_CAT, <<"normalize_destination_args">>, <<"-r 8000">>)). +-define(NORMALIZATION_FORMAT, kapps_config:get(<<"crossbar.media">>, <<"normalization_format">>, <<"mp3">>)). + -define(USE_ACCOUNT_OVERRIDES, kapps_config:get_is_true(?CONFIG_CAT, <<"support_account_overrides">>, 'true')). --type normalized_media() :: {'ok', iolist()} | - {'error', ne_binary()}. --spec normalize_media(ne_binary(), ne_binary(), binary()) -> - normalized_media(). --spec normalize_media(ne_binary(), ne_binary(), binary(), kz_proplist()) -> - normalized_media(). +%%-------------------------------------------------------------------- +%% @doc +%% Normalize audio file to the system default or specified sample rate. +%% Acceptes media file content binary as input. +%% +%% By default it returns result as binary, if you want file path to the +%% normalized file only, pass the {'output', 'file'} as option. +%% @end +%%-------------------------------------------------------------------- +-type normalized_media() :: {'ok', iodata()} | {'error', any()}. + +-spec normalize_media(ne_binary(), ne_binary(), binary()) -> normalized_media(). normalize_media(FromFormat, FromFormat, FileContents) -> {'ok', FileContents}; normalize_media(FromFormat, ToFormat, FileContents) -> normalize_media(FromFormat, ToFormat, FileContents, []). +-spec normalize_media(ne_binary(), ne_binary(), binary(), kz_proplist()) -> normalized_media(). normalize_media(FromFormat, ToFormat, FileContents, Options) -> - OldFlag = process_flag('trap_exit', 'true'), + FileName = tmp_file(FromFormat), + case file:write_file(FileName, FileContents) of + ok -> + Result = normalize_media_file(FromFormat, ToFormat, FileName, Options), + kz_util:delete_file(FileName), + {'ok', Result}; + {'error', _}=Error -> Error + end. +%%-------------------------------------------------------------------- +%% @doc +%% Normalize audio file to the system default or specified sample rate. +%% Acceptes a path to the media file as input. +%% +%% By default it returns result as binary, if you want file path to the +%% normalized file only, pass the {'output', 'file'} as option. +%% @end +%%-------------------------------------------------------------------- +-spec normalize_media_file(ne_binary(), ne_binary(), binary()) -> normalized_media(). +normalize_media_file(FromFormat, FromFormat, FromFile) -> + {'ok', FromFile}; +normalize_media_file(FromFormat, ToFormat, FromFile) -> + normalize_media_file(FromFormat, ToFormat, FromFile, []). + +-spec normalize_media_file(ne_binary(), ne_binary(), binary(), kz_proplist()) -> normalized_media(). +normalize_media_file(FromFormat, ToFormat, FromFile, Options) -> FromArgs = props:get_value('from_args', Options, ?NORMALIZE_SOURCE_ARGS), ToArgs = props:get_value('to_args', Options, ?NORMALIZE_DEST_ARGS), ExtraArgs = props:get_value('extra_args', Options, ""), + ToFile = props:get_value('out_file', Options, tmp_file(ToFormat)), Command = iolist_to_binary([?NORMALIZE_EXE ," ", ExtraArgs - ," -t ", FromFormat, " ", FromArgs, " - " - ," -t ", ToFormat, " ", ToArgs, " - " + ," -t ", FromFormat, " ", FromArgs, " ", FromFile + ," -t ", ToFormat, " ", ToArgs, " ", ToFile ]), - PortOptions = ['binary' - ,'exit_status' - ,'use_stdio' - ,'stderr_to_stdout' - ], - Response = - try open_port({'spawn', kz_util:to_list(Command)}, PortOptions) of - Port -> - lager:debug("opened port ~p to sox with '~s'", [Port, Command]), - do_normalize_media(FileContents, Port, props:get_integer_value('timeout', Options, 20 * ?MILLISECONDS_IN_SECOND)) - catch - _E:_R -> - lager:debug("failed to open port with '~s': ~s: ~p", [Command, _E, _R]), - {'error', <<"failed to open conversion utility">>} - end, - process_flag('trap_exit', OldFlag), - Response. - --spec do_normalize_media(binary(), port(), pos_integer()) -> - normalized_media(). -do_normalize_media(FileContents, Port, Timeout) -> - try erlang:port_command(Port, FileContents) of - 'true' -> - lager:debug("sent data to port"), - wait_for_results(Port, Timeout) + OutputType = props:get_value('output', Options, 'binary'), + lager:debug("normalize media with command: ~p", [Command]), + return_command_result(run_command(Command), ToFile, OutputType). + +-spec return_command_result({'ok', any()} | {'error', any()}, ne_binary(), 'binary' | 'file') -> normalized_media(). +return_command_result({'ok', _}, FileName, 'binary') -> + case file:read_file(FileName) of + {'ok', _}=OK -> + _ = kz_util:delete_file(FileName), + OK; + {'error', _}=Error -> Error + end; +return_command_result({'ok', _}, FileName, 'file') -> {'ok', FileName}; +return_command_result({'error', _}=Error, _FileName, _) -> Error. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% Run normalizer command +%% @end +%%-------------------------------------------------------------------- +-spec run_command(ne_binary()) -> normalized_media(). +run_command(Command) -> + try os:cmd(binary_to_list(Command)) of + Result -> + lager:debug("conversion utility result: ~p", [Result]), + {'ok', Result} catch - _E:_R -> - lager:debug("failed to send data to port: ~s: ~p", [_E, _R]), - catch erlang:port_close(Port), - {'error', <<"failed to communicate with conversion utility">>} + _E:Reason -> + lager:warning("conversion utility resulted in an exception: ~p:~p", [_E, Reason]), + {'error', Reason} + end. + +%%-------------------------------------------------------------------- +%% @doc +%% Synthesize a tone, returns as binary or a path to the generated file +%% @end +%%-------------------------------------------------------------------- +-spec synthesize_tone(ne_binary(), ne_binary(), ne_binary()) -> normalized_media(). +synthesize_tone(SampleRate, Frequency, Length) -> + FileName = tmp_file(<<"wav">>), + case synthesize_tone(SampleRate, Frequency, Length, FileName) of + {'ok', _} -> + Result = file:read_file(FileName), + kz_util:delete_file(FileName), + Result; + {'error', _}=Error -> Error + end. + +%%-------------------------------------------------------------------- +%% @doc +%% Synthesize a tone, returns as binary or a path to the generated file +%% @end +%%-------------------------------------------------------------------- +-spec synthesize_tone(ne_binary(), ne_binary(), ne_binary(), ne_binary()) -> normalized_media(). +synthesize_tone(SampleRate, Frequency, Length, FileName) -> + Command = iolist_to_binary([?NORMALIZE_EXE + ,<<" -r ">>, SampleRate + ,<<" -n ">>, FileName + ,<<" synth ">>, Length + ,<<" sin ">>, Frequency + ]), + lager:info("synthesize tone command ~p", [Command]), + run_command(Command). + +%%-------------------------------------------------------------------- +%% @doc +%% Detect sample rate of a media file +%% @end +%%-------------------------------------------------------------------- +-spec detect_file_sample_rate(ne_binary()) -> normalized_media(). +detect_file_sample_rate(FileName) -> + Command = iolist_to_binary([?NORMALIZE_EXE + ,<<" --i -r ">> + ,FileName + ]), + lager:info("detect sample rate command ~p", [Command]), + case run_command(Command) of + {'ok', Result} -> + Regex = "^(\\d+).*$", + RegexOptions = [{'capture', [1], 'binary'}], + case re:run(Result, Regex, RegexOptions) of + {'match', [SampleRate]} -> + {'ok', SampleRate}; + _Else -> + {'error', 'detection_failed'} + end; + {'error', _} -> + {'error', 'detection_failed'} + end. + +%%-------------------------------------------------------------------- +%% @doc +%% Detect media format of a media file +%% @end +%%-------------------------------------------------------------------- +-spec detect_file_format(ne_binary()) -> normalized_media(). +detect_file_format(FileName) -> + Command = iolist_to_binary([?NORMALIZE_EXE + ,<<" --i -t ">> + ,FileName + ]), + lager:info("detect file type command ~p~n~n", [Command]), + case run_command(Command) of + {'ok', Result} -> + Regex = "^(\\w+).*$", + RegexOptions = [{'capture', [1], 'binary'}], + case re:run(Result, Regex, RegexOptions) of + {'match', [Format]} -> + {'ok', Format}; + _Else -> + {'error', 'detection_failed'} + end; + {'error', _} -> + {'error', 'detection_failed'} + end. + +%%-------------------------------------------------------------------- +%% @doc +%% Join multiple Audio file together. It detects file format, sample rate +%% of each file and will try to convert sample rate if it different from the +%% requested sample rate or the default value of 16kHz. +%% @end +%%-------------------------------------------------------------------- +-type join_file() :: {ne_binary(), api_binary(), api_binary()}. +-type join_files() :: [join_file()]. + +-spec join_media_files(ne_binaries()) -> normalized_media(). +join_media_files(FileNames) -> + join_media_files(FileNames, []). + +-spec join_media_files(ne_binaries(), kz_proplist()) -> normalized_media(). +join_media_files(FileNames, Options) -> + DetectedOpts = [detect_format_options(F) || F <- FileNames], + SampleRate = props:get_value('sample_rate', Options, <<"16000">>), + case maybe_normalize_copy_files(DetectedOpts, SampleRate, []) of + {'ok', NewOpts} -> + maybe_join_media_files(NewOpts, Options, []); + {'error', _}=Error -> Error + end. + +-spec maybe_join_media_files(join_files(), kz_proplist(), join_files()) -> normalized_media(). +maybe_join_media_files([], Options, Acc) -> do_join_media_files(Acc, Options); +maybe_join_media_files([{_, 'undefined', _}|_], _, _) -> {'error', 'join_media_failed'}; +maybe_join_media_files([{_, _, 'undefined'}|_], _, _) -> {'error', 'join_media_failed'}; +maybe_join_media_files([F|Files], Options, Acc) -> + maybe_join_media_files(Files, Options, [F|Acc]). + +-spec do_join_media_files(join_files(), kz_proplist()) -> normalized_media(). +do_join_media_files(Files, Options) -> + SampleRate = props:get_value('sample_rate', Options, <<"16000">>), + ToFormat = props:get_value('to_format', Options, ?NORMALIZATION_FORMAT), + ToFile = props:get_value('out_file', Options, tmp_file(ToFormat)), + Command = iolist_to_binary( + [?NORMALIZE_EXE + ,[[" -r ", Rate, " -t ", Format, " ", File] + || {File, Rate, Format} <- Files + ] + ," -r ", SampleRate + ," -t ", ToFormat + ," ", ToFile + ] + ), + OutputType = props:get_value('output', Options, 'binary'), + lager:debug("joining media files with command: ~p", [Command]), + Result = return_command_result(run_command(Command), ToFile, OutputType), + %% cleanup copied files + _ = [kz_util:delete_file(F) || {F, _, _} <- Files], + Result. + +%%-------------------------------------------------------------------- +%% @private +%% @doc Based on detected format options, normalize the files if +%% sample rate are different of desire sample rate, otherwise +%% copy the files to a temporary place to join them together. +%% @end +%%-------------------------------------------------------------------- +-spec maybe_normalize_copy_files(join_files(), ne_binary(), join_files()) -> + {'ok', join_files()} | + {'error', 'normalization_failed'}. +maybe_normalize_copy_files([], _SampleRate, Acc) -> {'ok', Acc}; +maybe_normalize_copy_files([{File, SampleRate, Format}|Files], SampleRate, Acc) -> + NewFile = tmp_file(Format), + case file:copy(File, NewFile) of + {'ok', _} -> + maybe_normalize_copy_files(Files, SampleRate, [{NewFile, SampleRate, Format}|Acc]); + {'error', _} -> + lager:warning("failed to copy file to a temproray place to join media files"), + %% cleanup already copied files + _ = [kz_util:delete_file(F) || {F, _, _} <- Files], + {'error', 'normalization_failed'} + end; +maybe_normalize_copy_files([{File, _Other, Format}|Files], SampleRate, Acc) -> + NormOptions = [{'output', 'file'} + ,{'to_args', <<"-r ", SampleRate/binary>>} + ], + case normalize_media_file(Format, Format, File, NormOptions) of + {'ok', NormFile} -> + maybe_normalize_copy_files(Files, SampleRate, [{NormFile, SampleRate, Format}|Acc]); + {'error', _} -> + lager:warning("can't normalize file ~s for preforming join media", [File]), + %% cleanup already copied files + _ = [kz_util:delete_file(F) || {F, _, _} <- Files], + {'error', 'normalization_failed'} end. --spec wait_for_results(port(), pos_integer()) -> normalized_media(). --spec wait_for_results(port(), pos_integer(), iolist()) -> normalized_media(). -wait_for_results(Port, Timeout) -> - wait_for_results(Port, Timeout, []). -wait_for_results(Port, Timeout, Response) -> - receive - {Port, {'data', Msg}} -> - wait_for_results(Port, Timeout, [Response | [Msg]]); - {Port, {'exit_status', 0}} -> - lager:debug("process exited successfully"), - {'ok', Response}; - {Port, {'exit_status', _Err}} -> - lager:debug("process exited with status ~p", [_Err]), - {'error', iolist_to_binary(Response)}; - {'EXIT', Port, _Reason} -> - lager:debug("port closed unexpectedly: ~p", [_Reason]), - {'error', iolist_to_binary(Response)} - after Timeout -> - lager:debug("timeout, sending error response: ~p", [Response]), - catch erlang:port_close(Port), - {'error', iolist_to_binary(Response)} +%%-------------------------------------------------------------------- +%% @private +%% @doc Detect file format options(sample_rate, file format) and return +%% a tuple of detect options +%% @end +%%-------------------------------------------------------------------- +-spec detect_format_options(ne_binary()) -> join_file(). +detect_format_options(File) -> + FileSampleRate = detect_file_sample_rate(File), + FileFormat = detect_file_format(File), + case {FileSampleRate, FileFormat} of + {{'ok', SampleRate}, {'ok', Format}} -> + {File, SampleRate, Format}; + {{'ok', SampleRate}, {'error', _}} -> + {File, SampleRate, 'undefined'}; + {{'error', _}, {'ok', Format}} -> + {File, 'undefined', Format}; + {{'error', _}, {'error', _}} -> + {File, 'undefined', 'undefined'} end. +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% @end +%%-------------------------------------------------------------------- +-spec tmp_file(ne_binary()) -> ne_binary(). +tmp_file(Ext) -> + <<"/tmp/", (kz_util:rand_hex_binary(16))/binary, ".", Ext/binary>>. + -spec recording_url(ne_binary(), kz_json:object()) -> ne_binary(). recording_url(CallId, Data) -> %% TODO: look at the URL for {filename}, if present replace it with diff --git a/core/kazoo_modb/priv/couchdb/views/cdrs.json b/core/kazoo_modb/priv/couchdb/views/cdrs.json index fefe9bc0d28..cbfc2170f96 100644 --- a/core/kazoo_modb/priv/couchdb/views/cdrs.json +++ b/core/kazoo_modb/priv/couchdb/views/cdrs.json @@ -1,6 +1,9 @@ { "_id": "_design/cdrs", "language": "javascript", + "lists": { + "format_summary": "function() { var row, results = {'inbound': {}, 'outbound': {}}; while(row = getRow()){ var value = row.value; if(!results[value.direction][value.domain]) results[value.direction][value.domain] = {}; if(!results[value.direction][value.domain][value.classifier]) results[value.direction][value.domain][value.classifier] = {'total': 0}; results[value.direction][value.domain][value.classifier]['total'] += value.billable_seconds; if(value.rate_name) { if(!results[value.direction][value.domain][value.classifier][value.rate_name]) results[value.direction][value.domain][value.classifier][value.rate_name] = 0; results[value.direction][value.domain][value.classifier][value.rate_name] += value.billable_seconds; }} return JSON.stringify({'total_rows':1,'offset':0,'rows':[results]});}" + }, "views": { "crossbar_listing": { "map": "function(doc) {if (doc.pvt_deleted || doc.pvt_type != 'cdr') return;emit(doc.pvt_created, {id: doc._id,call_id: doc.call_id,caller_id_name: doc.caller_id_name,caller_id_number: doc.caller_id_number,callee_id_name: doc.callee_id_name,callee_id_number: doc.callee_id_number,duration_seconds: doc.duration_seconds,billing_seconds: doc.billing_seconds,timestamp: doc.timestamp,hangup_cause: doc.hangup_cause,other_leg_call_id: doc.other_leg_call_id,owner_id: doc.custom_channel_vars.owner_id,to: doc.to_uri,from: doc.from_uri,inception: doc.custom_channel_vars.inception,direction: doc.call_direction,request: doc.request,authorizing_id: doc.custom_channel_vars.authorizing_id,media_recordings: doc.custom_channel_vars.media_recordings});}" @@ -18,6 +21,9 @@ }, "listing_by_owner": { "map": "function(doc) { if(doc.pvt_type != 'cdr' || doc.pvt_deleted || !doc.custom_channel_vars || !doc.custom_channel_vars.owner_id) return; emit([doc.custom_channel_vars.owner_id, doc.pvt_created], {'id':doc._id, 'call_id': doc.call_id, 'caller_id_name': doc.caller_id_name, 'caller_id_number': doc.caller_id_number, 'callee_id_name': doc.callee_id_name, 'callee_id_number': doc.callee_id_number, 'duration_seconds': doc.duration_seconds, 'billing_seconds': doc.billing_seconds, 'timestamp': doc.timestamp, 'hangup_cause':doc.hangup_cause, 'other_leg_call_id':doc.other_leg_call_id, 'call_direction':doc.call_direction, 'to': doc.to_uri, 'from': doc.from_uri, 'inception':doc.custom_channel_vars.inception})}" + }, + "summarize_cdrs": { + "map": "function(doc) { if(doc.pvt_type != 'cdr' || doc.pvt_deleted || !doc.custom_channel_vars || doc.channel_name.indexOf(\"loopback\") !== -1 || (doc.call_direction == 'inbound' && doc.custom_channel_vars.authorizing_id) || (doc.call_direction == 'outbound' && !doc.custom_channel_vars.resource_id)) return; if (doc.call_direction == 'inbound') { var domain = doc.from.substr(doc.from.indexOf(\"@\") + 1); } else { var domain = doc.to.substr(doc.to.indexOf(\"@\") + 1); } var number = doc.to.substr(0, doc.to.indexOf('@')); if (number.match(/^\\+1((?:800|888|877|866|855)\\d{7})$/)) { var classifier = 'tollfree_us'; } else if (number.match(/^\\+1(900\\d{7})$/)) { var classifier = 'toll_us'; } else if (number.match(/^(911|933)$/)) { var classifier = 'emergency'; } else if (number.match(/^\\+?1((?:684|264|268|242|246|441|284|345|767|809|829|849|473|671|876|664|670|787|939|869|758|784|721|868|649|340)\\d{7})$/)) { var classifier = 'caribbean'; } else if (number.match(/^\\+?1?([2-9][0-9]{2}[2-9][0-9]{6})$/)) { var classifier = 'did_us'; } else if (number.match(/^\\+[2-9]\\d{7,}$/)) { var classifier = 'international'; } else { var classifier = 'unknown'; } if (doc.custom_channel_vars.rate_name) { emit (doc.pvt_created, {'direction': doc.call_direction, 'classifier': classifier, 'domain': domain, 'billable_seconds': parseInt(doc.billing_seconds), 'rate_name': doc.custom_channel_vars.rate_name}); } else { emit (doc.pvt_created, {'direction': doc.call_direction, 'classifier': classifier, 'domain': domain, 'billable_seconds': parseInt(doc.billing_seconds)}); }}" } } } diff --git a/core/kazoo_modb/src/kazoo_modb.erl b/core/kazoo_modb/src/kazoo_modb.erl index 03e465ee133..05d596ef331 100644 --- a/core/kazoo_modb/src/kazoo_modb.erl +++ b/core/kazoo_modb/src/kazoo_modb.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz, INC +%%% @copyright (C) 2011-2017, 2600Hz, INC %%% @doc %%% %%% @end @@ -326,7 +326,7 @@ is_account_deleted(AccountId) -> -spec refresh_views(ne_binary()) -> 'ok'. refresh_views(AccountMODb) -> - lager:debug("init modb ~p", [AccountMODb]), + lager:debug("refresh views on modb ~p", [AccountMODb]), EncodedMODb = kz_util:format_account_modb(AccountMODb, 'encoded'), Views = get_modb_views(), _ = kapps_util:update_views(EncodedMODb, Views, 'true'), diff --git a/core/kazoo_modb/src/kazoo_modb_maintenance.erl b/core/kazoo_modb/src/kazoo_modb_maintenance.erl index 3fe2650b6f6..c032cd53495 100644 --- a/core/kazoo_modb/src/kazoo_modb_maintenance.erl +++ b/core/kazoo_modb/src/kazoo_modb_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -32,14 +32,16 @@ delete_modbs(Period) -> io:format("period '~s' does not match YYYYMM format~n", [Period]) end. -delete_modbs(<<_/binary>> = Year, Month) -> +delete_modbs(?NE_BINARY=Year, Month) -> delete_modbs(kz_util:to_integer(Year), Month); -delete_modbs(Year, <<_/binary>> = Month) -> +delete_modbs(Year, ?NE_BINARY=Month) -> delete_modbs(Year, kz_util:to_integer(Month)); delete_modbs(Year, Month) when is_integer(Year), is_integer(Month), - Year > 2000 andalso Year < 2999, - Month > 0 andalso Month < 13 -> + Year > 2000, + Year < 2999, + Month > 0, + Month < 13 -> case erlang:date() of {Year, Month, _} -> io:format("request to delete the current MODB (~p~p) denied~n", [Year, Month]); diff --git a/core/kazoo_modb/src/kazoo_modb_util.erl b/core/kazoo_modb/src/kazoo_modb_util.erl index af0c60f5450..f7f4f812435 100644 --- a/core/kazoo_modb/src/kazoo_modb_util.erl +++ b/core/kazoo_modb/src/kazoo_modb_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz, INC +%%% @copyright (C) 2011-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_modb/src/kazoo_modb_view.erl b/core/kazoo_modb/src/kazoo_modb_view.erl index a97f69d17a1..89b30098dba 100644 --- a/core/kazoo_modb/src/kazoo_modb_view.erl +++ b/core/kazoo_modb/src/kazoo_modb_view.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz +%%% @copyright (C) 2011-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_modb/test/kazoo_modb_util_test.erl b/core/kazoo_modb/test/kazoo_modb_util_test.erl index d63a688adf6..3c8befdab82 100644 --- a/core/kazoo_modb/test/kazoo_modb_util_test.erl +++ b/core/kazoo_modb/test/kazoo_modb_util_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz, INC +%%% @copyright (C) 2011-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_number_manager/include/knm_phone_number.hrl b/core/kazoo_number_manager/include/knm_phone_number.hrl index f7771ed547e..6b545f65bb8 100644 --- a/core/kazoo_number_manager/include/knm_phone_number.hrl +++ b/core/kazoo_number_manager/include/knm_phone_number.hrl @@ -26,8 +26,8 @@ -define(PVT_CREATED, <<"pvt_created">>). -define(PVT_DB_NAME, <<"pvt_db_name">>). -define(PVT_FEATURES, <<"pvt_features">>). --define(PVT_FEATURES_AVAILABLE, <<"pvt_features_available">>). --define(PVT_IS_BILLABLE, <<"pvt_is_billable">>). +-define(PVT_FEATURES_ALLOWED, <<"pvt_features_allowed">>). +-define(PVT_FEATURES_DENIED, <<"pvt_features_denied">>). -define(PVT_MODIFIED, <<"pvt_modified">>). -define(PVT_MODULE_NAME, <<"pvt_module_name">>). -define(PVT_PORTED_IN, <<"pvt_ported_in">>). @@ -75,6 +75,23 @@ -define(FEATURE_PREPEND, <<"prepend">>). -define(FEATURE_RINGBACK, <<"ringback">>). +-define(LEGACY_DASH_E911, <<"dash_e911">>). +-define(LEGACY_TELNYX_E911, <<"telnyx_e911">>). +-define(LEGACY_VITELITY_E911, <<"vitelity_e911">>). + +-define(KAZOO_NUMBER_FEATURES, [?FEATURE_FAILOVER + ,?FEATURE_FORCE_OUTBOUND + ,?FEATURE_PREPEND + ,?FEATURE_RINGBACK + ]). + +-define(EXTERNAL_NUMBER_FEATURES, [?FEATURE_CNAM + ,?FEATURE_CNAM_INBOUND + ,?FEATURE_CNAM_OUTBOUND + ,?FEATURE_E911 + ,?FEATURE_PORT + ]). + -define(CNAM_DISPLAY_NAME, <<"display_name">>). -define(CNAM_INBOUND_LOOKUP, <<"inbound_lookup">>). diff --git a/core/kazoo_number_manager/priv/fixtures/old_vsn_1_out.json b/core/kazoo_number_manager/priv/fixtures/old_vsn_1_out.json index 5a167c67cff..0e79c2d3950 100644 --- a/core/kazoo_number_manager/priv/fixtures/old_vsn_1_out.json +++ b/core/kazoo_number_manager/priv/fixtures/old_vsn_1_out.json @@ -8,12 +8,19 @@ "pvt_features": { "local": {} }, - "pvt_features_available": [ + "pvt_features_allowed": [ + "failover", + "force_outbound", + "prepend", + "ringback" + ], + "pvt_features_denied": [ "cnam", + "inbound_cnam", + "outbound_cnam", "e911", - "failover", "port", - "prepend" + "failover" ], "pvt_is_billable": false, "pvt_modified": 63648176955, diff --git a/core/kazoo_number_manager/priv/fixtures/old_vsn_2_out.json b/core/kazoo_number_manager/priv/fixtures/old_vsn_2_out.json index c0d09886646..b74e88c1b5a 100644 --- a/core/kazoo_number_manager/priv/fixtures/old_vsn_2_out.json +++ b/core/kazoo_number_manager/priv/fixtures/old_vsn_2_out.json @@ -4,14 +4,16 @@ "pvt_authorizing_account": "system", "pvt_created": 63637990840, "pvt_db_name": "numbers%2F%2B1201", - "pvt_features_available": [ - "cnam", - "e911", + "pvt_features_allowed": [ "failover", - "port", - "prepend" + "force_outbound", + "prepend", + "ringback" ], - "pvt_is_billable": false, + "pvt_features_denied": [ + "failover" + ], + "pvt_is_billable": true, "pvt_modified": 63637990854, "pvt_module_name": "knm_pacwest", "pvt_ported_in": false, diff --git a/core/kazoo_number_manager/priv/fixtures/old_vsn_3_in.json b/core/kazoo_number_manager/priv/fixtures/old_vsn_3_in.json new file mode 100644 index 00000000000..7411ce30773 --- /dev/null +++ b/core/kazoo_number_manager/priv/fixtures/old_vsn_3_in.json @@ -0,0 +1,58 @@ +{ + "_id": "+14082141750", + "_rev": "5-d8c63d6bdc3e8376e9ffe157904ce114", + "e911": { + "extended_address": "", + "locality": "SAN FRANCISCO", + "postal_code": "94108-5630", + "region": "CA", + "street_address": "140 GEARY ST" + }, + "features": [ + "e911" + ], + "pvt_assigned_to": "eda33e3561baf133f9a088340643e35c", + "pvt_authorizing_account": "eda33e3561baf133f9a088340643e35c", + "pvt_carrier_data": { + "number": "+14082141750", + "order_id": "6c7e81e558cc48e1a55c783ff06244cc", + "order_name": "avaya-63646110391", + "rate_center": { + "lata": "722", + "name": "SAN MARTIN", + "state": "CA" + } + }, + "pvt_created": 63646110391, + "pvt_db_name": "numbers%2F%2B1408", + "pvt_features": { + "e911": { + "extended_address": "", + "locality": "SAN FRANCISCO", + "postal_code": "94108-5630", + "region": "CA", + "street_address": "140 GEARY ST" + } + }, + "pvt_features_available": [ + "cnam", + "dash_e911", + "failover", + "port", + "prepend", + "vitelity_e911", + "e911" + ], + "pvt_modified": 63646110391, + "pvt_module_name": "knm_bandwidth2", + "pvt_number_state": "in_service", + "pvt_type": "number", + "pvt_used_by": "callflow", + "state": "in_service", + "ui_metadata": { + "origin": "common", + "ui": "monster-ui", + "version": "4.0-3" + }, + "used_by": "callflow" +} diff --git a/core/kazoo_number_manager/priv/fixtures/old_vsn_3_out.json b/core/kazoo_number_manager/priv/fixtures/old_vsn_3_out.json new file mode 100644 index 00000000000..d75b551e349 --- /dev/null +++ b/core/kazoo_number_manager/priv/fixtures/old_vsn_3_out.json @@ -0,0 +1,56 @@ +{ + "_id": "+14082141750", + "e911": { + "extended_address": "", + "locality": "SAN FRANCISCO", + "postal_code": "94108-5630", + "region": "CA", + "street_address": "140 GEARY ST" + }, + "pvt_assigned_to": "eda33e3561baf133f9a088340643e35c", + "pvt_authorizing_account": "system", + "pvt_carrier_data": { + "number": "+14082141750", + "order_id": "6c7e81e558cc48e1a55c783ff06244cc", + "order_name": "avaya-63646110391", + "rate_center": { + "lata": "722", + "name": "SAN MARTIN", + "state": "CA" + } + }, + "pvt_created": 63646110391, + "pvt_db_name": "numbers%2F%2B1408", + "pvt_features": { + "e911": { + "extended_address": "", + "locality": "SAN FRANCISCO", + "postal_code": "94108-5630", + "region": "CA", + "street_address": "140 GEARY ST" + } + }, + "pvt_features_allowed": [ + "failover", + "force_outbound", + "prepend", + "ringback" + ], + "pvt_features_denied": [ + "failover" + ], + "pvt_is_billable": true, + "pvt_modified": 6364611391, + "pvt_module_name": "knm_bandwidth2", + "pvt_ported_in": false, + "pvt_state": "in_service", + "pvt_type": "number", + "pvt_used_by": "callflow", + "state": "in_service", + "ui_metadata": { + "origin": "common", + "ui": "monster-ui", + "version": "4.0-3" + }, + "used_by": "callflow" +} diff --git a/core/kazoo_number_manager/priv/fixtures/old_vsn_4_in.json b/core/kazoo_number_manager/priv/fixtures/old_vsn_4_in.json new file mode 100644 index 00000000000..dc9ed7d2efe --- /dev/null +++ b/core/kazoo_number_manager/priv/fixtures/old_vsn_4_in.json @@ -0,0 +1,29 @@ +{ + "AintThey": "pretty", + "MyField": [ + { + "my": "vals" + }, + 41, + 2 + ], + "_id": "+14242424247", + "_rev": "1-62ac91830bae51385cb4c6d56f294444", + "dash_e911": { + "caller_name": "Moua" + }, + "pvt_assigned_to": "4b8c6fec4b2597882c0390202d195419", + "pvt_authorizing_account": "4b8c6fec4b2597882c0390202d195419", + "pvt_created": 63627551737, + "pvt_db_name": "numbers%2F%2B1424", + "pvt_features": [], + "pvt_modified": 63627551739, + "pvt_module_name": "wnm_local", + "pvt_number_state": "reserved", + "pvt_reserve_history": [ + "4b8c6fec4b2597882c0390202d195419" + ], + "pvt_resource_db": "account%2F4b%2F8c%2F6fec4b2597882c0390202d195419", + "pvt_type": "number", + "used_by": "" +} diff --git a/core/kazoo_number_manager/priv/fixtures/old_vsn_4_out.json b/core/kazoo_number_manager/priv/fixtures/old_vsn_4_out.json new file mode 100644 index 00000000000..bf0778e9e92 --- /dev/null +++ b/core/kazoo_number_manager/priv/fixtures/old_vsn_4_out.json @@ -0,0 +1,47 @@ +{ + "AintThey": "pretty", + "MyField": [ + { + "my": "vals" + }, + 41, + 2 + ], + "_id": "+14242424247", + "dash_e911": { + "caller_name": "Moua" + }, + "e911": { + "caller_name": "Moua" + }, + "pvt_assigned_to": "4b8c6fec4b2597882c0390202d195419", + "pvt_authorizing_account": "system", + "pvt_created": 63627551737, + "pvt_db_name": "numbers%2F%2B1424", + "pvt_features": { + "local": {} + }, + "pvt_features_allowed": [ + "failover", + "force_outbound", + "prepend", + "ringback" + ], + "pvt_features_denied": [ + "cnam", + "inbound_cnam", + "outbound_cnam", + "e911", + "port", + "failover" + ], + "pvt_is_billable": false, + "pvt_modified": 63648366250, + "pvt_module_name": "knm_local", + "pvt_ported_in": false, + "pvt_reserve_history": [ + "4b8c6fec4b2597882c0390202d195419" + ], + "pvt_state": "reserved", + "pvt_type": "number" +} diff --git a/core/kazoo_number_manager/priv/fixtures/old_vsn_5_in.json b/core/kazoo_number_manager/priv/fixtures/old_vsn_5_in.json new file mode 100644 index 00000000000..c1e9ee73bce --- /dev/null +++ b/core/kazoo_number_manager/priv/fixtures/old_vsn_5_in.json @@ -0,0 +1,62 @@ +{ + "_id": "+19377038880", + "_rev": "31-a78eb06dc40b3203fb2800f19f6ef8c4", + "cnam": { + "display_name": "Bruce Wayne", + "inbound_lookup": true + }, + "dash_e911": { + "caller_name": "Valued Customer", + "latitude": "40.05424", + "legacy_data": { + "house_number": "23", + "predirectional": "N", + "streetname": "MAIN ST" + }, + "locality": "PLEASANT SIDE", + "location_id": "32379723", + "longitude": "-87.34416", + "plus_four": "8001", + "postal_code": "55359", + "region": "KZ", + "status": "PROVISIONED", + "street_address": "23 N MAIN ST" + }, + "pvt_assigned_to": "112bce1b4b782f2b33b366e420d05673", + "pvt_authorizing_account": "system", + "pvt_db_name": "numbers%2F%2B1937", + "pvt_features": { + "dash_e911": { + "caller_name": "Valued Customer", + "latitude": "40.05424", + "legacy_data": { + "house_number": "23", + "predirectional": "N", + "streetname": "MAIN ST" + }, + "locality": "PLEASANT SIDE", + "location_id": "32379723", + "longitude": "-87.34416", + "plus_four": "8001", + "postal_code": "55359", + "region": "KZ", + "status": "PROVISIONED", + "street_address": "23 N MAIN ST" + }, + "inbound_cnam": { + "inbound_lookup": true + }, + "outbound_cnam": { + "display_name": "Bruce Wayne" + } + }, + "pvt_module_name": "knm_bandwidth2", + "pvt_number_state": "in_service", + "pvt_type": "number", + "state": "in_service", + "ui_metadata": { + "ui": "kazoo-ui", + "version": "3.14-1" + }, + "used_by": "trunkstore" +} diff --git a/core/kazoo_number_manager/priv/fixtures/old_vsn_5_out.json b/core/kazoo_number_manager/priv/fixtures/old_vsn_5_out.json new file mode 100644 index 00000000000..76a4b2f8475 --- /dev/null +++ b/core/kazoo_number_manager/priv/fixtures/old_vsn_5_out.json @@ -0,0 +1,90 @@ +{ + "_id": "+19377038880", + "cnam": { + "display_name": "Bruce Wayne", + "inbound_lookup": true + }, + "dash_e911": { + "caller_name": "Valued Customer", + "latitude": "40.05424", + "legacy_data": { + "house_number": "23", + "predirectional": "N", + "streetname": "MAIN ST" + }, + "locality": "PLEASANT SIDE", + "location_id": "32379723", + "longitude": "-87.34416", + "plus_four": "8001", + "postal_code": "55359", + "region": "KZ", + "status": "PROVISIONED", + "street_address": "23 N MAIN ST" + }, + "e911": { + "caller_name": "Valued Customer", + "latitude": "40.05424", + "legacy_data": { + "house_number": "23", + "predirectional": "N", + "streetname": "MAIN ST" + }, + "locality": "PLEASANT SIDE", + "location_id": "32379723", + "longitude": "-87.34416", + "plus_four": "8001", + "postal_code": "55359", + "region": "KZ", + "status": "PROVISIONED", + "street_address": "23 N MAIN ST" + }, + "pvt_assigned_to": "112bce1b4b782f2b33b366e420d05673", + "pvt_authorizing_account": "system", + "pvt_created": 63606025486, + "pvt_db_name": "numbers%2F%2B1937", + "pvt_features": { + "e911": { + "caller_name": "Valued Customer", + "latitude": "40.05424", + "legacy_data": { + "house_number": "23", + "predirectional": "N", + "streetname": "MAIN ST" + }, + "locality": "PLEASANT SIDE", + "location_id": "32379723", + "longitude": "-87.34416", + "plus_four": "8001", + "postal_code": "55359", + "region": "KZ", + "status": "PROVISIONED", + "street_address": "23 N MAIN ST" + }, + "inbound_cnam": { + "inbound_lookup": true + }, + "outbound_cnam": { + "display_name": "Bruce Wayne" + } + }, + "pvt_features_allowed": [ + "failover", + "force_outbound", + "prepend", + "ringback" + ], + "pvt_features_denied": [ + "failover" + ], + "pvt_is_billable": true, + "pvt_modified": 63648435293, + "pvt_module_name": "knm_bandwidth2", + "pvt_ported_in": false, + "pvt_state": "in_service", + "pvt_type": "number", + "state": "in_service", + "ui_metadata": { + "ui": "kazoo-ui", + "version": "3.14-1" + } +} diff --git a/core/kazoo_number_manager/priv/fixtures/old_vsn_6_in.json b/core/kazoo_number_manager/priv/fixtures/old_vsn_6_in.json new file mode 100644 index 00000000000..2abf2d0bbe8 --- /dev/null +++ b/core/kazoo_number_manager/priv/fixtures/old_vsn_6_in.json @@ -0,0 +1,36 @@ +{ + "_id": "+12156774700", + "_rev": "5-186632bd3e625192146941105c33522f", + "failover": { + "sip": "sip:blipblop@158.85.21.24" + }, + "features": [ + "local", + "failover" + ], + "prepend": { + "enabled": true, + "number": "56100" + }, + "pvt_assigned_to": "009afc511c97b2ae693c6cc4920988e8", + "pvt_authorizing_account": "system", + "pvt_created": 63640935218, + "pvt_db_name": "numbers%2F%2B1215", + "pvt_features": { + "failover": { + "sip": "sip:blipblop@158.85.21.24" + }, + "local": {}, + "prepend": { + "enabled": true, + "number": "56100" + } + }, + "pvt_modified": 63640935218, + "pvt_module_name": "knm_local", + "pvt_state": "in_service", + "pvt_type": "number", + "pvt_used_by": "trunkstore", + "state": "in_service", + "used_by": "trunkstore" +} diff --git a/core/kazoo_number_manager/priv/fixtures/old_vsn_6_out.json b/core/kazoo_number_manager/priv/fixtures/old_vsn_6_out.json new file mode 100644 index 00000000000..7192331aad4 --- /dev/null +++ b/core/kazoo_number_manager/priv/fixtures/old_vsn_6_out.json @@ -0,0 +1,49 @@ +{ + "_id": "+12156774700", + "failover": { + "sip": "sip:blipblop@158.85.21.24" + }, + "features": [ + "local", + "failover" + ], + "prepend": { + "enabled": true, + "number": "56100" + }, + "pvt_assigned_to": "009afc511c97b2ae693c6cc4920988e8", + "pvt_authorizing_account": "system", + "pvt_created": 63640935218, + "pvt_db_name": "numbers%2F%2B1215", + "pvt_features": { + "failover": { + "sip": "sip:blipblop@158.85.21.24" + }, + "local": {}, + "prepend": { + "enabled": true, + "number": "56100" + } + }, + "pvt_features_allowed": [ + "failover", + "force_outbound", + "prepend", + "ringback" + ], + "pvt_features_denied": [ + "cnam", + "inbound_cnam", + "outbound_cnam", + "e911", + "port" + ], + "pvt_is_billable": false, + "pvt_modified": 63648931233, + "pvt_module_name": "knm_local", + "pvt_ported_in": false, + "pvt_state": "in_service", + "pvt_type": "number", + "pvt_used_by": "trunkstore", + "state": "in_service" +} diff --git a/core/kazoo_number_manager/src/carriers/knm_bandwidth.erl b/core/kazoo_number_manager/src/carriers/knm_bandwidth.erl index dc4129f49da..a86c2e32788 100644 --- a/core/kazoo_number_manager/src/carriers/knm_bandwidth.erl +++ b/core/kazoo_number_manager/src/carriers/knm_bandwidth.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Handle client requests for phone_number documents @@ -17,6 +17,7 @@ -export([disconnect_number/1]). -export([is_number_billable/1]). -export([should_lookup_cnam/0]). +-export([check_numbers/1]). -include("knm.hrl"). @@ -42,12 +43,16 @@ ) ). +-ifdef(TEST). +-define(BW_DEBUG(Format, Args), io:format(user, Format, Args)). +-else. -define(BW_DEBUG, kapps_config:get_is_true(?KNM_BW_CONFIG_CAT, <<"debug">>, 'false')). -define(BW_DEBUG_FILE, "/tmp/bandwidth.com.xml"). -define(BW_DEBUG(Format, Args), _ = ?BW_DEBUG andalso file:write_file(?BW_DEBUG_FILE, io_lib:format(Format, Args), ['append']) ). +-endif. -define(IS_SANDBOX_PROVISIONING_TRUE, kapps_config:get_is_true(?KNM_BW_CONFIG_CAT, <<"sandbox_provisioning">>, 'true')). @@ -72,6 +77,16 @@ -spec is_local() -> boolean(). is_local() -> 'false'. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Check with carrier if these numbers are registered with it. +%% @end +%%-------------------------------------------------------------------- +-spec check_numbers(ne_binaries()) -> {ok, kz_json:object()} | + {error, any()}. +check_numbers(_Numbers) -> {error, not_implemented}. + %%-------------------------------------------------------------------- %% @public %% @doc diff --git a/core/kazoo_number_manager/src/carriers/knm_bandwidth2.erl b/core/kazoo_number_manager/src/carriers/knm_bandwidth2.erl index 52de85f0055..94f5b5f3f2d 100644 --- a/core/kazoo_number_manager/src/carriers/knm_bandwidth2.erl +++ b/core/kazoo_number_manager/src/carriers/knm_bandwidth2.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% Handle client requests for phone_number documents using new bandwidth api @@ -20,6 +20,7 @@ -export([disconnect_number/1]). -export([is_number_billable/1]). -export([should_lookup_cnam/0]). +-export([check_numbers/1]). %% Maintenance commands -export([sites/0, peers/1]). @@ -29,15 +30,15 @@ -define(KNM_BW2_CONFIG_CAT, <<(?KNM_CONFIG_CAT)/binary, ".bandwidth2">>). -ifdef(TEST). -- export([auth/0]). %% Only to pass compilation +-export([auth/0]). %% Only to pass compilation -endif. -ifdef(TEST). --define(BW2_DEBUG, 'false'). --define(DEBUG_WRITE(Format, Args), lager:debug(Format, Args)). --define(DEBUG_APPEND(Format, Args), lager:debug(Format, Args)). +-define(DEBUG_WRITE(Format, Args), io:format(user, Format, Args)). +-define(DEBUG_APPEND(Format, Args), io:format(user, Format, Args)). -else. -define(BW2_DEBUG, kapps_config:get_is_true(?KNM_BW2_CONFIG_CAT, <<"debug">>, 'false')). +-define(BW2_DEBUG_FILE, "/tmp/bandwidth2.com.xml"). -define(DEBUG_WRITE(Format, Args), _ = ?BW2_DEBUG andalso file:write_file(?BW2_DEBUG_FILE, io_lib:format(Format, Args)) @@ -48,24 +49,15 @@ ). -endif. --define(BW2_DEBUG_FILE, "/tmp/bandwidth2.com.xml"). -define(BW2_BASE_URL, "https://api.inetwork.com/v1.0"). -ifdef(TEST). - --define(IS_SANDBOX_PROVISIONING_TRUE, 'true'). --define(IS_PROVISIONING_ENABLED, 'true'). --define(BW2_ORDER_NAME_PREFIX, "Kazoo"). -define(BW2_ACCOUNT_ID, "eunit_testing_account"). - --define(BW2_API_USERNAME, <<>>). --define(BW2_API_PASSWORD, <<>>). --define(BW2_SIP_PEER, ""). --define(BW2_SITE_ID, ""). - --define(MAX_SEARCH_QUANTITY, 500). - -else. +-define(BW2_ACCOUNT_ID, + kapps_config:get_string(?KNM_BW2_CONFIG_CAT, <<"account_id">>, "")). +-endif. + -define(IS_SANDBOX_PROVISIONING_TRUE, kapps_config:get_is_true(?KNM_BW2_CONFIG_CAT, <<"sandbox_provisioning">>, 'true')). -define(IS_PROVISIONING_ENABLED, @@ -73,9 +65,6 @@ -define(BW2_ORDER_NAME_PREFIX, kapps_config:get_string(?KNM_BW2_CONFIG_CAT, <<"order_name_prefix">>, "Kazoo")). --define(BW2_ACCOUNT_ID, - kapps_config:get_string(?KNM_BW2_CONFIG_CAT, <<"account_id">>, "")). - -define(BW2_API_USERNAME, kapps_config:get_binary(?KNM_BW2_CONFIG_CAT, <<"api_username">>, <<>>)). -define(BW2_API_PASSWORD, @@ -88,8 +77,6 @@ -define(MAX_SEARCH_QUANTITY, kapps_config:get_integer(?KNM_BW2_CONFIG_CAT, <<"max_search_quantity">>, 500)). --endif. - -define(BW2_ORDER_POLL_INTERVAL, 2000). @@ -118,6 +105,16 @@ is_local() -> 'false'. -spec is_number_billable(knm_phone_number:knm_phone_number()) -> boolean(). is_number_billable(_Number) -> 'true'. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Check with carrier if these numbers are registered with it. +%% @end +%%-------------------------------------------------------------------- +-spec check_numbers(ne_binaries()) -> {ok, kz_json:object()} | + {error, any()}. +check_numbers(_Numbers) -> {error, not_implemented}. + %%-------------------------------------------------------------------- %% @public %% @doc @@ -501,8 +498,12 @@ rate_center_to_json(Xml) -> verify_response(Xml) -> NPAPath = "count(//TelephoneNumberDetailList/TelephoneNumberDetail)", TollFreePath = "count(//TelephoneNumberList/TelephoneNumber)", + SitesPath = "count(//SitesResponse/Sites/Site)", + PeersPath = "count(//TNSipPeersResponse/SipPeers/SipPeer)", case validate_xpath_value(xmerl_xpath:string(NPAPath, Xml)) orelse validate_xpath_value(xmerl_xpath:string(TollFreePath, Xml)) + orelse validate_xpath_value(xmerl_xpath:string(SitesPath, Xml)) + orelse validate_xpath_value(xmerl_xpath:string(PeersPath, Xml)) orelse validate_xpath_value(kz_util:get_xml_value("//OrderStatus/text()", Xml)) of 'true' -> @@ -528,8 +529,4 @@ validate_xpath_value(_) -> 'true'. should_lookup_cnam() -> 'true'. -spec quantity_uri_param(integer()) -> string(). --ifdef(TEST). -quantity_uri_param(Q) -> integer_to_list(Q). --else. quantity_uri_param(Q) -> integer_to_list(min(Q, ?MAX_SEARCH_QUANTITY)). --endif. diff --git a/core/kazoo_number_manager/src/carriers/knm_carriers.erl b/core/kazoo_number_manager/src/carriers/knm_carriers.erl index 67b51716d61..efbdec80ec8 100644 --- a/core/kazoo_number_manager/src/carriers/knm_carriers.erl +++ b/core/kazoo_number_manager/src/carriers/knm_carriers.erl @@ -1,20 +1,23 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% %%% @end %%% @contributors %%% Peter Defebvre +%%% Pierre Fenoll %%%------------------------------------------------------------------- -module(knm_carriers). -include_lib("kazoo_json/include/kazoo_json.hrl"). -include("knm.hrl"). +-compile({no_auto_import,[apply/3]}). + -export([find/1, find/2 - ,check/1, check/2 - ,available_carriers/1 + ,check/1 + ,available_carriers/1, all_modules/0 ,default_carriers/0, default_carrier/0 ,acquire/1 ,disconnect/1 @@ -130,7 +133,7 @@ find_fold(_Carrier, _, _, Acc=#{should_continue := ShouldContinue lager:debug("stopping ~s with ~p (~p) numbers found", [_Carrier, _Count, Left]), Acc; find_fold(Carrier, Prefix, Options, Acc=#{left := Quantity}) -> - try Carrier:find_numbers(Prefix, Quantity, Options) of + try apply(Carrier, find_numbers, [Prefix, Quantity, Options]) of {'ok', []} -> Acc; {'ok', Numbers} -> process_carrier_results(Numbers, Acc); {'bulk', []} -> Acc; @@ -146,7 +149,7 @@ find_fold(Carrier, Prefix, Options, Acc=#{left := Quantity}) -> ST = erlang:get_stacktrace(), ?LOG_WARN("failed to query carrier ~s for ~p numbers: ~s: ~p" ,[Carrier, Quantity, _E, _R]), - log_stacktrace(ST), + kz_util:log_stacktrace(ST), Acc end. @@ -156,7 +159,7 @@ process_bulk_carrier_results(Numbers, Acc) -> -spec process_carrier_results(knm_number:knm_numbers(), find_acc()) -> find_acc(). process_carrier_results(Numbers, Acc) -> - acc_found(Acc, lists:foldl(fun process_number_result/2, [], Numbers)). + acc_found(Acc, [process_number_result(Number) || Number <- Numbers]). -spec acc_found(find_acc(), kz_json:objects()) -> find_acc(). acc_found(Acc=#{found := Found @@ -169,49 +172,42 @@ acc_found(Acc=#{found := Found ,left => Left - NewNumbersCount }. --spec process_number_result(knm_number:knm_number(), kz_json:objects()) -> - kz_json:objects(). -process_number_result(Number, Acc) -> +-spec process_number_result(knm_number:knm_number()) -> kz_json:object(). +process_number_result(Number) -> PhoneNumber = knm_number:phone_number(Number), Carrier = knm_phone_number:module_name(PhoneNumber), case is_local(Carrier) of - 'true' -> [found_number_to_jobj(Number) | Acc]; + 'true' -> found_number_to_jobj(Number); 'false' -> DID = knm_phone_number:number(PhoneNumber), - check_for_existing_did(Number, Acc, Carrier, knm_phone_number:fetch(DID)) + check_for_existing_did(Number, Carrier, knm_phone_number:fetch(DID)) end. --spec check_for_existing_did(knm_number:knm_number(), kz_json:objects(), ne_binary() - ,knm_phone_number_return()) -> kz_json:objects(). -check_for_existing_did(Number, Acc, _Carrier, {'error', 'not_found'}) -> +-spec check_for_existing_did(knm_number:knm_number(), ne_binary(), knm_phone_number_return()) -> kz_json:object(). +check_for_existing_did(Number, _Carrier, {'error', 'not_found'}) -> %% This case is only possible for -dTEST: tests don't save to DB (yet) %% and we make sure that non-local carriers save discovered numbers to DB. io:format(user, "number ~s was not in db\n" ,[knm_phone_number:number(knm_number:phone_number(Number))]), - [found_number_to_jobj(Number) | Acc]; -check_for_existing_did(Number, Acc, Carrier, {'ok', ExistingPhoneNumber}) -> + found_number_to_jobj(Number); +check_for_existing_did(Number, Carrier, {'ok', ExistingPhoneNumber}) -> case knm_phone_number:module_name(ExistingPhoneNumber) of - Carrier -> [found_number_to_jobj(Number) | Acc]; + Carrier -> found_number_to_jobj(Number); _OtherCarrier -> - transition_existing_to_discovery(Number, ExistingPhoneNumber, Acc) + transition_existing_to_discovery(Number, ExistingPhoneNumber) end. --spec transition_existing_to_discovery(knm_number:knm_number(), knm_phone_number:knm_phone_number() - ,kz_json:objects()) -> kz_json:objects(). -transition_existing_to_discovery(Number, ExistingPhoneNumber, Acc) -> +-spec transition_existing_to_discovery(knm_number:knm_number(), knm_phone_number:knm_phone_number()) -> + kz_json:object(). +transition_existing_to_discovery(Number, ExistingPhoneNumber) -> PhoneNumber0 = knm_number:phone_number(Number), Setters = [{fun knm_phone_number:set_module_name/2, knm_phone_number:module_name(PhoneNumber0)} ,{fun knm_phone_number:set_carrier_data/2, knm_phone_number:carrier_data(PhoneNumber0)} ,{fun knm_phone_number:set_state/2, ?NUMBER_STATE_DISCOVERY} ], - {'ok', PhoneNumber} = - knm_phone_number:setters(ExistingPhoneNumber, Setters), - case knm_number:save(knm_number:set_phone_number(Number, PhoneNumber)) of - {'ok', SavedNumber} -> [found_number_to_jobj(SavedNumber) | Acc]; - {'error', _R} -> - lager:debug("skipping number ~s: ~p", [knm_phone_number:number(PhoneNumber), _R]), - Acc - end. + {'ok', PhoneNumber} = knm_phone_number:setters(ExistingPhoneNumber, Setters), + found_number_to_jobj( + knm_number:set_phone_number(Number, knm_phone_number:save(PhoneNumber))). -spec found_number_to_jobj(knm_number:knm_number()) -> kz_json:object(). found_number_to_jobj(Number) -> @@ -237,26 +233,42 @@ activation_charge(DID, AccountId) -> %%-------------------------------------------------------------------- %% @public -%% @doc Normalize then query the various providers for available numbers. +%% @doc +%% Normalize then query the various providers for available numbers. +%% @end %%-------------------------------------------------------------------- --type checked_numbers() :: [{module(), {'ok', kz_json:object()} | - {'error', any()} | - {'EXIT', any()} - }]. --spec check(ne_binaries()) -> checked_numbers(). --spec check(ne_binaries(), options()) -> checked_numbers(). -check(Numbers) -> check(Numbers, []). - -check(Numbers, Options) -> - FormattedNumbers = [knm_converters:normalize(Num) || Num <- Numbers], - lager:info("attempting to check ~p ", [FormattedNumbers]), - [{Module, catch(Module:check_numbers(FormattedNumbers, Options))} - || Module <- available_carriers(Options) - ]. +-spec check(ne_binaries()) -> kz_json:object(). +check(Numbers) -> + Nums = lists:usort([knm_converters:normalize(Num) || Num <- Numbers]), + lager:info("attempting to check ~p ", [Nums]), + {_, OKs, KOs} = + lists:foldl(fun check_fold/2, {Nums, #{}, #{}}, available_carriers([])), + kz_json:from_map(maps:merge(KOs, OKs)). + +check_fold(_, {[], _, _}=Acc) -> Acc; +check_fold(Module, {Nums, OKs0, KOs0}) -> + {OKs, KOs} = check_numbers(Module, Nums), + OKNums = maps:keys(OKs0), + {Nums -- OKNums + ,maps:merge(OKs, OKs0) + ,maps:merge(maps:without(OKNums, KOs), KOs0) + }. + +check_numbers(Module, Nums) -> + try apply(Module, check_numbers, [Nums]) of + {ok, JObj} -> {kz_json:to_map(JObj), #{}}; + {error, _} -> {#{}, maps:from_list([{Num,<<"error">>} || Num <- Nums])} + catch + _:_ -> + kz_util:log_stacktrace(), + {#{}, maps:from_list([{Num,<<"error">>} || Num <- Nums])} + end. %%-------------------------------------------------------------------- %% @public -%% @doc Create a list of all available carrier modules +%% @doc +%% Create a list of all carrier modules available to a subaccount. +%% @end %%-------------------------------------------------------------------- -spec available_carriers(options()) -> atoms(). -ifdef(TEST). @@ -272,10 +284,11 @@ available_carriers(Options) -> -spec get_available_carriers(options()) -> atoms(). get_available_carriers(Options) -> - case account_id(Options) of - 'undefined' -> - keep_only_reachable(?CARRIER_MODULES); - _AccountId -> + case account_id(Options) =:= undefined + orelse reseller_id(Options) =:= undefined + of + true -> keep_only_reachable(?CARRIER_MODULES); + false -> ResellerId = reseller_id(Options), First = [?CARRIER_RESERVED, ?CARRIER_RESERVED_RESELLER, ?CARRIER_LOCAL], keep_only_reachable(First ++ (?CARRIER_MODULES(ResellerId) -- First)) @@ -289,13 +302,45 @@ default_carriers() -> default_carrier() -> ?DEFAULT_CARRIER_MODULE. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% List all carrier modules. +%% @end +%%-------------------------------------------------------------------- +-spec all_modules() -> ne_binaries(). +all_modules() -> + [<<"knm_bandwidth2">> + ,<<"knm_bandwidth">> + ,<<"knm_inum">> + ,<<"knm_local">> + ,<<"knm_managed">> + ,<<"knm_mdn">> + ,<<"knm_other">> + ,<<"knm_reserved">> + ,<<"knm_reserved_reseller">> + ,<<"knm_simwood">> + ,<<"knm_telnyx">> + ,<<"knm_vitelity">> + ,<<"knm_voip_innovations">> + ]. + %%-------------------------------------------------------------------- %% @public %% @doc %% Buy a number from its carrier module %% @end %%-------------------------------------------------------------------- --spec acquire(knm_number:knm_number()) -> knm_number:knm_number(). +-spec acquire(knm_number:knm_number()) -> knm_number:knm_number(); + (knm_numbers:collection()) -> knm_numbers:collection(). +acquire(T0=#{todo := Ns}) -> + F = fun (N, T) -> + case knm_number:attempt(fun acquire/1, [N]) of + {ok, NewN} -> knm_numbers:ok(NewN, T); + {error, R} -> knm_numbers:ko(N, R, T) + end + end, + lists:foldl(F, T0, Ns); acquire(Number) -> PhoneNumber = knm_number:phone_number(Number), Module = knm_phone_number:module_name(PhoneNumber), @@ -309,30 +354,35 @@ acquire(Number, 'undefined', _DryRun) -> acquire(Number, _Mod, 'true') -> Number; acquire(Number, ?NE_BINARY=Mod, 'false') -> - Module = carrier_module(Mod), - lager:debug("contacting carrier ~s", [Module]), - Module:acquire_number(Number). + apply(Mod, acquire_number, [Number]). %%-------------------------------------------------------------------- %% @public %% @doc -%% Create a list of all available carrier modules %% @end %%-------------------------------------------------------------------- --spec disconnect(knm_number:knm_number()) -> - knm_number:knm_number(). +-spec disconnect(knm_number:knm_number()) -> knm_number:knm_number(); + (knm_numbers:collection()) -> knm_numbers:collection(). +disconnect(T0=#{todo := Ns}) -> + F = fun (N, T) -> + case knm_number:attempt(fun disconnect/1, [N]) of + {ok, NewN} -> knm_numbers:ok(NewN, T); + {error, R} -> + Num = knm_phone_number:number(knm_number:phone_number(N)), + knm_numbers:ko(Num, R, T) + end + end, + lists:foldl(F, T0, Ns); disconnect(Number) -> - case knm_phone_number:module_name(knm_number:phone_number(Number)) of - ?NE_BINARY=Mod -> - Module = kz_util:to_atom(Mod, 'true'), - lager:debug("contacting carrier ~s", [Module]), - Module:disconnect_number(Number); - _Mod -> - lager:debug("non-existant carrier module ~p, allowing disconnect", [_Mod]), + Module = knm_phone_number:module_name(knm_number:phone_number(Number)), + try apply(Module, disconnect_number, [Number]) of + Result -> Result + catch + 'error':_ -> + lager:debug("non-existant carrier module ~p, allowing disconnect", [Module]), Number end. - -spec quantity(options()) -> pos_integer(). quantity(Options) -> Quantity = props:get_integer_value('quantity', Options, 1), @@ -370,7 +420,7 @@ blocks(Options) -> account_id(Options) -> props:get_value('account_id', Options). --spec reseller_id(options()) -> ne_binary(). +-spec reseller_id(options()) -> api_ne_binary(). reseller_id(Options) -> props:get_value('reseller_id', Options). @@ -384,9 +434,10 @@ reseller_id(Options) -> -spec is_number_billable(knm_phone_number:knm_phone_number()) -> boolean(). is_number_billable(PhoneNumber) -> Carrier = knm_phone_number:module_name(PhoneNumber), - Module = erlang:binary_to_existing_atom(Carrier, 'utf8'), - Module:is_number_billable(PhoneNumber). - + try apply(Carrier, is_number_billable, [PhoneNumber]) + catch + 'error':_R -> 'true' + end. %%%=================================================================== %%% Internal functions @@ -411,20 +462,28 @@ sort_find_result(A, B) -> %%-------------------------------------------------------------------- -spec is_local(ne_binary()) -> boolean(). is_local(Carrier) -> - Module = erlang:binary_to_existing_atom(Carrier, 'utf8'), - Module:is_local(). + try apply(Carrier, is_local, []) + catch + _E:_R -> + kz_util:log_stacktrace(), + true + end. %%-------------------------------------------------------------------- %% @private %% @doc %% @end %%-------------------------------------------------------------------- --spec carrier_module(knm_number:knm_number() | ne_binary()) -> atom(). -carrier_module(?NE_BINARY = Module) -> - kz_util:to_atom(Module, 'true'); -carrier_module(Number) -> - PhoneNumber = knm_number:phone_number(Number), - carrier_module(knm_phone_number:module_name(PhoneNumber)). +-spec apply(module() | ne_binary() | knm_number:knm_number(), atom(), list()) -> any(). +apply(Module, FName, Args) when is_atom(Module), Module =/= undefined -> + lager:debug("contacting carrier ~s for ~s", [Module, FName]), + erlang:apply(Module, FName, Args); +apply(?NE_BINARY=Carrier, FName, Args) -> + Module = erlang:binary_to_existing_atom(Carrier, 'utf8'), + apply(Module, FName, Args); +apply(Number, FName, Args) -> + Carrier = knm_phone_number:module_name(knm_number:phone_number(Number)), + apply(Carrier, FName, Args). %%-------------------------------------------------------------------- %% @private @@ -438,24 +497,3 @@ keep_only_reachable(ModuleNames) -> || M <- ModuleNames, (Module = kz_util:try_load_module(M)) =/= 'false' ]. - -%%-------------------------------------------------------------------- -%% @private -%% @doc -%% @end -%%-------------------------------------------------------------------- -log_stacktrace(ST) -> - ?LOG_DEBUG("stacktrace:", []), - _ = [log_stacktrace_mfa(M, F, A, Info) - || {M, F, A, Info} <- ST - ], - 'ok'. - -log_stacktrace_mfa(M, F, Arity, Info) when is_integer(Arity) -> - ?LOG_DEBUG("st: ~s:~s/~b at (~b)" - ,[M, F, Arity, props:get_value('line', Info, 0)] - ); -log_stacktrace_mfa(M, F, Args, Info) -> - ?LOG_DEBUG("st: ~s:~s at ~p", [M, F, props:get_value('line', Info, 0)]), - _ = [?LOG_DEBUG("args: ~p", [Arg]) || Arg <- Args], - 'ok'. diff --git a/core/kazoo_number_manager/src/carriers/knm_inum.erl b/core/kazoo_number_manager/src/carriers/knm_inum.erl index e7404ae60d7..647056aafb4 100644 --- a/core/kazoo_number_manager/src/carriers/knm_inum.erl +++ b/core/kazoo_number_manager/src/carriers/knm_inum.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Carrier for inums @@ -18,6 +18,7 @@ -export([disconnect_number/1]). -export([is_number_billable/1]). -export([should_lookup_cnam/0]). +-export([check_numbers/1]). -export([generate_numbers/3]). @@ -36,6 +37,16 @@ -spec is_local() -> boolean(). is_local() -> 'true'. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Check with carrier if these numbers are registered with it. +%% @end +%%-------------------------------------------------------------------- +-spec check_numbers(ne_binaries()) -> {ok, kz_json:object()} | + {error, any()}. +check_numbers(_Numbers) -> {error, not_implemented}. + %%-------------------------------------------------------------------- %% @public %% @doc diff --git a/core/kazoo_number_manager/src/carriers/knm_local.erl b/core/kazoo_number_manager/src/carriers/knm_local.erl index 098f6333d78..11542c677e0 100644 --- a/core/kazoo_number_manager/src/carriers/knm_local.erl +++ b/core/kazoo_number_manager/src/carriers/knm_local.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Allow resellers directly below the master account to find @@ -19,6 +19,7 @@ -export([disconnect_number/1]). -export([is_number_billable/1]). -export([should_lookup_cnam/0]). +-export([check_numbers/1]). -include("knm.hrl"). @@ -32,6 +33,16 @@ -spec is_local() -> boolean(). is_local() -> 'true'. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Check with carrier if these numbers are registered with it. +%% @end +%%-------------------------------------------------------------------- +-spec check_numbers(ne_binaries()) -> {ok, kz_json:object()} | + {error, any()}. +check_numbers(_Numbers) -> {error, not_implemented}. + %%-------------------------------------------------------------------- %% @public %% @doc @@ -93,9 +104,10 @@ find_more(_, _, _, _, _Enough, _, Numbers) -> {'ok', Numbers}. format_numbers(QID, JObjs) -> + Nums = [kz_doc:id(JObj) || JObj <- JObjs], + #{ok := Ns} = knm_numbers:get(Nums), [{QID, {knm_phone_number:number(PN), knm_phone_number:module_name(PN), knm_phone_number:state(PN), knm_phone_number:carrier_data(PN)}} - || JObj <- JObjs, - {ok, N} <- [knm_number:get(kz_doc:id(JObj))], + || N <- Ns, PN <- [knm_number:phone_number(N)] ]. diff --git a/core/kazoo_number_manager/src/carriers/knm_managed.erl b/core/kazoo_number_manager/src/carriers/knm_managed.erl index edcd9d36c34..01a9116813c 100644 --- a/core/kazoo_number_manager/src/carriers/knm_managed.erl +++ b/core/kazoo_number_manager/src/carriers/knm_managed.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -16,6 +16,7 @@ -export([disconnect_number/1]). -export([is_number_billable/1]). -export([should_lookup_cnam/0]). +-export([check_numbers/1]). -export([generate_numbers/3]). -export([import_numbers/2]). @@ -35,6 +36,16 @@ -spec is_local() -> boolean(). is_local() -> 'true'. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Check with carrier if these numbers are registered with it. +%% @end +%%-------------------------------------------------------------------- +-spec check_numbers(ne_binaries()) -> {ok, kz_json:object()} | + {error, any()}. +check_numbers(_Numbers) -> {error, not_implemented}. + %%-------------------------------------------------------------------- %% @public %% @doc diff --git a/core/kazoo_number_manager/src/carriers/knm_mdn.erl b/core/kazoo_number_manager/src/carriers/knm_mdn.erl index 438970323e9..94b34115b60 100644 --- a/core/kazoo_number_manager/src/carriers/knm_mdn.erl +++ b/core/kazoo_number_manager/src/carriers/knm_mdn.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Handle tower-of-power MDN phone numbers. @@ -18,6 +18,7 @@ -export([disconnect_number/1]). -export([is_number_billable/1]). -export([should_lookup_cnam/0]). +-export([check_numbers/1]). -include("knm.hrl"). @@ -31,6 +32,16 @@ -spec is_local() -> boolean(). is_local() -> 'false'. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Check with carrier if these numbers are registered with it. +%% @end +%%-------------------------------------------------------------------- +-spec check_numbers(ne_binaries()) -> {ok, kz_json:object()} | + {error, any()}. +check_numbers(_Numbers) -> {error, not_implemented}. + %%-------------------------------------------------------------------- %% @public %% @doc @@ -67,16 +78,13 @@ acquire_number(Number) -> Number. %% Release a number from the routing table %% @end %%-------------------------------------------------------------------- - --spec disconnect_number(knm_number:knm_number()) -> - knm_number:knm_number(). -disconnect_number(Number) -> - knm_number_states:to_deleted(Number). +-spec disconnect_number(knm_number:knm_number()) -> knm_number:knm_number(). +disconnect_number(Number) -> Number. %%-------------------------------------------------------------------- %% @public %% @doc %% @end %%-------------------------------------------------------------------- --spec should_lookup_cnam() -> 'true'. +-spec should_lookup_cnam() -> boolean(). should_lookup_cnam() -> 'true'. diff --git a/core/kazoo_number_manager/src/carriers/knm_other.erl b/core/kazoo_number_manager/src/carriers/knm_other.erl index 852f802c7f4..32dcd94f5dd 100644 --- a/core/kazoo_number_manager/src/carriers/knm_other.erl +++ b/core/kazoo_number_manager/src/carriers/knm_other.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Handle client requests for phone_number documents @@ -14,11 +14,11 @@ -export([is_local/0]). -export([find_numbers/3]). --export([check_numbers/2]). -export([is_number_billable/1]). -export([acquire_number/1]). -export([disconnect_number/1]). -export([should_lookup_cnam/0]). +-export([check_numbers/1]). -include("knm.hrl"). @@ -57,9 +57,9 @@ is_local() -> 'false'. %% in a rate center %% @end %%-------------------------------------------------------------------- --spec find_numbers(ne_binary(), pos_integer(), knm_carriers:options()) -> - {'ok', knm_number:knm_numbers()} | - {'bulk', knm_number:knm_numbers()} | +-spec find_numbers(ne_binary(), pos_integer(), knm_search:options()) -> + {'ok', list()} | + {'bulk', list()} | {'error', any()}. find_numbers(Prefix, Quantity, Options) -> case ?PHONEBOOK_URL(Options) of @@ -74,14 +74,12 @@ find_numbers(Prefix, Quantity, Options) -> %%-------------------------------------------------------------------- %% @public %% @doc -%% Query the local system for a quantity of available numbers -%% in a rate center +%% Check with carrier if these numbers are registered with it. %% @end %%-------------------------------------------------------------------- --spec check_numbers(ne_binaries(), knm_carriers:options()) -> - {'ok', kz_json:object()} | - {'error', any()}. -check_numbers(Numbers, _Options) -> +-spec check_numbers(ne_binaries()) -> {'ok', kz_json:object()} | + {'error', any()}. +check_numbers(Numbers) -> FormatedNumbers = [knm_converters:to_npan(Number) || Number <- Numbers], case kapps_config:get(?KNM_OTHER_CONFIG_CAT, <<"phonebook_url">>) of 'undefined' -> {'error', 'not_available'}; @@ -158,8 +156,7 @@ acquire_number(Number) -> %% Release a number from the routing table %% @end %%-------------------------------------------------------------------- --spec disconnect_number(knm_number:knm_number()) -> - knm_number:knm_number(). +-spec disconnect_number(knm_number:knm_number()) -> knm_number:knm_number(). disconnect_number(Number) -> Number. %%-------------------------------------------------------------------- @@ -210,8 +207,8 @@ format_check_numbers_success(Body) -> %% @doc %% @end %%-------------------------------------------------------------------- --spec get_numbers(ne_binary(), ne_binary(), ne_binary(), knm_carriers:options()) -> - {'ok', knm_number:knm_numbers()} | +-spec get_numbers(ne_binary(), ne_binary(), ne_binary(), knm_search:options()) -> + {'ok', list()} | {'error', 'not_available'}. get_numbers(Url, Prefix, Quantity, Options) -> Offset = props:get_binary_value('offset', Options, <<"0">>), @@ -230,8 +227,8 @@ query_for_numbers(Uri) -> kz_http:get(binary:bin_to_list(Uri)). -endif. --spec handle_number_query_results(kz_http:http_ret(), knm_carriers:options()) -> - {'ok', knm_number:knm_numbers()} | +-spec handle_number_query_results(kz_http:http_ret(), knm_search:options()) -> + {'ok', list()} | {'error', 'not_available'}. handle_number_query_results({'error', _Reason}, _Options) -> lager:error("number query failed: ~p", [_Reason]), @@ -243,7 +240,7 @@ handle_number_query_results({'ok', _Status, _Headers, _Body}, _Options) -> {'error', 'not_available'}. -spec format_numbers_resp(kz_json:object(), knm_search:options()) -> - {'ok', knm_number:knm_numbers()} | + {'ok', list()} | {'error', 'not_available'}. format_numbers_resp(JObj, Options) -> case kz_json:get_value(<<"status">>, JObj) of @@ -267,8 +264,8 @@ format_found(QID, DID, CarrierData) -> %% @doc %% @end %%-------------------------------------------------------------------- --spec get_blocks(ne_binary(), ne_binary(), ne_binary(), knm_carriers:options()) -> - {'ok', knm_number:knm_numbers()} | +-spec get_blocks(ne_binary(), ne_binary(), ne_binary(), knm_search:options()) -> + {'ok', list()} | {'error', 'not_available'}. -ifdef(TEST). get_blocks(?BLOCK_PHONEBOOK_URL, _Prefix, _Quantity, Options) -> @@ -300,13 +297,8 @@ get_blocks(Url, Prefix, Quantity, Options) -> end. -endif. -%%-------------------------------------------------------------------- -%% @private -%% @doc -%% @end -%%-------------------------------------------------------------------- -spec format_blocks_resp(kz_json:object(), knm_search:options()) -> - {'bulk', knm_number:knm_numbers()} | + {'bulk', list()} | {'error', 'not_available'}. format_blocks_resp(JObj, Options) -> case kz_json:get_value(<<"status">>, JObj) of diff --git a/core/kazoo_number_manager/src/carriers/knm_reserved.erl b/core/kazoo_number_manager/src/carriers/knm_reserved.erl index bfb6d1a9991..716cf4ba027 100644 --- a/core/kazoo_number_manager/src/carriers/knm_reserved.erl +++ b/core/kazoo_number_manager/src/carriers/knm_reserved.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Find reserved numbers in a sub-account. @@ -17,6 +17,7 @@ -export([disconnect_number/1]). -export([is_number_billable/1]). -export([should_lookup_cnam/0]). +-export([check_numbers/1]). -include("knm.hrl"). @@ -30,6 +31,16 @@ -spec is_local() -> boolean(). is_local() -> 'true'. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Check with carrier if these numbers are registered with it. +%% @end +%%-------------------------------------------------------------------- +-spec check_numbers(ne_binaries()) -> {ok, kz_json:object()} | + {error, any()}. +check_numbers(_Numbers) -> {error, not_implemented}. + %%-------------------------------------------------------------------- %% @public %% @doc @@ -87,9 +98,10 @@ find_more(_, _, _, _, _Enough, _, Numbers) -> {'ok', Numbers}. format_numbers(QID, JObjs) -> + Nums = [kz_doc:id(JObj) || JObj <- JObjs], + #{ok := Ns} = knm_numbers:get(Nums), [{QID, {knm_phone_number:number(PN), knm_phone_number:module_name(PN), knm_phone_number:state(PN), knm_phone_number:carrier_data(PN)}} - || JObj <- JObjs, - {ok, N} <- [knm_number:get(kz_doc:id(JObj))], + || N <- Ns, PN <- [knm_number:phone_number(N)] ]. diff --git a/core/kazoo_number_manager/src/carriers/knm_reserved_reseller.erl b/core/kazoo_number_manager/src/carriers/knm_reserved_reseller.erl index 7e2dfb433b6..12ce17fa339 100644 --- a/core/kazoo_number_manager/src/carriers/knm_reserved_reseller.erl +++ b/core/kazoo_number_manager/src/carriers/knm_reserved_reseller.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Find reserved numbers in an account's reseller account. @@ -17,6 +17,7 @@ -export([disconnect_number/1]). -export([is_number_billable/1]). -export([should_lookup_cnam/0]). +-export([check_numbers/1]). -include("knm.hrl"). @@ -30,6 +31,16 @@ -spec is_local() -> boolean(). is_local() -> 'true'. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Check with carrier if these numbers are registered with it. +%% @end +%%-------------------------------------------------------------------- +-spec check_numbers(ne_binaries()) -> {ok, kz_json:object()} | + {error, any()}. +check_numbers(_Numbers) -> {error, not_implemented}. + %%-------------------------------------------------------------------- %% @public %% @doc @@ -87,9 +98,10 @@ find_more(_, _, _, _, _Enough, _, Numbers) -> {'ok', Numbers}. format_numbers(QID, JObjs) -> + Nums = [kz_doc:id(JObj) || JObj <- JObjs], + #{ok := Ns} = knm_numbers:get(Nums), [{QID, {knm_phone_number:number(PN), knm_phone_number:module_name(PN), knm_phone_number:state(PN), knm_phone_number:carrier_data(PN)}} - || JObj <- JObjs, - {ok, N} <- [knm_number:get(kz_doc:id(JObj))], + || N <- Ns, PN <- [knm_number:phone_number(N)] ]. diff --git a/core/kazoo_number_manager/src/carriers/knm_simwood.erl b/core/kazoo_number_manager/src/carriers/knm_simwood.erl index 5cc6b0285bf..30cc3771629 100644 --- a/core/kazoo_number_manager/src/carriers/knm_simwood.erl +++ b/core/kazoo_number_manager/src/carriers/knm_simwood.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz INC +%%% @copyright (C) 2015-2017, 2600Hz INC %%% @doc %%% %%% Handle client requests for phone_number at Simwood (UK based provider) @@ -19,6 +19,7 @@ -export([disconnect_number/1]). -export([is_number_billable/1]). -export([should_lookup_cnam/0]). +-export([check_numbers/1]). -include("knm.hrl"). @@ -46,6 +47,16 @@ -spec is_local() -> boolean(). is_local() -> 'false'. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Check with carrier if these numbers are registered with it. +%% @end +%%-------------------------------------------------------------------- +-spec check_numbers(ne_binaries()) -> {ok, kz_json:object()} | + {error, any()}. +check_numbers(_Numbers) -> {error, not_implemented}. + %%-------------------------------------------------------------------- %% @public %% @doc diff --git a/core/kazoo_number_manager/src/carriers/knm_telnyx.erl b/core/kazoo_number_manager/src/carriers/knm_telnyx.erl index 1b414fb4954..4b6a90a1df1 100644 --- a/core/kazoo_number_manager/src/carriers/knm_telnyx.erl +++ b/core/kazoo_number_manager/src/carriers/knm_telnyx.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% A Number Manager module for carrier: telnyx.com @@ -17,6 +17,7 @@ -export([disconnect_number/1]). -export([is_number_billable/1]). -export([should_lookup_cnam/0]). +-export([check_numbers/1]). -include("knm.hrl"). @@ -44,6 +45,16 @@ is_local() -> 'false'. -spec is_number_billable(knm_number:knm_number()) -> boolean(). is_number_billable(_Number) -> 'true'. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Check with carrier if these numbers are registered with it. +%% @end +%%-------------------------------------------------------------------- +-spec check_numbers(ne_binaries()) -> {ok, kz_json:object()} | + {error, any()}. +check_numbers(_Numbers) -> {error, not_implemented}. + %%-------------------------------------------------------------------- %% @public @@ -51,7 +62,7 @@ is_number_billable(_Number) -> 'true'. %% Query the system for a quantity of available numbers in a rate center %% @end %%-------------------------------------------------------------------- --spec find_numbers(ne_binary(), pos_integer(), knm_carriers:options()) -> +-spec find_numbers(ne_binary(), pos_integer(), knm_search:options()) -> {'ok', knm_number:knm_numbers()}. find_numbers(<<"+1", Prefix:3/binary, _/binary>>, Quantity, Options) when ?IS_US_TOLLFREE(Prefix) -> @@ -67,7 +78,7 @@ find_numbers(<<"+1", NPA:3/binary, _/binary>>=Num, Quantity, Options) -> {'ok', numbers(Results, Options)}; find_numbers(<<"+",_/binary>>=_InternationalNum, Quantity, Options) -> - Country = knm_carriers:country(Options), + Country = knm_search:country(Options), Results = numbers('region', Quantity, Country, 'undefined'), {'ok', international_numbers(Results, Options)}. @@ -154,7 +165,7 @@ numbers(JObjs, Options) -> ]. international_numbers(JObjs, Options) -> - Dialcode = knm_carriers:dialcode(Options), + Dialcode = knm_search:dialcode(Options), QID = knm_search:query_id(Options), [{QID, {Num, ?MODULE, ?NUMBER_STATE_DISCOVERY, Data}} || Data <- JObjs, diff --git a/core/kazoo_number_manager/src/carriers/knm_vitelity.erl b/core/kazoo_number_manager/src/carriers/knm_vitelity.erl index 1a7c2108d4d..a25840f84d1 100644 --- a/core/kazoo_number_manager/src/carriers/knm_vitelity.erl +++ b/core/kazoo_number_manager/src/carriers/knm_vitelity.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% @doc %%% %%% Handle client requests for phone_number documents @@ -18,6 +18,7 @@ -export([disconnect_number/1]). -export([should_lookup_cnam/0]). -export([is_number_billable/1]). +-export([check_numbers/1]). -include("knm.hrl"). -include("knm_vitelity.hrl"). @@ -33,6 +34,16 @@ -spec is_local() -> boolean(). is_local() -> 'false'. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Check with carrier if these numbers are registered with it. +%% @end +%%-------------------------------------------------------------------- +-spec check_numbers(ne_binaries()) -> {ok, kz_json:object()} | + {error, any()}. +check_numbers(_Numbers) -> {error, not_implemented}. + %%-------------------------------------------------------------------- %% @public %% @doc @@ -43,6 +54,8 @@ is_local() -> 'false'. -spec find_numbers(ne_binary(), pos_integer(), knm_carriers:options()) -> {'ok', knm_number:knm_numbers()} | {'error', any()}. +find_numbers(<<"+1",Prefix/binary>>, Quantity, Options) -> + find_numbers(Prefix, Quantity, Options); find_numbers(Prefix, Quantity, Options) -> case props:is_true(tollfree, Options, 'false') of 'false' -> classify_and_find(Prefix, Quantity, Options); diff --git a/core/kazoo_number_manager/src/carriers/knm_voip_innovations.erl b/core/kazoo_number_manager/src/carriers/knm_voip_innovations.erl index bc0774415e6..0f87beedb1f 100644 --- a/core/kazoo_number_manager/src/carriers/knm_voip_innovations.erl +++ b/core/kazoo_number_manager/src/carriers/knm_voip_innovations.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% A Number Manager module for carrier: VoIPInnovations.com @@ -17,6 +17,7 @@ -export([disconnect_number/1]). -export([is_number_billable/1]). -export([should_lookup_cnam/0]). +-export([check_numbers/1]). -ifdef(TEST). - export([soap_request/2]). %% Only to pass compilation @@ -79,6 +80,16 @@ is_local() -> 'false'. -spec is_number_billable(knm_phone_number:knm_phone_number()) -> boolean(). is_number_billable(_Number) -> 'true'. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Check with carrier if these numbers are registered with it. +%% @end +%%-------------------------------------------------------------------- +-spec check_numbers(ne_binaries()) -> {ok, kz_json:object()} | + {error, any()}. +check_numbers(_Numbers) -> {error, not_implemented}. + %%-------------------------------------------------------------------- %% @public diff --git a/core/kazoo_number_manager/src/converters/knm_converter_regex.erl b/core/kazoo_number_manager/src/converters/knm_converter_regex.erl index c4c5f7f78b7..89271aa486c 100644 --- a/core/kazoo_number_manager/src/converters/knm_converter_regex.erl +++ b/core/kazoo_number_manager/src/converters/knm_converter_regex.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end @@ -11,19 +11,19 @@ -include("knm.hrl"). -export([normalize/1, normalize/2, normalize/3 - ,to_npan/1 - ,to_1npan/1 + ,to_npan/1 + ,to_1npan/1 ]). --define(DEFAULT_E164_CONVERTERS, [{<<"^\\+?1?([2-9][0-9]{2}[2-9][0-9]{6})$">> - ,kz_json:from_list([{<<"prefix">>, <<"+1">>}]) +-define(DEFAULT_E164_CONVERTERS, [{<<"^\\+?1?([2-9][0-9]{2}[2-9][0-9]{6})\$">> + ,kz_json:from_list([{<<"prefix">>, <<"+1">>}]) + } + ,{<<"^011(\\d*)$|^00(\\d*)\$">> + ,kz_json:from_list([{<<"prefix">>, <<"+">>}]) + } + ,{<<"^[2-9]\\d{7,}\$">> + ,kz_json:from_list([{<<"prefix">>, <<"+">>}]) } - ,{<<"^011(\\d*)$|^00(\\d*)$">> - ,kz_json:from_list([{<<"prefix">>, <<"+">>}]) - } - ,{<<"^[2-9]\\d{7,}$">> - ,kz_json:from_list([{<<"prefix">>, <<"+">>}]) - } ]). -define(KEY_E164_CONVERTERS, <<"e164_converters">>). @@ -57,7 +57,7 @@ normalize(?NE_BINARY = Num, AccountId, DialPlan) -> %%-------------------------------------------------------------------- -spec to_npan(ne_binary()) -> ne_binary(). to_npan(Num) -> - case re:run(Num, <<"^\\+?1?([2-9][0-9]{2}[2-9][0-9]{6})$">>, [{'capture', [1], 'binary'}]) of + case re:run(Num, <<"^\\+?1?([2-9][0-9]{2}[2-9][0-9]{6})\$">>, [{'capture', [1], 'binary'}]) of 'nomatch' -> Num; {'match', [NPAN]} -> NPAN end. @@ -69,7 +69,7 @@ to_npan(Num) -> %%-------------------------------------------------------------------- -spec to_1npan(ne_binary()) -> ne_binary(). to_1npan(Num) -> - case re:run(Num, <<"^\\+?1?([2-9][0-9]{2}[2-9][0-9]{6})$">>, [{'capture', [1], 'binary'}]) of + case re:run(Num, <<"^\\+?1?([2-9][0-9]{2}[2-9][0-9]{6})\$">>, [{'capture', [1], 'binary'}]) of 'nomatch' -> Num; {'match', [NPAN]} -> <<$1, NPAN/binary>> end. @@ -110,9 +110,9 @@ to_e164_from_account_dialplan(Number, AccountId, 'undefined') -> to_e164_from_account(Number, AccountId); to_e164_from_account_dialplan(Number, AccountId, DialPlan) -> to_e164_from_account_dialplan_regexes(Number - ,AccountId - ,DialPlan - ,kz_json:get_keys(DialPlan) + ,AccountId + ,DialPlan + ,kz_json:get_keys(DialPlan) ). to_e164_from_account_dialplan_regexes(Number, AccountId, _DialPlan, []) -> @@ -148,9 +148,9 @@ get_e164_converters() -> get_e164_converters() -> Default = kz_json:from_list(?DEFAULT_E164_CONVERTERS), try kapps_config:get(?KNM_CONFIG_CAT - ,?KEY_E164_CONVERTERS - ,Default - ) + ,?KEY_E164_CONVERTERS + ,Default + ) catch _:_ -> Default end. @@ -160,10 +160,10 @@ get_e164_converters() -> get_e164_converters(AccountId) -> Default = kz_json:from_list(?DEFAULT_E164_CONVERTERS), try kapps_account_config:get_global(AccountId - ,?KNM_CONFIG_CAT - ,?KEY_E164_CONVERTERS - ,Default - ) + ,?KNM_CONFIG_CAT + ,?KEY_E164_CONVERTERS + ,Default + ) catch _:_ -> Default end. diff --git a/core/kazoo_number_manager/src/converters/knm_converters.erl b/core/kazoo_number_manager/src/converters/knm_converters.erl index bc4f25cb24a..7fd60ac92cf 100644 --- a/core/kazoo_number_manager/src/converters/knm_converters.erl +++ b/core/kazoo_number_manager/src/converters/knm_converters.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end @@ -15,7 +15,7 @@ ,is_npan/1, to_npan/1 ,is_1npan/1, to_1npan/1 ,to_db/1 - ,is_reconcilable/1, is_reconcilable/2 + ,is_reconcilable/1, is_reconcilable/2, are_reconcilable/1 ,classify/1, available_classifiers/0 ,available_converters/0 ,default_converter/0 @@ -34,6 +34,9 @@ kapps_config:get_binary(?KNM_CONFIG_CAT, ?KEY_RECONCILE_REGEX, ?DEFAULT_RECONCILE_REGEX)). -endif. +-define(ACCOUNT_RECONCILE_REGEX, + kapps_account_config:get_global(AccountId, ?KNM_CONFIG_CAT, ?KEY_RECONCILE_REGEX, ?DEFAULT_RECONCILE_REGEX)). + -define(CONVERTER_MOD, kz_util:to_atom(<<"knm_converter_", (?DEFAULT_CONVERTER)/binary>>, 'true')). -define(DEFAULT_RECONCILE_REGEX, <<"^\\+?1?\\d{10}$|^\\+[2-9]\\d{7,}$|^011\\d*$|^00\\d*\$">>). @@ -79,14 +82,16 @@ ,{<<"friendly_name">>, <<"Unknown">>} ])). --define(DEFAULT_CLASSIFIERS, [{<<"tollfree_us">>, ?CLASSIFIER_TOLLFREE_US} - ,{<<"toll_us">>, ?CLASSIFIER_TOLLFREE} - ,{<<"emergency">>, ?CLASSIFIER_EMERGENCY} - ,{<<"caribbean">>, ?CLASSIFIER_CARIBBEAN} - ,{<<"did_us">>, ?CLASSIFIER_DID_US} - ,{<<"international">>, ?CLASSIFIER_INTERNATIONAL} - ,{<<"unknown">>, ?CLASSIFIER_UNKNOWN} - ]). +-define(DEFAULT_CLASSIFIERS, + kz_json:from_list([{<<"tollfree_us">>, ?CLASSIFIER_TOLLFREE_US} + ,{<<"toll_us">>, ?CLASSIFIER_TOLLFREE} + ,{<<"emergency">>, ?CLASSIFIER_EMERGENCY} + ,{<<"caribbean">>, ?CLASSIFIER_CARIBBEAN} + ,{<<"did_us">>, ?CLASSIFIER_DID_US} + ,{<<"international">>, ?CLASSIFIER_INTERNATIONAL} + ,{<<"unknown">>, ?CLASSIFIER_UNKNOWN} + ])). +-define(CLASSIFIERS, kapps_config:get(?KNM_CONFIG_CAT, <<"classifiers">>, ?DEFAULT_CLASSIFIERS)). %%-------------------------------------------------------------------- %% @public @@ -163,6 +168,16 @@ to_db(<<"+", NumPrefix:4/binary, _/binary>>) -> to_db(_) -> 'undefined'. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Returns `{Reconcilables, NotReconcilables}'. +%% @end +%%-------------------------------------------------------------------- +-spec are_reconcilable(ne_binaries()) -> {ne_binaries(), ne_binaries()}. +are_reconcilable(Nums) -> + lists:partition(fun is_reconcilable/1, Nums). + %%-------------------------------------------------------------------- %% @public %% @doc @@ -170,20 +185,13 @@ to_db(_) -> %%-------------------------------------------------------------------- -spec is_reconcilable(ne_binary()) -> boolean(). is_reconcilable(Number) -> - Regex = ?RECONCILE_REGEX, Num = normalize(Number), - is_reconcilable_by_regex(Num, Regex). + is_reconcilable_by_regex(Num, ?RECONCILE_REGEX). -spec is_reconcilable(ne_binary(), ne_binary()) -> boolean(). is_reconcilable(Number, AccountId) -> - Regex = kapps_account_config:get_global( - AccountId - ,?KNM_CONFIG_CAT - ,?KEY_RECONCILE_REGEX - ,?DEFAULT_RECONCILE_REGEX - ), Num = normalize(Number, AccountId), - is_reconcilable_by_regex(Num, Regex). + is_reconcilable_by_regex(Num, ?ACCOUNT_RECONCILE_REGEX). is_reconcilable_by_regex(Num, Regex) -> case re:run(Num, Regex) of @@ -199,17 +207,6 @@ is_reconcilable_by_regex(Num, Regex) -> %% @doc %% @end %%-------------------------------------------------------------------- --ifdef(TEST). --define(CLASSIFIERS, kz_json:from_list(?DEFAULT_CLASSIFIERS)). --else. --define(CLASSIFIERS - ,kapps_config:get(?KNM_CONFIG_CAT - ,<<"classifiers">> - ,kz_json:from_list(?DEFAULT_CLASSIFIERS) - ) - ). --endif. - -spec classify(ne_binary()) -> api_binary(). classify(Number) -> Num = normalize(Number), @@ -223,10 +220,7 @@ classify(Number) -> %%-------------------------------------------------------------------- -spec available_classifiers() -> kz_json:object(). available_classifiers() -> - kz_json:foldl(fun correct_depreciated_classifiers/3 - ,kz_json:new() - ,?CLASSIFIERS - ). + kz_json:foldl(fun correct_depreciated_classifiers/3, kz_json:new(), ?CLASSIFIERS). %%-------------------------------------------------------------------- %% @public @@ -286,7 +280,7 @@ get_classifier_regex(JObj) -> %%-------------------------------------------------------------------- -spec correct_depreciated_classifiers(kz_json:path(), kz_json:json_term(), kz_json:object()) -> kz_json:object(). -correct_depreciated_classifiers(Classifier, ?NE_BINARY = Regex, JObj) -> +correct_depreciated_classifiers(Classifier, ?NE_BINARY=Regex, JObj) -> J = kz_json:from_list([{<<"regex">>, Regex} ,{<<"friendly_name">>, Classifier} ]), diff --git a/core/kazoo_number_manager/src/kapi_discovery.erl b/core/kazoo_number_manager/src/kapi_discovery.erl index 9e8fce0a676..7bfdd910bf5 100644 --- a/core/kazoo_number_manager/src/kapi_discovery.erl +++ b/core/kazoo_number_manager/src/kapi_discovery.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% Routing requests, responses, and wins! %%% @end diff --git a/core/kazoo_number_manager/src/kazoo_number_manager_app.erl b/core/kazoo_number_manager/src/kazoo_number_manager_app.erl index dbe11255c0d..c2ed395b4de 100644 --- a/core/kazoo_number_manager/src/kazoo_number_manager_app.erl +++ b/core/kazoo_number_manager/src/kazoo_number_manager_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_number_manager/src/kazoo_number_manager_maintenance.erl b/core/kazoo_number_manager/src/kazoo_number_manager_maintenance.erl index 0bca51e94e5..6ae9155f2b5 100644 --- a/core/kazoo_number_manager/src/kazoo_number_manager_maintenance.erl +++ b/core/kazoo_number_manager/src/kazoo_number_manager_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @@ -25,6 +25,7 @@ -export([purge_discovery/0 ,purge_discovery/1 ]). +-export([update_number_services_view/1]). -define(TIME_BETWEEN_ACCOUNTS_MS ,kapps_config:get_integer(?KNM_CONFIG_CAT, <<"time_between_accounts_ms">>, ?MILLISECONDS_IN_SECOND)). @@ -52,7 +53,7 @@ refresh_numbers_dbs() -> || Db <- Databases, kzs_util:db_classification(Db) =:= 'numbers' orelse kzs_util:db_classification(Db) =:= 'system_numbers' - ], + ], refresh_numbers_dbs(NumberDbs, length(NumberDbs)). -spec refresh_numbers_dbs(ne_binaries(), non_neg_integer()) -> 'ok'. @@ -72,20 +73,48 @@ refresh_numbers_db(<> = NumberDb) -> refresh_numbers_db(<>) -> NumberDb = <>, refresh_numbers_db(NumberDb); -refresh_numbers_db(<<"+", Suffix/binary>>) -> - refresh_numbers_db(Suffix); +refresh_numbers_db(<<"+", _/binary>> = Num) -> + refresh_numbers_db(knm_converters:to_db(Num)); refresh_numbers_db(Suffix) -> NumberDb = <>, refresh_numbers_db(NumberDb). +%% @public +-spec update_number_services_view(ne_binary()) -> ok. +update_number_services_view(?MATCH_ACCOUNT_RAW(AccountId)) -> + update_number_services_view(kz_util:format_account_db(AccountId)); +update_number_services_view(?MATCH_ACCOUNT_ENCODED(_)=AccountDb) -> + JObj = knm_converters:available_classifiers(), %%TODO: per-account classifiers. + Pairs = [{Classification, kz_json:get_value([Classification, <<"regex">>], JObj)} + || Classification <- kz_json:get_keys(JObj) + ], + {Classifications, Regexs} = lists:unzip(Pairs), + MapView = number_services_map(Classifications, Regexs), + RedView = number_services_red(), + ViewName = <<"_design/numbers">>, + {ok, View} = kz_datamgr:open_doc(AccountDb, ViewName), + NewView = kz_json:set_values([{[<<"views">>, <<"reconcile_services">>, <<"map">>], MapView} + ,{[<<"views">>, <<"reconcile_services">>, <<"reduce">>], RedView} + ] + ,View + ), + case kz_json:are_equal(View, NewView) of + true -> ?LOG("View is up to date.", []); + false -> + true = kz_datamgr:db_view_update(AccountDb, [{ViewName, NewView}]), + ?LOG("View updated!", []) + end. + %% @public -spec fix_accounts_numbers([ne_binary()]) -> 'ok'. -spec fix_account_numbers(ne_binary()) -> 'ok'. fix_accounts_numbers(Accounts) -> - foreach_pause_in_between(?TIME_BETWEEN_ACCOUNTS_MS, fun fix_account_numbers/1, Accounts). + AccountDbs = lists:usort([kz_util:format_account_db(Account) || Account <- Accounts]), + _ = purge_discovery(), + foreach_pause_in_between(?TIME_BETWEEN_ACCOUNTS_MS, fun fix_account_numbers/1, AccountDbs). fix_account_numbers(AccountDb = ?MATCH_ACCOUNT_ENCODED(A,B,Rest)) -> - kz_util:put_callid(?MODULE), + kz_util:put_callid('fix_account_numbers'), ?LOG("########## fixing [~s] ##########", [AccountDb]), ?LOG("[~s] getting numbers from account db", [AccountDb]), DisplayPNs = get_DIDs(AccountDb, <<"phone_numbers/crossbar_listing">>), @@ -124,6 +153,8 @@ fix_account_numbers(AccountDb = ?MATCH_ACCOUNT_ENCODED(A,B,Rest)) -> ok =:= ?LOG("########## will remove [~s] doc: ~s ##########", [AccountDb, DID]) ], _ = kz_datamgr:del_docs(AccountDb, ToRm), + ?LOG("########## updating view [~s] ##########", [AccountDb]), + update_number_services_view(AccountDb), ?LOG("########## done fixing [~s] ##########", [AccountDb]); fix_account_numbers(Account = ?NE_BINARY) -> fix_account_numbers(kz_util:format_account_db(Account)). @@ -192,6 +223,66 @@ migrate_unassigned_numbers(NumberDb, Offset) -> %%% Internal functions %%%=================================================================== +escape(?NE_BINARY=Bin0) -> + StartSz = byte_size(Start= <<"<<">>), + EndSz = byte_size(End = <<">>">>), + Bin = iolist_to_binary(io_lib:format("~p", [Bin0])), + SizeOfWhatIWant = byte_size(Bin) - (StartSz + EndSz), + <> = Bin, + Escaped. + +number_services_map(Classifications, Regexs) -> + iolist_to_binary( + ["function(doc) {" + " if (doc.pvt_type != 'number' || doc.pvt_deleted) return;" + " var e164 = doc._id;" + %% "log('+14157125234'.match(",escape(<<"\\d+">>),"));" + " var resM = {};" + " resM[doc.pvt_module_name] = 1;" + " var resC = {};" + " if (false) return;" + ,[[" else if (e164.match(", escape(R), "))" + " resC['", Class, "'] = resM;" + ] + || {Class, R} <- lists:zip(Classifications, Regexs) + ] + ," var resF = {};" + " var used = doc.pvt_features || {};" + " for (var feature in used)" + " if (used.hasOwnProperty(feature))" + " resF[feature] = 1;" + " emit(doc._id, {'classifications':resC, 'features':resF});" + "}" + ]). + +number_services_red() -> + iolist_to_binary( + ["function(Keys, Values, _Rereduce) {" + " var incr = function (o, k, v) {" + " o[k] = v + ((o[k] === undefined) ? 0 : o[k]);" + " return o;" + " };" + " var acc = function (Oout, Oin) {" + " for (var Ofield in Oin)" + " if (Oin.hasOwnProperty(Ofield))" + " Oout = incr(Oout, Ofield, Oin[Ofield]);" + " return Oout;" + " };" + " var resF = {};" + " var resC = {};" + " for (var i in Values) {" + " var Value = Values[i];" + " resF = acc(resF, Value['features'] || {});" + " var Classifications = Value['classifications'] || {};" + " for (var klass in Classifications) {" + " if (Classifications.hasOwnProperty(klass))" + " resC[klass] = acc(resC[klass] || {}, Classifications[klass]);" + " }" + " }" + " return {'classifications':resC, 'features':resF};" + "}" + ]). + -spec foreach_pause_in_between(non_neg_integer(), fun(), list()) -> 'ok'. foreach_pause_in_between(_, _, []) -> 'ok'; foreach_pause_in_between(_, Fun, [Element]) -> @@ -227,7 +318,6 @@ fix_docs({error, _R}, _, _, _NumberDb, _DID) -> fix_docs({ok, NumDoc}, Doc, AccountDb, NumberDb, DID) -> case app_using(DID) =:= kz_json:get_ne_binary_value(?PVT_USED_BY, NumDoc) andalso have_same_pvt_values(NumDoc, Doc) - andalso are_features_available_synced(NumDoc) of true -> ?LOG("~s already synced", [DID]); false -> @@ -289,13 +379,6 @@ have_same_pvt_values(NumDoc0, Doc0) -> Doc = cleanse(kz_json:private_fields(Doc0)), NumDoc == Doc. --spec are_features_available_synced(kz_json:object()) -> boolean(). -are_features_available_synced(NumDoc) -> - kz_json:get_value(?PVT_FEATURES_AVAILABLE, NumDoc) =:= - knm_phone_number:features_available( - knm_phone_number:from_json(NumDoc) - ). - -spec cleanse(kz_json:object()) -> kz_json:object(). cleanse(JObj) -> kz_json:delete_keys([<<"id">>, <<"_id">> diff --git a/core/kazoo_number_manager/src/kazoo_number_manager_sup.erl b/core/kazoo_number_manager/src/kazoo_number_manager_sup.erl index 3956d7edbd8..f095cd2ae1c 100644 --- a/core/kazoo_number_manager/src/kazoo_number_manager_sup.erl +++ b/core/kazoo_number_manager/src/kazoo_number_manager_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_number_manager/src/knm.hrl b/core/kazoo_number_manager/src/knm.hrl index b3168430214..6653bade711 100644 --- a/core/kazoo_number_manager/src/knm.hrl +++ b/core/kazoo_number_manager/src/knm.hrl @@ -40,7 +40,14 @@ orelse Prefix == <<"88*">> ). --define(DEFAULT_E911_FEATURE, ?DASH_KEY). + +-define(DEFAULT_ALLOWED_FEATURES, [?FEATURE_CNAM + ,?FEATURE_E911 + ,?FEATURE_FAILOVER + ,?FEATURE_PORT + ,?FEATURE_PREPEND + ]). + -ifdef(TEST). @@ -51,12 +58,19 @@ -define(TEST_CREATE_NUM, <<"+15559871234">>). -define(TEST_AVAILABLE_NUM, <<"+15551239876">>). +-define(TEST_IN_SERVICE_BAD_CARRIER_NUM, <<"+15551233337">>). -define(TEST_IN_SERVICE_NUM, <<"+15551233322">>). +-define(TEST_IN_SERVICE_MDN, <<"+15551233324">>). -define(TEST_IN_SERVICE_WITH_HISTORY_NUM, <<"+15551255693">>). -define(TEST_CREATE_TOLL, <<"+18887771111">>). -define(TEST_EXISTING_TOLL, <<"+18005551212">>). -define(TEST_OLD_NUM, <<"+15045551226">>). -define(TEST_OLD2_NUM, <<"+12014370855">>). +-define(TEST_OLD3_NUM, <<"+14082141750">>). +-define(TEST_OLD4_NUM, <<"+14242424247">>). +-define(TEST_OLD5_NUM, <<"+19377038880">>). +-define(TEST_OLD6_NUM, <<"+12156774700">>). +-define(TEST_TELNYX_NUM, <<"+14352154006">>). -define(MASTER_ACCOUNT_ID, <<"master_account_6992af0e9504d0b27">>). -define(RESELLER_ACCOUNT_ID, <<"reseller_account_b113394f16cb76d">>). @@ -90,6 +104,24 @@ ) ). +-define(IN_SERVICE_BAD_CARRIER_NUMBER + ,kz_json:from_list( + [{<<"_id">>, ?TEST_IN_SERVICE_BAD_CARRIER_NUM} + ,{<<"_rev">>, <<"3-7dd6a1523e81a4e3c2689140ed3a8e69">>} + ,{?PVT_MODIFIED, 63565934349} + ,{?PVT_FEATURES, kz_json:new()} + ,{?PVT_ASSIGNED_TO, ?RESELLER_ACCOUNT_ID} + ,{?PVT_RESERVE_HISTORY, [?RESELLER_ACCOUNT_ID]} + ,{?PVT_MODULE_NAME, <<"wnm_pacwest">>} + ,{?PVT_STATE, ?NUMBER_STATE_IN_SERVICE} + ,{?PVT_DB_NAME, <<"numbers%2F%2B1555">>} + ,{?PVT_CREATED, 63565934344} + ,{?PVT_AUTH_BY, ?MASTER_ACCOUNT_ID} + ,{?PVT_USED_BY, <<"callflow">>} + ] + ) + ). + -define(IN_SERVICE_NUMBER ,kz_json:from_list( [{<<"_id">>, ?TEST_IN_SERVICE_NUM} @@ -108,6 +140,24 @@ ) ). +-define(IN_SERVICE_MDN + ,kz_json:from_list( + [{<<"_id">>, ?TEST_IN_SERVICE_MDN} + ,{<<"_rev">>, <<"4-7dd6a1523e81a4e3c2689140ed3a8e69">>} + ,{?PVT_MODIFIED, 63565934349} + ,{?PVT_FEATURES, kz_json:new()} + ,{?PVT_ASSIGNED_TO, ?RESELLER_ACCOUNT_ID} + ,{?PVT_RESERVE_HISTORY, [?RESELLER_ACCOUNT_ID]} + ,{?PVT_MODULE_NAME, ?CARRIER_MDN} + ,{?PVT_STATE, ?NUMBER_STATE_IN_SERVICE} + ,{?PVT_DB_NAME, <<"numbers%2F%2B1555">>} + ,{?PVT_CREATED, 63565934344} + ,{?PVT_AUTH_BY, ?MASTER_ACCOUNT_ID} + ,{?PVT_USED_BY, <<"callflow">>} + ] + ) + ). + -define(IN_SERVICE_WITH_HISTORY_NUMBER ,kz_json:from_list( [{<<"_id">>, ?TEST_IN_SERVICE_WITH_HISTORY_NUM} @@ -145,6 +195,23 @@ ) ). +-define(TELNY_NUMBER + ,kz_json:from_list( + [{<<"_id">>, ?TEST_TELNYX_NUM} + ,{<<"_rev">>, <<"10-7dd6a1523e81a4e3c2689140ed3a8e69">>} + ,{?PVT_MODIFIED, 63565934349} + ,{?PVT_FEATURES, kz_json:new()} + ,{?PVT_ASSIGNED_TO, ?RESELLER_ACCOUNT_ID} + ,{?PVT_RESERVE_HISTORY, [?RESELLER_ACCOUNT_ID]} + ,{?PVT_MODULE_NAME, <<"knm_telnyx">>} + ,{?PVT_STATE, ?NUMBER_STATE_AVAILABLE} + ,{?PVT_DB_NAME, <<"numbers%2F%2B1435">>} + ,{?PVT_CREATED, 63565934344} + ,{?PVT_AUTH_BY, ?MASTER_ACCOUNT_ID} + ] + ) + ). + -define(BLOCK_PHONEBOOK_URL, <<"http://blocks.tld">>). -define(START_BLOCK, <<"+14158867900">>). diff --git a/core/kazoo_number_manager/src/knm_errors.erl b/core/kazoo_number_manager/src/knm_errors.erl index 70890039540..45cc6e1693d 100644 --- a/core/kazoo_number_manager/src/knm_errors.erl +++ b/core/kazoo_number_manager/src/knm_errors.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end @@ -13,7 +13,7 @@ ,number_exists/1 ,invalid_state_transition/3 ,no_change_required/1 - ,service_restriction/1 + ,service_restriction/2 ,carrier_not_specified/1 ,not_enough_credit/2 ,invalid/2 @@ -64,24 +64,20 @@ unauthorized() -> number_exists(DID) -> throw({'error', 'number_exists', DID}). --spec invalid_state_transition(kn() | kpn(), ne_binary(), ne_binary()) -> - no_return(). +-spec invalid_state_transition(kn() | kpn(), api_ne_binary(), ne_binary()) -> no_return(). +invalid_state_transition(Number, undefined, ToState) -> + invalid_state_transition(Number, <<"(nothing)">>, ToState); invalid_state_transition(Number, FromState, ToState) -> - throw({'error' - ,'invalid_state_transition' - ,Number - ,iolist_to_binary(["from ", FromState - ," to ", ToState - ]) - }). + Reason = <<"from ", FromState/binary, " to ", ToState/binary>>, + throw({'error', 'invalid_state_transition', Number, Reason}). -spec no_change_required(kn()) -> no_return(). no_change_required(Number) -> throw({'error', 'no_change_required', Number}). --spec service_restriction(ne_binary()) -> no_return(). -service_restriction(Message) -> - throw({'error', 'service_restriction', Message}). +-spec service_restriction(kn(), ne_binary()) -> no_return(). +service_restriction(Number, Message) -> + throw({'error', 'service_restriction', Number, Message}). -spec carrier_not_specified(kn()) -> no_return(). carrier_not_specified(Number) -> @@ -91,7 +87,7 @@ carrier_not_specified(Number) -> not_enough_credit(Number, Units) -> throw({'error', 'not_enough_credit', Number, Units}). --spec invalid(kn(), kz_json:object()) -> no_return(). +-spec invalid(kn(), ne_binary()) -> no_return(). invalid(Number, Reason) -> throw({'error', 'invalid', Number, Reason}). @@ -99,19 +95,13 @@ invalid(Number, Reason) -> multiple_choice(Number, Update) -> throw({'error', 'multiple_choice', Number, Update}). --spec assign_failure(knm_phone_number:knm_phone_number(), any()) -> - no_return(). +-spec assign_failure(knm_phone_number:knm_phone_number(), any()) -> no_return(). assign_failure(PhoneNumber, E) -> throw({'error', 'assign_failure', PhoneNumber, E}). --spec database_error(kz_data:data_errors(), knm_phone_number:knm_phone_number()) -> - no_return(). +-spec database_error(kz_data:data_errors(), knm_phone_number:knm_phone_number()) -> no_return(). database_error(E, PhoneNumber) -> - throw({'error' - ,'database_error' - ,PhoneNumber - ,E - }). + throw({'error', 'database_error', PhoneNumber, E}). -spec number_is_porting(ne_binary()) -> no_return(). number_is_porting(Num) -> @@ -131,9 +121,9 @@ by_carrier(Carrier, E, Number) -> %%-------------------------------------------------------------------- -spec to_json(reason()) -> error(). --spec to_json(reason(), api_binary()) -> +-spec to_json(reason(), api_ne_binary()) -> error(). --spec to_json(reason(), api_binary(), api_binary()) -> +-spec to_json(reason(), api_ne_binary(), api_ne_binary()) -> error(). to_json(Reason)-> to_json(Reason, 'undefined'). @@ -156,12 +146,17 @@ to_json('not_reconcilable', Num=?NE_BINARY, _) -> to_json('unauthorized', _, Cause) -> Message = <<"requestor is unauthorized to perform operation">>, build_error(403, 'forbidden', Message, Cause); +to_json('service_restriction', Num=?NE_BINARY, Cause) -> + build_error(402, 'service_restriction', Cause, Num); to_json('no_change_required', _, Cause) -> Message = <<"no change required">>, build_error(400, 'no_change_required', Message, Cause); to_json('invalid_state_transition', _, Cause) -> Message = <<"invalid state transition">>, build_error(400, 'invalid_state_transition', Message, Cause); +to_json('assign_failure', _, Cause) -> + Message = <<"invalid account to assign to">>, + build_error(400, 'assign_failure', Message, Cause); to_json('by_carrier', Num, {_Carrier,_Cause}) -> lager:error("carrier ~s fault: ~p", [_Carrier, _Cause]), build_error(500, 'unspecified_fault', <<"fault by carrier">>, Num); diff --git a/core/kazoo_number_manager/src/knm_gen_carrier.erl b/core/kazoo_number_manager/src/knm_gen_carrier.erl index baf69064599..12809021a9d 100644 --- a/core/kazoo_number_manager/src/knm_gen_carrier.erl +++ b/core/kazoo_number_manager/src/knm_gen_carrier.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% When implementing carrier modules, these callbacks are a must! @@ -32,3 +32,7 @@ -callback is_local() -> boolean(). + +-callback check_numbers(ne_binaries()) -> + {'ok', kz_json:object()} | + {'error', any()}. diff --git a/core/kazoo_number_manager/src/knm_gen_provider.erl b/core/kazoo_number_manager/src/knm_gen_provider.erl index d6814104889..2af63f88e07 100644 --- a/core/kazoo_number_manager/src/knm_gen_provider.erl +++ b/core/kazoo_number_manager/src/knm_gen_provider.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% When implementing provider modules, these callbacks are a must! diff --git a/core/kazoo_number_manager/src/knm_locality.erl b/core/kazoo_number_manager/src/knm_locality.erl index 4766609007f..2ae38f593ea 100644 --- a/core/kazoo_number_manager/src/knm_locality.erl +++ b/core/kazoo_number_manager/src/knm_locality.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_number_manager/src/knm_number.erl b/core/kazoo_number_manager/src/knm_number.erl index 6878d12f689..b92132443c1 100644 --- a/core/kazoo_number_manager/src/knm_number.erl +++ b/core/kazoo_number_manager/src/knm_number.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz INC +%%% @copyright (C) 2015-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -10,7 +10,7 @@ %%%------------------------------------------------------------------- -module(knm_number). --export([new/0 +-export([new/0, new/1 ,get/1, get/2 ,create/2 ,move/2, move/3 @@ -19,30 +19,27 @@ ,delete/2 ,assign_to_app/2, assign_to_app/3 ,lookup_account/1 - ,save/1 ,reconcile/2 ,reserve/2 ]). -export([phone_number/1, set_phone_number/2 ,services/1, set_services/2 - ,billing_id/1, set_billing_id/2 ,transactions/1 ,add_transaction/2 - ,errors/1 ,charges/2, set_charges/3 ,to_public_json/1 ,is_number/1 ]). +-export([attempt/2 + ,ensure_can_create/1 + ,ensure_can_load_to_create/1 + ,state_for_create/2 + ]). -ifdef(TEST). --export([attempt/2]). --export([ensure_can_load_to_create/1]). -export([ensure_can_create/2]). --export([create_or_load/3]). --export([update_phone_number/2]). --include_lib("eunit/include/eunit.hrl"). -endif. -include_lib("kazoo_json/include/kazoo_json.hrl"). @@ -50,10 +47,8 @@ -record(knm_number, {knm_phone_number :: knm_phone_number:knm_phone_number() ,services :: kz_services:services() - ,billing_id :: api_binary() ,transactions = [] :: kz_transaction:transactions() - ,errors = [] :: [] - ,charges = [] :: [{ne_binary(), integer()}] + ,charges = [] :: [{ne_binary(), non_neg_integer()}] }). -opaque knm_number() :: #knm_number{}. -type knm_numbers() :: [knm_number()]. @@ -64,8 +59,6 @@ ,dry_run_return/0 ]). --type dry_run_or_number_return() :: knm_number() | dry_run_return(). - -type lookup_error() :: 'not_reconcilable' | 'not_found' | 'unassigned' | @@ -75,6 +68,29 @@ -type lookup_account_return() :: {'ok', ne_binary(), knm_number_options:extra_options()} | {'error', lookup_error()}. + +-define(TRY_CLAUSES(Num), + {_, #{ko := #{Num := Reason}}} -> + {error, Reason}; + {false, #{ok := [Number]}} -> + {ok, Number}; + {true, T=#{ok := [_Number], services := Services}} -> + Charges = knm_services:phone_number_activation_charges(T), + {dry_run, Services, Charges}). + +-define(TRY2(F, Num, Options), + case {knm_number_options:dry_run(Options) + ,knm_numbers:F([Num], Options) + } + of ?TRY_CLAUSES(Num) end). + +-define(TRY3(F, Num, Arg2, Options), + case {knm_number_options:dry_run(Options) + ,knm_numbers:F([Num], Arg2, Options) + } + of ?TRY_CLAUSES(Num) end). + + %%-------------------------------------------------------------------- %% @public %% @doc @@ -83,6 +99,14 @@ -spec new() -> knm_number(). new() -> #knm_number{}. +-spec new(knm_numbers:collection()) -> knm_numbers:collection(); + (knm_phone_number:knm_phone_number()) -> knm_number(). +new(T=#{todo := PNs}) -> + Numbers = [new(PN) || PN <- PNs], + knm_numbers:ok(Numbers, T); +new(PN) -> + set_phone_number(new(), PN). + -spec is_number(any()) -> boolean(). is_number(#knm_number{}) -> 'true'; is_number(_) -> 'false'. @@ -101,12 +125,9 @@ get(Num) -> get(Num, knm_number_options:default()). get(Num, Options) -> - case knm_converters:is_reconcilable(Num) of - 'false' -> {'error', 'not_reconcilable'}; - 'true' -> - wrap_phone_number_return( - attempt(fun knm_phone_number:fetch/2, [Num, Options]) - ) + case knm_numbers:get([Num], Options) of + #{ok := [Number]} -> {ok, Number}; + #{ko := #{Num := Reason}} -> {error, Reason} end. %%-------------------------------------------------------------------- @@ -116,24 +137,9 @@ get(Num, Options) -> %% Note: `assign_to' number option MUST be set. %% @end %%-------------------------------------------------------------------- --spec create(ne_binary(), knm_number_options:options()) -> - knm_number_return(). +-spec create(ne_binary(), knm_number_options:options()) -> knm_number_return(). create(Num, Options) -> - ?MATCH_ACCOUNT_RAW(_) = knm_number_options:assign_to(Options), - case knm_converters:is_reconcilable(Num) of - 'false' -> {'error', knm_errors:to_json('not_reconcilable', Num)}; - 'true' -> - attempt(fun create_or_load/2, [Num, Options]) - end. - --spec create_or_load(ne_binary(), knm_number_options:options()) -> - dry_run_or_number_return(). -create_or_load(Num, Options0) -> - AccountId = knm_number_options:assign_to(Options0), - ToState = state_for_create(AccountId, Options0), - lager:debug("picked ~s state ~s for ~s", [Num, ToState, AccountId]), - Options = [{'state', ToState} | Options0], - create_or_load(Num, Options, knm_phone_number:fetch(Num)). + ?TRY2(create, Num, Options). -spec state_for_create(ne_binary(), knm_number_options:options()) -> ne_binary(). -ifdef(TEST). @@ -159,21 +165,18 @@ state_for_create(AccountId, Options) -> end. -endif. --spec create_or_load(ne_binary(), knm_number_options:options(), knm_phone_number_return()) -> - dry_run_or_number_return(). -create_or_load(_Num, Options, {'ok', PhoneNumber}) -> - ensure_can_load_to_create(PhoneNumber), - Updates = knm_number_options:to_phone_number_setters( - props:delete('state', Options) - ), - {'ok', NewPhoneNumber} = knm_phone_number:setters(PhoneNumber, Updates), - create_phone_number(Options, set_phone_number(new(), NewPhoneNumber)); -create_or_load(Num, Options, {'error', 'not_found'}) -> - ensure_can_create(Num, Options), - PhoneNumber = knm_phone_number:new(Num, Options), - create_phone_number(Options, set_phone_number(new(), PhoneNumber)). - --spec ensure_can_load_to_create(knm_phone_number:knm_phone_number()) -> 'true'. +-spec ensure_can_load_to_create(knm_phone_number:knm_phone_number()) -> 'true'; + (knm_numbers:collection()) -> knm_numbers:collection(). +ensure_can_load_to_create(T0=#{todo := PNs}) -> + F = fun (PN, T) -> + case attempt(fun ensure_can_load_to_create/1, [PN]) of + true -> knm_numbers:ok(PN, T); + {error, R} -> + Num = knm_phone_number:number(PN), + knm_numbers:ko(Num, R, T) + end + end, + lists:foldl(F, T0, PNs); ensure_can_load_to_create(PhoneNumber) -> ensure_state(PhoneNumber, ?NUMBER_STATE_AVAILABLE). @@ -186,61 +189,25 @@ ensure_state(PhoneNumber, ExpectedState) -> knm_errors:number_exists(knm_phone_number:number(PhoneNumber)) end. --spec create_phone_number(knm_number_options:options(), knm_number()) -> - dry_run_or_number_return(). -create_phone_number(Options, Number) -> - TargetState = knm_number_options:state(Options), - Routines = [fun (N) -> knm_number_states:to_state(N, TargetState) end - ,fun save_number/1 - ], - apply_number_routines(Number, Routines). - %%-------------------------------------------------------------------- %% @public %% @doc -%% Fetches then transition an existing number to the reserved state. +%% Fetches then transitions an existing number to the reserved state. %% @end %%-------------------------------------------------------------------- -spec reserve(ne_binary(), knm_number_options:options()) -> knm_number_return(). reserve(Num, Options) -> - case get(Num, Options) of - {'ok', Number} -> - attempt(fun do_reserve/1, [Number]); - {'error', _R}=E -> E - end. - --spec do_reserve(knm_number()) -> knm_number_return(). -do_reserve(Number) -> - Routines = [fun knm_number_states:to_reserved/1 - ,fun save_number/1 - ], - apply_number_routines(Number, Routines). - --spec save_number(knm_number()) -> knm_number(). -save_number(Number) -> - Routines = [fun knm_providers:save/1 - ,fun save_phone_number/1 - ,fun knm_services:update_services/1 - ,fun dry_run_or_number/1 - ], - apply_number_routines(Number, Routines). - --spec save_phone_number(knm_number()) -> knm_number(). -save_phone_number(Number) -> - set_phone_number(Number, knm_phone_number:save(phone_number(Number))). - --spec save_wrap_phone_number(knm_phone_number:knm_phone_number(), knm_number()) -> knm_number_return(). -save_wrap_phone_number(PhoneNumber, Number) -> - wrap_phone_number_return(knm_phone_number:save(PhoneNumber), Number). - --spec dry_run_or_number(knm_number()) -> dry_run_or_number_return(). -dry_run_or_number(Number) -> - case knm_phone_number:dry_run(phone_number(Number)) of - 'false' -> Number; - 'true' -> - Charges = knm_services:phone_number_activation_charges(Number), - {'dry_run', services(Number), Charges} - end. + ?TRY2(reserve, Num, Options). + +-spec ensure_can_create(knm_numbers:collection()) -> knm_numbers:collection(). +ensure_can_create(T0=#{todo := Nums, options := Options}) -> + F = fun (Num, T) -> + case attempt(fun ensure_can_create/2, [Num, Options]) of + {error, R} -> knm_numbers:ko(Num, R, T); + true -> knm_numbers:ok(knm_phone_number:new(Num, Options), T) + end + end, + lists:foldl(F, T0, Nums). -spec ensure_can_create(ne_binary(), knm_number_options:options()) -> 'true'. ensure_can_create(Num, Options) -> @@ -267,9 +234,13 @@ ensure_account_is_allowed_to_create(_, ?KNM_DEFAULT_AUTH_BY) -> lager:info("bypassing auth"), 'true'; ensure_account_is_allowed_to_create(_Options, _AccountId) -> - {'ok', JObj} = ?LOAD_ACCOUNT(_Options, _AccountId), - kz_account:allow_number_additions(JObj) - orelse knm_errors:unauthorized(). + case knm_number_options:state(_Options) of + ?NUMBER_STATE_PORT_IN -> 'true'; + _Else -> + {'ok', JObj} = ?LOAD_ACCOUNT(_Options, _AccountId), + kz_account:allow_number_additions(JObj) + orelse knm_errors:unauthorized() + end. -spec ensure_number_is_not_porting(ne_binary(), knm_number_options:options()) -> 'true'. -ifdef(TEST). @@ -298,35 +269,8 @@ ensure_number_is_not_porting(Num, Options) -> move(Num, MoveTo) -> move(Num, MoveTo, knm_number_options:default()). -move(Num, ?MATCH_ACCOUNT_RAW(MoveTo), Options0) -> - Options = [{'assign_to', MoveTo} | Options0], - case get(Num, Options) of - {'ok', Number} -> attempt(fun move_to/1, [Number]); - {'error', 'not_found'} -> maybe_from_discovery(Num, Options); - {'error', _R}=E -> E - end. - - --spec maybe_from_discovery(ne_binary(), knm_number_options:options()) -> knm_number_return(). -maybe_from_discovery(Num, Options) -> - case knm_search:discovery(Num, Options) of - {'ok', Number} -> attempt(fun move_to/1, [Number]); - {'error', 'not_found'} -> from_not_found(Num, Options); - {'error', _R}=E -> E - end. - --spec from_not_found(ne_binary(), knm_number_options:options()) -> knm_number_return(). -from_not_found(Num, Options) -> - PN = knm_phone_number:new(Num, Options), - Number = set_phone_number(new(), PN), - attempt(fun move_to/1, [Number]). - --spec move_to(knm_number()) -> knm_number_return(). -move_to(Number) -> - Routines = [fun knm_number_states:to_in_service/1 - ,fun save_number/1 - ], - apply_number_routines(Number, Routines). +move(Num, MoveTo, Options) -> + ?TRY3(move, Num, MoveTo, Options). %%-------------------------------------------------------------------- %% @public @@ -335,58 +279,14 @@ move_to(Number) -> %% Note: will always result in a phone_number save. %% @end %%-------------------------------------------------------------------- --spec update(ne_binary(), knm_phone_number:set_functions()) -> - knm_number_return(). +-spec update(ne_binary(), knm_phone_number:set_functions()) -> knm_number_return(). -spec update(ne_binary(), knm_phone_number:set_functions(), knm_number_options:options()) -> knm_number_return(). update(Num, Routines) -> update(Num, Routines, knm_number_options:default()). update(Num, Routines, Options) -> - case get(Num, Options) of - {'error', _R}=E -> E; - {'ok', Number} -> - attempt(fun update_phone_number/2, [Number, Routines]) - end. - --spec update_phone_number(knm_number(), knm_phone_number:set_functions()) -> - knm_number_return(). -update_phone_number(Number, Routines) -> - PhoneNumber = phone_number(Number), - case knm_phone_number:setters(PhoneNumber, Routines) of - {'error', _R}=Error -> Error; - {'ok', NewPN} -> - {'ok', save_number(set_phone_number(Number, NewPN))} - end. - -%%-------------------------------------------------------------------- -%% @public -%% @doc -%% @end -%%-------------------------------------------------------------------- --spec save(knm_number()) -> knm_number_return(). -save(Number) -> - Num = - case is_carrier_search_result(Number) of - 'false' -> knm_services:update_services(Number); - 'true' -> - %% Number was created as a result of carrier search - %% thus has no services associated with it - Number - end, - PhoneNumber = knm_phone_number:save(phone_number(Num)), - wrap_phone_number_return(PhoneNumber, Num). - -%% @private --spec is_carrier_search_result(knm_number()) -> boolean(). -is_carrier_search_result(Number) -> - PhoneNumber = phone_number(Number), - SearchableStates = [?NUMBER_STATE_DISCOVERY - ,?NUMBER_STATE_AVAILABLE - ,?NUMBER_STATE_RESERVED - ], - 'undefined' == knm_phone_number:assigned_to(PhoneNumber) - andalso lists:member(knm_phone_number:state(PhoneNumber), SearchableStates). + ?TRY3(update, Num, Routines, Options). %%-------------------------------------------------------------------- %% @public @@ -396,203 +296,44 @@ is_carrier_search_result(Number) -> %%-------------------------------------------------------------------- -spec reconcile(ne_binary(), knm_number_options:options()) -> knm_number_return(). reconcile(DID, Options) -> - knm_number_options:assign_to(Options) == 'undefined' - andalso knm_errors:assign_failure(Options, 'field_undefined'), - NewOptions = [{'auth_by', ?KNM_DEFAULT_AUTH_BY} - | Options - ], - case ?MODULE:get(DID) of - {'ok', Number} -> - reconcile_number(Number, NewOptions); - {'error', 'not_found'} -> - AssignTo = knm_number_options:assign_to(Options), - %% Ensures state to be IN_SERVICE - move(DID, AssignTo, NewOptions); - {'error', _}=E -> E - end. - --spec reconcile_number(knm_number(), knm_number_options:options()) -> knm_number_return(). -reconcile_number(Number, Options) -> - PhoneNumber = phone_number(Number), - Updaters = case props:is_defined(module_name, Options) of - false -> []; - true -> - [{knm_number_options:module_name(Options) - ,knm_phone_number:module_name(PhoneNumber) - ,fun knm_phone_number:set_module_name/2 - }] - end ++ - [{knm_number_options:assign_to(Options) - ,knm_phone_number:assigned_to(PhoneNumber) - ,fun knm_phone_number:set_assigned_to/2 - } - ,{knm_number_options:auth_by(Options) - ,knm_phone_number:auth_by(PhoneNumber) - ,fun knm_phone_number:set_auth_by/2 - } - ,{knm_number_options:public_fields(Options) - ,knm_phone_number:doc(PhoneNumber) - ,fun knm_phone_number:update_doc/2 - } - ,{?NUMBER_STATE_IN_SERVICE - ,knm_phone_number:state(PhoneNumber) - ,fun knm_phone_number:set_state/2 - } - ], - case updates_require_save(PhoneNumber, Updaters) of - {'false', _PhoneNumber} -> {'ok', Number}; - {'true', UpdatedPhoneNumber} -> - save_wrap_phone_number(UpdatedPhoneNumber, Number) - end. - --spec updates_require_save(knm_phone_number:knm_phone_number(), up_req_els()) -> up_req_acc(). -updates_require_save(PhoneNumber, Updaters) -> - Acc0 = {'false', PhoneNumber}, - lists:foldl(fun update_requires_save/2, Acc0, Updaters). - --type set_fun() :: fun((knm_phone_number:knm_phone_number(), any()) -> knm_phone_number:knm_phone_number()). - --type up_req_el() :: {ne_binary(), api_binary(), set_fun()}. --type up_req_els() :: [up_req_el()]. --type up_req_acc() :: {boolean(), knm_phone_number:knm_phone_number()}. - --spec update_requires_save(up_req_el(), up_req_acc()) -> up_req_acc(). -update_requires_save({V, V, _Fun}, Acc) -> - Acc; -update_requires_save({NewV, _OldV, SetFun}, {_, PhoneNumber}) -> - {'true', SetFun(PhoneNumber, NewV)}. + ?TRY2(reconcile, DID, Options). %%-------------------------------------------------------------------- %% @public %% @doc %% @end %%-------------------------------------------------------------------- --spec release(ne_binary()) -> - knm_number_return(). --spec release(ne_binary(), knm_number_options:options()) -> - knm_number_return(). +-spec release(ne_binary()) -> knm_number_return(). +-spec release(ne_binary(), knm_number_options:options()) -> knm_number_return(). release(Num) -> release(Num, knm_number_options:default()). release(Num, Options) -> - case get(Num, Options) of - {'error', _R}=E -> E; - {'ok', Number} -> - attempt(fun release_number/2, [Number, Options]) - end. - --spec release_number(knm_number(), knm_number_options:options()) -> knm_number_return(). -release_number(Number, Options) -> - Routines = [fun knm_phone_number:release/1 - ], - {'ok', PhoneNumber} = knm_phone_number:setters(phone_number(Number), Routines), - N1 = knm_providers:delete(set_phone_number(Number, PhoneNumber)), - N = unwind_or_disconnect(N1, Options), - save_wrap_phone_number(phone_number(N), N). - --spec unwind_or_disconnect(knm_number(), knm_number_options:options()) -> knm_number(). -unwind_or_disconnect(Number, Options) -> - PhoneNumber = knm_phone_number:unwind_reserve_history(phone_number(Number)), - N = set_phone_number(Number, PhoneNumber), - case knm_phone_number:reserve_history(PhoneNumber) of - [] -> disconnect(N, Options); - History -> unwind(N, History) - end. - --spec unwind(knm_phone_number:phone_number(), ne_binaries()) -> knm_number(). -unwind(Number, [NewAssignedTo|_]) -> - Routines = [{fun knm_phone_number:set_assigned_to/2, NewAssignedTo} - ,{fun knm_phone_number:set_state/2, ?NUMBER_STATE_RESERVED} - ], - {'ok', PhoneNumber} = knm_phone_number:setters(phone_number(Number), Routines), - set_phone_number(Number, PhoneNumber). - --spec disconnect(knm_number(), knm_number_options:options()) -> knm_number(). -disconnect(Number, Options) -> - ShouldDelete = knm_config:should_permanently_delete( - knm_number_options:should_delete(Options) - ), - try knm_carriers:disconnect(Number) of - N when ShouldDelete -> delete_phone_number(N); - N -> maybe_age(N) - catch - _E:_R when ShouldDelete -> - ?LOG_WARN("failed to disconnect number: ~s: ~p", [_E, _R]), - delete_phone_number(Number) - end. - --spec delete_phone_number(knm_number()) -> knm_number(). -delete_phone_number(Number) -> - lager:debug("deleting permanently"), - knm_number_states:to_deleted(Number). - --spec maybe_age(knm_number()) -> knm_number(). -maybe_age(Number) -> - case knm_config:should_age() - andalso knm_phone_number:state(phone_number(Number)) - of - ?NUMBER_STATE_AVAILABLE -> - lager:debug("aging available number for some time"), - knm_number_states:to_aging(Number); - _ -> Number - end. + ?TRY2(release, Num, Options). %%-------------------------------------------------------------------- %% @public %% @doc -%% Remove a number from the system without doing any checking. +%% Remove a number from the system without doing any state checking. %% Sounds too harsh for you? You are looking for release/1,2. %% @end %%-------------------------------------------------------------------- -spec delete(ne_binary(), knm_number_options:options()) -> knm_number_return(). delete(Num, Options) -> - case get(Num, Options) of - {'error', _R}=E -> E; - {'ok', Number} -> - AuthBy = knm_number_options:auth_by(Options), - attempt(fun delete_number/2, [Number, AuthBy]) - end. - --spec delete_number(knm_number(), ne_binary()) -> knm_number_return(). -delete_number(Number, AuthBy) -> - case ?KNM_DEFAULT_AUTH_BY =:= AuthBy - orelse kz_util:is_system_admin(AuthBy) - of - 'false' -> knm_errors:unauthorized(); - 'true' -> - N = knm_providers:delete(Number), - PN = knm_phone_number:delete(phone_number(N)), - wrap_phone_number_return(PN, N) - end. + ?TRY2(delete, Num, Options). %%-------------------------------------------------------------------- %% @public %% @doc %% @end %%-------------------------------------------------------------------- --spec assign_to_app(ne_binary(), api_binary()) -> knm_number_return(). --spec assign_to_app(ne_binary(), api_binary(), knm_number_options:options()) -> knm_number_return(). +-spec assign_to_app(ne_binary(), api_ne_binary()) -> knm_number_return(). +-spec assign_to_app(ne_binary(), api_ne_binary(), knm_number_options:options()) -> knm_number_return(). assign_to_app(Num, App) -> assign_to_app(Num, App, knm_number_options:default()). assign_to_app(Num, App, Options) -> - case get(Num, Options) of - {'error', _R}=E -> E; - {'ok', Number} -> - maybe_update_assignment(Number, App) - end. - --spec maybe_update_assignment(knm_number(), api_binary()) -> knm_number_return(). -maybe_update_assignment(Number, NewApp) -> - PhoneNumber = phone_number(Number), - case knm_phone_number:used_by(PhoneNumber) of - NewApp -> {'ok', Number}; - _OldApp -> - lager:debug("assigning ~s to ~s", [knm_phone_number:number(PhoneNumber), NewApp]), - save_wrap_phone_number(knm_phone_number:set_used_by(PhoneNumber, NewApp) - ,Number - ) - end. + ?TRY3(assign_to_app, Num, App, Options). %%-------------------------------------------------------------------- %% @public @@ -824,31 +565,6 @@ fetch_account_from_ports(NormalizedNum, Error) -> {'ok', AccountId, Props} end. -%%-------------------------------------------------------------------- -%% @private -%% @doc -%% @end -%%-------------------------------------------------------------------- --spec wrap_phone_number_return(knm_phone_number_return() | knm_phone_number:knm_phone_number()) -> - knm_number_return(). --spec wrap_phone_number_return(knm_phone_number_return() | knm_phone_number:knm_phone_number(), knm_number()) -> - knm_number_return(). -wrap_phone_number_return(Result) -> - wrap_phone_number_return(Result, new()). - -wrap_phone_number_return({'error', _R}=E, #knm_number{knm_phone_number = _PhoneNumber}) - when _PhoneNumber /= 'undefined' -> - lager:debug("number ~s (~s) error: ~p" - ,[knm_phone_number:number(_PhoneNumber), knm_phone_number:state(_PhoneNumber), _R]), - E; -wrap_phone_number_return({'error', _R}=E, _) -> - lager:debug("number error: ~p", [_R]), - E; -wrap_phone_number_return({'ok', PhoneNumber}, Number) -> - {'ok', set_phone_number(Number, PhoneNumber)}; -wrap_phone_number_return(PhoneNumber, Number) -> - {'ok', set_phone_number(Number, PhoneNumber)}. - -spec phone_number(knm_number()) -> knm_phone_number:knm_phone_number(). -spec set_phone_number(knm_number(), knm_phone_number:knm_phone_number()) -> knm_number(). @@ -863,14 +579,6 @@ services(#knm_number{services=Services}) -> Services. set_services(#knm_number{}=Number, Services) -> Number#knm_number{services=Services}. --spec billing_id(knm_number()) -> api_binary(). -billing_id(#knm_number{billing_id=BillingId}) -> - BillingId. - --spec set_billing_id(knm_number(), ne_binary()) -> knm_number(). -set_billing_id(#knm_number{}=Number, BillingId) -> - Number#knm_number{billing_id=BillingId}. - -spec transactions(knm_number()) -> kz_transaction:transactions(). transactions(#knm_number{transactions=Transactions}) -> Transactions. @@ -878,11 +586,8 @@ transactions(#knm_number{transactions=Transactions}) -> Transactions. add_transaction(#knm_number{transactions=Transactions}=Number, Transaction) -> Number#knm_number{transactions=[Transaction|Transactions]}. --spec errors(knm_number()) -> list(). -errors(#knm_number{errors=Errors}) -> Errors. - --spec charges(knm_number(), ne_binary()) -> number(). --spec set_charges(knm_number(), ne_binary(), number()) -> knm_number(). +-spec charges(knm_number(), ne_binary()) -> non_neg_integer(). +-spec set_charges(knm_number(), ne_binary(), non_neg_integer()) -> knm_number(). charges(#knm_number{charges=Charges}, Key) -> props:get_value(Key, Charges, 0). @@ -894,7 +599,8 @@ to_public_json(#knm_number{}=Number) -> knm_phone_number:to_public_json(phone_number(Number)). -spec attempt(fun(), list()) -> knm_number_return() | - knm_phone_number_return(). + knm_phone_number_return() | + true. attempt(Fun, Args) -> try apply(Fun, Args) of #knm_number{}=N -> {'ok', N}; @@ -908,18 +614,8 @@ attempt(Fun, Args) -> {'error', knm_errors:to_json(Reason, num_to_did(Number), Cause)} end. --spec num_to_did(api_binary() | knm_number() | knm_phone_number:knm_phone_number()) -> - api_binary(). +-spec num_to_did(api_binary() | knm_number() | knm_phone_number:knm_phone_number()) -> api_ne_binary(). num_to_did('undefined') -> 'undefined'; num_to_did(?NE_BINARY = DID) -> DID; -num_to_did(#knm_number{}=Number) -> - num_to_did(phone_number(Number)); -num_to_did(PhoneNumber) -> - knm_phone_number:number(PhoneNumber). - --type number_routine() :: fun((knm_number()) -> dry_run_or_number_return()). --type number_routines() :: [number_routine()]. --spec apply_number_routines(knm_number(), number_routines()) -> - dry_run_or_number_return(). -apply_number_routines(Number, Routines) -> - lists:foldl(fun(F, N) -> F(N) end, Number, Routines). +num_to_did(#knm_number{}=Number) -> num_to_did(phone_number(Number)); +num_to_did(PhoneNumber) -> knm_phone_number:number(PhoneNumber). diff --git a/core/kazoo_number_manager/src/knm_number_options.erl b/core/kazoo_number_manager/src/knm_number_options.erl index 496687e3ce3..ed512c70352 100644 --- a/core/kazoo_number_manager/src/knm_number_options.erl +++ b/core/kazoo_number_manager/src/knm_number_options.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz INC +%%% @copyright (C) 2015-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_number_manager/src/knm_number_states.erl b/core/kazoo_number_manager/src/knm_number_states.erl index 8e08f73f758..545c716df5e 100644 --- a/core/kazoo_number_manager/src/knm_number_states.erl +++ b/core/kazoo_number_manager/src/knm_number_states.erl @@ -1,215 +1,209 @@ - %------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%%------------------------------------------------------------------- +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end %%% @contributors %%% Peter Defebvre +%%% Pierre Fenoll %%%------------------------------------------------------------------- -module(knm_number_states). --export([to_reserved/1 - ,to_deleted/1 - ,to_in_service/1 - ,to_aging/1 - ,to_port_in/1 - ,to_state/2, to_state/3 - ]). +-export([to_options_state/1]). -include("knm.hrl"). --ifdef(TEST). --include_lib("eunit/include/eunit.hrl"). --endif. - -type kn() :: knm_number:knm_number(). - --spec to_state(ne_binary() | kn(), ne_binary()) -> kn(). --spec to_state(ne_binary() | kn(), ne_binary(), kz_proplist()) -> kn(). -to_state(DID, ToState) -> - to_state(DID, ToState, knm_number_options:default()). -to_state(?NE_BINARY = DID, ToState, Options) -> - case knm_number:get(DID, Options) of - {'error', E} -> knm_errors:unspecified(E, DID); - {'ok', Number} -> change_state(Number, ToState) - end; -to_state(Number, ToState, _Options) -> - change_state(Number, ToState). - --spec change_state(kn(), ne_binary()) -> kn(). -change_state(Number, ?NUMBER_STATE_RESERVED) -> - to_reserved(Number); -change_state(Number, ?NUMBER_STATE_DELETED) -> - to_deleted(Number); -change_state(Number, ?NUMBER_STATE_IN_SERVICE) -> - to_in_service(Number); -change_state(Number, ?NUMBER_STATE_AVAILABLE) -> - to_available(Number); -change_state(Number, ?NUMBER_STATE_AGING) -> - to_aging(Number); -change_state(Number, ?NUMBER_STATE_PORT_IN) -> - to_port_in(Number); -change_state(Number, _State) -> +-type t() :: knm_numbers:collection(). + +-define(TO_STATE2(ToStateF, T0), + knm_numbers:merge_okkos( + [begin + NewT0 = T0#{todo => [], ok => Ns}, + knm_numbers:do(fun (T) -> ToStateF(T, State) end, NewT0) + end + || {State, Ns} <- group_by_state(T0), + [] =/= Ns + ])). + +-spec to_options_state(t()) -> t(). +to_options_state(T=#{options := Options}) -> + TargetState = knm_number_options:state(Options), + change_state(T, TargetState). + +-spec change_state(t(), ne_binary()) -> t(). +change_state(T, ?NUMBER_STATE_RESERVED) -> + to_reserved(T); +change_state(T, ?NUMBER_STATE_DELETED) -> + to_deleted(T); +change_state(T, ?NUMBER_STATE_IN_SERVICE) -> + to_in_service(T); +change_state(T, ?NUMBER_STATE_AVAILABLE) -> + to_available(T); +change_state(T, ?NUMBER_STATE_AGING) -> + to_aging(T); +change_state(T, ?NUMBER_STATE_PORT_IN) -> + to_port_in(T); +change_state(T=#{todo := Ns}, _State) -> lager:debug("unhandled state change to ~p", [_State]), - knm_errors:unspecified('invalid_state', Number). - --spec to_port_in(kn()) -> kn(). --spec to_port_in(kn(), ne_binary()) -> kn(). -to_port_in(Number) -> - to_port_in(Number, number_state(Number)). - -to_port_in(Number, ?NUMBER_STATE_PORT_IN) -> - Routines = [fun move_to_port_in_state/1 - ], - apply_transitions(Number, Routines); -to_port_in(Number, State) -> - knm_errors:invalid_state_transition(Number, State, ?NUMBER_STATE_PORT_IN). - --spec to_aging(kn()) -> kn(). --spec to_aging(kn(), ne_binary()) -> kn(). -to_aging(Number) -> - to_aging(Number, number_state(Number)). - -to_aging(Number, ?NUMBER_STATE_AGING) -> - Routines = [fun move_to_aging_state/1 - ], - apply_transitions(Number, Routines); -to_aging(Number, ?NUMBER_STATE_RELEASED) -> - Routines = [fun move_to_aging_state/1 - ], - apply_transitions(Number, Routines); -to_aging(Number, ?NUMBER_STATE_AVAILABLE) -> - Routines = [fun move_to_aging_state/1 - ], - apply_transitions(Number, Routines); -to_aging(Number, State) -> - knm_errors:invalid_state_transition(Number, State, ?NUMBER_STATE_AGING). - --spec to_available(kn()) -> kn(). --spec to_available(kn(), ne_binary()) -> kn(). -to_available(Number) -> - to_available(Number, number_state(Number)). - -to_available(Number, ?NUMBER_STATE_AVAILABLE) -> - Routines = [fun authorize/1 - ,fun move_to_available_state/1 - ,fun knm_services:activate_phone_number/1 - ], - apply_transitions(Number, Routines); -to_available(Number, State) -> - knm_errors:invalid_state_transition(Number, State, ?NUMBER_STATE_AVAILABLE). - --spec to_reserved(kn()) -> kn(). --spec to_reserved(kn(), ne_binary()) -> kn(). -to_reserved(Number) -> - to_reserved(Number, number_state(Number)). - -to_reserved(Number, ?NUMBER_STATE_RESERVED) -> - Routines = [fun not_assigning_to_self/1 - ,fun is_auth_by_authorized/1 - ,fun update_reserve_history/1 - ,fun move_to_reserved_state/1 - ,fun knm_services:activate_phone_number/1 - ,fun knm_carriers:acquire/1 - ], - apply_transitions(Number, Routines); -to_reserved(Number, ?NUMBER_STATE_DISCOVERY) -> - Routines = [fun authorize/1 - ,fun update_reserve_history/1 - ,fun move_to_reserved_state/1 - ,fun knm_services:activate_phone_number/1 - ,fun knm_carriers:acquire/1 - ], - apply_transitions(Number, Routines); -to_reserved(Number, ?NUMBER_STATE_AVAILABLE) -> - Routines = [fun authorize/1 - ,fun update_reserve_history/1 - ,fun move_to_reserved_state/1 - ,fun knm_services:activate_phone_number/1 - ], - apply_transitions(Number, Routines); -to_reserved(Number, ?NUMBER_STATE_IN_SERVICE) -> - Routines = [fun authorize/1], - apply_transitions(Number, Routines); -to_reserved(Number, State) -> - knm_errors:invalid_state_transition(Number, State, ?NUMBER_STATE_RESERVED). - --spec to_in_service(kn()) -> kn(). --spec to_in_service(kn(), ne_binary()) -> kn(). -to_in_service(Number) -> - to_in_service(Number, number_state(Number)). - -to_in_service(Number, ?NUMBER_STATE_DISCOVERY) -> - Routines = [fun authorize/1 - ,fun move_to_in_service_state/1 - ,fun knm_services:activate_phone_number/1 - ,fun knm_carriers:acquire/1 - ], - apply_transitions(Number, Routines); -to_in_service(Number, ?NUMBER_STATE_PORT_IN) -> - Routines = [fun authorize/1 - ,fun move_to_in_service_state/1 - ], - apply_transitions(Number, Routines); -to_in_service(Number, ?NUMBER_STATE_AVAILABLE) -> - Routines = [fun authorize/1 - ,fun move_to_in_service_state/1 - ,fun knm_services:activate_phone_number/1 - ,fun knm_carriers:acquire/1 - ], - apply_transitions(Number, Routines); -to_in_service(Number, ?NUMBER_STATE_RESERVED) -> - Routines = [fun in_service_from_reserved_authorize/1 - ,fun move_to_in_service_state/1 - ], - apply_transitions(Number, Routines); -to_in_service(Number, ?NUMBER_STATE_IN_SERVICE) -> - PhoneNumber = knm_number:phone_number(Number), - AssignTo = knm_phone_number:assign_to(PhoneNumber), - case knm_phone_number:assigned_to(PhoneNumber) of - AssignTo -> Number; - _AssignedTo -> - Routines = [fun in_service_from_in_service_authorize/1 - ,fun move_to_in_service_state/1 - ], - apply_transitions(Number, Routines) - end; -to_in_service(Number, State) -> - knm_errors:invalid_state_transition(Number, State, ?NUMBER_STATE_IN_SERVICE). - --spec to_deleted(kn()) -> kn(). -to_deleted(Number) -> - Routines = [fun move_to_deleted_state/1 - ], - apply_transitions(Number, Routines). - --spec authorize(kn()) -> kn(). --spec authorize(kn(), api_binary()) -> kn(). -authorize(Number) -> - authorize(Number, knm_phone_number:auth_by(knm_number:phone_number(Number))). + Error = knm_errors:to_json(invalid_state), + knm_numbers:ko(Ns, Error, T). + +-spec to_port_in(t()) -> t(). +to_port_in(T0) -> ?TO_STATE2(to_port_in, T0). + +to_port_in(T, ?NUMBER_STATE_PORT_IN) -> + knm_numbers:pipe(T + ,[fun move_to_port_in_state/1 + ]); +to_port_in(T, State) -> + invalid_state_transition(T, State, ?NUMBER_STATE_PORT_IN). + +-spec to_aging(t()) -> t(). +to_aging(T0) -> ?TO_STATE2(to_aging, T0). + +to_aging(T, ?NUMBER_STATE_AGING) -> + knm_numbers:pipe(T + ,[fun move_to_aging_state/1 + ]); +to_aging(T, ?NUMBER_STATE_RELEASED) -> + knm_numbers:pipe(T + ,[fun move_to_aging_state/1 + ]); +to_aging(T, ?NUMBER_STATE_AVAILABLE) -> + knm_numbers:pipe(T + ,[fun move_to_aging_state/1 + ]); +to_aging(T, State) -> + invalid_state_transition(T, State, ?NUMBER_STATE_AGING). + +-spec to_available(t()) -> t(). +to_available(T0) -> ?TO_STATE2(to_available, T0). + +to_available(T, ?NUMBER_STATE_AVAILABLE) -> + knm_numbers:pipe(T + ,[fun authorize/1 + ,fun move_to_available_state/1 + ,fun knm_services:activate_phone_number/1 + ]); +to_available(T, State) -> + invalid_state_transition(T, State, ?NUMBER_STATE_AVAILABLE). + +-spec to_reserved(t()) -> t(). +to_reserved(T0) -> ?TO_STATE2(to_reserved, T0). + +to_reserved(T, ?NUMBER_STATE_RESERVED) -> + knm_numbers:pipe(T + ,[fun not_assigning_to_self/1 + ,fun is_auth_by_authorized/1 + ,fun update_reserve_history/1 + ,fun move_to_reserved_state/1 + ,fun knm_services:activate_phone_number/1 + ,fun knm_carriers:acquire/1 + ]); +to_reserved(T, ?NUMBER_STATE_DISCOVERY) -> + knm_numbers:pipe(T + ,[fun authorize/1 + ,fun update_reserve_history/1 + ,fun move_to_reserved_state/1 + ,fun knm_services:activate_phone_number/1 + ,fun knm_carriers:acquire/1 + ]); +to_reserved(T, ?NUMBER_STATE_AVAILABLE) -> + knm_numbers:pipe(T + ,[fun authorize/1 + ,fun update_reserve_history/1 + ,fun move_to_reserved_state/1 + ,fun knm_services:activate_phone_number/1 + ]); +to_reserved(T, ?NUMBER_STATE_IN_SERVICE) -> + knm_numbers:pipe(T + ,[fun authorize/1 + ]); +to_reserved(T, State) -> + invalid_state_transition(T, State, ?NUMBER_STATE_RESERVED). + +-spec to_in_service(t()) -> t(). +to_in_service(T0) -> ?TO_STATE2(to_in_service, T0). + +to_in_service(T, ?NUMBER_STATE_DISCOVERY) -> + knm_numbers:pipe(T + ,[fun authorize/1 + ,fun move_to_in_service_state/1 + ,fun knm_services:activate_phone_number/1 + ,fun knm_carriers:acquire/1 + ]); +to_in_service(T, ?NUMBER_STATE_PORT_IN) -> + knm_numbers:pipe(T + ,[fun authorize/1 + ,fun move_to_in_service_state/1 + ]); +to_in_service(T, ?NUMBER_STATE_AVAILABLE) -> + knm_numbers:pipe(T + ,[fun authorize/1 + ,fun move_to_in_service_state/1 + ,fun knm_services:activate_phone_number/1 + ,fun knm_carriers:acquire/1 + ]); +to_in_service(T, ?NUMBER_STATE_RESERVED) -> + knm_numbers:pipe(T + ,[fun in_service_from_reserved_authorize/1 + ,fun move_to_in_service_state/1 + ]); +to_in_service(T=#{todo := Ns}, ?NUMBER_STATE_IN_SERVICE) -> + {Yes, No} = lists:partition(fun is_assigned_to_assignto/1, Ns), + Ta = knm_numbers:ok(Yes, T), + Tb = knm_numbers:pipe(T#{todo => No} + ,[fun in_service_from_in_service_authorize/1 + ,fun move_to_in_service_state/1 + ]), + knm_numbers:merge_okkos(Ta, Tb); +to_in_service(T, State) -> + invalid_state_transition(T, State, ?NUMBER_STATE_IN_SERVICE). + +-spec to_deleted(t()) -> t(). +to_deleted(T) -> + knm_numbers:pipe(T, [fun move_to_deleted_state/1]). -ifdef(TEST). -define(ACCT_HIERARCHY(AuthBy, AssignTo, _) ,AuthBy =:= ?MASTER_ACCOUNT_ID - andalso AssignTo =:= ?RESELLER_ACCOUNT_ID - ). + andalso AssignTo =:= ?RESELLER_ACCOUNT_ID). -else. -define(ACCT_HIERARCHY(AuthBy, AssignTo, Bool) - ,kz_util:is_in_account_hierarchy(AuthBy, AssignTo, Bool) - ). + ,kz_util:is_in_account_hierarchy(AuthBy, AssignTo, Bool)). -endif. -authorize(Number, ?KNM_DEFAULT_AUTH_BY) -> - lager:info("bypassing auth"), - Number; -authorize(Number, AuthBy) -> - AssignTo = knm_phone_number:assign_to(knm_number:phone_number(Number)), +-spec authorize(t()) -> t(). +authorize(T0=#{todo := Ns, options := Options}) -> + case knm_number_options:auth_by(Options) of + ?KNM_DEFAULT_AUTH_BY -> + lager:info("bypassing auth"), + knm_numbers:ok(Ns, T0); + AuthBy -> + F = fun (N, T) -> authorize_fold(N, T, AuthBy) end, + lists:foldl(F, T0, Ns) + end. + +authorize_fold(N, T, AuthBy) -> + AssignTo = knm_phone_number:assign_to(knm_number:phone_number(N)), case ?ACCT_HIERARCHY(AuthBy, AssignTo, 'true') of - 'false' -> knm_errors:unauthorized(); - 'true' -> Number + true -> knm_numbers:ok(N, T); + false -> + Reason = knm_errors:to_json(unauthorized), + knm_numbers:ko(N, Reason, T) end. --spec in_service_from_reserved_authorize(kn()) -> kn(). +-spec in_service_from_reserved_authorize(kn()) -> kn(); + (t()) -> t(). +in_service_from_reserved_authorize(T0=#{todo := Ns}) -> + F = fun (N, T) -> + case knm_number:attempt(fun in_service_from_reserved_authorize/1, [N]) of + {ok, NewN} -> knm_numbers:ok(NewN, T); + {error, R} -> knm_numbers:ko(N, R, T) + end + end, + lists:foldl(F, T0, Ns); in_service_from_reserved_authorize(Number) -> PhoneNumber = knm_number:phone_number(Number), AssignTo = knm_phone_number:assign_to(PhoneNumber), @@ -230,24 +224,35 @@ in_service_from_reserved_authorize(Number) -> Number end. --spec in_service_from_in_service_authorize(kn()) -> kn(). -in_service_from_in_service_authorize(Number) -> - PhoneNumber = knm_number:phone_number(Number), - AssignTo = knm_phone_number:assign_to(PhoneNumber), - AuthBy = knm_phone_number:auth_by(PhoneNumber), +-spec in_service_from_in_service_authorize(kn()) -> kn(); + (t()) -> t(). +in_service_from_in_service_authorize(T=#{todo := Ns, options := Options}) -> + AssignTo = knm_number_options:assign_to(Options), + AuthBy = knm_number_options:auth_by(Options), Sudo = ?KNM_DEFAULT_AUTH_BY =:= AuthBy, case Sudo orelse ?ACCT_HIERARCHY(AssignTo, AuthBy, 'true') orelse ?ACCT_HIERARCHY(AuthBy, AssignTo, 'false') of - 'false' -> knm_errors:unauthorized(); - 'true' -> + false -> + Reason = knm_errors:to_json(unauthorized), + knm_numbers:ko(Ns, Reason, T); + true -> Sudo andalso lager:info("bypassing auth"), - Number + knm_numbers:ok(Ns, T) end. --spec not_assigning_to_self(kn()) -> kn(). +-spec not_assigning_to_self(kn()) -> kn(); + (t()) -> t(). +not_assigning_to_self(T0=#{todo := Ns}) -> + F = fun (N, T) -> + case knm_number:attempt(fun not_assigning_to_self/1, [N]) of + {ok, NewN} -> knm_numbers:ok(NewN, T); + {error, R} -> knm_numbers:ko(N, R, T) + end + end, + lists:foldl(F, T0, Ns); not_assigning_to_self(Number) -> PhoneNumber = knm_number:phone_number(Number), AssignedTo = knm_phone_number:assigned_to(PhoneNumber), @@ -258,6 +263,14 @@ not_assigning_to_self(Number) -> end. -spec is_auth_by_authorized(kn()) -> kn(). +is_auth_by_authorized(T0=#{todo := Ns}) -> + F = fun (N, T) -> + case knm_number:attempt(fun is_auth_by_authorized/1, [N]) of + {ok, NewN} -> knm_numbers:ok(NewN, T); + {error, R} -> knm_numbers:ko(N, R, T) + end + end, + lists:foldl(F, T0, Ns); is_auth_by_authorized(Number) -> PhoneNumber = knm_number:phone_number(Number), AssignedTo = knm_phone_number:assigned_to(PhoneNumber), @@ -276,37 +289,50 @@ is_auth_by_authorized(Number) -> end. -spec update_reserve_history(kn()) -> kn(). +update_reserve_history(T0=#{todo := Ns}) -> + F = fun (N, T) -> + case knm_number:attempt(fun update_reserve_history/1, [N]) of + {ok, NewN} -> knm_numbers:ok(NewN, T); + {error, R} -> knm_numbers:ko(N, R, T) + end + end, + lists:foldl(F, T0, Ns); update_reserve_history(Number) -> PhoneNumber = knm_number:phone_number(Number), AssignTo = knm_phone_number:assign_to(PhoneNumber), PN = knm_phone_number:add_reserve_history(PhoneNumber, AssignTo), knm_number:set_phone_number(Number, PN). --spec move_to_port_in_state(kn()) -> kn(). -move_to_port_in_state(Number) -> - move_number_to_state(Number, ?NUMBER_STATE_PORT_IN). +-spec move_to_port_in_state(t()) -> t(). +move_to_port_in_state(T) -> + move_number_to_state(T, ?NUMBER_STATE_PORT_IN). --spec move_to_aging_state(kn()) -> kn(). -move_to_aging_state(Number) -> - move_number_to_state(Number, ?NUMBER_STATE_AGING). +-spec move_to_aging_state(t()) -> t(). +move_to_aging_state(T) -> + move_number_to_state(T, ?NUMBER_STATE_AGING). --spec move_to_available_state(kn()) -> kn(). -move_to_available_state(Number) -> - move_number_to_state(Number, ?NUMBER_STATE_AVAILABLE). +-spec move_to_available_state(t()) -> t(). +move_to_available_state(T) -> + move_number_to_state(T, ?NUMBER_STATE_AVAILABLE). --spec move_to_reserved_state(kn()) -> kn(). -move_to_reserved_state(Number) -> - move_number_to_state(Number, ?NUMBER_STATE_RESERVED). +-spec move_to_reserved_state(t()) -> t(). +move_to_reserved_state(T) -> + move_number_to_state(T, ?NUMBER_STATE_RESERVED). --spec move_to_in_service_state(kn()) -> kn(). -move_to_in_service_state(Number) -> - move_number_to_state(Number, ?NUMBER_STATE_IN_SERVICE). +-spec move_to_in_service_state(t()) -> t(). +move_to_in_service_state(T) -> + move_number_to_state(T, ?NUMBER_STATE_IN_SERVICE). --spec move_to_deleted_state(kn()) -> kn(). -move_to_deleted_state(Number) -> - move_number_to_state(Number, ?NUMBER_STATE_DELETED). +-spec move_to_deleted_state(kn()) -> kn(); + (t()) -> t(). +move_to_deleted_state(T) -> + move_number_to_state(T, ?NUMBER_STATE_DELETED). --spec move_number_to_state(kn(), ne_binary()) -> kn(). +-spec move_number_to_state(kn(), ne_binary()) -> kn(); + (t(), ne_binary()) -> t(). +move_number_to_state(T=#{todo := Ns}, ToState) -> + NewNs = [move_number_to_state(N, ToState) || N <- Ns], + knm_numbers:ok(NewNs, T); move_number_to_state(Number, ToState) -> PhoneNumber = knm_number:phone_number(Number), AssignedTo = knm_phone_number:assigned_to(PhoneNumber), @@ -336,18 +362,30 @@ move_phone_number_to_state(PhoneNumber, ToState, AssignedTo, AssignTo) -> ], knm_phone_number:setters(PhoneNumber, Setters). --type transition() :: fun((kn()) -> kn()). --type transitions() :: [transition()]. - --spec apply_transitions(kn(), transitions()) -> kn(). -apply_transitions(Number, Routines) -> - lists:foldl(fun(F, N) -> F(N) end, Number, Routines). - -spec is_authorized_operation(ne_binary(), ne_binary()) -> boolean(). is_authorized_operation(CheckFor, InAccount) -> kz_util:is_in_account_hierarchy(CheckFor, InAccount). --spec number_state(kn()) -> ne_binary(). -number_state(Number) -> - knm_phone_number:state( - knm_number:phone_number(Number)). + +%% @private +-spec invalid_state_transition(t(), api_ne_binary(), ne_binary()) -> t(). +invalid_state_transition(T=#{todo := Ns}, FromState, ToState) -> + {error,A,B,C} = (catch knm_errors:invalid_state_transition(undefined, FromState, ToState)), + {error, Reason} = knm_errors:to_json(A, B, C), + knm_numbers:ko(Ns, Reason, T). + +%% @private +is_assigned_to_assignto(N) -> + PN = knm_number:phone_number(N), + knm_phone_number:assign_to(PN) + =:= knm_phone_number:assigned_to(PN). + +%% @private +-spec group_by_state(t()) -> [{ne_binary(), knm_numbers:oks()}]. +group_by_state(#{todo := Ns}) -> + F = fun (N, M) -> + State = knm_phone_number:state(knm_number:phone_number(N)), + AccNs = maps:get(State, M, []), + M#{State => [N|AccNs]} + end, + maps:to_list(lists:foldl(F, #{}, Ns)). diff --git a/core/kazoo_number_manager/src/knm_numbers.erl b/core/kazoo_number_manager/src/knm_numbers.erl index 8716c422971..87396f3a3a4 100644 --- a/core/kazoo_number_manager/src/knm_numbers.erl +++ b/core/kazoo_number_manager/src/knm_numbers.erl @@ -1,7 +1,8 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz INC +%%% @copyright (C) 2015-2017, 2600Hz INC %%% @doc -%%% Bulk operations on numbers. Follows knm_number's API. +%%% Bulk operations on numbers. +%%% Note: functions should not `throw`, instead return `ret()`. %%% @end %%% @contributors %%% Peter Defebvre @@ -9,6 +10,19 @@ %%%------------------------------------------------------------------- -module(knm_numbers). +-export([todo/1 + ,options/1, options/2 + ,plan/1, plan/2 + ,services/1, services/2 + ,transactions/1, transactions/2, transaction/2 + ,charges/1, charges/2, charge/2, charge/3 + ]). +-export([ok/2, ko/3]). +-export([assigned_to/1 + ,prev_assigned_to/1 + ,to_json/1 + ]). + -export([get/1, get/2 ,create/2 ,move/2, move/3 @@ -18,7 +32,6 @@ ,reconcile/2 ,reserve/2 - ,to_state/2, to_state/3 ,assign_to_app/2, assign_to_app/3 ,free/1 @@ -27,149 +40,373 @@ ,account_listing/1 ]). +-export([pipe/2]). +-export([do/2]). +-export([merge_okkos/2, merge_okkos/1]). + -include("knm.hrl"). --type number_return() :: {ne_binary(), knm_number:knm_number_return()}. --type numbers_return() :: [number_return()]. +-type num() :: ne_binary(). %%TODO: support ranges? +-type nums() :: [num()]. +-type ok() :: knm_number:knm_number(). +-type oks() :: [ok()]. +-type ko() :: knm_errors:error() | atom(). +-type kos() :: #{num() => ko()}. +-type ret() :: #{ok => oks() + ,ko => kos() + ,services => services() + ,charges => charges() + ,options => options() + }. + +-export_type([ret/0 + ,ok/0, oks/0 + ,ko/0, kos/0 + ,num/0, nums/0 + ]). + +-type t() :: t(oks()). +-type t(OKs) :: t(OKs, OKs). +-type t(OKs, TODOs) :: #{todo => nums() | TODOs + ,ok => OKs + ,ko => kos() + + ,options => options() + ,plan => plan() + ,services => services() + ,transactions => transactions() + ,charges => charges() + }. + +-type t_pn() :: t(knm_phone_number:knm_phone_number()). + +-opaque collection() :: t(). +-export_type([collection/0]). + +-type options() :: knm_number_options:options(). +-type plan() :: kz_service_plans:plan() | undefined. +-type services() :: kz_services:services() | undefined. +-type transaction() :: kz_transaction:transaction(). +-type transactions() :: kz_transaction:transactions(). +-type charges() :: [{ne_binary(), non_neg_integer()}]. + +-export_type([options/0 + ,plan/0 + ,services/0 + ,transaction/0, transactions/0 + ,charges/0 + ]). + +-type applier() :: fun((t()) -> t()). +-type appliers() :: [applier()]. + +%% @private +-spec num(knm_number:knm_number()) -> num(). +num(N) -> + knm_phone_number:number(knm_number:phone_number(N)). %%-------------------------------------------------------------------- %% @public %% @doc +%% Either `nums()' xor `oks()'. %% @end %%-------------------------------------------------------------------- --spec get(ne_binaries()) -> - numbers_return(). --spec get(ne_binaries(), knm_number_options:options()) -> - numbers_return(). -get(Nums) -> - get(Nums, knm_number_options:default()). +-spec todo(t()) -> nums() | oks(). +todo(#{todo := ToDo}) -> ToDo. -get(Nums, Options) -> - [{Num, knm_number:get(Num, Options)} || Num <- Nums]. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Set of numbers' assigned_to fields. +%% @end +%%-------------------------------------------------------------------- +-spec assigned_to(t()) -> api_ne_binary(). +assigned_to(#{todo := Ns}) -> + F = fun (N, S) -> + case knm_phone_number:assigned_to(knm_number:phone_number(N)) of + undefined -> S; + ?MATCH_ACCOUNT_RAW(AccountId) -> sets:add_element(AccountId, S) + end + end, + case sets:to_list(lists:foldl(F, sets:new(), Ns)) of + [] -> undefined; + [AccountId] -> AccountId + end. %%-------------------------------------------------------------------- %% @public %% @doc +%% Set of numbers' prev_assigned_to fields. %% @end %%-------------------------------------------------------------------- --spec create(ne_binaries(), knm_number_options:options()) -> numbers_return(). +-spec prev_assigned_to(t()) -> api_ne_binary(). +prev_assigned_to(#{todo := Ns}) -> + F = fun (N, S) -> + case knm_phone_number:prev_assigned_to(knm_number:phone_number(N)) of + undefined -> S; + ?MATCH_ACCOUNT_RAW(AccountId) -> sets:add_element(AccountId, S) + end + end, + case sets:to_list(lists:foldl(F, sets:new(), Ns)) of + [] -> undefined; + [AccountId] -> AccountId + end. + +%% @public +-spec options(t()) -> options(). +-spec options(options(), t()) -> t(). +options(#{options := V}) -> V. +options(V, T) -> T#{options => V}. + +%% @public +-spec plan(t()) -> plan(). +-spec plan(plan(), t()) -> t(). +plan(#{plan := V}) -> V. +plan(V, T) -> T#{plan => V}. + +%% @public +-spec services(t()) -> services(). +-spec services(services(), t()) -> t(). +services(#{services := V}) -> V. +services(V, T) -> T#{services => V}. + +%% @public +-spec transactions(t()) -> transactions(). +-spec transactions(transactions(), t()) -> t(). +transactions(#{transactions := V}) -> V. +transactions(V, T) -> T#{transactions => V}. + +%% @public +-spec transaction(kz_transaction:transaction(), t()) -> t(). +transaction(V, T=#{transactions := Vs}) -> T#{transactions => [V | Vs]}. + +%% @public +-spec charges(t()) -> charges(). +-spec charges(charges(), t()) -> t(). +charges(#{charges := V}) -> V. +charges(V, T) -> T#{charges => V}. + +%% @public +-spec charge(ne_binary(), t()) -> non_neg_integer(). +-spec charge(ne_binary(), non_neg_integer(), t()) -> t(). +charge(K, #{charges := Vs}) -> props:get_value(K, Vs, 0). +charge(K, V, T=#{charges := Vs}) -> T#{charges => [{K, V} | Vs]}. + +%% @public +-spec ok(ok() | oks(), t()) -> t(). +ok(Numbers, T) when is_list(Numbers) -> + T#{ok => Numbers}; +ok(Number, T) -> T#{ok => [Number | maps:get(ok, T)]}. + +%% @public +-spec ko(num() | knm_number:knm_number() | nums(), ko(), t()) -> t(). +ko(?NE_BINARY=Num, Reason, T) -> + lager:debug("number ~s error: ~p", [Num, Reason]), + KOs = maps:get(ko, T), + T#{ko => KOs#{Num => Reason}}; +ko(Ns=[_|_], Reason, T0) -> + F = fun (N, T) -> ko(N, Reason, T) end, + lists:foldl(F, T0, Ns); +ko(N, Reason, T) -> + PN = knm_number:phone_number(N), + Num = knm_phone_number:number(PN), + lager:debug("number ~s state: ~s", [Num, knm_phone_number:state(PN)]), + ko(Num, Reason, T). + +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Attempts to get numbers from DB. +%% Note: each number in `Nums' has to be normalized. +%% @end +%%-------------------------------------------------------------------- +-spec get(ne_binaries()) -> ret(). +-spec get(ne_binaries(), knm_number_options:options()) -> ret(). +get(Nums) -> get(Nums, knm_number_options:default()). +get(Nums, Options) -> ret(do_get(Nums, Options)). + +-spec do_get(ne_binaries(), knm_number_options:options()) -> t(). +do_get(Nums, Options) -> + {Yes, No} = are_reconcilable(Nums), + pipe(new(Options, Yes, No) + ,[fun knm_phone_number:fetch/1 %% fetch/1 puts PNs in "ok"! + ,fun knm_number:new/1 + ]). + +-spec do_get_pn(ne_binaries(), knm_number_options:options()) -> t_pn(). +-spec do_get_pn(ne_binaries(), knm_number_options:options(), reason_t()) -> t_pn(). +do_get_pn(Nums, Options) -> + {Yes, No} = are_reconcilable(Nums), + do(fun knm_phone_number:fetch/1, new(Options, Yes, No)). +do_get_pn(Nums, Options, Error) -> + {Yes, No} = are_reconcilable(Nums), + do(fun knm_phone_number:fetch/1, new(Options, Yes, No, Error)). + +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% Attempts to create new numbers in DB or modify existing ones. +%% Note: `assign_to' number option MUST be set. +%% @end +%%-------------------------------------------------------------------- +-spec create(ne_binaries(), knm_number_options:options()) -> ret(). create(Nums, Options) -> - [{Num, knm_number:create(Num, Options)} || Num <- Nums]. + ?MATCH_ACCOUNT_RAW(AccountId) = knm_number_options:assign_to(Options), %%FIXME: can crash + T0 = do_get_pn(Nums, Options, knm_errors:to_json(not_reconcilable)), + case take_not_founds(T0) of + {#{ok := []}, []} -> T0; + {T1, NotFounds} -> + ToState = knm_number:state_for_create(AccountId, Options), + lager:debug("picked state ~s for ~s for ~p", [ToState, AccountId, Nums]), + NewOptions = [{'state', ToState} | Options], + ret(pipe(maybe_create(NotFounds, options(NewOptions, T1)) + ,[fun knm_number:new/1 + ,fun knm_number_states:to_options_state/1 + ,fun save_numbers/1 + ])) + end. %%-------------------------------------------------------------------- %% @public %% @doc %% @end %%-------------------------------------------------------------------- --spec move(ne_binaries(), ne_binary()) -> - numbers_return(). --spec move(ne_binaries(), ne_binary(), knm_number_options:options()) -> - numbers_return(). +-spec move(ne_binaries(), ne_binary()) -> ret(). +-spec move(ne_binaries(), ne_binary(), knm_number_options:options()) -> ret(). move(Nums, MoveTo) -> move(Nums, MoveTo, knm_number_options:default()). -move(Nums, MoveTo, Options) -> - [{Num, knm_number:move(Num, MoveTo, Options)} || Num <- Nums]. +move(Nums, ?MATCH_ACCOUNT_RAW(MoveTo), Options0) -> + Options = [{'assign_to', MoveTo} | Options0], + {TFound, NotFounds} = take_not_founds(do_get(Nums, Options)), + {TDiscovered, NotExisting} = take_not_founds(do(fun discover/1, new(Options, NotFounds))), + TNew = do_move_not_founds(NotExisting, Options), + T = merge_okkos([TFound, TDiscovered, TNew]), + ret(do(fun move_to/1, T)). %%-------------------------------------------------------------------- %% @public %% @doc +%% Attempts to update some phone_number fields. +%% Note: will always result in a phone_number save. %% @end %%-------------------------------------------------------------------- --spec update(ne_binaries(), knm_phone_number:set_functions()) -> - numbers_return(). --spec update(ne_binaries(), knm_phone_number:set_functions(), knm_number_options:options()) -> - numbers_return(). +-spec update(ne_binaries(), knm_phone_number:set_functions()) -> ret(). +-spec update(ne_binaries(), knm_phone_number:set_functions(), knm_number_options:options()) -> ret(). update(Nums, Routines) -> update(Nums, Routines, knm_number_options:default()). +-ifdef(TEST). +update([?NE_BINARY|_]=Nums, Routines, Options) -> + Reason = not_reconcilable, %% FIXME: unify to atom OR knm_error. + do_update(do_get_pn(Nums, Options, Reason), Routines); +update(Ns, Routines, Options) -> + T0 = new(Options, Ns), + T1 = do_in_wrap(fun (T) -> knm_phone_number:setters(T, Routines) end, T0), + ret(do(fun save_numbers/1, T1)). +-else. update(Nums, Routines, Options) -> - [{Num, knm_number:update(Num, Routines, Options)} || Num <- Nums]. + Reason = not_reconcilable, %% FIXME: unify to atom OR knm_error. + do_update(do_get_pn(Nums, Options, Reason), Routines). +-endif. + +do_update(T0, Routines) -> + ret(pipe(T0 + ,[fun (T) -> knm_phone_number:setters(T, Routines) end + ,fun knm_number:new/1 + ,fun save_numbers/1 + ])). %%-------------------------------------------------------------------- %% @public %% @doc %% @end %%-------------------------------------------------------------------- --spec release(ne_binaries()) -> - numbers_return(). --spec release(ne_binaries(), knm_number_options:options()) -> - numbers_return(). +-spec release(ne_binaries()) -> ret(). +-spec release(ne_binaries(), knm_number_options:options()) -> ret(). release(Nums) -> release(Nums, knm_number_options:default()). release(Nums, Options) -> - [{Num, knm_number:release(Num, Options)} || Num <- Nums]. + ret(pipe(do_get_pn(Nums, Options) + ,[fun knm_phone_number:release/1 + ,fun knm_number:new/1 + ,fun knm_providers:delete/1 + ,fun unwind_or_disconnect/1 + ,fun save_phone_numbers/1 + ])). %%-------------------------------------------------------------------- %% @public %% @doc +%% Remove numbers from the system without doing any state checking. +%% Sounds too harsh for you? You are looking for release/1,2. %% @end %%-------------------------------------------------------------------- --spec delete(ne_binaries(), knm_number_options:options()) -> - numbers_return(). +-spec delete(ne_binaries(), knm_number_options:options()) -> ret(). delete(Nums, Options) -> - [{Num, knm_number:delete(Num, Options)} || Num <- Nums]. + AuthBy = knm_number_options:auth_by(Options), + case ?KNM_DEFAULT_AUTH_BY =:= AuthBy + orelse kz_util:is_system_admin(AuthBy) + of + false -> + Error = knm_errors:to_json(unauthorized), + ret(new(Options, [], Nums, Error)); + true -> + T0 = do_get(Nums, Options), + F1 = fun knm_providers:delete/1, + F2 = fun knm_phone_number:delete/1, + ret(do_in_wrap(F2, do(F1, T0))) + end. %%-------------------------------------------------------------------- %% @public %% @doc +%% Note: option 'assign_to' needs to be set. %% @end %%-------------------------------------------------------------------- --spec reconcile(ne_binaries(), knm_number_options:options()) -> - numbers_return(). -reconcile(Nums, Options) -> - [{Num, knm_number:reconcile(Num, Options)} || Num <- Nums]. +-spec reconcile(ne_binaries(), knm_number_options:options()) -> ret(). +reconcile(Nums, Options0) -> + case knm_number_options:assign_to(Options0) =:= undefined of + true -> + Error = knm_errors:to_json(assign_failure, undefined, field_undefined), + ret(new(Options0, [], Nums, Error)); + false -> + Options = [{'auth_by', ?KNM_DEFAULT_AUTH_BY} | Options0], + {T0, NotFounds} = take_not_founds(do_get(Nums, Options)), + %% Ensures state to be IN_SERVICE + Ta = do_move_not_founds(NotFounds, Options), + Tb = do(fun (T) -> reconcile_number(T, Options) end, T0), + ret(merge_okkos(Ta, Tb)) + end. %%-------------------------------------------------------------------- %% @public %% @doc +%% Fetches then transitions existing numbers to the reserved state. %% @end %%-------------------------------------------------------------------- --spec reserve(ne_binaries(), knm_number_options:options()) -> - numbers_return(). +-spec reserve(ne_binaries(), knm_number_options:options()) -> ret(). reserve(Nums, Options) -> - [{Num, knm_number:reserve(Num, Options)} || Num <- Nums]. - -%%-------------------------------------------------------------------- -%% @public -%% @doc -%% @end -%%-------------------------------------------------------------------- --spec to_state(ne_binaries(), ne_binary()) -> - numbers_return(). --spec to_state(ne_binaries(), ne_binary(), knm_number_options:options()) -> - numbers_return(). -to_state(Nums, ToState) -> - to_state(Nums, ToState, knm_number_options:default()). - -to_state(Nums, ToState, Options) -> - [{Num, change_state(Num, ToState, Options)} || Num <- Nums]. - --spec change_state(ne_binary(), ne_binary(), knm_number_options:options()) -> - {'ok', knm_number:knm_number()} | - knm_errors:thrown_error(). -change_state(Num, ToState, Options) -> - try knm_number_states:to_state(Num, ToState, Options) of - Number -> {'ok', Number} - catch - 'throw':R -> R - end. + ret(do(fun to_reserved/1, do_get(Nums, Options))). %%-------------------------------------------------------------------- %% @public %% @doc %% @end %%-------------------------------------------------------------------- --spec assign_to_app(ne_binaries(), api_binary()) -> - numbers_return(). --spec assign_to_app(ne_binaries(), api_binary(), knm_number_options:options()) -> - numbers_return(). +-spec assign_to_app(ne_binaries(), api_ne_binary()) -> ret(). +-spec assign_to_app(ne_binaries(), api_ne_binary(), knm_number_options:options()) -> ret(). assign_to_app(Nums, App) -> assign_to_app(Nums, App, knm_number_options:default()). assign_to_app(Nums, App, Options) -> - [{Num, knm_number:assign_to_app(Num, App, Options)} || Num <- Nums]. + Setters = [{fun knm_phone_number:set_used_by/2, App}], + ret(pipe(do_get_pn(Nums, Options) + ,[fun (T) -> knm_phone_number:setters(T, Setters) end + ,fun knm_phone_number:save/1 + ,fun knm_number:new/1 + ])). %%-------------------------------------------------------------------- %% @public @@ -180,12 +417,12 @@ assign_to_app(Nums, App, Options) -> free(Account=?NE_BINARY) -> AccountDb = kz_util:format_account_db(Account), {Numbers, _NumbersData} = lists:unzip(account_listing(AccountDb)), - lists:foreach(fun ({Num, {'ok', _PhoneNumber}}) -> - lager:debug("successfully released ~s from ~s", [Num, Account]); - ({Num, {'error', _R}}) -> - lager:error("error when releasing ~s from ~s: ~p", [Num, Account, _R]) + #{ok := Ns, ko := KOs} = release(Numbers), + lager:debug("successfully released ~p from ~s", [[num(N) || N <- Ns], Account]), + lists:foreach(fun ({Num, R}) -> + lager:error("error when releasing ~s from ~s: ~p", [Num, Account, R]) end - ,release(Numbers) + ,maps:to_list(KOs) ). %%-------------------------------------------------------------------- @@ -210,7 +447,7 @@ emergency_enabled(AccountId=?MATCH_ACCOUNT_RAW(_)) -> %% @end %%-------------------------------------------------------------------- -spec account_listing(ne_binary()) -> [{ne_binary(), kz_json:object()}]. -account_listing(AccountDb = ?MATCH_ACCOUNT_ENCODED(_,_,_)) -> +account_listing(AccountDb=?MATCH_ACCOUNT_ENCODED(_,_,_)) -> case kz_datamgr:get_results(AccountDb, <<"phone_numbers/crossbar_listing">>) of {'ok', []} -> lager:debug("account ~s holds no numbers", [AccountDb]), @@ -222,3 +459,287 @@ account_listing(AccountDb = ?MATCH_ACCOUNT_ENCODED(_,_,_)) -> {'error', _R} -> lager:debug("error listing numbers for ~s: ~p", [AccountDb, _R]) end. + + +%%%=================================================================== +%%% Internal functions +%%%=================================================================== + +%% @private +-type reason_t() :: atom() | fun((num())-> knm_errors:error()). +-spec new(knm_number_options:options(), nums()) -> t(). +-spec new(knm_number_options:options(), nums(), nums()) -> t(). +-spec new(knm_number_options:options(), nums(), nums(), reason_t()) -> t(). +new(Options, ToDos) -> new(Options, ToDos, []). +new(Options, ToDos, KOs) -> new(Options, ToDos, KOs, not_reconcilable). +new(Options, ToDos, KOs, Reason) -> + #{todo => ToDos + ,ok => [] + ,ko => case is_function(Reason, 1) of %%FIXME: find something better than Reason/1. + false -> maps:from_list([{KO, Reason} || KO <- KOs]); + true -> maps:from_list([{KO, Reason(KO)} || KO <- KOs]) + end + + ,options => Options + ,plan => undefined + ,services => undefined + ,transactions => [] + ,charges => [] + }. + +%% @private +%% @doc +%% Apply something to "todo" if not empty, +%% if empty use "ok" as the new "todo". +%% If "ok" is empty, return. +%% Exported ONLY for knm_number_states use. +%% @end +-spec pipe(t(), appliers()) -> t(); + (t_pn(), appliers()) -> t_pn(). +pipe(T, []) -> T; +pipe(T=#{todo := [], ok := []}, _) -> T; +pipe(T=#{todo := [], ok := OK}, Fs) -> + NewT = T#{todo => OK, ok => []}, + pipe(NewT, Fs); +pipe(T, [F|Fs]) -> + case do(F, T) of + NewT=#{ok := []} -> NewT; + NewT -> pipe(NewT, Fs) + end. + +%% @private +%% @doc +%% Exported ONLY for knm_number_states use. +%% @end +-spec do(applier(), t()) -> t(). +do(_, T=#{todo := [], ok := []}) -> T; +do(F, T=#{todo := [], ok := OK}) -> + %% For calls not from pipe/2 + do(F, T#{todo => OK, ok => []}); +do(F, T) -> + lager:debug("applying ~p", [F]), + NewT = F(T), + NewT#{todo => []}. + +%% @private +-spec do_in_wrap(applier(), t()) -> t(). +do_in_wrap(_, T=#{todo := [], ok := []}) -> T; +do_in_wrap(F, T=#{todo := [], ok := OK}) -> + %% For calls not from pipe/2 + do_in_wrap(F, T#{todo => OK, ok => []}); +do_in_wrap(F, T0=#{todo := Ns}) -> + {NumsMap, PNs} = unwrap_phone_numbers(Ns), + T1 = do(F, T0#{todo => PNs}), + rewrap_phone_numbers(NumsMap, T1). + +%% @private +%% Exported ONLY for knm_number_states use. +-spec merge_okkos(t(), t()) -> t(). +merge_okkos(#{ok := OKa, ko := KOa} + ,#{ok := OKb, ko := KOb} = B) -> + B#{ok => OKa ++ OKb + ,ko => maps:merge(KOa, KOb) + }. + +%% @private +%% Exported ONLY for knm_number_states use. +-spec merge_okkos([t()]) -> t(). +merge_okkos([T]) -> T; +merge_okkos([T0|Ts]) -> + lists:foldl(fun merge_okkos/2, T0, Ts). + +%% @private +-spec id(t()) -> t(). +id(T=#{todo := Todo}) -> ok(Todo, T). + +%% @private +-spec ret(t()) -> ret(). +ret(#{ok := OKs + ,ko := KOs + ,services := Services + ,charges := Charges + ,options := Options + }) -> + #{ok => OKs + ,ko => KOs %%FIXME Convert to error format + ,services => Services + ,charges => Charges + ,options => Options + }. + +%% @public +-spec to_json(ret()) -> kz_json:object(). +to_json(#{ok := Ns, ko := KOs}) -> + Successes = [{num(N), knm_number:to_public_json(N)} || N <- Ns], + kz_json:from_list( + props:filter_empty( + [{<<"success">>, kz_json:from_list(Successes)} + ,{<<"error">>, kz_json:from_map(KOs)} + ])). + +%% @private +-spec unwrap_phone_numbers(knm_number:knm_numbers()) -> + {#{num() => knm_number:knm_number()} + ,knm_phone_number:knm_phone_numbers() + }. +unwrap_phone_numbers(Ns) -> + F = fun (N, {M, PNs}) -> + PN = knm_number:phone_number(N), + Num = knm_phone_number:number(PN), + {M#{Num => N}, [PN|PNs]} + end, + lists:foldl(F, {#{}, []}, Ns). + +%% @private +-spec rewrap_phone_numbers(#{num() => knm_number:knm_number()}, t()) -> t(). +rewrap_phone_numbers(NumsMap, T=#{ok := PNs}) -> + F = fun (PN, Ns) -> + N = maps:get(knm_phone_number:number(PN), NumsMap), + [knm_number:set_phone_number(N, PN) | Ns] + end, + T#{ok => lists:foldl(F, [], PNs)}. + + +are_reconcilable(Nums) -> + knm_converters:are_reconcilable(lists:usort(Nums)). + +take_not_founds(T=#{ko := KOs}) -> + F = fun ({_Num, Reason}) -> not_found =:= Reason end, + {NumsNotFound, NewKOs} = lists:partition(F, maps:to_list(KOs)), + Nums = [Num || {Num,not_found} <- NumsNotFound], + {T#{ko := maps:from_list(NewKOs)}, Nums}. + +-spec maybe_create(ne_binaries(), t_pn()) -> t_pn(). +maybe_create(NotFounds, T) -> + Ta = do(fun knm_number:ensure_can_create/1, new(options(T), NotFounds)), + Tb = pipe(T, [fun knm_number:ensure_can_load_to_create/1 + ,fun update_for_create/1 + ]), + merge_okkos(Ta, Tb). + +-spec update_for_create(t_pn()) -> t_pn(). +update_for_create(T=#{todo := _PNs, options := Options}) -> + Updates = knm_number_options:to_phone_number_setters( + props:delete('state', Options) + ), + knm_phone_number:setters(T, Updates). + +-spec update_for_reconcile(t_pn(), knm_number_options:options()) -> t_pn(). +update_for_reconcile(T, Options) -> + S = [{fun knm_phone_number:set_assigned_to/2, knm_number_options:assign_to(Options)} + ,{fun knm_phone_number:set_auth_by/2, knm_number_options:auth_by(Options)} + ,{fun knm_phone_number:update_doc/2, knm_number_options:public_fields(Options)} + ,{fun knm_phone_number:set_state/2, ?NUMBER_STATE_IN_SERVICE} + | case props:is_defined(module_name, Options) of + false -> []; + true -> + [{fun knm_phone_number:set_module_name/2, knm_number_options:module_name(Options)}] + end + ], + knm_phone_number:setters(T, S). + +save_phone_numbers(T) -> + do_in_wrap(fun knm_phone_number:save/1, T). + +save_numbers(T) -> + pipe(T, [fun knm_providers:save/1 + ,fun save_phone_numbers/1 + ,fun knm_services:update_services/1 + ]). + +reconcile_number(T0, Options) -> + F1 = fun (T) -> update_for_reconcile(T, Options) end, + %%FIXME: create a pipe_in_wrap that does not create the superfluous Numbers. + pipe(do_in_wrap(F1, T0), [fun save_phone_numbers/1]). + +do_move_not_founds(Nums, Options) -> + pipe(new(Options, Nums) + ,[fun knm_phone_number:new/1 + ,fun knm_number:new/1 + ]). + +discover(T0=#{todo := Nums, options := Options}) -> + F = fun (Num, T) -> + case knm_search:discovery(Num, Options) of + {ok, N} -> ok(N, T); + {error, R} -> ko(Num, R, T) + end + end, + lists:foldl(F, T0, Nums). + +move_to(T) -> + NewOptions = [{state, ?NUMBER_STATE_IN_SERVICE} | options(T)], + pipe(options(NewOptions, T) + ,[fun knm_number_states:to_options_state/1 + ,fun save_numbers/1 + ]). + +to_reserved(T) -> + NewOptions = [{state, ?NUMBER_STATE_RESERVED} | options(T)], + pipe(options(NewOptions, T) + ,[fun knm_number_states:to_options_state/1 + ,fun save_numbers/1 + ]). + +unwind_or_disconnect(T) -> + #{ok := Ns} = T0 = do_in_wrap(fun knm_phone_number:unwind_reserve_history/1, T), + {ToDisconnect, ToUnwind} = lists:partition(fun is_history_empty/1, Ns), + Ta = do_in_wrap(fun unwind/1, ok(ToUnwind, T0)), + Tb = pipe(ok(ToDisconnect, T0) + ,[fun knm_carriers:disconnect/1 + ,fun delete_maybe_age/1 + ]), + merge_okkos(Ta, Tb). + +unwind(T0=#{todo := PNs}) -> + BaseRoutines = [{fun knm_phone_number:set_state/2, ?NUMBER_STATE_RESERVED}], + F = fun (PN, T) -> + [NewAssignedTo|_] = knm_phone_number:reserve_history(PN), + Routines = [{fun knm_phone_number:set_assigned_to/2, NewAssignedTo} | BaseRoutines], + {ok, NewPN} = knm_phone_number:setters(PN, Routines), + ok(NewPN, T) + end, + lists:foldl(F, T0, PNs). + +delete_maybe_age(T=#{todo := _Ns, options := Options}) -> + case knm_config:should_permanently_delete( + knm_number_options:should_delete(Options)) + of + true -> delete_permanently(T); + false -> + {DeleteNs, OtherNs} = split_on(fun is_carrier_local_or_mdn/1, T), + merge_okkos(delete_permanently(DeleteNs), maybe_age(OtherNs)) + end. + +delete_permanently(T=#{options := Options}) -> + lager:debug("deleting permanently"), + NewOptions = [{state, ?NUMBER_STATE_DELETED} | Options], + do(fun knm_number_states:to_options_state/1, options(NewOptions, T)). + +split_on(Pred, T=#{todo := Ns}) -> + {Yes, No} = lists:partition(Pred, Ns), + {T#{todo => Yes}, T#{todo => No}}. + +is_carrier_local_or_mdn(N) -> + Carrier = knm_phone_number:module_name(knm_number:phone_number(N)), + ?CARRIER_LOCAL =:= Carrier + orelse ?CARRIER_MDN =:= Carrier. + +maybe_age(T=#{todo := Ns}) -> + case knm_config:should_age() of + false -> ok(Ns, T); + true -> + lager:debug("aging for some time"), + {Yes, No} = lists:partition(fun is_state_available/1, Ns), + Ta = do(fun id/1, T#{todo => No}), + NewOptions = [{state, ?NUMBER_STATE_AGING} | options(T)], + Tb = do(fun knm_number_states:to_options_state/1 + ,options(NewOptions, T#{todo => Yes})), + merge_okkos(Ta, Tb) + end. + +is_history_empty(N) -> + [] =:= knm_phone_number:reserve_history(knm_number:phone_number(N)). + +is_state_available(N) -> + ?NUMBER_STATE_AVAILABLE =:= knm_phone_number:state(knm_number:phone_number(N)). diff --git a/core/kazoo_number_manager/src/knm_phone_number.erl b/core/kazoo_number_manager/src/knm_phone_number.erl index b606b495e74..99ba75a3c43 100644 --- a/core/kazoo_number_manager/src/knm_phone_number.erl +++ b/core/kazoo_number_manager/src/knm_phone_number.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz INC +%%% @copyright (C) 2015-2017, 2600Hz INC %%% @doc %%% %%% @end @@ -29,8 +29,9 @@ ,assigned_to/1, set_assigned_to/2 ,prev_assigned_to/1, set_prev_assigned_to/2 ,used_by/1, set_used_by/2 - ,features/1, features_available/1, features_list/1, set_features/2 + ,features/1, features_list/1, set_features/2 ,feature/2, set_feature/3 + ,features_allowed/1, features_denied/1 ,state/1, set_state/2 ,reserve_history/1, add_reserve_history/2, unwind_reserve_history/1 ,ported_in/1, set_ported_in/2 @@ -44,7 +45,6 @@ ,doc/1, update_doc/2, reset_doc/2 ,modified/1, set_modified/2 ,created/1, set_created/2 - ,is_billable/1 ]). -export([list_attachments/2]). @@ -56,6 +56,9 @@ -include("knm.hrl"). -include_lib("kazoo_json/include/kazoo_json.hrl"). +-define(DEFAULT_FEATURES_ALLOWED, []). +-define(DEFAULT_FEATURES_DENIED, []). + -record(knm_phone_number, {number :: ne_binary() ,number_db :: ne_binary() ,assign_to :: api_ne_binary() @@ -76,8 +79,9 @@ ,doc = kz_json:new() :: kz_json:object() ,modified :: gregorian_seconds() ,created :: gregorian_seconds() - ,is_billable = 'false' :: boolean() ,is_dirty = 'false' :: boolean() + ,features_allowed = ?DEFAULT_FEATURES_ALLOWED :: ne_binaries() + ,features_denied = ?DEFAULT_FEATURES_DENIED :: ne_binaries() }). -opaque knm_phone_number() :: #knm_phone_number{}. @@ -100,21 +104,32 @@ %% @doc %% @end %%-------------------------------------------------------------------- --spec new(ne_binary()) -> knm_phone_number(). +-spec new(ne_binary()) -> knm_phone_number(); + (knm_numbers:collection()) -> knm_numbers:collection(). +new(T=#{todo := Nums, options := Options}) -> + Setters = new_setters(Options), + PNs = [do_new(DID, Setters) || DID <- Nums], + knm_numbers:ok(PNs, T); new(DID) -> new(DID, knm_number_options:default()). -spec new(ne_binary(), knm_number_options:options()) -> knm_phone_number(). -new(DID, Options0) -> - Options = case knm_number_options:state(Options0) of - ?NUMBER_STATE_PORT_IN -> [{'module_name', ?PORTING_MODULE_NAME} | Options0]; - _ -> Options0 - end, - {'ok', PhoneNumber} = - setters(new(), - [{fun set_number/2, knm_converters:normalize(DID)} - | knm_number_options:to_phone_number_setters(Options) - ]), +new(DID, Options) -> + do_new(DID, new_setters(Options)). + +-spec new_setters(knm_number_options:options()) -> set_functions(). +new_setters(Options) -> + knm_number_options:to_phone_number_setters( + case knm_number_options:state(Options) of + ?NUMBER_STATE_PORT_IN -> [{'module_name', ?PORTING_MODULE_NAME} | Options]; + _ -> Options + end + ). + +-spec do_new(ne_binary(), set_functions()) -> knm_phone_number(). +do_new(DID, Setters0) -> + Setters = [{fun set_number/2, knm_converters:normalize(DID)} | Setters0], + {ok, PhoneNumber} = setters(new(), Setters), PhoneNumber. %%-------------------------------------------------------------------- @@ -122,29 +137,57 @@ new(DID, Options0) -> %% @doc %% @end %%-------------------------------------------------------------------- --spec fetch(ne_binary()) -> knm_phone_number_return(). +-spec fetch(ne_binary()) -> knm_phone_number_return(); + (knm_numbers:collection()) -> knm_numbers:collection(). -spec fetch(ne_binary(), knm_number_options:options()) -> knm_phone_number_return(). -fetch(Num) -> - fetch(Num, knm_number_options:default()). +fetch(?NE_BINARY=Num) -> + fetch(Num, knm_number_options:default()); +fetch(T) -> + Options = knm_numbers:options(T), + Fetch = fun (Num, Acc) -> + case knm_number:attempt(fun fetch/2, [Num, Options]) of + {ok, PN} -> knm_numbers:ok(PN, Acc); + {error, R} -> knm_numbers:ko(Num, R, Acc) + end + end, + lists:foldl(Fetch, T, knm_numbers:todo(T)). -ifdef(TEST). fetch(?TEST_CREATE_NUM, _Options) -> {'error', 'not_found'}; fetch(?TEST_AVAILABLE_NUM, Options) -> handle_fetched_result(?AVAILABLE_NUMBER, Options); +fetch(?TEST_IN_SERVICE_BAD_CARRIER_NUM, Options) -> + handle_fetched_result(?IN_SERVICE_BAD_CARRIER_NUMBER, Options); fetch(?TEST_IN_SERVICE_NUM, Options) -> handle_fetched_result(?IN_SERVICE_NUMBER, Options); +fetch(?TEST_IN_SERVICE_MDN, Options) -> + handle_fetched_result(?IN_SERVICE_MDN, Options); fetch(?TEST_IN_SERVICE_WITH_HISTORY_NUM, Options) -> handle_fetched_result(?IN_SERVICE_WITH_HISTORY_NUMBER, Options); fetch(?BW_EXISTING_DID, Options) -> handle_fetched_result(?BW_EXISTING_JSON, Options); +fetch(?TEST_TELNYX_NUM, Options) -> + handle_fetched_result(?TELNY_NUMBER, Options); fetch(?TEST_OLD_NUM, Options) -> JObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_1_in.json"))), handle_fetched_result(JObj, Options); fetch(?TEST_OLD2_NUM, Options) -> JObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_2_in.json"))), handle_fetched_result(JObj, Options); +fetch(?TEST_OLD3_NUM, Options) -> + JObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_3_in.json"))), + handle_fetched_result(JObj, Options); +fetch(?TEST_OLD4_NUM, Options) -> + JObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_4_in.json"))), + handle_fetched_result(JObj, Options); +fetch(?TEST_OLD5_NUM, Options) -> + JObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_5_in.json"))), + handle_fetched_result(JObj, Options); +fetch(?TEST_OLD6_NUM, Options) -> + JObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_6_in.json"))), + handle_fetched_result(JObj, Options); fetch(_DID, _Options) -> {'error', 'not_found'}. -else. @@ -179,12 +222,24 @@ handle_fetched_result(JObj, Options) -> %% @doc %% @end %%-------------------------------------------------------------------- --spec save(knm_phone_number()) -> knm_phone_number(). -save(#knm_phone_number{dry_run='true'}=PhoneNumber) -> - lager:debug("dry_run-ing btw"), - PhoneNumber; +-spec save(knm_phone_number()) -> knm_phone_number(); + (knm_numbers:collection()) -> knm_numbers:collection(). +save(T0=#{todo := PNs, options := Options}) -> + case knm_number_options:dry_run(Options) of + true -> + lager:debug("dry_run-ing btw"), + knm_numbers:ok(PNs, T0); + false -> + F = fun (PN, T) -> + case knm_number:attempt(fun save/1, [PN]) of + {error, R} -> knm_numbers:ko(number(PN), R, T); + NewPN -> knm_numbers:ok(NewPN, T) + end + end, + lists:foldl(F, T0, PNs) + end; save(#knm_phone_number{is_dirty = false}=PhoneNumber) -> - lager:debug("not dirty: skipping save"), + lager:debug("not dirty: skip saving ~s", [number(PhoneNumber)]), PhoneNumber; save(PhoneNumber) -> Routines = [fun save_to_number_db/1 @@ -196,13 +251,25 @@ save(PhoneNumber) -> %%-------------------------------------------------------------------- %% @public %% @doc -%% To call only from knm_number:delete/2 (only for sysadmins). +%% To call only from knm_numbers:delete/2 (only for sysadmins). %% @end %%-------------------------------------------------------------------- --spec delete(knm_phone_number()) -> knm_phone_number(). -delete(#knm_phone_number{dry_run='true'}=PhoneNumber) -> - lager:debug("dry_run-ing btw"), - PhoneNumber; +-spec delete(knm_phone_number()) -> knm_phone_number(); + (knm_numbers:collection()) -> knm_numbers:collection(). +delete(T0=#{todo := PNs, options := Options}) -> + case knm_number_options:dry_run(Options) of + true -> + lager:debug("dry_run-ing btw"), + knm_numbers:ok(PNs, T0); + false -> + F = fun (PN, T) -> + case knm_number:attempt(fun delete/1, [PN]) of + {error, R} -> knm_numbers:ko(number(PN), R, T); + NewPN -> knm_numbers:ok(NewPN, T) + end + end, + lists:foldl(F, T0, PNs) + end; delete(PhoneNumber) -> Routines = [fun try_delete_number_doc/1 ,fun try_maybe_remove_number_from_account/1 @@ -227,8 +294,17 @@ try_maybe_remove_number_from_account(PN) -> {'ok', PN} end. --spec release(knm_phone_number()) -> knm_phone_number(). +-spec release(knm_phone_number()) -> knm_phone_number(); + (knm_numbers:collection()) -> knm_numbers:collection(). -spec release(knm_phone_number(), ne_binary()) -> knm_phone_number(). +release(T0=#{todo := PNs}) -> + F = fun (PN, T) -> + case knm_number:attempt(fun release/1, [PN]) of + {error, Reason} -> knm_numbers:ko(number(PN), Reason, T); + NewPN -> knm_numbers:ok(NewPN, T) + end + end, + lists:foldl(F, T0, PNs); release(PhoneNumber) -> release(PhoneNumber, state(PhoneNumber)). @@ -276,7 +352,7 @@ authorized_release(PhoneNumber) -> Routines = [{fun set_features/2, kz_json:new()} ,{fun set_doc/2, kz_json:private_fields(doc(PhoneNumber))} ,{fun set_prev_assigned_to/2, assigned_to(PhoneNumber)} - ,{fun set_assigned_to/2, 'undefined'} + ,{fun set_assigned_to/2, undefined} ,{fun set_state/2, ReleasedState} ], {'ok', NewPhoneNumber} = setters(PhoneNumber, Routines), @@ -284,7 +360,9 @@ authorized_release(PhoneNumber) -> %%-------------------------------------------------------------------- %% @public -%% @doc Returns same fields view phone_numbers.json returns. +%% @doc +%% Returns same fields view phone_numbers.json returns. +%% @end %%-------------------------------------------------------------------- -spec to_public_json(knm_phone_number()) -> kz_json:object(). to_public_json(Number) -> @@ -300,7 +378,9 @@ to_public_json(Number) -> ,State ,UsedBy ,Features - ,{<<"features_available">>, features_available(Number)} + ,{<<"features_available">>, knm_providers:available_features(Number)} + ,{<<"features_allowed">>, features_allowed(Number)} + ,{<<"features_denied">>, features_denied(Number)} ]) ), Values = props:filter_empty( @@ -326,7 +406,6 @@ to_json(#knm_phone_number{doc=JObj}=N) -> ,{?PVT_MODULE_NAME, module_name(N)} ,{?PVT_MODIFIED, modified(N)} ,{?PVT_CREATED, created(N)} - ,{?PVT_IS_BILLABLE, is_billable(N)} ,{?PVT_TYPE, <<"number">>} | kz_json:to_proplist(sanitize_public_fields(JObj)) ] @@ -337,7 +416,8 @@ to_json(#knm_phone_number{doc=JObj}=N) -> ,{?PVT_PREVIOUSLY_ASSIGNED_TO, prev_assigned_to(N)} ,{?PVT_USED_BY, used_by(N)} ,{?PVT_FEATURES, features(N)} - ,{?PVT_FEATURES_AVAILABLE, features_available(N)} + ,{?PVT_FEATURES_ALLOWED, features_allowed(N)} + ,{?PVT_FEATURES_DENIED, features_denied(N)} ,{?PVT_RESERVE_HISTORY, reserve_history(N)} ,{?PVT_CARRIER_DATA, carrier_data(N)} ,{?PVT_REGION, region(N)} @@ -350,37 +430,66 @@ to_json(#knm_phone_number{doc=JObj}=N) -> %% @end %%-------------------------------------------------------------------- -spec from_json(kz_json:object()) -> knm_phone_number(). -from_json(JObj) -> +from_json(JObj0) -> + JObj = maybe_update_rw_features(JObj0), Features = - case kz_json:get_value(?PVT_FEATURES, JObj) of + case kz_json:get_ne_value(?PVT_FEATURES, JObj) of 'undefined' -> kz_json:new(); - FeaturesList when is_list(FeaturesList) -> - lists:foldl(fun (F, A) -> features_fold(F, A, JObj) end, kz_json:new(), FeaturesList); + FeaturesList when is_list(FeaturesList) -> migrate_features(FeaturesList, JObj); FeaturesJObj -> FeaturesJObj end, Now = kz_util:current_tstamp(), - IsBillable = kz_json:is_true(?PVT_IS_BILLABLE, JObj, 'undefined'), UsedBy = kz_json:get_value(?PVT_USED_BY, JObj), {'ok', PhoneNumber} = setters(new(), [{fun set_number/2, knm_converters:normalize(kz_doc:id(JObj))} ,{fun set_assigned_to/3, kz_json:get_value(?PVT_ASSIGNED_TO, JObj), UsedBy} ,{fun set_prev_assigned_to/2, kz_json:get_value(?PVT_PREVIOUSLY_ASSIGNED_TO, JObj)} - ,{fun set_features/2, Features} + ,{fun set_features/2, maybe_rename_features(Features)} ,{fun set_state/2, kz_json:get_first_defined([?PVT_STATE, ?PVT_STATE_LEGACY], JObj)} ,{fun set_reserve_history/2, kz_json:get_value(?PVT_RESERVE_HISTORY, JObj, [])} ,{fun set_ported_in/2, kz_json:is_true(?PVT_PORTED_IN, JObj, 'false')} - ,{fun set_module_name/3, kz_json:get_value(?PVT_MODULE_NAME, JObj), IsBillable} + ,{fun set_module_name/2, kz_json:get_value(?PVT_MODULE_NAME, JObj)} ,{fun set_carrier_data/2, kz_json:get_value(?PVT_CARRIER_DATA, JObj)} ,{fun set_region/2, kz_json:get_value(?PVT_REGION, JObj)} ,{fun set_auth_by/2, kz_json:get_value(?PVT_AUTH_BY, JObj)} ,{fun set_doc/2, sanitize_public_fields(JObj)} ,{fun set_modified/2, kz_doc:modified(JObj, Now)} ,{fun set_created/2, kz_doc:created(JObj, Now)} + ,{fun set_features_allowed/2, kz_json:get_list_value(?PVT_FEATURES_ALLOWED, JObj, ?DEFAULT_FEATURES_ALLOWED)} + ,{fun set_features_denied/2, kz_json:get_list_value(?PVT_FEATURES_DENIED, JObj, ?DEFAULT_FEATURES_DENIED)} ]), PhoneNumber. +%% Handle moving away from provider-specific E911 +maybe_rename_features(Features) -> + Fs = kz_json:delete_keys([?LEGACY_DASH_E911, ?LEGACY_VITELITY_E911], Features), + case {kz_json:get_ne_value(?LEGACY_DASH_E911, Features) + ,kz_json:get_ne_value(?LEGACY_VITELITY_E911, Features) + } + of + {undefined, undefined} -> Features; + {Dash, undefined} -> kz_json:set_value(?FEATURE_E911, Dash, Fs); + {undefined, Vitelity} -> kz_json:set_value(?FEATURE_E911, Vitelity, Fs); + {_Dash, Vitelity} -> kz_json:set_value(?FEATURE_E911, Vitelity, Fs) + end. + +maybe_update_rw_features(JObj) -> + case {kz_json:get_ne_value(?LEGACY_DASH_E911, JObj) + ,kz_json:get_ne_value(?LEGACY_VITELITY_E911, JObj) + } + of + {undefined, undefined} -> JObj; + {Dash, undefined} -> kz_json:set_value(?FEATURE_E911, Dash, JObj); + {undefined, Vitelity} -> kz_json:set_value(?FEATURE_E911, Vitelity, JObj); + {_Dash, Vitelity} -> kz_json:set_value(?FEATURE_E911, Vitelity, JObj) + end. + %% Handle 3.22 -> 4.0 features migration. +migrate_features(FeaturesList, JObj) -> + F = fun (Feature, A) -> features_fold(Feature, A, JObj) end, + lists:foldl(F, kz_json:new(), FeaturesList). + %% Note: if a feature matches here that means it was enabled in 3.22. features_fold(?FEATURE_FORCE_OUTBOUND, Acc, JObj) -> Data = kz_json:is_true(?FEATURE_FORCE_OUTBOUND, JObj), @@ -394,7 +503,7 @@ features_fold(?FEATURE_RINGBACK, Acc, JObj) -> kz_json:set_value(?FEATURE_RINGBACK, Data, Acc); features_fold(?FEATURE_PREPEND, Acc, JObj) -> Name = kz_json:get_ne_value([?FEATURE_PREPEND, <<"name">>], JObj), - Data = kz_json:from_list([{<<"enabled">>, true} + Data = kz_json:from_list([{<<"enabled">>, kz_json:is_true([?FEATURE_PREPEND, <<"enabled">>], JObj)} ,{<<"name">>, Name} ]), kz_json:set_value(?FEATURE_PREPEND, Data, Acc); @@ -405,16 +514,20 @@ features_fold(?FEATURE_CNAM_OUTBOUND, Acc, JObj) -> features_fold(?CNAM_INBOUND_LOOKUP, Acc, _) -> Data = kz_json:from_list([{?CNAM_INBOUND_LOOKUP, true}]), kz_json:set_value(?FEATURE_CNAM_INBOUND, Data, Acc); -features_fold(<<"dash_e911">>=Feature, Acc, JObj) -> +features_fold(?LEGACY_DASH_E911=Feature, Acc, JObj) -> + Data = kz_json:get_value(Feature, JObj), + kz_json:set_value(?FEATURE_E911, Data, Acc); +features_fold(?LEGACY_VITELITY_E911=Feature, Acc, JObj) -> Data = kz_json:get_value(Feature, JObj), kz_json:set_value(?FEATURE_E911, Data, Acc); -features_fold(<<"vitelity_e911">>=Feature, Acc, JObj) -> +features_fold(?LEGACY_TELNYX_E911=Feature, Acc, JObj) -> Data = kz_json:get_value(Feature, JObj), kz_json:set_value(?FEATURE_E911, Data, Acc); features_fold(FeatureKey, Acc, JObj) -> %% Encompasses at least: %% ?FEATURE_PORT & ?FEATURE_FAILOVER Data = kz_json:get_ne_value(FeatureKey, JObj, kz_json:new()), + lager:debug("emcompassed ~s", [FeatureKey, kz_json:encode(Data)]), kz_json:set_value(FeatureKey, Data, Acc). %%-------------------------------------------------------------------- @@ -447,8 +560,7 @@ from_json_with_options(JObj, PhoneNumber) -> %% @end %%-------------------------------------------------------------------- -spec new() -> knm_phone_number(). -new() -> - #knm_phone_number{}. +new() -> #knm_phone_number{}. -spec is_phone_number(any()) -> boolean(). is_phone_number(#knm_phone_number{}) -> 'true'; @@ -459,20 +571,36 @@ is_phone_number(_) -> 'false'. %% @doc %% @end %%-------------------------------------------------------------------- --spec setters(knm_phone_number(), set_functions()) -> knm_phone_number_return(). -setters(Number, Routines) -> - try lists:foldl(fun setters_fold/2, Number, Routines) of +-spec setters(knm_phone_number(), set_functions()) -> knm_phone_number_return(); + (knm_numbers:collection(), set_functions()) -> knm_numbers:collection(). +setters(T0=#{todo := PNs}, Routines) -> + F = fun (PN, T) -> + case setters(PN, Routines) of + {ok, NewPN} -> knm_numbers:ok(NewPN, T); + {error, R} -> knm_numbers:ko(number(PN), R, T) + end + end, + lists:foldl(F, T0, PNs); +setters(PN, Routines) -> + try lists:foldl(fun setters_fold/2, PN, Routines) of {'ok', _N}=Ok -> Ok; {'error', _R}=Error -> Error; Result -> {'ok', Result} catch 'throw':{'stop', Error} -> Error; 'error':'function_clause' -> - {_M, FName, [_PhoneNumber,Arg|_], _Info} = hd(erlang:get_stacktrace()), + ST = erlang:get_stacktrace(), + {FName, Arg} = + case ST of + [{lists, foldl, [Name|_PhoneNumber], Arg2}|_] -> {Name, Arg2}; + [{_M, Name, [_PhoneNumber,Arg2|_], _Info}|_] -> {Name, Arg2} + end, lager:error("~s failed, argument: ~p", [FName, Arg]), - kz_util:log_stacktrace(), + kz_util:log_stacktrace(ST), {'error', FName}; - 'error':Reason -> {'error', Reason} + 'error':Reason -> + kz_util:log_stacktrace(), + {'error', Reason} end. -type set_function() :: fun((knm_phone_number()) -> setter_acc()) | @@ -617,6 +745,7 @@ set_used_by(N, UsedBy='undefined') -> ,used_by = UsedBy }; set_used_by(N, UsedBy=?NE_BINARY) -> + lager:debug("assigning ~s to ~s", [number(N), UsedBy]), N#knm_phone_number{is_dirty = true ,used_by = UsedBy }. @@ -633,10 +762,6 @@ features(#knm_phone_number{features=Features}) -> Features. features_list(N) -> sets:to_list(sets:from_list(kz_json:get_keys(features(N)))). --spec features_available(knm_phone_number()) -> ne_binaries(). -features_available(N) -> - knm_providers:allowed_features(N). - -spec set_features(knm_phone_number(), kz_json:object()) -> knm_phone_number(). set_features(N, Features) -> 'true' = kz_json:is_json_object(Features), @@ -654,9 +779,53 @@ feature(Number, Feature) -> -spec set_feature(knm_phone_number(), ne_binary(), kz_json:json_term()) -> knm_phone_number(). -set_feature(N, Feature=?NE_BINARY, Data) -> - Features = kz_json:set_value(Feature, Data, features(N)), - set_features(N, Features). %% Sets is_dirty. +set_feature(N0, Feature=?NE_BINARY, Data) -> + Features = kz_json:set_value(Feature, Data, features(N0)), + N = set_features(N0, Features), + N#knm_phone_number.is_dirty + andalso lager:debug("setting ~s feature ~s: ~s", [number(N), Feature, kz_json:encode(Data)]), + N. + + +-spec set_features_allowed(knm_phone_number(), ne_binaries()) -> knm_phone_number(). +set_features_allowed(N, Features) -> + true = lists:all(fun kz_util:is_ne_binary/1, Features), + case lists:usort(N#knm_phone_number.features_allowed) =:= lists:usort(Features) of + true -> N; + false -> + N#knm_phone_number{is_dirty = true + ,features_allowed = Features + } + end. + +-spec set_features_denied(knm_phone_number(), ne_binaries()) -> knm_phone_number(). +set_features_denied(N, Features) -> + true = lists:all(fun kz_util:is_ne_binary/1, Features), + case lists:usort(N#knm_phone_number.features_denied) =:= lists:usort(Features) of + true -> N; + false -> + N#knm_phone_number{is_dirty = true + ,features_denied = Features + } + end. + +-spec features_allowed(knm_phone_number()) -> ne_binaries(). +-ifdef(TEST). +features_allowed(#knm_phone_number{number = ?TEST_TELNYX_NUM}) -> + [<<"cnam">>, <<"e911">>, <<"failover">>, <<"force_outbound">>, <<"prepend">>, <<"ringback">>]; +features_allowed(#knm_phone_number{features_allowed = Features}) -> Features. +-else. +features_allowed(#knm_phone_number{features_allowed = Features}) -> Features. +-endif. + +-spec features_denied(knm_phone_number()) -> ne_binaries(). +-ifdef(TEST). +features_denied(#knm_phone_number{number = ?TEST_TELNYX_NUM}) -> + [<<"port">>, <<"failover">>]; +features_denied(#knm_phone_number{features_denied = Features}) -> Features. +-else. +features_denied(#knm_phone_number{features_denied = Features}) -> Features. +-endif. %%-------------------------------------------------------------------- %% @public @@ -697,7 +866,8 @@ set_reserve_history(N, History) when is_list(History) -> Cons = fun (A, PN) -> add_reserve_history(PN, A) end, lists:foldr(Cons, N#knm_phone_number{reserve_history=[]}, History). --spec add_reserve_history(knm_phone_number(), ne_binary()) -> knm_phone_number(). +-spec add_reserve_history(knm_phone_number(), api_ne_binary()) -> knm_phone_number(). +add_reserve_history(N, undefined) -> N; add_reserve_history(#knm_phone_number{reserve_history=[AccountId|_]}=N ,?MATCH_ACCOUNT_RAW(AccountId) ) -> @@ -709,7 +879,11 @@ add_reserve_history(#knm_phone_number{reserve_history=ReserveHistory}=N ,reserve_history=[AccountId | ReserveHistory] }. --spec unwind_reserve_history(knm_phone_number()) -> knm_phone_number(). +-spec unwind_reserve_history(knm_phone_number()) -> knm_phone_number(); + (knm_numbers:collection()) -> knm_numbers:collection(). +unwind_reserve_history(T=#{todo := PNs}) -> + NewPNs = [unwind_reserve_history(PN) || PN <- PNs], + knm_numbers:ok(NewPNs, T); unwind_reserve_history(PN) -> ReserveHistory = PN#knm_phone_number.reserve_history, case lists:delete(prev_assigned_to(PN), reserve_history(PN)) of @@ -761,34 +935,16 @@ set_module_name(N, <<"wnm_bandwidth">>) -> set_module_name(N, <<"knm_bandwidth2">>); set_module_name(N, <<"wnm_", Name/binary>>) -> set_module_name(N, <<"knm_", Name/binary>>); -set_module_name(N, Name=?NE_BINARY) -> - IsBillable = knm_carriers:is_number_billable(N), - case {N#knm_phone_number.module_name, N#knm_phone_number.is_billable} of - {Name, IsBillable} -> N; - _ -> - N#knm_phone_number{is_dirty = true - ,module_name = Name - ,is_billable = IsBillable - } - end. - --spec set_module_name(knm_phone_number(), ne_binary(), api_boolean()) -> knm_phone_number(). %% Some old docs have these as module name -set_module_name(N, <<"undefined">>, IsBillable) -> - set_module_name(N, ?CARRIER_LOCAL, IsBillable); -set_module_name(N0, Name, IsBillable) - when is_boolean(IsBillable) -> - N = set_module_name(N0, Name), - %% Do not override is_billable when field is already set on doc. - case N#knm_phone_number.is_billable of - IsBillable -> N; - _ -> - N#knm_phone_number{is_dirty = true - ,is_billable = IsBillable - } - end; -set_module_name(N0, Name, 'undefined') -> - set_module_name(N0, Name). +set_module_name(N, <<"undefined">>) -> + set_module_name(N, ?CARRIER_LOCAL); +set_module_name(N, 'undefined') -> + set_module_name(N, ?CARRIER_LOCAL); +set_module_name(N=#knm_phone_number{module_name = Name}, Name=?NE_BINARY) -> N; +set_module_name(N, Name) -> + N#knm_phone_number{is_dirty = true + ,module_name = Name + }. %%-------------------------------------------------------------------- %% @public @@ -938,7 +1094,7 @@ update_doc(N=#knm_phone_number{doc = Doc}, JObj) -> reset_doc(N=#knm_phone_number{doc = Doc}, JObj) -> 'true' = kz_json:is_json_object(JObj), Updated = kz_json:merge_recursive(kz_json:public_fields(JObj), kz_json:private_fields(Doc)), - Data = kz_json:delete_key(<<"id">>, Updated), + Data = maybe_update_rw_features(kz_json:delete_key(<<"id">>, Updated)), case kz_json:are_equal(Data, N#knm_phone_number.doc) of true -> N; false -> @@ -967,21 +1123,14 @@ set_modified(PN, Modified) %% @end %%-------------------------------------------------------------------- -spec created(knm_phone_number()) -> gregorian_seconds(). -created(#knm_phone_number{created=Created}) -> Created. +created(#knm_phone_number{created = undefined}) -> kz_util:current_tstamp(); +created(#knm_phone_number{created = Created}) -> Created. -spec set_created(knm_phone_number(), gregorian_seconds()) -> knm_phone_number(). set_created(PN, Created) when is_integer(Created), Created > 0 -> PN#knm_phone_number{created=Created}. -%%-------------------------------------------------------------------- -%% @public -%% @doc -%% @end -%%-------------------------------------------------------------------- --spec is_billable(knm_phone_number()) -> boolean(). -is_billable(#knm_phone_number{is_billable = IsBillable}) -> IsBillable. - %%-------------------------------------------------------------------- %% @public %% @doc @@ -1203,6 +1352,9 @@ get_number_in_account(AccountId, Num) -> %% @end %%-------------------------------------------------------------------- -spec delete_number_doc(knm_phone_number()) -> knm_phone_number_return(). +-ifdef(TEST). +delete_number_doc(Number) -> {ok, Number}. +-else. delete_number_doc(Number) -> NumberDb = number_db(Number), JObj = to_json(Number), @@ -1210,6 +1362,7 @@ delete_number_doc(Number) -> {'error', _R}=E -> E; {'ok', _} -> {'ok', Number} end. +-endif. %%-------------------------------------------------------------------- %% @private @@ -1217,6 +1370,9 @@ delete_number_doc(Number) -> %% @end %%-------------------------------------------------------------------- -spec maybe_remove_number_from_account(knm_phone_number()) -> knm_phone_number_return(). +-ifdef(TEST). +maybe_remove_number_from_account(Number) -> {ok, Number}. +-else. maybe_remove_number_from_account(Number) -> AssignedTo = assigned_to(Number), case kz_util:is_empty(AssignedTo) of @@ -1229,6 +1385,7 @@ maybe_remove_number_from_account(Number) -> {'ok', _} -> {'ok', Number} end end. +-endif. -ifndef(TEST). %%-------------------------------------------------------------------- diff --git a/core/kazoo_number_manager/src/knm_port_request.erl b/core/kazoo_number_manager/src/knm_port_request.erl index 6ecc82073a9..e4fa403a25e 100644 --- a/core/kazoo_number_manager/src/knm_port_request.erl +++ b/core/kazoo_number_manager/src/knm_port_request.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_number_manager/src/knm_search.erl b/core/kazoo_number_manager/src/knm_search.erl index 6b03da12f4a..dd9478dbf89 100644 --- a/core/kazoo_number_manager/src/knm_search.erl +++ b/core/kazoo_number_manager/src/knm_search.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @@ -57,6 +57,8 @@ -define(POLLING_INTERVAL, 5000). +-define(NUMBER_SEARCH_TIMEOUT, kapps_config:get_integer(?KNM_CONFIG_CAT, <<"number_search_timeout_ms">>, 5000)). + -define(EOT, '$end_of_table'). -type state() :: #{}. @@ -299,14 +301,18 @@ wait_for_search(N, Options) -> lager:debug("~s found numbers", [_Carrier]), gen_listener:cast(?MODULE, {'add_result', Numbers}), wait_for_search(N - 1, Options); + {_Carrier, {bulk, Numbers}} -> + lager:debug("~s found bulk numbers", [_Carrier]), + gen_listener:cast(?MODULE, {'add_result', Numbers}), + wait_for_search(N - 1, Options); {_Carrier, {error, not_available}} -> lager:debug("~s had no results", [_Carrier]), wait_for_search(N - 1, Options); _Other -> lager:debug("unexpected search result ~p", [_Other]), wait_for_search(N - 1, Options) - after 5000 -> - lager:debug("timeout (~B) collecting responses from search providers", [5000]), + after ?NUMBER_SEARCH_TIMEOUT -> + lager:debug("timeout (~B) collecting responses from search providers", [?NUMBER_SEARCH_TIMEOUT]), wait_for_search(N - 1, Options) end. @@ -318,10 +324,8 @@ next(Options) -> MatchSpec = [{{QID,'$1'},[],['$1']}], QLH = qlc:keysort(1, ets:table(?ETS_DISCOVERY_CACHE, [{'traverse', {'select', MatchSpec}}])), QLC = qlc:cursor(QLH), - _ = case Offset > 0 of - 'true' -> qlc:next_answers(QLC, Offset); - _ -> 'true' - end, + _ = Offset > 0 + andalso qlc:next_answers(QLC, Offset), Results = qlc:next_answers(QLC, Quantity), qlc:delete_cursor(QLC), lager:debug("returning ~B results", [length(Results)]), @@ -443,7 +447,7 @@ remote_discovery(Number, Options) -> ,fun kapi_discovery:resp_v/1 ) of - {'ok', JObj} -> create_discovery(kapi_discovery:results(JObj), Options); + {'ok', JObj} -> {'ok', create_discovery(kapi_discovery:results(JObj), Options)}; {'error', _Error} -> lager:debug("error requesting number from amqp : ~p", [_Error]), {'error', 'not_found'} diff --git a/core/kazoo_number_manager/src/knm_services.erl b/core/kazoo_number_manager/src/knm_services.erl index 7f874ba66e7..f393e4124d1 100644 --- a/core/kazoo_number_manager/src/knm_services.erl +++ b/core/kazoo_number_manager/src/knm_services.erl @@ -1,11 +1,12 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% %%% @end %%% @contributors %%% Peter Defebvre +%%% Pierre Fenoll %%%------------------------------------------------------------------- -module(knm_services). @@ -20,13 +21,7 @@ -include("knm.hrl"). --ifdef(TEST). --include_lib("eunit/include/eunit.hrl"). --endif. - -define(KEY_NUMBER_ACTIVATION_CHARGES, <<"number_activation_charges">>). --define(KEY_TRANSACTIONS, <<"transactions">>). --define(KEY_ACTIVATION_CHARGES, <<"activation">>). %%-------------------------------------------------------------------- %% @public @@ -85,7 +80,6 @@ maybe_create_activation_transaction(Number, Feature, Units, TotalCharges) -> Transaction = create_transaction(Number, Feature, Units), N = knm_number:set_charges(Number, Feature, TotalCharges), knm_number:add_transaction(N, Transaction). - -endif. %%-------------------------------------------------------------------- @@ -119,38 +113,34 @@ deactivate_features(Number, Features) -> %% @doc %% @end %%-------------------------------------------------------------------- --spec update_services(knm_number:knm_number()) -> knm_number:knm_number(). +-spec update_services(knm_numbers:collection()) -> knm_numbers:collection(). -ifdef(TEST). -update_services(Number) -> Number. +update_services(T=#{todo := Ns}) -> knm_numbers:ok(Ns, T). -else. -update_services(Number) -> - PhoneNumber = knm_number:phone_number(Number), - update_services(Number - ,knm_phone_number:dry_run(PhoneNumber) - ,knm_phone_number:batch_run(PhoneNumber) - ). - --spec update_services(knm_number:knm_number(), boolean(), boolean()) -> - knm_number:knm_number(). -update_services(Number, _, 'true') -> - lager:debug("batch_run-ing btw"), - Number; -update_services(Number, 'true', _) -> - lager:debug("somewhat dry_run-ing btw"), - PhoneNumber = knm_number:phone_number(Number), - Services = kz_service_phone_numbers:reconcile(fetch_services(Number), [PhoneNumber]), - knm_number:set_services(Number, Services); -update_services(Number, 'false', _) -> - PhoneNumber = knm_number:phone_number(Number), - AssignedTo = knm_phone_number:assigned_to(PhoneNumber), - _ = kz_services:reconcile(AssignedTo, <<"phone_numbers">>), - PrevAssignedTo = knm_phone_number:prev_assigned_to(PhoneNumber), - _ = kz_services:reconcile(PrevAssignedTo, <<"phone_numbers">>), - Services = fetch_services(Number), - Transactions = knm_number:transactions(Number), - _ = 'undefined' =/= AssignedTo - andalso kz_services:commit_transactions(Services, Transactions), - Number. +update_services(T=#{todo := Ns, options := Options}) -> + case {knm_number_options:batch_run(Options) + ,knm_number_options:dry_run(Options) + } + of + {true, _} -> + lager:debug("batch_run-ing btw"), + knm_numbers:ok(Ns, T); + {_, true} -> + lager:debug("somewhat dry_run-ing btw"), + PNs = [knm_number:phone_number(N) || N <- Ns], + AssignedTo = knm_numbers:assigned_to(T), + Services = kz_service_phone_numbers:reconcile(do_fetch_services(AssignedTo), PNs), + knm_numbers:ok(Ns, T#{services => Services}); + {_, false} -> + AssignedTo = knm_numbers:assigned_to(T), + _ = kz_services:reconcile(AssignedTo, <<"phone_numbers">>), + PrevAssignedTo = knm_numbers:prev_assigned_to(T), + _ = kz_services:reconcile(PrevAssignedTo, <<"phone_numbers">>), + Services = do_fetch_services(AssignedTo), + _ = 'undefined' =/= AssignedTo + andalso kz_services:commit_transactions(Services, knm_numbers:transactions(T)), + knm_numbers:ok(Ns, T#{services => Services}) + end. -endif. %%-------------------------------------------------------------------- @@ -158,69 +148,76 @@ update_services(Number, 'false', _) -> %% @doc %% @end %%-------------------------------------------------------------------- --spec activate_phone_number(knm_number:knm_number()) -> - knm_number:knm_number(). --spec activate_phone_number(knm_number:knm_number(), ne_binary()) -> - knm_number:knm_number(). --spec activate_phone_number(knm_number:knm_number(), ne_binary(), integer()) -> - knm_number:knm_number(). -activate_phone_number(Number) -> - BillingId = fetch_billing_id(Number), - activate_phone_number(Number, BillingId). - -activate_phone_number(Number, BillingId) -> - Services = fetch_services(Number), - Num = knm_phone_number:number(knm_number:phone_number(Number)), - Units = kz_service_phone_numbers:phone_number_activation_charge(Services, Num), - activate_phone_number(Number, BillingId, Units). - -activate_phone_number(Number, _BillingId, 0) -> - Num = knm_phone_number:number(knm_number:phone_number(Number)), - lager:debug("no activation charge for ~s", [Num]), - Number; -activate_phone_number(Number, BillingId, Units) -> - Charges = knm_number:charges(Number, ?KEY_ACTIVATION_CHARGES), - TotalCharges = Charges + Units, - +-spec activate_phone_number(knm_numbers:collection()) -> knm_numbers:collection(). +activate_phone_number(T=#{services := undefined}) -> + AssignedTo = knm_numbers:assigned_to(T), + activate_phone_number(T#{services => do_fetch_services(AssignedTo)}); +activate_phone_number(T0=#{todo := Ns, services := Services}) -> + AssignedTo = knm_numbers:assigned_to(T0), + BillingId = fetch_billing_id(T0), + F = fun (N, T) -> + Num = knm_phone_number:number(knm_number:phone_number(N)), + case kz_service_phone_numbers:phone_number_activation_charge(Services, Num) of + 0 -> + lager:debug("no activation charge for ~s", [Num]), + knm_numbers:ok(N, T); + Units -> + T1 = do_activate(T, Num, Units, BillingId, AssignedTo), + knm_numbers:ok(N, T1) + end + end, + lists:foldl(F, T0, Ns). + +do_activate(T, Num, Units, BillingId, AssignedTo) -> + TotalCharges = activation_charges(T) + Units, case kz_services:check_bookkeeper(BillingId, TotalCharges) of - 'false' -> - Message = io_lib:format("not enough credit to activate number for $~p" - ,[wht_util:units_to_dollars(Units)]), + false -> + Message = + iolist_to_binary( + io_lib:format("not enough credit to activate number for $~p" + ,[wht_util:units_to_dollars(Units)])), lager:error(Message), - knm_errors:service_restriction(Message); - 'true' -> - Transaction = create_transaction(Number, Units), - - knm_number:set_charges(knm_number:add_transaction(Number, Transaction) - ,?KEY_NUMBER_ACTIVATION_CHARGES - ,TotalCharges - ) + Error = knm_errors:to_json(service_restriction, undefined, Message), + knm_numbers:ko(Num, Error, T); + true -> + Transaction = create_transaction(Num, Units, BillingId, AssignedTo), + knm_numbers:charge(?KEY_NUMBER_ACTIVATION_CHARGES + ,TotalCharges + ,knm_numbers:transaction(Transaction, T) + ) end. +%% @public +-spec phone_number_activation_charges(knm_numbers:collection()) -> non_neg_integer(). +phone_number_activation_charges(T) -> + knm_numbers:charge(?KEY_NUMBER_ACTIVATION_CHARGES, T). + +%% @public +-spec activation_charges(knm_numbers:collection()) -> non_neg_integer(). +activation_charges(T) -> + knm_numbers:charge(<<"activation">>, T). + %%%=================================================================== %%% Internal functions %%%=================================================================== -%%-------------------------------------------------------------------- -%% @public -%% @doc -%% @end -%%-------------------------------------------------------------------- --spec fetch_services(knm_number:knm_number()) -> kz_services:services(). -ifdef(TEST). -fetch_services(_Number) -> kz_services:new(). +do_fetch_services(undefined) -> kz_services:new(); +do_fetch_services(?MATCH_ACCOUNT_RAW(_)) -> kz_services:new(). -else. +-spec fetch_services(knm_number:knm_number()) -> kz_services:services(). fetch_services(Number) -> case knm_number:services(Number) of 'undefined' -> - case knm_phone_number:assigned_to(knm_number:phone_number(Number)) of - 'undefined' -> kz_services:new(); - AssignedTo -> - kz_services:fetch(AssignedTo) - end; + do_fetch_services( + knm_phone_number:assigned_to( + knm_number:phone_number(Number))); Services -> Services end. + +do_fetch_services(undefined) -> kz_services:new(); +do_fetch_services(?MATCH_ACCOUNT_RAW(AssignedTo)) -> kz_services:fetch(AssignedTo). -endif. %%-------------------------------------------------------------------- @@ -228,40 +225,28 @@ fetch_services(Number) -> %% @doc %% @end %%-------------------------------------------------------------------- --spec fetch_billing_id(knm_number:knm_number()) -> - ne_binary(). +-spec fetch_billing_id(knm_number:knm_number()) -> api_ne_binary(); + (knm_numbers:collection()) -> api_ne_binary(). -ifdef(TEST). fetch_billing_id(_Number) -> ?RESELLER_ACCOUNT_ID. -else. +fetch_billing_id(#{services := Services}) -> + kz_services:get_billing_id(Services); fetch_billing_id(Number) -> kz_services:get_billing_id(fetch_services(Number)). -endif. -%%-------------------------------------------------------------------- %% @private -%% @doc -%% @end -%%-------------------------------------------------------------------- --spec create_transaction(knm_number:knm_number(), integer()) -> - kz_transaction:transaction(). -create_transaction(Number, Units) -> - BillingId = fetch_billing_id(Number), - PhoneNumber = knm_number:phone_number(Number), - AccountId = knm_phone_number:assigned_to(PhoneNumber), - LedgerId = kz_util:format_account_id(BillingId, 'raw'), - Num = knm_phone_number:number(PhoneNumber), - - Routines = [fun(T) -> set_activation_reason(T, LedgerId, AccountId, <<"number">>) end - ,fun(T) -> kz_transaction:set_number(Num, T) end - ,fun(T) -> set_feature_description(T, kz_util:to_binary(Num)) end - ], +create_transaction(Num, Units, BillingId, AccountId) -> + LedgerId = kz_util:format_account_id(BillingId), + Fs = [fun(T) -> set_activation_reason(T, LedgerId, AccountId, <<"number">>) end + ,fun(T) -> kz_transaction:set_number(Num, T) end + ,fun(T) -> set_feature_description(T, kz_util:to_binary(Num)) end + ], lager:debug("staging number activation charge $~p for ~s via billing account ~s" ,[wht_util:units_to_dollars(Units), AccountId, LedgerId]), - - lists:foldl(fun(F, T) -> F(T) end - ,kz_transaction:debit(LedgerId, Units) - ,Routines - ). + T0 = kz_transaction:debit(LedgerId, Units), + lists:foldl(fun(F, T) -> F(T) end, T0, Fs). -ifndef(TEST). -spec create_transaction(knm_number:knm_number(), ne_binary(), integer()) -> @@ -306,11 +291,3 @@ set_activation_reason(Transaction, _LedgetId, AccountId, Key) -> kz_transaction:set_reason(<<"sub_account_", Key/binary, "_activation">> ,kz_transaction:set_sub_account_info(AccountId, Transaction) ). - --spec phone_number_activation_charges(knm_number:knm_number()) -> number(). -phone_number_activation_charges(Number) -> - knm_number:charges(Number, ?KEY_NUMBER_ACTIVATION_CHARGES). - --spec activation_charges(knm_number:knm_number()) -> number(). -activation_charges(Number) -> - knm_number:charges(Number, ?KEY_ACTIVATION_CHARGES). diff --git a/core/kazoo_number_manager/src/knm_telnyx_util.erl b/core/kazoo_number_manager/src/knm_telnyx_util.erl index 632fd7a3113..eab8301c6bf 100644 --- a/core/kazoo_number_manager/src/knm_telnyx_util.erl +++ b/core/kazoo_number_manager/src/knm_telnyx_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% @doc %%% %%% diff --git a/core/kazoo_number_manager/src/knm_util.erl b/core/kazoo_number_manager/src/knm_util.erl index 85a695d858a..7a435c2c8ba 100644 --- a/core/kazoo_number_manager/src/knm_util.erl +++ b/core/kazoo_number_manager/src/knm_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% diff --git a/core/kazoo_number_manager/src/knm_vitelity_util.erl b/core/kazoo_number_manager/src/knm_vitelity_util.erl index ca51439fea4..c77b78eda7f 100644 --- a/core/kazoo_number_manager/src/knm_vitelity_util.erl +++ b/core/kazoo_number_manager/src/knm_vitelity_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% @doc %%% %%% diff --git a/core/kazoo_number_manager/src/providers/knm_cnam_notifier.erl b/core/kazoo_number_manager/src/providers/knm_cnam_notifier.erl index d3ea73cd458..e7bf0b0d0b6 100644 --- a/core/kazoo_number_manager/src/providers/knm_cnam_notifier.erl +++ b/core/kazoo_number_manager/src/providers/knm_cnam_notifier.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% diff --git a/core/kazoo_number_manager/src/providers/knm_dash_e911.erl b/core/kazoo_number_manager/src/providers/knm_dash_e911.erl index f9047e82a13..417ce565898 100644 --- a/core/kazoo_number_manager/src/providers/knm_dash_e911.erl +++ b/core/kazoo_number_manager/src/providers/knm_dash_e911.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% Handle e911 provisioning @@ -96,7 +96,7 @@ feature(Number) -> maybe_update_e911(Number) -> CurrentE911 = feature(Number), E911 = kz_json:get_ne_value(?FEATURE_E911, knm_phone_number:doc(knm_number:phone_number(Number))), - NotChanged = kz_json:are_identical(CurrentE911, E911), + NotChanged = kz_json:are_equal(CurrentE911, E911), case kz_util:is_empty(E911) of 'true' -> lager:debug("information has been removed, updating upstream"), @@ -120,10 +120,7 @@ maybe_update_e911(Number, Address) -> knm_errors:unspecified(E, Number); {'invalid', Reason}-> lager:error("error while checking location ~p", [Reason]), - Error = - kz_json:from_list([{<<"cause">>, Address} - ,{<<"message">>, Reason} - ]), + Error = <>, knm_errors:invalid(Number, Error); {'provisioned', _} -> lager:debug("location seems already provisioned"), diff --git a/core/kazoo_number_manager/src/providers/knm_failover.erl b/core/kazoo_number_manager/src/providers/knm_failover.erl index dca9ab88da7..88127c7e4c1 100644 --- a/core/kazoo_number_manager/src/providers/knm_failover.erl +++ b/core/kazoo_number_manager/src/providers/knm_failover.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Handle failover provisioning %%% @end @@ -67,7 +67,7 @@ update_failover(Number) -> CurrentFailover = feature(Number), PhoneNumber = knm_number:phone_number(Number), Failover = kz_json:get_ne_value(?KEY, knm_phone_number:doc(PhoneNumber)), - NotChanged = kz_json:are_identical(CurrentFailover, Failover), + NotChanged = kz_json:are_equal(CurrentFailover, Failover), case kz_util:is_empty(Failover) of 'true' -> knm_services:deactivate_feature(Number, ?KEY); diff --git a/core/kazoo_number_manager/src/providers/knm_port_notifier.erl b/core/kazoo_number_manager/src/providers/knm_port_notifier.erl index 2c80b14882b..a4f02393ead 100644 --- a/core/kazoo_number_manager/src/providers/knm_port_notifier.erl +++ b/core/kazoo_number_manager/src/providers/knm_port_notifier.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% Handle publishing notification events for new port requests @@ -87,7 +87,7 @@ maybe_port_changed(Number, Port) -> maybe_port_changed(Number, _Port, 'true') -> Number; maybe_port_changed(Number, Port, 'false') -> CurrentPort = feature(Number), - case kz_json:are_identical(CurrentPort, Port) of + case kz_json:are_equal(CurrentPort, Port) of 'true' -> Number; 'false' -> lager:debug("port information has been changed: ~s", [kz_json:encode(Port)]), diff --git a/core/kazoo_number_manager/src/providers/knm_prepend.erl b/core/kazoo_number_manager/src/providers/knm_prepend.erl index fed6ab7d60a..bc7dd721e21 100644 --- a/core/kazoo_number_manager/src/providers/knm_prepend.erl +++ b/core/kazoo_number_manager/src/providers/knm_prepend.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Handle prepend feature %%% @end @@ -67,7 +67,7 @@ update_prepend(Number) -> CurrentPrepend = feature(Number), PhoneNumber = knm_number:phone_number(Number), Prepend = kz_json:get_ne_value(?KEY, knm_phone_number:doc(PhoneNumber)), - NotChanged = kz_json:are_identical(CurrentPrepend, Prepend), + NotChanged = kz_json:are_equal(CurrentPrepend, Prepend), case kz_util:is_empty(Prepend) of 'true' -> knm_services:deactivate_feature(Number, ?KEY); diff --git a/core/kazoo_number_manager/src/providers/knm_providers.erl b/core/kazoo_number_manager/src/providers/knm_providers.erl index a2fdbc85c58..8cc25af6337 100644 --- a/core/kazoo_number_manager/src/providers/knm_providers.erl +++ b/core/kazoo_number_manager/src/providers/knm_providers.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Handle prepend feature %%% @end @@ -13,19 +13,16 @@ -export([save/1]). -export([delete/1]). --export([allowed_features/1 +-export([available_features/1, available_features/5 ,service_name/2 ]). -export([e911_caller_name/2]). -define(DEFAULT_CNAM_PROVIDER, <<"knm_cnam_notifier">>). -define(DEFAULT_E911_PROVIDER, <<"knm_dash_e911">>). --define(DEFAULT_ALLOWED_FEATURES, [?FEATURE_CNAM - ,?FEATURE_E911 - ,?FEATURE_FAILOVER - ,?FEATURE_PORT - ,?FEATURE_PREPEND - ]). + +-define(KEY_FEATURES_ALLOW, [<<"features">>, <<"allow">>]). +-define(KEY_FEATURES_DENY, [<<"features">>, <<"deny">>]). -define(CNAM_PROVIDER(AccountId), kapps_account_config:get_from_reseller(AccountId, ?KNM_CONFIG_CAT, <<"cnam_provider">>, ?DEFAULT_CNAM_PROVIDER)). @@ -33,48 +30,61 @@ -define(E911_PROVIDER(AccountId), kapps_account_config:get_from_reseller(AccountId, ?KNM_CONFIG_CAT, <<"e911_provider">>, ?DEFAULT_E911_PROVIDER)). --define(ALLOWED_FEATURES(AccountId), - lists:usort( - kapps_account_config:get_from_reseller(AccountId, ?KNM_CONFIG_CAT, <<"allowed_features">>, ?DEFAULT_ALLOWED_FEATURES))). +-define(FEATURES_ALLOWED_RESELLER(AccountId), + kapps_account_config:get_from_reseller(AccountId, ?KNM_CONFIG_CAT, ?KEY_FEATURES_ALLOW)). + +-define(FEATURES_DENIED_RESELLER(AccountId), + kapps_account_config:get_from_reseller(AccountId, ?KNM_CONFIG_CAT, ?KEY_FEATURES_DENY)). + +-define(SYSTEM_PROVIDERS, + kapps_config:get(?KNM_CONFIG_CAT, <<"providers">>)). + +-define(FEATURES_ALLOWED_SYSTEM(Default), + kapps_config:get(?KNM_CONFIG_CAT, ?KEY_FEATURES_ALLOW, Default)). + +-define(FEATURES_ALLOWED_SYSTEM, + ?FEATURES_ALLOWED_SYSTEM(?KAZOO_NUMBER_FEATURES)). + + +-record(feature_parameters, {is_local = 'false' :: boolean() + ,assigned_to :: api_ne_binary() + ,used_by :: api_ne_binary() + ,allowed_features = [] :: ne_binaries() + ,denied_features = [] :: ne_binaries() + }). +-type feature_parameters() :: #feature_parameters{}. %%-------------------------------------------------------------------- %% @public %% @doc %% @end %%-------------------------------------------------------------------- --spec save(knm_number:knm_number()) -> knm_number:knm_number(). +-spec save(knm_numbers:collection()) -> knm_numbers:collection(). save(Number) -> - exec(Number, 'save'). + do_exec(Number, 'save'). %%-------------------------------------------------------------------- %% @public %% @doc %% @end %%-------------------------------------------------------------------- --spec delete(knm_number:knm_number()) -> knm_number:knm_number(). +-spec delete(knm_numbers:collection()) -> knm_numbers:collection(). delete(Number) -> - exec(Number, 'delete'). + do_exec(Number, 'delete'). %%-------------------------------------------------------------------- %% @public %% @doc -%% List features a number is allowedby its reseller to enable. +%% List features a number is allowed by its reseller to enable. %% @end %%-------------------------------------------------------------------- --spec allowed_features(knm_phone_number:knm_phone_number()) -> ne_binaries(). -allowed_features(PhoneNumber) -> - case knm_phone_number:assigned_to(PhoneNumber) of - 'undefined' -> []; - AccountId -> maybe_fix_e911(?ALLOWED_FEATURES(AccountId)) - end. +-spec available_features(knm_phone_number:knm_phone_number()) -> ne_binaries(). +available_features(PhoneNumber) -> + list_available_features(feature_parameters(PhoneNumber)). --spec maybe_fix_e911(ne_binaries()) -> ne_binaries(). -maybe_fix_e911(Features) -> - E911 = [<<"dash_e911">>, <<"vitelity_e911">>], - case lists:any(fun(F) -> lists:member(F, Features) end, E911) of - 'true' -> Features ++ [<<"e911">>]; - 'false' -> Features - end. +-spec available_features(boolean(), api_ne_binary(), api_ne_binary(), ne_binaries(), ne_binaries()) -> ne_binaries(). +available_features(IsLocal, AssignedTo, UsedBy, Allowed, Denied) -> + list_available_features(feature_parameters(IsLocal, AssignedTo, UsedBy, Allowed, Denied)). %%-------------------------------------------------------------------- %% @public @@ -117,37 +127,148 @@ e911_caller_name(Number, 'undefined') -> %%%=================================================================== -spec service_name(ne_binary()) -> ne_binary(). -service_name(<<"knm_dash_e911">>) -> <<"dash_e911">>; -service_name(<<"knm_telnyx_e911">>) -> <<"telnyx_e911">>; -service_name(<<"knm_vitelity_e911">>) -> <<"vitelity_e911">>; +service_name(<<"knm_dash_e911">>) -> ?LEGACY_DASH_E911; +service_name(<<"knm_telnyx_e911">>) -> ?LEGACY_TELNYX_E911; +service_name(<<"knm_vitelity_e911">>) -> ?LEGACY_VITELITY_E911; service_name(<<"knm_cnam_notifier">>) -> <<"cnam">>; service_name(<<"knm_telnyx_cnam">>) -> <<"telnyx_cnam">>; service_name(<<"knm_vitelity_cnam">>) -> <<"vitelity_cnam">>; service_name(Feature) -> Feature. +-spec list_available_features(feature_parameters()) -> ne_binaries(). +list_available_features(Parameters) -> + Allowed = lists:usort([legacy_provider_to_feature(F) || F <- list_allowed_features(Parameters)]), + Denied = lists:usort([legacy_provider_to_feature(F) || F <- list_denied_features(Parameters)]), + [Feature + || Feature <- Allowed, + not lists:member(Feature, Denied) + ]. + +-spec feature_parameters(knm_phone_number:knm_phone_number()) -> feature_parameters(). +feature_parameters(PhoneNumber) -> + feature_parameters(?CARRIER_LOCAL =:= knm_phone_number:module_name(PhoneNumber) + ,knm_phone_number:assigned_to(PhoneNumber) + ,knm_phone_number:used_by(PhoneNumber) + ,knm_phone_number:features_allowed(PhoneNumber) + ,knm_phone_number:features_denied(PhoneNumber) + ). + +-spec feature_parameters(boolean(), api_ne_binary(), api_ne_binary(), ne_binaries(), ne_binaries()) -> + feature_parameters(). +feature_parameters(IsLocal, AssignedTo, UsedBy, Allowed, Denied) -> + #feature_parameters{is_local = IsLocal + ,assigned_to = AssignedTo + ,used_by = UsedBy + ,allowed_features = Allowed + ,denied_features = Denied + }. + +-spec list_allowed_features(feature_parameters()) -> ne_binaries(). +list_allowed_features(Parameters) -> + case number_allowed_features(Parameters) of + [] -> reseller_allowed_features(Parameters); + NumberAllowed -> NumberAllowed + end. + +-spec reseller_allowed_features(feature_parameters()) -> ne_binaries(). +reseller_allowed_features(#feature_parameters{assigned_to = 'undefined'}) -> + system_allowed_features(); +reseller_allowed_features(#feature_parameters{assigned_to = AccountId}) -> + case ?FEATURES_ALLOWED_RESELLER(AccountId) of + 'undefined' -> system_allowed_features(); + Providers -> + lager:debug("allowed number features set on reseller for ~s: ~p", [AccountId, Providers]), + Providers + end. + +-spec system_allowed_features() -> ne_binaries(). +system_allowed_features() -> + lager:debug("allowed number features fetched from system config"), + case ?SYSTEM_PROVIDERS of + 'undefined' -> ?FEATURES_ALLOWED_SYSTEM; + Providers -> ?FEATURES_ALLOWED_SYSTEM(Providers) + end. + +-spec number_allowed_features(feature_parameters()) -> ne_binaries(). +number_allowed_features(#feature_parameters{allowed_features = AllowedFeatures}) -> + lager:debug("allowed number features set on number document: ~p", [AllowedFeatures]), + AllowedFeatures. + +-spec list_denied_features(feature_parameters()) -> ne_binaries(). +list_denied_features(Parameters) -> + case number_denied_features(Parameters) of + [] -> + reseller_denied_features(Parameters) + ++ used_by_denied_features(Parameters); + NumberDenied -> NumberDenied + end. + +-spec reseller_denied_features(feature_parameters()) -> ne_binaries(). +reseller_denied_features(#feature_parameters{assigned_to = 'undefined'}) -> + lager:debug("denying external number features for unassigned number"), + ?EXTERNAL_NUMBER_FEATURES; +reseller_denied_features(#feature_parameters{assigned_to = AccountId}=Parameters) -> + case ?FEATURES_DENIED_RESELLER(AccountId) of + 'undefined' -> local_denied_features(Parameters); + Providers -> + lager:debug("denied number features set on reseller for ~s: ~p", [AccountId, Providers]), + Providers + end. + +-spec local_denied_features(feature_parameters()) -> ne_binaries(). +local_denied_features(#feature_parameters{is_local = 'false'}) -> []; +local_denied_features(#feature_parameters{is_local = 'true'}) -> + lager:debug("denying external number features for local number"), + ?EXTERNAL_NUMBER_FEATURES. + +-spec used_by_denied_features(feature_parameters()) -> ne_binaries(). +used_by_denied_features(#feature_parameters{used_by = <<"trunkstore">>}) -> []; +used_by_denied_features(#feature_parameters{used_by = UsedBy}) -> + lager:debug("denying external number features for number used by ~s", [UsedBy]), + [?FEATURE_FAILOVER]. + +-spec number_denied_features(feature_parameters()) -> ne_binaries(). +number_denied_features(#feature_parameters{denied_features = DeniedFeatures}) -> + lager:debug("denied number features set on number document: ~p", [DeniedFeatures]), + DeniedFeatures. + +-spec legacy_provider_to_feature(ne_binary()) -> ne_binary(). +legacy_provider_to_feature(<<"wnm_", Rest/binary>>) -> legacy_provider_to_feature(Rest); +legacy_provider_to_feature(<<"knm_", Rest/binary>>) -> legacy_provider_to_feature(Rest); +legacy_provider_to_feature(<<"cnam_notifier">>) -> ?FEATURE_CNAM; +legacy_provider_to_feature(?LEGACY_DASH_E911) -> ?FEATURE_E911; +legacy_provider_to_feature(<<"port_notifier">>) -> ?FEATURE_PORT; +legacy_provider_to_feature(<<"telnyx_cnam">>) -> ?FEATURE_CNAM; +legacy_provider_to_feature(?LEGACY_TELNYX_E911) -> ?FEATURE_E911; +legacy_provider_to_feature(<<"vitelity_cnam">>) -> ?FEATURE_CNAM; +legacy_provider_to_feature(?LEGACY_VITELITY_E911) -> ?FEATURE_E911; +legacy_provider_to_feature(Else) -> Else. + %%-------------------------------------------------------------------- %% @private %% @doc %% @end %%-------------------------------------------------------------------- --spec provider_modules(knm_number:knm_number()) -> ne_binaries(). -provider_modules(Number) -> +-spec requested_modules(knm_number:knm_number()) -> ne_binaries(). +requested_modules(Number) -> PhoneNumber = knm_number:phone_number(Number), AccountId = knm_phone_number:assigned_to(PhoneNumber), - Possible0 = kz_json:get_keys(knm_phone_number:doc(PhoneNumber)), - Possible = lists:usort(Possible0 ++ knm_phone_number:features_list(PhoneNumber)), - AllowedBase = allowed_features(PhoneNumber), - Allowed = case lists:member(?FEATURE_E911, Possible0) of - true -> AllowedBase; - false -> - %% For backward compatibility - AllowedBase ++ [<<"dash_e911">>, <<"vitelity_e911">>] - end, - lager:debug("allowed ~p, possible ~p", [Allowed, Possible]), - [provider_module(Feature, AccountId) - || Feature <- Possible, - lists:member(Feature, Allowed) - ]. + RequestedFeatures = kz_json:get_keys(knm_phone_number:doc(PhoneNumber)), + ExistingFeatures = knm_phone_number:features_list(PhoneNumber), + provider_modules(RequestedFeatures ++ ExistingFeatures, AccountId). + +-spec allowed_modules(knm_number:knm_number()) -> ne_binaries(). +allowed_modules(Number) -> + PhoneNumber = knm_number:phone_number(Number), + AccountId = knm_phone_number:assigned_to(PhoneNumber), + provider_modules(available_features(PhoneNumber), AccountId). + +-spec provider_modules(ne_binaries(), api_ne_binary()) -> ne_binaries(). +provider_modules(Features, MaybeAccountId) -> + lists:usort( + [provider_module(Feature, MaybeAccountId) + || Feature <- Features + ]). -spec provider_module(ne_binary(), api_ne_binary()) -> ne_binary(). provider_module(?FEATURE_CNAM, ?MATCH_ACCOUNT_RAW(AccountId)) -> @@ -160,13 +281,8 @@ provider_module(?FEATURE_PORT, _) -> <<"knm_port_notifier">>; provider_module(?FEATURE_FAILOVER, _) -> <<"knm_failover">>; -%% These 2 for backward compatibility: -provider_module(<<"dash_e911">>=OldFeature, _) -> - <<"knm_", OldFeature/binary>>; -provider_module(<<"vitelity_e911">>=OldFeature, _) -> - <<"knm_", OldFeature/binary>>; provider_module(Other, _) -> - lager:warning("unmatched feature provider '~s', allowing", [Other]), + lager:warning("unmatched feature provider ~p, allowing", [Other]), Other. -ifdef(TEST). @@ -189,38 +305,43 @@ cnam_provider(AccountId) -> ?CNAM_PROVIDER(AccountId). %% @end %%-------------------------------------------------------------------- -type exec_action() :: 'save' | 'delete'. --spec exec(knm_number:knm_number(), exec_action()) -> - knm_number:knm_number(). + +-spec do_exec(knm_numbers:collection(), exec_action()) -> knm_numbers:collection(). +do_exec(T0=#{todo := Ns}, Action) -> + F = fun (N, T) -> + case knm_number:attempt(fun exec/2, [N, Action]) of + {ok, NewN} -> knm_numbers:ok(NewN, T); + {error, R} -> knm_numbers:ko(N, R, T) + end + end, + lists:foldl(F, T0, Ns). + +-spec exec(knm_number:knm_number(), exec_action()) -> knm_number:knm_number(). -spec exec(knm_number:knm_number(), exec_action(), ne_binaries()) -> knm_number:knm_number(). +exec(Number, Action=delete) -> + RequestedModules = requested_modules(Number), + lager:debug("requested number features: ~p", [RequestedModules]), + exec(Number, Action, RequestedModules); exec(Number, Action) -> - Number1 = fix_old_fields_names(Number), - exec(Number1, Action, provider_modules(Number)). + RequestedModules = requested_modules(Number), + lager:debug("requested number features: ~p", [RequestedModules]), + AllowedModules = allowed_modules(Number), + Filter = fun (Feature) -> lists:member(Feature, AllowedModules) end, + {AllowedRequests, DeniedRequests} = lists:partition(Filter, RequestedModules), + lager:debug("allowing number features ~p", [AllowedRequests]), + Number1 = exec(Number, Action, AllowedRequests), + lager:debug("denied number features ~p", [DeniedRequests]), + exec(Number1, delete, DeniedRequests). -%% @private -fix_old_fields_names(Number) -> - PN = knm_number:phone_number(Number), - Doc = knm_phone_number:doc(PN), - Values = props:filter_undefined( - [{?FEATURE_E911, kz_json:get_ne_value(<<"dash_e911">>, Doc)} - ,{?FEATURE_E911, kz_json:get_ne_value(<<"vitelity_e911">>, Doc)} - ]), - ToDelete = [<<"dash_e911">>, <<"vitelity_e911">>], - NewDoc = kz_json:set_values(Values, kz_json:delete_keys(ToDelete, Doc)), - NewPN = knm_phone_number:update_doc(PN, NewDoc), - knm_number:set_phone_number(Number, NewPN). - -exec(Number, Action, Providers) -> - lists:foldl(fun (Provider, N) -> - case apply_action(N, Action, Provider) of - {'true', NewN} -> NewN; - 'false' -> N - end - end - ,Number - ,Providers - ). +exec(Number, _, []) -> Number; +exec(Number, Action, [Provider|Providers]) -> + case apply_action(Number, Action, Provider) of + 'false' -> exec(Number, Action, Providers); + {'true', UpdatedNumber} -> + exec(UpdatedNumber, Action, Providers) + end. -spec apply_action(knm_number:knm_number(), exec_action(), ne_binary()) -> {'true', any()} | 'false'. diff --git a/core/kazoo_number_manager/src/providers/knm_telnyx_cnam.erl b/core/kazoo_number_manager/src/providers/knm_telnyx_cnam.erl index 9da506ed528..d60ce40a221 100644 --- a/core/kazoo_number_manager/src/providers/knm_telnyx_cnam.erl +++ b/core/kazoo_number_manager/src/providers/knm_telnyx_cnam.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% diff --git a/core/kazoo_number_manager/src/providers/knm_telnyx_e911.erl b/core/kazoo_number_manager/src/providers/knm_telnyx_e911.erl index 10dc6f36385..fc75dd21a25 100644 --- a/core/kazoo_number_manager/src/providers/knm_telnyx_e911.erl +++ b/core/kazoo_number_manager/src/providers/knm_telnyx_e911.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% Handle e911 provisioning @@ -81,7 +81,7 @@ maybe_update_e911(Number) -> maybe_update_e911(Number, 'true') -> CurrentE911 = feature(Number), E911 = kz_json:get_ne_value(?FEATURE_E911, knm_phone_number:doc(knm_number:phone_number(Number))), - NotChanged = kz_json:are_identical(CurrentE911, E911), + NotChanged = kz_json:are_equal(CurrentE911, E911), case kz_util:is_empty(E911) of 'true' -> lager:debug("dry run: information has been removed, updating upstream"), @@ -96,7 +96,7 @@ maybe_update_e911(Number, 'true') -> maybe_update_e911(Number, 'false') -> CurrentE911 = feature(Number), E911 = kz_json:get_ne_value(?FEATURE_E911, knm_phone_number:doc(knm_number:phone_number(Number))), - NotChanged = kz_json:are_identical(CurrentE911, E911), + NotChanged = kz_json:are_equal(CurrentE911, E911), case kz_util:is_empty(E911) of 'true' -> lager:debug("information has been removed, updating upstream"), diff --git a/core/kazoo_number_manager/src/providers/knm_vitelity_cnam.erl b/core/kazoo_number_manager/src/providers/knm_vitelity_cnam.erl index c3f5498213c..5c55ad7db8b 100644 --- a/core/kazoo_number_manager/src/providers/knm_vitelity_cnam.erl +++ b/core/kazoo_number_manager/src/providers/knm_vitelity_cnam.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% diff --git a/core/kazoo_number_manager/src/providers/knm_vitelity_e911.erl b/core/kazoo_number_manager/src/providers/knm_vitelity_e911.erl index 52e2956a554..5bb3267a5f3 100644 --- a/core/kazoo_number_manager/src/providers/knm_vitelity_e911.erl +++ b/core/kazoo_number_manager/src/providers/knm_vitelity_e911.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% @doc %%% %%% Handle e911 provisioning @@ -118,7 +118,7 @@ maybe_update_e911(Number) -> maybe_update_e911(Number, 'true') -> CurrentE911 = feature(Number), E911 = kz_json:get_ne_value(?FEATURE_E911, knm_phone_number:doc(knm_number:phone_number(Number))), - NotChanged = kz_json:are_identical(CurrentE911, E911), + NotChanged = kz_json:are_equal(CurrentE911, E911), case kz_util:is_empty(E911) of 'true' -> lager:debug("dry run: information has been removed, updating upstream"), @@ -133,7 +133,7 @@ maybe_update_e911(Number, 'true') -> maybe_update_e911(Number, 'false') -> CurrentE911 = feature(Number), E911 = kz_json:get_ne_value(?FEATURE_E911, knm_phone_number:doc(knm_number:phone_number(Number))), - NotChanged = kz_json:are_identical(CurrentE911, E911), + NotChanged = kz_json:are_equal(CurrentE911, E911), case kz_util:is_empty(E911) of 'true' -> lager:debug("information has been removed, updating upstream"), diff --git a/core/kazoo_number_manager/test/knm_bandwidth2_test.erl b/core/kazoo_number_manager/test/knm_bandwidth2_test.erl index faa32be9b24..629415e945b 100644 --- a/core/kazoo_number_manager/test/knm_bandwidth2_test.erl +++ b/core/kazoo_number_manager/test/knm_bandwidth2_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% @end %%% @contributors @@ -11,17 +11,20 @@ -include("knm.hrl"). api_test_() -> - {'ok', Pid} = knm_search:start_link(), Options = [{'account_id', ?RESELLER_ACCOUNT_ID} ,{'carriers', [<<"knm_bandwidth2">>]} ,{'query_id', <<"QID">>} ], - X = [find_numbers(Options) - ,find_tollfree_numbers(Options) - ,acquire_number() - ], - _ = gen_server:stop(Pid), - X. + {setup + ,fun () -> {'ok', Pid} = knm_search:start_link(), Pid end + ,fun gen_server:stop/1 + ,fun (_ReturnOfSetup) -> + [find_numbers(Options) + ,find_tollfree_numbers(Options) + ,acquire_number() + ] + end + }. find_numbers(Options) -> Limit = 2, diff --git a/core/kazoo_number_manager/test/knm_bandwidth_find_test.erl b/core/kazoo_number_manager/test/knm_bandwidth_find_test.erl index be5c7c5d02b..01591554c82 100644 --- a/core/kazoo_number_manager/test/knm_bandwidth_find_test.erl +++ b/core/kazoo_number_manager/test/knm_bandwidth_find_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% @end %%% @contributors @@ -11,16 +11,19 @@ -include("knm.hrl"). api_test_() -> - {'ok', Pid} = knm_search:start_link(), Options = [{'account_id', ?RESELLER_ACCOUNT_ID} ,{'carriers', [<<"knm_bandwidth">>]} ,{'query_id', <<"QID">>} ], - X = [npan_tests(Options) - ,area_code_tests(Options) - ], - _ = gen_server:stop(Pid), - X. + {setup + ,fun () -> {'ok', Pid} = knm_search:start_link(), Pid end + ,fun gen_server:stop/1 + ,fun (_ReturnOfSetup) -> + [npan_tests(Options) + ,area_code_tests(Options) + ] + end + }. npan_tests(Options) -> Limit = 1, @@ -28,7 +31,8 @@ npan_tests(Options) -> Results = knm_search:find([{'quantity',Limit} ,{prefix, Prefix} ,{query_id, <<"QID-", Prefix/binary>>} - |Options]), + | Options + ]), [{"Verify area code result size" ,?_assertEqual(Limit, length(Results)) } @@ -40,7 +44,8 @@ area_code_tests(Options) -> Results = knm_search:find([{'quantity',Limit} ,{prefix, Prefix} ,{query_id, <<"QID-", Prefix/binary>>} - |Options]), + | Options + ]), [{"Verify area code result size" ,?_assertEqual(Limit, length(Results)) } diff --git a/core/kazoo_number_manager/test/knm_carriers_find_test.erl b/core/kazoo_number_manager/test/knm_carriers_find_test.erl index 07b576954f8..b2f6ad71e98 100644 --- a/core/kazoo_number_manager/test/knm_carriers_find_test.erl +++ b/core/kazoo_number_manager/test/knm_carriers_find_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% @end %%% @contributors @@ -10,6 +10,34 @@ -include_lib("eunit/include/eunit.hrl"). -include("knm.hrl"). +is_number_billable_test_() -> + {ok, N} = knm_number:get(?TEST_OLD_NUM), + PN1 = knm_number:phone_number(N), + PN2 = knm_phone_number:set_module_name(PN1, <<"knm_bandwidth2">>), + PN3 = knm_phone_number:set_module_name(PN1, <<"wnm_pacwest">>), + [?_assertEqual(false, knm_carriers:is_number_billable(PN1)) + ,?_assertEqual(true, knm_carriers:is_number_billable(PN2)) + ,?_assertEqual(true, knm_carriers:is_number_billable(PN3)) + ]. + +check_test_() -> + Nums = [?TEST_AVAILABLE_NUM + ,?TEST_IN_SERVICE_NUM + ,?TEST_IN_SERVICE_WITH_HISTORY_NUM + ,?TEST_EXISTING_TOLL + ], + [?_assertEqual(kz_json:new(), knm_carriers:check([])) + ,{"Checking numbers against unconfigured carriers" + ,?_assertEqual(#{?TEST_AVAILABLE_NUM => <<"error">> + ,?TEST_IN_SERVICE_NUM => <<"error">> + ,?TEST_IN_SERVICE_WITH_HISTORY_NUM => <<"error">> + ,?TEST_EXISTING_TOLL => <<"error">> + } + ,kz_json:to_map(knm_carriers:check(Nums)) + ) + } + ]. + find_local_test_() -> [{"Finding local numbers not supported" ,?_assertMatch({'error', 'not_available'} @@ -22,16 +50,20 @@ find_local_test_() -> ]. find_other_test_() -> - {'ok', Pid} = knm_search:start_link(), Options = [{carriers, [?CARRIER_OTHER]} ,{'query_id', <<"QID">>} ], - X = [find_no_phonebook(Options) - ,find_blocks(Options) - ,find_numbers(Options) - ], - _ = gen_server:stop(Pid), - X. + {setup + ,fun () -> {'ok', Pid} = knm_search:start_link(), Pid end + ,fun gen_server:stop/1 + ,fun (_ReturnOfSetup) -> + [find_no_phonebook(Options) + ,?_assertEqual([], knm_search:find([{prefix, <<"415">>}])) + ,find_numbers(Options) + ,find_blocks(Options) + ] + end + }. find_no_phonebook(Options0) -> Prefix = <<"415">>, @@ -54,48 +86,16 @@ find_blocks(Options0) -> | Options0 ], - {'bulk', [StartNumber, EndNumber]=Numbers} = - knm_other:find_numbers(Prefix, Limit, Options), - [StartJObj, EndJObj]=Results = knm_search:find(Options), + {'bulk', [StartNumber, EndNumber]=Numbers} = knm_other:find_numbers(Prefix, Limit, Options), + [StartRep, EndRep]=Results = knm_search:find(Options), - [{"Verify the same amount of numbers and results" - ,?_assertEqual(length(Numbers), length(Results)) - } - | verify_start(StartNumber, StartJObj) - ++ verify_end(EndNumber, EndJObj) - ]. - -verify_start(StartNumber, StartJObj) -> - PhoneNumber = knm_number:phone_number(StartNumber), - verify_block(PhoneNumber, StartJObj, ?START_BLOCK, 5.0). - -verify_end(EndNumber, EndJObj) -> - PhoneNumber = knm_number:phone_number(EndNumber), - verify_block(PhoneNumber, EndJObj, ?END_BLOCK, 'undefined'). - -verify_block(PhoneNumber, JObj, DID, Activation) -> - [{"Verify start number matches start of block" - ,?_assertEqual(DID, knm_phone_number:number(PhoneNumber)) - } - ,{"Verify start number carrier module" - ,?_assertEqual(?CARRIER_OTHER, knm_phone_number:module_name(PhoneNumber)) - } - ,{"Verify auth_by account id" - ,?_assertEqual(?RESELLER_ACCOUNT_ID, knm_phone_number:auth_by(PhoneNumber)) - } - ,{"Verify assigned_to account id" - ,?_assertEqual('undefined', knm_phone_number:assigned_to(PhoneNumber)) - } - ,{"Verify phone number database" - ,?_assertEqual(<<"numbers%2F%2B1415">>, knm_phone_number:number_db(PhoneNumber)) - } - - ,{"Verify JObj number is start number" - ,?_assertEqual(DID, kz_json:get_value(<<"number">>, JObj)) - } - ,{"Verify JObj activation charge" - ,?_assertEqual(Activation, kz_json:get_value(<<"activation_charge">>, JObj)) - } + [?_assertEqual(length(Numbers), length(Results)) + ,?_assertEqual(?START_BLOCK, kz_json:get_value(<<"number">>, StartRep)) + ,?_assertEqual(?END_BLOCK, kz_json:get_value(<<"number">>, EndRep)) + ,?_assertEqual(?START_BLOCK, element(1,element(2,StartNumber))) + ,?_assertEqual(?END_BLOCK, element(1,element(2,EndNumber))) + ,?_assertEqual(?CARRIER_OTHER, kz_util:to_binary(element(2,element(2,StartNumber)))) + ,?_assertEqual(?CARRIER_OTHER, kz_util:to_binary(element(2,element(2,EndNumber)))) ]. find_numbers(Options0) -> @@ -124,23 +124,7 @@ verify_number_result(Result, {Tests, N}) -> ,kz_json:get_value(<<"number">>, Result) ) } - ,{"Verify result activation charge" - ,activation_charge_test(Result, <<"+1415886790", (N+$0)>>) - } | Tests ] ,N+1 }. - -activation_charge_test(Result, ?START_BLOCK) -> - {"Verify start of range activation" - ,?_assertEqual(5.0, kz_json:get_value(<<"activation_charge">>, Result)) - }; -activation_charge_test(Result, ?END_BLOCK) -> - {"Verify end of range activation" - ,?_assertEqual('undefined', kz_json:get_value(<<"activation_charge">>, Result)) - }; -activation_charge_test(Result, _DID) -> - {"Verify inner range activation" - ,?_assertEqual(1.0, kz_json:get_value(<<"activation_charge">>, Result)) - }. diff --git a/core/kazoo_number_manager/test/knm_converters_test.erl b/core/kazoo_number_manager/test/knm_converters_test.erl index f90f36a5cbb..73f3c91e486 100644 --- a/core/kazoo_number_manager/test/knm_converters_test.erl +++ b/core/kazoo_number_manager/test/knm_converters_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% diff --git a/core/kazoo_number_manager/test/knm_create_new_number_test.erl b/core/kazoo_number_manager/test/knm_create_new_number_test.erl index dc566ec7604..8f475be5006 100644 --- a/core/kazoo_number_manager/test/knm_create_new_number_test.erl +++ b/core/kazoo_number_manager/test/knm_create_new_number_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% @end %%% @contributors @@ -40,6 +40,53 @@ create_new_number_test_() -> } ]. +reseller_new_number_test_() -> + Props = [{'auth_by', ?RESELLER_ACCOUNT_ID} + ,{'assign_to', ?RESELLER_ACCOUNT_ID} + ,{'dry_run', 'false'} + ,{<<"auth_by_account">> + ,kz_account:set_allow_number_additions(?RESELLER_ACCOUNT_DOC, 'true') + } + ], + {'ok', N} = knm_number:create(?TEST_CREATE_NUM, Props), + PN = knm_number:phone_number(N), + [{"Verify phone number is assigned to reseller account" + ,?_assertEqual(?RESELLER_ACCOUNT_ID, knm_phone_number:assigned_to(PN)) + } + ,{"Verify new phone number was authorized by master account" + ,?_assertEqual(?RESELLER_ACCOUNT_ID, knm_phone_number:auth_by(PN)) + } + ,{"Verify new phone number database is properly set" + ,?_assertEqual(<<"numbers%2F%2B1555">>, knm_phone_number:number_db(PN)) + } + ,{"Verify new phone number is in RESERVED state" + ,?_assertEqual(?NUMBER_STATE_RESERVED, knm_phone_number:state(PN)) + } + ,{"Verify the reseller account is listed in reserve history" + ,?_assertEqual([?RESELLER_ACCOUNT_ID], knm_phone_number:reserve_history(PN)) + } + ,{"Verify the local carrier module is being used" + ,?_assertEqual(?CARRIER_LOCAL, knm_phone_number:module_name(PN)) + } + ]. + +fail_new_number_test_() -> + Props = [{'auth_by', ?RESELLER_ACCOUNT_ID} + ,{'assign_to', ?RESELLER_ACCOUNT_ID} + ,{'dry_run', 'false'} + ,{<<"auth_by_account">> + ,kz_account:set_allow_number_additions(?RESELLER_ACCOUNT_DOC, 'false') + } + ], + {'error', Reason} = knm_number:create(?TEST_CREATE_NUM, Props), + [{"Verify that without the allow number additions the proper error is thrown" + ,?_assertEqual(<<"forbidden">>, kz_json:get_value(<<"error">>, Reason)) + } + ,{"Verify that without the allow number additions the proper message is thrown" + ,?_assertEqual(<<"requestor is unauthorized to perform operation">>, kz_json:get_value(<<"message">>, Reason)) + } + ]. + create_new_available_number_test_() -> Props = [{'auth_by', ?KNM_DEFAULT_AUTH_BY} ,{'assign_to', ?MASTER_ACCOUNT_ID} @@ -99,11 +146,11 @@ create_existing_number_test_() -> ]. create_new_port_in_test_() -> - Props = [{'auth_by', ?MASTER_ACCOUNT_ID} + Props = [{'auth_by', ?RESELLER_ACCOUNT_ID} ,{'assign_to', ?RESELLER_ACCOUNT_ID} ,{'dry_run', 'false'} ,{<<"auth_by_account">> - ,kz_account:set_allow_number_additions(?RESELLER_ACCOUNT_DOC, 'true') + ,kz_account:set_allow_number_additions(?RESELLER_ACCOUNT_DOC, 'false') } ,{'state', ?NUMBER_STATE_PORT_IN} ,{'module_name', ?CARRIER_LOCAL} @@ -114,7 +161,7 @@ create_new_port_in_test_() -> ,?_assertEqual(?RESELLER_ACCOUNT_ID, knm_phone_number:assigned_to(PN)) } ,{"Verify new phone number was authorized by master account" - ,?_assertEqual(?MASTER_ACCOUNT_ID, knm_phone_number:auth_by(PN)) + ,?_assertEqual(?RESELLER_ACCOUNT_ID, knm_phone_number:auth_by(PN)) } ,{"Verify new phone number database is properly set" ,?_assertEqual(<<"numbers%2F%2B1555">>, knm_phone_number:number_db(PN)) @@ -128,30 +175,18 @@ create_new_port_in_test_() -> ,{"Verify the local carrier module is being used" ,?_assertEqual(?CARRIER_LOCAL, knm_phone_number:module_name(PN)) } + ,{"Verify local number is not billable" + ,?_assertEqual(false, knm_carriers:is_number_billable(PN)) + } ]. create_existing_in_service_test_() -> - InServicePN = - knm_phone_number:set_state(knm_phone_number:from_json(?AVAILABLE_NUMBER) - ,?NUMBER_STATE_IN_SERVICE - ), - Props = [{'auth_by', ?MASTER_ACCOUNT_ID} - ,{'assign_to', ?RESELLER_ACCOUNT_ID} - ,{'dry_run', 'false'} - ,{<<"auth_by_account">> - ,kz_account:set_allow_number_additions(?RESELLER_ACCOUNT_DOC, 'true') - } - ], - Resp = knm_number:attempt(fun knm_number:create_or_load/3 - ,[?TEST_AVAILABLE_NUM - ,Props - ,{'ok', InServicePN} - ] - ), + Options = [{assign_to, ?RESELLER_ACCOUNT_ID} | knm_number_options:default()], + Resp = knm_number:create(?TEST_IN_SERVICE_NUM, Options), [{"Verifying that IN SERVICE numbers can't be created" ,?_assertMatch({'error', _}, Resp) } - | check_error_response(Resp, 409, <<"number_exists">>, ?TEST_AVAILABLE_NUM) + | check_error_response(Resp, 409, <<"number_exists">>, ?TEST_IN_SERVICE_NUM) ]. create_dry_run_test_() -> @@ -168,7 +203,7 @@ create_dry_run_test_() -> ,?_assertEqual(0, Charges) } ,{"Verify services for dry_run" - ,?_assertEqual('undefined', Services) + ,?_assertEqual(true, Services =:= kz_services:new()) } ]. @@ -178,9 +213,7 @@ create_checks_test_() -> load_existing_checks() -> PN = knm_phone_number:from_json(?AVAILABLE_NUMBER), - [existing_in_state(knm_phone_number:set_state(PN, State) - ,IsAllowed - ) + [existing_in_state(knm_phone_number:set_state(PN, State), IsAllowed) || {State, IsAllowed} <- [{?NUMBER_STATE_AVAILABLE, 'true'} ,{?NUMBER_STATE_DELETED, 'false'} ,{?NUMBER_STATE_DISCONNECTED, 'false'} @@ -195,9 +228,7 @@ load_existing_checks() -> existing_in_state(PN, 'false') -> State = kz_util:to_list(knm_phone_number:state(PN)), - Resp = knm_number:attempt(fun knm_number:ensure_can_load_to_create/1 - ,[PN] - ), + Resp = knm_number:attempt(fun knm_number:ensure_can_load_to_create/1, [PN]), [{lists:flatten(["Ensure number in ", State, " cannot be 'created'"]) ,?_assertMatch({'error', _}, Resp) } diff --git a/core/kazoo_number_manager/test/knm_iso3166a2_itu_test.erl b/core/kazoo_number_manager/test/knm_iso3166a2_itu_test.erl index 3e25fa57584..982fc5380ed 100644 --- a/core/kazoo_number_manager/test/knm_iso3166a2_itu_test.erl +++ b/core/kazoo_number_manager/test/knm_iso3166a2_itu_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% diff --git a/core/kazoo_number_manager/test/knm_move_number_test.erl b/core/kazoo_number_manager/test/knm_move_number_test.erl index e5b742efa2c..e314d4823ef 100644 --- a/core/kazoo_number_manager/test/knm_move_number_test.erl +++ b/core/kazoo_number_manager/test/knm_move_number_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz +%%% @copyright (C) 2015-2017, 2600Hz %%% @doc %%% @end %%% @contributors @@ -11,14 +11,13 @@ -include_lib("eunit/include/eunit.hrl"). -include("knm.hrl"). -move_number_test_() -> - TestFuns = [fun move_to_child/0 - ], - [F() || F <- TestFuns]. - -move_to_child() -> +move_to_child_test_() -> {'ok', Number} = knm_number:move(?TEST_AVAILABLE_NUM, ?CHILD_ACCOUNT_ID), PhoneNumber = knm_number:phone_number(Number), - {"verify assigned_to is child account" - ,?_assertEqual(?CHILD_ACCOUNT_ID, knm_phone_number:assigned_to(PhoneNumber)) - }. + [{"verify assigned_to is child account" + ,?_assertEqual(?CHILD_ACCOUNT_ID, knm_phone_number:assigned_to(PhoneNumber)) + } + ,{"verify number is in service" + ,?_assertEqual(?NUMBER_STATE_IN_SERVICE, knm_phone_number:state(PhoneNumber)) + } + ]. diff --git a/core/kazoo_number_manager/test/knm_number_test.erl b/core/kazoo_number_manager/test/knm_number_test.erl index 9aa798c9657..994d48e4f92 100644 --- a/core/kazoo_number_manager/test/knm_number_test.erl +++ b/core/kazoo_number_manager/test/knm_number_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% @end %%% @contributors @@ -10,26 +10,17 @@ -include_lib("eunit/include/eunit.hrl"). -include("knm.hrl"). -get_available_test_() -> - [fun available_as_owner/0 - ,fun available_as_parent/0 - ,fun available_as_rando/0 - ]. - -available_as_owner() -> +available_as_owner_test_() -> available_as(?RESELLER_ACCOUNT_ID). -available_as_parent() -> +available_as_parent_test_() -> available_as(?MASTER_ACCOUNT_ID). -available_as_rando() -> +available_as_rando_test_() -> available_as(kz_util:rand_hex_binary(16)). available_as(AuthAccountId) -> - case knm_number:get(?TEST_AVAILABLE_NUM - ,[{'auth_by', AuthAccountId}] - ) - of + case knm_number:get(?TEST_AVAILABLE_NUM, [{'auth_by', AuthAccountId}]) of {'ok', Number} -> available_tests(Number); {'error', Error} -> unavailable_tests(Error) end. @@ -45,7 +36,6 @@ unavailable_tests(ErrorJObj) -> available_tests(Number) -> PhoneNumber = knm_number:phone_number(Number), - [{"Verify available phone number" ,?_assertEqual(?TEST_AVAILABLE_NUM, knm_phone_number:number(PhoneNumber)) } @@ -59,8 +49,6 @@ available_tests(Number) -> get_unreconcilable_number_test_() -> [{"Verify non-reconcilable numbers result in errors" - ,?_assertMatch({'error', 'not_reconcilable'} - ,knm_number:get(<<"1000">>) - ) + ,?_assertMatch({'error', 'not_reconcilable'}, knm_number:get(<<"1000">>)) } ]. diff --git a/core/kazoo_number_manager/test/knm_numbers_test.erl b/core/kazoo_number_manager/test/knm_numbers_test.erl new file mode 100644 index 00000000000..e4e7c9417a8 --- /dev/null +++ b/core/kazoo_number_manager/test/knm_numbers_test.erl @@ -0,0 +1,196 @@ +%%%------------------------------------------------------------------- +%%% @copyright (C) 2017, 2600Hz +%%% @doc +%%% @end +%%% @contributors +%%% Pierre Fenoll +%%%------------------------------------------------------------------- +-module(knm_numbers_test). + +-include_lib("eunit/include/eunit.hrl"). +-include("knm.hrl"). + + +-define(NOT_NUM, <<"NOT a number">>). + +n_x(X, Ret) -> + lists:nth(X, maps:get(ok, Ret)). + +pn_x(X, Ret) -> + knm_number:phone_number(n_x(X, Ret)). + + +get_test_() -> + Ret = knm_numbers:get([?TEST_AVAILABLE_NUM]), + [?_assertEqual(#{}, maps:get(ko, Ret)) + ,?_assertMatch([_], maps:get(ok, Ret)) + ,?_assertEqual(?TEST_AVAILABLE_NUM, knm_phone_number:number(pn_x(1, Ret))) + ,?_assertMatch(#{ko := #{?NOT_NUM := not_reconcilable}} + ,knm_numbers:get([?NOT_NUM], []) + ) + ,?_assertMatch(#{ko := #{?TEST_CREATE_NUM := not_found}} + ,knm_numbers:get([?TEST_CREATE_NUM], []) + ) + ,?_assertMatch(#{ko := #{?NOT_NUM := not_reconcilable} + ,ok := [_] + } + ,knm_numbers:get([?TEST_AVAILABLE_NUM, ?NOT_NUM]) + ) + ,?_assertMatch(#{ko := #{?NOT_NUM := not_reconcilable} + ,ok := [_] + } + ,knm_numbers:get([?TEST_AVAILABLE_NUM, ?NOT_NUM + ,?TEST_AVAILABLE_NUM, ?NOT_NUM]) + ) + ,?_assertMatch(#{ko := #{?NOT_NUM := not_reconcilable + ,?TEST_CREATE_NUM := not_found + } + ,ok := [_] + } + ,knm_numbers:get([?TEST_AVAILABLE_NUM, ?NOT_NUM + ,?TEST_AVAILABLE_NUM, ?NOT_NUM + ,?TEST_CREATE_NUM]) + ) + ]. + + +create_test_e911() -> + kz_json:from_list( + [{?E911_STREET1, <<"301 marina blvd.">>} + ,{?E911_CITY, <<"San Francisco">>} + ,{?E911_STATE, <<"CA">>} + ,{?E911_ZIP, <<"94123">>} + ]). + +create_test_() -> + Num = ?TEST_TELNYX_NUM, + E911 = create_test_e911(), + JObj = kz_json:from_list([{?FEATURE_E911, E911}]), + Options = [{'auth_by', ?MASTER_ACCOUNT_ID} + ,{'assign_to', ?RESELLER_ACCOUNT_ID} + ,{<<"auth_by_account">>, kz_json:new()} + ], + Ret = knm_numbers:create([Num], [{'public_fields', JObj}|Options]), + [?_assertEqual(#{}, maps:get(ko, Ret)) + ,?_assertMatch([_], maps:get(ok, Ret)) + ,?_assertEqual(true, knm_number:is_number(n_x(1, Ret))) + ,?_assertEqual(true, knm_phone_number:is_phone_number(pn_x(1, Ret))) + ,{"Verify feature is properly set" + ,?_assertEqual(E911, knm_phone_number:feature(pn_x(1, Ret), ?FEATURE_E911)) + } + ,{"Verify we are keeping track of intermediary address_id" + ,?_assertEqual(<<"421564943280637078">> + ,kz_json:get_value(<<"address_id">>, knm_phone_number:carrier_data(pn_x(1, Ret))) + ) + } + ,?_assertMatch(#{ko := #{?NOT_NUM := _ + ,?TEST_CREATE_NUM := _ + } + ,ok := [_] + } + ,knm_numbers:create([Num, ?NOT_NUM, ?TEST_CREATE_NUM], Options) + ) + ]. + + +move_test_() -> + Ret = knm_numbers:move([?NOT_NUM, ?TEST_AVAILABLE_NUM], ?CHILD_ACCOUNT_ID), + [?_assertEqual(#{?NOT_NUM => not_reconcilable}, maps:get(ko, Ret)) + ,?_assertMatch([_], maps:get(ok, Ret)) + ,?_assertEqual(?TEST_AVAILABLE_NUM, knm_phone_number:number(pn_x(1, Ret))) + ,{"verify assigned_to is child account" + ,?_assertEqual(?CHILD_ACCOUNT_ID, knm_phone_number:assigned_to(pn_x(1, Ret))) + } + ,{"verify number is in service" + ,?_assertEqual(?NUMBER_STATE_IN_SERVICE, knm_phone_number:state(pn_x(1, Ret))) + } + ]. + + +update_test_() -> + NotDefault = true, + Setters = [{fun knm_phone_number:set_ported_in/2, NotDefault}], + Ret = knm_numbers:update([?NOT_NUM, ?TEST_AVAILABLE_NUM], Setters), + [?_assertEqual(#{?NOT_NUM => not_reconcilable}, maps:get(ko, Ret)) + ,?_assertMatch([_], maps:get(ok, Ret)) + ,{"verify number was indeed updated" + ,?_assertEqual(NotDefault, knm_phone_number:ported_in(pn_x(1, Ret))) + } + ]. + + +delete_test_() -> + Ret = knm_numbers:delete([?NOT_NUM, ?TEST_AVAILABLE_NUM], knm_number_options:default()), + [?_assertEqual(#{?NOT_NUM => not_reconcilable}, maps:get(ko, Ret)) + ,?_assertMatch([_], maps:get(ok, Ret)) + ,{"verify number was indeed deleted" + ,?_assertEqual(?NUMBER_STATE_DELETED, knm_phone_number:state(pn_x(1, Ret))) + } + ]. + + +reconcile_test_() -> + Ret0 = knm_numbers:reconcile([?NOT_NUM], []), + Options = [{assign_to, ?RESELLER_ACCOUNT_ID} | knm_number_options:default()], + Ret = knm_numbers:reconcile([?NOT_NUM, ?TEST_AVAILABLE_NUM], Options), + [?_assertEqual(<<"assign_failure">> + ,knm_errors:error(maps:get(?NOT_NUM, maps:get(ko, Ret0))) + ) + ,?_assertEqual(#{?NOT_NUM => not_reconcilable}, maps:get(ko, Ret)) + ,?_assertMatch([_], maps:get(ok, Ret)) + ,{"verify number is now in service" + ,?_assertEqual(?NUMBER_STATE_IN_SERVICE, knm_phone_number:state(pn_x(1, Ret))) + } + ,{"verify number is indeed owned by account" + ,?_assertEqual(?RESELLER_ACCOUNT_ID, knm_phone_number:assigned_to(pn_x(1, Ret))) + } + ]. + + +reserve_test_() -> + Ret1 = knm_numbers:reserve([?NOT_NUM, ?TEST_AVAILABLE_NUM], knm_number_options:default()), + Ret2 = knm_numbers:reserve([?NOT_NUM, ?TEST_IN_SERVICE_NUM], knm_number_options:default()), + [?_assertEqual(#{?NOT_NUM => not_reconcilable}, maps:get(ko, Ret1)) + ,?_assertMatch([_], maps:get(ok, Ret1)) + ,?_assertEqual(#{?NOT_NUM => not_reconcilable}, maps:get(ko, Ret2)) + ,?_assertMatch([_], maps:get(ok, Ret2)) + ,{"verify number was indeed reserved" + ,?_assertEqual(?NUMBER_STATE_RESERVED, knm_phone_number:state(pn_x(1, Ret1))) + } + ,{"verify number is still in service" + ,?_assertEqual(?NUMBER_STATE_IN_SERVICE, knm_phone_number:state(pn_x(1, Ret2))) + } + ]. + + +assign_to_app_test_() -> + MyApp = <<"my_app">>, + Ret1 = knm_numbers:get([?NOT_NUM, ?TEST_AVAILABLE_NUM]), + Ret2 = knm_numbers:assign_to_app([?NOT_NUM, ?TEST_AVAILABLE_NUM], MyApp), + [?_assertEqual(#{?NOT_NUM => not_reconcilable}, maps:get(ko, Ret1)) + ,?_assertMatch([_], maps:get(ok, Ret1)) + ,{"Verify number is not already assigned to MyApp" + ,?_assertNotEqual(MyApp, knm_phone_number:used_by(pn_x(1, Ret1))) + } + ,?_assertEqual(#{?NOT_NUM => not_reconcilable}, maps:get(ko, Ret2)) + ,?_assertMatch([_], maps:get(ok, Ret2)) + ,{"Verify number is now used by MyApp" + ,?_assertEqual(MyApp, knm_phone_number:used_by(pn_x(1, Ret2))) + } + ]. + + +release_test_() -> + Ret = knm_numbers:release([?NOT_NUM, ?TEST_IN_SERVICE_WITH_HISTORY_NUM]), + Ret1 = knm_numbers:release([?NOT_NUM, ?TEST_IN_SERVICE_NUM]), + [?_assertEqual(#{?NOT_NUM => not_reconcilable}, maps:get(ko, Ret)) + ,?_assertMatch([_], maps:get(ok, Ret)) + ,{"Verify number went from in_service to reserved" + ,?_assertEqual(?NUMBER_STATE_RESERVED, knm_phone_number:state(pn_x(1, Ret))) + } + ,?_assertEqual(#{?NOT_NUM => not_reconcilable}, maps:get(ko, Ret1)) + ,?_assertMatch([_], maps:get(ok, Ret1)) + ,{"Verify number went from in_service to available" + ,?_assertEqual(?NUMBER_STATE_DELETED, knm_phone_number:state(pn_x(1, Ret1))) + } + ]. diff --git a/core/kazoo_number_manager/test/knm_phone_number_test.erl b/core/kazoo_number_manager/test/knm_phone_number_test.erl index 135657d3c35..882507dbbb2 100644 --- a/core/kazoo_number_manager/test/knm_phone_number_test.erl +++ b/core/kazoo_number_manager/test/knm_phone_number_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% @end %%% @contributors @@ -10,16 +10,9 @@ -include_lib("eunit/include/eunit.hrl"). -include("knm.hrl"). --define(FEATURES_AVAILABLE, [<<"cnam">> - ,<<"e911">> - ,<<"failover">> - ,<<"port">> - ,<<"prepend">> - ]). - -is_dirty_test_() -> - {ok, OldPN} = knm_phone_number:fetch(?TEST_OLD_NUM), - JObj = knm_phone_number:to_json(OldPN), +is_dirty1_test_() -> + {ok, PN} = knm_phone_number:fetch(?TEST_OLD_NUM), + JObj = knm_phone_number:to_json(PN), NewJObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_1_out.json"))), OldJObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_1_in.json"))), [?_assertEqual(kz_json:get_value(<<"pvt_assigned_to">>, NewJObj) @@ -36,13 +29,6 @@ is_dirty_test_() -> ,kz_json:get_value(<<"pvt_db_name">>, JObj) ) - ,?_assertEqual(kz_json:get_value(<<"pvt_features_available">>, NewJObj) - ,kz_json:get_value(<<"pvt_features_available">>, JObj) - ) - ,?_assertEqual(kz_json:get_value(<<"pvt_features_available">>, OldJObj) - ,kz_json:get_value(<<"pvt_features_available">>, JObj) - ) - ,?_assertEqual(kz_json:get_value(<<"pvt_module_name">>, NewJObj) ,kz_json:get_value(<<"pvt_module_name">>, JObj) ) @@ -85,10 +71,6 @@ is_dirty_test_() -> ,kz_json:get_value(<<"_id">>, JObj) ) - ,?_assertEqual(undefined, kz_json:get_value(<<"pvt_is_billable">>, OldJObj)) - ,?_assertEqual(false, kz_json:get_value(<<"pvt_is_billable">>, JObj)) - ,?_assertEqual(false, kz_json:get_value(<<"pvt_is_billable">>, NewJObj)) - ,?_assertEqual(<<"undefined">>, kz_json:get_value(<<"pvt_created">>, OldJObj)) ,?_assertNotEqual(<<"undefined">>, kz_json:get_value(<<"pvt_created">>, JObj)) ,?_assertNotEqual(<<"undefined">>, kz_json:get_value(<<"pvt_created">>, NewJObj)) @@ -112,8 +94,8 @@ is_dirty_test_() -> is_dirty2_test_() -> - {ok, OldPN} = knm_phone_number:fetch(?TEST_OLD2_NUM), - JObj = knm_phone_number:to_json(OldPN), + {ok, PN} = knm_phone_number:fetch(?TEST_OLD2_NUM), + JObj = knm_phone_number:to_json(PN), NewJObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_2_out.json"))), OldJObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_2_in.json"))), [?_assertEqual(kz_json:get_value(<<"pvt_assigned_to">>, NewJObj) @@ -151,10 +133,6 @@ is_dirty2_test_() -> ,kz_json:get_value(<<"_id">>, JObj) ) - ,?_assertEqual(undefined, kz_json:get_value(<<"pvt_features_available">>, OldJObj)) - ,?_assertEqual(?FEATURES_AVAILABLE, kz_json:get_value(<<"pvt_features_available">>, JObj)) - ,?_assertEqual(?FEATURES_AVAILABLE, kz_json:get_value(<<"pvt_features_available">>, NewJObj)) - ,?_assertEqual(<<"wnm_pacwest">>, kz_json:get_value(<<"pvt_module_name">>, OldJObj)) ,?_assertEqual(<<"knm_pacwest">>, kz_json:get_value(<<"pvt_module_name">>, JObj)) ,?_assertEqual(<<"knm_pacwest">>, kz_json:get_value(<<"pvt_module_name">>, NewJObj)) @@ -167,10 +145,6 @@ is_dirty2_test_() -> ,?_assertEqual(<<"in_service">>, kz_json:get_value(<<"pvt_state">>, JObj)) ,?_assertEqual(<<"in_service">>, kz_json:get_value(<<"pvt_state">>, NewJObj)) - ,?_assertEqual(undefined, kz_json:get_value(<<"pvt_is_billable">>, OldJObj)) - ,?_assertEqual(false, kz_json:get_value(<<"pvt_is_billable">>, JObj)) - ,?_assertEqual(false, kz_json:get_value(<<"pvt_is_billable">>, NewJObj)) - ,?_assertEqual(63637990840, kz_json:get_value(<<"pvt_created">>, OldJObj)) ,?_assertEqual(63637990840, kz_json:get_value(<<"pvt_created">>, JObj)) ,?_assertEqual(63637990840, kz_json:get_value(<<"pvt_created">>, NewJObj)) @@ -193,3 +167,325 @@ is_dirty2_test_() -> ,?_assertEqual(?KNM_DEFAULT_AUTH_BY, kz_json:get_value(<<"pvt_authorizing_account">>, JObj)) ,?_assertEqual(?KNM_DEFAULT_AUTH_BY, kz_json:get_value(<<"pvt_authorizing_account">>, NewJObj)) ]. + + +is_dirty3_test_() -> + {ok, PN} = knm_phone_number:fetch(?TEST_OLD3_NUM), + JObj = knm_phone_number:to_json(PN), + NewJObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_3_out.json"))), + OldJObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_3_in.json"))), + [?_assertEqual(kz_json:get_value(<<"pvt_assigned_to">>, NewJObj) + ,kz_json:get_value(<<"pvt_assigned_to">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_assigned_to">>, OldJObj) + ,kz_json:get_value(<<"pvt_assigned_to">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"pvt_db_name">>, NewJObj) + ,kz_json:get_value(<<"pvt_db_name">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_db_name">>, OldJObj) + ,kz_json:get_value(<<"pvt_db_name">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"pvt_reserve_history">>, NewJObj) + ,kz_json:get_value(<<"pvt_reserve_history">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_reserve_history">>, OldJObj) + ,kz_json:get_value(<<"pvt_reserve_history">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"pvt_type">>, NewJObj) + ,kz_json:get_value(<<"pvt_type">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_type">>, OldJObj) + ,kz_json:get_value(<<"pvt_type">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"_id">>, NewJObj) + ,kz_json:get_value(<<"_id">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"_id">>, OldJObj) + ,kz_json:get_value(<<"_id">>, JObj) + ) + + ,?_assertEqual(<<"knm_bandwidth2">>, kz_json:get_value(<<"pvt_module_name">>, OldJObj)) + ,?_assertEqual(<<"knm_bandwidth2">>, kz_json:get_value(<<"pvt_module_name">>, JObj)) + ,?_assertEqual(<<"knm_bandwidth2">>, kz_json:get_value(<<"pvt_module_name">>, NewJObj)) + + ,?_assertEqual(undefined, kz_json:get_value(<<"pvt_ported_in">>, OldJObj)) + ,?_assertEqual(false, kz_json:get_value(<<"pvt_ported_in">>, JObj)) + ,?_assertEqual(false, kz_json:get_value(<<"pvt_ported_in">>, NewJObj)) + + ,?_assertEqual(<<"in_service">>, kz_json:get_value(<<"pvt_number_state">>, OldJObj)) + ,?_assertEqual(<<"in_service">>, kz_json:get_value(<<"pvt_state">>, JObj)) + ,?_assertEqual(<<"in_service">>, kz_json:get_value(<<"pvt_state">>, NewJObj)) + + ,?_assertEqual(63646110391, kz_json:get_value(<<"pvt_created">>, OldJObj)) + ,?_assertEqual(63646110391, kz_json:get_value(<<"pvt_created">>, JObj)) + ,?_assertEqual(63646110391, kz_json:get_value(<<"pvt_created">>, NewJObj)) + + ,?_assertEqual(63646110391, kz_json:get_value(<<"pvt_modified">>, OldJObj)) + ,?_assertNotEqual(63646110391, kz_json:get_value(<<"pvt_modified">>, JObj)) + ,?_assertNotEqual(63646110391, kz_json:get_value(<<"pvt_modified">>, NewJObj)) + ,?_assertEqual(true, is_integer(kz_json:get_value(<<"pvt_modified">>, JObj))) + ,?_assertEqual(true, is_integer(kz_json:get_value(<<"pvt_modified">>, NewJObj))) + + ,?_assertEqual(kz_json:to_map(kz_json:get_value(<<"pvt_features">>, OldJObj)) + ,kz_json:to_map(kz_json:get_value(<<"pvt_features">>, JObj))) + ,?_assertEqual(kz_json:to_map(kz_json:get_value(<<"pvt_features">>, OldJObj)) + ,kz_json:to_map(kz_json:get_value(<<"pvt_features">>, NewJObj))) + + ,?_assertEqual(<<"callflow">>, kz_json:get_value(<<"used_by">>, OldJObj)) + ,?_assertEqual(<<"callflow">>, kz_json:get_value(<<"pvt_used_by">>, JObj)) + ,?_assertEqual(<<"callflow">>, kz_json:get_value(<<"pvt_used_by">>, NewJObj)) + ]. + + +is_dirty4_test_() -> + {ok, PN} = knm_phone_number:fetch(?TEST_OLD4_NUM), + JObj = knm_phone_number:to_json(PN), + NewJObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_4_out.json"))), + OldJObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_4_in.json"))), + [?_assertEqual(kz_json:get_value(<<"pvt_assigned_to">>, NewJObj) + ,kz_json:get_value(<<"pvt_assigned_to">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_assigned_to">>, OldJObj) + ,kz_json:get_value(<<"pvt_assigned_to">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"pvt_db_name">>, NewJObj) + ,kz_json:get_value(<<"pvt_db_name">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_db_name">>, OldJObj) + ,kz_json:get_value(<<"pvt_db_name">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"pvt_reserve_history">>, NewJObj) + ,kz_json:get_value(<<"pvt_reserve_history">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_reserve_history">>, OldJObj) + ,kz_json:get_value(<<"pvt_reserve_history">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"pvt_type">>, NewJObj) + ,kz_json:get_value(<<"pvt_type">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_type">>, OldJObj) + ,kz_json:get_value(<<"pvt_type">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"_id">>, NewJObj) + ,kz_json:get_value(<<"_id">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"_id">>, OldJObj) + ,kz_json:get_value(<<"_id">>, JObj) + ) + + ,?_assertEqual(<<"wnm_local">>, kz_json:get_value(<<"pvt_module_name">>, OldJObj)) + ,?_assertEqual(<<"knm_local">>, kz_json:get_value(<<"pvt_module_name">>, JObj)) + ,?_assertEqual(<<"knm_local">>, kz_json:get_value(<<"pvt_module_name">>, NewJObj)) + + ,?_assertEqual(undefined, kz_json:get_value(<<"pvt_ported_in">>, OldJObj)) + ,?_assertEqual(false, kz_json:get_value(<<"pvt_ported_in">>, JObj)) + ,?_assertEqual(false, kz_json:get_value(<<"pvt_ported_in">>, NewJObj)) + + ,?_assertEqual(<<"reserved">>, kz_json:get_value(<<"pvt_number_state">>, OldJObj)) + ,?_assertEqual(<<"reserved">>, kz_json:get_value(<<"pvt_state">>, JObj)) + ,?_assertEqual(<<"reserved">>, kz_json:get_value(<<"pvt_state">>, NewJObj)) + + ,?_assertEqual(63627551737, kz_json:get_value(<<"pvt_created">>, OldJObj)) + ,?_assertEqual(63627551737, kz_json:get_value(<<"pvt_created">>, JObj)) + ,?_assertEqual(63627551737, kz_json:get_value(<<"pvt_created">>, NewJObj)) + + ,?_assertEqual(63627551739, kz_json:get_value(<<"pvt_modified">>, OldJObj)) + ,?_assertNotEqual(63627551739, kz_json:get_value(<<"pvt_modified">>, JObj)) + ,?_assertNotEqual(63627551739, kz_json:get_value(<<"pvt_modified">>, NewJObj)) + ,?_assertEqual(true, is_integer(kz_json:get_value(<<"pvt_modified">>, JObj))) + ,?_assertEqual(true, is_integer(kz_json:get_value(<<"pvt_modified">>, NewJObj))) + + ,?_assertEqual([], kz_json:get_value(<<"pvt_features">>, OldJObj)) + ,?_assertEqual(#{<<"local">> => #{}} + ,kz_json:to_map(kz_json:get_value(<<"pvt_features">>, JObj))) + ,?_assertEqual(#{<<"local">> => #{}} + ,kz_json:to_map(kz_json:get_value(<<"pvt_features">>, NewJObj))) + + ,?_assertEqual(<<>>, kz_json:get_value(<<"used_by">>, OldJObj)) + ,?_assertEqual(undefined, kz_json:get_value(<<"pvt_used_by">>, JObj)) + ,?_assertEqual(undefined, kz_json:get_value(<<"pvt_used_by">>, NewJObj)) + + ,?_assertEqual(kz_json:to_map(kz_json:public_fields(JObj)) + ,kz_json:to_map(kz_json:public_fields(NewJObj))) + ,?_assertEqual(maps:remove(<<"e911">>, kz_json:to_map(kz_json:public_fields(JObj))) + ,kz_json:to_map(kz_json:public_fields(kz_json:delete_key(<<"used_by">>, OldJObj)))) + ]. + + +maps_take(Key, Map) -> + {maps:get(Key, Map), maps:remove(Key, Map)}. + +features_5(OldJObj) -> + OldFeatures = kz_json:to_map(kz_json:get_value(<<"pvt_features">>, OldJObj)), + {E911, M} = maps_take(?LEGACY_DASH_E911, OldFeatures), + M#{<<"e911">> => E911}. + +public_fields_new_5(OldJObj) -> + M = kz_json:to_map( + kz_json:public_fields( + kz_json:delete_key(<<"used_by">>, OldJObj))), + M#{<<"e911">> => maps:get(?LEGACY_DASH_E911, M)}. + +is_dirty5_test_() -> + {ok, PN} = knm_phone_number:fetch(?TEST_OLD5_NUM), + JObj = knm_phone_number:to_json(PN), + NewJObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_5_out.json"))), + OldJObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_5_in.json"))), + [?_assertEqual(kz_json:get_value(<<"pvt_assigned_to">>, NewJObj) + ,kz_json:get_value(<<"pvt_assigned_to">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_assigned_to">>, OldJObj) + ,kz_json:get_value(<<"pvt_assigned_to">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"pvt_db_name">>, NewJObj) + ,kz_json:get_value(<<"pvt_db_name">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_db_name">>, OldJObj) + ,kz_json:get_value(<<"pvt_db_name">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"pvt_reserve_history">>, NewJObj) + ,kz_json:get_value(<<"pvt_reserve_history">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_reserve_history">>, OldJObj) + ,kz_json:get_value(<<"pvt_reserve_history">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"pvt_type">>, NewJObj) + ,kz_json:get_value(<<"pvt_type">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_type">>, OldJObj) + ,kz_json:get_value(<<"pvt_type">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"_id">>, NewJObj) + ,kz_json:get_value(<<"_id">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"_id">>, OldJObj) + ,kz_json:get_value(<<"_id">>, JObj) + ) + + ,?_assertEqual(<<"knm_bandwidth2">>, kz_json:get_value(<<"pvt_module_name">>, OldJObj)) + ,?_assertEqual(<<"knm_bandwidth2">>, kz_json:get_value(<<"pvt_module_name">>, JObj)) + ,?_assertEqual(<<"knm_bandwidth2">>, kz_json:get_value(<<"pvt_module_name">>, NewJObj)) + + ,?_assertEqual(undefined, kz_json:get_value(<<"pvt_ported_in">>, OldJObj)) + ,?_assertEqual(false, kz_json:get_value(<<"pvt_ported_in">>, JObj)) + ,?_assertEqual(false, kz_json:get_value(<<"pvt_ported_in">>, NewJObj)) + + ,?_assertEqual(<<"in_service">>, kz_json:get_value(<<"pvt_number_state">>, OldJObj)) + ,?_assertEqual(undefined, kz_json:get_value(<<"pvt_state">>, OldJObj)) + ,?_assertEqual(<<"in_service">>, kz_json:get_value(<<"pvt_state">>, JObj)) + ,?_assertEqual(<<"in_service">>, kz_json:get_value(<<"pvt_state">>, NewJObj)) + + ,?_assertEqual(undefined, kz_json:get_value(<<"pvt_created">>, OldJObj)) + ,?_assertEqual(true, is_integer(kz_json:get_value(<<"pvt_created">>, JObj))) + ,?_assertEqual(true, is_integer(kz_json:get_value(<<"pvt_created">>, NewJObj))) + + ,?_assertEqual(undefined, kz_json:get_value(<<"pvt_modified">>, OldJObj)) + ,?_assertEqual(true, is_integer(kz_json:get_value(<<"pvt_modified">>, JObj))) + ,?_assertEqual(true, is_integer(kz_json:get_value(<<"pvt_modified">>, NewJObj))) + + ,?_assertEqual(features_5(OldJObj) + ,kz_json:to_map(kz_json:get_value(<<"pvt_features">>, JObj))) + ,?_assertEqual(features_5(OldJObj) + ,kz_json:to_map(kz_json:get_value(<<"pvt_features">>, NewJObj))) + + ,?_assertEqual(<<"trunkstore">>, kz_json:get_value(<<"used_by">>, OldJObj)) + ,?_assertEqual(undefined, kz_json:get_value(<<"used_by">>, JObj)) + ,?_assertEqual(undefined, kz_json:get_value(<<"used_by">>, NewJObj)) + ,?_assertEqual(undefined, kz_json:get_value(<<"pvt_used_by">>, JObj)) + ,?_assertEqual(undefined, kz_json:get_value(<<"pvt_used_by">>, NewJObj)) + + ,?_assertEqual(public_fields_new_5(OldJObj), kz_json:to_map(kz_json:public_fields(JObj))) + ,?_assertEqual(public_fields_new_5(OldJObj), kz_json:to_map(kz_json:public_fields(NewJObj))) + ]. + + +is_dirty6_test_() -> + {ok, PN} = knm_phone_number:fetch(?TEST_OLD6_NUM), + JObj = knm_phone_number:to_json(PN), + NewJObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_6_out.json"))), + OldJObj = kz_json:decode(list_to_binary(knm_util:fixture("old_vsn_6_in.json"))), + [?_assertEqual(kz_json:get_value(<<"pvt_assigned_to">>, NewJObj) + ,kz_json:get_value(<<"pvt_assigned_to">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_assigned_to">>, OldJObj) + ,kz_json:get_value(<<"pvt_assigned_to">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"pvt_db_name">>, NewJObj) + ,kz_json:get_value(<<"pvt_db_name">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_db_name">>, OldJObj) + ,kz_json:get_value(<<"pvt_db_name">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"pvt_reserve_history">>, NewJObj) + ,kz_json:get_value(<<"pvt_reserve_history">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_reserve_history">>, OldJObj) + ,kz_json:get_value(<<"pvt_reserve_history">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"pvt_type">>, NewJObj) + ,kz_json:get_value(<<"pvt_type">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"pvt_type">>, OldJObj) + ,kz_json:get_value(<<"pvt_type">>, JObj) + ) + + ,?_assertEqual(kz_json:get_value(<<"_id">>, NewJObj) + ,kz_json:get_value(<<"_id">>, JObj) + ) + ,?_assertEqual(kz_json:get_value(<<"_id">>, OldJObj) + ,kz_json:get_value(<<"_id">>, JObj) + ) + + ,?_assertEqual(<<"knm_local">>, kz_json:get_value(<<"pvt_module_name">>, OldJObj)) + ,?_assertEqual(<<"knm_local">>, kz_json:get_value(<<"pvt_module_name">>, JObj)) + ,?_assertEqual(<<"knm_local">>, kz_json:get_value(<<"pvt_module_name">>, NewJObj)) + + ,?_assertEqual(undefined, kz_json:get_value(<<"pvt_ported_in">>, OldJObj)) + ,?_assertEqual(false, kz_json:get_value(<<"pvt_ported_in">>, JObj)) + ,?_assertEqual(false, kz_json:get_value(<<"pvt_ported_in">>, NewJObj)) + + ,?_assertEqual(<<"in_service">>, kz_json:get_value(<<"pvt_state">>, OldJObj)) + ,?_assertEqual(<<"in_service">>, kz_json:get_value(<<"pvt_state">>, JObj)) + ,?_assertEqual(<<"in_service">>, kz_json:get_value(<<"pvt_state">>, NewJObj)) + + ,?_assertEqual(63640935218, kz_json:get_value(<<"pvt_created">>, OldJObj)) + ,?_assertEqual(63640935218, kz_json:get_value(<<"pvt_created">>, JObj)) + ,?_assertEqual(63640935218, kz_json:get_value(<<"pvt_created">>, NewJObj)) + + ,?_assertEqual(63640935218, kz_json:get_value(<<"pvt_modified">>, OldJObj)) + ,?_assertNotEqual(63640935218, kz_json:get_value(<<"pvt_modified">>, JObj)) + ,?_assertNotEqual(63640935218, kz_json:get_value(<<"pvt_modified">>, NewJObj)) + ,?_assertEqual(true, is_integer(kz_json:get_value(<<"pvt_modified">>, JObj))) + ,?_assertEqual(true, is_integer(kz_json:get_value(<<"pvt_modified">>, NewJObj))) + + ,?_assertEqual(kz_json:to_map(kz_json:get_value(<<"pvt_features">>, OldJObj)) + ,kz_json:to_map(kz_json:get_value(<<"pvt_features">>, JObj))) + ,?_assertEqual(kz_json:to_map(kz_json:get_value(<<"pvt_features">>, OldJObj)) + ,kz_json:to_map(kz_json:get_value(<<"pvt_features">>, NewJObj))) + + ,?_assertEqual(<<"trunkstore">>, kz_json:get_value(<<"used_by">>, OldJObj)) + ,?_assertEqual(<<"trunkstore">>, kz_json:get_value(<<"pvt_used_by">>, OldJObj)) + ,?_assertEqual(<<"trunkstore">>, kz_json:get_value(<<"pvt_used_by">>, JObj)) + ,?_assertEqual(<<"trunkstore">>, kz_json:get_value(<<"pvt_used_by">>, NewJObj)) + + ,?_assertEqual(kz_json:to_map(kz_json:public_fields(JObj)) + ,kz_json:to_map(kz_json:public_fields(NewJObj))) + ,?_assertEqual(kz_json:to_map(kz_json:public_fields(JObj)) + ,kz_json:to_map(kz_json:public_fields(kz_json:delete_key(<<"used_by">>, OldJObj)))) + ]. diff --git a/core/kazoo_number_manager/test/knm_reconcile_test.erl b/core/kazoo_number_manager/test/knm_reconcile_test.erl index f4566162b8a..c170191d8e3 100644 --- a/core/kazoo_number_manager/test/knm_reconcile_test.erl +++ b/core/kazoo_number_manager/test/knm_reconcile_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% @end %%% @contributors diff --git a/core/kazoo_number_manager/test/knm_release_number_test.erl b/core/kazoo_number_manager/test/knm_release_number_test.erl index 0326b356d7e..2bd8fa58df0 100644 --- a/core/kazoo_number_manager/test/knm_release_number_test.erl +++ b/core/kazoo_number_manager/test/knm_release_number_test.erl @@ -1,62 +1,55 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% @end %%% @contributors %%% James Aimonetti +%%% Pierre Fenoll %%%------------------------------------------------------------------- -module(knm_release_number_test). -include_lib("eunit/include/eunit.hrl"). -include("knm.hrl"). -release_number_test_() -> - Tests = [fun release_unknown_number/1 - ,fun release_available_number/1 - ,fun release_in_service_number/1 - ,fun release_with_history/1 - ,fun release_for_hard_delete/1 - ], - lists:foldl(fun(F, Acc) -> - F(Acc) - end, [], Tests - ). - -release_unknown_number(Tests) -> +release_unknown_number_test_() -> [{"verfiy missing numbers return errors" - ,?_assertMatch( - {'error', 'not_found'} - ,knm_number:release(?TEST_CREATE_NUM) - ) + ,?_assertMatch({'error', 'not_found'}, knm_number:release(?TEST_CREATE_NUM)) } - | Tests ]. -release_available_number(Tests) -> +release_available_number_test_() -> {'error', Error} = knm_number:release(?TEST_AVAILABLE_NUM), - [{"Verify error code for releasing available number" ,?_assertEqual(400, knm_errors:code(Error)) } ,{"Verify error for releasing available number" ,?_assertEqual(<<"invalid_state_transition">>, knm_errors:error(Error)) } - | Tests ]. -release_in_service_number(Tests) -> +release_in_service_bad_carrier_number_test_() -> + {'ok', Released} = knm_number:release(?TEST_IN_SERVICE_BAD_CARRIER_NUM), + PhoneNumber = knm_number:phone_number(Released), + [{"verify number state is changed" + ,?_assertEqual(?NUMBER_STATE_AVAILABLE, knm_phone_number:state(PhoneNumber)) + } + ,{"verify reserve history is empty now" + ,?_assertEqual([], knm_phone_number:reserve_history(PhoneNumber)) + } + ]. + +release_in_service_number_test_() -> {'ok', Released} = knm_number:release(?TEST_IN_SERVICE_NUM), PhoneNumber = knm_number:phone_number(Released), [{"verify number state is changed" - ,?_assertEqual(knm_config:released_state(), knm_phone_number:state(PhoneNumber)) + ,?_assertNotEqual(?NUMBER_STATE_IN_SERVICE, knm_phone_number:state(PhoneNumber)) } ,{"verify reserve history is empty now" ,?_assertEqual([], knm_phone_number:reserve_history(PhoneNumber)) } - | Tests ]. -release_with_history(Tests) -> +release_with_history_test_() -> {'ok', Unwound} = knm_number:release(?TEST_IN_SERVICE_WITH_HISTORY_NUM), PhoneNumber = knm_number:phone_number(Unwound), [{"verify number state is moved to RESERVED" @@ -68,14 +61,21 @@ release_with_history(Tests) -> ,{"verify number is assigned to prev account" ,?_assertEqual(?MASTER_ACCOUNT_ID, knm_phone_number:assigned_to(PhoneNumber)) } - | Tests ]. -release_for_hard_delete(Tests) -> +release_for_hard_delete_test_() -> {'ok', Deleted} = knm_number:release(?TEST_IN_SERVICE_NUM, [{'should_delete', 'true'}]), PhoneNumber = knm_number:phone_number(Deleted), [{"verify number state is moved to DELETED" ,?_assertEqual(?NUMBER_STATE_DELETED, knm_phone_number:state(PhoneNumber)) } - | Tests + ]. + +release_mdn_test_() -> + {'ok', Deleted} = knm_number:release(?TEST_IN_SERVICE_MDN), + PhoneNumber = knm_number:phone_number(Deleted), + [{"verify number state is moved to DELETED" + ,?_assertEqual(?NUMBER_STATE_DELETED, knm_phone_number:state(PhoneNumber)) + } + ,?_assertEqual(?CARRIER_MDN, knm_phone_number:module_name(PhoneNumber)) ]. diff --git a/core/kazoo_number_manager/test/knm_telnyx_test.erl b/core/kazoo_number_manager/test/knm_telnyx_test.erl index 991479d75df..8de36207760 100644 --- a/core/kazoo_number_manager/test/knm_telnyx_test.erl +++ b/core/kazoo_number_manager/test/knm_telnyx_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% @end %%% @contributors @@ -13,14 +13,19 @@ api_test_() -> Options = [{'account_id', ?RESELLER_ACCOUNT_ID} ,{'carriers', [<<"knm_telnyx">>]} + ,{'query_id', <<"QID">>} ], - [find_numbers(Options) - ,find_international_numbers(Options) - ,acquire_number() - ]. - + {setup + ,fun () -> {'ok', Pid} = knm_search:start_link(), Pid end + ,fun gen_server:stop/1 + ,fun (_ReturnOfSetup) -> + [find_numbers(Options) + ,find_international_numbers(Options) + ] + end + }. -find_numbers(Options) -> +find_numbers(Options0) -> [[{"Verify found numbers" ,?_assertEqual(Limit, length(Results)) } @@ -31,12 +36,15 @@ find_numbers(Options) -> || {Prefix, Limit} <- [{<<"301359">>, 5} ,{<<"800">>, 2} ], - Results <- [knm_carriers:find(Prefix, [{'quantity',Limit}|Options])] + Options <- [[{quantity, Limit} + ,{prefix, Prefix} + | Options0 + ]], + Results <- [knm_search:find(Options)] ]. find_international_numbers(Options0) -> Country = <<"GB">>, - Options = [{'country', Country} | Options0], [[{"Verify found numbers" ,?_assertEqual(Limit, length(Results)) } @@ -46,7 +54,12 @@ find_international_numbers(Options0) -> ] || {Prefix, Limit} <- [{<<"1">>, 2} ], - Results <- [knm_carriers:find(Prefix, [{'quantity',Limit}|Options])] + Options <- [[{country, Country} + ,{quantity, Limit} + ,{prefix, Prefix} + | Options0 + ]], + Results <- [knm_search:find(Options)] ]. matcher(Dialcode, Prefix) -> @@ -59,8 +72,8 @@ matcher(Dialcode, Prefix) -> end end. -acquire_number() -> - N = <<"+14352154006">>, +acquire_number_test_() -> + N = ?TEST_TELNYX_NUM, PhoneNumber = knm_phone_number:set_number(knm_phone_number:new(), N), Number = knm_number:set_phone_number(knm_number:new(), PhoneNumber), Result = knm_telnyx:acquire_number(Number), @@ -82,8 +95,8 @@ e911_test_() -> ,{<<"auth_by_account">>, kz_json:new()} ,{'public_fields', JObj} ], - {'ok', N1} = knm_number:create(?TEST_AVAILABLE_NUM, Options), - {'ok', N2} = knm_number:update_phone_number(N1, [{fun knm_phone_number:reset_doc/2, JObj}]), + {'ok', N1} = knm_number:create(?TEST_TELNYX_NUM, Options), + #{'ok' := [N2]} = knm_numbers:update([N1], [{fun knm_phone_number:reset_doc/2, JObj}]), PN1 = knm_number:phone_number(N1), PN2 = knm_number:phone_number(N2), [{"Verify feature is properly set" @@ -115,8 +128,8 @@ cnam_test_() -> ,{<<"auth_by_account">>, kz_json:new()} ,{'public_fields', JObj} ], - {'ok', N1} = knm_number:create(?TEST_AVAILABLE_NUM, Options), - {'ok', N2} = knm_number:update_phone_number(N1, [{fun knm_phone_number:reset_doc/2, JObj}]), + {'ok', N1} = knm_number:create(?TEST_TELNYX_NUM, Options), + #{'ok' := [N2]} = knm_numbers:update([N1], [{fun knm_phone_number:reset_doc/2, JObj}]), PN1 = knm_number:phone_number(N1), PN2 = knm_number:phone_number(N2), [{"Verify inbound CNAM is properly activated" diff --git a/core/kazoo_number_manager/test/knm_util_test.erl b/core/kazoo_number_manager/test/knm_util_test.erl index 4cce8bb13dc..92c8f9c0f60 100644 --- a/core/kazoo_number_manager/test/knm_util_test.erl +++ b/core/kazoo_number_manager/test/knm_util_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% diff --git a/core/kazoo_number_manager/test/knm_vitelity_find_test.erl b/core/kazoo_number_manager/test/knm_vitelity_find_test.erl index 53781569043..9e66426f4f4 100644 --- a/core/kazoo_number_manager/test/knm_vitelity_find_test.erl +++ b/core/kazoo_number_manager/test/knm_vitelity_find_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% @end %%% @contributors @@ -11,47 +11,55 @@ -include("knm.hrl"). find_test_() -> - [tollfree_tests() - ,local_number_tests() - ,local_prefix_tests() - ]. - -tollfree_tests() -> Options = [{'account_id', ?RESELLER_ACCOUNT_ID} ,{'carriers', [<<"knm_vitelity">>]} - ,{'quantity', 1} + ,{'query_id', <<"QID">>} ], - <<"+1", Num/binary>> = ?TEST_CREATE_TOLL, - [Result] = knm_carriers:find(Num, Options), - [Result] = knm_carriers:find(Num, [{'tollfree','true'}|Options]), + {setup + ,fun () -> {'ok', Pid} = knm_search:start_link(), Pid end + ,fun gen_server:stop/1 + ,fun (_ReturnOfSetup) -> + [tollfree_tests(Options) + ,local_number_tests(Options) + ,local_prefix_tests(Options) + ] + end + }. +tollfree_tests(Options0) -> + <<"+1", Num/binary>> = ?TEST_CREATE_TOLL, + Options = [{'prefix', Num} + ,{'quantity', 1} + | Options0 + ], + [Result] = knm_search:find(Options), [{"Verify found number" ,?_assertEqual(?TEST_CREATE_TOLL, kz_json:get_value(<<"number">>, Result)) } - ,{"Verify activation charge found" - ,?_assertEqual(1.0, kz_json:get_value(<<"activation_charge">>, Result)) - } + ,?_assertEqual([Result], knm_search:find([{'tollfree','true'}|Options])) ]. -local_number_tests() -> +local_number_tests(Options0) -> Limit = 1, - Options = [{'account_id', ?RESELLER_ACCOUNT_ID} - ,{'carriers', [<<"knm_vitelity">>]} + Prefix = <<"9875559876">>, + Options = [{'prefix', Prefix} ,{'quantity', Limit} + | Options0 ], - Results = knm_carriers:find(<<"9875559876">>, Options), + Results = knm_search:find(Options), [{"Verify local number search result size" ,?_assertEqual(Limit, length(Results)) } ]. -local_prefix_tests() -> +local_prefix_tests(Options0) -> Limit = 2, - Options = [{'account_id', ?RESELLER_ACCOUNT_ID} - ,{'carriers', [<<"knm_vitelity">>]} + Prefix = <<"987">>, + Options = [{'prefix', Prefix} ,{'quantity', Limit} + | Options0 ], - Results = knm_carriers:find(<<"987">>, Options), + Results = knm_search:find(Options), [{"Verify local prefix search result size" ,?_assertEqual(Limit, length(Results)) } diff --git a/core/kazoo_number_manager/test/knm_voip_innovations_test.erl b/core/kazoo_number_manager/test/knm_voip_innovations_test.erl index 72c988649dd..808aa82c448 100644 --- a/core/kazoo_number_manager/test/knm_voip_innovations_test.erl +++ b/core/kazoo_number_manager/test/knm_voip_innovations_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% @end %%% @contributors @@ -13,14 +13,18 @@ api_test_() -> Options = [{'account_id', ?RESELLER_ACCOUNT_ID} ,{'carriers', [<<"knm_voip_innovations">>]} + ,{'query_id', <<"QID">>} ], - [find_numbers(Options) - ,acquire_number() - ,disconnect_number() - ]. - + {setup + ,fun () -> {'ok', Pid} = knm_search:start_link(), Pid end + ,fun gen_server:stop/1 + ,fun (_ReturnOfSetup) -> + [find_numbers(Options) + ] + end + }. -find_numbers(Options) -> +find_numbers(Options0) -> [[{"Verify found numbers" ,?_assertEqual(Limit, length(Results)) } @@ -31,7 +35,11 @@ find_numbers(Options) -> || {Prefix, Limit} <- [{<<"435">>, 2} ,{<<"877">>, 1} ], - Results <- [knm_carriers:find(Prefix, [{'quantity',Limit}|Options])] + Options <- [[{quantity, Limit} + ,{prefix, Prefix} + | Options0 + ]], + Results <- [knm_search:find(Options)] ]. matcher(Prefix) -> @@ -43,7 +51,7 @@ matcher(Prefix) -> end end. -acquire_number() -> +acquire_number_test_() -> N = <<"+14352154006">>, PhoneNumber = knm_phone_number:set_number(knm_phone_number:new(), N), Number = knm_number:set_phone_number(knm_number:new(), PhoneNumber), @@ -53,7 +61,7 @@ acquire_number() -> } ]. -disconnect_number() -> +disconnect_number_test_() -> N = <<"+14352154974">>, PhoneNumber = knm_phone_number:set_number(knm_phone_number:new(), N), Number = knm_number:set_phone_number(knm_number:new(), PhoneNumber), diff --git a/core/kazoo_services/src/bookkeepers/kz_bookkeeper_braintree.erl b/core/kazoo_services/src/bookkeepers/kz_bookkeeper_braintree.erl index fb3eeaa84cc..6684796fda6 100644 --- a/core/kazoo_services/src/bookkeepers/kz_bookkeeper_braintree.erl +++ b/core/kazoo_services/src/bookkeepers/kz_bookkeeper_braintree.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/bookkeepers/kz_bookkeeper_http.erl b/core/kazoo_services/src/bookkeepers/kz_bookkeeper_http.erl index 6375d489ed5..4161b63f6bf 100644 --- a/core/kazoo_services/src/bookkeepers/kz_bookkeeper_http.erl +++ b/core/kazoo_services/src/bookkeepers/kz_bookkeeper_http.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/bookkeepers/kz_bookkeeper_local.erl b/core/kazoo_services/src/bookkeepers/kz_bookkeeper_local.erl index 8a261a30cfa..8a46c76af87 100644 --- a/core/kazoo_services/src/bookkeepers/kz_bookkeeper_local.erl +++ b/core/kazoo_services/src/bookkeepers/kz_bookkeeper_local.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/kazoo_services_app.erl b/core/kazoo_services/src/kazoo_services_app.erl index 4c1d6930226..a22b9fd0bf6 100644 --- a/core/kazoo_services/src/kazoo_services_app.erl +++ b/core/kazoo_services/src/kazoo_services_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/kazoo_services_maintenance.erl b/core/kazoo_services/src/kazoo_services_maintenance.erl index 200f8fe2891..35f23b92278 100644 --- a/core/kazoo_services/src/kazoo_services_maintenance.erl +++ b/core/kazoo_services/src/kazoo_services_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/kazoo_services_sup.erl b/core/kazoo_services/src/kazoo_services_sup.erl index 796a591b71d..27abea5fa6d 100644 --- a/core/kazoo_services/src/kazoo_services_sup.erl +++ b/core/kazoo_services/src/kazoo_services_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/kz_service_item.erl b/core/kazoo_services/src/kz_service_item.erl index 70f393fb39e..287262deca2 100644 --- a/core/kazoo_services/src/kz_service_item.erl +++ b/core/kazoo_services/src/kz_service_item.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/kz_service_items.erl b/core/kazoo_services/src/kz_service_items.erl index bb02c8ebe8c..d5a6a2914aa 100644 --- a/core/kazoo_services/src/kz_service_items.erl +++ b/core/kazoo_services/src/kz_service_items.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/kz_service_plan.erl b/core/kazoo_services/src/kz_service_plan.erl index 6ec2bd35264..3723f850bed 100644 --- a/core/kazoo_services/src/kz_service_plan.erl +++ b/core/kazoo_services/src/kz_service_plan.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/kz_service_plans.erl b/core/kazoo_services/src/kz_service_plans.erl index ef9482938ca..fea72bd1809 100644 --- a/core/kazoo_services/src/kz_service_plans.erl +++ b/core/kazoo_services/src/kz_service_plans.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end @@ -29,8 +29,10 @@ ,plans = [] :: kzd_service_plan:docs() }). --type plans() :: [#kz_service_plans{}]. --export_type([plans/0]). +-type plan() :: #kz_service_plans{}. +-type plans() :: [plan()]. + +-export_type([plan/0, plans/0]). %%-------------------------------------------------------------------- %% @public diff --git a/core/kazoo_services/src/kz_service_sync.erl b/core/kazoo_services/src/kz_service_sync.erl index 7a4c193820d..e279b605db1 100644 --- a/core/kazoo_services/src/kz_service_sync.erl +++ b/core/kazoo_services/src/kz_service_sync.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/kz_services.erl b/core/kazoo_services/src/kz_services.erl index 072fee57656..869339e3047 100644 --- a/core/kazoo_services/src/kz_services.erl +++ b/core/kazoo_services/src/kz_services.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end @@ -1090,13 +1090,11 @@ calculate_services_charges(#kz_services{jobj=ServiceJObj}=Services) -> calculate_services_charges(#kz_services{jobj=ServiceJObj ,updates=UpdatesJObj - ,cascade_quantities=CascadeQuantities - } + }=Service ,ServicePlans ) -> CurrentQuantities = kzd_services:quantities(ServiceJObj), - UpdatesWithCascade = apply_cascade_quantities(UpdatesJObj, CascadeQuantities), - UpdatedQuantities = kz_json:merge_jobjs(UpdatesWithCascade, CurrentQuantities), + UpdatedQuantities = kz_json:merge_jobjs(UpdatesJObj, CurrentQuantities), UpdatedServiceJObj = kzd_services:set_quantities(ServiceJObj ,UpdatedQuantities @@ -1106,30 +1104,16 @@ calculate_services_charges(#kz_services{jobj=ServiceJObj UpdatedItems = kz_service_plans:create_items(UpdatedServiceJObj, ServicePlans), Changed = kz_service_items:get_updated_items(UpdatedItems, ExistingItems), + lager:debug("current items: ~p items after update: ~p service diff quantities: ~p" + ,[kz_service_items:public_json(ExistingItems) + ,kz_service_items:public_json(UpdatedItems) + ,diff_quantities(Service) + ] + ), + lager:debug("computed service charges"), {'ok', kz_service_items:public_json(Changed)}. --spec apply_cascade_quantities(kz_json:object(), kz_json:object()) -> - kz_json:object(). -apply_cascade_quantities(Quantities, CascadeQuantities) -> - kz_json:map(fun(CategoryId, ItemsJObj) -> - {CategoryId, apply_cascade_categories(CategoryId, ItemsJObj, CascadeQuantities)} - end - ,Quantities - ). - --spec apply_cascade_categories(ne_binary(), kz_json:object(), kz_json:object()) -> - kz_json:object(). -apply_cascade_categories(CategoryId, ItemsJObj, CascadeQuantities) -> - kz_json:map(fun(ItemId, ItemQuantity) -> - Key = [CategoryId, ItemId], - CascadeQuantity = kz_json:get_integer_value(Key, CascadeQuantities, 0), - lager:debug("incrementing update ~p:~p with cascade ~p", [Key, ItemQuantity, CascadeQuantity]), - {ItemId, ItemQuantity + CascadeQuantity} - end - ,ItemsJObj - ). - %%-------------------------------------------------------------------- %% @private %% @doc @@ -1196,19 +1180,17 @@ dry_run_activation_charges(CategoryId, CategoryJObj, Services, JObjs) -> dry_run_activation_charges(CategoryId, ItemId, Quantity, #kz_services{jobj=JObj}=Services, JObjs) -> case kzd_services:item_quantity(JObj, CategoryId, ItemId) of Quantity -> JObjs; - OldQuantity -> + _OldQuantity -> ServicesJObj = to_json(Services), Plans = kz_service_plans:from_service_json(ServicesJObj), ServicePlan = kz_service_plans:public_json(Plans), ItemPlan = get_item_plan(CategoryId, ItemId, ServicePlan), - Charges = activation_charges(CategoryId, ItemId, Services), - [kz_json:from_list( [{<<"category">>, CategoryId} ,{<<"item">>, kzd_item_plan:masquerade_as(ItemPlan, ItemId)} ,{<<"amount">>, Charges} - ,{<<"quantity">>, Quantity-OldQuantity} + ,{<<"quantity">>, Quantity} ]) |JObjs ] diff --git a/core/kazoo_services/src/kz_services_modb.erl b/core/kazoo_services/src/kz_services_modb.erl index dc98821f2c7..aa7ec963dde 100644 --- a/core/kazoo_services/src/kz_services_modb.erl +++ b/core/kazoo_services/src/kz_services_modb.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/services/kz_service_billing.erl b/core/kazoo_services/src/services/kz_service_billing.erl index 0ab17e8afcf..60bd021b4e3 100644 --- a/core/kazoo_services/src/services/kz_service_billing.erl +++ b/core/kazoo_services/src/services/kz_service_billing.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/services/kz_service_devices.erl b/core/kazoo_services/src/services/kz_service_devices.erl index 78aed90649b..ccf5e138aa7 100644 --- a/core/kazoo_services/src/services/kz_service_devices.erl +++ b/core/kazoo_services/src/services/kz_service_devices.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/services/kz_service_ips.erl b/core/kazoo_services/src/services/kz_service_ips.erl index 4f7f332cfed..f5441b9e287 100644 --- a/core/kazoo_services/src/services/kz_service_ips.erl +++ b/core/kazoo_services/src/services/kz_service_ips.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/services/kz_service_ledgers.erl b/core/kazoo_services/src/services/kz_service_ledgers.erl index bef89f5e2c8..66e7c03426f 100644 --- a/core/kazoo_services/src/services/kz_service_ledgers.erl +++ b/core/kazoo_services/src/services/kz_service_ledgers.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/services/kz_service_limits.erl b/core/kazoo_services/src/services/kz_service_limits.erl index 89a8c6df7d5..fe69946b51b 100644 --- a/core/kazoo_services/src/services/kz_service_limits.erl +++ b/core/kazoo_services/src/services/kz_service_limits.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/services/kz_service_phone_numbers.erl b/core/kazoo_services/src/services/kz_service_phone_numbers.erl index c8ef9b19cc7..f355ccc2890 100644 --- a/core/kazoo_services/src/services/kz_service_phone_numbers.erl +++ b/core/kazoo_services/src/services/kz_service_phone_numbers.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end @@ -14,9 +14,20 @@ -include("kazoo_services.hrl"). -include_lib("kazoo_number_manager/include/knm_phone_number.hrl"). --define(PHONE_NUMBERS, <<"phone_numbers">>). -define(NUMBER_SERVICES, <<"number_services">>). --define(LISTING_BY_NUMBER, <<"numbers/list_by_number">>). +-define(PHONE_NUMBERS, <<"phone_numbers">>). +-define(NUMBER_CARRIERS, <<"number_carriers">>). + +-define(KEY_VALUE, <<"value">>). +-define(CLASSIFICATIONS, [?KEY_VALUE, <<"classifications">>]). +-define(FEATURES, [?KEY_VALUE, <<"features">>]). + +-define(MAP_CATEGORIES, #{?CLASSIFICATIONS => ?PHONE_NUMBERS + ,?FEATURES => ?NUMBER_SERVICES + }). + +%% ?NUMBER_CARRIERS is nested under ?CLASSIFICATIONS, so we add it "manually". +-define(DEFAULT_RESET_CATEGORIES, [?NUMBER_CARRIERS | maps:keys(?MAP_CATEGORIES)]). -type pn() :: knm_phone_number:knm_phone_number(). -type pns() :: [pn()]. @@ -30,23 +41,28 @@ -spec reconcile(kz_services:services()) -> kz_services:services(). -spec reconcile(kz_services:services(), pns()) -> kz_services:services(). reconcile(Services) -> - AccountId = kz_services:account_id(Services), - AccountDb = kz_util:format_account_id(AccountId, 'encoded'), - case kz_datamgr:get_results(AccountDb, ?LISTING_BY_NUMBER, ['include_docs']) of - {'error', _R} -> - lager:debug("unable to get current phone numbers in service: ~p", [_R]), + AccountDb = kz_util:format_account_db(kz_services:account_id(Services)), + case kz_datamgr:get_results(AccountDb, <<"numbers/reconcile_services">>) of + {error, _R} -> + lager:debug("unable to get reconcile_services for phone numbers: ~p", [_R]), Services; - {'ok', JObjs} -> - reconcile(Services - ,[knm_phone_number:from_json(kz_json:get_value(<<"doc">>, JObj)) - || JObj <- JObjs - ]) + {ok, []} -> reset(Services); + {ok, [JObj]} -> + F = fun (Path, Cat, S) -> update_categories_fold(Path, Cat, S, JObj) end, + maps:fold(F, reset(Services), ?MAP_CATEGORIES) end. reconcile(Services, PNs) -> - S1 = kz_services:reset_category(?PHONE_NUMBERS, Services), - S2 = kz_services:reset_category(?NUMBER_SERVICES, S1), - update_numbers(S2, PNs). + update_numbers(reset(Services), PNs). + +-spec reset(kz_services:services()) -> kz_services:services(). +reset(Services) -> + reset(Services, ?DEFAULT_RESET_CATEGORIES). + +-spec reset(kz_services:services(), ne_binaries()) -> kz_services:services(). +reset(Services, []) -> Services; +reset(Services, [Category | Categories]) -> + reset(kz_services:reset_category(Category, Services), Categories). %%-------------------------------------------------------------------- %% @public @@ -79,15 +95,31 @@ phone_number_activation_charge(Services, Number) -> %%% Internal functions %%%=================================================================== -%%-------------------------------------------------------------------- +update_categories_fold(Path, Category, Services, JObj) -> + kz_json:foldl(fun (SubCat, Count, S) -> update_quantities_fold(SubCat, Count, S, Category) end + ,kz_services:reset_category(Category, Services) + ,kz_json:get_value(Path, JObj) + ). + +update_quantities_fold(Feature, Count, Services, ?NUMBER_SERVICES=Category) -> + Name = knm_providers:service_name(Feature, kz_services:account_id(Services)), + Quantity = kz_services:updated_quantity(Category, Name, Services), + kz_services:update(Category, Name, Quantity + Count, Services); + +update_quantities_fold(Classification, Carriers, Services, ?PHONE_NUMBERS=Category) -> + CountPerClass = kz_json:foldl(fun (_Carrier, Count, Sum) -> Count + Sum end, 0, Carriers), + Quantity = kz_services:updated_quantity(Category, Classification, Services), + S0 = kz_services:update(Category, Classification, Quantity + CountPerClass, Services), + kz_json:foldl(fun manually_update_nested_quantities_fold/3, S0, Carriers). + +manually_update_nested_quantities_fold(Carrier, Count, S) -> + Cat = ?NUMBER_CARRIERS, + Q = kz_services:updated_quantity(Cat, Carrier, S), + kz_services:update(Cat, Carrier, Q + Count, S). + %% @private -%% @doc -%% -%% @end -%%-------------------------------------------------------------------- -spec update_numbers(kz_services:services(), pns()) -> kz_services:services(). -update_numbers(Services, []) -> - Services; +update_numbers(Services, []) -> Services; update_numbers(Services, [PN|PNs]) -> case knm_converters:is_reconcilable(knm_phone_number:number(PN)) of 'false' -> Services; @@ -102,12 +134,7 @@ update_numbers(Services, [PN|PNs]) -> update_numbers(UpdatedServices, PNs) end. -%%-------------------------------------------------------------------- %% @private -%% @doc -%% -%% @end -%%-------------------------------------------------------------------- -spec update_number_quantities(kz_services:services(), pn()) -> kz_services:services(). update_number_quantities(Services, PN) -> DID = knm_phone_number:number(PN), @@ -121,22 +148,16 @@ update_number_quantities(Services, PN) -> kz_services:update(?PHONE_NUMBERS, Classification, Quantity + 1, Services) end. -%%-------------------------------------------------------------------- %% @private -%% @doc -%% -%% @end -%%-------------------------------------------------------------------- -spec is_number_billable(pn()) -> boolean(). is_number_billable(PN) -> - IsBillable = (catch knm_phone_number:is_billable(PN)), + IsBillable = knm_carriers:is_number_billable(PN), lager:debug("is ~s's ~s billable: ~p", [knm_phone_number:module_name(PN) ,knm_phone_number:number(PN) ,IsBillable ]), IsBillable. -%%-------------------------------------------------------------------- %% @private %% @doc %% diff --git a/core/kazoo_services/src/services/kz_service_transactions.erl b/core/kazoo_services/src/services/kz_service_transactions.erl index b7029c52f55..664c1a388c3 100644 --- a/core/kazoo_services/src/services/kz_service_transactions.erl +++ b/core/kazoo_services/src/services/kz_service_transactions.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/services/kz_service_ui_apps.erl b/core/kazoo_services/src/services/kz_service_ui_apps.erl index 3556d9db0aa..0947f7eba3f 100644 --- a/core/kazoo_services/src/services/kz_service_ui_apps.erl +++ b/core/kazoo_services/src/services/kz_service_ui_apps.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/services/kz_service_users.erl b/core/kazoo_services/src/services/kz_service_users.erl index d658b4e62f3..a182ac047aa 100644 --- a/core/kazoo_services/src/services/kz_service_users.erl +++ b/core/kazoo_services/src/services/kz_service_users.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/services/kz_service_whitelabel.erl b/core/kazoo_services/src/services/kz_service_whitelabel.erl index 66a73f4494a..81b8a96fc5e 100644 --- a/core/kazoo_services/src/services/kz_service_whitelabel.erl +++ b/core/kazoo_services/src/services/kz_service_whitelabel.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/src/whs_account_conversion.erl b/core/kazoo_services/src/whs_account_conversion.erl index 64b6ba318e3..c21d0a305e0 100644 --- a/core/kazoo_services/src/whs_account_conversion.erl +++ b/core/kazoo_services/src/whs_account_conversion.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_services/test/kz_services_test.erl b/core/kazoo_services/test/kz_services_test.erl index 5050b2681d7..d8dd751bcb8 100644 --- a/core/kazoo_services/test/kz_services_test.erl +++ b/core/kazoo_services/test/kz_services_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz, INC +%%% @copyright (C) 2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_sip/src/kzsip_diversion.erl b/core/kazoo_sip/src/kzsip_diversion.erl index e3226b68589..80173ca4aea 100644 --- a/core/kazoo_sip/src/kzsip_diversion.erl +++ b/core/kazoo_sip/src/kzsip_diversion.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% @doc %%% Diversion SIP header manipulation %%% @end diff --git a/core/kazoo_sip/src/kzsip_uri.erl b/core/kazoo_sip/src/kzsip_uri.erl index 235749de8f6..ecce95b3386 100644 --- a/core/kazoo_sip/src/kzsip_uri.erl +++ b/core/kazoo_sip/src/kzsip_uri.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% Parse and manipulate SIP URIs %%% @end diff --git a/core/kazoo_sip/test/kzsip_diversion_test.erl b/core/kazoo_sip/test/kzsip_diversion_test.erl index 6a9bdd705b7..574cafea005 100644 --- a/core/kazoo_sip/test/kzsip_diversion_test.erl +++ b/core/kazoo_sip/test/kzsip_diversion_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% @doc %%% Diversion SIP header manipulation tests %%% @end diff --git a/core/kazoo_sip/test/kzsip_uri_test.erl b/core/kazoo_sip/test/kzsip_uri_test.erl index 1ab631fa8bf..c651e075c75 100644 --- a/core/kazoo_sip/test/kzsip_uri_test.erl +++ b/core/kazoo_sip/test/kzsip_uri_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016, 2600Hz INC +%%% @copyright (C) 2011-2017, 2600Hz INC %%% @doc %%% %%% diff --git a/core/kazoo_stats/src/kazoo_stats_app.erl b/core/kazoo_stats/src/kazoo_stats_app.erl index a328efa8f9b..b10294294b9 100644 --- a/core/kazoo_stats/src/kazoo_stats_app.erl +++ b/core/kazoo_stats/src/kazoo_stats_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_stats/src/kazoo_stats_sup.erl b/core/kazoo_stats/src/kazoo_stats_sup.erl index 0e9fb0e9c70..d16e6f1c581 100644 --- a/core/kazoo_stats/src/kazoo_stats_sup.erl +++ b/core/kazoo_stats/src/kazoo_stats_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_tasks/src/kz_csv.erl b/core/kazoo_tasks/src/kz_csv.erl index f66d162e72b..9d4ff8ab53a 100644 --- a/core/kazoo_tasks/src/kz_csv.erl +++ b/core/kazoo_tasks/src/kz_csv.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Simple & efficient operations on CSV binaries. %%% @end diff --git a/core/kazoo_tasks/src/kz_tasks.erl b/core/kazoo_tasks/src/kz_tasks.erl index 4b8c0de9fb4..54eb105c286 100644 --- a/core/kazoo_tasks/src/kz_tasks.erl +++ b/core/kazoo_tasks/src/kz_tasks.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% Utilities for tasks validation & stuff. %%% @end diff --git a/core/kazoo_templates/src/kz_pdf.erl b/core/kazoo_templates/src/kz_pdf.erl index 0b4761006bf..fb04e0f4b77 100644 --- a/core/kazoo_templates/src/kz_pdf.erl +++ b/core/kazoo_templates/src/kz_pdf.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2011-2016 2600Hz, INC +%%% @copyright (C) 2011-2017 2600Hz, INC %%% @doc %%% Builds PDF from an HTML template using HTMLDoc (http://www.msweet.org/projects.php?Z1) %%% @end @@ -10,11 +10,11 @@ -module(kz_pdf). -export([find_template/2 - ,find_template/3 + ,find_template/3 ]). -export([generate/2 - ,generate/3 + ,generate/3 ]). -export([error_empty/0]). @@ -69,7 +69,7 @@ generate(AccountId, Props) -> case find_template(AccountId, Props) of {'error', _R}=Error -> Error; {'ok', Template} -> - generate(AccountId, Props, Template) + generate(AccountId, Props, Template) end. generate(Account, Props, Template) -> @@ -93,10 +93,10 @@ generate(Account, Props, Template) -> RawCmd = kapps_config:get(?PDF_CONFIG_CAT, <<"html2pdf">>, ?HTML_TO_PDF), Cmd = lists:foldl(fun cmd_fold/2 - ,RawCmd - ,[{<<"$pdf$">>, PDFFile} - ,{<<"$html$">>, HTMLFile} - ] + ,RawCmd + ,[{<<"\$pdf\$">>, PDFFile} + ,{<<"\$html\$">>, HTMLFile} + ] ), lager:debug("exec ~s", [Cmd]), case os:cmd(kz_util:to_list(Cmd)) of @@ -141,7 +141,7 @@ default_template(DocType, AttachmentId) -> {'error', 'not_found'} -> maybe_create_default_template(DocType, AttachmentId); {'error', _R}=Error -> lager:error("failed to find default template ~s/~s : ~p" - ,[?TEMPLATE_DOC_ID(DocType), AttachmentId, _R]), + ,[?TEMPLATE_DOC_ID(DocType), AttachmentId, _R]), Error end. @@ -162,21 +162,20 @@ create_default_template(Template, DocType, AttachmentId) -> lager:debug("creating default template ~s", [DocType]), Default = kz_json:from_list([{<<"template_name">>, DocType}]), JObj = - kz_doc:update_pvt_parameters( - kz_json:from_list( - [{<<"_id">>, ?TEMPLATE_DOC_ID(DocType)} - ,{<<"default">>, Default} - ] - ) - ,?KZ_CONFIG_DB - ,[{'type', <<"config">>}] - ), + kz_doc:update_pvt_parameters(kz_json:from_list( + [{<<"_id">>, ?TEMPLATE_DOC_ID(DocType)} + ,{<<"default">>, Default} + ] + ) + ,?KZ_CONFIG_DB + ,[{'type', <<"config">>}] + ), case kz_datamgr:save_doc(?KZ_CONFIG_DB, JObj) of {'ok', _} -> save_default_attachment(Template, DocType, AttachmentId); {'error', 'conflict'} -> save_default_attachment(Template, DocType, AttachmentId); {'error', _R}=Error -> lager:error("failed to create default template doc for ~s : ~p" - ,[?TEMPLATE_DOC_ID(DocType), _R]), + ,[?TEMPLATE_DOC_ID(DocType), _R]), Error end. @@ -184,16 +183,15 @@ create_default_template(Template, DocType, AttachmentId) -> save_default_attachment(Template, DocType, AttachmentId) -> lager:debug("saving default template ~s attachment", [DocType]), case - kz_datamgr:put_attachment( - ?KZ_CONFIG_DB - ,?TEMPLATE_DOC_ID(DocType) - ,AttachmentId - ,Template - ) + kz_datamgr:put_attachment(?KZ_CONFIG_DB + ,?TEMPLATE_DOC_ID(DocType) + ,AttachmentId + ,Template + ) of {'error', _R}=Error -> lager:error("failed to save default template attachment for ~s : ~p" - ,[?TEMPLATE_DOC_ID(DocType), _R]), + ,[?TEMPLATE_DOC_ID(DocType), _R]), Error; {'ok', _} -> {'ok', Template} end. diff --git a/core/kazoo_templates/src/kz_template.erl b/core/kazoo_templates/src/kz_template.erl index 4896b7b2d55..79e1ede3450 100644 --- a/core/kazoo_templates/src/kz_template.erl +++ b/core/kazoo_templates/src/kz_template.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_token_buckets/src/kazoo_token_buckets_app.erl b/core/kazoo_token_buckets/src/kazoo_token_buckets_app.erl index 04bab7bee11..2b1b340ddc5 100644 --- a/core/kazoo_token_buckets/src/kazoo_token_buckets_app.erl +++ b/core/kazoo_token_buckets/src/kazoo_token_buckets_app.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_token_buckets/src/kazoo_token_buckets_sup.erl b/core/kazoo_token_buckets/src/kazoo_token_buckets_sup.erl index c68f3e4cf8f..69f18688a2b 100644 --- a/core/kazoo_token_buckets/src/kazoo_token_buckets_sup.erl +++ b/core/kazoo_token_buckets/src/kazoo_token_buckets_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_token_buckets/src/kz_buckets.erl b/core/kazoo_token_buckets/src/kz_buckets.erl index c2431e69aef..14a94dd1480 100644 --- a/core/kazoo_token_buckets/src/kz_buckets.erl +++ b/core/kazoo_token_buckets/src/kz_buckets.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz INC +%%% @copyright (C) 2014-2017, 2600Hz INC %%% @doc %%% API interface for buckets %%% ETS writer for table diff --git a/core/kazoo_token_buckets/src/kz_buckets_sup.erl b/core/kazoo_token_buckets/src/kz_buckets_sup.erl index 2f29932c4d7..4a6b0147174 100644 --- a/core/kazoo_token_buckets/src/kz_buckets_sup.erl +++ b/core/kazoo_token_buckets/src/kz_buckets_sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Supervisor for Kazoo Token Bucket Servers %%% @end diff --git a/core/kazoo_token_buckets/src/kz_token_bucket.erl b/core/kazoo_token_buckets/src/kz_token_bucket.erl index a0725676d22..12fb086e419 100644 --- a/core/kazoo_token_buckets/src/kz_token_bucket.erl +++ b/core/kazoo_token_buckets/src/kz_token_bucket.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Implementation of a token bucket as gen_server %%% https://en.wikipedia.org/wiki/Token_bucket#The_token_bucket_algorithm diff --git a/core/kazoo_token_buckets/test/kz_token_bucket_pqc.erl b/core/kazoo_token_buckets/test/kz_token_bucket_pqc.erl index c687d549289..6a00b7f3373 100644 --- a/core/kazoo_token_buckets/test/kz_token_bucket_pqc.erl +++ b/core/kazoo_token_buckets/test/kz_token_bucket_pqc.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% The goal is to model how a token bucket works and, using PropEr, diff --git a/core/kazoo_transactions/src/kazoo_transactions_maintenance.erl b/core/kazoo_transactions/src/kazoo_transactions_maintenance.erl index 94ea49f490a..89671e206be 100644 --- a/core/kazoo_transactions/src/kazoo_transactions_maintenance.erl +++ b/core/kazoo_transactions/src/kazoo_transactions_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz, INC +%%% @copyright (C) 2014-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_transactions/src/kz_topup.erl b/core/kazoo_transactions/src/kz_topup.erl index 810da3f3f83..a2e1b833f1c 100644 --- a/core/kazoo_transactions/src/kz_topup.erl +++ b/core/kazoo_transactions/src/kz_topup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz, INC +%%% @copyright (C) 2012-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_transactions/src/kz_transaction.erl b/core/kazoo_transactions/src/kz_transaction.erl index d101526c527..d30d66630cd 100644 --- a/core/kazoo_transactions/src/kz_transaction.erl +++ b/core/kazoo_transactions/src/kz_transaction.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_transactions/src/kz_transactions.erl b/core/kazoo_transactions/src/kz_transactions.erl index 5d328645f3c..c552738e4fe 100644 --- a/core/kazoo_transactions/src/kz_transactions.erl +++ b/core/kazoo_transactions/src/kz_transactions.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz INC +%%% @copyright (C) 2013-2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_transactions/src/wht_util.erl b/core/kazoo_transactions/src/wht_util.erl index 293b7738d70..9b9cea8cf99 100644 --- a/core/kazoo_transactions/src/wht_util.erl +++ b/core/kazoo_transactions/src/wht_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz, INC +%%% @copyright (C) 2013-2017, 2600Hz, INC %%% @doc %%% %%% @end diff --git a/core/kazoo_translator/src/convertors/kzt_kazoo.erl b/core/kazoo_translator/src/convertors/kzt_kazoo.erl index de9b6ab38db..663313eaac0 100644 --- a/core/kazoo_translator/src/convertors/kzt_kazoo.erl +++ b/core/kazoo_translator/src/convertors/kzt_kazoo.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Process dynamicly generated callflow "flow" %%% @end diff --git a/core/kazoo_translator/src/convertors/kzt_twiml.erl b/core/kazoo_translator/src/convertors/kzt_twiml.erl index ab1619180a2..fc985002349 100644 --- a/core/kazoo_translator/src/convertors/kzt_twiml.erl +++ b/core/kazoo_translator/src/convertors/kzt_twiml.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_translator/src/convertors/kzt_twiml_dial.erl b/core/kazoo_translator/src/convertors/kzt_twiml_dial.erl index 0a71a73024a..a052104db49 100644 --- a/core/kazoo_translator/src/convertors/kzt_twiml_dial.erl +++ b/core/kazoo_translator/src/convertors/kzt_twiml_dial.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Handle the emulation of the Dial verb %%% @end diff --git a/core/kazoo_translator/src/convertors/kzt_twiml_say.erl b/core/kazoo_translator/src/convertors/kzt_twiml_say.erl index 0f749dbb517..e9e25f11159 100644 --- a/core/kazoo_translator/src/convertors/kzt_twiml_say.erl +++ b/core/kazoo_translator/src/convertors/kzt_twiml_say.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Execute the 'Say' verb %%% @end diff --git a/core/kazoo_translator/src/convertors/kzt_twiml_util.erl b/core/kazoo_translator/src/convertors/kzt_twiml_util.erl index 03b50cf7c8d..4d5597c478f 100644 --- a/core/kazoo_translator/src/convertors/kzt_twiml_util.erl +++ b/core/kazoo_translator/src/convertors/kzt_twiml_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_translator/src/kzt_receiver.erl b/core/kazoo_translator/src/kzt_receiver.erl index 55d785a483b..06428d03d35 100644 --- a/core/kazoo_translator/src/kzt_receiver.erl +++ b/core/kazoo_translator/src/kzt_receiver.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% Receive call events for various scenarios %%% @end diff --git a/core/kazoo_translator/src/kzt_translator.erl b/core/kazoo_translator/src/kzt_translator.erl index d2b29cfc44b..86320b1e33c 100644 --- a/core/kazoo_translator/src/kzt_translator.erl +++ b/core/kazoo_translator/src/kzt_translator.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% Standard interface for client modules to use to get dialplan commands %%% translated into 2600Hz-specific commands diff --git a/core/kazoo_translator/src/kzt_util.erl b/core/kazoo_translator/src/kzt_util.erl index 9f1945fbe33..950a44326a1 100644 --- a/core/kazoo_translator/src/kzt_util.erl +++ b/core/kazoo_translator/src/kzt_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_translator/test/kzt_twiml_dial_test.erl b/core/kazoo_translator/test/kzt_twiml_dial_test.erl index c55ae2d0662..dac484001fe 100644 --- a/core/kazoo_translator/test/kzt_twiml_dial_test.erl +++ b/core/kazoo_translator/test/kzt_twiml_dial_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_translator/test/kzt_util_test.erl b/core/kazoo_translator/test/kzt_util_test.erl index ce20f403992..666f878e77f 100644 --- a/core/kazoo_translator/test/kzt_util_test.erl +++ b/core/kazoo_translator/test/kzt_util_test.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz +%%% @copyright (C) 2012-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/kazoo_voicemail/src/kazoo_voicemail_maintenance.erl b/core/kazoo_voicemail/src/kazoo_voicemail_maintenance.erl index 3fc61a21af6..0112e73bc5c 100644 --- a/core/kazoo_voicemail/src/kazoo_voicemail_maintenance.erl +++ b/core/kazoo_voicemail/src/kazoo_voicemail_maintenance.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Mailbox maintenance %%% @end @@ -17,6 +17,7 @@ ,recover_messages_account/1 ,recover_messages_account/3 ]). +-export([renotify/2]). -include("kz_voicemail.hrl"). @@ -144,9 +145,85 @@ rebuild_message_metadata(JObj, AttachmentName) -> Routines = [{fun kapps_call:set_to/2, <>} ,{fun kapps_call:set_from/2, <>} ,{fun kapps_call:set_call_id/2, kz_util:rand_hex_binary(12)} + ,{fun kapps_call:set_caller_id_number/2, CIDNumber} + ,{fun kapps_call:set_caller_id_name/2, CIDName} ], Call = kapps_call:exec(Routines, kapps_call:new()), Metadata = kzd_box_message:build_metadata_object(Length, Call, MediaId, CIDNumber, CIDName, Timestamp), kzd_box_message:set_metadata(Metadata, JObj). +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% @end +%%-------------------------------------------------------------------- +-spec renotify(text(), text()) -> 'ok'. +renotify(Account, MessageId) -> + MODb = get_modb(Account, MessageId), + AccountId = get_account_id(Account), + case kz_datamgr:open_doc(MODb, MessageId) of + {'error', _R} -> ?LOG("unable to find message ~s in ~s: ~p", [MODb, MessageId, _R]); + {'ok', JObj} -> + Call = rebuild_kapps_call(JObj, AccountId), + BoxId = kzd_box_message:source_id(JObj), + Metadata = kzd_box_message:metadata(JObj), + Length = kz_json:get_value(<<"length">>, Metadata, 0), + Props = [{<<"Transcribe-Voicemail">>, 'false'}], + log_renotify_result( + MessageId + ,BoxId + ,kvm_util:publish_saved_notify(MessageId, BoxId, Call, Length, Props) + ) + end. +-spec log_renotify_result(ne_binary(), ne_binary(), kz_amqp_worker:request_return()) -> 'ok'. +log_renotify_result(MessageId, BoxId, {'ok', JObj}) -> + ?LOG("re-notify sent message ~s from mailbox ~s: ~s" + ,[MessageId, BoxId, kz_json:encode(JObj)] + ); +log_renotify_result(MessageId, BoxId, {'error', JObj}) -> + ?LOG("re-notify failed to send message ~s from mailbox ~s: ~s" + ,[MessageId, BoxId, kz_json:encode(JObj)] + ); +log_renotify_result(MessageId, BoxId, {'timeout', JObjs}) -> + ?LOG("re-notify timed out sending message ~s from mailbox ~s: ~s" + ,[MessageId, BoxId, kz_json:encode(JObjs)] + ); +log_renotify_result(MessageId, BoxId, Result) -> + ?LOG("unexpected error in re-notify sending message ~s from mailbox ~s: ~p" + ,[MessageId, BoxId, Result] + ). + +-spec get_modb(ne_binary(), ne_binary()) -> ne_binary(). +get_modb(?MATCH_MODB_SUFFIX_ENCODED(_A, _B, _C, _Y, _M) = MODb, _) -> MODb; +get_modb(?MATCH_MODB_SUFFIX_encoded(_A, _B, _C, _Y, _M) = MODb, _) -> MODb; +get_modb(?MATCH_MODB_SUFFIX_RAW(_A, _B, _C, _Y, _M) = MODb, _) -> + kz_util:format_account_modb(MODb, 'encoded'); +get_modb(?MATCH_MODB_SUFFIX_UNENCODED(_A, _B, _C, _Y, _M) = MODb, _) -> + kz_util:format_account_modb(MODb, 'encoded'); +get_modb(Account, ?MATCH_MODB_PREFIX(Year, Month, _)) -> + kz_util:format_account_mod_id(Account, Year, Month). + +-spec get_account_id(ne_binary()) -> ne_binary(). +get_account_id(?MATCH_ACCOUNT_RAW(AccountId)) -> AccountId; +get_account_id(?MATCH_ACCOUNT_UNENCODED(A, B, Rest)) -> ?MATCH_ACCOUNT_RAW(A, B, Rest); +get_account_id(?MATCH_ACCOUNT_ENCODED(A, B, Rest)) -> ?MATCH_ACCOUNT_RAW(A, B, Rest); +get_account_id(?MATCH_MODB_SUFFIX_RAW(AccountId, _, _)) -> AccountId; +get_account_id(?MATCH_MODB_SUFFIX_ENCODED(A, B, Rest, _, _)) -> ?MATCH_ACCOUNT_RAW(A, B, Rest); +get_account_id(?MATCH_MODB_SUFFIX_UNENCODED(A, B, Rest, _, _)) -> ?MATCH_ACCOUNT_RAW(A, B, Rest). + +-spec rebuild_kapps_call(kz_json:object(), ne_binary()) -> kapps_call:call(). +rebuild_kapps_call(JObj, AccountId) -> + Metadata = kzd_box_message:metadata(JObj), + To = kz_json:get_value(<<"to">>, Metadata, <<"unknown@nodomain">>), + CCVs = [{<<"Account-ID">>, AccountId}], + Props = [{<<"Call-ID">>, kz_json:get_value(<<"call_id">>, Metadata, kz_util:rand_hex_binary(12))} + ,{<<"From">>, kz_json:get_value(<<"from">>, Metadata, <<"unknown@nodomain">>)} + ,{<<"Caller-ID-Name">>, kz_json:get_value(<<"caller_id_name">>, Metadata, kz_util:anonymous_caller_id_name())} + ,{<<"Caller-ID-Number">>, kz_json:get_value(<<"caller_id_number">>, Metadata, kz_util:anonymous_caller_id_number())} + ,{<<"Custom-Channel-Vars">>, kz_json:from_list(CCVs)} + ,{<<"Custom-SIP-Headers">>, kz_json:new()} + ,{<<"Request">>, To} + ,{<<"To">>, To} + ], + kapps_call:from_route_req(kz_json:from_list(Props), kapps_call:new()). diff --git a/core/kazoo_voicemail/src/kvm_message.erl b/core/kazoo_voicemail/src/kvm_message.erl index a7f2732bea8..efec3628b20 100644 --- a/core/kazoo_voicemail/src/kvm_message.erl +++ b/core/kazoo_voicemail/src/kvm_message.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Mailbox messages operation %%% @end @@ -8,7 +8,7 @@ %%%------------------------------------------------------------------- -module(kvm_message). --export([new/2 +-export([new/2, forward_message/4 ,fetch/2, fetch/3, message/2, message/3 ,set_folder/3, change_folder/3, change_folder/4 @@ -22,6 +22,8 @@ -export_type([vm_folder/0]). +-type new_msg_ret() :: 'ok' | {'error', kapps_call:call(), any()}. + %%-------------------------------------------------------------------- %% @public %% @doc recieve and store a new voicemail message @@ -38,7 +40,7 @@ %% ] %% @end %%-------------------------------------------------------------------- --spec new(kapps_call:call(), kz_proplist()) -> any(). +-spec new(kapps_call:call(), kz_proplist()) -> new_msg_ret(). new(Call, Props) -> BoxId = props:get_value(<<"Box-Id">>, Props), Length = props:get_value(<<"Length">>, Props), @@ -46,7 +48,7 @@ new(Call, Props) -> lager:debug("saving new ~bms voicemail media and metadata", [Length]), - {MessageId, MediaUrl} = create_message_doc(Call, Props), + {MessageId, MediaUrl} = create_new_message_doc(Call, Props), Msg = io_lib:format("failed to store voicemail media ~s in voicemail box ~s of account ~s" ,[MessageId, BoxId, kapps_call:account_id(Call)] @@ -66,6 +68,45 @@ new(Call, Props) -> {'error', Call1, Msg} end. +-spec forward_message(kapps_call:call(), kz_json:object(), ne_binary(), kz_proplist()) -> new_msg_ret(). +forward_message(Call, Metadata, SrcBoxId, Props) -> + case props:get_value(<<"Attachment-Name">>, Props) of + 'undefined' -> + %% user chose to forward without prepending + forward_to_vmbox(Call, Metadata, SrcBoxId, Props); + _AttachmentName -> + %% user chose to forward and prepend a messge + new_forward_message(Call, Metadata, SrcBoxId, Props) + end. + +-spec new_forward_message(kapps_call:call(), kz_json:object(), ne_binary(), kz_proplist()) -> new_msg_ret(). +new_forward_message(Call, Metadata, SrcBoxId, Props) -> + DestBoxId = props:get_value(<<"Box-Id">>, Props), + Length = props:get_value(<<"Length">>, Props), + AttachmentName = props:get_value(<<"Attachment-Name">>, Props), + + lager:debug("saving new ~bms forward voicemail media and metadata", [Length]), + + {ForwardId, MediaUrl} = create_forward_message_doc(Call, Metadata, SrcBoxId, Props), + + Msg = io_lib:format("failed to store forward voicemail media ~s in voicemail box ~s of account ~s" + ,[ForwardId, DestBoxId, kapps_call:account_id(Call)] + ), + Funs = [{fun kapps_call:kvs_store/3, 'dest_mailbox_id', DestBoxId} + ,{fun kapps_call:kvs_store/3, 'attachment_name', AttachmentName} + ,{fun kapps_call:kvs_store/3, 'media_id', ForwardId} + ,{fun kapps_call:kvs_store/3, 'media_length', Length} + ], + + lager:debug("storing forward voicemail media recording ~s in doc ~s", [AttachmentName, ForwardId]), + case store_recording(AttachmentName, MediaUrl, kapps_call:exec(Funs, Call), ForwardId) of + 'ok' -> + prepend_and_notify(Call, ForwardId, Metadata, SrcBoxId, Props); + {'error', Call1} -> + lager:error(Msg), + {'error', Call1, Msg} + end. + %%-------------------------------------------------------------------- %% @public %% @doc fetch message doc @@ -224,6 +265,11 @@ copy_to_vmboxes(AccountId, JObj, OldBoxId, [NBId | NBIds], CopiedDict) -> {'ok', NBoxJ} = kz_datamgr:open_cache_doc(AccountDb, NBId), Funs = kvm_util:get_change_vmbox_funs(AccountId, NBId, NBoxJ, OldBoxId), + + lager:debug("copying voicemail ~s from ~s to ~s in account ~s" + ,[kz_doc:id(JObj), OldBoxId, NBId, AccountId] + ), + Id = kz_doc:id(JObj), NewCopiedDict = case do_copy(AccountId, JObj, Funs) of {'ok', CopiedJObj} -> @@ -293,37 +339,69 @@ media_url(AccountId, Message) -> %% @doc %% @end %%-------------------------------------------------------------------- --spec create_message_doc(kapps_call:call(), kz_proplist()) -> {ne_binary(), ne_binary() | function()}. -create_message_doc(Call, Props) -> - AccountId = kapps_call:account_id(Call), +-type sotre_media_url() :: fun(() -> ne_binary() | {'error', any()}). +-spec create_new_message_doc(kapps_call:call(), kz_proplist()) -> + {ne_binary(), sotre_media_url()}. +create_new_message_doc(Call, Props) -> + MsgJObj = create_message_doc(Call, 'undefined', Props), + save_generate_media_url(MsgJObj, props:get_value(<<"Attachment-Name">>, Props)). + +-spec create_forward_message_doc(kapps_call:call(), kz_json:object(), ne_binary(), kz_proplist()) -> + {ne_binary(), sotre_media_url()}. +create_forward_message_doc(Call, Metadata, SrcBoxId, Props) -> + AccountId = kapps_call:account_id(Call), + MsgJObj = create_message_doc(Call, Metadata, Props), + %% create a fake Destination Box JObj to pass to change vmbox functions + %% Note: set pvt_account_id and db just to make sure if timezone is not passed + %% kzd_voicemail_box can find timezone for the owner or account + NewBoxJObj = kz_json:from_list( + [{<<"_id">>, props:get_value(<<"Box-Id">>, Props)} + ,{<<"mailbox">>, props:get_value(<<"Box-Num">>, Props)} + ,{<<"timezone">>, props:get_value(<<"Timezone">>, Props)} + ,{<<"owner_id">>, props:get_value(<<"Owner-Id">>, Props)} + ,{<<"pvt_account_id">>, AccountId} + ,{<<"pvt_account_db">>, kapps_call:account_db(Call)} + ] + ), + UpdateFuns = kvm_util:get_change_vmbox_funs(AccountId, kz_doc:id(NewBoxJObj), NewBoxJObj, SrcBoxId), + ForwardJObj = lists:foldl(fun(F, J) -> F(J) end, MsgJObj, UpdateFuns), + save_generate_media_url(ForwardJObj, props:get_value(<<"Attachment-Name">>, Props)). + +-spec create_message_doc(kapps_call:call(), api_object(), kz_proplist()) -> kz_json:object(). +create_message_doc(Call, Metadata, Props) -> + AccountId = kapps_call:account_id(Call), JObj = kzd_box_message:new(AccountId, Props), + maybe_add_metadata(Call, JObj, Metadata, Props). - MediaId = kz_doc:id(JObj), +-spec maybe_add_metadata(kapps_call:call(), kz_json:object(), api_object(), kz_proplist()) -> kz_json:object(). +maybe_add_metadata(Call, JObj, 'undefined', Props) -> Length = props:get_value(<<"Length">>, Props), CIDNumber = kvm_util:get_caller_id_number(Call), CIDName = kvm_util:get_caller_id_name(Call), Timestamp = kz_util:current_tstamp(), + Metadata = kzd_box_message:build_metadata_object(Length, Call, kz_doc:id(JObj), CIDNumber, CIDName, Timestamp), + kzd_box_message:set_metadata(Metadata, JObj); +maybe_add_metadata(_Call, JObj, Metadata, Props) -> + MediaId = kz_doc:id(JObj), + Updates = [fun(M) -> kz_json:set_value(<<"timestamp">>, kz_util:current_tstamp(), M) end + ,fun(M) -> kzd_box_message:set_media_id(MediaId, M) end + ,fun(M) -> kz_json:set_value(<<"lenght">>, props:get_value(<<"Length">>, Props), M) end + ], + kzd_box_message:set_metadata(lists:foldl(fun(F, Meta) -> F(Meta) end, Metadata, Updates), JObj). - Metadata = kzd_box_message:build_metadata_object(Length, Call, MediaId, CIDNumber, CIDName, Timestamp), - - MsgJObj = kzd_box_message:set_metadata(Metadata, JObj), +-spec save_generate_media_url(kz_json:object(), ne_binary()) -> {ne_binary(), sotre_media_url()}. +save_generate_media_url(MsgJObj, AttachmentName) -> {'ok', SavedJObj} = kz_datamgr:save_doc(kz_doc:account_db(MsgJObj), MsgJObj), - - MediaUrl = fun() -> - kz_media_url:store(SavedJObj - ,props:get_value(<<"Attachment-Name">>, Props) - ) - end, - - {MediaId, MediaUrl}. + MediaUrl = fun() -> kz_media_url:store(SavedJObj, AttachmentName) end, + {kz_doc:id(SavedJObj), MediaUrl}. %%-------------------------------------------------------------------- %% @private %% @doc %% @end %%-------------------------------------------------------------------- --spec store_recording(ne_binary(), ne_binary() | function(), kapps_call:call(), ne_binary()) -> +-spec store_recording(ne_binary(), ne_binary() | sotre_media_url(), kapps_call:call(), ne_binary()) -> 'ok' | {'error', kapps_call:call()}. store_recording(AttachmentName, Url, Call, MessageId) -> @@ -349,6 +427,100 @@ check_attachment_exists(Call, MessageId) -> {'error', Call} end. +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% @end +%%-------------------------------------------------------------------- +-spec forward_to_vmbox(kapps_call:call(), kz_json:object(), ne_binary(), kz_proplist()) -> new_msg_ret(). +forward_to_vmbox(Call, Metadata, SrcBoxId, Props) -> + AccountId = kapps_call:account_id(Call), + MediaId = kzd_box_message:media_id(Metadata), + DestBoxId = props:get_value(<<"Box-Id">>, Props), + Length = props:get_value(<<"Length">>, Props), + Result = copy_to_vmboxes(AccountId, MediaId, SrcBoxId, DestBoxId), + Failed = kz_json:get_value(<<"failed">>, Result, []), + Succeeded = kz_json:get_value(<<"succeeded">>, Result, []), + case {Failed, Succeeded} of + {[], []} -> {'error', Call, 'internal_error'}; + {[], [ForwardId]} -> + %%TODO: update lenght and caller_id + notify_and_update_meta(Call, ForwardId, Length, Props); + {[{_id, Reason}], _} -> {'error', Call, Reason} + end. + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% @end +%%-------------------------------------------------------------------- +-spec prepend_and_notify(kapps_call:call(), ne_binary(), kz_json:object(), ne_binary(), kz_proplist()) -> new_msg_ret(). +prepend_and_notify(Call, ForwardId, Metadata, SrcBoxId, Props) -> + Length = props:get_value(<<"Length">>, Props), + try prepend_forward_message(Call, ForwardId, Metadata, SrcBoxId, Props) of + {'ok', _} -> + %%TODO: update lenght and caller_id + notify_and_update_meta(Call, ForwardId, Length, Props); + {'error', _R} -> + %% prepend failed, so at least try to forward without a prepend message + forward_to_vmbox(Call, Metadata, SrcBoxId, Props) + catch + _T:_E -> + %% prepend failed, so at least try to forward without a prepend message + ST = erlang:get_stacktrace(), + lager:error("exception occured during prepend and forward message: ~p:~p", [_T, _E]), + kz_util:log_stacktrace(ST), + forward_to_vmbox(Call, Metadata, SrcBoxId, Props) + end. + +-spec prepend_forward_message(kapps_call:cal(), ne_binary(), kz_json:object(), ne_binary(), kz_proplist()) -> db_ret(). +prepend_forward_message(Call, ForwardId, Metadata, _SrcBoxId, Props) -> + lager:debug("trying to prepend a message to forwarded voicemail message ~s", [ForwardId]), + AccountId = kapps_call:account_id(Call), + + lager:debug("saving prepend message ~s attachment to file system", [ForwardId]), + TmpAttachmentName = props:get_ne_binary_value(<<"Attachment-Name">>, Props), + {'ok', TmpPath} = write_attachment_to_file(AccountId, ForwardId, [TmpAttachmentName]), + {'ok', _} = kz_datamgr:delete_attachment(kvm_util:get_db(AccountId, ForwardId), ForwardId, TmpAttachmentName), + + OrigMsgId = kzd_box_message:media_id(Metadata), + lager:debug("saving original message ~s attachment to file system", [OrigMsgId]), + {'ok', OrigPath} = write_attachment_to_file(AccountId, OrigMsgId), + {'ok', OrigSampleRate} = kz_media_util:detect_file_sample_rate(OrigPath), + + TonePath = kz_util:join_binary([<<"/tmp/">>, <<(kz_util:rand_hex_binary(16))/binary, ".wav">>], <<>>), + kz_media_util:synthesize_tone(OrigSampleRate, <<"440">>, <<"0.5">>, TonePath), + + lager:debug("joining prepend to original message"), + case kz_media_util:join_media_files([TmpPath, TonePath, OrigPath], [{sample_rate, OrigSampleRate}]) of + {'ok', FileContents} -> + JoinFilename = <<(kz_util:rand_hex_binary(16))/binary, ".mp3">>, + _ = [kz_util:delete_file(F) || F <- [TmpPath, OrigPath, TonePath]], + %%TODO: update forwarded doc with lenght and media_filename + kz_datamgr:put_attachment(kvm_util:get_db(AccountId, ForwardId), ForwardId, JoinFilename, FileContents); + {'error', _} -> + _ = [kz_util:delete_file(F) || F <- [TmpPath, OrigPath, TonePath]], + lager:warning("failed to join forward message media files"), + {'error', 'join_failed'} + + end. + +-spec write_attachment_to_file(ne_binary(), ne_binary()) -> {'ok', ne_binary()} | {'error', any()}. +write_attachment_to_file(AccountId, MessageId) -> + case fetch(AccountId, MessageId) of + {'ok', Doc} -> + write_attachment_to_file(AccountId, MessageId, kz_doc:attachment_names(Doc)); + {'error', _}=Error -> Error + end. + +-spec write_attachment_to_file(ne_binary(), ne_binary(), ne_binaries()) -> {'ok', ne_binary()} | {'error', any()}. +write_attachment_to_file(AccountId, MessageId, [AttachmentId]) -> + Db = kvm_util:get_db(AccountId, MessageId), + {'ok', AttachmentBin} = kz_datamgr:fetch_attachment(Db, MessageId, AttachmentId), + FilePath = kz_util:join_binary([<<"/tmp/_">>, AttachmentId], <<>>), + kz_util:write_file(FilePath, AttachmentBin, ['write', 'binary']), + {'ok', FilePath}. + %%-------------------------------------------------------------------- %% @private %% @doc @@ -364,29 +536,39 @@ notify_and_update_meta(Call, MediaId, Length, Props) -> case kvm_util:publish_saved_notify(MediaId, BoxId, Call, Length, Props) of {'ok', JObjs} -> JObj = kvm_util:get_notify_completed_message(JObjs), - log_notification_response(NotifyAction, MediaId, JObj), + log_notification_response(NotifyAction, MediaId, JObj, Call), maybe_update_meta(Length, NotifyAction, Call, MediaId, BoxId); {'timeout', JObjs} -> JObj = kvm_util:get_notify_completed_message(JObjs), - log_notification_response(NotifyAction, MediaId, JObj), + log_notification_response(NotifyAction, MediaId, JObj, Call), maybe_update_meta(Length, 'nothing', Call, MediaId, BoxId); - {'error', _E} -> - lager:debug("voicemail new notification error: ~p", [_E]), + {'error', _R} -> + AccountId = kapps_call:account_id(Call), + lager:debug("failed to send new voicemail notification for message ~s in account ~s: ~p" + ,[MediaId, AccountId, _R]), maybe_update_meta(Length, 'nothing', Call, MediaId, BoxId) end. --spec log_notification_response(notify_action(), ne_binary(), kz_json:object()) -> 'ok'. -log_notification_response('nothing', _MediaId, _UpdateJObj) -> 'ok'; -log_notification_response(_Action, MediaId, UpdateJObj) -> +-spec log_notification_response(notify_action(), ne_binary(), kz_json:object(), kapps_call:call()) -> 'ok'. +log_notification_response('nothing', _MediaId, _UpdateJObj, Call) -> + AccountId = kapps_call:account_id(Call), + lager:debug("successfully sent new voicemail notification for message ~s in account ~s: ~s" + ,[_MediaId, AccountId, kz_json:encode(_UpdateJObj)]); +log_notification_response(_Action, MediaId, UpdateJObj, Call) -> + AccountId = kapps_call:account_id(Call), case kz_json:get_value(<<"Status">>, UpdateJObj) of - <<"completed">> -> 'ok'; + <<"completed">> -> + lager:debug("successfully sent new voicemail notification for message ~s in account ~s: ~s" + ,[MediaId, AccountId, kz_json:encode(UpdateJObj)]); <<"failed">> -> - lager:debug("attachment for ~s failed to send out via notification: ~s" + lager:debug("failed to send new voicemail notification for message ~s in account ~s: ~s" ,[MediaId + ,AccountId ,kz_json:get_value(<<"Failure-Message">>, UpdateJObj) ]); _ -> - lager:info("timed out waiting for new voicemail (~s) notification resp", [MediaId]) + lager:info("failed to send new voicemail notification for message ~s in account ~s: timeout" + ,[MediaId, AccountId]) end. -spec maybe_update_meta(pos_integer(), notify_action(), kapps_call:call(), ne_binary(), ne_binary()) -> 'ok'. diff --git a/core/kazoo_voicemail/src/kvm_messages.erl b/core/kazoo_voicemail/src/kvm_messages.erl index bca0556b12a..b90e6e48309 100644 --- a/core/kazoo_voicemail/src/kvm_messages.erl +++ b/core/kazoo_voicemail/src/kvm_messages.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% %%% @end @@ -86,21 +86,29 @@ count_by_owner(?MATCH_ACCOUNT_ENCODED(_)=AccountDb, OwnerId) -> AccountId = kz_util:format_account_id(AccountDb), count_by_owner(AccountId, OwnerId); count_by_owner(AccountId, OwnerId) -> - ViewOpts = [{'key', [OwnerId, <<"vmbox">>]}], - - case kz_datamgr:get_results(kvm_util:get_db(AccountId), <<"attributes/owned">>, ViewOpts) of + ViewOptions = [{'key', [OwnerId, <<"vmbox">>]}], + case kz_datamgr:get_results(kvm_util:get_db(AccountId), <<"attributes/owned">>, ViewOptions) of {'ok', []} -> - lager:info("voicemail box owner is not found"), + lager:info("no voicemail boxes belonging to user ~s found", [OwnerId]), {0, 0}; - {'ok', [Owned|_]} -> - VMBoxId = kz_json:get_value(<<"value">>, Owned), - FoldersCounts = count_per_folder(AccountId, VMBoxId), - normalize_count_none_deleted(VMBoxId, FoldersCounts); + {'ok', Boxes} -> + FolderQuantities = count_per_folder(AccountId), + BoxIds = [kz_json:get_value(<<"value">>, Box) || Box <- Boxes], + lager:debug("found ~p vociemail boxes belonging to user ~s", [length(BoxIds), OwnerId]), + sum_owner_mailboxes(FolderQuantities, BoxIds, {0, 0}); {'error', _R} -> lager:info("unable to lookup vm counts by owner: ~p", [_R]), {0, 0} end. +-spec sum_owner_mailboxes(kz_json:object(), ne_binaries(), count_result()) -> count_result(). +sum_owner_mailboxes(_, [], Results) -> Results; +sum_owner_mailboxes(FolderQuantities, [BoxId|BoxIds], {New, Saved}) -> + {BoxNew, BoxSaved} = normalize_count_none_deleted(BoxId, FolderQuantities), + lager:debug("adding mailbox ~s with ~p new and ~p saved messages to user's quantities" + ,[BoxId, BoxNew, BoxSaved]), + sum_owner_mailboxes(FolderQuantities, BoxIds, {New + BoxNew, Saved + BoxSaved}). + %%-------------------------------------------------------------------- %% @public %% @doc @@ -188,13 +196,11 @@ fetch(AccountId, MsgIds, BoxId) -> dict:fold(Fun, dict:new(), DbsRange) ) ). + -spec fetch_fun(ne_binary(), ne_binary(), ne_binaries(), dict:dict(), gregorian_seconds()) -> dict:dict(). fetch_fun(Db, BoxId, Ids, ResDict, RetenTimestamp) -> - ViewOpts = [{'keys', Ids} - ,'include_docs' - ], case kz_datamgr:db_exists(Db) - andalso kz_datamgr:all_docs(Db, ViewOpts) + andalso kz_datamgr:open_cache_docs(Db, Ids) of 'false' -> fetch_faild_with_reason("not_found", Db, Ids, ResDict); @@ -206,8 +212,7 @@ fetch_fun(Db, BoxId, Ids, ResDict, RetenTimestamp) -> -spec fetch_faild_with_reason(any(), ne_binary(), ne_binaries(), dict:dict()) -> dict:dict(). fetch_faild_with_reason(Reason, Db, Ids, ResDict) -> - lager:warning("failed to bulk fetch voicemail messages from db ~s: ~p" - ,[Db, Reason]), + lager:warning("failed to bulk fetch voicemail messages from db ~s: ~p", [Db, Reason]), Failed = kz_json:from_list([{Id, kz_util:to_binary(Reason)} || Id <- Ids ]), diff --git a/core/kazoo_voicemail/src/kvm_util.erl b/core/kazoo_voicemail/src/kvm_util.erl index 78fd69183eb..683a1fe6a74 100644 --- a/core/kazoo_voicemail/src/kvm_util.erl +++ b/core/kazoo_voicemail/src/kvm_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Voice mailbox utility functions %%% @end @@ -173,6 +173,7 @@ get_change_vmbox_funs(AccountId, NewBoxId, NBoxJ, OldBoxId) -> ,fun(DocJ) -> kzd_box_message:change_message_name(NBoxJ, DocJ) end ,fun(DocJ) -> kzd_box_message:change_to_sip_field(AccountId, NBoxJ, DocJ) end ,fun(DocJ) -> kzd_box_message:add_message_history(OldBoxId, DocJ) end + ,fun(DocJ) -> kz_json:set_value(<<"timestamp">>, kz_util:current_tstamp(), DocJ) end ]. %%-------------------------------------------------------------------- @@ -215,11 +216,9 @@ get_caller_id_number(Call) -> %% @end %%-------------------------------------------------------------------- -spec publish_saved_notify(ne_binary(), ne_binary(), kapps_call:call(), pos_integer(), kz_proplist()) -> - {'ok', kz_json:objects()} | - {'timeout', kz_json:objects()} | - {'error', any()}. + kz_amqp_worker:request_return(). publish_saved_notify(MediaId, BoxId, Call, Length, Props) -> - MaybeTranscribe = props:get_value(<<"Transcribe-Voicemail">>, Props), + MaybeTranscribe = props:get_value(<<"Transcribe-Voicemail">>, Props, 'false'), Transcription = maybe_transcribe(kapps_call:account_id(Call), MediaId, MaybeTranscribe), NotifyProp = [{<<"From-User">>, kapps_call:from_user(Call)} diff --git a/core/kazoo_voicemail/src/migrate/kvm_migrate_account.erl b/core/kazoo_voicemail/src/migrate/kvm_migrate_account.erl index b990d78bae0..22a53263953 100644 --- a/core/kazoo_voicemail/src/migrate/kvm_migrate_account.erl +++ b/core/kazoo_voicemail/src/migrate/kvm_migrate_account.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end @@ -211,11 +211,8 @@ update_mailboxes(AccountId, ViewResults) -> Failed = dict:from_list(get_stats(?FAILED)), BoxIds = lists:usort([kz_doc:id(B) || B <- ViewResults]), - ViewOpts = [{'keys', BoxIds} - ,'include_docs' - ], Db = kvm_util:get_db(AccountId), - case kz_datamgr:all_docs(Db, ViewOpts) of + case kz_datamgr:open_cache_docs(Db, BoxIds) of {'ok', BoxJObjs} -> NewBoxJObjs = update_mailbox_jobjs(BoxJObjs, MODbFailed, Failed), case kz_datamgr:save_docs(Db, NewBoxJObjs) of @@ -277,14 +274,8 @@ update_message_array(BoxJObj, MODbFailed, Failed) -> %%-------------------------------------------------------------------- -spec get_messages_from_vmboxes(ne_binary(), ne_binaries()) -> db_ret(). get_messages_from_vmboxes(AccountId, ExpectedBoxIds) -> - Db = kz_util:format_account_db(AccountId), - ViewOpts = props:filter_empty( - [{'keys', ExpectedBoxIds} - ,'include_docs' - ]), - case kz_datamgr:all_docs(Db, ViewOpts) of - {'ok', JObjs} -> - {'ok', normalize_mailbox_results(JObjs)}; + case kz_datamgr:open_cache_docs(kz_util:format_account_db(AccountId), ExpectedBoxIds) of + {'ok', JObjs} -> {'ok', normalize_mailbox_results(JObjs)}; {'error', _E} = Error -> ?ERROR(" [~s] failed to open mailbox(es)", [AccountId]), Error diff --git a/core/kazoo_voicemail/src/migrate/kvm_migrate_crawler.erl b/core/kazoo_voicemail/src/migrate/kvm_migrate_crawler.erl index b48a7cd93c8..08f15b8fe83 100644 --- a/core/kazoo_voicemail/src/migrate/kvm_migrate_crawler.erl +++ b/core/kazoo_voicemail/src/migrate/kvm_migrate_crawler.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz INC +%%% @copyright (C) 2017, 2600Hz INC %%% @doc %%% %%% @end diff --git a/core/kazoo_web/src/kz_html.erl b/core/kazoo_web/src/kz_html.erl index c759f4180dd..8bcf7d82f57 100644 --- a/core/kazoo_web/src/kz_html.erl +++ b/core/kazoo_web/src/kz_html.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz +%%% @copyright (C) 2015-2017, 2600Hz %%% @doc HML helper functions for Kazoo %%% %%% @contributors diff --git a/core/kazoo_web/src/kz_http.erl b/core/kazoo_web/src/kz_http.erl index 6d42e2509d4..9d3882fbf75 100644 --- a/core/kazoo_web/src/kz_http.erl +++ b/core/kazoo_web/src/kz_http.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2016, 2600Hz +%%% @copyright (C) 2017, 2600Hz %%% @doc %%% Kazoo HTTP client %%% @end diff --git a/core/kazoo_web/src/kz_http_util.erl b/core/kazoo_web/src/kz_http_util.erl index cb55ebc9b4b..99a82a15247 100644 --- a/core/kazoo_web/src/kz_http_util.erl +++ b/core/kazoo_web/src/kz_http_util.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2015-2016, 2600Hz +%%% @copyright (C) 2015-2017, 2600Hz %%% @doc HTTP helper functions for Kazoo %%% %%% @contributors diff --git a/core/kazoo_xml/src/kz_xml.erl b/core/kazoo_xml/src/kz_xml.erl index f7c6f3a54b9..056e9e3b962 100644 --- a/core/kazoo_xml/src/kz_xml.erl +++ b/core/kazoo_xml/src/kz_xml.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2014-2016, 2600Hz +%%% @copyright (C) 2014-2017, 2600Hz %%% @doc %%% %%% @end diff --git a/core/sup/src/sup.erl b/core/sup/src/sup.erl index d86272c4b4b..dd714d89454 100644 --- a/core/sup/src/sup.erl +++ b/core/sup/src/sup.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2012-2016, 2600Hz INC +%%% @copyright (C) 2012-2017, 2600Hz INC %%% @doc %%% A really simple escript to accept RPC request and push them %%% into a running kazoo virtual machine. diff --git a/core/webseq/src/webseq.erl b/core/webseq/src/webseq.erl index 438a8846fb2..66d66632dcb 100644 --- a/core/webseq/src/webseq.erl +++ b/core/webseq/src/webseq.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Log messages in a way to make importing to WebSequenceDiagrams.com %%% easier diff --git a/core/webseq/src/webseq_diagram_srv.erl b/core/webseq/src/webseq_diagram_srv.erl index f4f426164b9..6bdc3ef0b07 100644 --- a/core/webseq/src/webseq_diagram_srv.erl +++ b/core/webseq/src/webseq_diagram_srv.erl @@ -1,5 +1,5 @@ %%%------------------------------------------------------------------- -%%% @copyright (C) 2013-2016, 2600Hz +%%% @copyright (C) 2013-2017, 2600Hz %%% @doc %%% Log messages in a way to make importing to WebSequenceDiagrams.com %%% easier diff --git a/doc/blog/.org/storage.org b/doc/blog/.org/storage.org new file mode 100644 index 00000000000..fc2968961a1 --- /dev/null +++ b/doc/blog/.org/storage.org @@ -0,0 +1,274 @@ +#+OPTIONS: ':nil *:t -:t ::t <:t H:3 \n:nil ^:{} arch:headline +#+OPTIONS: author:t broken-links:nil c:nil creator:nil +#+OPTIONS: d:(not "LOGBOOK") date:t e:t email:nil f:t inline:t num:t +#+OPTIONS: p:nil pri:nil prop:nil stat:t tags:t tasks:t tex:t +#+OPTIONS: timestamp:t title:t toc:t todo:t |:t +#+TITLE: Alternative Storage Options for Kazoo +#+DATE: <2016-12-15 Thu> +#+AUTHOR: James Aimonetti +#+EMAIL: james@2600hz.com +#+LANGUAGE: en +#+SELECT_TAGS: export +#+EXCLUDE_TAGS: noexport +#+CREATOR: Emacs 26.0.50.1 (Org mode 9.0.1) + +* Alternative Storage Options for Kazoo + +Kazoo has long been opinionated about where it stores its data - [[https://en.wikipedia.org/wiki/CouchDB][CouchDB]]. Historically, the project relied on [[https://en.wikipedia.org/wiki/BigCouch][BigCouch]] but with the release of CouchDB 2.0 and Kazoo 4.0, modern installations of Kazoo can leverage the new codebase. + +However, while CouchDB serves the majority of Kazoo's needs well, there are scenarios where CouchDB isn't the best option. We'll try to cover some of those scenarios as well as provide step-by-step instructions for how to take advantage of alternative storage options. + +** Scenarios + +The most frequent request is to put call recordings (and voicemail) into a company's existing storage system, be it [[https://en.wikipedia.org/wiki/Google_Drive][Google Drive]], [[https://en.wikipedia.org/wiki/Amazon_S3][Amazon S3]], or what have you. This makes a lot of sense for companies with compliance requirements, service providers that want to use the media (perhaps run voicemail through an [[https://en.wikipedia.org/wiki/Speech_recognition][ASR engine]] and provide a transcript), or folks that just want to save a sweet voicemail from their loved one somewhere they can enjoy it at their leisure. + +Other requests that have come up have been having the ability to save [[https://en.wikipedia.org/wiki/Call_detail_record][CDRs]] directly to a provider's database or spreadsheet. This eases the provider's abililty to bill, analyze usage patterns, etc. + +Other possibilities include: + +- Sending and receiving faxes (add a PDF to your Google Drive, have it faxed automatically!) +- Store recorded calls for compliance, training, or other purposes. +- Serve custom music-on-hold or other recordings for your customers, allowing you to manage them through your storage provider's interface. +- Delete voicemail message from your mailbox when you delete the file from storage. +- And many more! + +** Introducing Storage Plans + +With Kazoo 4.0, the 'storage plan' concept is introduced to allow system administrators, resellers, and account holders, to configure alternative storage options for their needs. Storage is configured in two phases: + +1. Configure 'storage', what storage engines are available (such as adding AWS credentials for S3). +2. Configure 'plans', to determine what types of data will use which configured 'storage' option. + +** Getting started + +System administrators will need to enable the 'storage' endpoint in Crossbar: + +#+BEGIN_SRC sh +sup crossbar_maintenance start_module cb_storage +#+END_SRC + +Once started, query the base storage endpoint: +#+BEGIN_SRC sh +curl -v -H "X-Auth-Token: $AUTH_TOKEN" \ "http://localhost:8000/v2/accounts/$ACCOUNT_ID/storage" +#+END_SRC +#+BEGIN_SRC json +{ + "data": { + "cause": "{ACCOUNT_ID}", + "message": "bad identifier" + }, + "error": "404", + "message": "bad_identifier", + "status": "error", + "request_id": "{REQUEST_ID}", + "auth_token": "{AUTH_TOKEN}" +} +#+END_SRC + +What happened? + +Well, the storage hasn't been configured yet, so of course it wasn't found. + +*** Create the initial storage + +Let's create the initial storage configuration document: +#+BEGIN_SRC sh +curl -v -X PUT \ + -H "X-Auth-Token: $AUTH_TOKEN" \ + -d '{"data":{}}' + "http://localhost:8000/v2/accounts/$ACCOUNT_ID/storage" +#+END_SRC +#+BEGIN_SRC json +{ + "data": { + "id": "{ACCOUNT_ID}" + }, + "revision": "1-f0b539057db194c04f76cd1e0a2144cd", + "request_id": "{REQUEST_ID}", + "status": "success", + "auth_token": "{AUTH_TOKEN} +} +#+END_SRC +*** Add S3 configuration + +First, we need a 32-character UUID which will be the ID of the S3 configuration that we'll use later in the storage plan setup. Creating a UUID is easy to do with the following cURL command: +#+BEGIN_SRC sh +curl https://www.uuidgenerator.net/api/version4/1 | sed 's/-//g' +e3e26e06a4b1465599e6dc9e1516fd8b +#+END_SRC + +We'll use the UUID to PATCH the 'storage' document with our 'attachments' object. First, the 'storage' JSON to PATCH: + +#+BEGIN_SRC json +{ + "attachments": { + "{UUID}":{ + "handler":"s3", + "name":"Kazoo S3 storage config", + "settings":{ + "bucket":"my_kazoo_bucket_name", + "key":"{AWS_ACCESS_KEY}", + "secret":"{AWS_SECRET_KEY}" + } + } + } +} +#+END_SRC + +Let's now add that to the JSON envelope and PATCH it in: +#+BEGIN_SRC sh +curl -v -X PATCH \ + -H "X-Auth-Token: $AUTH_TOKEN" \ + -d '{"data":{ + "attachments": { + "{UUID}":{ + "handler":"s3", + "name":"Kazoo S3", + "settings":{ + "bucket":"{S3_BUCKET}", + "key":"{AWS_ACCESS_KEY}", + "secret":"{AWS_SECRET_KEY}" + } + } + } +}}' \ + "http://localhost:8000/v2/accounts/$ACCOUNT_ID/storage" +#+END_SRC +#+BEGIN_SRC json +{ + "auth_token": "{AUTH_TOKEN}", + "data": { + "attachments": { + "{UUID}": { + "handler": "s3", + "name": "Kazoo S3", + "settings": { + "bucket": "{S3_BUCKET}", + "key": "{AWS_ACCESS_KEY}", + "secret": "{AWS_SECRET_KEY}" + } + } + }, + "id": "{ACCOUNT_ID}" + }, + "request_id": "{REQUEST_ID}", + "revision": "1-f0b539057db194c04f76cd1e0a2144cd", + "status": "success" +} +#+END_SRC + +Success! We now have an attachment configuration at '{UUID}' to reference elsewhere. +** Creating Storage Plans + +Now that we've created a storage configuration for S3 we can create a storage plan for our account. This will allow us to specify what types of data we want to use our S3 backend. + +There are three database categories available for configuration: + +1. Account - documents that would be stored in the account's database, like configuration data for devices, users, etc. +2. Month-only (modb) - temporal data related to an account (CDRs, recordings, etc) +3. System - for administrators, store system data elsewhere. + +For our purposes, we'll focus on the modb plan to store our voicemails. + +Our base "plan" will look like this: +#+BEGIN_SRC json +{ + "plan":{ + "modb":{ + } + } +} +#+END_SRC + +*** MODB plan + +For the modb plan, we want to only store certain types of attachments (voicemails) so we define a 'types' object that will configure Kazoo to store voicemails to our S3. In Kazoo, voicemails are known as 'mailbox messages' since we plan on supporting video voicemail and other things in the future. + +Augmenting our plan to add the 'types' restriction: +#+BEGIN_SRC json +{ + "plan":{ + "modb":{ + "types":{ + "mailbox_message":{ + } + } + } + } +} +#+END_SRC + +*** Mailbox message attachments + +We just want to store the binary data (and not the metadata) in S3, so we'll define an 'attachments' object to point to S3. This is done in the 'handler' property and will use the UUID we defined above: + +#+BEGIN_SRC json +{ + "plan":{ + "modb":{ + "types":{ + "mailbox_message":{ + "attachments":{ + "handler":"{UUID}" + } + } + } + } + } +} +#+END_SRC + +*** Adding the plan + +Just as we did with the S3 configs, we'll PATCH our storage document to add our plan: + +#+BEGIN_SRC sh +curl -v -X PATCH -H "content-type: application/json" -H "X-Auth-Token: $AUTH_TOKEN" "http://localhost:8000/v2/accounts/$ACCOUNT_ID/storage" -d '{"data":{"plan":{ + "modb":{ + "types":{ + "mailbox_message":{ + "attachments":{ + "handler":"e3e26e06a4b1465599e6dc9e1516fd8b" + } + } + } + } + }}}' +#+END_SRC +#+BEGIN_SRC json +{ + "auth_token": "{AUTH_TOKEN}", + "data": { + "attachments": { + "{UUID}": { + "handler": "s3", + "name": "Kazoo S3", + "settings": { + "bucket": "{S3_BUCKET}", + "key": "{AWS_ACCESS_KEY}", + "secret": "{AWS_SECRET_KEY}" + } + } + }, + "id": "{ACCOUNT_ID}", + "plan": { + "modb": { + "types": { + "mailbox_message": { + "attachments": { + "handler": "{UUID}" + } + } + } + } + } + }, + "request_id": "{REQUEST_ID}", + "revision": "7-ec3ee8ff8893e59ad8064bcbe684bde5", + "status": "success" +} +#+END_SRC +** Wrapping Up +Now that you've created the storage plan for the account, try placing a call to leave a voicemail. Once left, you should see a file appear in your S3 bucket within a minute or two! + +There's a lot more to storage than just pushing voicemails to S3. We'll cover those in future articles! diff --git a/doc/blog/storage.md b/doc/blog/storage.md new file mode 100644 index 00000000000..521248b41f2 --- /dev/null +++ b/doc/blog/storage.md @@ -0,0 +1,320 @@ +- [Alternative Storage Options for Kazoo](#org8916b87) + - [Scenarios](#orgdbd1b36) + - [Introducing Storage Plans](#orga265582) + - [Getting started](#org6770240) + - [Create the initial storage](#org8386c70) + - [Add S3 configuration](#org889959c) + - [Creating Storage Plans](#orge72995a) + - [MODB plan](#org5099381) + - [Mailbox message attachments](#org782a1d9) + - [Adding the plan](#org150e76d) + - [Wrapping Up](#orga6745b5) + + + + + +# Alternative Storage Options for Kazoo + +Kazoo has long been opinionated about where it stores its data - [CouchDB](https://en.wikipedia.org/wiki/CouchDB). Historically, the project relied on [BigCouch](https://en.wikipedia.org/wiki/BigCouch) but with the release of CouchDB 2.0 and Kazoo 4.0, modern installations of Kazoo can leverage the new codebase. + +However, while CouchDB serves the majority of Kazoo's needs well, there are scenarios where CouchDB isn't the best option. We'll try to cover some of those scenarios as well as provide step-by-step instructions for how to take advantage of alternative storage options. + + + + +## Scenarios + +The most frequent request is to put call recordings (and voicemail) into a company's existing storage system, be it [Google Drive](https://en.wikipedia.org/wiki/Google_Drive), [Amazon S3](https://en.wikipedia.org/wiki/Amazon_S3), or what have you. This makes a lot of sense for companies with compliance requirements, service providers that want to use the media (perhaps run voicemail through an [ASR engine](https://en.wikipedia.org/wiki/Speech_recognition) and provide a transcript), or folks that just want to save a sweet voicemail from their loved one somewhere they can enjoy it at their leisure. + +Other requests that have come up have been having the ability to save [CDRs](https://en.wikipedia.org/wiki/Call_detail_record) directly to a provider's database or spreadsheet. This eases the provider's abililty to bill, analyze usage patterns, etc. + +Other possibilities include: + +- Sending and receiving faxes (add a PDF to your Google Drive, have it faxed automatically!) +- Store recorded calls for compliance, training, or other purposes. +- Serve custom music-on-hold or other recordings for your customers, allowing you to manage them through your storage provider's interface. +- Delete voicemail message from your mailbox when you delete the file from storage. +- And many more! + + + + +## Introducing Storage Plans + +With Kazoo 4.0, the 'storage plan' concept is introduced to allow system administrators, resellers, and account holders, to configure alternative storage options for their needs. Storage is configured in two phases: + +1. Configure 'storage', what storage engines are available (such as adding AWS credentials for S3). +2. Configure 'plans', to determine what types of data will use which configured 'storage' option. + + + + +## Getting started + +System administrators will need to enable the 'storage' endpoint in Crossbar: + +```sh +sup crossbar_maintenance start_module cb_storage +``` + +Once started, query the base storage endpoint: + +```sh +curl -v -H "X-Auth-Token: $AUTH_TOKEN" \ "http://localhost:8000/v2/accounts/$ACCOUNT_ID/storage" +``` + +```json +{ + "data": { + "cause": "{ACCOUNT_ID}", + "message": "bad identifier" + }, + "error": "404", + "message": "bad_identifier", + "status": "error", + "request_id": "{REQUEST_ID}", + "auth_token": "{AUTH_TOKEN}" +} +``` + +What happened? + +Well, the storage hasn't been configured yet, so of course it wasn't found. + + + + +### Create the initial storage + +Let's create the initial storage configuration document: + +```sh +curl -v -X PUT \ + -H "X-Auth-Token: $AUTH_TOKEN" \ + -d '{"data":{}}' + "http://localhost:8000/v2/accounts/$ACCOUNT_ID/storage" +``` + +```json +{ + "data": { + "id": "{ACCOUNT_ID}" + }, + "revision": "1-f0b539057db194c04f76cd1e0a2144cd", + "request_id": "{REQUEST_ID}", + "status": "success", + "auth_token": "{AUTH_TOKEN} +} +``` + + + + +### Add S3 configuration + +First, we need a 32-character UUID which will be the ID of the S3 configuration that we'll use later in the storage plan setup. Creating a UUID is easy to do with the following cURL command: + +```sh +curl https://www.uuidgenerator.net/api/version4/1 | sed 's/-//g' +e3e26e06a4b1465599e6dc9e1516fd8b +``` + +We'll use the UUID to PATCH the 'storage' document with our 'attachments' object. First, the 'storage' JSON to PATCH: + +```json +{ + "attachments": { + "{UUID}":{ + "handler":"s3", + "name":"Kazoo S3 storage config", + "settings":{ + "bucket":"my_kazoo_bucket_name", + "key":"{AWS_ACCESS_KEY}", + "secret":"{AWS_SECRET_KEY}" + } + } + } +} +``` + +Let's now add that to the JSON envelope and PATCH it in: + +```sh +curl -v -X PATCH \ + -H "X-Auth-Token: $AUTH_TOKEN" \ + -d '{"data":{ + "attachments": { + "{UUID}":{ + "handler":"s3", + "name":"Kazoo S3", + "settings":{ + "bucket":"{S3_BUCKET}", + "key":"{AWS_ACCESS_KEY}", + "secret":"{AWS_SECRET_KEY}" + } + } + } +}}' \ + "http://localhost:8000/v2/accounts/$ACCOUNT_ID/storage" +``` + +```json +{ + "auth_token": "{AUTH_TOKEN}", + "data": { + "attachments": { + "{UUID}": { + "handler": "s3", + "name": "Kazoo S3", + "settings": { + "bucket": "{S3_BUCKET}", + "key": "{AWS_ACCESS_KEY}", + "secret": "{AWS_SECRET_KEY}" + } + } + }, + "id": "{ACCOUNT_ID}" + }, + "request_id": "{REQUEST_ID}", + "revision": "1-f0b539057db194c04f76cd1e0a2144cd", + "status": "success" +} +``` + +Success! We now have an attachment configuration at '{UUID}' to reference elsewhere. + + + + +## Creating Storage Plans + +Now that we've created a storage configuration for S3 we can create a storage plan for our account. This will allow us to specify what types of data we want to use our S3 backend. + +There are three database categories available for configuration: + +1. Account - documents that would be stored in the account's database, like configuration data for devices, users, etc. +2. Month-only (modb) - temporal data related to an account (CDRs, recordings, etc) +3. System - for administrators, store system data elsewhere. + +For our purposes, we'll focus on the modb plan to store our voicemails. + +Our base "plan" will look like this: + +```json +{ + "plan":{ + "modb":{ + } + } +} +``` + + + + +### MODB plan + +For the modb plan, we want to only store certain types of attachments (voicemails) so we define a 'types' object that will configure Kazoo to store voicemails to our S3. In Kazoo, voicemails are known as 'mailbox messages' since we plan on supporting video voicemail and other things in the future. + +Augmenting our plan to add the 'types' restriction: + +```json +{ + "plan":{ + "modb":{ + "types":{ + "mailbox_message":{ + } + } + } + } +} +``` + + + + +### Mailbox message attachments + +We just want to store the binary data (and not the metadata) in S3, so we'll define an 'attachments' object to point to S3. This is done in the 'handler' property and will use the UUID we defined above: + +```json +{ + "plan":{ + "modb":{ + "types":{ + "mailbox_message":{ + "attachments":{ + "handler":"{UUID}" + } + } + } + } + } +} +``` + + + + +### Adding the plan + +Just as we did with the S3 configs, we'll PATCH our storage document to add our plan: + +```sh +curl -v -X PATCH -H "content-type: application/json" -H "X-Auth-Token: $AUTH_TOKEN" "http://localhost:8000/v2/accounts/$ACCOUNT_ID/storage" -d '{"data":{"plan":{ + "modb":{ + "types":{ + "mailbox_message":{ + "attachments":{ + "handler":"e3e26e06a4b1465599e6dc9e1516fd8b" + } + } + } + } + }}}' +``` + +```json +{ + "auth_token": "{AUTH_TOKEN}", + "data": { + "attachments": { + "{UUID}": { + "handler": "s3", + "name": "Kazoo S3", + "settings": { + "bucket": "{S3_BUCKET}", + "key": "{AWS_ACCESS_KEY}", + "secret": "{AWS_SECRET_KEY}" + } + } + }, + "id": "{ACCOUNT_ID}", + "plan": { + "modb": { + "types": { + "mailbox_message": { + "attachments": { + "handler": "{UUID}" + } + } + } + } + } + }, + "request_id": "{REQUEST_ID}", + "revision": "7-ec3ee8ff8893e59ad8064bcbe684bde5", + "status": "success" +} +``` + + + + +## Wrapping Up + +Now that you've created the storage plan for the account, try placing a call to leave a voicemail. Once left, you should see a file appear in your S3 bucket within a minute or two! + +There's a lot more to storage than just pushing voicemails to S3. We'll cover those in future articles! \ No newline at end of file diff --git a/doc/engineering/dialyzer.md b/doc/engineering/dialyzer.md index 8b6d0b35bac..932fd55031b 100644 --- a/doc/engineering/dialyzer.md +++ b/doc/engineering/dialyzer.md @@ -1,7 +1,3 @@ -/* -Section: Kazoo -Title: Dialyzer -*/ # Using Dialyzer on Kazoo diff --git a/doc/engineering/releases.md b/doc/engineering/releases.md index 647a52dd406..5682175b700 100644 --- a/doc/engineering/releases.md +++ b/doc/engineering/releases.md @@ -1,7 +1,3 @@ -/* -Section: Kazoo -Title: Releases -*/ # How to use Erlang releases with Kazoo diff --git a/doc/installation.md b/doc/installation.md index 44e75f654e1..75824a1714e 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -15,6 +15,13 @@ $ sudo apt-get install build-essential libxslt-dev \ Note: `htmldoc` is required only if [you want to be able to download PDFs](./announcements.md#company-directory-pdf). +#### Docs-relatd + +When running `make docs`, some Python libraries are useful: + +```shell +$ sudo apt-get install python2.7 python-yaml +``` ### Erlang diff --git a/doc/kazoocon/pivot2014.md b/doc/kazoocon/pivot2014.md index d3add865ecf..a9fbfd14d2b 100644 --- a/doc/kazoocon/pivot2014.md +++ b/doc/kazoocon/pivot2014.md @@ -1,8 +1,3 @@ -/* -Section: Pivot -Title: Pivot KazooCon 2014 Demo -Language: en-US -*/ # Infrastructure by Pastie.org diff --git a/doc/mkdocs/mkdocs.yml b/doc/mkdocs/mkdocs.yml index b7103542839..ae374da7536 100644 --- a/doc/mkdocs/mkdocs.yml +++ b/doc/mkdocs/mkdocs.yml @@ -1,9 +1,69 @@ site_name: Dev Reference -theme: null theme_dir: '2600Hz_theme' pages: - 'index.md' +- 'Voice': + - 'API Basics': + - 'applications/crossbar/doc/api_authentication.md' + - 'applications/crossbar/doc/basic_auth.md' + - 'applications/crossbar/doc/basics.md' + - 'applications/crossbar/doc/multipart.md' + - 'applications/crossbar/doc/schemas.md' + - 'applications/crossbar/doc/token_auth.md' + - 'applications/crossbar/doc/user_authentication.md' + - 'applications/crossbar/doc/402.md' + - 'Account Management': + - 'applications/crossbar/doc/whitelabeling.md' + - 'applications/crossbar/doc/transactions.md' + - 'applications/crossbar/doc/services.md' + - 'applications/crossbar/doc/service_plans.md' + - 'applications/crossbar/doc/search.md' + - 'applications/crossbar/doc/port_requests.md' + - 'applications/crossbar/doc/limits.md' + - 'applications/crossbar/doc/allotments.md' + - 'applications/crossbar/doc/accounts.md' + - 'Billing': + - 'applications/crossbar/doc/ledgers.md' + - 'applications/crossbar/doc/cdrs.md' + - 'Branding': + - 'applications/crossbar/doc/notifications.md' + - 'Connectivity': + - 'applications/crossbar/doc/resources.md' + - 'applications/crossbar/doc/rates.md' + - 'applications/crossbar/doc/ips.md' + - 'Media Management': + - 'applications/crossbar/doc/media.md' + - 'Misc': + - 'applications/crossbar/doc/comments.md' + - 'PBX Features': + - 'applications/crossbar/doc/voicemail.md' + - 'applications/crossbar/doc/users.md' + - 'applications/crossbar/doc/temporal_rules_sets.md' + - 'applications/crossbar/doc/recordings.md' + - 'applications/crossbar/doc/phone_numbers.md' + - 'applications/crossbar/doc/metaflows.md' + - 'applications/crossbar/doc/groups.md' + - 'applications/crossbar/doc/faxes.md' + - 'applications/crossbar/doc/directories.md' + - 'applications/crossbar/doc/devices.md' + - 'applications/crossbar/doc/conference.md' + - 'applications/crossbar/doc/blacklists.md' + - 'Status': + - 'applications/crossbar/doc/registrations.md' + - 'applications/crossbar/doc/presence.md' + - 'applications/crossbar/doc/channels.md' + - 'System Management': + - 'applications/crossbar/doc/token_restrictions.md' + - 'applications/crossbar/doc/system_configs.md' + - 'applications/crossbar/doc/sup.md' + - 'applications/crossbar/doc/securing_crossbar.md' + - 'applications/crossbar/doc/reverse_proxy.md' + - 'applications/crossbar/doc/rate_limiting.md' + - 'applications/crossbar/doc/maintenance.md' + - 'applications/crossbar/doc/configuration.md' + - 'applications/crossbar/doc/call_inspector.md' + - 'applications/crossbar/doc/apps_store.md' - 'Integrations': - 'Pivot': - 'Intro': 'applications/pivot/doc/README.md' @@ -17,7 +77,7 @@ pages: - 'Twiml': - 'applications/pivot/doc/twiml/README.md' - 'Tutorials': - - 'applications/pivot/doc/kazoocon-2014.md' + - 'doc/kazoocon/pivot2014.md' - 'Known_Issues': - 'applications/pivot/doc/issues.md' - 'Kazoo': @@ -31,64 +91,3 @@ pages: - 'applications/pivot/doc/kazoo/conferencing.md' - 'applications/pivot/doc/kazoo/collect.md' - 'applications/pivot/doc/kazoo/bridging.md' -- 'Voice': - - 'System Management': - - 'applications/crossbar/doc/token_restrictions.md' - - 'applications/crossbar/doc/system_configs.md' - - 'applications/crossbar/doc/sup.md' - - 'applications/crossbar/doc/securing_crossbar.md' - - 'applications/crossbar/doc/reverse_proxy.md' - - 'applications/crossbar/doc/rate_limiting.md' - - 'applications/crossbar/doc/maintenance.md' - - 'applications/crossbar/doc/configuration.md' - - 'applications/crossbar/doc/call_inspector.md' - - 'applications/crossbar/doc/apps_store.md' - - 'Status': - - 'applications/crossbar/doc/registrations.md' - - 'applications/crossbar/doc/presence.md' - - 'applications/crossbar/doc/channels.md' - - 'PBX Features': - - 'applications/crossbar/doc/voicemail.md' - - 'applications/crossbar/doc/users.md' - - 'applications/crossbar/doc/temporal_rules_sets.md' - - 'applications/crossbar/doc/recordings.md' - - 'applications/crossbar/doc/phone_numbers.md' - - 'applications/crossbar/doc/metaflows.md' - - 'applications/crossbar/doc/groups.md' - - 'applications/crossbar/doc/faxes.md' - - 'applications/crossbar/doc/directories.md' - - 'applications/crossbar/doc/devices.md' - - 'applications/crossbar/doc/conference.md' - - 'applications/crossbar/doc/blacklists.md' - - 'Misc': - - 'applications/crossbar/doc/comments.md' - - 'Media Management': - - 'applications/crossbar/doc/media.md' - - 'Connectivity': - - 'applications/crossbar/doc/resources.md' - - 'applications/crossbar/doc/rates.md' - - 'applications/crossbar/doc/ips.md' - - 'Branding': - - 'applications/crossbar/doc/notifications.md' - - 'Billing': - - 'applications/crossbar/doc/ledgers.md' - - 'applications/crossbar/doc/cdrs.md' - - 'Account Management': - - 'applications/crossbar/doc/whitelabeling.md' - - 'applications/crossbar/doc/transactions.md' - - 'applications/crossbar/doc/services.md' - - 'applications/crossbar/doc/service_plans.md' - - 'applications/crossbar/doc/search.md' - - 'applications/crossbar/doc/port_requests.md' - - 'applications/crossbar/doc/limits.md' - - 'applications/crossbar/doc/allotments.md' - - 'applications/crossbar/doc/accounts.md' - - 'API Basics': - - 'applications/crossbar/doc/user_authentication.md' - - 'applications/crossbar/doc/token_auth.md' - - 'applications/crossbar/doc/schemas.md' - - 'applications/crossbar/doc/multipart.md' - - 'applications/crossbar/doc/basics.md' - - 'applications/crossbar/doc/basic_auth.md' - - 'applications/crossbar/doc/api_authentication.md' - - 'applications/crossbar/doc/402.md' diff --git a/doc/reference/caller_id_formatting.md b/doc/reference/caller_id_formatting.md index 5b19ef77031..5f157e690b0 100644 --- a/doc/reference/caller_id_formatting.md +++ b/doc/reference/caller_id_formatting.md @@ -1,7 +1,3 @@ -/* -Section: Kazoo -Title: Caller ID Formatting -*/ # Caller ID Formatting diff --git a/doc/reference/routing.md b/doc/reference/routing.md index 458b0bb7f53..dd86c4f49b5 100644 --- a/doc/reference/routing.md +++ b/doc/reference/routing.md @@ -1,9 +1,3 @@ -/* -Section: Reference -Title: Rating and Limits -Language: en-US -Version: 3.22 -*/ # Rating and Limits diff --git a/make/deps.mk b/make/deps.mk index f8346429ec3..b63e1d59e6c 100644 --- a/make/deps.mk +++ b/make/deps.mk @@ -21,11 +21,12 @@ dep_detergent = git https://github.com/pap/detergent e86dfeded3e4f9f3f9278c6a1ae dep_jiffy = hex 0.14.7 dep_nklib = git https://github.com/NetComposer/nklib -dep_couchbeam = git https://github.com/lazedo/couchbeam 1.3.1.2 -###dep_couchbeam = git https://github.com/benoitc/couchbeam 1.3.1 -### waiting for pull request -### https://github.com/benoitc/couchbeam/pull/149 -### after that one is merged, another will follow +dep_couchbeam = git https://github.com/2600hz/couchbeam 1.4.1a +###dep_couchbeam = git https://github.com/benoitc/couchbeam 1.4.1 +### waiting for pull requests +### https://github.com/benoitc/couchbeam/pull/158 +### https://github.com/benoitc/couchbeam/pull/164 +### https://github.com/benoitc/couchbeam/pull/165 ##dep_jesse = git https://github.com/for-GET/jesse 1.4.0 ## pull request pending @@ -34,7 +35,7 @@ dep_couchbeam = git https://github.com/lazedo/couchbeam 1.3.1.2 ## there are some commits after 1.4.0 that will go into 1.5.0 ## that break a loot of stuff. please be careful if updating to 1.5.0 ## from for-GET/jesse -dep_jesse = git https://github.com/lazedo/jesse 1.4.3 +dep_jesse = git https://github.com/2600hz/jesse 1.4.4 dep_lager = git https://github.com/erlang-lager/lager 3.2.1 dep_trie = git https://github.com/okeuday/trie v1.5.4 diff --git a/scripts/check-dialyzer.escript b/scripts/check-dialyzer.escript index 05aa5f741bf..e6bf39e5073 100755 --- a/scripts/check-dialyzer.escript +++ b/scripts/check-dialyzer.escript @@ -154,6 +154,9 @@ filter(W) -> %% More ETS false positives, from applications/ {warn_matching, {"src/ecallmgr_fs_channels.erl",_}, {pattern_match,["pattern <{[Channel = {'channel', CallId, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _"++_,_]}} -> 'false'; + %% Dialyzer on 18 & 19 "such contracts are currently unsupported and are simply ignored" + {warn_contract_types, _, {overlapping_contract,_}} -> 'false'; + _ -> %% io:format("W = ~p\n", [W]), 'true' diff --git a/scripts/generate-doc-schemas.sh b/scripts/generate-doc-schemas.sh new file mode 100755 index 00000000000..77b2164fc0e --- /dev/null +++ b/scripts/generate-doc-schemas.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env python2 + +# print 'Usage: ' + sys.argv[0] + ' doc/ref/*.md' + +from __future__ import print_function +import os +import re +import sys + +if len(sys.argv) < 2: + pass + +def find_schema(txt): + found = re.findall('#### Schema\n\n[^>]*\n\n\n', txt, re.MULTILINE | re.DOTALL) + return found[0] + +def public_doc(ref_path): + doc_root = os.path.dirname(os.path.dirname(ref_path)) + ref_name = os.path.basename(ref_path) + ref_to_doc = { + 'api_auth.md': 'api_authentication.md', + 'conferences.md': 'conference.md', + 'user_auth.md': 'user_authentication.md', + 'vmboxes.md': 'voicemail.md', + 'whitelabel.md': 'whitelabeling.md', + } + return os.path.join(doc_root, ref_to_doc.get(ref_name, ref_name)) + +errors = 0 +for fname in sys.argv[1::]: + docname = public_doc(fname) + try: + with open(fname, 'r') as f: + schemas = find_schema(f.read()) + except IndexError: + # print('No schemas found, ignoring', fname) + continue + + if not os.path.isfile(docname): + print('Doc does not exist, please create', docname, file=sys.stderr) + errors += 1 + continue + + with open(docname, 'r') as f: + whole_doc = f.read() + outdated = find_schema(whole_doc) + updated = whole_doc.replace(outdated, schemas) + try: + with open(docname, 'w') as f: + f.write(updated) + except IndexError: + print('These missing schemas need to be manually added to', docname, file=sys.stderr) + print(schemas, file=sys.stderr) + errors += 1 + +sys.exit(errors) diff --git a/scripts/validate_mkdocs.py b/scripts/validate_mkdocs.py new file mode 100755 index 00000000000..1d14e073d9f --- /dev/null +++ b/scripts/validate_mkdocs.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python2 +from __future__ import print_function + +import yaml, os.path, sys + +# from https://stackoverflow.com/questions/5574702/how-to-print-to-stderr-in-python +def eprint(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + +def parse_page_dict(errors_detected, kv): + (header, pages) = kv + if pages is None: + eprint("section ", header, " is incomplete") + return True + else: + return parse_page(errors_detected, pages) + +def parse_page_string(errors_detected, page): + if "index.md" != page and (not os.path.isfile(page)): + eprint("page ", page, " is not valid") + return True + else: + return errors_detected + +def parse_page(errors_detected, page): + "parse a page for existence" + if isinstance(page, dict): + return reduce(parse_page_dict, page.items(), errors_detected) + elif isinstance(page, list): + return reduce(parse_page, page, errors_detected) + elif isinstance(page, str): + return parse_page_string(errors_detected, page) + else: + return errors_detected + +stream = open("doc/mkdocs/mkdocs.yml", 'r') +mkdocs = yaml.load_all(stream) +errors_detected = False + +for doc in mkdocs: + for k,v in doc.items(): + if "pages" == k: + errors_detected = parse_page(False, v) + +if errors_detected: + sys.exit(1)