%%%----------------------------------------------------------------------------- %%% @copyright (C) 2011-2019, 2600Hz %%% @doc Handles inspection of incoming caller id and branching to a child %%% callflow node accordingly. %%% %%%

Data options:

%%%
%%%
`use_absolute_mode'
%%%
A boolean, if `true', direct call down a branch that matches the %%% incoming caller ID. If `false', use regex to determine whether incoming call %%% should directed down the "match" or "nomatch" branch. Default is `false'. %%%
%%% %%%
`regex'
%%%
A regular expression (like `^\\+15558881111') used to determine match/nomatch %%% when `use_absolute_mode' is `false'. Default matches all incoming caller IDs. %%%
%%% %%%
`caller_id'
%%%
Optional: Caller ID to applied to incoming call. %%%
%%%
`external'
%%%
Applied to external caller ID. Matches branch, if specified. %%%
%%%
`name'
A string for caller ID name, e.g. "Joseph"
%%%
`number'
A string for caller ID number, e.g. "+15558881122"
%%%
%%%
%%% %%%
`internal'
%%%
Applied to internal caller ID. %%%
%%%
`name'
A string for caller ID name, e.g. "Joseph"
%%%
`number'
A string for caller ID number, e.g. "+15558881122"
%%%
%%%
%%%
%%%
%%% %%%
`user_id'
%%%
Optional: User Id applied as owner of incoming call when %%% a call goes down the match branch, if specified. %%%
%%%
%%% %%% Sample for children section of Callflow to branch into based on the variable: %%% ``` %%% "children": { %%% "match": { // callflow node to branch to when absolute mode is false and regex matches }, %%% "nomatch": { // callflow node to branch to when regex does not match or no child node defined for incoming caller id }, %%% "+15558881111": { // callflow node to branch to absolute mode is true and caller id matches +15558881111) } %%% } %%% ''' %%% %%% @author Brian Davis %%% @end %%%----------------------------------------------------------------------------- -module(cf_check_cid). -behaviour(gen_cf_action). -export([handle/2]). -include("callflow.hrl"). %%------------------------------------------------------------------------------ %% @doc Entry point for this module %% @end %%------------------------------------------------------------------------------ -spec handle(kz_json:object(), kapps_call:call()) -> 'ok'. handle(Data, Call) -> CallerIdNumber = kapps_call:caller_id_number(Call), Regex = kz_json:get_ne_binary_value(<<"regex">>, Data, <<".*">>), lager:debug("comparing caller id ~s against regex ~s", [CallerIdNumber, Regex]), case re:run(CallerIdNumber, Regex) of {'match', _} -> handle_match(Data, Call, CallerIdNumber); 'nomatch' -> handle_no_match(Call) end. %%------------------------------------------------------------------------------ %% @doc Handle a caller id "match" condition %% @end %%------------------------------------------------------------------------------ -spec handle_match(kz_json:object(), kapps_call:call(), kz_term:ne_binary()) -> 'ok'. handle_match(Data, Call, CallerIdNumber) -> case kz_json:is_true(<<"use_absolute_mode">>, Data, 'false') of 'true' -> maybe_branch_on_caller_id(Data, Call, CallerIdNumber); 'false' -> maybe_branch_on_regex(Data, Call) end. -spec maybe_branch_on_caller_id(kz_json:object(), kapps_call:call(), kz_term:ne_binary()) -> 'ok'. maybe_branch_on_caller_id(Data, Call, CallerIdNumber) -> case is_callflow_child(CallerIdNumber, Call) of 'true' -> update_caller_identity(Data, Call); 'false' -> cf_exe:continue(Call) end. -spec maybe_branch_on_regex(kz_json:object(), kapps_call:call()) -> 'ok'. maybe_branch_on_regex(Data, Call) -> case is_callflow_child(<<"match">>, Call) of 'true' -> update_caller_identity(Data, Call); 'false' -> cf_exe:continue(Call) end. %%------------------------------------------------------------------------------ %% @doc Handle a caller id "no match" condition %% @end %%------------------------------------------------------------------------------ -spec handle_no_match(kapps_call:call()) -> 'ok'. handle_no_match(Call) -> case is_callflow_child(<<"nomatch">>, Call) of 'true' -> 'ok'; 'false' -> cf_exe:continue(Call) end. %%------------------------------------------------------------------------------ %% @doc Check if the given node name is a callflow child %% @end %%------------------------------------------------------------------------------ -spec is_callflow_child(kz_term:ne_binary(), kapps_call:call()) -> boolean(). is_callflow_child(Name, Call) -> lager:debug("looking for callflow child ~s", [Name]), case cf_exe:attempt(Name, Call) of {'attempt_resp', 'ok'} -> lager:debug("found callflow child"), 'true'; {'attempt_resp', {'error', _}} -> lager:debug("failed to find callflow child"), 'false' end. %%------------------------------------------------------------------------------ %% @doc update the caller id and owner information for this call %% @end %%------------------------------------------------------------------------------ -spec update_caller_identity(kz_json:object(), kapps_call:call()) -> 'ok'. update_caller_identity(Data, Call) -> Name = kz_json:get_ne_binary_value([<<"caller_id">>, <<"external">>, <<"name">>], Data), Number = kz_json:get_ne_binary_value([<<"caller_id">>, <<"external">>, <<"number">>], Data), UserId = kz_json:get_ne_binary_value([<<"user_id">>], Data), case is_valid_caller_identity(Name, Number, UserId) of 'true' -> lager:info("setting caller id to ~s <~s>", [Number, Name]), lager:info("setting owner id to ~s", [UserId]), 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:kvs_store('owner_id', UserId, C) end ], {'ok', C} = cf_exe:get_call(Call), cf_exe:set_call(kapps_call:exec(Updates, C)); 'false' -> 'ok' end. %%------------------------------------------------------------------------------ %% @doc validate that all required parameters are defined %% @end %%------------------------------------------------------------------------------ -spec is_valid_caller_identity(kz_term:api_binary(), kz_term:api_binary(), kz_term:api_binary()) -> boolean(). is_valid_caller_identity('undefined', _Number, _UserId) -> 'false'; is_valid_caller_identity(_Name, 'undefined', _UserId) -> 'false'; is_valid_caller_identity(_Name, _Number, 'undefined') -> 'false'; is_valid_caller_identity(_Name, _Number, _UserId) -> 'true'.