Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'WHISTLE-1388'

Conflicts:
	whistle_apps/apps/callflow/src/cf_util.erl
  • Loading branch information...
commit 790c292125c5ddf69f12e4402e89890e7b9173ef 2 parents 02edc2d + 5607e61
James Aimonetti jamesaimonetti authored
203 lib/whistle_couch-1.0.0/src/couch_compactor.erl
View
@@ -16,15 +16,6 @@
,compact_db/2
]).
-%% Conflict resolution-enabled API
--export([compact_all/1
- ,compact_all/2
- ,compact_node/2
- ,compact_node/3
- ,compact_db/3
- ,compact_db/4
- ]).
-
%% internal API functions
-export([compact_shard/3]).
@@ -44,95 +35,49 @@ init(Parent) ->
lager:debug("starting compactor"),
- case {couch_config:fetch(<<"compact_automatically">>, false), couch_config:fetch(<<"conflict_strategy">>, null)} of
- {true, null} ->
+ case couch_config:fetch(<<"compact_automatically">>, false) of
+ true ->
lager:debug("just compacting"),
proc_lib:init_ack(Parent, {ok, self()}),
compact_all();
- {true, Strategy} ->
- lager:debug("compacting and removing conflicts"),
- proc_lib:init_ack(Parent, {ok, self()}),
- compact_all(Strategy);
- {false, _Strategy} ->
+ false ->
lager:debug("auto-compaction not enabled"),
- proc_lib:init_ack(Parent, ignore);
- {null, _Strategy} ->
- lager:debug("auto-compaction not enabled"),
- proc_lib:init_ack(Parent, ignore),
- couch_config:store(<<"compact_automatically">>, false);
- _Other ->
- lager:debug("unexpected values for auto-compaction: ~p", [_Other])
+ proc_lib:init_ack(Parent, ignore)
end.
-spec compact_all/0 :: () -> 'done'.
--spec compact_all/1 :: (couch_conflict:resolution_strategy()) -> 'done'.
--spec compact_all/2 :: (couch_conflict:resolution_strategy(), couch_conflict:merge_fun()) -> 'done'.
compact_all() ->
lager:debug("compacting all nodes"),
{ok, Nodes} = couch_mgr:admin_all_docs(<<"nodes">>),
_ = [ compact_node(wh_json:get_value(<<"id">>, Node)) || Node <- shuffle(Nodes)],
done.
-compact_all(ConflictStrategy) ->
- lager:debug("compacting all nodes"),
- {ok, Nodes} = couch_mgr:admin_all_docs(<<"nodes">>),
- _ = [ compact_node(wh_json:get_value(<<"id">>, Node), ConflictStrategy) || Node <- shuffle(Nodes)],
- done.
-compact_all(ConflictStrategy, F) ->
- lager:debug("compacting all nodes"),
- {ok, Nodes} = couch_mgr:admin_all_docs(<<"nodes">>),
- _ = [ compact_node(wh_json:get_value(<<"id">>, Node), ConflictStrategy, F) || Node <- shuffle(Nodes)],
- done.
-spec compact_node/1 :: (ne_binary() | atom()) -> 'done'.
--spec compact_node/2 :: (ne_binary() | atom(), couch_conflict:resolution_strategy()) -> 'done'.
--spec compact_node/3 :: (ne_binary() | atom(), couch_conflict:resolution_strategy(), couch_conflict:merge_fun()) -> 'done'.
compact_node(Node) when is_atom(Node) ->
compact_node(wh_util:to_binary(Node));
compact_node(NodeBin) ->
put(callid, NodeBin),
lager:debug("compacting node ~s", [NodeBin]),
- {Conn, AdminConn} = get_node_connections(NodeBin),
- {ok, DBs} = couch_util:db_info(Conn),
- Total = length(DBs),
- _ = lists:foldl(fun(DB, Count) ->
- lager:debug("compacting database (~p/~p) '~s'", [Count, Total, DB]),
- _ = (catch compact_node_db(NodeBin, DB, Conn, AdminConn)),
- Count + 1
- end, 1, shuffle(DBs, Total)),
- done.
-
-compact_node(Node, ConflictStrategy) when is_atom(Node) ->
- compact_node(wh_util:to_binary(Node), ConflictStrategy);
-compact_node(NodeBin, ConflictStrategy) ->
- put(callid, NodeBin),
- lager:debug("compacting node ~s", [NodeBin]),
-
- {Conn, _AdminConn} = get_node_connections(NodeBin),
- {ok, DBs} = couch_util:db_info(Conn),
- lager:debug("found ~b DBs to compact", [length(DBs)]),
-
- _ = [ compact_db(NodeBin, DB, ConflictStrategy) || DB <- DBs ],
- done.
-compact_node(Node, ConflictStrategy, F) when is_atom(Node) ->
- compact_node(wh_util:to_binary(Node), ConflictStrategy, F);
-compact_node(NodeBin, ConflictStrategy, F) ->
- put(callid, NodeBin),
- lager:debug("compacting node ~s", [NodeBin]),
-
- {Conn, _AdminConn} = get_node_connections(NodeBin),
- {ok, DBs} = couch_util:db_info(Conn),
- lager:debug("found ~b DBs to compact", [length(DBs)]),
-
- _ = [ compact_db(NodeBin, DB, ConflictStrategy, F) || DB <- DBs ],
- done.
+ try get_node_connections(NodeBin) of
+ {Conn, AdminConn} ->
+ {ok, DBs} = node_dbs(AdminConn),
+ Total = length(DBs),
+ _ = lists:foldl(fun(DB, Count) ->
+ lager:debug("compacting database (~p/~p) '~s'", [Count, Total, DB]),
+ _ = (catch compact_node_db(NodeBin, DB, Conn, AdminConn)),
+ Count + 1
+ end, 1, shuffle(DBs, Total)),
+ done
+ catch
+ _:_ ->
+ lager:error("unable to open connection to ~s", [NodeBin]),
+ done
+ end.
%% Use compact_db/1 to compact the DB across all known nodes
%% Use compact_db/2 to compact the DB on a specific node
-spec compact_db/1 :: (ne_binary()) -> 'done'.
-spec compact_db/2 :: (ne_binary() | atom(), ne_binary()) -> 'done'.
--spec compact_db/3 :: (ne_binary() | atom(), ne_binary(), couch_conflict:resolution_strategy()) -> 'done'.
--spec compact_db/4 :: (ne_binary() | atom(), ne_binary(), couch_conflict:resolution_strategy(), couch_conflict:merge_fun()) -> 'done'.
-
compact_db(DB) ->
{ok, Nodes} = couch_mgr:admin_all_docs(<<"nodes">>),
_ = [ compact_db(wh_json:get_value(<<"id">>, Node), DB) || Node <- Nodes],
@@ -141,38 +86,23 @@ compact_db(Node, DB) when is_atom(Node) ->
compact_db(wh_util:to_binary(Node), DB);
compact_db(NodeBin, DB) ->
put(callid, NodeBin),
- {Conn, AdminConn} = get_node_connections(NodeBin),
- ok = compact_node_db(NodeBin, DB, Conn, AdminConn),
- done.
-
-compact_db(Node, DB, ConflictStrategy) when is_atom(Node) ->
- compact_db(wh_util:to_binary(Node), DB, ConflictStrategy);
-compact_db(NodeBin, DB, ConflictStrategy) ->
- put(callid, NodeBin),
- {Conn, AdminConn} = get_node_connections(NodeBin),
-
- _ = couch_conflict:resolve(Conn, DB, couch_conflict:default_view(), ConflictStrategy),
-
- ok = compact_node_db(NodeBin, DB, Conn, AdminConn),
- done.
-
-compact_db(Node, DB, ConflictStrategy, F) when is_atom(Node) ->
- compact_db(wh_util:to_binary(Node), DB, ConflictStrategy, F);
-compact_db(NodeBin, DB, ConflictStrategy, F) ->
- put(callid, NodeBin),
- {Conn, AdminConn} = get_node_connections(NodeBin),
-
- _ = couch_conflict:resolve(Conn, DB, couch_conflict:default_view(), ConflictStrategy, F),
-
- ok = compact_node_db(NodeBin, DB, Conn, AdminConn),
- done.
+ try get_node_connections(NodeBin) of
+ {Conn, AdminConn} ->
+ ok = compact_node_db(NodeBin, DB, Conn, AdminConn),
+ done
+ catch
+ _:_ ->
+ lager:error("unable to open connection to ~s", [NodeBin]),
+ done
+ end.
%% Internal Functions ----------------------------------------------------------
-spec compact_node_db/4 :: (ne_binary(), ne_binary(), #server{}, #server{}) -> 'ok'.
compact_node_db(NodeBin, DB, Conn, AdminConn) ->
DBEncoded = binary:replace(DB, <<"/">>, <<"%2f">>, [global]),
lager:debug("compacting db ~s node ~s", [DBEncoded, NodeBin]),
- case couch_util:db_exists(Conn, DBEncoded) andalso get_db_shards(AdminConn, DBEncoded) of
+
+ case couch_util:db_exists(Conn, DBEncoded) andalso get_db_shards(NodeBin, AdminConn, DB, DBEncoded) of
false -> lager:debug("db ~s not on node ~s", [DBEncoded, NodeBin]);
[] -> lager:debug("no shards found matching ~s", [DBEncoded]);
Shards ->
@@ -183,18 +113,18 @@ compact_node_db(NodeBin, DB, Conn, AdminConn) ->
ok
end.
--spec compact_node_shards/3 :: ([ne_binary(),...], server(), [ne_binary(),...] | []) -> 'ok'.
+-spec compact_node_shards/3 :: ([ne_binary(),...], server(), [ne_binary(),...] | []) -> 'ok'.
compact_node_shards(Shards, AdminConn, DesignDocs) ->
case catch(lists:split(?MAX_COMPACTING_SHARDS, Shards)) of
- {'EXIT', _} ->
+ {'EXIT', _} ->
compact_shards(Shards, AdminConn, DesignDocs),
ok;
{Compact, Remaining} ->
compact_shards(Compact, AdminConn, DesignDocs),
compact_node_shards(Remaining, AdminConn, DesignDocs)
- end.
+ end.
--spec compact_shards/3 :: ([ne_binary(),...], server(), [ne_binary(),...] | []) -> 'ok'.
+-spec compact_shards/3 :: ([ne_binary(),...], server(), [ne_binary(),...] | []) -> 'ok'.
compact_shards(Shards, AdminConn, DesignDocs) ->
Pids = [spawn_monitor(?MODULE, compact_shard, [AdminConn, Shard, DesignDocs])
|| Shard <- Shards
@@ -219,23 +149,23 @@ compact_shard(AdminConn, Shard, DesignDocs) ->
couch_util:db_compact(AdminConn, Shard),
wait_for_compaction(AdminConn, Shard),
- lager:debug("cleanup views in shard ~s", [Shard]),
+ lager:debug("cleanup views"),
couch_util:db_view_cleanup(AdminConn, Shard),
wait_for_compaction(AdminConn, Shard),
- lager:debug("cleanup design docs in shard ~s", [Shard]),
+ lager:debug("cleanup design docs"),
compact_design_docs(AdminConn, Shard, DesignDocs),
wait_for_compaction(AdminConn, Shard),
- lager:debug("finished compacting shard ~s", [Shard]).
+ lager:debug("finished compacting shard").
-spec compact_design_docs/3 :: (server(), ne_binary(), [ne_binary(),...] | []) -> 'ok'.
compact_design_docs(AdminConn, Shard, DesignDocs) ->
case catch(lists:split(?MAX_COMPACTING_VIEWS, DesignDocs)) of
- {'EXIT', _} ->
+ {'EXIT', _} ->
_ = [begin
- lager:debug("cleanup design doc ~s in shard ~s", [Design, Shard]),
- couch_util:design_compact(AdminConn, Shard, Design)
+ lager:debug("cleanup design doc ~s", [Design]),
+ couch_util:design_compact(AdminConn, Shard, Design)
end
|| Design <- DesignDocs
],
@@ -244,7 +174,7 @@ compact_design_docs(AdminConn, Shard, DesignDocs) ->
ok;
{Compact, Remaining} ->
_ = [begin
- lager:debug("cleanup design doc ~s in shard ~s", [Design, Shard]),
+ lager:debug("cleanup design doc ~s", [Design]),
couch_util:design_compact(AdminConn, Shard, Design)
end
|| Design <- Compact
@@ -262,12 +192,12 @@ wait_for_compaction(AdminConn, Shard) ->
case wh_json:is_true(<<"compact_running">>, ShardData, false) of
false -> ok;
true ->
- lager:debug("waiting for compaction of shard ~s", [Shard]),
+ lager:debug("waiting for compaction to finish"),
ok = timer:sleep(couch_config:fetch(<<"sleep_between_poll">>, ?SLEEP_BETWEEN_POLL)),
wait_for_compaction(AdminConn, Shard)
end;
{error, db_not_found} ->
- lager:debug("db shard ~s not found, skipping", [Shard]);
+ lager:debug("shard not found, skipping");
{error, _E} ->
lager:debug("failed to query shard for compaction status: ~p", [_E]),
ok = timer:sleep(couch_config:fetch(<<"sleep_between_poll">>, ?SLEEP_BETWEEN_POLL)),
@@ -279,32 +209,22 @@ get_db_design_docs(Conn, DBEncoded) ->
{ok, Designs} = couch_util:all_design_docs(Conn, DBEncoded, []),
[ binary:replace(wh_json:get_value(<<"id">>, Design), <<"_design/">>, <<>>, [global]) || Design <- Designs ].
--spec get_db_shards/2 :: (#server{}, ne_binary()) -> [ne_binary()].
-get_db_shards(AdminConn, DBEncoded) ->
- case couch_config:fetch(DBEncoded, undefined, ?WH_COUCH_CACHE) of
- undefined ->
- case couch_util:db_info(AdminConn) of
- {ok, []} -> lager:debug("no shards found on admin conn? That's odd"), [];
- {ok, Shards} ->
- Encoded = [ ShardEncoded || Shard <- Shards, is_a_shard(ShardEncoded=binary:replace(Shard, <<"/">>, <<"%2f">>, [global]), DBEncoded) ],
- couch_config:store(DBEncoded, Encoded, ?WH_COUCH_CACHE),
- lager:debug("cached encoded shards for ~s", [DBEncoded]),
- Encoded;
- {error, _E} ->
- %% TODO: check this error for terminal cases
- lager:debug("unable to get shards atm: ~p", [_E]),
- ok = timer:sleep(couch_config:fetch(<<"sleep_between_poll">>, ?SLEEP_BETWEEN_POLL)),
- get_db_shards(AdminConn, DBEncoded)
- end;
- Encoded ->
- lager:debug("pulled encoded shards from cache for ~s", [DBEncoded]),
- Encoded
+-spec get_db_shards/4 :: (ne_binary(), #server{}, ne_binary(), ne_binary()) -> [ne_binary()].
+get_db_shards(NodeBin, AdminConn, Db, DBEncoded) ->
+ case couch_util:open_cache_doc(AdminConn, <<"dbs">>, Db, []) of
+ {ok, Doc} ->
+ Suffix = wh_json:get_value(<<"shard_suffix">>, Doc),
+ Ranges = wh_json:get_value([<<"by_node">>, NodeBin], Doc, []),
+ [<<"shards%2f", Range/binary, "%2f", DBEncoded/binary, (wh_util:to_binary(Suffix))/binary>>
+ || Range <- Ranges
+ ];
+ {error, _E} ->
+ %% TODO: check this error for terminal cases
+ lager:debug("unable to get shards for ~s atm: ~p", [DBEncoded, _E]),
+ ok = timer:sleep(couch_config:fetch(<<"sleep_between_poll">>, ?SLEEP_BETWEEN_POLL)),
+ get_db_shards(NodeBin, AdminConn, Db, DBEncoded)
end.
--spec is_a_shard/2 :: (ne_binary(), ne_binary()) -> boolean().
-is_a_shard(Shard, DB) ->
- binary:match(Shard, <<"%2f", DB/binary, ".">>) =/= nomatch.
-
-spec get_node_connections/1 :: (ne_binary()) -> {#server{}, #server{}}.
get_node_connections(NodeBin) ->
[_Name, H] = binary:split(NodeBin, <<"@">>),
@@ -357,7 +277,14 @@ get_ports(_Node, pang) ->
-spec get_conns/5 :: (nonempty_string(), pos_integer(), string(), string(), pos_integer()) -> {#server{}, #server{}}.
get_conns(Host, Port, User, Pass, AdminPort) ->
{couch_util:get_new_connection(Host, Port, User, Pass),
- couch_util:get_new_connection(Host, AdminPort, User, Pass)}.
+ couch_util:get_new_connection(Host, AdminPort, User, Pass)
+ }.
+
+%% returns list of DBs in unencoded format
+-spec node_dbs/1 :: (#server{}) -> {'ok', wh_json:json_strings()}.
+node_dbs(AdminConn) ->
+ {ok, Dbs} = couch_util:all_docs(AdminConn, <<"dbs">>, []),
+ {ok, [wh_json:get_value(<<"id">>, Db) || Db <- Dbs]}.
-spec shuffle/1 :: (list()) -> list().
-spec shuffle/2 :: (list(), integer()) -> list().
2  lib/whistle_couch-1.0.0/src/couch_mgr.erl
View
@@ -232,7 +232,7 @@ revise_docs_from_folder(DbName, App, Folder) ->
revise_docs_from_folder(DbName, App, Folder, true).
revise_docs_from_folder(DbName, App, Folder, Sleep) ->
- Files = filelib:wildcard(lists:flatten([code:priv_dir(App), "/couchdb/", Folder, "/*.json"])),
+ Files = filelib:wildcard([code:priv_dir(App), "/couchdb/", Folder, "/*.json"]),
do_revise_docs_from_folder(DbName, Sleep, Files).
-spec do_revise_docs_from_folder/3 :: (ne_binary(), boolean(), [ne_binary() | nonempty_string(),...]) -> 'ok'.
4 lib/whistle_couch-1.0.0/src/couch_util.erl
View
@@ -242,13 +242,13 @@ do_get_design_info(#db{}=Db, Design) ->
-spec open_cache_doc/4 :: (server(), ne_binary(), ne_binary(), proplist()) -> {'ok', wh_json:json_object()} |
{'error', atom()}.
open_cache_doc(#server{}=Conn, DbName, DocId, Options) ->
- case wh_cache:peek({?MODULE, DbName, DocId}) of
+ case wh_cache:peek({?MODULE, Conn, DbName, DocId}) of
{ok, _}=Ok -> Ok;
{error, not_found} ->
case open_doc(Conn, DbName, DocId, Options) of
{error, _}=E -> E;
{ok, JObj}=Ok ->
- wh_cache:store({?MODULE, DbName, DocId}, JObj, 900),
+ wh_cache:store({?MODULE, Conn, DbName, DocId}, JObj, 900),
Ok
end
end.
2  lib/whistle_number_manager-1.0.0/Makefile
View
@@ -2,7 +2,7 @@ ROOT = ../..
DIALYZER = dialyzer
REBAR = $(ROOT)/bin/rebar
-DIRS = . ../whistle_amqp-1.0.0 ../whistle_couch-1.0.0
+DIRS = . ../whistle_amqp-1.0.0 ../whistle_couch-1.0.0 ../whistle-1.0.0
all: app
45 lib/whistle_number_manager-1.0.0/src/providers/wnm_dash_e911.erl
View
@@ -1,11 +1,12 @@
%%%-------------------------------------------------------------------
-%%% @copyright (C) 2011, VoIP INC
+%%% @copyright (C) 2011-2012, VoIP INC
%%% @doc
%%%
%%% Handle e911 provisioning
%%%
%%% @end
-%%% Created : 08 Jan 2012 by Karl Anderson <karl@2600hz.org>
+%%% @contributors
+%%% Karl Anderson
%%%-------------------------------------------------------------------
-module(wnm_dash_e911).
@@ -18,8 +19,6 @@
-define(WNM_DASH_CONFIG_CAT, <<(?WNM_CONFIG_CAT)/binary, ".dash_e911">>).
--define(SERVER, ?MODULE).
-
-define(DASH_XML_PROLOG, "<?xml version=\"1.0\"?>").
-define(DASH_AUTH_USERNAME, whapps_config:get_string(?WNM_DASH_CONFIG_CAT, <<"auth_username">>, <<>>)).
-define(DASH_AUTH_PASSWORD, whapps_config:get_string(?WNM_DASH_CONFIG_CAT, <<"auth_password">>, <<>>)).
@@ -31,7 +30,7 @@
%%--------------------------------------------------------------------
%% @public
%% @doc
-%% This function is called each time a number is saved, and will
+%% This function is called each time a number is saved, and will
%% provision e911 or remove the number depending on the state
%% @end
%%--------------------------------------------------------------------
@@ -42,21 +41,21 @@ save(#number{state = <<"reserved">>} = Number) ->
maybe_update_dash_e911(Number);
save(#number{state = <<"in_service">>} = Number) ->
maybe_update_dash_e911(Number);
-save(Number) -> delete(Number).
+save(Number) -> delete(Number).
%%--------------------------------------------------------------------
%% @public
%% @doc
-%% This function is called each time a number is deleted, and will
+%% This function is called each time a number is deleted, and will
%% provision e911 or remove the number depending on the state
%% @end
%%--------------------------------------------------------------------
-spec delete/1 :: (wnm_number()) -> wnm_number().
delete(#number{features=Features, number=Num
- ,current_number_doc=CurrentDoc, number_doc=Doc}=Number) ->
+ ,current_number_doc=CurrentDoc, number_doc=Doc}=Number) ->
case wh_json:get_ne_value(<<"dash_e911">>, CurrentDoc) of
undefined -> Number;
- _Else ->
+ _Else ->
lager:debug("removing e911 information"),
_ = remove_number(Num),
Number#number{features=sets:del_element(<<"dash_e911">>, Features)
@@ -76,7 +75,7 @@ maybe_update_dash_e911(#number{current_number_doc=CurrentJObj, number_doc=JObj
E911 = wh_json:get_ne_value(<<"dash_e911">>, JObj),
NotChanged = wnm_util:are_jobjs_identical(CurrentE911, E911),
case wh_util:is_empty(E911) of
- true ->
+ true ->
lager:debug("dash e911 information has been removed, updating dash"),
_ = remove_number(Number),
N#number{features=sets:del_element(<<"dash_e911">>, Features)};
@@ -102,19 +101,19 @@ update_e911(Number, Address, JObj) ->
Location = json_address_to_xml_location(Address),
CallerName = wh_json:get_ne_value(<<"caller_name">>, Address, <<"Valued Customer">>),
case add_location(Number, Location, CallerName) of
- {error, R}=E ->
+ {error, R}=E ->
lager:debug("error provisioning dash e911 address: ~p", [R]),
E;
- {provisioned, E911} ->
+ {provisioned, E911} ->
lager:debug("provisioned dash e911 address"),
{ok, wh_json:set_value(<<"dash_e911">>, E911, JObj)};
{geocoded, E911} ->
lager:debug("added location to dash e911, attempting to provision new location"),
case provision_location(wh_json:get_value(<<"location_id">>, E911)) of
- undefined ->
+ undefined ->
lager:debug("provisioning attempt moved location to status: undefined"),
{ok, wh_json:set_value(<<"dash_e911">>, E911, JObj)};
- Status ->
+ Status ->
lager:debug("provisioning attempt moved location to status: ~s", [Status]),
{ok, wh_json:set_value(<<"dash_e911">>, wh_json:set_value(<<"status">>, Status, E911), JObj)}
end
@@ -199,7 +198,7 @@ emergency_provisioning_request(Verb, Props) ->
%%
%% @end
%%--------------------------------------------------------------------
--spec is_valid_location/1 :: (term()) -> {geocoded, wh_json:json_object()} |
+-spec is_valid_location/1 :: (term()) -> {geocoded, wh_json:json_object()} |
{provisioned, wh_json:json_object()} |
{error, binary()}.
is_valid_location(Location) ->
@@ -223,7 +222,7 @@ is_valid_location(Location) ->
%%
%% @end
%%--------------------------------------------------------------------
--spec add_location/3 :: (ne_binary(), term(), ne_binary()) -> {geocoded, wh_json:json_object()} |
+-spec add_location/3 :: (ne_binary(), term(), ne_binary()) -> {geocoded, wh_json:json_object()} |
{provisioned, wh_json:json_object()} |
{error, binary()}.
add_location(Number, Location, CallerName) ->
@@ -268,12 +267,12 @@ remove_number(Number) ->
lager:debug("removing dash e911 number '~s'", [Number]),
Props = [{'uri', [wh_util:to_list(<<"tel:", (wnm_util:to_1npan(Number))/binary>>)]}],
case emergency_provisioning_request('removeURI', Props) of
- {error, server_error} ->
+ {error, server_error} ->
lager:debug("removed number from dash e911"),
<<"REMOVED">>;
Response ->
case wh_util:get_xml_value("//URIStatus/code/text()", Response) of
- <<"REMOVED">> = R ->
+ <<"REMOVED">> = R ->
lager:debug("removed number from dash e911"),
R;
Else ->
@@ -316,11 +315,11 @@ location_xml_to_json_address(Xml) ->
Props = [{<<"street_address">>, wh_util:get_xml_value("address1/text()", Xml)}
,{<<"extended_address">>, wh_util:get_xml_value("address2/text()", Xml)}
,{<<"activated_time">>, wh_util:get_xml_value("activated_time/text()", Xml)}
- ,{<<"caller_name">>, wh_util:get_xml_value("callername/text()", Xml)}
- ,{<<"comments">>, wh_util:get_xml_value("comments/text()", Xml)}
- ,{<<"locality">>, wh_util:get_xml_value("community/text()", Xml)}
- ,{<<"order_id">>, wh_util:get_xml_value("customerorderid/text()", Xml)}
- ,{<<"latitude">>, wh_util:get_xml_value("latitude/text()", Xml)}
+ ,{<<"caller_name">>, wh_util:get_xml_value("callername/text()", Xml)}
+ ,{<<"comments">>, wh_util:get_xml_value("comments/text()", Xml)}
+ ,{<<"locality">>, wh_util:get_xml_value("community/text()", Xml)}
+ ,{<<"order_id">>, wh_util:get_xml_value("customerorderid/text()", Xml)}
+ ,{<<"latitude">>, wh_util:get_xml_value("latitude/text()", Xml)}
,{<<"longitude">>, wh_util:get_xml_value("longitude/text()", Xml)}
,{<<"location_id">>, wh_util:get_xml_value("locationid/text()", Xml)}
,{<<"plus_four">>, wh_util:get_xml_value("plusfour/text()", Xml)}
67 lib/whistle_number_manager-1.0.0/src/providers/wnm_failover.erl
View
@@ -0,0 +1,67 @@
+%%%-------------------------------------------------------------------
+%%% @copyright (C) 2012, VoIP INC
+%%% @doc
+%%% Handle failover provisioning
+%%% @end
+%%% @contributors
+%%% James Aimonetti
+%%%-------------------------------------------------------------------
+-module(wnm_failover).
+
+-export([save/1
+ ,delete/1
+ ]).
+
+-include_lib("whistle_number_manager/src/wh_number_manager.hrl").
+
+-define(FAILOVER_KEY, <<"failover">>).
+
+%%--------------------------------------------------------------------
+%% @public
+%% @doc
+%% This function is called each time a number is saved, and will
+%% add the failover route (for in service numbers only)
+%% @end
+%%--------------------------------------------------------------------
+-spec save/1 :: (wnm_number()) -> wnm_number().
+save(#number{state = <<"in_service">>} = Number) ->
+ maybe_update_failover(Number);
+save(Number) ->
+ delete(Number).
+
+%%--------------------------------------------------------------------
+%% @public
+%% @doc
+%% This function is called each time a number is deleted, and will
+%% remove the failover route
+%% @end
+%%--------------------------------------------------------------------
+-spec delete/1 :: (wnm_number()) -> wnm_number().
+delete(#number{features=Features
+ ,current_number_doc=CurrentDoc
+ ,number_doc=Doc
+ }=Number) ->
+ case wh_json:get_ne_value(?FAILOVER_KEY, CurrentDoc) of
+ undefined -> Number;
+ _Else ->
+ Number#number{features=sets:del_element(?FAILOVER_KEY, Features)
+ ,number_doc=wh_json:delete_key(?FAILOVER_KEY, Doc)
+ }
+ end.
+
+-spec maybe_update_failover/1 :: (wnm_number()) -> wnm_number().
+maybe_update_failover(#number{current_number_doc=CurrentJObj
+ ,number_doc=JObj
+ ,features=Features
+ }=N) ->
+ CurrentFailover = wh_json:get_ne_value(?FAILOVER_KEY, CurrentJObj),
+ Failover = wh_json:get_ne_value(?FAILOVER_KEY, JObj),
+ NotChanged = wnm_util:are_jobjs_identical(CurrentFailover, Failover),
+
+ case wh_util:is_empty(Failover) of
+ true ->
+ N#number{features=sets:del_element(?FAILOVER_KEY, Features)};
+ false when NotChanged -> N#number{features=sets:add_element(?FAILOVER_KEY, Features)};
+ false ->
+ wnm_number:activate_feature(?FAILOVER_KEY, N)
+ end.
95 lib/whistle_number_manager-1.0.0/src/wh_number_manager.erl
View
@@ -154,17 +154,16 @@ port_in(Number, AssignTo, AuthBy) ->
port_in(Number, AssignTo, AuthBy, PublicFields) ->
lager:debug("attempting to port_in number ~s for account ~s", [Number, AssignTo]),
- Routines = [fun(_) -> wnm_number:get(Number, PublicFields) end
- ,fun({not_found, #number{}=N}) ->
- NewNumber = N#number{number=Number
- ,assign_to=AssignTo
- ,auth_by=AuthBy
- ,number_doc=PublicFields
- },
- wnm_number:create_port_in(NewNumber);
- ({_, #number{}}=E) -> E;
- (#number{}=N) -> wnm_number:error_number_exists(N)
- end
+ Routines = [fun({not_found, #number{}=N}) ->
+ NewNumber = N#number{number=Number
+ ,assign_to=AssignTo
+ ,auth_by=AuthBy
+ ,number_doc=PublicFields
+ },
+ wnm_number:create_port_in(NewNumber);
+ ({_, #number{}}=E) -> E;
+ (#number{}=N) -> wnm_number:error_number_exists(N)
+ end
,fun({_, #number{}}=E) -> E;
(#number{}=N) -> wnm_number:save(N)
end
@@ -176,7 +175,7 @@ port_in(Number, AssignTo, AuthBy, PublicFields) ->
{ok, wh_json:public_fields(JObj)}
end
],
- lists:foldl(fun(F, J) -> catch F(J) end, ok, Routines).
+ lists:foldl(fun(F, J) -> catch F(J) end, catch wnm_number:get(Number, PublicFields), Routines).
%%--------------------------------------------------------------------
%% @public
@@ -187,21 +186,20 @@ port_in(Number, AssignTo, AuthBy, PublicFields) ->
%%--------------------------------------------------------------------
-spec reconcile_number/3 :: (ne_binary(), ne_binary(), ne_binary()) -> operation_return().
reconcile_number(Number, AssignTo, AuthBy) ->
- Routines = [fun(_) -> wnm_number:get(Number) end
- ,fun({not_found, #number{}=N}) when is_binary(AssignTo) ->
- NewNumber = N#number{number=Number
- ,assign_to=AssignTo
- ,auth_by=wh_util:to_binary(AuthBy)
- },
- wnm_number:create_available(NewNumber);
- ({_, #number{}}=E) -> E;
- (#number{}=N) when is_binary(AssignTo) ->
- N#number{assign_to=AssignTo};
- (#number{assigned_to=undefined}=N) ->
- wnm_number:error_unauthorized(N);
- (#number{assigned_to=AssignedTo}=N) ->
- N#number{assign_to=AssignedTo}
- end
+ Routines = [fun({not_found, #number{}=N}) when is_binary(AssignTo) ->
+ NewNumber = N#number{number=Number
+ ,assign_to=AssignTo
+ ,auth_by=wh_util:to_binary(AuthBy)
+ },
+ wnm_number:create_available(NewNumber);
+ ({_, #number{}}=E) -> E;
+ (#number{}=N) when is_binary(AssignTo) ->
+ N#number{assign_to=AssignTo};
+ (#number{assigned_to=undefined}=N) ->
+ wnm_number:error_unauthorized(N);
+ (#number{assigned_to=AssignedTo}=N) ->
+ N#number{assign_to=AssignedTo}
+ end
,fun({_, #number{}}=E) -> E;
(#number{}=N) when is_binary(AuthBy) ->
N#number{auth_by=AuthBy};
@@ -228,7 +226,7 @@ reconcile_number(Number, AssignTo, AuthBy) ->
{ok, wh_json:public_fields(JObj)}
end
],
- lists:foldl(fun(F, J) -> catch F(J) end, ok, Routines).
+ lists:foldl(fun(F, J) -> catch F(J) end, catch wnm_number:get(Number), Routines).
%%--------------------------------------------------------------------
%% @public
@@ -236,7 +234,7 @@ reconcile_number(Number, AssignTo, AuthBy) ->
%% Release all numbers currently assigned to an account
%% @end
%%--------------------------------------------------------------------
--spec free_numbers/1 :: (ne_binary()) -> ok.
+-spec free_numbers/1 :: (ne_binary()) -> 'ok'.
free_numbers(AccountId) ->
lager:debug("attempting to free all numbers assigned to account ~s", [AccountId]),
AccountDb = wh_util:format_account_id(AccountId, encoded),
@@ -259,15 +257,15 @@ free_numbers(AccountId) ->
%% @end
%%--------------------------------------------------------------------
-spec reserve_number/3 :: (ne_binary(), ne_binary(), ne_binary()) -> operation_return().
--spec reserve_number/4 :: (ne_binary(), ne_binary(), ne_binary(), wh_json:json_object()) -> operation_return().
+-spec reserve_number/4 :: (ne_binary(), ne_binary(), ne_binary(), wh_json:json_object() | 'undefined')
+ -> operation_return().
reserve_number(Number, AssignTo, AuthBy) ->
reserve_number(Number, AssignTo, AuthBy, undefined).
reserve_number(Number, AssignTo, AuthBy, PublicFields) ->
lager:debug("attempting to reserve ~s for account ~s", [Number, AssignTo]),
- Routines = [fun(_) -> wnm_number:get(Number, PublicFields) end
- ,fun({_, #number{}}=E) -> E;
+ Routines = [fun({_, #number{}}=E) -> E;
(#number{}=N) -> wnm_number:reserved(N#number{assign_to=AssignTo, auth_by=AuthBy})
end
,fun({_, #number{}}=E) -> E;
@@ -281,7 +279,7 @@ reserve_number(Number, AssignTo, AuthBy, PublicFields) ->
{ok, wh_json:public_fields(JObj)}
end
],
- lists:foldl(fun(F, J) -> catch F(J) end, ok, Routines).
+ lists:foldl(fun(F, J) -> catch F(J) end, catch wnm_number:get(Number, PublicFields), Routines).
%%--------------------------------------------------------------------
%% @public
@@ -291,7 +289,8 @@ reserve_number(Number, AssignTo, AuthBy, PublicFields) ->
%% @end
%%--------------------------------------------------------------------
-spec assign_number_to_account/3 :: (ne_binary(), ne_binary(), ne_binary()) -> operation_return().
--spec assign_number_to_account/4 :: (ne_binary(), ne_binary(), ne_binary(), wh_json:json_object()) -> operation_return().
+-spec assign_number_to_account/4 :: (ne_binary(), ne_binary(), ne_binary(), wh_json:json_object() | 'undefined')
+ -> operation_return().
assign_number_to_account(Number, AssignTo, AuthBy) ->
assign_number_to_account(Number, AssignTo, AuthBy, undefined).
@@ -508,15 +507,13 @@ get_public_fields(Number, AuthBy) ->
%%--------------------------------------------------------------------
-spec set_public_fields/3 :: (ne_binary(), wh_json:json_object(), ne_binary()) -> operation_return().
set_public_fields(Number, PublicFields, AuthBy) ->
- lager:debug("attempting to set public fields for number ~s", [Number]),
- Routines = [fun(_) -> wnm_number:get(Number, PublicFields) end
- ,fun({_, #number{}}=E) -> E;
- (#number{assigned_to=AssignedTo}=N) ->
- case wh_util:is_in_account_hierarchy(AuthBy, AssignedTo, true) of
- false -> wnm_number:error_unauthorized(N);
- true -> N
- end
- end
+ Routines = [fun({_, #number{}}=E) -> E;
+ (#number{assigned_to=AssignedTo}=N) ->
+ case wh_util:is_in_account_hierarchy(AuthBy, AssignedTo, true) of
+ false -> wnm_number:error_unauthorized(N);
+ true -> N
+ end
+ end
,fun({_, #number{}}=E) -> E;
(#number{}=N) -> wnm_number:save(N)
end
@@ -528,7 +525,7 @@ set_public_fields(Number, PublicFields, AuthBy) ->
{ok, wh_json:public_fields(JObj)}
end
],
- lists:foldl(fun(F, J) -> catch F(J) end, ok, Routines).
+ lists:foldl(fun(F, J) -> catch F(J) end, wnm_number:get(Number, PublicFields), Routines).
%%--------------------------------------------------------------------
%% @private
@@ -537,9 +534,9 @@ set_public_fields(Number, PublicFields, AuthBy) ->
%% ensure the modules data is stored for later acquisition.
%% @end
%%--------------------------------------------------------------------
--spec prepare_find_results/2 :: (wh_proplist(), [] | [[ne_binary(),...],...]) -> [] | [ne_binary(),...].
--spec prepare_find_results/4 :: ([] | [ne_binary(),...], atom(), wh_json:json_object(), [] | [ne_binary(),...])
- -> [] | [ne_binary(),...].
+-spec prepare_find_results/2 :: (wh_proplist(), [] | [wh_json:json_strings(),...]) -> wh_json:json_strings().
+-spec prepare_find_results/4 :: (wh_json:json_strings(), atom(), wh_json:json_object(), wh_json:json_strings())
+ -> wh_json:json_strings().
prepare_find_results([], Found) ->
Results = lists:flatten(Found),
@@ -549,7 +546,7 @@ prepare_find_results([{Module, {ok, ModuleResults}}|T], Found) ->
case wh_json:get_keys(ModuleResults) of
[] -> prepare_find_results(T, Found);
Numbers ->
- Results = prepare_find_results(Numbers, wh_util:to_binary(Module)
+ Results = prepare_find_results(Numbers, Module
,ModuleResults, Found),
prepare_find_results(T, [Results|Found])
end;
@@ -570,7 +567,7 @@ prepare_find_results([Number|Numbers], ModuleName, ModuleResults, Found) ->
end;
{not_found, #number{}=N} ->
NewNumber = N#number{number=Number
- ,module_name=ModuleName
+ ,module_name = ModuleName
,module_data=wh_json:get_value(Number, ModuleResults)
},
case catch wnm_number:save(wnm_number:create_discovery(NewNumber)) of
6 lib/whistle_number_manager-1.0.0/src/wh_number_manager.hrl
View
@@ -7,15 +7,15 @@
-define(APP_VERSION, <<"1.0.0">>).
-define(APP_NAME, <<"whistle_number_manager">>).
--record(number, {number = 'undefined' :: 'undefined' | ne_binary()
+-record(number, {number = 'undefined' :: 'undefined' | wh_json:json_string()
,number_db = 'undefined' :: 'undefined' | ne_binary()
,state = <<"discovery">> :: ne_binary()
- ,reserve_history = ordsets:new() :: ordsets:ordset()
+ ,reserve_history = ordsets:new() :: ordsets:ordset(ne_binary())
,assign_to = 'undefined' :: 'undefined' | ne_binary()
,assigned_to = 'undefined' :: 'undefined' | ne_binary()
,prev_assigned_to = 'undefined' :: 'undefined' | ne_binary()
,auth_by = 'undefined' :: 'undefined' | 'system' | ne_binary()
- ,module_name = 'undefined' :: 'undefined' | atom()
+ ,module_name = 'undefined' :: atom()
,module_data = wh_json:new() :: wh_json:json_object()
,features = sets:new() :: set()
,current_features = sets:new() :: set()
34 lib/whistle_number_manager-1.0.0/src/whistle_number_manager_maintenance.erl
View
@@ -12,6 +12,8 @@
-export([reconcile_numbers/0, reconcile_numbers/1]).
-export([reconcile_accounts/0, reconcile_accounts/1]).
+-export([reconcile_providers/0]).
+
-include("wh_number_manager.hrl").
-include_lib("whistle/include/wh_databases.hrl").
@@ -105,13 +107,43 @@ reconcile_accounts(AccountId) ->
no_return.
%%--------------------------------------------------------------------
+%% @public
+%% @doc
+%% Load known provider modules into system_config
+%% exist
+%% @end
+%%--------------------------------------------------------------------
+-spec reconcile_providers/0 :: () -> any().
+-spec reconcile_providers/2 :: ([ne_binary(),...] | [], [ne_binary(),...] | []) -> any().
+reconcile_providers() ->
+ Paths = filelib:wildcard([code:lib_dir(whistle_number_manager), "/src/providers/*.erl"]),
+ Mods = [wh_util:to_binary(filename:rootname(filename:basename(P))) || P <- Paths],
+
+ lager:debug("Mods: ~p", [Mods]),
+
+ Providers = whapps_config:get(?WNM_CONFIG_CAT, <<"providers">>, []),
+ lager:debug("prov: ~p", [Providers]),
+
+ reconcile_providers(Mods, Providers).
+
+reconcile_providers([<<"wnm_", P/binary>>|Avail], Config) ->
+ case lists:member(P, Config) of
+ true -> reconcile_providers(Avail, Config);
+ false -> reconcile_providers(Avail, [P | Config])
+ end;
+reconcile_providers([_|Avail], Config) ->
+ reconcile_providers(Avail, Config);
+reconcile_providers([], Config) ->
+ whapps_config:set_default(?WNM_CONFIG_CAT, <<"providers">>, Config).
+
+%%--------------------------------------------------------------------
%% @private
%% @doc
%% Given an account create a json object of all numbers that look to
%% external (TODO: currently just uses US rules).
%% @end
%%--------------------------------------------------------------------
--spec get_callflow_account_numbers/1 :: (ne_binary()) -> wh_json:json_object().
+-spec get_callflow_account_numbers/1 :: (ne_binary()) -> wh_json:json_strings().
get_callflow_account_numbers(AccountId) ->
AccountDb = wh_util:format_account_id(AccountId, encoded),
case couch_mgr:get_all_results(AccountDb, ?CALLFLOW_VIEW) of
83 lib/whistle_number_manager-1.0.0/src/wnm_number.erl
View
@@ -125,7 +125,7 @@ get(Number) ->
get(Number, PublicFields) ->
Num = wnm_util:normalize_number(Number),
- Routines = [fun(#number{}=N) ->
+ Routines = [fun(#number{}=N) ->
case wnm_util:is_reconcilable(Num) of
false -> error_not_reconcilable(N);
true -> N
@@ -181,7 +181,7 @@ save_phone_number_docs([], Number) -> Number;
save_phone_number_docs([{Account, JObj}|Props], #number{number=Num}=Number) ->
AccountDb = wh_util:format_account_id(Account, encoded),
case couch_mgr:save_doc(AccountDb, JObj) of
- {ok, _} ->
+ {ok, _} ->
lager:debug("saved updated phone_numbers doc in account db ~s", [AccountDb]),
save_phone_number_docs(Props, Number);
{error, conflict} ->
@@ -253,15 +253,15 @@ available(#number{state = <<"released">>}=Number) ->
Routines = [fun(#number{auth_by=AuthBy}=N) ->
%% Only the 'system' maintenance routines or a system admin can
%% move a released (aging) number back to available.
- case AuthBy =:= system
- orelse wh_util:is_system_admin(AuthBy)
+ case AuthBy =:= system
+ orelse wh_util:is_system_admin(AuthBy)
of
true -> N#number{state = <<"available">>};
false -> error_unauthorized(N)
end
end
],
- lists:foldl(fun(F, N) -> F(N) end, Number, Routines);
+ lists:foldl(fun(F, N) -> F(N) end, Number, Routines);
available(#number{state = <<"available">>}=Number) ->
error_no_change_required(<<"available">>, Number);
available(Number) ->
@@ -284,11 +284,11 @@ reserved(#number{state = <<"discovery">>}=Number) ->
,fun(#number{reserve_history=ReserveHistory, assign_to=AssignTo}=N) ->
N#number{reserve_history=ordsets:add_element(AssignTo, ReserveHistory)}
end
- ,fun(#number{assigned_to=undefined, assign_to=AssignTo}=N) ->
+ ,fun(#number{assigned_to=undefined, assign_to=AssignTo}=N) ->
N#number{state = <<"reserved">>, assigned_to=AssignTo};
- (#number{assigned_to=AssignedTo, prev_assigned_to=AssignedTo}=N) ->
+ (#number{assigned_to=AssignedTo, prev_assigned_to=AssignedTo}=N) ->
N#number{state = <<"reserved">>};
- (#number{assigned_to=AssignedTo, assign_to=AssignTo}=N) ->
+ (#number{assigned_to=AssignedTo, assign_to=AssignTo}=N) ->
N#number{state = <<"reserved">>, assigned_to=AssignTo, prev_assigned_to=AssignedTo}
end
,fun(#number{}=N) -> activate_phone_number(N) end
@@ -309,11 +309,11 @@ reserved(#number{state = <<"available">>}=Number) ->
,fun(#number{reserve_history=ReserveHistory, assign_to=AssignTo}=N) ->
N#number{reserve_history=ordsets:add_element(AssignTo, ReserveHistory)}
end
- ,fun(#number{assigned_to=undefined, assign_to=AssignTo}=N) ->
+ ,fun(#number{assigned_to=undefined, assign_to=AssignTo}=N) ->
N#number{state = <<"reserved">>, assigned_to=AssignTo};
- (#number{assigned_to=AssignedTo, prev_assigned_to=AssignedTo}=N) ->
+ (#number{assigned_to=AssignedTo, prev_assigned_to=AssignedTo}=N) ->
N#number{state = <<"reserved">>};
- (#number{assigned_to=AssignedTo, assign_to=AssignTo}=N) ->
+ (#number{assigned_to=AssignedTo, assign_to=AssignTo}=N) ->
N#number{state = <<"reserved">>, assigned_to=AssignTo, prev_assigned_to=AssignedTo}
end
,fun(#number{}=N) -> activate_phone_number(N) end
@@ -330,15 +330,15 @@ reserved(#number{state = <<"reserved">>}=Number) ->
false -> error_unauthorized(N);
true -> N
end
- end
+ end
,fun(#number{reserve_history=ReserveHistory, assign_to=AssignTo}=N) ->
N#number{reserve_history=ordsets:add_element(AssignTo, ReserveHistory)}
end
- ,fun(#number{assigned_to=undefined, assign_to=AssignTo}=N) ->
+ ,fun(#number{assigned_to=undefined, assign_to=AssignTo}=N) ->
N#number{state = <<"reserved">>, assigned_to=AssignTo};
- (#number{assigned_to=AssignedTo, prev_assigned_to=AssignedTo}=N) ->
+ (#number{assigned_to=AssignedTo, prev_assigned_to=AssignedTo}=N) ->
N#number{state = <<"reserved">>};
- (#number{assigned_to=AssignedTo, assign_to=AssignTo}=N) ->
+ (#number{assigned_to=AssignedTo, assign_to=AssignTo}=N) ->
N#number{state = <<"reserved">>, assigned_to=AssignTo, prev_assigned_to=AssignedTo}
end
,fun(#number{}=N) -> activate_phone_number(N) end
@@ -355,7 +355,7 @@ reserved(#number{state = <<"in_service">>}=Number) ->
lists:foldl(fun(F, J) -> F(J) end, Number, Routines);
reserved(Number) ->
error_invalid_state_transition(<<"reserved">>, Number).
-
+
%%--------------------------------------------------------------------
%% @public
%% @doc
@@ -370,9 +370,9 @@ in_service(#number{state = <<"discovery">>}=Number) ->
true -> N
end
end
- ,fun(#number{assigned_to=undefined, assign_to=AssignTo}=N) ->
+ ,fun(#number{assigned_to=undefined, assign_to=AssignTo}=N) ->
N#number{state = <<"in_service">>, assigned_to=AssignTo};
- (#number{assigned_to=AssignedTo, assign_to=AssignedTo}=N) ->
+ (#number{assigned_to=AssignedTo, assign_to=AssignedTo}=N) ->
N#number{state = <<"in_service">>};
(#number{assigned_to=AssignedTo, assign_to=AssignTo}=N) ->
N#number{state = <<"in_service">>, assigned_to=AssignTo, prev_assigned_to=AssignedTo}
@@ -401,9 +401,9 @@ in_service(#number{state = <<"available">>}=Number) ->
true -> N
end
end
- ,fun(#number{assigned_to=undefined, assign_to=AssignTo}=N) ->
+ ,fun(#number{assigned_to=undefined, assign_to=AssignTo}=N) ->
N#number{state = <<"in_service">>, assigned_to=AssignTo};
- (#number{assigned_to=AssignedTo, assign_to=AssignedTo}=N) ->
+ (#number{assigned_to=AssignedTo, assign_to=AssignedTo}=N) ->
N#number{state = <<"in_service">>};
(#number{assigned_to=AssignedTo, assign_to=AssignTo}=N) ->
N#number{state = <<"in_service">>, assigned_to=AssignTo, prev_assigned_to=AssignedTo}
@@ -421,9 +421,9 @@ in_service(#number{state = <<"reserved">>}=Number) ->
true -> N
end
end
- ,fun(#number{assigned_to=undefined, assign_to=AssignTo}=N) ->
+ ,fun(#number{assigned_to=undefined, assign_to=AssignTo}=N) ->
N#number{state = <<"in_service">>, assigned_to=AssignTo};
- (#number{assigned_to=AssignedTo, assign_to=AssignedTo}=N) ->
+ (#number{assigned_to=AssignedTo, assign_to=AssignedTo}=N) ->
N#number{state = <<"in_service">>};
(#number{assigned_to=AssignedTo, assign_to=AssignTo}=N) ->
N#number{state = <<"in_service">>, assigned_to=AssignTo, prev_assigned_to=AssignedTo}
@@ -461,10 +461,10 @@ released(#number{state = <<"reserved">>}=Number) ->
,fun(#number{module_name=ModuleName, prev_assigned_to=AssignedTo, reserve_history=ReserveHistory}=N) ->
History = ordsets:del_element(AssignedTo, ReserveHistory),
case ordsets:to_list(History) of
- [] when ModuleName =:= wnm_local ->
+ [] when ModuleName =:= wnm_local ->
lager:debug("flagging released local number for hard delete", []),
N#number{state = <<"released">>, reserve_history=ordsets:new(), hard_delete=true};
- [] ->
+ [] ->
lager:debug("moving ~p number to number_manager.released_state '~s'", [ModuleName, NewState]),
N#number{state = NewState, reserve_history=ordsets:new()};
[PrevReservation|_] ->
@@ -493,10 +493,10 @@ released(#number{state = <<"in_service">>}=Number) ->
,fun(#number{module_name=ModuleName, prev_assigned_to=AssignedTo, reserve_history=ReserveHistory}=N) ->
History = ordsets:del_element(AssignedTo, ReserveHistory),
case ordsets:to_list(History) of
- [] when ModuleName =:= wnm_local ->
+ [] when ModuleName =:= wnm_local ->
lager:debug("flagging local number for hard delete", []),
N#number{state = <<"released">>, reserve_history=ordsets:new(), hard_delete=true};
- [] ->
+ [] ->
lager:debug("moving ~p number to number_manager.released_state '~s'", [ModuleName, NewState]),
N#number{state = NewState, reserve_history=ordsets:new()};
[PrevReservation|_] ->
@@ -554,8 +554,8 @@ json_to_record(JObj, #number{number=Num, number_db=Db}=Number) ->
,assigned_to=wh_json:get_ne_value(<<"pvt_assigned_to">>, JObj)
,prev_assigned_to=wh_json:get_ne_value(<<"pvt_previously_assigned_to">>, JObj)
,module_name=wnm_util:get_carrier_module(JObj)
- ,module_data=wh_json:get_ne_value(<<"pvt_module_data">>, JObj)
- ,features=sets:from_list(wh_json:get_ne_value(<<"pvt_features">>, JObj, []))
+ ,module_data=wh_json:get_ne_value(<<"pvt_module_data">>, JObj)
+ ,features=sets:from_list(wh_json:get_ne_value(<<"pvt_features">>, JObj, []))
,current_features=sets:from_list(wh_json:get_ne_value(<<"pvt_features">>, JObj, []))
,number_doc=JObj
,current_number_doc=JObj
@@ -614,10 +614,10 @@ save_number_doc(#number{number_db=Db, number=Num, number_doc=JObj}=Number) ->
true = couch_mgr:db_create(Db),
couch_mgr:revise_views_from_folder(Db, whistle_number_manager),
save_number_doc(Number);
- {error, Reason} ->
+ {error, Reason} ->
lager:debug("failed to save '~s' in '~s': ~p", [Num, Db, Reason]),
error_number_database(Reason, Number);
- {ok, J} ->
+ {ok, J} ->
lager:debug("saved '~s' in '~s'", [Num, Db]),
Number#number{number_doc=J}
end.
@@ -631,7 +631,7 @@ save_number_doc(#number{number_db=Db, number=Num, number_doc=JObj}=Number) ->
-spec delete_number_doc/1 :: (wnm_number()) -> wnm_number().
delete_number_doc(#number{number_db=Db, number=Num, number_doc=JObj}=Number) ->
case couch_mgr:del_doc(Db, JObj) of
- {ok, _} ->
+ {ok, _} ->
lager:debug("deleted '~s' from '~s'", [Num, Db]),
Number#number{number_doc=wh_json:new()};
{error, Reason} ->
@@ -676,7 +676,6 @@ exec_providers(Number, Action) ->
exec_providers([], _, Number) -> Number;
exec_providers([Provider|Providers], Action, Number) ->
- lager:debug("executing provider ~s", [Provider]),
case wnm_util:try_load_module(<<"wnm_", Provider/binary>>) of
false ->
lager:debug("provider ~s is unknown, skipping", [Provider]),
@@ -685,7 +684,7 @@ exec_providers([Provider|Providers], Action, Number) ->
case apply(Mod, Action, [Number]) of
#number{}=N -> exec_providers(Providers, Action, N);
{error, Reason} ->
- Errors = wh_json:from_list([{Provider, Reason}]),
+ Errors = wh_json:from_list([{Provider, Reason}]),
wnm_number:error_provider_fault(Errors, Number)
end
end.
@@ -704,7 +703,7 @@ error_invalid_state_transition(Transition, #number{state = State}=N) ->
-spec error_unauthorized/1 :: (wnm_number()) -> no_return().
error_unauthorized(N) ->
- Error = <<"Not authorized to preform requested number operation">>,
+ Error = <<"Not authorized to preform requested number operation">>,
lager:debug("~s", [Error]),
throw({unauthorized, N#number{error_jobj=wh_json:from_list([{<<"unauthorized">>, Error}])}}).
@@ -736,13 +735,13 @@ error_carrier_not_specified(N) ->
error_number_not_found(N) ->
Error = <<"The number could not be found">>,
lager:debug("~s", [Error]),
- throw({not_found, N#number{error_jobj=wh_json:from_list([{<<"not_found">>, Error}])}}).
+ throw({not_found, N#number{error_jobj=wh_json:from_list([{<<"not_found">>, Error}])}}).
-spec error_number_exists/1 :: (wnm_number()) -> no_return().
error_number_exists(N) ->
Error = <<"The number already exists">>,
lager:debug("~s", [Error]),
- throw({number_exists, N#number{error_jobj=wh_json:from_list([{<<"number_exists">>, Error}])}}).
+ throw({number_exists, N#number{error_jobj=wh_json:from_list([{<<"number_exists">>, Error}])}}).
-spec error_service_restriction/2 :: (wh_json:json_object(), wnm_number()) -> no_return().
error_service_restriction(Reason, N) ->
@@ -798,9 +797,9 @@ get_updated_phone_number_docs(#number{state=State}=Number) ->
remove_from_phone_number_doc(Account, #number{number=Num, phone_number_docs=PhoneNumberDocs}=Number) ->
case get_phone_number_doc(Account, Number) of
{error, _} -> Number;
- {ok, JObj} ->
+ {ok, JObj} ->
case wh_json:delete_key(Num, JObj) of
- JObj ->
+ JObj ->
lager:debug("no need to remove ~s on phone_numbers for account ~s", [Num, Account]),
Number;
UpdatedJObj ->
@@ -819,10 +818,10 @@ remove_from_phone_number_doc(Account, #number{number=Num, phone_number_docs=Phon
update_phone_number_doc(Account, #number{number=Num, phone_number_docs=PhoneNumberDocs}=Number) ->
case get_phone_number_doc(Account, Number) of
{error, _} -> Number;
- {ok, JObj} ->
+ {ok, JObj} ->
Features = create_number_summary(Account, Number),
case wh_json:set_value(Num, Features, JObj) of
- JObj ->
+ JObj ->
lager:debug("no need to update ~s on phone_numbers for account ~s", [Num, Account]),
Number;
UpdatedJObj ->
@@ -852,7 +851,7 @@ get_phone_number_doc(Account, #number{phone_number_docs=Docs}) ->
%% @end
%%--------------------------------------------------------------------
-spec create_number_summary/2 :: (ne_binary(), wnm_number()) -> wh_json:json_object().
-create_number_summary(Account, #number{state=State, features=Features, assigned_to=AssignedTo}) ->
+create_number_summary(Account, #number{state=State, features=Features, assigned_to=AssignedTo}) ->
wh_json:from_list([{<<"state">>, State}
,{<<"features">>, [wh_util:to_binary(F) || F <- sets:to_list(Features)]}
,{<<"on_subaccount">>, Account =/= AssignedTo}
@@ -878,7 +877,7 @@ load_phone_number_doc(Account) ->
,{<<"pvt_modified">>, wh_util:current_tstamp()}
],
case couch_mgr:open_doc(AccountDb, ?WNM_PHONE_NUMBER_DOC) of
- {ok, J} ->
+ {ok, J} ->
lager:debug("loaded phone_numbers from ~s", [AccountId]),
{ok, wh_json:set_values(PVTs, J)};
{error, not_found} ->
3  whistle_apps/apps/crossbar/src/modules/cb_phone_numbers.erl
View
@@ -1,8 +1,7 @@
%%%-------------------------------------------------------------------
-%%% @copyright (C) 2011, VoIP INC
+%%% @copyright (C) 2011-2012, VoIP INC
%%% @doc
%%%
-%%%
%%% Handle client requests for phone_number documents
%%%
%%% @end
6 whistle_apps/apps/stepswitch/src/stepswitch_util.erl
View
@@ -23,11 +23,11 @@
lookup_number(Number) ->
Num = wnm_util:normalize_number(Number),
case wh_cache:fetch_local(?STEPSWITCH_CACHE, cache_key_number(Number)) of
- {ok, {AccountId, ForceOut}} -> {ok, AccountId, ForceOut};
+ {ok, {AccountId, ForceOut, Ported}} -> {ok, AccountId, ForceOut, Ported};
{error, not_found} ->
case wh_number_manager:lookup_account_by_number(Num) of
- {ok, AccountId, ForceOut, _}=Ok ->
- wh_cache:store_local(?STEPSWITCH_CACHE, cache_key_number(Number), {AccountId, ForceOut}),
+ {ok, AccountId, ForceOut, Ported}=Ok ->
+ wh_cache:store_local(?STEPSWITCH_CACHE, cache_key_number(Number), {AccountId, ForceOut, Ported}),
lager:debug("~s is associated with account ~s", [Num, AccountId]),
Ok;
{error, Reason}=E ->
38 whistle_apps/apps/trunkstore/src/ts_callflow.erl
View
@@ -117,14 +117,16 @@ wait_for_bridge(State, Timeout) ->
JObj = wh_json:decode(Payload),
case process_event_for_bridge(State, JObj) of
ignore ->
- wait_for_bridge(State, Timeout - (timer:now_diff(erlang:now(), Start) div 1000));
+ wait_for_bridge(State, Timeout - wh_util:elapsed_ms(Start));
{bridged, _}=Success -> Success;
{error, _}=Error -> Error;
- {hangup, _}=Hangup -> Hangup
+ {hangup, _}=Hangup -> Hangup;
+ E -> lager:debug("unhandled return: ~p", [E]),
+ throw(E)
end;
_E ->
- lager:debug("Unexpected msg: ~p", [_E]),
- wait_for_bridge(State, Timeout - (timer:now_diff(erlang:now(), Start) div 1000))
+ lager:debug("unexpected msg: ~p", [_E]),
+ wait_for_bridge(State, Timeout - wh_util:elapsed_ms(Start))
after Timeout ->
lager:debug("timeout waiting for bridge"),
{timeout, State}
@@ -138,14 +140,14 @@ process_event_for_bridge(#ts_callflow_state{aleg_callid=ALeg, my_q=Q, callctl_q=
{_, <<"offnet_resp">>, <<"resource">>} ->
case wh_json:get_value(<<"Response-Message">>, JObj) of
- <<"ERROR">> ->
- Failure = wh_json:get_value(<<"Error-Message">>, JObj, wh_json:get_value(<<"Response-Code">>, JObj)),
- lager:debug("offnet failed: ~s", [Failure]),
- {error, State};
<<"SUCCESS">> ->
lager:debug("offnet bridge has completed"),
lager:debug("~p", [JObj]),
- {hangup, State}
+ {hangup, State};
+ _Err ->
+ Failure = wh_json:get_value(<<"Error-Message">>, JObj, wh_json:get_value(<<"Response-Code">>, JObj)),
+ lager:debug("offnet failed: ~s(~s)", [Failure, _Err]),
+ {error, State}
end;
{ _, <<"CHANNEL_BRIDGE">>, <<"call_event">> } ->
@@ -233,6 +235,10 @@ process_event_for_cdr(#ts_callflow_state{aleg_callid=ALeg}=State, JObj) ->
lager:debug("Unbridge received, waiting on CDR"),
{hangup, State};
+ { <<"call_event">>, <<"CHANNEL_DESTROY">> } ->
+ lager:debug("channel has been destroyed"),
+ {hangup, State};
+
{ <<"error">>, _ } ->
lager:debug("Error received, waiting on CDR"),
{hangup, State};
@@ -240,11 +246,11 @@ process_event_for_cdr(#ts_callflow_state{aleg_callid=ALeg}=State, JObj) ->
{ <<"call_event">>, <<"CHANNEL_EXECUTE_COMPLETE">>} ->
case {wh_json:get_value(<<"Application-Name">>, JObj), wh_json:get_value(<<"Application-Response">>, JObj)} of
{<<"bridge">>, <<"SUCCESS">>} ->
- lager:debug("Bridge event finished successfully, sending hangup"),
+ lager:debug("bridge event finished successfully, sending hangup"),
send_hangup(State),
ignore;
{<<"bridge">>, Cause} ->
- lager:debug("Failed to bridge: ~s", [Cause]),
+ lager:debug("failed to bridge: ~s", [Cause]),
{error, State};
{_,_} ->
ignore
@@ -256,26 +262,24 @@ process_event_for_cdr(#ts_callflow_state{aleg_callid=ALeg}=State, JObj) ->
Duration = ts_util:get_call_duration(JObj),
lager:debug("CDR received for leg ~s", [Leg]),
- lager:debug("Leg to be billed for ~b seconds", [Duration]),
+ lager:debug("leg to be billed for ~b seconds", [Duration]),
case Leg =:= ALeg of
true -> {cdr, aleg, JObj, State};
false -> {cdr, bleg, JObj, State}
end;
_E ->
- lager:debug("Ignorable event: ~p", [_E]),
+ lager:debug("ignorable event: ~p", [_E]),
ignore
end.
-spec finish_leg/2 :: (#ts_callflow_state{}, 'undefined' | ne_binary()) -> 'ok'.
-finish_leg(_State, undefined) ->
- ok;
+finish_leg(_State, undefined) -> ok;
finish_leg(#ts_callflow_state{}=State, _Leg) ->
send_hangup(State).
-spec send_hangup/1 :: (#ts_callflow_state{}) -> 'ok'.
-send_hangup(#ts_callflow_state{callctl_q = <<>>}) ->
- ok;
+send_hangup(#ts_callflow_state{callctl_q = <<>>}) -> ok;
send_hangup(#ts_callflow_state{callctl_q=CtlQ, my_q=Q, aleg_callid=CallID}) ->
Command = [
{<<"Application-Name">>, <<"hangup">>}
47 whistle_apps/apps/trunkstore/src/ts_from_offnet.erl
View
@@ -92,6 +92,7 @@ wait_for_bridge(State) ->
{bridged, State1} ->
wait_for_cdr(State1);
{error, State2} ->
+ lager:debug("error waiting for bridge, try failover"),
try_failover(State2);
{hangup, State3} ->
ALeg = ts_callflow:get_aleg_id(State3),
@@ -147,6 +148,10 @@ try_failover(State) ->
lager:debug("no callctl for failover"),
ts_callflow:send_hangup(State),
wait_for_cdr(State);
+ {_, undefined} ->
+ lager:debug("no failover defined"),
+ ts_callflow:send_hangup(State),
+ wait_for_cdr(State);
{_, Failover} ->
case wh_json:is_empty(Failover) of
true ->
@@ -170,6 +175,8 @@ try_failover_sip(State, SIPUri) ->
CtlQ = ts_callflow:get_control_queue(State),
Q = ts_callflow:get_my_queue(State),
+ lager:debug("routing to failover sip uri: ~s", [SIPUri]),
+
EndPoint = wh_json:from_list([
{<<"Invite-Format">>, <<"route">>}
,{<<"Route">>, SIPUri}
@@ -180,13 +187,11 @@ try_failover_sip(State, SIPUri) ->
{<<"Call-ID">>, CallID}
,{<<"Application-Name">>, <<"bridge">>}
,{<<"Endpoints">>, [EndPoint]}
- | wh_api:default_headers(Q, <<"call_control">>, <<"command">>, ?APP_NAME, ?APP_VERSION)
+ | wh_api:default_headers(Q, <<"call">>, <<"command">>, ?APP_NAME, ?APP_VERSION)
],
{ok, Payload} = wapi_dialplan:bridge(Command),
- lager:debug("sending SIP failover for ~s: ~s", [SIPUri, Payload]),
-
amqp_util:targeted_publish(CtlQ, Payload, <<"application/json">>),
wait_for_bridge(ts_callflow:set_failover(State, wh_json:new())).
@@ -224,12 +229,15 @@ try_failover_e164(State, ToDID) ->
-spec get_endpoint_data/1 :: (wh_json:json_object()) -> {'endpoint', wh_json:json_object()}.
get_endpoint_data(JObj) ->
%% wh_timer:tick("inbound_route/1"),
- AcctID = wh_json:get_value([<<"Custom-Channel-Vars">>, <<"Account-ID">>], JObj),
+ AcctId = wh_json:get_value([<<"Custom-Channel-Vars">>, <<"Account-ID">>], JObj),
{ToUser, _} = whapps_util:get_destination(JObj, ?APP_NAME, <<"inbound_user_field">>),
ToDID = wnm_util:to_e164(ToUser),
- RoutingData = routing_data(ToDID, AcctID),
+ {ok, AcctId, ForceOut, _} = wh_number_manager:lookup_account_by_number(ToDID),
+ lager:debug("acct ~s force out ~s", [AcctId, ForceOut]),
+
+ RoutingData = routing_data(ToDID, AcctId),
AuthUser = props:get_value(<<"To-User">>, RoutingData),
AuthRealm = props:get_value(<<"To-Realm">>, RoutingData),
@@ -265,6 +273,11 @@ routing_data(ToDID, AcctID, Settings) ->
DIDOptions = wh_json:get_value(<<"DID_Opts">>, Settings, wh_json:new()),
RouteOpts = wh_json:get_value(<<"options">>, DIDOptions, []),
+ NumConfig = case wh_number_manager:get_public_fields(ToDID, AcctID) of
+ {ok, Fields} -> Fields;
+ {error, _} -> wh_json:new()
+ end,
+
AuthU = wh_json:get_value(<<"auth_user">>, AuthOpts),
AuthR = wh_json:get_value(<<"auth_realm">>, AuthOpts, wh_json:get_value(<<"auth_realm">>, Acct)),
@@ -309,29 +322,15 @@ routing_data(ToDID, AcctID, Settings) ->
]),
FailoverLocations = [
- wh_json:get_value(<<"failover">>, DIDOptions)
+ wh_json:get_value(<<"failover">>, NumConfig)
+ ,wh_json:get_value(<<"failover">>, DIDOptions)
,wh_json:get_value(<<"failover">>, SrvOptions)
,wh_json:get_value(<<"failover">>, AcctStuff)
],
+ lager:debug("looking for failover in ~p", [FailoverLocations]),
- Num = wnm_util:normalize_number(ToDID),
- Db = wnm_util:number_to_db_name(Num),
- FL = case couch_mgr:open_doc(Db, Num) of
- {ok, NumJObj} ->
- case wh_json:get_value(<<"pvt_assigned_to">>, NumJObj) =:= AcctID of
- true ->
- lager:debug("found ~s in ~s", [Num, Db]),
- [wh_json:get_value(<<"failover">>, NumJObj) | FailoverLocations];
- false ->
- lager:debug("found ~s in ~s, but is for account ~s", [Num, Db, wh_json:get_value(<<"pvt_assigned_to">>, NumJObj)]),
- FailoverLocations
- end;
- {error, _E} ->
- lager:debug("failed to find ~s in ~s: ~p", [Num, Db, _E]),
- FailoverLocations
- end,
-
- Failover = ts_util:failover(FL),
+ Failover = ts_util:failover(FailoverLocations),
+ lager:debug("failover found: ~p", [Failover]),
Delay = ts_util:delay([
wh_json:get_value(<<"delay">>, DIDOptions)
5 whistle_apps/apps/trunkstore/src/ts_from_onnet.erl
View
@@ -118,8 +118,9 @@ onnet_data(State) ->
send_park(State, Command)
catch
_A:_B ->
- lager:debug("Exception ~p:~p", [_A, _B]),
- lager:debug("Stacktrace: ~p", [erlang:get_stacktrace()]),
+ ST = erlang:get_stacktrace(),
+ lager:debug("exception ~p:~p", [_A, _B]),
+ _ = [lager:debug("st: ~p", [S]) || S <- ST],
wait_for_cdr(State)
end.
4 whistle_apps/apps/trunkstore/src/ts_util.erl
View
@@ -164,11 +164,11 @@ sip_headers(L) when is_list(L) ->
_ -> undefined
end.
--spec failover/1 :: ([wh_json:json_object() | binary(),...]) -> wh_json:json_object().
+-spec failover/1 :: ([wh_json:json_object() | binary() | 'undefined',...]) -> wh_json:json_object() | 'undefined'.
%% cascade from DID to Srv to Acct
failover(L) ->
case simple_extract(L) of
- B when is_binary(B) -> wh_json:new();
+ B when is_binary(B) -> undefined;
Other -> Other
end.
3  whistle_apps/src/whapps_maintenance.erl
View
@@ -51,6 +51,9 @@ migrate() ->
%% Ensure the phone_numbers doc in the account db is up-to-date
_ = whistle_number_manager_maintenance:reconcile_numbers(),
+ %% Load available providers into system_config
+ _ = whistle_number_manager_maintenance:reconcile_providers(),
+
%% Ensure the views in each DB are update-to-date, depreciated view removed, sip_auth docs
%% that need to be aggregated have been, and the account definition is aggregated
_ = blocking_refresh(),
Please sign in to comment.
Something went wrong with that request. Please try again.