From 639ce22a8452e3bba333a461a682b951806db783 Mon Sep 17 00:00:00 2001 From: John White Date: Tue, 7 Apr 2020 17:10:19 -0500 Subject: [PATCH 01/12] PROD-210: Add new convert to strip + - Add to_strip_plus and is_strip_plus to knm_converters abstraction - Add to_strip_plus stub to th knm_regex_converter --- .../src/converters/knm_converter_regex.erl | 10 ++++++++++ .../src/converters/knm_converters.erl | 17 +++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/core/kazoo_numbers/src/converters/knm_converter_regex.erl b/core/kazoo_numbers/src/converters/knm_converter_regex.erl index d17ac50f4c0..23ae1479851 100644 --- a/core/kazoo_numbers/src/converters/knm_converter_regex.erl +++ b/core/kazoo_numbers/src/converters/knm_converter_regex.erl @@ -13,6 +13,7 @@ -export([normalize/1, normalize/2, normalize/3 ,to_npan/1 ,to_1npan/1 + ,to_strip_plus/1 ]). -export([get_e164_converters/0 ,get_e164_converters/1 @@ -81,6 +82,15 @@ to_1npan(Num) -> {'match', [NPAN]} -> <<$1, NPAN/binary>> end. +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec to_strip_plus(kz_term:ne_binary()) -> kz_term:ne_binary(). +to_strip_plus(Number) -> + <<"+",N/binary>> = to_e164(Number), + N. + %%%============================================================================= %%% Internal functions %%%============================================================================= diff --git a/core/kazoo_numbers/src/converters/knm_converters.erl b/core/kazoo_numbers/src/converters/knm_converters.erl index e3b0610a0f3..5afd9ad0b61 100644 --- a/core/kazoo_numbers/src/converters/knm_converters.erl +++ b/core/kazoo_numbers/src/converters/knm_converters.erl @@ -16,6 +16,7 @@ ,is_normalized/1 ,is_npan/1, to_npan/1 ,is_1npan/1, to_1npan/1 + ,is_strip_plus/1, to_strip_plus/1 ,to_db/1 ,is_reconcilable/1, is_reconcilable/2, are_reconcilable/1 ,classify/1, available_classifiers/0 @@ -175,6 +176,22 @@ is_1npan(Num) -> to_1npan(Num) -> (?CONVERTER_MOD):to_1npan(Num). +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec is_strip_plus(kz_term:ne_binary()) -> boolean(). +is_strip_plus(Num) -> + to_strip_plus(Num) =:= Num. + +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec to_strip_plus(kz_term:ne_binary()) -> kz_term:ne_binary(). +to_strip_plus(Num) -> + (?CONVERTER_MOD):to_strip_plus(Num). + %%------------------------------------------------------------------------------ %% @doc Given a number determine the database name it belongs to.. %% @end From 9bc3b1158c9596748002f888ddda979f90cded83 Mon Sep 17 00:00:00 2001 From: John White Date: Tue, 7 Apr 2020 17:21:42 -0500 Subject: [PATCH 02/12] add strip_plus to schema objects with INVITE Format and their docs. --- applications/crossbar/doc/connectivity.md | 2 +- applications/crossbar/doc/devices.md | 2 +- applications/crossbar/doc/ref/connectivity.md | 2 +- applications/crossbar/doc/ref/devices.md | 2 +- applications/crossbar/doc/ref/resources.md | 2 +- applications/crossbar/doc/resources.md | 2 +- applications/crossbar/priv/api/descriptions.system_config.json | 2 +- applications/crossbar/priv/couchdb/schemas/connectivity.json | 3 ++- applications/crossbar/priv/couchdb/schemas/devices.json | 1 + .../priv/couchdb/schemas/kapi.dialplan.bridge_endpoint.json | 1 + .../crossbar/priv/couchdb/schemas/kapi.route.resp_route.json | 1 + applications/crossbar/priv/couchdb/schemas/resources.json | 3 ++- .../priv/couchdb/schemas/system_config.number_manager.json | 2 +- applications/crossbar/priv/couchdb/schemas/trunkstore.json | 1 + .../test/fixtures/schemav3_sub_defaults_array.json | 3 ++- 15 files changed, 18 insertions(+), 11 deletions(-) diff --git a/applications/crossbar/doc/connectivity.md b/applications/crossbar/doc/connectivity.md index 4b90409f429..7e186803e02 100644 --- a/applications/crossbar/doc/connectivity.md +++ b/applications/crossbar/doc/connectivity.md @@ -56,7 +56,7 @@ Key | Description | Type | Default | Required | Support Level `servers.[].options.hunt_account_id` | When using local resources, use this account instead of the account making the call (useful for resellers) | `string()` | | `false` | `servers.[].options.hunt_non_reconcilable` | Whether to allow routing to continue on a non-reconcilable TO number | `boolean()` | `false` | `false` | `servers.[].options.ignore_early_media` | | `boolean()` | | `false` | -`servers.[].options.inbound_format` | Determines how the INVITE is sent to the server | `string('e164' | 'npan' | '1npan' | 'username')` | `npan` | `false` | +`servers.[].options.inbound_format` | Determines how the INVITE is sent to the server | `string('e164' | 'npan' | '1npan' | 'username' | 'strip_plus')` | `npan` | `false` | `servers.[].options.ip` | IP (sip) address for this device | `string()` | | `false` | `servers.[].options.media_handling` | Determine whether the switch should be in the media path or not | `string('process' | 'bypass')` | `bypass` | `false` | `servers.[].options.port` | Port to send SIP traffic for the remote device | `integer()` | | `false` | diff --git a/applications/crossbar/doc/devices.md b/applications/crossbar/doc/devices.md index e6920917aa0..dedf38705f2 100644 --- a/applications/crossbar/doc/devices.md +++ b/applications/crossbar/doc/devices.md @@ -74,7 +74,7 @@ Key | Description | Type | Default | Required | Support Level `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` | `supported` `sip.forward` | Forward IP to use | `string()` | | `false` | `sip.ignore_completed_elsewhere` | When set to false the phone should not consider ring group calls answered elsewhere as missed | `boolean()` | | `false` | -`sip.invite_format` | The SIP request URI invite format | `string('username' | 'npan' | '1npan' | 'e164' | 'route' | 'contact')` | `contact` | `false` | `supported` +`sip.invite_format` | The SIP request URI invite format | `string('username' | 'npan' | '1npan' | 'e164' | 'route' | 'strip_plus' | 'contact')` | `contact` | `false` | `supported` `sip.ip` | IP address for this device | `string()` | | `false` | `supported` `sip.method` | Method of authentication | `string('password' | 'ip')` | `password` | `false` | `supported` `sip.number` | The number used if the invite format is 1npan, npan, or e164 (if not set the dialed number is used) | `string()` | | `false` | diff --git a/applications/crossbar/doc/ref/connectivity.md b/applications/crossbar/doc/ref/connectivity.md index 53bedfb92f4..3987e76b557 100644 --- a/applications/crossbar/doc/ref/connectivity.md +++ b/applications/crossbar/doc/ref/connectivity.md @@ -56,7 +56,7 @@ Key | Description | Type | Default | Required | Support Level `servers.[].options.hunt_account_id` | When using local resources, use this account instead of the account making the call (useful for resellers) | `string()` | | `false` | `servers.[].options.hunt_non_reconcilable` | Whether to allow routing to continue on a non-reconcilable TO number | `boolean()` | `false` | `false` | `servers.[].options.ignore_early_media` | | `boolean()` | | `false` | -`servers.[].options.inbound_format` | Determines how the INVITE is sent to the server | `string('e164' | 'npan' | '1npan' | 'username')` | `npan` | `false` | +`servers.[].options.inbound_format` | Determines how the INVITE is sent to the server | `string('e164' | 'npan' | '1npan' | 'username' | 'strip_plus')` | `npan` | `false` | `servers.[].options.ip` | IP (sip) address for this device | `string()` | | `false` | `servers.[].options.media_handling` | Determine whether the switch should be in the media path or not | `string('process' | 'bypass')` | `bypass` | `false` | `servers.[].options.port` | Port to send SIP traffic for the remote device | `integer()` | | `false` | diff --git a/applications/crossbar/doc/ref/devices.md b/applications/crossbar/doc/ref/devices.md index 7269798f38c..b601723606a 100644 --- a/applications/crossbar/doc/ref/devices.md +++ b/applications/crossbar/doc/ref/devices.md @@ -71,7 +71,7 @@ Key | Description | Type | Default | Required | Support Level `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` | `supported` `sip.forward` | Forward IP to use | `string()` | | `false` | `sip.ignore_completed_elsewhere` | When set to false the phone should not consider ring group calls answered elsewhere as missed | `boolean()` | | `false` | -`sip.invite_format` | The SIP request URI invite format | `string('username' | 'npan' | '1npan' | 'e164' | 'route' | 'contact')` | `contact` | `false` | `supported` +`sip.invite_format` | The SIP request URI invite format | `string('username' | 'npan' | '1npan' | 'e164' | 'route' | 'strip_plus' | 'contact')` | `contact` | `false` | `supported` `sip.ip` | IP address for this device | `string()` | | `false` | `supported` `sip.method` | Method of authentication | `string('password' | 'ip')` | `password` | `false` | `supported` `sip.number` | The number used if the invite format is 1npan, npan, or e164 (if not set the dialed number is used) | `string()` | | `false` | diff --git a/applications/crossbar/doc/ref/resources.md b/applications/crossbar/doc/ref/resources.md index 522b5c29a95..7329f7ad448 100644 --- a/applications/crossbar/doc/ref/resources.md +++ b/applications/crossbar/doc/ref/resources.md @@ -48,7 +48,7 @@ Key | Description | Type | Default | Required | Support Level `gateways.[].force_port` | Allow request only from this port | `boolean()` | `false` | `false` | `gateways.[].format_from_uri` | When set to true requests to this resource gateway will have a reformatted SIP From Header | `boolean()` | | `false` | `gateways.[].from_uri_realm` | When formatting 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.[].invite_format` | The format of the DID needed by the underlying hardware/gateway | `string('route' | 'username' | 'e164' | 'npan' | '1npan' | 'strip_plus')` | `route` | `false` | `gateways.[].invite_parameters.dynamic.[]` | | `string()|string()|string('zone')|object()` | | | `gateways.[].invite_parameters.dynamic` | A list of properties that, if found on the inbound call, should be added as an INVITE parameter | `array()` | | `false` | `gateways.[].invite_parameters.static.[]` | | `string()` | | `false` | diff --git a/applications/crossbar/doc/resources.md b/applications/crossbar/doc/resources.md index b65f2862ca2..760483a1f68 100644 --- a/applications/crossbar/doc/resources.md +++ b/applications/crossbar/doc/resources.md @@ -64,7 +64,7 @@ Key | Description | Type | Default | Required | Support Level `gateways.[].force_port` | Allow request only from this port | `boolean()` | `false` | `false` | `gateways.[].format_from_uri` | When set to true requests to this resource gateway will have a reformatted SIP From Header | `boolean()` | | `false` | `gateways.[].from_uri_realm` | When formatting 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.[].invite_format` | The format of the DID needed by the underlying hardware/gateway | `string('route' | 'username' | 'e164' | 'npan' | '1npan' | 'strip_plus')` | `route` | `false` | `gateways.[].invite_parameters.dynamic.[]` | | `string()|string()|string('zone')|object()` | | | `gateways.[].invite_parameters.dynamic` | A list of properties that, if found on the inbound call, should be added as an INVITE parameter | `array()` | | `false` | `gateways.[].invite_parameters.static.[]` | | `string()` | | `false` | diff --git a/applications/crossbar/priv/api/descriptions.system_config.json b/applications/crossbar/priv/api/descriptions.system_config.json index 53de918786f..8e001d2f903 100644 --- a/applications/crossbar/priv/api/descriptions.system_config.json +++ b/applications/crossbar/priv/api/descriptions.system_config.json @@ -512,7 +512,7 @@ "number_manager.bandwidth2.site_id": "number_manager.bandwidth2 site id", "number_manager.carrier_modules": "carrier modules to perform number search & ordering from", "number_manager.classifiers": "regular expressions & billing names for numbers", - "number_manager.converters": "suffix for the KNM module to use for E164, NPAN and 1NPAN normalization of numbers", + "number_manager.converters": "suffix for the KNM module to use for E164, NPAN, 1NPAN and strip_plus normalization of numbers", "number_manager.dash_e911.auth_password": "number_manager.dash_e911 auth password", "number_manager.dash_e911.auth_username": "number_manager.dash_e911 auth username", "number_manager.dash_e911.debug": "number_manager.dash_e911 debug", diff --git a/applications/crossbar/priv/couchdb/schemas/connectivity.json b/applications/crossbar/priv/couchdb/schemas/connectivity.json index acb4d11613a..4511d966dc7 100644 --- a/applications/crossbar/priv/couchdb/schemas/connectivity.json +++ b/applications/crossbar/priv/couchdb/schemas/connectivity.json @@ -232,7 +232,8 @@ "e164", "npan", "1npan", - "username" + "username", + "strip_plus" ], "type": "string" }, diff --git a/applications/crossbar/priv/couchdb/schemas/devices.json b/applications/crossbar/priv/couchdb/schemas/devices.json index a416191729d..37ac7ca73bf 100644 --- a/applications/crossbar/priv/couchdb/schemas/devices.json +++ b/applications/crossbar/priv/couchdb/schemas/devices.json @@ -373,6 +373,7 @@ "1npan", "e164", "route", + "strip_plus", "contact" ], "support_level": "supported", diff --git a/applications/crossbar/priv/couchdb/schemas/kapi.dialplan.bridge_endpoint.json b/applications/crossbar/priv/couchdb/schemas/kapi.dialplan.bridge_endpoint.json index df4935f06e8..43fcf0488d3 100644 --- a/applications/crossbar/priv/couchdb/schemas/kapi.dialplan.bridge_endpoint.json +++ b/applications/crossbar/priv/couchdb/schemas/kapi.dialplan.bridge_endpoint.json @@ -43,6 +43,7 @@ "npan", "1npan", "route", + "strip_plus", "loopback", "contact" ], diff --git a/applications/crossbar/priv/couchdb/schemas/kapi.route.resp_route.json b/applications/crossbar/priv/couchdb/schemas/kapi.route.resp_route.json index 70f088c302f..9c1a8f9fe00 100644 --- a/applications/crossbar/priv/couchdb/schemas/kapi.route.resp_route.json +++ b/applications/crossbar/priv/couchdb/schemas/kapi.route.resp_route.json @@ -48,6 +48,7 @@ "npan", "1npan", "route", + "strip_plus", "loopback", "contact" ], diff --git a/applications/crossbar/priv/couchdb/schemas/resources.json b/applications/crossbar/priv/couchdb/schemas/resources.json index 3604522de66..2ab8da5621d 100644 --- a/applications/crossbar/priv/couchdb/schemas/resources.json +++ b/applications/crossbar/priv/couchdb/schemas/resources.json @@ -232,7 +232,8 @@ "username", "e164", "npan", - "1npan" + "1npan", + "strip_plus" ], "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 f75dd8f10f5..7a6fc71b4c0 100644 --- a/applications/crossbar/priv/couchdb/schemas/system_config.number_manager.json +++ b/applications/crossbar/priv/couchdb/schemas/system_config.number_manager.json @@ -66,7 +66,7 @@ "default": [ "regex" ], - "description": "suffix for the KNM module to use for E164, NPAN and 1NPAN normalization of numbers", + "description": "suffix for the KNM module to use for E164, NPAN, 1NPAN and strip_plus normalization of numbers", "items": { "type": "string" }, diff --git a/applications/crossbar/priv/couchdb/schemas/trunkstore.json b/applications/crossbar/priv/couchdb/schemas/trunkstore.json index 9659d9965f1..5b1a931efc4 100644 --- a/applications/crossbar/priv/couchdb/schemas/trunkstore.json +++ b/applications/crossbar/priv/couchdb/schemas/trunkstore.json @@ -245,6 +245,7 @@ "e164", "npan", "1npan", + "strip_plus", "username" ], "type": "string" diff --git a/core/kazoo_schemas/test/fixtures/schemav3_sub_defaults_array.json b/core/kazoo_schemas/test/fixtures/schemav3_sub_defaults_array.json index a95929bcac3..9b0544b8509 100644 --- a/core/kazoo_schemas/test/fixtures/schemav3_sub_defaults_array.json +++ b/core/kazoo_schemas/test/fixtures/schemav3_sub_defaults_array.json @@ -167,7 +167,8 @@ "username", "e164", "npan", - "1npan" + "1npan", + "strip_plus" ], "type": "string" }, From 6144a8c573d4b9d515f9b9f92ca150cdcf9cbf3b Mon Sep 17 00:00:00 2001 From: John White Date: Thu, 30 Apr 2020 15:54:13 -0500 Subject: [PATCH 03/12] - Add strip_plus converter case to trunkstore - Add strip_plus converter case to ecallmgr - Add strip_plus converter case to kapps_call_command - Add strip_plus converter to kz_directory_endpoints - Add strip_plus converter to kz_endpoints - Remove extraneous comment from regex_converter --- applications/ecallmgr/src/ecallmgr_util.erl | 8 +++++++ applications/trunkstore/src/ts_util.erl | 21 ++++++++----------- core/kazoo_amqp/src/api/kapi_dialplan.hrl | 1 + core/kazoo_call/src/kapps_call_command.erl | 1 + .../src/kz_directory_endpoint.erl | 1 + core/kazoo_endpoint/src/kz_formatters.erl | 3 ++- .../src/converters/knm_converter_regex.erl | 6 ++++-- 7 files changed, 26 insertions(+), 15 deletions(-) diff --git a/applications/ecallmgr/src/ecallmgr_util.erl b/applications/ecallmgr/src/ecallmgr_util.erl index b59035d27c7..08ec775202f 100644 --- a/applications/ecallmgr/src/ecallmgr_util.erl +++ b/applications/ecallmgr/src/ecallmgr_util.erl @@ -955,6 +955,12 @@ build_freetdm_channel(#bridge_endpoint{invite_format = <<"1npan">> ,channel_selection=ChannelSelection }) -> {'ok', <<"freetdm/", Span/binary, "/", ChannelSelection/binary, "/", (knm_converters:to_1npan(Number))/binary>>}; +build_freetdm_channel(#bridge_endpoint{invite_format = <<"strip_plus">> + ,number=Number + ,span=Span + ,channel_selection=ChannelSelection + }) -> + {'ok', <<"freetdm/", Span/binary, "/", ChannelSelection/binary, "/", (knm_converters:to_strip_plus(Number))/binary>>}; build_freetdm_channel(#bridge_endpoint{number=Number ,span=Span ,channel_selection=ChannelSelection @@ -1142,6 +1148,8 @@ maybe_format_user(Contact, #bridge_endpoint{invite_format = <<"npan">>, number=N re:replace(Contact, "^[^\@]+", knm_converters:to_npan(Number), [{'return', 'binary'}]); maybe_format_user(Contact, #bridge_endpoint{invite_format = <<"1npan">>, number=Number}) -> re:replace(Contact, "^[^\@]+", knm_converters:to_1npan(Number), [{'return', 'binary'}]); +maybe_format_user(Contact, #bridge_endpoint{invite_format = <<"strip_plus">>, number=Number}) -> + re:replace(Contact, "^[^\@]+", knm_converters:to_strip_plus(Number), [{'return', 'binary'}]); maybe_format_user(Contact, _) -> Contact. -spec maybe_set_interface(kz_term:ne_binary(), bridge_endpoint()) -> kz_term:ne_binary(). diff --git a/applications/trunkstore/src/ts_util.erl b/applications/trunkstore/src/ts_util.erl index b290dbef73f..58f3eda6a2b 100644 --- a/applications/trunkstore/src/ts_util.erl +++ b/applications/trunkstore/src/ts_util.erl @@ -259,18 +259,11 @@ invite_format(<<"e164">>, To) -> [{<<"Invite-Format">>, <<"e164">>} ,{<<"To-DID">>, knm_converters:normalize(To)} ]; -invite_format(<<"e164_without_plus">>, To) -> - case knm_converters:normalize(To) of - <<$+, PluslessDID/binary>> -> - lager:info("while processing 'e164_without_plus' flag, DID ~s converted to E.164 with truncated '+': ~s",[To, PluslessDID]), - [{<<"Invite-Format">>, <<"e164">>} - ,{<<"To-DID">>, PluslessDID} - ]; - AsIsDID -> - [{<<"Invite-Format">>, <<"e164">>} - ,{<<"To-DID">>, AsIsDID} - ] - end; +invite_format(<<"e164_without_plus">>=Format, To) -> + lager:debug("~p: changing legacy format ~p to strip_plus", [?MODULE, Format]), + [{<<"Invite-Format">>, <<"strip_plus">>} + ,{<<"To-DID">>, knm_converters:to_strip_plus(To)} + ]; invite_format(<<"1npanxxxxxx">>, To) -> [{<<"Invite-Format">>, <<"1npan">>} ,{<<"To-DID">>, knm_converters:to_1npan(To)} @@ -287,6 +280,10 @@ invite_format(<<"npan">>, To) -> [{<<"Invite-Format">>, <<"npan">>} ,{<<"To-DID">>, knm_converters:to_npan(To)} ]; +invite_format(<<"strip_plus">>, To) -> + [{<<"Invite-Format">>, <<"strip_plus">>} + ,{<<"To-DID">>, knm_converters:to_strip_plus(To)} + ]; invite_format(_, _) -> [{<<"Invite-Format">>, <<"username">>}]. diff --git a/core/kazoo_amqp/src/api/kapi_dialplan.hrl b/core/kazoo_amqp/src/api/kapi_dialplan.hrl index 39c46ba03b5..bae4526fbcd 100644 --- a/core/kazoo_amqp/src/api/kapi_dialplan.hrl +++ b/core/kazoo_amqp/src/api/kapi_dialplan.hrl @@ -16,6 +16,7 @@ ,<<"route">>, <<"loopback">> ,<<"contact">> ,<<"endpoint">>, <<"forward">> + ,<<"strip_plus">> ] }). diff --git a/core/kazoo_call/src/kapps_call_command.erl b/core/kazoo_call/src/kapps_call_command.erl index 2ef6b14c9a7..d92b694d1bc 100644 --- a/core/kazoo_call/src/kapps_call_command.erl +++ b/core/kazoo_call/src/kapps_call_command.erl @@ -1199,6 +1199,7 @@ bridge_context_request_uris(Call, Props) -> URIs = [{<<"e164">>, knm_converters:normalize(kapps_call:request_user(Call), kapps_call:account_id(Call))} ,{<<"npan">>, knm_converters:to_npan(kapps_call:request_user(Call))} ,{<<"1npan">>, knm_converters:to_1npan(kapps_call:request_user(Call))} + ,{<<"strip_plus">>, knm_converters:to_strip_plus(kapps_call:request_user(Call))} ,{<<"route">>, kapps_call:request_user(Call)} ], [{<<"request">>, kz_json:from_list(URIs)} | Props]. diff --git a/core/kazoo_directory/src/kz_directory_endpoint.erl b/core/kazoo_directory/src/kz_directory_endpoint.erl index 34db2f81348..0fa9ef8d4aa 100644 --- a/core/kazoo_directory/src/kz_directory_endpoint.erl +++ b/core/kazoo_directory/src/kz_directory_endpoint.erl @@ -134,6 +134,7 @@ invite_uri(Endpoint, CCVs) -> <<"e164">> -> set_invite_uri(fun knm_converters:normalize/1, kzd_devices:sip_number(Endpoint), <<"e164">>, Realm, CCVs); <<"1npan">> -> set_invite_uri(fun knm_converters:to_1npan/1, kzd_devices:sip_number(Endpoint), <<"1npan">>, Realm, CCVs); <<"npan">> -> set_invite_uri(fun knm_converters:to_npan/1, kzd_devices:sip_number(Endpoint), <<"npan">>, Realm, CCVs); + <<"strip_plus">> -> set_invite_uri(fun knm_converters:to_strip_plus/1, kzd_devices:sip_number(Endpoint), <<"strip_plus">>, Realm, CCVs); <<"contact">> -> set_invite_uri(kzd_devices:sip_username(Endpoint), Realm, CCVs); <<"username">> -> set_invite_uri(kzd_devices:sip_username(Endpoint), Realm, CCVs) end. diff --git a/core/kazoo_endpoint/src/kz_formatters.erl b/core/kazoo_endpoint/src/kz_formatters.erl index eaa2c807763..e81827316bd 100644 --- a/core/kazoo_endpoint/src/kz_formatters.erl +++ b/core/kazoo_endpoint/src/kz_formatters.erl @@ -289,7 +289,8 @@ invite_format_fun(JObj) -> case kz_json:get_ne_binary_value(<<"Invite-Format">>, JObj) of <<"e164">> -> fun knm_converters:normalize/1; <<"1npan">> -> fun knm_converters:to_1npan/1; - <<"npan">> -> fun knm_converters:to_npan/1 + <<"npan">> -> fun knm_converters:to_npan/1; + <<"strip_plus">> -> fun knm_converters:to_strip_plus/1 end. -spec maybe_match(kz_json:object(), kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), kz_json:object()) -> diff --git a/core/kazoo_numbers/src/converters/knm_converter_regex.erl b/core/kazoo_numbers/src/converters/knm_converter_regex.erl index 23ae1479851..cb366613cb0 100644 --- a/core/kazoo_numbers/src/converters/knm_converter_regex.erl +++ b/core/kazoo_numbers/src/converters/knm_converter_regex.erl @@ -88,8 +88,10 @@ to_1npan(Num) -> %%------------------------------------------------------------------------------ -spec to_strip_plus(kz_term:ne_binary()) -> kz_term:ne_binary(). to_strip_plus(Number) -> - <<"+",N/binary>> = to_e164(Number), - N. + case normalize(Number) of + <<$+,N/binary>> -> N; + DID -> DID + end. %%%============================================================================= %%% Internal functions From d2486f8ac8447fde9bcb7171646554381adb7f9d Mon Sep 17 00:00:00 2001 From: John White Date: Thu, 30 Apr 2020 15:58:59 -0500 Subject: [PATCH 04/12] - Adds migration script to change invite_format on devices, resources, and trunks --- .../knm_converter_migrate_maintenance.erl | 361 ++++++++++++++++++ 1 file changed, 361 insertions(+) create mode 100644 core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl diff --git a/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl b/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl new file mode 100644 index 00000000000..5f307e6d859 --- /dev/null +++ b/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl @@ -0,0 +1,361 @@ +%%%----------------------------------------------------------------------------- +%%% @copyright (C) 2010-2020, 2600Hz +%%% @doc +%%% This Source Code Form is subject to the terms of the Mozilla Public +%%% License, v. 2.0. If a copy of the MPL was not distributed with this +%%% file, You can obtain one at https://mozilla.org/MPL/2.0/. +%%% +%%% @end +%%%----------------------------------------------------------------------------- +-module (knm_converter_migrate_maintenance). + +-export ([migrate/0 + ,migrate_account/1 + ,migrate_invite_format/1, migrate_invite_format/3 + ,migrate_devices/1, migrate_devices/3 + ,migrate_global_resources/0, migrate_global_resources/2 + ,migrate_local_resources/1, migrate_local_resources/3 + ,migrate_trunkstore/1, migrate_trunkstore/3 + ]). + +-define(LEGACY_STRIP_PLUS, <<"e164_without_plus">>). +-define(ONE_NPAN, <<"1npan">>). +-define(NPAN, <<"npan">>). +-define(STRIP_PLUS, <<"strip_plus">>). +-define(DEFAULT_FROM, <<"npan">>). +-define(DEFAULT_TO, <<"strip_plus">>). + +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec migrate() -> 'ok'. +migrate() -> + AccountIds = kz_term:shuffle_list(kapps_util:get_all_accounts('raw')), + Total = length(AccountIds), + io:format("Start migrating from ~b databases~n~n", [Total]), + lists:foldl(fun(A, C) -> migrate_account_fold(A, C, Total) end, 1, AccountIds), + migrate_global_resources(), + 'ok'. + +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec migrate_account_fold(kz_term:ne_binary(), non_neg_integer(), non_neg_integer()) -> non_neg_integer(). +migrate_account_fold(AccountId, Current, Total) -> + io:format("(~p/~p) migrating items within account '~s'~n", [Current, Total, AccountId]), + _ = migrate_account(AccountId), + io:format("[~s] finished migrating items~n~n", [AccountId]), + Current + 1. + +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec migrate_account(kz_term:ne_binary()) -> 'ok'. +migrate_account(Account) -> + lists:foreach(fun(Fun) -> Fun(Account) end + ,[fun migrate_invite_format/1] + ). + +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec migrate_invite_format(kz_term:ne_binary()) -> 'ok'. +migrate_invite_format(Account) -> + migrate_invite_format(Account, ?DEFAULT_FROM, ?DEFAULT_TO). + +-spec migrate_invite_format(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary()) -> 'ok'. +migrate_invite_format(Account, From, To) -> + io:format("migrating INVITE formatter from ~s to ~s account ~s~n", [From, To, Account]), + lists:foreach(fun(Fun) -> Fun(Account, From, To) end + ,[fun migrate_devices/3 + ,fun migrate_local_resources/3 + ,fun migrate_trunkstore/3 + ] + ). + +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec migrate_devices(kz_term:ne_binary()) -> 'ok'. +migrate_devices(Account) -> + migrate_devices(Account, ?DEFAULT_FROM, ?DEFAULT_TO). + +-spec migrate_devices(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary()) -> 'ok'. +migrate_devices(Account, From, To) -> + AccountDb = kzs_util:format_account_db(Account), + Total = get_view_count(AccountDb, <<"devices/crossbar_listing">>), + migrate_devices(AccountDb, From, To, Total). + +-spec migrate_devices(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), non_neg_integer()) -> 'ok'. +migrate_devices(AccountDb, _From, _To, 0) -> + io:format("[~s] no devices found~n", [kzs_util:format_account_id(AccountDb)]); +migrate_devices(AccountDb, From, To, Total) -> + Limit = kz_datamgr:max_bulk_read(), + io:format("[~s] start migrating total ~b devices with batch size ~b~n", [kzs_util:format_account_id(AccountDb), Total, Limit]), + Stats = #{total => Total + ,processed => 0 + ,updated => 0 + ,result => #{} + ,skip => 0 + }, + maybe_migrate_devices(AccountDb, From, To, Stats, [{'limit', Limit}]). + +-spec maybe_migrate_devices(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), map(), kz_term:proplist()) -> 'ok'. +maybe_migrate_devices(AccountDb, From, To, #{total := Total, processed := _Processed, updated := Updated, skip := _Skip}=Stats, ViewOptions) -> + AccountId = kzs_util:format_account_id(AccountDb), + case kz_datamgr:get_results(AccountDb, <<"devices/crossbar_listing">>, ViewOptions) of + {'ok', []} -> + io:format("[~s] device migration finished, (~b/~b) devices has been updated~n" + ,[kzs_util:format_account_id(AccountId), Updated, Total] + ); + {'ok', ViewResults} -> + Length = length(ViewResults), + io:format("[~s] processing ~b devices~n", [AccountId, Length]), + UpdateFun = fun(JObj, Map) -> + maybe_update_device(AccountDb, kz_json:get_ne_binary_value(<<"key">>, JObj), From, To, Map) + end, + ProcessMap = lists:foldl(UpdateFun, Stats, ViewResults), + io:format("[~s] device migration finished, (~b/~b) devices has been updated~n" + ,[AccountId, maps:get('updated', ProcessMap), Total] + ); + {'error', _R} -> + io:format("[~s] failed to fetch devices: ~p~n~n", [AccountId, _R]) + end. + +maybe_update_device(AccountDb, DeviceId, From, To, #{total := _Total, processed := Processed, updated := Updated, skip := Skip}=Map) -> + {'ok', Doc} = kzd_devices:fetch(AccountDb, DeviceId), + case kzd_devices:sip_invite_format(Doc) of + From -> + NewDevice = kzd_devices:set_sip_invite_format(Doc, To), + maybe_save_doc(NewDevice, Map); + _ -> + Map#{processed => Processed+1, updated => Updated, skip => Skip+1} + end. + +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec migrate_local_resources(kz_term:ne_binary()) -> 'ok'. +migrate_local_resources(Account) -> + migrate_local_resources(Account, ?DEFAULT_FROM, ?DEFAULT_TO). + +-spec migrate_local_resources(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary()) -> 'ok'. +migrate_local_resources(Account, From, To) -> + AccountDb = kzs_util:format_account_db(Account), + Total = get_view_count(AccountDb, <<"resources/crossbar_listing">>), + migrate_resources(AccountDb, From, To, Total). + +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec migrate_global_resources() -> 'ok'. +migrate_global_resources() -> + migrate_global_resources(?DEFAULT_FROM, ?DEFAULT_TO). + +-spec migrate_global_resources(kz_term:ne_binary(), kz_term:ne_binary()) -> 'ok'. +migrate_global_resources(From, To) -> + Db = <<"offnet">>, + Total = get_view_count(Db, <<"resources/crossbar_listing">>), + migrate_resources(Db, From, To, Total). + +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec migrate_resources(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), non_neg_integer()) -> 'ok'. +migrate_resources(AccountId, _From, _To, 0) -> + io:format("[~s] no resources found~n", [AccountId]); +migrate_resources(<<"offnet">>=AccountDb, From, To, Total) -> + maybe_migrate_resources(AccountDb, From, To, Total); +migrate_resources(AccountId, From, To, Total) -> + AccountDb = kzs_util:format_account_db(AccountId), + maybe_migrate_resources(AccountDb, From, To, Total). + +-spec maybe_migrate_resources(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), non_neg_integer()) -> 'ok'. +maybe_migrate_resources(AccountDb, From, To, Total) -> + Limit = kz_datamgr:max_bulk_read(), + io:format("[~s] start migrating total ~b resources with batch size ~b~n", [kzs_util:format_account_id(AccountDb), Total, Limit]), + Stats = #{total => Total + ,processed => 0 + ,updated => 0 + ,result => #{} + ,skip => 0 + }, + maybe_migrate_resources(AccountDb, From, To, Stats, [{'limit', Limit}]). + +-spec maybe_migrate_resources(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), map(), kz_term:proplist()) -> 'ok'. +maybe_migrate_resources(AccountDb, From, To, #{total := Total, processed := _Processed, updated := Updated, skip := _Skip}=Stats, ViewOptions) -> + AccountId = kzs_util:format_account_id(AccountDb), + case kz_datamgr:get_results(AccountDb, <<"resources/crossbar_listing">>, ViewOptions) of + {'ok', []} -> + io:format("[~s] resource migration finished, (~b/~b) resources has been updated~n" + ,[AccountId, Updated, Total] + ); + {'ok', ViewResults} -> + Length = length(ViewResults), + io:format("[~s] processing ~b resources~n", [AccountId, Length]), + UpdateFun = fun(JObj, Map) -> + maybe_update_resource(AccountDb, kz_json:get_ne_binary_value(<<"key">>, JObj), From, To, Map) + end, + ProcessMap = lists:foldl(UpdateFun, Stats, ViewResults), + io:format("[~s] resource migration finished, (~b/~b) resources has been updated~n" + ,[AccountId, maps:get('updated', ProcessMap), Total] + ); + {'error', _R} -> + io:format("[~s] failed to fetch resources: ~p~n~n", [AccountId, _R]) + end. + +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec maybe_update_resource(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), map()) -> map(). +maybe_update_resource(AccountDb, ResourceId, From, To, #{total := _Total, processed := Processed, updated := _Updated, skip := Skip}=Map) -> + {'ok', Doc} = kz_datamgr:open_doc(AccountDb, ResourceId), + UpdateFun = fun(JObj, Acc) -> + maybe_update_gateways(JObj, From, To, Acc) + end, + Gateways = kzd_resources:gateways(Doc), + NewGateways = lists:foldl(UpdateFun, [], Gateways), + NewResource = kzd_resources:set_gateways(Doc, NewGateways), + case kz_json:are_equal(Doc, NewResource) of + 'true' -> + Map#{processed => Processed+1, skip => Skip+1}; + 'false' -> + maybe_save_doc(NewResource, Map) + end. +-spec maybe_update_gateways(kz_json:object(), kz_term:ne_binary(), kz_term:ne_binary(), kz_json:objects()) -> kz_json:objects(). +maybe_update_gateways(Gateway, From, To, Acc) -> + case kz_json:get_ne_binary_value(<<"invite_format">>, Gateway, 'undefined') of + From -> + NewGateway = kz_json:set_value(<<"invite_format">>, To, Gateway), + [NewGateway | Acc]; + _ -> [Gateway | Acc] + end. + +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec migrate_trunkstore(kz_term:ne_binary()) -> 'ok'. +migrate_trunkstore(Account) -> + migrate_trunkstore(Account, ?DEFAULT_FROM, ?DEFAULT_TO). + +-spec migrate_trunkstore(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary()) -> 'ok'. +migrate_trunkstore(Account, From, To) -> + AccountDb = kzs_util:format_account_db(Account), + Total = get_view_count(AccountDb, <<"trunkstore/crossbar_listing">>, []), + migrate_trunkstore(AccountDb, From, To, Total), + 'ok'. + +-spec migrate_trunkstore(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), non_neg_integer()) -> 'ok'. +migrate_trunkstore(AccountDb, _From, _To, 0) -> + io:format("[~s] no trunks found~n", [kzs_util:format_account_id(AccountDb)]); +migrate_trunkstore(AccountDb, From, To, Total) -> + Limit = kz_datamgr:max_bulk_read(), + io:format("[~s] start migrating total ~b trunks with batch size ~b~n", [kzs_util:format_account_id(AccountDb), Total, Limit]), + Stats = #{total => Total + ,processed => 0 + ,updated => 0 + ,result => #{} + ,skip => 0 + }, + maybe_migrate_trunkstore(AccountDb, From, To, Stats, [{'limit', Limit}, {'reduce', 'false'}]). + +-spec maybe_migrate_trunkstore(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), map(), kz_term:proplist()) -> 'ok'. +maybe_migrate_trunkstore(AccountDb, From, To, #{total := Total, processed := _Processed, updated := Updated, skip := _Skip}=Stats, ViewOptions) -> + AccountId =kzs_util:format_account_id(AccountDb), + case kz_datamgr:get_results(AccountDb, <<"trunkstore/crossbar_listing">>, ViewOptions) of + {'ok', []} -> + io:format("[~s] trunk migration finished, (~b/~b) trunks has been updated~n" + ,[AccountId, Updated, Total] + ); + {'ok', ViewResults} -> + Length = length(ViewResults), + io:format("[~s] processing ~b trunks~n", [AccountId, Length]), + UpdateFun = fun(JObj, Map) -> + maybe_update_trunk(AccountDb, kz_json:get_ne_binary_value(<<"id">>, JObj), From, To, Map) + end, + ProcessMap = lists:foldl(UpdateFun, Stats, ViewResults), + io:format("[~s] trunkstore migration finished, (~b/~b) trunks has been updated~n" + ,[AccountId, maps:get('updated', ProcessMap), Total] + ); + {'error', _R} -> + io:format("[~s] failed to fetch trunks: ~p~n~n", [AccountId, _R]) + end. + +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec maybe_update_trunk(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), map()) -> map(). +maybe_update_trunk(AccountDb, TrunkId, From, To, #{total := _Total, processed := Processed, updated := _Updated, skip := Skip}=Map) -> + {'ok', Doc} = kz_datamgr:open_doc(AccountDb, TrunkId), + UpdateFun = fun(JObj, Acc) -> + maybe_update_servers(JObj, From, To, Acc) + end, + Servers = kzd_trunkstore:servers(Doc), + NewServers = lists:foldl(UpdateFun, [], Servers), + NewTrunkstore = kzd_trunkstore:set_servers(Doc, NewServers), + case kz_json:are_equal(Doc, NewTrunkstore) of + 'true' -> + Map#{processed => Processed+1, skip => Skip+1}; + 'false' -> + maybe_save_doc(NewTrunkstore, Map) + end. + +-spec maybe_update_servers(kz_json:object(), kz_term:ne_binary(), kz_term:ne_binary(), kz_json:objects()) -> kz_json:objects(). +maybe_update_servers(Server, From, To, Acc) -> + case kz_json:get_ne_binary_value([<<"options">>, <<"inbound_format">>], Server, 'undefined') of + From -> + NewServer = kz_json:set_value([<<"options">>, <<"inbound_format">>], To, Server), + [NewServer | Acc]; + _ -> [Server | Acc] + end. + +%%%============================================================================= +%%% Internal functions +%%%============================================================================= + +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec get_view_count(kz_term:ne_binary(), kz_term:ne_binary()) -> non_neg_integer(). +get_view_count(AccountDb, View) -> + get_view_count(AccountDb, View, 2). + +-spec get_view_count(kz_term:ne_binary(), kz_term:ne_binary(), integer()) -> non_neg_integer(). +get_view_count(AccountDb, _View, Retry) when Retry < 0 -> + io:format("[~s] failed to fetch view ~s count~n", [kzs_util:format_account_id(AccountDb), _View]), + 0; +get_view_count(AccountDb, View, Retry) -> + case kz_datamgr:get_results_count(AccountDb, View, [{'reduce', 'false'}]) of + {'ok', Total} -> Total; + {'error', 'not_found'} -> + _ = kapps_maintenance:refresh(AccountDb), + get_view_count(AccountDb, View, Retry-1); + {'error', _} -> + get_view_count(AccountDb, View, Retry-1) + end. + +%%------------------------------------------------------------------------------ +%% @doc +%% @end +%%------------------------------------------------------------------------------ +-spec maybe_save_doc(kz_doc:doc(), map()) -> map(). +maybe_save_doc(Doc, #{total := _Total, processed := Processed, updated := Updated, skip := Skip}=Map) -> + case kz_datamgr:save_doc(kz_doc:account_db(Doc), Doc) of + {'ok', _} -> + Map#{processed => Processed+1, updated => Updated+1, skip => Skip}; + {'error', _Reason} -> + io:format("[~s] failed to update ~p: ~p~n", [kz_doc:account_id(Doc), kz_doc:id(Doc), _Reason]), + Map#{processed => Processed+1, updated => Updated, skip => Skip} + end. From ebe60444f5829582c419726b968972cd92c6fbb7 Mon Sep 17 00:00:00 2001 From: John White Date: Thu, 30 Apr 2020 16:02:16 -0500 Subject: [PATCH 05/12] Add converter migration docs --- .../doc/ref/knm_converter_migrate_maintenance.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 core/kazoo_numbers/doc/ref/knm_converter_migrate_maintenance.md diff --git a/core/kazoo_numbers/doc/ref/knm_converter_migrate_maintenance.md b/core/kazoo_numbers/doc/ref/knm_converter_migrate_maintenance.md new file mode 100644 index 00000000000..87b72d4ff4c --- /dev/null +++ b/core/kazoo_numbers/doc/ref/knm_converter_migrate_maintenance.md @@ -0,0 +1,16 @@ +## SUP-able functions + +| Function | Arguments | Description | +| -------- | --------- | ----------- | +| `migrate/0` | | | +| `migrate_account/1` | `(Account)` | | +| `migrate_devices/1` | `(Account)` | | +| `migrate_devices/3` | `(Account,From,To)` | | +| `migrate_global_resources/0` | | | +| `migrate_global_resources/2` | `(From,To)` | | +| `migrate_invite_format/1` | `(Account)` | | +| `migrate_invite_format/3` | `(Account,From,To)` | | +| `migrate_local_resources/1` | `(Account)` | | +| `migrate_local_resources/3` | `(Account,From,To)` | | +| `migrate_trunkstore/1` | `(Account)` | | +| `migrate_trunkstore/3` | `(Account,From,To)` | | From a00518ef605c5f8e57a23818676a00c9c276238d Mon Sep 17 00:00:00 2001 From: John White Date: Thu, 30 Apr 2020 16:02:39 -0500 Subject: [PATCH 06/12] update swagger spec --- applications/crossbar/priv/api/swagger.json | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/applications/crossbar/priv/api/swagger.json b/applications/crossbar/priv/api/swagger.json index 4505f310f88..ce04364fa5f 100644 --- a/applications/crossbar/priv/api/swagger.json +++ b/applications/crossbar/priv/api/swagger.json @@ -5408,7 +5408,8 @@ "e164", "npan", "1npan", - "username" + "username", + "strip_plus" ], "type": "string" }, @@ -5858,6 +5859,7 @@ "1npan", "e164", "route", + "strip_plus", "contact" ], "type": "string" @@ -13948,6 +13950,7 @@ "npan", "1npan", "route", + "strip_plus", "loopback", "contact" ], @@ -26461,6 +26464,7 @@ "npan", "1npan", "route", + "strip_plus", "loopback", "contact" ], @@ -31499,7 +31503,8 @@ "username", "e164", "npan", - "1npan" + "1npan", + "strip_plus" ], "type": "string" }, @@ -37147,7 +37152,7 @@ "default": [ "regex" ], - "description": "suffix for the KNM module to use for E164, NPAN and 1NPAN normalization of numbers", + "description": "suffix for the KNM module to use for E164, NPAN, 1NPAN and strip_plus normalization of numbers", "items": { "type": "string" }, @@ -39587,6 +39592,7 @@ "e164", "npan", "1npan", + "strip_plus", "username" ], "type": "string" From 90bd65b3695b1a21ed03ded281779a46c99db9c9 Mon Sep 17 00:00:00 2001 From: John White Date: Thu, 30 Apr 2020 16:03:04 -0500 Subject: [PATCH 07/12] update OAS3 spec --- applications/crossbar/priv/oas3/oas3-schemas.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/applications/crossbar/priv/oas3/oas3-schemas.yml b/applications/crossbar/priv/oas3/oas3-schemas.yml index f00f71259d1..1b367fa5b14 100644 --- a/applications/crossbar/priv/oas3/oas3-schemas.yml +++ b/applications/crossbar/priv/oas3/oas3-schemas.yml @@ -4285,6 +4285,7 @@ - npan - 1npan - username + - strip_plus 'type': string 'ip': 'description': IP (sip) address for this device @@ -4651,6 +4652,7 @@ - 1npan - e164 - route + - strip_plus - contact 'type': string 'x-support_level': supported @@ -8104,6 +8106,7 @@ - e164 - npan - 1npan + - strip_plus 'type': string 'invite_parameters': 'additionalProperties': false @@ -12468,7 +12471,7 @@ 'default': - regex 'description': |- - suffix for the KNM module to use for E164, NPAN and 1NPAN normalization of numbers + suffix for the KNM module to use for E164, NPAN, 1NPAN and strip_plus normalization of numbers 'items': 'type': string 'type': array @@ -14452,6 +14455,7 @@ - e164 - npan - 1npan + - strip_plus - username 'type': string 'media_handling': From 3e77e03d72b3096f6b71ef3b4543deb3e834fa77 Mon Sep 17 00:00:00 2001 From: John White Date: Thu, 30 Apr 2020 16:48:44 -0500 Subject: [PATCH 08/12] fix formatting/whitespace issue --- .../knm_converter_migrate_maintenance.erl | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl b/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl index 5f307e6d859..84fdf93267c 100644 --- a/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl +++ b/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl @@ -7,16 +7,16 @@ %%% %%% @end %%%----------------------------------------------------------------------------- --module (knm_converter_migrate_maintenance). +-module(knm_converter_migrate_maintenance). --export ([migrate/0 - ,migrate_account/1 - ,migrate_invite_format/1, migrate_invite_format/3 - ,migrate_devices/1, migrate_devices/3 - ,migrate_global_resources/0, migrate_global_resources/2 - ,migrate_local_resources/1, migrate_local_resources/3 - ,migrate_trunkstore/1, migrate_trunkstore/3 - ]). +-export([migrate/0 + ,migrate_account/1 + ,migrate_invite_format/1, migrate_invite_format/3 + ,migrate_devices/1, migrate_devices/3 + ,migrate_global_resources/0, migrate_global_resources/2 + ,migrate_local_resources/1, migrate_local_resources/3 + ,migrate_trunkstore/1, migrate_trunkstore/3 + ]). -define(LEGACY_STRIP_PLUS, <<"e164_without_plus">>). -define(ONE_NPAN, <<"1npan">>). @@ -117,7 +117,7 @@ maybe_migrate_devices(AccountDb, From, To, #{total := Total, processed := _Proce Length = length(ViewResults), io:format("[~s] processing ~b devices~n", [AccountId, Length]), UpdateFun = fun(JObj, Map) -> - maybe_update_device(AccountDb, kz_json:get_ne_binary_value(<<"key">>, JObj), From, To, Map) + maybe_update_device(AccountDb, kz_json:get_ne_binary_value(<<"key">>, JObj), From, To, Map) end, ProcessMap = lists:foldl(UpdateFun, Stats, ViewResults), io:format("[~s] device migration finished, (~b/~b) devices has been updated~n" @@ -202,7 +202,7 @@ maybe_migrate_resources(AccountDb, From, To, #{total := Total, processed := _Pro Length = length(ViewResults), io:format("[~s] processing ~b resources~n", [AccountId, Length]), UpdateFun = fun(JObj, Map) -> - maybe_update_resource(AccountDb, kz_json:get_ne_binary_value(<<"key">>, JObj), From, To, Map) + maybe_update_resource(AccountDb, kz_json:get_ne_binary_value(<<"key">>, JObj), From, To, Map) end, ProcessMap = lists:foldl(UpdateFun, Stats, ViewResults), io:format("[~s] resource migration finished, (~b/~b) resources has been updated~n" @@ -220,7 +220,7 @@ maybe_migrate_resources(AccountDb, From, To, #{total := Total, processed := _Pro maybe_update_resource(AccountDb, ResourceId, From, To, #{total := _Total, processed := Processed, updated := _Updated, skip := Skip}=Map) -> {'ok', Doc} = kz_datamgr:open_doc(AccountDb, ResourceId), UpdateFun = fun(JObj, Acc) -> - maybe_update_gateways(JObj, From, To, Acc) + maybe_update_gateways(JObj, From, To, Acc) end, Gateways = kzd_resources:gateways(Doc), NewGateways = lists:foldl(UpdateFun, [], Gateways), @@ -281,9 +281,9 @@ maybe_migrate_trunkstore(AccountDb, From, To, #{total := Total, processed := _Pr Length = length(ViewResults), io:format("[~s] processing ~b trunks~n", [AccountId, Length]), UpdateFun = fun(JObj, Map) -> - maybe_update_trunk(AccountDb, kz_json:get_ne_binary_value(<<"id">>, JObj), From, To, Map) + maybe_update_trunk(AccountDb, kz_json:get_ne_binary_value(<<"id">>, JObj), From, To, Map) end, - ProcessMap = lists:foldl(UpdateFun, Stats, ViewResults), + ProcessMap = lists:foldl(UpdateFun, Stats, ViewResults), io:format("[~s] trunkstore migration finished, (~b/~b) trunks has been updated~n" ,[AccountId, maps:get('updated', ProcessMap), Total] ); @@ -299,7 +299,7 @@ maybe_migrate_trunkstore(AccountDb, From, To, #{total := Total, processed := _Pr maybe_update_trunk(AccountDb, TrunkId, From, To, #{total := _Total, processed := Processed, updated := _Updated, skip := Skip}=Map) -> {'ok', Doc} = kz_datamgr:open_doc(AccountDb, TrunkId), UpdateFun = fun(JObj, Acc) -> - maybe_update_servers(JObj, From, To, Acc) + maybe_update_servers(JObj, From, To, Acc) end, Servers = kzd_trunkstore:servers(Doc), NewServers = lists:foldl(UpdateFun, [], Servers), From 6f29d9b9d8d7be38dda497fc7ab9282f3a1877dc Mon Sep 17 00:00:00 2001 From: John White Date: Fri, 1 May 2020 09:05:20 -0500 Subject: [PATCH 09/12] remove debug artifact to appease The Great Dialyzer! --- .../src/converters/knm_converter_migrate_maintenance.erl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl b/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl index 84fdf93267c..005aaa2e00b 100644 --- a/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl +++ b/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl @@ -16,7 +16,7 @@ ,migrate_global_resources/0, migrate_global_resources/2 ,migrate_local_resources/1, migrate_local_resources/3 ,migrate_trunkstore/1, migrate_trunkstore/3 - ]). + ]). -define(LEGACY_STRIP_PLUS, <<"e164_without_plus">>). -define(ONE_NPAN, <<"1npan">>). @@ -251,9 +251,8 @@ migrate_trunkstore(Account) -> -spec migrate_trunkstore(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary()) -> 'ok'. migrate_trunkstore(Account, From, To) -> AccountDb = kzs_util:format_account_db(Account), - Total = get_view_count(AccountDb, <<"trunkstore/crossbar_listing">>, []), - migrate_trunkstore(AccountDb, From, To, Total), - 'ok'. + Total = get_view_count(AccountDb, <<"trunkstore/crossbar_listing">>), + migrate_trunkstore(AccountDb, From, To, Total). -spec migrate_trunkstore(kz_term:ne_binary(), kz_term:ne_binary(), kz_term:ne_binary(), non_neg_integer()) -> 'ok'. migrate_trunkstore(AccountDb, _From, _To, 0) -> From 6726bdf90b57e64f7f53adadc93a575f37f67962 Mon Sep 17 00:00:00 2001 From: John White Date: Fri, 1 May 2020 09:21:31 -0500 Subject: [PATCH 10/12] add missing doc for migration command --- .../doc/knm_converter_migrate_maintenance.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 core/kazoo_numbers/doc/knm_converter_migrate_maintenance.md diff --git a/core/kazoo_numbers/doc/knm_converter_migrate_maintenance.md b/core/kazoo_numbers/doc/knm_converter_migrate_maintenance.md new file mode 100644 index 00000000000..87b72d4ff4c --- /dev/null +++ b/core/kazoo_numbers/doc/knm_converter_migrate_maintenance.md @@ -0,0 +1,16 @@ +## SUP-able functions + +| Function | Arguments | Description | +| -------- | --------- | ----------- | +| `migrate/0` | | | +| `migrate_account/1` | `(Account)` | | +| `migrate_devices/1` | `(Account)` | | +| `migrate_devices/3` | `(Account,From,To)` | | +| `migrate_global_resources/0` | | | +| `migrate_global_resources/2` | `(From,To)` | | +| `migrate_invite_format/1` | `(Account)` | | +| `migrate_invite_format/3` | `(Account,From,To)` | | +| `migrate_local_resources/1` | `(Account)` | | +| `migrate_local_resources/3` | `(Account,From,To)` | | +| `migrate_trunkstore/1` | `(Account)` | | +| `migrate_trunkstore/3` | `(Account,From,To)` | | From 33c193ae23fc0dc886e8a67f50859203581dfe56 Mon Sep 17 00:00:00 2001 From: John White Date: Fri, 1 May 2020 09:24:49 -0500 Subject: [PATCH 11/12] make fmt --- core/kazoo_call/src/kapps_call_command.erl | 20 +++++++++---------- .../knm_converter_migrate_maintenance.erl | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core/kazoo_call/src/kapps_call_command.erl b/core/kazoo_call/src/kapps_call_command.erl index d92b694d1bc..bd1f64216cc 100644 --- a/core/kazoo_call/src/kapps_call_command.erl +++ b/core/kazoo_call/src/kapps_call_command.erl @@ -346,7 +346,7 @@ presence(State, PresenceId, CallId, 'undefined', 'undefined') -> ,{<<"To-Realm">>, Realm} ,{<<"State">>, State} ,{<<"Call-ID">>, CallId} - | kz_api:default_headers(?APP_NAME, ?APP_VERSION) + | kz_api:default_headers(?APP_NAME, ?APP_VERSION) ]), kapi_presence:publish_update(Command); presence(State, PresenceId, CallId, TargetURI, 'undefined') -> @@ -361,7 +361,7 @@ presence(State, PresenceId, CallId, TargetURI, 'undefined') -> ,{<<"To-Realm">>, Realm} ,{<<"State">>, State} ,{<<"Call-ID">>, CallId} - | kz_api:default_headers(?APP_NAME, ?APP_VERSION) + | kz_api:default_headers(?APP_NAME, ?APP_VERSION) ]), kapi_presence:publish_update(Command); presence(State, PresenceId, CallId, TargetURI, Call) -> @@ -378,7 +378,7 @@ presence(State, PresenceId, CallId, TargetURI, Call) -> ,{<<"To-Tag">>, kapps_call:to_tag(Call)} ,{<<"State">>, State} ,{<<"Call-ID">>, CallId} - | kz_api:default_headers(module_as_app(Call), ?APP_VERSION) + | kz_api:default_headers(module_as_app(Call), ?APP_VERSION) ]), kapi_presence:publish_update(Command). @@ -426,7 +426,7 @@ channel_status(Call) -> b_channel_status('undefined') -> {'error', 'no_channel_id'}; b_channel_status(<>) -> Command = [{<<"Call-ID">>, ChannelId} - | kz_api:default_headers(?APP_NAME, ?APP_VERSION) + | kz_api:default_headers(?APP_NAME, ?APP_VERSION) ], Resp = kz_amqp_worker:call_collect(Command ,fun kapi_call:publish_channel_status_req/1 @@ -506,7 +506,7 @@ audio_macro(Prompts, Call, GroupId) -> ,{<<"Msg-ID">>, NoopId} ,{<<"Call-ID">>, kapps_call:call_id(Call)} ]) - | Queue + | Queue ], Command = [{<<"Application-Name">>, <<"queue">>} ,{<<"Commands">>, Commands} @@ -956,7 +956,7 @@ receive_fax(ResourceFlag, ReceiveFlag, Call) -> receive_fax(ResourceFlag, ReceiveFlag, LocalFilename, Call) -> Commands = props:filter_undefined([{<<"Application-Name">>, <<"receive_fax">>} ,{<<"Fax-Local-Filename">>, LocalFilename} - | get_inbound_t38_settings(ResourceFlag, ReceiveFlag) + | get_inbound_t38_settings(ResourceFlag, ReceiveFlag) ]), send_command(Commands, Call). @@ -1373,7 +1373,7 @@ soft_hold_command(CallId, UnholdKey, AMOH, BMOH, InsertAt) -> ,{<<"Call-ID">>, CallId} ,{<<"Insert-At">>, InsertAt} ,{<<"Unhold-Key">>, UnholdKey} - | build_moh_keys(AMOH, BMOH) + | build_moh_keys(AMOH, BMOH) ]). -spec build_moh_keys(kz_term:api_binary(), kz_term:api_binary()) -> @@ -1836,7 +1836,7 @@ record_call(Media, Action, TimeLimit, Terminators, Call) -> ,{<<"Time-Limit">>, Limit} ,{<<"Terminators">>, Terminators} ,{<<"Insert-At">>, <<"now">>} - | Media + | Media ]), send_command(Command, Call). @@ -3399,7 +3399,7 @@ store_file(Filename, URLFun, Tries, Timeout, Call) -> API = fun() -> [{<<"Command">>, <<"send_http">>} ,{<<"Args">>, kz_json:from_list(store_file_args(Filename, URLFun))} ,{<<"FreeSWITCH-Node">>, kapps_call:switch_nodename(Call)} - | kz_api:default_headers(AppName, AppVersion) + | kz_api:default_headers(AppName, AppVersion) ] end, do_store_file(Tries, Timeout, API, Msg, Call). @@ -3563,7 +3563,7 @@ sound_touch_command(Options, Call) -> [{<<"Application-Name">>, <<"sound_touch">>} ,{<<"Insert-At">>, <<"now">>} ,{<<"Call-ID">>, kapps_call:call_id(Call)} - | Options + | Options ]). -spec start_sound_touch(kz_term:proplist(), kapps_call:call()) -> 'ok'. diff --git a/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl b/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl index 005aaa2e00b..da50cdd2b3c 100644 --- a/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl +++ b/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl @@ -16,7 +16,7 @@ ,migrate_global_resources/0, migrate_global_resources/2 ,migrate_local_resources/1, migrate_local_resources/3 ,migrate_trunkstore/1, migrate_trunkstore/3 - ]). + ]). -define(LEGACY_STRIP_PLUS, <<"e164_without_plus">>). -define(ONE_NPAN, <<"1npan">>). From 8a93a1054b94c71e4ae2de63422faf8e3aed7131 Mon Sep 17 00:00:00 2001 From: John White Date: Fri, 1 May 2020 09:37:52 -0500 Subject: [PATCH 12/12] - add doc to doc index - remove unused defines --- .../src/converters/knm_converter_migrate_maintenance.erl | 2 -- doc/mkdocs/mkdocs.yml | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl b/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl index da50cdd2b3c..f0bc14bbb97 100644 --- a/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl +++ b/core/kazoo_numbers/src/converters/knm_converter_migrate_maintenance.erl @@ -18,8 +18,6 @@ ,migrate_trunkstore/1, migrate_trunkstore/3 ]). --define(LEGACY_STRIP_PLUS, <<"e164_without_plus">>). --define(ONE_NPAN, <<"1npan">>). -define(NPAN, <<"npan">>). -define(STRIP_PLUS, <<"strip_plus">>). -define(DEFAULT_FROM, <<"npan">>). diff --git a/doc/mkdocs/mkdocs.yml b/doc/mkdocs/mkdocs.yml index b756c5ca0e5..57a7a5e1e61 100644 --- a/doc/mkdocs/mkdocs.yml +++ b/doc/mkdocs/mkdocs.yml @@ -441,6 +441,7 @@ nav: - 'core/kazoo_numbers/doc/knm_voxbone.md' - 'core/kazoo_numbers/doc/maintenance.md' - 'core/kazoo_numbers/doc/number_states.md' + - 'core/kazoo_numbers/doc/knm_converter_migrate_maintenance.md' - 'Kazoo CNAM': - 'core/kazoo_cnam/doc/cnam_maintenance.md' - 'Kazoo AMQP':