diff --git a/applications/crossbar/doc/devices.md b/applications/crossbar/doc/devices.md index aa0b0c5782f..e6920917aa0 100644 --- a/applications/crossbar/doc/devices.md +++ b/applications/crossbar/doc/devices.md @@ -70,16 +70,21 @@ Key | Description | Type | Default | Required | Support Level `sip.custom_sip_headers.out` | Custom SIP Headers to be applied to calls outbound from Kazoo to the endpoint | [#/definitions/custom_sip_headers](#custom_sip_headers) | | `false` | `sip.custom_sip_headers.^[a-zA-z0-9_\-]+$` | The SIP header to add | `string()` | | `false` | `sip.custom_sip_headers` | A property list of SIP headers | `object()` | | `false` | +`sip.custom_sip_interface` | If the bridge string should target a different SIP interface | `string()` | | `false` | `sip.expire_seconds` | The time, in seconds, sent to the provisioner for the registration period that the device should be configured with. | `integer()` | `300` | `false` | `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.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` | `sip.password` | SIP authentication password | `string(5..32)` | | `false` | `supported` +`sip.proxy` | Proxy IP address to use | `string()` | | `false` | `sip.realm` | The realm this device should use, overriding the account realm. Should rarely be necessary. | `string(4..253)` | | `false` | `sip.route` | The SIP URL used if the invite format is 'route' | `string()` | | `false` | `supported` +`sip.static_invite` | SIP To user | `string()` | | `false` | `sip.static_route` | Sends all inbound calls to this string (instead of dialed number or username) | `string()` | | `false` | +`sip.transport` | SIP Transport to use | `string()` | | `false` | `sip.username` | SIP authentication username | `string(2..32)` | | `false` | `supported` `sip` | SIP Parameters | `object()` | `{}` | `false` | `suppress_unregister_notifications` | When true disables deregister notifications | `boolean()` | `false` | `false` | diff --git a/applications/crossbar/doc/ref/devices.md b/applications/crossbar/doc/ref/devices.md index 532a3c07bb6..7269798f38c 100644 --- a/applications/crossbar/doc/ref/devices.md +++ b/applications/crossbar/doc/ref/devices.md @@ -67,16 +67,21 @@ Key | Description | Type | Default | Required | Support Level `sip.custom_sip_headers.out` | Custom SIP Headers to be applied to calls outbound from Kazoo to the endpoint | [#/definitions/custom_sip_headers](#custom_sip_headers) | | `false` | `sip.custom_sip_headers.^[a-zA-z0-9_\-]+$` | The SIP header to add | `string()` | | `false` | `sip.custom_sip_headers` | A property list of SIP headers | `object()` | | `false` | +`sip.custom_sip_interface` | If the bridge string should target a different SIP interface | `string()` | | `false` | `sip.expire_seconds` | The time, in seconds, sent to the provisioner for the registration period that the device should be configured with. | `integer()` | `300` | `false` | `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.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` | `sip.password` | SIP authentication password | `string(5..32)` | | `false` | `supported` +`sip.proxy` | Proxy IP address to use | `string()` | | `false` | `sip.realm` | The realm this device should use, overriding the account realm. Should rarely be necessary. | `string(4..253)` | | `false` | `sip.route` | The SIP URL used if the invite format is 'route' | `string()` | | `false` | `supported` +`sip.static_invite` | SIP To user | `string()` | | `false` | `sip.static_route` | Sends all inbound calls to this string (instead of dialed number or username) | `string()` | | `false` | +`sip.transport` | SIP Transport to use | `string()` | | `false` | `sip.username` | SIP authentication username | `string(2..32)` | | `false` | `supported` `sip` | SIP Parameters | `object()` | `{}` | `false` | `suppress_unregister_notifications` | When true disables deregister notifications | `boolean()` | `false` | `false` | diff --git a/applications/crossbar/doc/ref/resources.md b/applications/crossbar/doc/ref/resources.md index 452e53ce9c6..91fd861a816 100644 --- a/applications/crossbar/doc/ref/resources.md +++ b/applications/crossbar/doc/ref/resources.md @@ -10,6 +10,17 @@ Schema for resources Key | Description | Type | Default | Required | Support Level --- | ----------- | ---- | ------- | -------- | ------------- +`caller_id_options.type` | Caller ID type to choose | `string('internal' | 'external' | 'emergency')` | | `false` | +`caller_id_options` | Caller ID options | `object()` | | `false` | +`cid_rules.[]` | | `string()` | | `false` | +`cid_rules` | Regexps to match against caller ID | `array(string())` | | `false` | +`classifiers.emergency` | Determines if the resource represents emergency services | `boolean()` | `false` | `false` | +`classifiers.enabled` | Determines if the resource is currently enabled | `boolean()` | `true` | `false` | +`classifiers.prefix` | A string to prepend to the dialed number or capture group of the matching rule | `string(0..64)` | | `false` | +`classifiers.regex` | regexp to match against dialed number | `string()` | | `false` | +`classifiers.suffix` | A string to append to the dialed number or capture group of the matching rule | `string(0..64)` | | `false` | +`classifiers.weight_cost` | A value between 0 and 100 that determines the order of resources when multiple can be used | `integer()` | `50` | `false` | +`classifiers` | Resource classifiers to use as rules when matching against dialed numbers | `object()` | | `false` | `emergency` | Determines if the resource represents emergency services | `boolean()` | `false` | `false` | `enabled` | Determines if the resource is currently enabled | `boolean()` | `true` | `false` | `flags.[]` | | `string()` | | `false` | @@ -18,6 +29,7 @@ Key | Description | Type | Default | Required | Support Level `flat_rate_whitelist` | Regex for determining if the number is eligible for flat-rate trunking | `string()` | | `false` | `format_from_uri` | When set to true requests to this resource will have a reformatted SIP From Header | `boolean()` | | `false` | `formatters` | Schema for request formatters | `object()` | | `false` | +`from_account_realm` | When formatting SIP From on outbound requests, use the calling account's SIP realm | `boolean()` | `false` | `false` | `from_uri_realm` | When formatting SIP From on outbound requests this can be used to override the realm | `string()` | | `false` | `gateway_strategy` | The strategy of choosing gateways from list: sequential or random | `string('sequential' | 'random')` | | `false` | `gateways.[].bypass_media` | The resource gateway bypass media mode | `boolean()` | | `false` | diff --git a/applications/crossbar/doc/resources.md b/applications/crossbar/doc/resources.md index e88b3ffe051..c9dbc34cc92 100644 --- a/applications/crossbar/doc/resources.md +++ b/applications/crossbar/doc/resources.md @@ -26,6 +26,17 @@ Schema for resources Key | Description | Type | Default | Required | Support Level --- | ----------- | ---- | ------- | -------- | ------------- +`caller_id_options.type` | Caller ID type to choose | `string('internal' | 'external' | 'emergency')` | | `false` | +`caller_id_options` | Caller ID options | `object()` | | `false` | +`cid_rules.[]` | | `string()` | | `false` | +`cid_rules` | Regexps to match against caller ID | `array(string())` | | `false` | +`classifiers.emergency` | Determines if the resource represents emergency services | `boolean()` | `false` | `false` | +`classifiers.enabled` | Determines if the resource is currently enabled | `boolean()` | `true` | `false` | +`classifiers.prefix` | A string to prepend to the dialed number or capture group of the matching rule | `string(0..64)` | | `false` | +`classifiers.regex` | regexp to match against dialed number | `string()` | | `false` | +`classifiers.suffix` | A string to append to the dialed number or capture group of the matching rule | `string(0..64)` | | `false` | +`classifiers.weight_cost` | A value between 0 and 100 that determines the order of resources when multiple can be used | `integer()` | `50` | `false` | +`classifiers` | Resource classifiers to use as rules when matching against dialed numbers | `object()` | | `false` | `emergency` | Determines if the resource represents emergency services | `boolean()` | `false` | `false` | `enabled` | Determines if the resource is currently enabled | `boolean()` | `true` | `false` | `flags.[]` | | `string()` | | `false` | @@ -34,6 +45,7 @@ Key | Description | Type | Default | Required | Support Level `flat_rate_whitelist` | Regex for determining if the number is eligible for flat-rate trunking | `string()` | | `false` | `format_from_uri` | When set to true requests to this resource will have a reformatted SIP From Header | `boolean()` | | `false` | `formatters` | Schema for request formatters | `object()` | | `false` | +`from_account_realm` | When formatting SIP From on outbound requests, use the calling account's SIP realm | `boolean()` | `false` | `false` | `from_uri_realm` | When formatting SIP From on outbound requests this can be used to override the realm | `string()` | | `false` | `gateway_strategy` | The strategy of choosing gateways from list: sequential or random | `string('sequential' | 'random')` | | `false` | `gateways.[].bypass_media` | The resource gateway bypass media mode | `boolean()` | | `false` | @@ -145,7 +157,7 @@ The `INVITE` parameters object defines both static and dynamic parameters that s Static parameters are added 'as-is' and can be any format. However, they should follow the SIP standard for the header field format and should not include a semi-colon. -Dynamic parameters obtain the value from properties of the initiating call (requestor) if present, and are ignored if not. Dynamic parameters can be defined either as a string or an object. When defined as a string the property is extracted from the requestor and if found the resulting value used without modification as an `INVITE` parameter. When defined as an object both a tag as well as a key property must be defined. The key property is used to extract the value from the requestor and the tag is appended as the `INVITE` parameter name. By default the `INVITE` parameter name and value are separated by an equals sign but this can be overridden by providing a separator property. +Dynamic parameters obtain the value from properties of the initiating call (requester) if present, and are ignored if not. Dynamic parameters can be defined either as a string or an object. When defined as a string the property is extracted from the requester and if found the resulting value used without modification as an `INVITE` parameter. When defined as an object both a tag as well as a key property must be defined. The key property is used to extract the value from the requester and the tag is appended as the `INVITE` parameter name. By default the `INVITE` parameter name and value are separated by an equals sign but this can be overridden by providing a separator property. For example, if a resource gateway contains the following object: @@ -170,6 +182,13 @@ and assuming the requesting call has pass-through (with value `pass-through=0288 INVITE sip:+14158867900@10.26.0.88;npid;id=XXXX;pass-through=0288 SIP/2.0 ``` +## Formatting the From + +Some upstream carriers require the From address' realm to be formatted. There are a couple toggles you have to control this realm. First, you will need to configure `"format_from_uri":true` to enable this formatting functionality. Then you have 3 options, evaluated in this order: + +1. Set `"from_uri_realm":"{CUSTOM_REALM}"` where `{CUSTOM_REALM}` is the static realm you'd like on the From +2. Set `"from_account_realm":true` to use the calling account's realm +3. Set `"realm":"{CUSTOM_REALM}"` on a per-gateway basis (not on the top-level resource) ## Fetch diff --git a/applications/crossbar/priv/api/swagger.json b/applications/crossbar/priv/api/swagger.json index 24df0f6fe6f..b8d8e722d78 100644 --- a/applications/crossbar/priv/api/swagger.json +++ b/applications/crossbar/priv/api/swagger.json @@ -5790,11 +5790,19 @@ "description": "A property list of SIP headers", "type": "object" }, + "custom_sip_interface": { + "description": "If the bridge string should target a different SIP interface", + "type": "string" + }, "expire_seconds": { "default": 300, "description": "The time, in seconds, sent to the provisioner for the registration period that the device should be configured with.", "type": "integer" }, + "forward": { + "description": "Forward IP to use", + "type": "string" + }, "ignore_completed_elsewhere": { "description": "When set to false the phone should not consider ring group calls answered elsewhere as missed", "type": "boolean" @@ -5835,6 +5843,10 @@ "minLength": 5, "type": "string" }, + "proxy": { + "description": "Proxy IP address to use", + "type": "string" + }, "realm": { "description": "The realm this device should use, overriding the account realm. Should rarely be necessary.", "maxLength": 253, @@ -5846,10 +5858,18 @@ "description": "The SIP URL used if the invite format is 'route'", "type": "string" }, + "static_invite": { + "description": "SIP To user", + "type": "string" + }, "static_route": { "description": "Sends all inbound calls to this string (instead of dialed number or username)", "type": "string" }, + "transport": { + "description": "SIP Transport to use", + "type": "string" + }, "username": { "description": "SIP authentication username", "maxLength": 32, @@ -6895,12 +6915,12 @@ }, "Presence-State": { "enum": [ - "trying", - "online", - "offline", - "early", "confirmed", - "terminated" + "early", + "offline", + "online", + "terminated", + "trying" ], "type": "string" }, @@ -6943,12 +6963,12 @@ }, "Presence-State": { "enum": [ - "offline", - "online", - "trying", "confirmed", "early", - "terminated" + "offline", + "online", + "terminated", + "trying" ], "type": "string" }, @@ -6991,12 +7011,12 @@ }, "Presence-State": { "enum": [ - "offline", - "online", - "trying", "confirmed", "early", - "terminated" + "offline", + "online", + "terminated", + "trying" ], "type": "string" }, @@ -7067,12 +7087,12 @@ }, "Presence-State": { "enum": [ - "offline", - "online", - "trying", "confirmed", "early", - "terminated" + "offline", + "online", + "terminated", + "trying" ], "type": "string" }, @@ -7115,12 +7135,12 @@ }, "Presence-State": { "enum": [ - "offline", - "online", - "trying", "confirmed", "early", - "terminated" + "offline", + "online", + "terminated", + "trying" ], "type": "string" }, @@ -7163,12 +7183,12 @@ }, "Presence-State": { "enum": [ - "trying", - "online", - "offline", - "early", "confirmed", - "terminated" + "early", + "offline", + "online", + "terminated", + "trying" ], "type": "string" }, @@ -7211,12 +7231,12 @@ }, "Presence-State": { "enum": [ - "trying", - "online", - "offline", - "early", "confirmed", - "terminated" + "early", + "offline", + "online", + "terminated", + "trying" ], "type": "string" }, @@ -31246,6 +31266,66 @@ "resources": { "description": "Schema for resources", "properties": { + "caller_id_options": { + "description": "Caller ID options", + "properties": { + "type": { + "description": "Caller ID type to choose", + "enum": [ + "internal", + "external", + "emergency" + ], + "type": "string" + } + }, + "type": "object" + }, + "cid_rules": { + "description": "Regexps to match against caller ID", + "items": { + "description": "Regexp to match against caller ID", + "type": "string" + }, + "type": "array" + }, + "classifiers": { + "description": "Resource classifiers to use as rules when matching against dialed numbers", + "properties": { + "emergency": { + "default": false, + "description": "Determines if the resource represents emergency services", + "type": "boolean" + }, + "enabled": { + "default": true, + "description": "Determines if the resource is currently enabled", + "type": "boolean" + }, + "prefix": { + "description": "A string to prepend to the dialed number or capture group of the matching rule", + "maxLength": 64, + "type": "string" + }, + "regex": { + "description": "regexp to match against dialed number", + "type": "string" + }, + "suffix": { + "description": "A string to append to the dialed number or capture group of the matching rule", + "maxLength": 64, + "type": "string" + }, + "weight_cost": { + "default": 50, + "description": "A value between 0 and 100 that determines the order of resources when multiple can be used", + "maximum": 100, + "minimum": 0, + "type": "integer" + } + }, + "type": "object" + }, "emergency": { "default": false, "description": "Determines if the resource represents emergency services", @@ -31280,6 +31360,11 @@ "$ref": "#/definitions/formatters", "type": "object" }, + "from_account_realm": { + "default": false, + "description": "When formatting SIP From on outbound requests, use the calling account's SIP realm", + "type": "boolean" + }, "from_uri_realm": { "description": "When formatting SIP From on outbound requests this can be used to override the realm", "type": "string" diff --git a/applications/crossbar/priv/couchdb/schemas/devices.json b/applications/crossbar/priv/couchdb/schemas/devices.json index 06701ad73a2..a416191729d 100644 --- a/applications/crossbar/priv/couchdb/schemas/devices.json +++ b/applications/crossbar/priv/couchdb/schemas/devices.json @@ -346,12 +346,20 @@ "description": "A property list of SIP headers", "type": "object" }, + "custom_sip_interface": { + "description": "If the bridge string should target a different SIP interface", + "type": "string" + }, "expire_seconds": { "default": 300, "description": "The time, in seconds, sent to the provisioner for the registration period that the device should be configured with.", "support_level": "supported", "type": "integer" }, + "forward": { + "description": "Forward IP to use", + "type": "string" + }, "ignore_completed_elsewhere": { "description": "When set to false the phone should not consider ring group calls answered elsewhere as missed", "type": "boolean" @@ -396,6 +404,10 @@ "support_level": "supported", "type": "string" }, + "proxy": { + "description": "Proxy IP address to use", + "type": "string" + }, "realm": { "description": "The realm this device should use, overriding the account realm. Should rarely be necessary.", "maxLength": 253, @@ -408,10 +420,18 @@ "support_level": "supported", "type": "string" }, + "static_invite": { + "description": "SIP To user", + "type": "string" + }, "static_route": { "description": "Sends all inbound calls to this string (instead of dialed number or username)", "type": "string" }, + "transport": { + "description": "SIP Transport to use", + "type": "string" + }, "username": { "description": "SIP authentication username", "maxLength": 32, diff --git a/applications/crossbar/priv/couchdb/schemas/kapi.acdc_agent.end_wrapup.json b/applications/crossbar/priv/couchdb/schemas/kapi.acdc_agent.end_wrapup.json index 928bc356f82..bf043fbf054 100644 --- a/applications/crossbar/priv/couchdb/schemas/kapi.acdc_agent.end_wrapup.json +++ b/applications/crossbar/priv/couchdb/schemas/kapi.acdc_agent.end_wrapup.json @@ -26,12 +26,12 @@ }, "Presence-State": { "enum": [ - "trying", - "online", - "offline", - "early", "confirmed", - "terminated" + "early", + "offline", + "online", + "terminated", + "trying" ], "type": "string" }, diff --git a/applications/crossbar/priv/couchdb/schemas/kapi.acdc_agent.pause.json b/applications/crossbar/priv/couchdb/schemas/kapi.acdc_agent.pause.json index b9afdc440e3..15e2f37a7c8 100644 --- a/applications/crossbar/priv/couchdb/schemas/kapi.acdc_agent.pause.json +++ b/applications/crossbar/priv/couchdb/schemas/kapi.acdc_agent.pause.json @@ -26,12 +26,12 @@ }, "Presence-State": { "enum": [ - "trying", - "online", - "offline", - "early", "confirmed", - "terminated" + "early", + "offline", + "online", + "terminated", + "trying" ], "type": "string" }, diff --git a/applications/crossbar/priv/couchdb/schemas/kapi.acdc_agent.resume.json b/applications/crossbar/priv/couchdb/schemas/kapi.acdc_agent.resume.json index d39014d8fc2..28a7dd99286 100644 --- a/applications/crossbar/priv/couchdb/schemas/kapi.acdc_agent.resume.json +++ b/applications/crossbar/priv/couchdb/schemas/kapi.acdc_agent.resume.json @@ -26,12 +26,12 @@ }, "Presence-State": { "enum": [ - "trying", - "online", - "offline", - "early", "confirmed", - "terminated" + "early", + "offline", + "online", + "terminated", + "trying" ], "type": "string" }, diff --git a/applications/crossbar/priv/couchdb/schemas/resources.json b/applications/crossbar/priv/couchdb/schemas/resources.json index 98b5039d2ec..a8cc7a1dfb1 100644 --- a/applications/crossbar/priv/couchdb/schemas/resources.json +++ b/applications/crossbar/priv/couchdb/schemas/resources.json @@ -3,6 +3,66 @@ "_id": "resources", "description": "Schema for resources", "properties": { + "caller_id_options": { + "description": "Caller ID options", + "properties": { + "type": { + "description": "Caller ID type to choose", + "enum": [ + "internal", + "external", + "emergency" + ], + "type": "string" + } + }, + "type": "object" + }, + "cid_rules": { + "description": "Regexps to match against caller ID", + "items": { + "description": "Regexp to match against caller ID", + "type": "string" + }, + "type": "array" + }, + "classifiers": { + "description": "Resource classifiers to use as rules when matching against dialed numbers", + "properties": { + "emergency": { + "default": false, + "description": "Determines if the resource represents emergency services", + "type": "boolean" + }, + "enabled": { + "default": true, + "description": "Determines if the resource is currently enabled", + "type": "boolean" + }, + "prefix": { + "description": "A string to prepend to the dialed number or capture group of the matching rule", + "maxLength": 64, + "type": "string" + }, + "regex": { + "description": "regexp to match against dialed number", + "type": "string" + }, + "suffix": { + "description": "A string to append to the dialed number or capture group of the matching rule", + "maxLength": 64, + "type": "string" + }, + "weight_cost": { + "default": 50, + "description": "A value between 0 and 100 that determines the order of resources when multiple can be used", + "maximum": 100, + "minimum": 0, + "type": "integer" + } + }, + "type": "object" + }, "emergency": { "default": false, "description": "Determines if the resource represents emergency services", @@ -37,6 +97,11 @@ "$ref": "formatters", "type": "object" }, + "from_account_realm": { + "default": false, + "description": "When formatting SIP From on outbound requests, use the calling account's SIP realm", + "type": "boolean" + }, "from_uri_realm": { "description": "When formatting SIP From on outbound requests this can be used to override the realm", "type": "string" diff --git a/applications/crossbar/priv/oas3/oas3-schemas.yml b/applications/crossbar/priv/oas3/oas3-schemas.yml index 33f1fb6f0e6..a8bfd68d7bd 100644 --- a/applications/crossbar/priv/oas3/oas3-schemas.yml +++ b/applications/crossbar/priv/oas3/oas3-schemas.yml @@ -4591,12 +4591,18 @@ Custom SIP Headers to be applied to calls outbound from Kazoo to the endpoint 'description': A property list of SIP headers 'type': object + 'custom_sip_interface': + 'description': If the bridge string should target a different SIP interface + 'type': string 'expire_seconds': 'default': 300 'description': |- The time, in seconds, sent to the provisioner for the registration period that the device should be configured with. 'type': integer 'x-support_level': supported + 'forward': + 'description': Forward IP to use + 'type': string 'ignore_completed_elsewhere': 'description': |- When set to false the phone should not consider ring group calls answered elsewhere as missed @@ -4635,6 +4641,9 @@ 'minLength': 5 'type': string 'x-support_level': supported + 'proxy': + 'description': Proxy IP address to use + 'type': string 'realm': 'description': |- The realm this device should use, overriding the account realm. Should rarely be necessary. @@ -4646,10 +4655,16 @@ 'description': The SIP URL used if the invite format is 'route' 'type': string 'x-support_level': supported + 'static_invite': + 'description': SIP To user + 'type': string 'static_route': 'description': |- Sends all inbound calls to this string (instead of dialed number or username) 'type': string + 'transport': + 'description': SIP Transport to use + 'type': string 'username': 'description': SIP authentication username 'maxLength': 32 @@ -7861,6 +7876,56 @@ 'resources': 'description': Schema for resources 'properties': + 'caller_id_options': + 'description': Caller ID options + 'properties': + 'type': + 'description': Caller ID type to choose + 'enum': + - internal + - external + - emergency + 'type': string + 'type': object + 'cid_rules': + 'description': Regexps to match against caller ID + 'items': + 'description': Regexp to match against caller ID + 'type': string + 'type': array + 'classifiers': + 'description': |- + Resource classifiers to use as rules when matching against dialed numbers + 'properties': + 'emergency': + 'default': false + 'description': Determines if the resource represents emergency services + 'type': boolean + 'enabled': + 'default': true + 'description': Determines if the resource is currently enabled + 'type': boolean + 'prefix': + 'description': |- + A string to prepend to the dialed number or capture group of the matching rule + 'maxLength': 64 + 'type': string + 'regex': + 'description': regexp to match against dialed number + 'type': string + 'suffix': + 'description': |- + A string to append to the dialed number or capture group of the matching rule + 'maxLength': 64 + 'type': string + 'weight_cost': + 'default': 50 + 'description': |- + A value between 0 and 100 that determines the order of resources when multiple can be used + 'maximum': 100 + 'minimum': 0 + 'type': integer + 'type': object 'emergency': 'default': false 'description': Determines if the resource represents emergency services @@ -7890,6 +7955,11 @@ 'formatters': '$ref': '#/formatters' 'type': object + 'from_account_realm': + 'default': false + 'description': |- + When formatting SIP From on outbound requests, use the calling account's SIP realm + 'type': boolean 'from_uri_realm': 'description': |- When formatting SIP From on outbound requests this can be used to override the realm diff --git a/applications/crossbar/src/modules/cb_resources.erl b/applications/crossbar/src/modules/cb_resources.erl index 33690b30891..fb47658778a 100644 --- a/applications/crossbar/src/modules/cb_resources.erl +++ b/applications/crossbar/src/modules/cb_resources.erl @@ -640,16 +640,16 @@ validate_gateway_ips([{Idx, InboundIP, ServerIP}|IPs], SIPAuth, ACLs, ResourceId %% @doc %% @end %%------------------------------------------------------------------------------ --spec aggregate_resource(kz_json:object()) -> 'ok'. -aggregate_resource(Resource) -> +-spec aggregate_resource(kzd_resources:doc()) -> 'ok'. +aggregate_resource(ResourceJObj) -> lager:debug("adding resource to the sip auth aggregate"), - Doc = kz_doc:delete_revision(Resource), + Doc = kz_doc:delete_revision(ResourceJObj), Update = kz_json:to_proplist(kz_json:flatten(Doc)), UpdateOptions = [{'update', Update} ,{'create', []} ,{'ensure_saved', 'true'} ], - {'ok', _} = kz_datamgr:update_doc(?KZ_SIP_DB, kz_doc:id(Resource), UpdateOptions), + {'ok', _} = kz_datamgr:update_doc(?KZ_SIP_DB, kz_doc:id(ResourceJObj), UpdateOptions), 'ok'. -spec remove_aggregate(kz_term:ne_binary()) -> boolean(). @@ -740,37 +740,31 @@ validate_ip(IP, SIPAuth, ACLs, ResourceId) -> %% @doc %% @end %%------------------------------------------------------------------------------ --spec maybe_aggregate_resources(kz_json:objects()) -> 'ok'. +-spec maybe_aggregate_resources(kzd_resources:docs()) -> 'ok'. maybe_aggregate_resources([]) -> 'ok'; -maybe_aggregate_resources([Resource|Resources]) -> +maybe_aggregate_resources([ResourceJObj|ResourceJObjs]) -> case lists:any(fun(Gateway) -> kz_json:is_true(<<"register">>, Gateway) andalso (not kz_json:is_false(<<"enabled">>, Gateway)) end - ,kz_json:get_list_value(<<"gateways">>, Resource, []) + ,kzd_resources:gateways(ResourceJObj, []) ) of 'true' -> - aggregate_resource(Resource), + aggregate_resource(ResourceJObj), _ = kapi_switch:publish_reload_gateways(), _ = kapi_switch:publish_reload_acls(), - maybe_aggregate_resources(Resources); + maybe_aggregate_resources(ResourceJObjs); 'false' -> - _ = maybe_remove_aggregates([Resource]), - maybe_aggregate_resources(Resources) + _ = maybe_remove_aggregates([ResourceJObj]), + maybe_aggregate_resources(ResourceJObjs) end. %%------------------------------------------------------------------------------ %% @doc %% @end %%------------------------------------------------------------------------------ --spec maybe_remove_aggregates(kz_json:objects()) -> 'ok'. +-spec maybe_remove_aggregates(kzd_resources:docs()) -> 'ok'. maybe_remove_aggregates([]) -> 'ok'; -maybe_remove_aggregates([Resource|Resources]) -> - case kz_datamgr:del_doc(?KZ_SIP_DB, kz_doc:id(Resource)) of - {'ok', _JObj} -> - _ = kapi_switch:publish_reload_gateways(), - _ = kapi_switch:publish_reload_acls(), - maybe_remove_aggregates(Resources); - {'error', 'not_found'} -> - maybe_remove_aggregates(Resources) - end. +maybe_remove_aggregates([ResourceJObj|ResourceJObjs]) -> + _ = remove_aggregate(kz_doc:id(ResourceJObj)), + maybe_remove_aggregates(ResourceJObjs). diff --git a/applications/stepswitch/src/stepswitch_resources.erl b/applications/stepswitch/src/stepswitch_resources.erl index fd7905b2d7e..b01c48a1845 100644 --- a/applications/stepswitch/src/stepswitch_resources.erl +++ b/applications/stepswitch/src/stepswitch_resources.erl @@ -149,7 +149,7 @@ ,fax_option :: kz_term:ne_binary() | boolean() ,codecs = [] :: kz_term:ne_binaries() ,bypass_media = 'false' :: boolean() - ,formatters :: kz_term:api_objects() + ,formatters :: kz_term:api_object() ,proxies = [] :: kz_term:proplist() ,selector_marks = [] :: [tuple()] ,privacy_method = 'undefined' :: kz_term:api_binary() @@ -913,7 +913,7 @@ fetch_global_resources() -> []; {'ok', JObjs} -> CacheProps = [{'origin', [{'db', ?KZ_OFFNET_DB, <<"resource">>}]}], - Docs = [kz_json:get_value(<<"doc">>, JObj) || JObj <- JObjs], + Docs = [kz_json:get_json_value(<<"doc">>, JObj) || JObj <- JObjs], Resources = resources_from_jobjs(Docs), kz_cache:store_local(?CACHE_NAME, 'global_resources', Resources, CacheProps), Resources @@ -979,21 +979,21 @@ build_account_dedicated_proxy(Proxy) -> %% @end %%------------------------------------------------------------------------------ --spec resources_from_jobjs(kz_json:objects()) -> resources(). +-spec resources_from_jobjs(kzd_resources:docs()) -> resources(). resources_from_jobjs(JObjs) -> resources_from_jobjs(JObjs, []). --spec resources_from_jobjs(kz_json:objects(), resources()) -> resources(). +-spec resources_from_jobjs(kzd_resources:docs(), resources()) -> resources(). resources_from_jobjs([], Resources) -> Resources; resources_from_jobjs([JObj|JObjs], Resources) -> - case kz_json:is_true(<<"enabled">>, JObj, 'true') of + case kzd_resources:enabled(JObj) of 'false' -> resources_from_jobjs(JObjs, Resources); 'true' -> resources_from_jobjs(JObjs, create_resource(JObj, Resources)) end. --spec create_resource(kz_json:object(), resources()) -> resources(). +-spec create_resource(kzd_resources:doc(), resources()) -> resources(). create_resource(JObj, Resources) -> - case kz_json:get_value(<<"classifiers">>, JObj) of + case kzd_resources:classifiers(JObj) of 'undefined' -> [resource_from_jobj(JObj) | Resources]; ResourceClassifiers -> AvailableClassifiers = kz_json:to_proplist(knm_converters:available_classifiers()), @@ -1004,36 +1004,36 @@ create_resource(JObj, Resources) -> ) end. --spec create_resource(kz_term:proplist(), kz_term:proplist(), kz_json:object(), resources()) -> resources(). -create_resource([], _ConfigClassifiers, _Resource, Resources) -> Resources; -create_resource([{Classifier, ClassifierJObj}|Classifiers], ConfigClassifiers, Resource, Resources) -> +-spec create_resource(kz_term:proplist(), kz_term:proplist(), kzd_resources:doc(), resources()) -> resources(). +create_resource([], _ConfigClassifiers, _ResourceJObj, Resources) -> Resources; +create_resource([{Classifier, ClassifierJObj}|Classifiers], ConfigClassifiers, ResourceJObj, Resources) -> case props:get_value(Classifier, ConfigClassifiers) of 'undefined' -> - create_resource(Classifiers, ConfigClassifiers, Resource, Resources); + create_resource(Classifiers, ConfigClassifiers, ResourceJObj, Resources); ConfigClassifier -> JObj = - create_classifier_resource(Resource + create_classifier_resource(ResourceJObj ,ClassifierJObj ,Classifier ,ConfigClassifier ), create_resource(Classifiers ,ConfigClassifiers - ,Resource + ,ResourceJObj ,[resource_from_jobj(JObj) | Resources ] ) end. --spec create_classifier_resource(kz_json:object(), kz_json:object(), kz_term:ne_binary(), kz_term:proplist()) -> kz_json:object(). -create_classifier_resource(Resource, ClassifierJObj, Classifier, ConfigClassifier) -> +-spec create_classifier_resource(kzd_resources:doc(), kz_json:object(), kz_term:ne_binary(), kz_term:proplist()) -> kz_json:object(). +create_classifier_resource(ResourceJObj, ClassifierJObj, Classifier, ConfigClassifier) -> DefaultRegex = kz_json:get_value(<<"regex">>, ConfigClassifier), DefaultEmergency = kz_json:is_true(<<"emergency">>, ConfigClassifier, 'undefined'), Props = props:filter_undefined( - [{<<"_id">>, <<(kz_json:get_value(<<"_id">>, Resource))/binary, "-", Classifier/binary>>} - ,{<<"name">>, <<(kz_json:get_value(<<"name">>, Resource))/binary, " - ", Classifier/binary>>} + [{<<"_id">>, <<(kz_doc:id(ResourceJObj))/binary, "-", Classifier/binary>>} + ,{<<"name">>, <<(kzd_resources:name(ResourceJObj))/binary, " - ", Classifier/binary>>} ,{<<"rules">>, [kz_json:get_value(<<"regex">>, ClassifierJObj, DefaultRegex)]} ,{<<"weight_cost">>, kz_json:get_value(<<"weight_cost">>, ClassifierJObj)} ,{<<"emergency">>, classifier_is_emergency(ClassifierJObj, Classifier, DefaultEmergency)} @@ -1041,10 +1041,10 @@ create_classifier_resource(Resource, ClassifierJObj, Classifier, ConfigClassifie ,{<<"classifier_enable">>, kz_json:is_true(<<"enabled">>, ClassifierJObj, 'true')} ] ), - create_classifier_gateways(kz_json:set_values(Props, Resource), ClassifierJObj). + create_classifier_gateways(kz_json:set_values(Props, ResourceJObj), ClassifierJObj). --spec create_classifier_gateways(kz_json:object(), kz_json:object()) -> kz_json:object(). -create_classifier_gateways(Resource, ClassifierJObj) -> +-spec create_classifier_gateways(kzd_resources:doc(), kz_json:object()) -> kz_json:object(). +create_classifier_gateways(ResourceJObj, ClassifierJObj) -> Props = props:filter_undefined( [{<<"suffix">>, kz_json:get_value(<<"suffix">>, ClassifierJObj)} @@ -1053,9 +1053,9 @@ create_classifier_gateways(Resource, ClassifierJObj) -> ), Gateways = [kz_json:set_values(Props, Gateway) - || Gateway <- kz_json:get_value(<<"gateways">>, Resource, []) + || Gateway <- kzd_resources:gateways(ResourceJObj, []) ], - kz_json:set_value(<<"gateways">>, Gateways, Resource). + kzd_resources:set_gateways(ResourceJObj, Gateways). -spec classifier_is_emergency(kz_json:object(), kz_term:ne_binary(), boolean() | 'undefined') -> boolean(). classifier_is_emergency(ClassifierJObj, <<"emergency">>, _DefaultEmergency) -> @@ -1070,21 +1070,21 @@ classifier_is_emergency(ClassifierJObj, _Classifier, DefaultEmergency) -> -type rule() :: re:mp(). -type rules() :: [rule()]. --spec resource_from_jobj(kz_json:object()) -> resource(). +-spec resource_from_jobj(kzd_resources:doc()) -> resource(). resource_from_jobj(JObj) -> Resource = #resrc{id=kz_doc:id(JObj) ,rev=kz_doc:revision(JObj) - ,name=kz_json:get_value(<<"name">>, JObj) - ,flags=kz_json:get_value(<<"flags">>, JObj, []) - ,require_flags=kz_json:is_true(<<"require_flags">>, JObj) - ,ignore_flags=kz_json:is_true(<<"ignore_flags">>, JObj) - ,format_from_uri=kz_json:is_true(<<"format_from_uri">>, JObj) - ,from_uri_realm=kz_json:get_ne_value(<<"from_uri_realm">>, JObj) - ,from_account_realm=kz_json:is_true(<<"from_account_realm">>, JObj) - ,fax_option=kz_json:is_true([<<"media">>, <<"fax_option">>], JObj) - ,raw_rules=kz_json:get_value(<<"rules">>, JObj, []) + ,name=kzd_resources:name(JObj) + ,flags=kzd_resources:flags(JObj, []) + ,require_flags=kzd_resources:require_flags(JObj, 'false') + ,ignore_flags=kzd_resources:ignore_flags(JObj, 'false') + ,format_from_uri=kzd_resources:format_from_uri(JObj, 'false') + ,from_uri_realm=kzd_resources:from_uri_realm(JObj) + ,from_account_realm=kzd_resources:from_account_realm(JObj) + ,fax_option=kzd_resources:media_fax_option(JObj) + ,raw_rules=kzd_resources:rules(JObj, []) ,rules=resource_rules(JObj) - ,cid_raw_rules=kz_json:get_value(<<"cid_rules">>, JObj, []) + ,cid_raw_rules=kzd_resources:cid_rules(JObj, []) ,cid_rules=resource_cid_rules(JObj) ,weight=resource_weight(JObj) ,grace_period=resource_grace_period(JObj) @@ -1099,39 +1099,38 @@ resource_from_jobj(JObj) -> ,privacy_hide_number=kz_privacy:should_hide_number(JObj) ,classifier=kz_json:get_ne_value(<<"classifier">>, JObj) ,classifier_enable=kz_json:is_true(<<"classifier_enable">>, JObj, 'true') - ,gateway_strategy=kz_json:get_atom_value(<<"gateway_strategy">>, JObj, 'sequential') + ,gateway_strategy=kz_term:to_atom(kzd_resources:gateway_strategy(JObj, <<"sequential">>), 'true') }, - Gateways = gateways_from_jobjs(kz_json:get_value(<<"gateways">>, JObj, []) - ,Resource - ), + Gateways = gateways_from_jobjs(kzd_resources:gateways(JObj, []), Resource), Resource#resrc{gateways=Gateways}. --spec resource_bypass_media(kz_json:object()) -> boolean(). +-spec resource_bypass_media(kzd_resources:doc()) -> boolean(). resource_bypass_media(JObj) -> Default = kapps_config:get_is_true(?SS_CONFIG_CAT, <<"default_bypass_media">>, 'false'), - kz_json:is_true([<<"media">>, <<"bypass_media">>], JObj, Default). + kzd_resources:media_bypass_media(JObj, Default). --spec resource_formatters(kz_json:object()) -> kz_term:api_objects(). +-spec resource_formatters(kzd_resources:doc()) -> kz_term:api_object(). resource_formatters(JObj) -> Default = kapps_config:get(?SS_CONFIG_CAT, <<"default_formatters">>), - kz_json:get_value(<<"formatters">>, JObj, Default). + kzd_resources:formatters(JObj, Default). --spec resource_codecs(kz_json:object()) -> kz_term:ne_binaries(). +-spec resource_codecs(kzd_resources:doc()) -> kz_term:ne_binaries(). resource_codecs(JObj) -> DefaultAudio = kapps_config:get_ne_binaries(?SS_CONFIG_CAT, <<"default_audio_codecs">>, []), DefaultVideo = kapps_config:get_ne_binaries(?SS_CONFIG_CAT, <<"default_video_codecs">>, []), - case kz_json:get_value([<<"media">>, <<"audio">>, <<"codecs">>], JObj, DefaultAudio) - ++ kz_json:get_value([<<"media">>, <<"video">>, <<"codecs">>], JObj, DefaultVideo) + case kzd_resources:media_audio_codecs(JObj, DefaultAudio) + ++ kzd_resources:media_video_codecs(JObj, DefaultVideo) of [] -> kapps_config:get_ne_binaries(?SS_CONFIG_CAT, <<"default_codecs">>, []); Codecs -> Codecs end. --spec resource_rules(kz_json:object()) -> rules(). +-spec resource_rules(kzd_resources:doc()) -> rules(). resource_rules(JObj) -> - Rules = kz_json:get_value(<<"rules">>, JObj, []), + Rules = kzd_resources:rules(JObj, []), lager:info("compiling resource rules for ~s / ~s: ~p" - ,[kz_doc:account_db(JObj, <<"offnet">>), kz_doc:id(JObj), Rules]), + ,[kz_doc:account_db(JObj, <<"offnet">>), kz_doc:id(JObj), Rules] + ), resource_rules(Rules, []). -spec resource_rules(kz_term:ne_binaries(), rules()) -> rules(). @@ -1145,31 +1144,32 @@ resource_rules([Rule|Rules], CompiledRules) -> resource_rules(Rules, CompiledRules) end. --spec resource_cid_rules(kz_json:object()) -> rules(). -resource_cid_rules(JObj) -> +-spec resource_cid_rules(kzd_resources:doc()) -> rules(). +resource_cid_rules(ResourceJObj) -> lager:info("compiling caller id rules for ~s / ~s" - ,[kz_doc:account_db(JObj, <<"offnet">>), kz_doc:id(JObj)]), - Rules = kz_json:get_value(<<"cid_rules">>, JObj, []), + ,[kz_doc:account_db(ResourceJObj, <<"offnet">>), kz_doc:id(ResourceJObj)] + ), + Rules = kzd_resources:cid_rules(ResourceJObj, []), resource_rules(Rules, []). --spec resource_grace_period(kz_json:object() | integer()) -> 0..100. +-spec resource_grace_period(kzd_resources:doc() | integer()) -> 0..100. resource_grace_period(JObj) when not is_integer(JObj) -> - resource_grace_period(kz_json:get_integer_value(<<"grace_period">>, JObj, ?DEFAULT_WEIGHT)); + resource_grace_period(kzd_resources:grace_period(JObj, ?DEFAULT_WEIGHT)); resource_grace_period(GracePeriod) when is_integer(GracePeriod), GracePeriod > 100 -> 100; resource_grace_period(GracePeriod) when is_integer(GracePeriod), GracePeriod < 0 -> 0; resource_grace_period(GracePeriod) when is_integer(GracePeriod) -> GracePeriod. --spec resource_weight(kz_json:object() | integer()) -> integer(). +-spec resource_weight(kzd_resources:doc() | integer()) -> integer(). resource_weight(JObj) when not is_integer(JObj) -> - resource_weight(kz_json:get_integer_value(<<"weight_cost">>, JObj, ?DEFAULT_WEIGHT)); + resource_weight(kzd_resources:weight_cost(JObj, ?DEFAULT_WEIGHT)); resource_weight(W) when W > 100 -> 100; resource_weight(W) when W < 1 -> 1; resource_weight(W) -> W. -spec resource_is_emergency(kz_json:object()) -> boolean(). resource_is_emergency(JObj) -> - kz_json:is_true(<<"emergency">>, JObj) - orelse (kz_json:get_value([<<"caller_id_options">>, <<"type">>], JObj) =:= <<"emergency">>). + kzd_resources:emergency(JObj, 'false') + orelse (kzd_resources:caller_id_options_type(JObj) =:= <<"emergency">>). %%------------------------------------------------------------------------------ %% @doc @@ -1194,46 +1194,46 @@ gateways_from_jobjs([JObj|JObjs], Resource, Gateways) -> %% @end %%------------------------------------------------------------------------------ -spec gateway_from_jobj(kz_json:object(), resource()) -> gateway(). -gateway_from_jobj(JObj, #resrc{is_emergency=IsEmergency - ,format_from_uri=FormatFrom - ,from_uri_realm=FromRealm - ,from_account_realm=FromAccountRealm - ,fax_option=T38 - ,codecs=Codecs - ,bypass_media=BypassMedia - ,privacy_method=PrivacyMethod - ,privacy_hide_name=HideName - ,privacy_hide_number=HideNumber - }) -> - EndpointType = kz_json:get_ne_value(<<"endpoint_type">>, JObj, <<"sip">>), +gateway_from_jobj(GatewayJObj, #resrc{is_emergency=IsEmergency + ,format_from_uri=FormatFrom + ,from_uri_realm=FromRealm + ,from_account_realm=FromAccountRealm + ,fax_option=T38 + ,codecs=Codecs + ,bypass_media=BypassMedia + ,privacy_method=PrivacyMethod + ,privacy_hide_name=HideName + ,privacy_hide_number=HideNumber + }) -> + EndpointType = kz_json:get_ne_value(<<"endpoint_type">>, GatewayJObj, <<"sip">>), #gateway{endpoint_type = EndpointType - ,server = kz_json:get_ne_binary_value(<<"server">>, JObj) - ,port = kz_json:get_integer_value(<<"port">>, JObj) - ,realm = kz_json:get_value(<<"realm">>, JObj) - ,username = kz_json:get_value(<<"username">>, JObj) - ,password = kz_json:get_value(<<"password">>, JObj) - ,sip_headers = kz_custom_sip_headers:outbound(kz_json:get_json_value(<<"custom_sip_headers">>, JObj, kz_json:new())) - ,sip_interface = kz_json:get_ne_value(<<"custom_sip_interface">>, JObj) - ,invite_format = kz_json:get_value(<<"invite_format">>, JObj, <<"route">>) - ,format_from_uri = kz_json:is_true(<<"format_from_uri">>, JObj, FormatFrom) - ,from_uri_realm = kz_json:get_ne_value(<<"from_uri_realm">>, JObj, FromRealm) - ,from_account_realm=kz_json:is_true(<<"from_account_realm">>, JObj, FromAccountRealm) - ,is_emergency = gateway_is_emergency(JObj, IsEmergency) - ,fax_option = kz_json:is_true([<<"media">>, <<"fax_option">>], JObj, T38) - ,codecs = kz_json:get_value(<<"codecs">>, JObj, Codecs) - ,bypass_media = kz_json:is_true(<<"bypass_media">>, JObj, BypassMedia) - ,force_port = kz_json:is_true(<<"force_port">>, JObj) - ,route = kz_json:get_ne_value(<<"route">>, JObj, ?DEFAULT_ROUTE) - ,prefix = kz_json:get_binary_value(<<"prefix">>, JObj, ?DEFAULT_PREFIX) - ,suffix = kz_json:get_binary_value(<<"suffix">>, JObj, ?DEFAULT_SUFFIX) - ,rtcp_mux = kz_json:get_binary_value([<<"media">>, <<"rtcp_mux">>], JObj, ?DEFAULT_RTCP_MUX) - ,caller_id_type = kz_json:get_ne_value(<<"caller_id_type">>, JObj, ?DEFAULT_CALLER_ID_TYPE) - ,progress_timeout = kz_json:get_integer_value(<<"progress_timeout">>, JObj, ?DEFAULT_PROGRESS_TIMEOUT) - ,endpoint_options = endpoint_options(JObj, EndpointType) - ,privacy_method = kz_privacy:get_method(JObj, PrivacyMethod) - ,privacy_hide_name = kz_privacy:should_hide_name(JObj, HideName) - ,privacy_hide_number = kz_privacy:should_hide_name(JObj, HideNumber) - ,invite_parameters=kz_json:get_ne_value(<<"invite_parameters">>, JObj) + ,server = kz_json:get_ne_binary_value(<<"server">>, GatewayJObj) + ,port = kz_json:get_integer_value(<<"port">>, GatewayJObj) + ,realm = kz_json:get_value(<<"realm">>, GatewayJObj) + ,username = kz_json:get_value(<<"username">>, GatewayJObj) + ,password = kz_json:get_value(<<"password">>, GatewayJObj) + ,sip_headers = kz_custom_sip_headers:outbound(kz_json:get_json_value(<<"custom_sip_headers">>, GatewayJObj, kz_json:new())) + ,sip_interface = kz_json:get_ne_value(<<"custom_sip_interface">>, GatewayJObj) + ,invite_format = kz_json:get_value(<<"invite_format">>, GatewayJObj, <<"route">>) + ,format_from_uri = kz_json:is_true(<<"format_from_uri">>, GatewayJObj, FormatFrom) + ,from_uri_realm = kz_json:get_ne_value(<<"from_uri_realm">>, GatewayJObj, FromRealm) + ,from_account_realm=kz_json:is_true(<<"from_account_realm">>, GatewayJObj, FromAccountRealm) + ,is_emergency = gateway_is_emergency(GatewayJObj, IsEmergency) + ,fax_option = kz_json:is_true([<<"media">>, <<"fax_option">>], GatewayJObj, T38) + ,codecs = kz_json:get_value(<<"codecs">>, GatewayJObj, Codecs) + ,bypass_media = kz_json:is_true(<<"bypass_media">>, GatewayJObj, BypassMedia) + ,force_port = kz_json:is_true(<<"force_port">>, GatewayJObj) + ,route = kz_json:get_ne_value(<<"route">>, GatewayJObj, ?DEFAULT_ROUTE) + ,prefix = kz_json:get_binary_value(<<"prefix">>, GatewayJObj, ?DEFAULT_PREFIX) + ,suffix = kz_json:get_binary_value(<<"suffix">>, GatewayJObj, ?DEFAULT_SUFFIX) + ,rtcp_mux = kz_json:get_binary_value([<<"media">>, <<"rtcp_mux">>], GatewayJObj, ?DEFAULT_RTCP_MUX) + ,caller_id_type = kz_json:get_ne_value(<<"caller_id_type">>, GatewayJObj, ?DEFAULT_CALLER_ID_TYPE) + ,progress_timeout = kz_json:get_integer_value(<<"progress_timeout">>, GatewayJObj, ?DEFAULT_PROGRESS_TIMEOUT) + ,endpoint_options = endpoint_options(GatewayJObj, EndpointType) + ,privacy_method = kz_privacy:get_method(GatewayJObj, PrivacyMethod) + ,privacy_hide_name = kz_privacy:should_hide_name(GatewayJObj, HideName) + ,privacy_hide_number = kz_privacy:should_hide_name(GatewayJObj, HideNumber) + ,invite_parameters=kz_json:get_ne_value(<<"invite_parameters">>, GatewayJObj) }. -spec gateway_is_emergency(kz_json:object(), boolean()) -> boolean(). @@ -1254,8 +1254,7 @@ endpoint_options(JObj, <<"skype">>) -> ]); endpoint_options(JObj, <<"sip">>) -> kz_json:from_list( - [{<<"Route-ID">>, kz_json:get_value(<<"route_id">>, JObj)} - ]); + [{<<"Route-ID">>, kz_json:get_value(<<"route_id">>, JObj)}]); endpoint_options(_, _) -> kz_json:new(). @@ -1349,7 +1348,7 @@ get_resrc_codecs(#resrc{codecs=Codecs}) -> Codecs. -spec get_resrc_bypass_media(resource()) -> boolean(). get_resrc_bypass_media(#resrc{bypass_media=BypassMedia}) -> BypassMedia. --spec get_resrc_formatters(resource()) -> kz_term:api_objects(). +-spec get_resrc_formatters(resource()) -> kz_term:api_object(). get_resrc_formatters(#resrc{formatters=Formatters}) -> Formatters. -spec get_resrc_proxies(resource()) -> kz_term:proplist(). @@ -1427,7 +1426,7 @@ set_resrc_codecs(Resource, Codecs) -> Resource#resrc{codecs=Codecs}. -spec set_resrc_bypass_media(resource(), boolean()) -> resource(). set_resrc_bypass_media(Resource, BypassMedia) -> Resource#resrc{bypass_media=BypassMedia}. --spec set_resrc_formatters(resource(), kz_term:api_objects()) -> resource(). +-spec set_resrc_formatters(resource(), kz_term:api_object()) -> resource(). set_resrc_formatters(Resource, Formatters) -> Resource#resrc{formatters=Formatters}. -spec set_resrc_proxies(resource(), kz_term:proplist()) -> resource(). diff --git a/core/kazoo_apps/src/kapps_maintenance.erl b/core/kazoo_apps/src/kapps_maintenance.erl index 0cb5d53cfbf..7a3937a1079 100644 --- a/core/kazoo_apps/src/kapps_maintenance.erl +++ b/core/kazoo_apps/src/kapps_maintenance.erl @@ -662,7 +662,7 @@ ensure_aggregate_faxbox(Account) -> AccountDb = kzs_util:format_account_db(Account), case kz_datamgr:get_results(AccountDb, ?FAXBOX_VIEW, ['include_docs']) of {'ok', Faxboxes} -> - update_or_add_to_faxes_db([kz_json:get_value(<<"doc">>, Faxbox) || Faxbox <- Faxboxes]); + update_or_add_to_faxes_db([kz_json:get_json_value(<<"doc">>, Faxbox) || Faxbox <- Faxboxes]); {'error', _} -> 'ok' end. @@ -1977,6 +1977,14 @@ deprecate_timezone_for_node(Node, AccountsConfig, Timezone, 'undefined') -> deprecate_timezone_for_node(Node, AccountsConfig, _Timezone, _Default) -> kz_json:delete_key([Node, <<"timezone">>], AccountsConfig). +check_system_schemas() -> + _ = rpc:call(node() + ,'crossbar_maintenance' + ,'update_schemas' + ,[] + ), + 'ok'. + -spec check_system_configs() -> 'ok'. check_system_configs() -> io:format("starting system schemas validation~n"), @@ -2172,6 +2180,7 @@ check_release() -> kz_log:put_callid('check_release'), Checks = [fun kapps_started/0 ,fun check_system_configs/0 + ,fun check_system_schemas/0 ,fun master_account_created/0 ,fun migration_4_0_ran/0 ,fun migration_ran/0 @@ -2193,20 +2202,20 @@ check_release() -> -spec run_check(fun()) -> 'ok'. run_check(CheckFun) -> - StartTimeMs = kz_time:now_ms(), + StartTime = kz_time:start_time(), {Pid, Ref} = kz_process:spawn_monitor(CheckFun, []), - wait_for_check(Pid, Ref, StartTimeMs). + wait_for_check(Pid, Ref, StartTime). --spec wait_for_check(pid(), reference(), pos_integer()) -> 'ok'. -wait_for_check(Pid, Ref, StartTimeMs) -> +-spec wait_for_check(pid(), reference(), kz_time:start_time()) -> 'ok'. +wait_for_check(Pid, Ref, StartTime) -> receive {'DOWN', Ref, 'process', Pid, 'normal'} -> - lager:info("check finished in ~pms", [kz_time:elapsed_ms(StartTimeMs)]); + lager:info("check finished in ~pms", [kz_time:elapsed_ms(StartTime)]); {'DOWN', Ref, 'process', Pid, Reason} -> - lager:error("check in ~p failed to run after ~pms: ~p", [Pid, kz_time:elapsed_ms(StartTimeMs), Reason]), + lager:error("check in ~p failed to run after ~pms: ~p", [Pid, kz_time:elapsed_ms(StartTime), Reason]), throw(Reason) after 5 * ?MILLISECONDS_IN_MINUTE -> - lager:error("check in ~p timed out", [Pid]), + lager:error("check in ~p timed out after 5 minutes", [Pid]), exit(Pid, 'kill'), throw('timeout') end. diff --git a/core/kazoo_ast/src/kapi_schemas.erl b/core/kazoo_ast/src/kapi_schemas.erl index b1e98eb4e20..1308ebd8001 100644 --- a/core/kazoo_ast/src/kapi_schemas.erl +++ b/core/kazoo_ast/src/kapi_schemas.erl @@ -33,8 +33,7 @@ -type acc() :: #acc{}. -ifdef(TEST). --export([base_schema/2 - ]). +-export([base_schema/2]). -endif. -spec to_schemas() -> 'ok'. @@ -585,7 +584,7 @@ ast_to_value(Fun) when is_function(Fun) -> ast_to_value(<>) -> Bin; ast_to_value(Bins) when is_list(Bins) -> Bins; ast_to_value(?MOD_FUN_ARGS('kapi_presence', 'presence_states', [])) -> - kapi_presence:presence_states(); + lists:usort(kapi_presence:presence_states()); ast_to_value(?BINARY(_)=Bin) -> kz_ast_util:binary_match_to_binary(Bin); ast_to_value(?FA(F, A)) -> diff --git a/core/kazoo_directory/src/kz_directory_resource.erl b/core/kazoo_directory/src/kz_directory_resource.erl index 7d37e313782..add2c2164f0 100644 --- a/core/kazoo_directory/src/kz_directory_resource.erl +++ b/core/kazoo_directory/src/kz_directory_resource.erl @@ -141,7 +141,7 @@ set_resource_id(Map) -> Map. -spec maybe_add_t38_settings(resource_context()) -> resource_context(). maybe_add_t38_settings(#{resource := {'ok', Resource}, ccvs := CCVs} = Map) -> - Map#{ccvs => [{<<"Resource-Fax-Option">>, kzd_resources:fax_option(Resource)} | CCVs]}; + Map#{ccvs => [{<<"Resource-Fax-Option">>, kzd_resources:media_fax_option(Resource)} | CCVs]}; maybe_add_t38_settings(Map) -> Map. -spec set_ignore_display_updates(resource_context()) -> resource_context(). diff --git a/core/kazoo_documents/src/kzd_devices.erl b/core/kazoo_documents/src/kzd_devices.erl index 3d655ff0f15..b827b5b117b 100644 --- a/core/kazoo_documents/src/kzd_devices.erl +++ b/core/kazoo_documents/src/kzd_devices.erl @@ -62,16 +62,21 @@ -export([ringtones_internal/1, ringtones_internal/2, set_ringtones_internal/2]). -export([sip/1, sip/2, set_sip/2]). -export([sip_custom_sip_headers/1, sip_custom_sip_headers/2, set_sip_custom_sip_headers/2]). +-export([sip_custom_sip_interface/1, sip_custom_sip_interface/2, set_sip_custom_sip_interface/2]). -export([sip_expire_seconds/1, sip_expire_seconds/2, set_sip_expire_seconds/2]). +-export([sip_forward/1, sip_forward/2, set_sip_forward/2]). -export([sip_ignore_completed_elsewhere/1, sip_ignore_completed_elsewhere/2, set_sip_ignore_completed_elsewhere/2]). -export([sip_invite_format/1, sip_invite_format/2, set_sip_invite_format/2]). -export([sip_ip/1, sip_ip/2, set_sip_ip/2]). -export([sip_method/1, sip_method/2, set_sip_method/2]). -export([sip_number/1, sip_number/2, set_sip_number/2]). -export([sip_password/1, sip_password/2, set_sip_password/2]). +-export([sip_proxy/1, sip_proxy/2, set_sip_proxy/2]). -export([sip_realm/1, sip_realm/2, set_sip_realm/2]). -export([sip_route/1, sip_route/2, set_sip_route/2]). +-export([sip_static_invite/1, sip_static_invite/2, set_sip_static_invite/2]). -export([sip_static_route/1, sip_static_route/2, set_sip_static_route/2]). +-export([sip_transport/1, sip_transport/2, set_sip_transport/2]). -export([sip_username/1, sip_username/2, set_sip_username/2]). -export([suppress_unregister_notifications/1, suppress_unregister_notifications/2, set_suppress_unregister_notifications/2]). -export([timezone/1, timezone/2, set_timezone/2]). @@ -791,6 +796,18 @@ sip_custom_sip_headers(Doc, Default) -> set_sip_custom_sip_headers(Doc, SipCustomSipHeaders) -> kz_json:set_value([<<"sip">>, <<"custom_sip_headers">>], SipCustomSipHeaders, Doc). +-spec sip_custom_sip_interface(doc()) -> kz_term:api_binary(). +sip_custom_sip_interface(Doc) -> + sip_custom_sip_interface(Doc, 'undefined'). + +-spec sip_custom_sip_interface(doc(), Default) -> binary() | Default. +sip_custom_sip_interface(Doc, Default) -> + kz_json:get_binary_value([<<"sip">>, <<"custom_sip_interface">>], Doc, Default). + +-spec set_sip_custom_sip_interface(doc(), binary()) -> doc(). +set_sip_custom_sip_interface(Doc, SipCustomSipInterface) -> + kz_json:set_value([<<"sip">>, <<"custom_sip_interface">>], SipCustomSipInterface, Doc). + -spec sip_expire_seconds(doc()) -> integer(). sip_expire_seconds(Doc) -> sip_expire_seconds(Doc, 300). @@ -803,6 +820,18 @@ sip_expire_seconds(Doc, Default) -> set_sip_expire_seconds(Doc, SipExpireSeconds) -> kz_json:set_value([<<"sip">>, <<"expire_seconds">>], SipExpireSeconds, Doc). +-spec sip_forward(doc()) -> kz_term:api_binary(). +sip_forward(Doc) -> + sip_forward(Doc, 'undefined'). + +-spec sip_forward(doc(), Default) -> binary() | Default. +sip_forward(Doc, Default) -> + kz_json:get_binary_value([<<"sip">>, <<"forward">>], Doc, Default). + +-spec set_sip_forward(doc(), binary()) -> doc(). +set_sip_forward(Doc, SipForward) -> + kz_json:set_value([<<"sip">>, <<"forward">>], SipForward, Doc). + -spec sip_ignore_completed_elsewhere(doc()) -> kz_term:api_boolean(). sip_ignore_completed_elsewhere(Doc) -> sip_ignore_completed_elsewhere(Doc, 'undefined'). @@ -875,6 +904,18 @@ sip_password(Doc, Default) -> set_sip_password(Doc, SipPassword) -> kz_json:set_value([<<"sip">>, <<"password">>], SipPassword, Doc). +-spec sip_proxy(doc()) -> kz_term:api_binary(). +sip_proxy(Doc) -> + sip_proxy(Doc, 'undefined'). + +-spec sip_proxy(doc(), Default) -> binary() | Default. +sip_proxy(Doc, Default) -> + kz_json:get_binary_value([<<"sip">>, <<"proxy">>], Doc, Default). + +-spec set_sip_proxy(doc(), binary()) -> doc(). +set_sip_proxy(Doc, SipProxy) -> + kz_json:set_value([<<"sip">>, <<"proxy">>], SipProxy, Doc). + -spec sip_realm(doc()) -> kz_term:api_ne_binary(). sip_realm(Doc) -> sip_realm(Doc, 'undefined'). @@ -899,6 +940,18 @@ sip_route(Doc, Default) -> set_sip_route(Doc, SipRoute) -> kz_json:set_value([<<"sip">>, <<"route">>], SipRoute, Doc). +-spec sip_static_invite(doc()) -> kz_term:api_binary(). +sip_static_invite(Doc) -> + sip_static_invite(Doc, 'undefined'). + +-spec sip_static_invite(doc(), Default) -> binary() | Default. +sip_static_invite(Doc, Default) -> + kz_json:get_binary_value([<<"sip">>, <<"static_invite">>], Doc, Default). + +-spec set_sip_static_invite(doc(), binary()) -> doc(). +set_sip_static_invite(Doc, SipStaticInvite) -> + kz_json:set_value([<<"sip">>, <<"static_invite">>], SipStaticInvite, Doc). + -spec sip_static_route(doc()) -> kz_term:api_binary(). sip_static_route(Doc) -> sip_static_route(Doc, 'undefined'). @@ -911,6 +964,18 @@ sip_static_route(Doc, Default) -> set_sip_static_route(Doc, SipStaticRoute) -> kz_json:set_value([<<"sip">>, <<"static_route">>], SipStaticRoute, Doc). +-spec sip_transport(doc()) -> kz_term:api_binary(). +sip_transport(Doc) -> + sip_transport(Doc, 'undefined'). + +-spec sip_transport(doc(), Default) -> binary() | Default. +sip_transport(Doc, Default) -> + kz_json:get_binary_value([<<"sip">>, <<"transport">>], Doc, Default). + +-spec set_sip_transport(doc(), binary()) -> doc(). +set_sip_transport(Doc, SipTransport) -> + kz_json:set_value([<<"sip">>, <<"transport">>], SipTransport, Doc). + -spec sip_username(doc()) -> kz_term:api_ne_binary(). sip_username(Doc) -> sip_username(Doc, 'undefined'). diff --git a/core/kazoo_documents/src/kzd_devices.erl.src b/core/kazoo_documents/src/kzd_devices.erl.src index 7e6d8bc7c2a..4fb66f6af8a 100644 --- a/core/kazoo_documents/src/kzd_devices.erl.src +++ b/core/kazoo_documents/src/kzd_devices.erl.src @@ -60,16 +60,21 @@ -export([ringtones_internal/1, ringtones_internal/2, set_ringtones_internal/2]). -export([sip/1, sip/2, set_sip/2]). -export([sip_custom_sip_headers/1, sip_custom_sip_headers/2, set_sip_custom_sip_headers/2]). +-export([sip_custom_sip_interface/1, sip_custom_sip_interface/2, set_sip_custom_sip_interface/2]). -export([sip_expire_seconds/1, sip_expire_seconds/2, set_sip_expire_seconds/2]). +-export([sip_forward/1, sip_forward/2, set_sip_forward/2]). -export([sip_ignore_completed_elsewhere/1, sip_ignore_completed_elsewhere/2, set_sip_ignore_completed_elsewhere/2]). -export([sip_invite_format/1, sip_invite_format/2, set_sip_invite_format/2]). -export([sip_ip/1, sip_ip/2, set_sip_ip/2]). -export([sip_method/1, sip_method/2, set_sip_method/2]). -export([sip_number/1, sip_number/2, set_sip_number/2]). -export([sip_password/1, sip_password/2, set_sip_password/2]). +-export([sip_proxy/1, sip_proxy/2, set_sip_proxy/2]). -export([sip_realm/1, sip_realm/2, set_sip_realm/2]). -export([sip_route/1, sip_route/2, set_sip_route/2]). +-export([sip_static_invite/1, sip_static_invite/2, set_sip_static_invite/2]). -export([sip_static_route/1, sip_static_route/2, set_sip_static_route/2]). +-export([sip_transport/1, sip_transport/2, set_sip_transport/2]). -export([sip_username/1, sip_username/2, set_sip_username/2]). -export([suppress_unregister_notifications/1, suppress_unregister_notifications/2, set_suppress_unregister_notifications/2]). -export([timezone/1, timezone/2, set_timezone/2]). @@ -734,6 +739,18 @@ sip_custom_sip_headers(Doc, Default) -> set_sip_custom_sip_headers(Doc, SipCustomSipHeaders) -> kz_json:set_value([<<"sip">>, <<"custom_sip_headers">>], SipCustomSipHeaders, Doc). +-spec sip_custom_sip_interface(doc()) -> kz_term:api_binary(). +sip_custom_sip_interface(Doc) -> + sip_custom_sip_interface(Doc, 'undefined'). + +-spec sip_custom_sip_interface(doc(), Default) -> binary() | Default. +sip_custom_sip_interface(Doc, Default) -> + kz_json:get_binary_value([<<"sip">>, <<"custom_sip_interface">>], Doc, Default). + +-spec set_sip_custom_sip_interface(doc(), binary()) -> doc(). +set_sip_custom_sip_interface(Doc, SipCustomSipInterface) -> + kz_json:set_value([<<"sip">>, <<"custom_sip_interface">>], SipCustomSipInterface, Doc). + -spec sip_expire_seconds(doc()) -> integer(). sip_expire_seconds(Doc) -> sip_expire_seconds(Doc, 300). @@ -746,6 +763,18 @@ sip_expire_seconds(Doc, Default) -> set_sip_expire_seconds(Doc, SipExpireSeconds) -> kz_json:set_value([<<"sip">>, <<"expire_seconds">>], SipExpireSeconds, Doc). +-spec sip_forward(doc()) -> kz_term:api_binary(). +sip_forward(Doc) -> + sip_forward(Doc, 'undefined'). + +-spec sip_forward(doc(), Default) -> binary() | Default. +sip_forward(Doc, Default) -> + kz_json:get_binary_value([<<"sip">>, <<"forward">>], Doc, Default). + +-spec set_sip_forward(doc(), binary()) -> doc(). +set_sip_forward(Doc, SipForward) -> + kz_json:set_value([<<"sip">>, <<"forward">>], SipForward, Doc). + -spec sip_ignore_completed_elsewhere(doc()) -> kz_term:api_boolean(). sip_ignore_completed_elsewhere(Doc) -> sip_ignore_completed_elsewhere(Doc, 'undefined'). @@ -818,6 +847,18 @@ sip_password(Doc, Default) -> set_sip_password(Doc, SipPassword) -> kz_json:set_value([<<"sip">>, <<"password">>], SipPassword, Doc). +-spec sip_proxy(doc()) -> kz_term:api_binary(). +sip_proxy(Doc) -> + sip_proxy(Doc, 'undefined'). + +-spec sip_proxy(doc(), Default) -> binary() | Default. +sip_proxy(Doc, Default) -> + kz_json:get_binary_value([<<"sip">>, <<"proxy">>], Doc, Default). + +-spec set_sip_proxy(doc(), binary()) -> doc(). +set_sip_proxy(Doc, SipProxy) -> + kz_json:set_value([<<"sip">>, <<"proxy">>], SipProxy, Doc). + -spec sip_realm(doc()) -> kz_term:api_ne_binary(). sip_realm(Doc) -> sip_realm(Doc, 'undefined'). @@ -842,6 +883,18 @@ sip_route(Doc, Default) -> set_sip_route(Doc, SipRoute) -> kz_json:set_value([<<"sip">>, <<"route">>], SipRoute, Doc). +-spec sip_static_invite(doc()) -> kz_term:api_binary(). +sip_static_invite(Doc) -> + sip_static_invite(Doc, 'undefined'). + +-spec sip_static_invite(doc(), Default) -> binary() | Default. +sip_static_invite(Doc, Default) -> + kz_json:get_binary_value([<<"sip">>, <<"static_invite">>], Doc, Default). + +-spec set_sip_static_invite(doc(), binary()) -> doc(). +set_sip_static_invite(Doc, SipStaticInvite) -> + kz_json:set_value([<<"sip">>, <<"static_invite">>], SipStaticInvite, Doc). + -spec sip_static_route(doc()) -> kz_term:api_binary(). sip_static_route(Doc) -> sip_static_route(Doc, 'undefined'). @@ -854,6 +907,18 @@ sip_static_route(Doc, Default) -> set_sip_static_route(Doc, SipStaticRoute) -> kz_json:set_value([<<"sip">>, <<"static_route">>], SipStaticRoute, Doc). +-spec sip_transport(doc()) -> kz_term:api_binary(). +sip_transport(Doc) -> + sip_transport(Doc, 'undefined'). + +-spec sip_transport(doc(), Default) -> binary() | Default. +sip_transport(Doc, Default) -> + kz_json:get_binary_value([<<"sip">>, <<"transport">>], Doc, Default). + +-spec set_sip_transport(doc(), binary()) -> doc(). +set_sip_transport(Doc, SipTransport) -> + kz_json:set_value([<<"sip">>, <<"transport">>], SipTransport, Doc). + -spec sip_username(doc()) -> kz_term:api_ne_binary(). sip_username(Doc) -> sip_username(Doc, 'undefined'). diff --git a/core/kazoo_documents/src/kzd_resources.erl b/core/kazoo_documents/src/kzd_resources.erl index a1dd5d2a98f..847b9bcbad7 100644 --- a/core/kazoo_documents/src/kzd_resources.erl +++ b/core/kazoo_documents/src/kzd_resources.erl @@ -9,7 +9,19 @@ %%%----------------------------------------------------------------------------- -module(kzd_resources). --export([new/0]). +-export([new/0 + ,type/0, type/1 + ]). +-export([caller_id_options/1, caller_id_options/2, set_caller_id_options/2]). +-export([caller_id_options_type/1, caller_id_options_type/2, set_caller_id_options_type/2]). +-export([cid_rules/1, cid_rules/2, set_cid_rules/2]). +-export([classifiers/1, classifiers/2, set_classifiers/2]). +-export([classifiers_emergency/1, classifiers_emergency/2, set_classifiers_emergency/2]). +-export([classifiers_enabled/1, classifiers_enabled/2, set_classifiers_enabled/2]). +-export([classifiers_prefix/1, classifiers_prefix/2, set_classifiers_prefix/2]). +-export([classifiers_regex/1, classifiers_regex/2, set_classifiers_regex/2]). +-export([classifiers_suffix/1, classifiers_suffix/2, set_classifiers_suffix/2]). +-export([classifiers_weight_cost/1, classifiers_weight_cost/2, set_classifiers_weight_cost/2]). -export([emergency/1, emergency/2, set_emergency/2]). -export([enabled/1, enabled/2, set_enabled/2]). -export([flags/1, flags/2, set_flags/2]). @@ -17,6 +29,7 @@ -export([flat_rate_whitelist/1, flat_rate_whitelist/2, set_flat_rate_whitelist/2]). -export([format_from_uri/1, format_from_uri/2, set_format_from_uri/2]). -export([formatters/1, formatters/2, set_formatters/2]). +-export([from_account_realm/1, from_account_realm/2, set_from_account_realm/2]). -export([from_uri_realm/1, from_uri_realm/2, set_from_uri_realm/2]). -export([gateway_strategy/1, gateway_strategy/2, set_gateway_strategy/2]). -export([gateways/1, gateways/2, set_gateways/2]). @@ -27,19 +40,152 @@ -export([require_flags/1, require_flags/2, set_require_flags/2]). -export([rules/1, rules/2, set_rules/2]). -export([weight_cost/1, weight_cost/2, set_weight_cost/2]). --export([fax_option/1, fax_option/2]). +-export([media_fax_option/1, media_fax_option/2 + ,media_bypass_media/1, media_bypass_media/2 + ,media_audio_codecs/1, media_audio_codecs/2 + ,media_video_codecs/1, media_video_codecs/2 + ]). -include("kz_documents.hrl"). -type doc() :: kz_json:object(). --export_type([doc/0]). +-type docs() :: [doc()]. +-export_type([doc/0, docs/0]). +-define(PVT_TYPE, <<"resource">>). -define(SCHEMA, <<"resources">>). -spec new() -> doc(). new() -> - kz_json_schema:default_object(?SCHEMA). + kz_doc:set_type(kz_json_schema:default_object(?SCHEMA), type()). + +-spec type() -> kz_term:ne_binary(). +type() -> ?PVT_TYPE. + +-spec type(doc()) -> kz_term:ne_binary(). +type(Doc) -> + kz_doc:type(Doc, ?PVT_TYPE). + +-spec caller_id_options(doc()) -> kz_term:api_object(). +caller_id_options(Doc) -> + caller_id_options(Doc, 'undefined'). + +-spec caller_id_options(doc(), Default) -> kz_json:object() | Default. +caller_id_options(Doc, Default) -> + kz_json:get_json_value([<<"caller_id_options">>], Doc, Default). + +-spec set_caller_id_options(doc(), kz_json:object()) -> doc(). +set_caller_id_options(Doc, CallerIdOptions) -> + kz_json:set_value([<<"caller_id_options">>], CallerIdOptions, Doc). + +-spec caller_id_options_type(doc()) -> kz_term:api_binary(). +caller_id_options_type(Doc) -> + caller_id_options_type(Doc, 'undefined'). + +-spec caller_id_options_type(doc(), Default) -> binary() | Default. +caller_id_options_type(Doc, Default) -> + kz_json:get_binary_value([<<"caller_id_options">>, <<"type">>], Doc, Default). + +-spec set_caller_id_options_type(doc(), binary()) -> doc(). +set_caller_id_options_type(Doc, CallerIdOptionsType) -> + kz_json:set_value([<<"caller_id_options">>, <<"type">>], CallerIdOptionsType, Doc). + +-spec cid_rules(doc()) -> kz_term:api_ne_binaries(). +cid_rules(Doc) -> + cid_rules(Doc, 'undefined'). + +-spec cid_rules(doc(), Default) -> kz_term:ne_binaries() | Default. +cid_rules(Doc, Default) -> + kz_json:get_list_value([<<"cid_rules">>], Doc, Default). + +-spec set_cid_rules(doc(), kz_term:ne_binaries()) -> doc(). +set_cid_rules(Doc, CidRules) -> + kz_json:set_value([<<"cid_rules">>], CidRules, Doc). + +-spec classifiers(doc()) -> kz_term:api_object(). +classifiers(Doc) -> + classifiers(Doc, 'undefined'). + +-spec classifiers(doc(), Default) -> kz_json:object() | Default. +classifiers(Doc, Default) -> + kz_json:get_json_value([<<"classifiers">>], Doc, Default). + +-spec set_classifiers(doc(), kz_json:object()) -> doc(). +set_classifiers(Doc, Classifiers) -> + kz_json:set_value([<<"classifiers">>], Classifiers, Doc). + +-spec classifiers_emergency(doc()) -> boolean(). +classifiers_emergency(Doc) -> + classifiers_emergency(Doc, false). + +-spec classifiers_emergency(doc(), Default) -> boolean() | Default. +classifiers_emergency(Doc, Default) -> + kz_json:get_boolean_value([<<"classifiers">>, <<"emergency">>], Doc, Default). + +-spec set_classifiers_emergency(doc(), boolean()) -> doc(). +set_classifiers_emergency(Doc, ClassifiersEmergency) -> + kz_json:set_value([<<"classifiers">>, <<"emergency">>], ClassifiersEmergency, Doc). + +-spec classifiers_enabled(doc()) -> boolean(). +classifiers_enabled(Doc) -> + classifiers_enabled(Doc, true). + +-spec classifiers_enabled(doc(), Default) -> boolean() | Default. +classifiers_enabled(Doc, Default) -> + kz_json:get_boolean_value([<<"classifiers">>, <<"enabled">>], Doc, Default). + +-spec set_classifiers_enabled(doc(), boolean()) -> doc(). +set_classifiers_enabled(Doc, ClassifiersEnabled) -> + kz_json:set_value([<<"classifiers">>, <<"enabled">>], ClassifiersEnabled, Doc). + +-spec classifiers_prefix(doc()) -> kz_term:api_binary(). +classifiers_prefix(Doc) -> + classifiers_prefix(Doc, 'undefined'). + +-spec classifiers_prefix(doc(), Default) -> binary() | Default. +classifiers_prefix(Doc, Default) -> + kz_json:get_binary_value([<<"classifiers">>, <<"prefix">>], Doc, Default). + +-spec set_classifiers_prefix(doc(), binary()) -> doc(). +set_classifiers_prefix(Doc, ClassifiersPrefix) -> + kz_json:set_value([<<"classifiers">>, <<"prefix">>], ClassifiersPrefix, Doc). + +-spec classifiers_regex(doc()) -> kz_term:api_binary(). +classifiers_regex(Doc) -> + classifiers_regex(Doc, 'undefined'). + +-spec classifiers_regex(doc(), Default) -> binary() | Default. +classifiers_regex(Doc, Default) -> + kz_json:get_binary_value([<<"classifiers">>, <<"regex">>], Doc, Default). + +-spec set_classifiers_regex(doc(), binary()) -> doc(). +set_classifiers_regex(Doc, ClassifiersRegex) -> + kz_json:set_value([<<"classifiers">>, <<"regex">>], ClassifiersRegex, Doc). + +-spec classifiers_suffix(doc()) -> kz_term:api_binary(). +classifiers_suffix(Doc) -> + classifiers_suffix(Doc, 'undefined'). + +-spec classifiers_suffix(doc(), Default) -> binary() | Default. +classifiers_suffix(Doc, Default) -> + kz_json:get_binary_value([<<"classifiers">>, <<"suffix">>], Doc, Default). + +-spec set_classifiers_suffix(doc(), binary()) -> doc(). +set_classifiers_suffix(Doc, ClassifiersSuffix) -> + kz_json:set_value([<<"classifiers">>, <<"suffix">>], ClassifiersSuffix, Doc). + +-spec classifiers_weight_cost(doc()) -> integer(). +classifiers_weight_cost(Doc) -> + classifiers_weight_cost(Doc, 50). + +-spec classifiers_weight_cost(doc(), Default) -> integer() | Default. +classifiers_weight_cost(Doc, Default) -> + kz_json:get_integer_value([<<"classifiers">>, <<"weight_cost">>], Doc, Default). + +-spec set_classifiers_weight_cost(doc(), integer()) -> doc(). +set_classifiers_weight_cost(Doc, ClassifiersWeightCost) -> + kz_json:set_value([<<"classifiers">>, <<"weight_cost">>], ClassifiersWeightCost, Doc). -spec emergency(doc()) -> boolean(). emergency(Doc) -> @@ -125,6 +271,18 @@ formatters(Doc, Default) -> set_formatters(Doc, Formatters) -> kz_json:set_value([<<"formatters">>], Formatters, Doc). +-spec from_account_realm(doc()) -> boolean(). +from_account_realm(Doc) -> + from_account_realm(Doc, 'false'). + +-spec from_account_realm(doc(), Default) -> boolean() | Default. +from_account_realm(Doc, Default) -> + kz_json:get_boolean_value([<<"from_account_realm">>], Doc, Default). + +-spec set_from_account_realm(doc(), boolean()) -> doc(). +set_from_account_realm(Doc, FromAccountRealm) -> + kz_json:set_value([<<"from_account_realm">>], FromAccountRealm, Doc). + -spec from_uri_realm(doc()) -> kz_term:api_binary(). from_uri_realm(Doc) -> from_uri_realm(Doc, 'undefined'). @@ -245,10 +403,34 @@ weight_cost(Doc, Default) -> set_weight_cost(Doc, WeightCost) -> kz_json:set_value([<<"weight_cost">>], WeightCost, Doc). --spec fax_option(doc()) -> kz_term:api_ne_binary(). -fax_option(Doc) -> - fax_option(Doc, 'undefined'). +-spec media_fax_option(doc()) -> boolean(). +media_fax_option(Doc) -> + media_fax_option(Doc, 'false'). + +-spec media_fax_option(doc(), Default) -> boolean() | Default. +media_fax_option(Doc, Default) -> + kz_json:is_true([<<"media">>, <<"fax_option">>], Doc, Default). + +-spec media_bypass_media(doc()) -> boolean(). +media_bypass_media(Doc) -> + media_bypass_media(Doc, 'false'). + +-spec media_bypass_media(doc(), Default) -> boolean() | Default. +media_bypass_media(Doc, Default) -> + kz_json:is_true([<<"media">>, <<"bypass_media">>], Doc, Default). + +-spec media_audio_codecs(doc()) -> kz_term:api_ne_binaries(). +media_audio_codecs(Doc) -> + media_audio_codecs(Doc, 'undefined'). + +-spec media_audio_codecs(doc(), Default) -> kz_term:ne_binaries() | Default. +media_audio_codecs(Doc, Default) -> + kz_json:get_list_value([<<"media">>, <<"audio">>, <<"codecs">>], Doc, Default). + +-spec media_video_codecs(doc()) -> kz_term:api_ne_binaries(). +media_video_codecs(Doc) -> + media_video_codecs(Doc, 'undefined'). --spec fax_option(doc(), Default) -> kz_term:api_ne_binary() | Default. -fax_option(Doc, Default) -> - kz_json:get_ne_binary_value(<<"fax_option">>, media(Doc, kz_json:new()), Default). +-spec media_video_codecs(doc(), Default) -> kz_term:ne_binaries() | Default. +media_video_codecs(Doc, Default) -> + kz_json:get_list_value([<<"media">>, <<"video">>, <<"codecs">>], Doc, Default). diff --git a/core/kazoo_documents/src/kzd_resources.erl.src b/core/kazoo_documents/src/kzd_resources.erl.src index dafb6ef20c9..5f0dc109ae5 100644 --- a/core/kazoo_documents/src/kzd_resources.erl.src +++ b/core/kazoo_documents/src/kzd_resources.erl.src @@ -6,6 +6,16 @@ -module(kzd_resources). -export([new/0]). +-export([caller_id_options/1, caller_id_options/2, set_caller_id_options/2]). +-export([caller_id_options_type/1, caller_id_options_type/2, set_caller_id_options_type/2]). +-export([cid_rules/1, cid_rules/2, set_cid_rules/2]). +-export([classifiers/1, classifiers/2, set_classifiers/2]). +-export([classifiers_emergency/1, classifiers_emergency/2, set_classifiers_emergency/2]). +-export([classifiers_enabled/1, classifiers_enabled/2, set_classifiers_enabled/2]). +-export([classifiers_prefix/1, classifiers_prefix/2, set_classifiers_prefix/2]). +-export([classifiers_regex/1, classifiers_regex/2, set_classifiers_regex/2]). +-export([classifiers_suffix/1, classifiers_suffix/2, set_classifiers_suffix/2]). +-export([classifiers_weight_cost/1, classifiers_weight_cost/2, set_classifiers_weight_cost/2]). -export([emergency/1, emergency/2, set_emergency/2]). -export([enabled/1, enabled/2, set_enabled/2]). -export([flags/1, flags/2, set_flags/2]). @@ -13,6 +23,7 @@ -export([flat_rate_whitelist/1, flat_rate_whitelist/2, set_flat_rate_whitelist/2]). -export([format_from_uri/1, format_from_uri/2, set_format_from_uri/2]). -export([formatters/1, formatters/2, set_formatters/2]). +-export([from_account_realm/1, from_account_realm/2, set_from_account_realm/2]). -export([from_uri_realm/1, from_uri_realm/2, set_from_uri_realm/2]). -export([gateway_strategy/1, gateway_strategy/2, set_gateway_strategy/2]). -export([gateways/1, gateways/2, set_gateways/2]). @@ -36,6 +47,126 @@ new() -> kz_json_schema:default_object(?SCHEMA). +-spec caller_id_options(doc()) -> kz_term:api_object(). +caller_id_options(Doc) -> + caller_id_options(Doc, 'undefined'). + +-spec caller_id_options(doc(), Default) -> kz_json:object() | Default. +caller_id_options(Doc, Default) -> + kz_json:get_json_value([<<"caller_id_options">>], Doc, Default). + +-spec set_caller_id_options(doc(), kz_json:object()) -> doc(). +set_caller_id_options(Doc, CallerIdOptions) -> + kz_json:set_value([<<"caller_id_options">>], CallerIdOptions, Doc). + +-spec caller_id_options_type(doc()) -> kz_term:api_binary(). +caller_id_options_type(Doc) -> + caller_id_options_type(Doc, 'undefined'). + +-spec caller_id_options_type(doc(), Default) -> binary() | Default. +caller_id_options_type(Doc, Default) -> + kz_json:get_binary_value([<<"caller_id_options">>, <<"type">>], Doc, Default). + +-spec set_caller_id_options_type(doc(), binary()) -> doc(). +set_caller_id_options_type(Doc, CallerIdOptionsType) -> + kz_json:set_value([<<"caller_id_options">>, <<"type">>], CallerIdOptionsType, Doc). + +-spec cid_rules(doc()) -> kz_term:api_ne_binaries(). +cid_rules(Doc) -> + cid_rules(Doc, 'undefined'). + +-spec cid_rules(doc(), Default) -> kz_term:ne_binaries() | Default. +cid_rules(Doc, Default) -> + kz_json:get_list_value([<<"cid_rules">>], Doc, Default). + +-spec set_cid_rules(doc(), kz_term:ne_binaries()) -> doc(). +set_cid_rules(Doc, CidRules) -> + kz_json:set_value([<<"cid_rules">>], CidRules, Doc). + +-spec classifiers(doc()) -> kz_term:api_object(). +classifiers(Doc) -> + classifiers(Doc, 'undefined'). + +-spec classifiers(doc(), Default) -> kz_json:object() | Default. +classifiers(Doc, Default) -> + kz_json:get_json_value([<<"classifiers">>], Doc, Default). + +-spec set_classifiers(doc(), kz_json:object()) -> doc(). +set_classifiers(Doc, Classifiers) -> + kz_json:set_value([<<"classifiers">>], Classifiers, Doc). + +-spec classifiers_emergency(doc()) -> boolean(). +classifiers_emergency(Doc) -> + classifiers_emergency(Doc, false). + +-spec classifiers_emergency(doc(), Default) -> boolean() | Default. +classifiers_emergency(Doc, Default) -> + kz_json:get_boolean_value([<<"classifiers">>, <<"emergency">>], Doc, Default). + +-spec set_classifiers_emergency(doc(), boolean()) -> doc(). +set_classifiers_emergency(Doc, ClassifiersEmergency) -> + kz_json:set_value([<<"classifiers">>, <<"emergency">>], ClassifiersEmergency, Doc). + +-spec classifiers_enabled(doc()) -> boolean(). +classifiers_enabled(Doc) -> + classifiers_enabled(Doc, true). + +-spec classifiers_enabled(doc(), Default) -> boolean() | Default. +classifiers_enabled(Doc, Default) -> + kz_json:get_boolean_value([<<"classifiers">>, <<"enabled">>], Doc, Default). + +-spec set_classifiers_enabled(doc(), boolean()) -> doc(). +set_classifiers_enabled(Doc, ClassifiersEnabled) -> + kz_json:set_value([<<"classifiers">>, <<"enabled">>], ClassifiersEnabled, Doc). + +-spec classifiers_prefix(doc()) -> kz_term:api_binary(). +classifiers_prefix(Doc) -> + classifiers_prefix(Doc, 'undefined'). + +-spec classifiers_prefix(doc(), Default) -> binary() | Default. +classifiers_prefix(Doc, Default) -> + kz_json:get_binary_value([<<"classifiers">>, <<"prefix">>], Doc, Default). + +-spec set_classifiers_prefix(doc(), binary()) -> doc(). +set_classifiers_prefix(Doc, ClassifiersPrefix) -> + kz_json:set_value([<<"classifiers">>, <<"prefix">>], ClassifiersPrefix, Doc). + +-spec classifiers_regex(doc()) -> kz_term:api_binary(). +classifiers_regex(Doc) -> + classifiers_regex(Doc, 'undefined'). + +-spec classifiers_regex(doc(), Default) -> binary() | Default. +classifiers_regex(Doc, Default) -> + kz_json:get_binary_value([<<"classifiers">>, <<"regex">>], Doc, Default). + +-spec set_classifiers_regex(doc(), binary()) -> doc(). +set_classifiers_regex(Doc, ClassifiersRegex) -> + kz_json:set_value([<<"classifiers">>, <<"regex">>], ClassifiersRegex, Doc). + +-spec classifiers_suffix(doc()) -> kz_term:api_binary(). +classifiers_suffix(Doc) -> + classifiers_suffix(Doc, 'undefined'). + +-spec classifiers_suffix(doc(), Default) -> binary() | Default. +classifiers_suffix(Doc, Default) -> + kz_json:get_binary_value([<<"classifiers">>, <<"suffix">>], Doc, Default). + +-spec set_classifiers_suffix(doc(), binary()) -> doc(). +set_classifiers_suffix(Doc, ClassifiersSuffix) -> + kz_json:set_value([<<"classifiers">>, <<"suffix">>], ClassifiersSuffix, Doc). + +-spec classifiers_weight_cost(doc()) -> integer(). +classifiers_weight_cost(Doc) -> + classifiers_weight_cost(Doc, 50). + +-spec classifiers_weight_cost(doc(), Default) -> integer() | Default. +classifiers_weight_cost(Doc, Default) -> + kz_json:get_integer_value([<<"classifiers">>, <<"weight_cost">>], Doc, Default). + +-spec set_classifiers_weight_cost(doc(), integer()) -> doc(). +set_classifiers_weight_cost(Doc, ClassifiersWeightCost) -> + kz_json:set_value([<<"classifiers">>, <<"weight_cost">>], ClassifiersWeightCost, Doc). + -spec emergency(doc()) -> boolean(). emergency(Doc) -> emergency(Doc, false). @@ -120,6 +251,18 @@ formatters(Doc, Default) -> set_formatters(Doc, Formatters) -> kz_json:set_value([<<"formatters">>], Formatters, Doc). +-spec from_account_realm(doc()) -> boolean(). +from_account_realm(Doc) -> + from_account_realm(Doc, false). + +-spec from_account_realm(doc(), Default) -> boolean() | Default. +from_account_realm(Doc, Default) -> + kz_json:get_boolean_value([<<"from_account_realm">>], Doc, Default). + +-spec set_from_account_realm(doc(), boolean()) -> doc(). +set_from_account_realm(Doc, FromAccountRealm) -> + kz_json:set_value([<<"from_account_realm">>], FromAccountRealm, Doc). + -spec from_uri_realm(doc()) -> kz_term:api_binary(). from_uri_realm(Doc) -> from_uri_realm(Doc, 'undefined'). diff --git a/core/kazoo_endpoint/src/kz_endpoint_v4.erl b/core/kazoo_endpoint/src/kz_endpoint_v4.erl index 73487ce2e7b..eab74ca42ad 100644 --- a/core/kazoo_endpoint/src/kz_endpoint_v4.erl +++ b/core/kazoo_endpoint/src/kz_endpoint_v4.erl @@ -212,20 +212,17 @@ cache_origin(JObj, EndpointId, AccountDb) -> -spec maybe_cached_owner_id(kz_term:proplist(), kz_json:object(), kz_term:ne_binary()) -> kz_term:proplist(). maybe_cached_owner_id(Props, JObj, AccountDb) -> - case kz_json:get_ne_binary_value(<<"owner_id">>, JObj) of + case kzd_devices:owner_id(JObj) of 'undefined' -> Props; OwnerId -> [{'db', AccountDb, OwnerId}|Props] end. -spec maybe_cached_hotdesk_ids(kz_term:proplist(), kz_json:object(), kz_term:ne_binary()) -> kz_term:proplist(). maybe_cached_hotdesk_ids(Props, JObj, AccountDb) -> - case kz_json:get_keys([<<"hotdesk">>, <<"users">>], JObj) of - [] -> Props; - OwnerIds -> - lists:foldl(fun(Id, P) -> - [{'db', AccountDb, Id}|P] - end, Props, OwnerIds) - end. + lists:foldl(fun(Id, P) -> [{'db', AccountDb, Id}|P] end + ,Props + ,kzd_devices:hotdesk_ids(JObj, []) + ). -spec maybe_format_endpoint(kz_json:object(), kz_term:api_object()) -> kz_json:object(). maybe_format_endpoint(Endpoint, 'undefined') -> @@ -335,26 +332,26 @@ merge_attribute(<<"call_restriction">>, Account, Endpoint, Owner) -> Classifiers = kz_json:get_keys(knm_converters:available_classifiers()), merge_call_restrictions(Classifiers, Account, Endpoint, Owner); merge_attribute(<<"name">> = Key, Account, Endpoint, Owner) -> - Name = create_endpoint_name(kz_json:get_ne_value(<<"first_name">>, Owner) - ,kz_json:get_ne_value(<<"last_name">>, Owner) - ,kz_json:get_ne_value(Key, Endpoint) - ,kz_json:get_ne_value(Key, Account) + Name = create_endpoint_name(kzd_users:first_name(Owner) + ,kzd_users:last_name(Owner) + ,kzd_devices:name(Endpoint) + ,kzd_accounts:name(Account) ), kz_json:set_value(Key, Name, Endpoint); -merge_attribute(<<"call_forward">> = Key, Account, Endpoint, Owner) -> - EndpointAttr = kz_json:get_ne_value(Key, Endpoint, kz_json:new()), - case kz_json:is_true(<<"enabled">>, EndpointAttr) of +merge_attribute(<<"call_forward">> = Key, _Account, Endpoint, Owner) -> + case kzd_devices:call_forward_enabled(Endpoint) of 'true' -> Endpoint; 'false' -> - AccountAttr = kz_json:get_ne_value(Key, Account, kz_json:new()), - OwnerAttr = kz_json:get_ne_value(Key, Owner, kz_json:new()), - Merged = kz_json:merge([AccountAttr, EndpointAttr, OwnerAttr]), + OwnerAttr = kzd_users:call_forward(Owner, kz_json:new()), + EndpointAttr = kzd_devices:call_forward(Endpoint, kz_json:new()), + Merged = kz_json:merge([EndpointAttr, OwnerAttr]), kz_json:set_value(Key, Merged, Endpoint) end; merge_attribute(<<"call_waiting">> = Key, Account, Endpoint, Owner) -> - AccountAttr = kz_json:get_ne_value(Key, Account, kz_json:new()), - EndpointAttr = kz_json:get_ne_value(Key, Endpoint, kz_json:new()), - OwnerAttr = kz_json:get_ne_value(Key, Owner, kz_json:new()), + AccountAttr = kzd_accounts:call_waiting(Account, kz_json:new()), + EndpointAttr = kzd_devices:call_waiting(Endpoint, kz_json:new()), + OwnerAttr = kzd_users:call_waiting(Owner, kz_json:new()), + %% allow the device to override the owner preference (and vice versa) so %% endpoints such as mobile device can disable call_waiting while sip phone %% might still have it enabled @@ -1246,19 +1243,19 @@ create_sip_endpoint(Endpoint, Properties, Call) -> -spec create_sip_endpoint(kz_json:object(), kz_json:object(), clid(), kapps_call:call()) -> kz_json:object(). create_sip_endpoint(Endpoint, Properties, #clid{}=Clid, Call) -> - SIPJObj = kz_json:get_json_value(<<"sip">>, Endpoint), + SIPJObj = kzd_devices:sip(Endpoint), SIPEndpoint = kz_json:from_list( - [{<<"Invite-Format">>, get_invite_format(SIPJObj)} + [{<<"Invite-Format">>, get_invite_format(Endpoint)} ,{<<"To-User">>, get_to_user(SIPJObj, Properties)} ,{<<"To-Username">>, get_to_username(SIPJObj)} ,{<<"To-Realm">>, get_sip_realm(Endpoint, kapps_call:account_id(Call))} ,{<<"To-DID">>, get_to_did(Endpoint, Call)} - ,{<<"To-IP">>, kz_json:get_ne_binary_value(<<"ip">>, SIPJObj)} - ,{<<"SIP-Transport">>, get_sip_transport(SIPJObj)} - ,{<<"SIP-Interface">>, get_custom_sip_interface(SIPJObj)} - ,{<<"Route">>, kz_json:get_ne_binary_value(<<"route">>, SIPJObj)} - ,{<<"Proxy-IP">>, kz_json:get_ne_binary_value(<<"proxy">>, SIPJObj)} - ,{<<"Forward-IP">>, kz_json:get_ne_binary_value(<<"forward">>, SIPJObj)} + ,{<<"To-IP">>, kzd_devices:sip_ip(Endpoint)} + ,{<<"SIP-Transport">>, get_sip_transport(Endpoint)} + ,{<<"SIP-Interface">>, get_custom_sip_interface(Endpoint)} + ,{<<"Route">>, kzd_devices:sip_route(Endpoint)} + ,{<<"Proxy-IP">>, kzd_devices:sip_proxy(Endpoint)} + ,{<<"Forward-IP">>, kzd_devices:sip_forward(Endpoint)} ,{<<"Outbound-Caller-ID-Number">>, Clid#clid.caller_number} ,{<<"Outbound-Caller-ID-Name">>, Clid#clid.caller_name} ,{<<"Outbound-Callee-ID-Name">>, Clid#clid.callee_name} @@ -1280,11 +1277,11 @@ create_sip_endpoint(Endpoint, Properties, #clid{}=Clid, Call) -> ,{<<"Flags">>, get_outbound_flags(Endpoint)} ,{<<"Ignore-Completed-Elsewhere">>, get_ignore_completed_elsewhere(Endpoint)} ,{<<"Failover">>, maybe_build_failover(Endpoint, Call)} - ,{<<"Metaflows">>, kz_json:get_json_value(<<"metaflows">>, Endpoint)} + ,{<<"Metaflows">>, kzd_devices:metaflows(Endpoint)} ,{<<"Endpoint-Actions">>, endpoint_actions(Endpoint, Call)} | maybe_get_t38(Endpoint, Call) ]), - maybe_format_endpoint(SIPEndpoint, kz_json:get_json_value(<<"formatters">>, Endpoint)). + maybe_format_endpoint(SIPEndpoint, kzd_devices:formatters(Endpoint)). -spec maybe_get_t38(kz_json:object(), kapps_call:call()) -> kz_term:proplist(). maybe_get_t38(Endpoint, Call) -> @@ -1302,9 +1299,8 @@ maybe_get_t38(Endpoint, Call) -> -spec maybe_build_failover(kz_json:object(), kapps_call:call()) -> kz_term:api_object(). maybe_build_failover(Endpoint, Call) -> - CallForward = kz_json:get_value(<<"call_forward">>, Endpoint), - Number = kz_json:get_value(<<"number">>, CallForward), - case kz_json:is_true(<<"failover">>, CallForward) + Number = kzd_devices:call_forward_number(Endpoint), + case kzd_devices:call_forward_failover(Endpoint, 'false') andalso not kz_term:is_empty(Number) of 'false' -> 'undefined'; @@ -1314,7 +1310,7 @@ maybe_build_failover(Endpoint, Call) -> -spec create_push_endpoint(kz_json:object(), kz_json:object(), kapps_call:call()) -> kz_term:api_object(). create_push_endpoint(Endpoint, Properties, Call) -> Clid = get_clid(Endpoint, Properties, Call), - SIPJObj = kz_json:get_value(<<"sip">>, Endpoint), + SIPJObj = kzd_devices:sip(Endpoint), ToUsername = get_to_username(SIPJObj), ToRealm = get_sip_realm(Endpoint, kapps_call:account_id(Call)), ToUser = <>, @@ -1326,7 +1322,7 @@ create_push_endpoint(Endpoint, Properties, Call) -> ,{<<"To-Username">>, ToUsername} ,{<<"To-Realm">>, ToRealm} ,{<<"To-DID">>, get_to_did(Endpoint, Call)} - ,{<<"SIP-Transport">>, get_sip_transport(SIPJObj)} + ,{<<"SIP-Transport">>, get_sip_transport(Endpoint)} ,{<<"Route">>, <<"sip:", ToUser/binary, ";fs_path='", Proxy/binary, "'">> } ,{<<"Outbound-Callee-ID-Name">>, Clid#clid.callee_name} ,{<<"Outbound-Callee-ID-Number">>, Clid#clid.callee_number} @@ -1373,9 +1369,9 @@ push_headers(PushJObj) -> %% @doc %% @end %%------------------------------------------------------------------------------ --spec get_sip_transport(kz_json:object()) -> kz_term:api_binary(). -get_sip_transport(SIPJObj) -> - case validate_sip_transport(kz_json:get_value(<<"transport">>, SIPJObj)) of +-spec get_sip_transport(kzd_devices:doc()) -> kz_term:api_binary(). +get_sip_transport(DeviceJObj) -> + case validate_sip_transport(kzd_devices:sip_transport(DeviceJObj)) of 'undefined' -> validate_sip_transport(kapps_config:get_ne_binary(?CONFIG_CAT, <<"sip_transport">>)); Transport -> Transport @@ -1392,9 +1388,9 @@ validate_sip_transport(_) -> 'undefined'. %% @doc %% @end %%------------------------------------------------------------------------------ --spec get_custom_sip_interface(kz_json:object()) -> kz_term:api_ne_binary(). +-spec get_custom_sip_interface(kzd_devices:doc()) -> kz_term:api_ne_binary(). get_custom_sip_interface(JObj) -> - case kz_json:get_value(<<"custom_sip_interface">>, JObj) of + case kzd_devices:sip_custom_sip_interface(JObj) of 'undefined' -> kapps_config:get_ne_binary(?CONFIG_CAT, <<"custom_sip_interface">>); Else -> Else @@ -1430,13 +1426,13 @@ create_skype_endpoint(Endpoint, Properties, _Call) -> kz_json:object(). create_call_fwd_endpoint(Endpoint, Properties, Call) -> CallForward = kz_json:get_ne_value(<<"call_forward">>, Endpoint, kz_json:new()), - ToDID = kz_json:get_value(<<"number">>, CallForward), + ToDID = kzd_devices:call_forward_number(Endpoint), lager:info("call forwarding endpoint to ~s", [ToDID]), - IgnoreEarlyMedia = case kz_json:is_true(<<"require_keypress">>, CallForward) - orelse not kz_json:is_true(<<"substitute">>, CallForward) + IgnoreEarlyMedia = case kzd_devices:call_forward_require_keypress(Endpoint, 'false') + orelse not kzd_devices:call_forward_substitute(Endpoint, 'false') of - 'true' -> <<"true">>; - 'false' -> kz_json:get_binary_boolean(<<"ignore_early_media">>, CallForward) + 'true' -> 'true'; + 'false' -> kzd_devices:call_forward_ignore_early_media(Endpoint) end, Clid = case kapps_call:inception(Call) of 'undefined' -> get_clid(Endpoint, Properties, Call, <<"external">>); @@ -1891,18 +1887,15 @@ maybe_set_call_waiting({Endpoint, Call, CallFwd, CCVs}) -> end }. --spec get_invite_format(kz_json:object()) -> kz_term:ne_binary(). -get_invite_format(SIPJObj) -> - IF = kz_json:get_ne_binary_value(<<"invite_format">>, SIPJObj, <<"username">>), +-spec get_invite_format(kzd_devices:doc()) -> kz_term:ne_binary(). +get_invite_format(DeviceJObj) -> + IF = kzd_devices:sip_invite_format(DeviceJObj, <<"username">>), lager:debug("invite format: ~s", [IF]), IF. --spec get_to_did(kz_json:object(), kapps_call:call()) -> kz_term:api_ne_binary(). +-spec get_to_did(kzd_devices:doc(), kapps_call:call()) -> kz_term:api_ne_binary(). get_to_did(Endpoint, Call) -> - kz_json:get_ne_binary_value([<<"sip">>, <<"number">>] - ,Endpoint - ,kapps_call:request_user(Call) - ). + kzd_devices:sip_number(Endpoint, kapps_call:request_user(Call)). -spec get_to_user(kz_json:object(), kz_json:object()) -> kz_term:api_ne_binary(). get_to_user(SIPJObj, Properties) -> diff --git a/core/kazoo_schemas/src/kz_json_schema.erl b/core/kazoo_schemas/src/kz_json_schema.erl index 85d49bb1f11..dc5a9cdab96 100644 --- a/core/kazoo_schemas/src/kz_json_schema.erl +++ b/core/kazoo_schemas/src/kz_json_schema.erl @@ -93,10 +93,10 @@ load(Schema) -> fload(Schema). -spec load(kz_term:ne_binary() | string()) -> load_return(). load(<<"./", Schema/binary>>) -> load(Schema); load(<<"file://", Schema/binary>>) -> load(Schema); -load(<>) -> - case kz_datamgr:open_cache_doc(?KZ_SCHEMA_DB, Schema, [{'cache_failures', ['not_found']}]) of +load(<>) -> + case kz_datamgr:open_cache_doc(?KZ_SCHEMA_DB, SchemaId, [{'cache_failures', ['not_found']}]) of {'error', _E}=E -> E; - {'ok', JObj} -> {'ok', kz_json:insert_value(<<"id">>, Schema, JObj)} + {'ok', JObj} -> {'ok', kz_json:insert_value(<<"id">>, SchemaId, JObj)} end; load(Schema) -> load(kz_term:to_binary(Schema)). -endif. @@ -1005,7 +1005,7 @@ flatten_prop(Path, ?JSON_WRAPPER(L) = Value) when is_list(L) -> -spec default_object(string() | kz_term:ne_binary() | kz_json:object()) -> kz_json:object(). default_object([_|_]=SchemaId) -> default_object(list_to_binary(SchemaId)); -default_object(?NE_BINARY=SchemaId) -> +default_object(<>) -> {'ok', Schema} = load(SchemaId), default_object(Schema); default_object(Schema) -> diff --git a/doc/mkdocs/mkdocs.yml b/doc/mkdocs/mkdocs.yml index a5f18137e7c..3ea4909c272 100644 --- a/doc/mkdocs/mkdocs.yml +++ b/doc/mkdocs/mkdocs.yml @@ -406,6 +406,8 @@ pages: - 'Kazoo IPs': - 'core/kazoo_ips/doc/README.md' - 'core/kazoo_ips/doc/maintenance.md' + - 'Kazoo IM': + - 'core/kazoo_im/doc/README.md' - 'Kazoo Media': - 'core/kazoo_media/doc/README.md' - 'core/kazoo_media/doc/maintenance.md' @@ -425,6 +427,8 @@ pages: - 'core/kazoo_apps/doc/kazoo_maintenance.md' - 'Kazoo Translator': - 'core/kazoo_translator/doc/README.md' + - 'Kazoo Telemetry': + - 'core/kazoo_telemetry/doc/README.md' - 'Kazoo Number Manager': - 'core/kazoo_numbers/doc/README.md' - 'core/kazoo_numbers/doc/carrier_types.md'